1 /*
2     OWFS -- One-Wire filesystem
3     OWHTTPD -- One-Wire Web Server
4     Written 2003 Paul H Alfille
5     email: paul.alfille@gmail.com
6     Released under the GPL
7     See the header file: ow.h for full attribution
8     1wire/iButton system from Dallas Semiconductor
9 */
10 
11 #include <config.h>
12 #include "owfs_config.h"
13 #include "ow.h"
14 #include "ow_counters.h"
15 #include "ow_connection.h"
16 
17 /* All the rest of the program sees is the DS9907_detect and the entry in iroutines */
18 
19 static RESET_TYPE DS9097_reset(const struct parsedname *pn);
20 static RESET_TYPE DS9097_reset_in( struct connection_in * in );
21 static GOOD_OR_BAD DS9097_pre_reset(struct connection_in *in ) ;
22 static void DS9097_post_reset(struct connection_in *in ) ;
23 static GOOD_OR_BAD DS9097_sendback_bits(const BYTE * outbits, BYTE * inbits, const size_t length, const struct parsedname *pn);
24 static void DS9097_setroutines(struct connection_in *in);
25 static GOOD_OR_BAD DS9097_send_and_get(const BYTE * bussend, BYTE * busget, const size_t length, struct connection_in *in);
26 
27 #define	OneBit	0xFF
28 //#define ZeroBit 0xC0
29 // Should be all zero's when we send 8 bits. digitemp write 0xFF or 0x00
30 #define ZeroBit 0x00
31 
32 // at slower speed of course
33 #define RESET_BYTE 0xF0
34 
35 /* Device-specific functions */
DS9097_setroutines(struct connection_in * in)36 static void DS9097_setroutines(struct connection_in *in)
37 {
38 	in->iroutines.detect = DS9097_detect;
39 	in->iroutines.reset = DS9097_reset;
40 	in->iroutines.next_both = NO_NEXT_BOTH_ROUTINE;
41 	in->iroutines.PowerByte = NO_POWERBYTE_ROUTINE;
42     in->iroutines.ProgramPulse = NO_PROGRAMPULSE_ROUTINE;
43 	in->iroutines.sendback_data = NO_SENDBACKDATA_ROUTINE;
44 	in->iroutines.sendback_bits = DS9097_sendback_bits;
45 	in->iroutines.select = NO_SELECT_ROUTINE;
46 	in->iroutines.select_and_sendback = NO_SELECTANDSENDBACK_ROUTINE;
47 	in->iroutines.set_config = NO_SET_CONFIG_ROUTINE;
48 	in->iroutines.get_config = NO_GET_CONFIG_ROUTINE;
49 	in->iroutines.reconnect = NO_RECONNECT_ROUTINE;
50 	in->iroutines.close = COM_close;
51 	in->iroutines.verify = NO_VERIFY_ROUTINE ;
52 	in->iroutines.flags = ADAP_FLAG_default;
53 	in->bundling_length = UART_FIFO_SIZE / 10;
54 }
55 
56 /* _detect is a bit of a misnomer, no detection is actually done */
57 // no bus locking here (higher up)
DS9097_detect(struct port_in * pin)58 GOOD_OR_BAD DS9097_detect(struct port_in *pin)
59 {
60 	struct connection_in * in = pin->first ;
61 	/* Set up low-level routines */
62 	DS9097_setroutines(in);
63 
64 	in->Adapter = adapter_DS9097;
65 	// in->adapter_name already set, to support HA3 and HA4B
66 	pin->busmode = bus_passive;	// in case initially tried DS9097U
67 
68 	/* open the COM port in 9600 Baud  */
69 	COM_set_standard( in ) ; // standard COM port settings
70 	pin->vmin = 1; // minimum chars
71 	pin->vtime = 0; // decisec wait
72 
73 	if (pin->init_data == NULL) {
74 		LEVEL_DEFAULT("DS9097 (passive) busmaster requires port name");
75 		return gbBAD;
76 	}
77 	RETURN_BAD_IF_BAD(COM_open(in)) ;
78 
79 	pin->flow = flow_first; // flow control
80 	switch( DS9097_reset_in(in) ) {
81 		case BUS_RESET_OK:
82 		case BUS_RESET_SHORT:
83 			return gbGOOD ;
84 		default:
85 			break ;
86 	}
87 	if ( GOOD(serial_powercycle(in)) ) {
88 		switch( DS9097_reset_in(in) ) {
89 			case BUS_RESET_OK:
90 			case BUS_RESET_SHORT:
91 				return gbGOOD ;
92 			default:
93 				break ;
94 		}
95 	}
96 
97 	/* open the COM port in 9600 Baud  */
98 	/* Second pass */
99 	pin->flow = flow_second ;
100 	RETURN_BAD_IF_BAD(COM_change(in)) ;
101 
102 	switch( DS9097_reset_in(in) ) {
103 		case BUS_RESET_OK:
104 		case BUS_RESET_SHORT:
105 			return gbGOOD ;
106 		default:
107 			break ;
108 	}
109 
110 	/* open the COM port in 9600 Baud  */
111 	/* Third pass, hardware flow control */
112 	pin->flow = flow_first ;
113 	RETURN_BAD_IF_BAD(COM_change(in)) ;
114 
115 	switch( DS9097_reset_in(in) ) {
116 		case BUS_RESET_OK:
117 		case BUS_RESET_SHORT:
118 			return gbGOOD ;
119 		default:
120 			break ;
121 	}
122 
123 	return gbBAD ;
124 }
125 
126 /* DS9097 Reset -- A little different from DS2480B */
127 /* Puts in 9600 baud, sends 11110000 then reads response */
DS9097_reset(const struct parsedname * pn)128 static RESET_TYPE DS9097_reset(const struct parsedname *pn)
129 {
130 	return DS9097_reset_in( pn->selected_connection ) ;
131 }
132 
133 /* DS9097 Reset -- A little different from DS2480B */
134 /* Puts in 9600 baud, sends 11110000 then reads response */
DS9097_reset_in(struct connection_in * in)135 static RESET_TYPE DS9097_reset_in( struct connection_in * in )
136 {
137 	BYTE resetbyte = RESET_BYTE;
138 	BYTE responsebyte;
139 
140 	if ( BAD( DS9097_pre_reset( in ) ) ) {
141 		return BUS_RESET_ERROR ;
142 	}
143 
144 	if ( BAD( DS9097_send_and_get(&resetbyte, &responsebyte, 1, in )) ) {
145 		DS9097_post_reset( in) ;
146 		return BUS_RESET_ERROR ;
147 	}
148 
149 	DS9097_post_reset(in) ;
150 
151 	switch (responsebyte) {
152 	case 0x00:
153 		return BUS_RESET_SHORT;
154 	case RESET_BYTE:
155 		// no presence
156 		in->AnyDevices = anydevices_no ;
157 		return BUS_RESET_OK;
158 	default:
159 		in->AnyDevices = anydevices_yes ;
160 		return BUS_RESET_OK;
161 	}
162 }
163 
164 /* Puts in 9600 baud */
DS9097_pre_reset(struct connection_in * in)165 static GOOD_OR_BAD DS9097_pre_reset(struct connection_in *in )
166 {
167 	struct port_in * pin = in->pown ;
168 
169 	RETURN_BAD_IF_BAD( COM_test(in) ) ;
170 
171 	/* 8 data bits */
172 	pin->bits = 8 ;
173 	pin->baud = B9600 ;
174 
175 	if ( BAD( COM_change(in)) ) {
176 		ERROR_CONNECT("Cannot set attributes: %s", SAFESTRING(DEVICENAME(in)));
177 		DS9097_post_reset( in ) ;
178 		return gbBAD;
179 	}
180 	return gbGOOD;
181 }
182 
183 /* Restore terminal settings (serial port settings) */
DS9097_post_reset(struct connection_in * in)184 static void DS9097_post_reset(struct connection_in *in )
185 {
186 	struct port_in * pin = in->pown ;
187 
188 	if (Globals.eightbit_serial) {
189 		/* coninue with 8 data bits */
190 		pin->bits = 8;
191 	} else {
192 		/* 6 data bits, Receiver enabled, Hangup, Dont change "owner" */
193 		pin->bits = 6;
194 	}
195 #ifndef B115200
196 	/* MacOSX support max 38400 in termios.h ? */
197 	pin->baud = B38400 ;
198 #else
199 	pin->baud = B115200 ;
200 #endif
201 
202 	/* Flush the input and output buffers */
203 	COM_flush(in); // Adds no appreciable time
204 	COM_change(in) ;
205 }
206 
207 /* Symmetric */
208 /* send bits -- read bits */
209 /* Actually uses bit zero of each byte */
210 /* So each "byte" has already been expanded to 1 bit/byte */
211 /* Dispatches DS9097_MAX_BITS "bits" at a time */
212 #define DS9097_MAX_BITS 24
DS9097_sendback_bits(const BYTE * outbits,BYTE * inbits,const size_t length,const struct parsedname * pn)213 static GOOD_OR_BAD DS9097_sendback_bits(const BYTE * outbits, BYTE * inbits, const size_t length, const struct parsedname *pn)
214 {
215 	BYTE local_data[DS9097_MAX_BITS];
216 	size_t global_counter ;
217 	size_t local_counter ;
218 	size_t offset ;
219 	struct connection_in * in = pn->selected_connection ;
220 
221 	/* Split into smaller packets? */
222 	for ( local_counter = global_counter = offset = 0 ; offset < length ; ) {
223 		// encode this bit
224 		local_data[local_counter] = outbits[global_counter] ? OneBit : ZeroBit;
225 		// point to next one
226 		++local_counter ;
227 		++global_counter ;
228 		// test if enough bits to send to master
229 		if (local_counter == DS9097_MAX_BITS || global_counter == length) {
230 			/* Communication with DS9097 routine */
231 			/* Up to DS9097_MAX_BITS bits at a time */
232 			if ( BAD( DS9097_send_and_get( local_data, &inbits[offset], local_counter, in )) ) {
233 				STAT_ADD1_BUS(e_bus_errors, in);
234 				return gbBAD;
235 			}
236 			offset += local_counter ;
237 			local_counter = 0 ;
238 		}
239 	}
240 
241 	/* Decode Bits */
242 	for (global_counter = 0; global_counter < length; ++global_counter) {
243 		inbits[global_counter] &= 0x01; // mask out all but lowest bit
244 	}
245 
246 	return gbGOOD;
247 }
248 
249 /* Routine to send a string of bits and get another string back */
DS9097_send_and_get(const BYTE * bussend,BYTE * busget,const size_t length,struct connection_in * in)250 static GOOD_OR_BAD DS9097_send_and_get(const BYTE * bussend, BYTE * busget, const size_t length, struct connection_in * in)
251 {
252 	switch( in->pown->type ) {
253 		case ct_telnet:
254 			RETURN_BAD_IF_BAD( telnet_write_binary( bussend, length, in) ) ;
255 			break ;
256 		case ct_serial:
257 		default:
258 			RETURN_BAD_IF_BAD( COM_write( bussend, length, in ) ) ;
259 			break ;
260 	}
261 
262 	/* get back string -- with timeout and partial read loop */
263 	return COM_read( busget, length, in ) ;
264 }
265