Mercurial > ~darius > hgwebdir.cgi > avr
annotate 1wire.c @ 10:eb1faf51968e
- Add some useful return values to search functions.
- Remove some unecessary trailing \'s in macros
- Replace some inline assembly I missed last time with C/macros.
author | darius |
---|---|
date | Mon, 12 Jul 2004 23:59:00 +0930 |
parents | f9a085a0ba93 |
children | 4b141cc7cbd4 |
rev | line source |
---|---|
0 | 1 /* |
2 * Various 1 wire routines | |
3 * Search routine is copied from the Dallas owpd library with mods. | |
4 * | |
8
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
5 * $Id$ |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
6 * |
0 | 7 * Copyright (c) 2004 |
8 * Daniel O'Connor <darius@dons.net.au>. All rights reserved. | |
9 * | |
10 * Redistribution and use in source and binary forms, with or without | |
11 * modification, are permitted provided that the following conditions | |
12 * are met: | |
13 * 1. Redistributions of source code must retain the above copyright | |
14 * notice, this list of conditions and the following disclaimer. | |
15 * 2. Redistributions in binary form must reproduce the above copyright | |
16 * notice, this list of conditions and the following disclaimer in the | |
17 * documentation and/or other materials provided with the distribution. | |
18 * | |
19 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE | |
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 * SUCH DAMAGE. | |
30 */ | |
31 | |
32 #include <stdio.h> | |
33 #include <avr/io.h> | |
34 #include <avr/pgmspace.h> | |
35 | |
36 #include "1wire.h" | |
8
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
37 #include "1wire-delay.h" |
0 | 38 |
39 void uart_putsP(const char *addr); | |
40 void uart_puts(const char *addr); | |
41 void uart_getc(); | |
42 int uart_putc(char c); | |
43 | |
44 static uint8_t OW_LastDevice = 0; | |
45 static uint8_t OW_LastDiscrepancy = 0; | |
46 static uint8_t OW_LastFamilyDiscrepancy = 0; | |
47 | |
48 static void | |
49 OWdelay(void) { | |
10 | 50 DELAY_I; |
0 | 51 } |
52 | |
53 /*----------------------------------------------------------------------------- | |
54 * Generate a 1-Wire reset, return 1 if no presence detect was found, | |
55 * return 0 otherwise. | |
56 * (NOTE: Does not handle alarm presence from DS2404/DS1994) | |
57 */ | |
58 int | |
59 OWTouchReset(void) { | |
10 | 60 DELAY_G; |
61 OWIREOUTPORT &= ~(_BV(OWIREOUTPIN)); | |
62 OWIREDDR |= _BV(OWIREOUTPIN); | |
63 DELAY_H; | |
64 OWIREDDR &= ~(_BV(OWIREOUTPIN)); | |
65 DELAY_I; | |
0 | 66 |
10 | 67 return(OWIREINPORT & _BV(OWIREINPIN) ? 1 : 0); |
0 | 68 } |
69 | |
70 /*----------------------------------------------------------------------------- | |
71 * Send a 1-wire write bit. | |
72 */ | |
73 void | |
74 OWWriteBit(int bit) { | |
75 OWdelay(); | |
76 if (bit) { | |
8
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
77 OWIREOUTPORT &= ~(_BV(OWIREOUTPIN)); |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
78 OWIREDDR |= _BV(OWIREOUTPIN); |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
79 DELAY_A; |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
80 OWIREDDR &= ~(_BV(OWIREOUTPIN)); |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
81 DELAY_B; |
0 | 82 } else { |
8
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
83 OWIREOUTPORT &= ~(_BV(OWIREOUTPIN)); |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
84 OWIREDDR |= _BV(OWIREOUTPIN); |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
85 DELAY_C; |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
86 OWIREDDR &= ~(_BV(OWIREOUTPIN)); |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
87 DELAY_D; |
0 | 88 } |
89 } | |
90 | |
91 /*----------------------------------------------------------------------------- | |
92 * Read a bit from the 1-wire bus and return it. | |
93 */ | |
94 int | |
95 OWReadBit(void) { | |
96 OWdelay(); | |
97 | |
8
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
98 OWIREOUTPORT &= ~(_BV(OWIREOUTPIN)); |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
99 OWIREDDR |= _BV(OWIREOUTPIN); |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
100 DELAY_A; |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
101 OWIREDDR &= ~(_BV(OWIREOUTPIN)); |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
102 DELAY_E; |
f9a085a0ba93
Change the 1 wire routines to mostly C with assembly delay routines
darius
parents:
0
diff
changeset
|
103 return(OWIREINPORT & _BV(OWIREINPIN) ? 1 : 0); |
0 | 104 } |
105 | |
106 /*----------------------------------------------------------------------------- | |
107 * Write a byte to the 1-wire bus | |
108 */ | |
109 void | |
110 OWWriteByte(uint8_t data) { | |
111 int i; | |
112 | |
113 /* Send LSB first */ | |
114 for (i = 0; i < 8; i++) { | |
115 OWWriteBit(data & 0x01); | |
116 data >>= 1; | |
117 } | |
118 } | |
119 | |
120 /*----------------------------------------------------------------------------- | |
121 * Read a byte from the 1-wire bus | |
122 */ | |
123 int | |
124 OWReadByte(void) { | |
125 int i, result = 0; | |
126 | |
127 for (i = 0; i < 8; i++) { | |
128 result >>= 1; | |
129 if (OWReadBit()) | |
130 result |= 0x80; | |
131 } | |
132 return(result); | |
133 } | |
134 | |
135 /*----------------------------------------------------------------------------- | |
136 * Write a 1-wire data byte and return the sampled result. | |
137 */ | |
138 int | |
139 OWTouchByte(uint8_t data) { | |
140 int i, result = 0; | |
141 | |
142 for (i = 0; i < 8; i++) { | |
143 result >>= 1; | |
144 | |
145 /* If sending a 1 then read a bit, otherwise write a 0 */ | |
146 if (data & 0x01) { | |
147 if (OWReadBit()) | |
148 result |= 0x80; | |
149 } else | |
150 OWWriteBit(0); | |
151 | |
152 data >>= 1; | |
153 } | |
154 | |
155 return(result); | |
156 } | |
157 | |
158 /*----------------------------------------------------------------------------- | |
159 * Write a block of bytes to the 1-wire bus and return the sampled result in | |
160 * the same buffer | |
161 */ | |
162 void | |
163 OWBlock(uint8_t *data, int len) { | |
164 int i; | |
165 | |
166 for (i = 0; i < len; i++) | |
167 data[i] = OWTouchByte(data[i]); | |
168 } | |
169 | |
170 | |
171 /*----------------------------------------------------------------------------- | |
172 * Send a 1 wire command to a device, or all if no ROM ID provided | |
173 */ | |
174 void | |
175 OWSendCmd(uint8_t *ROM, uint8_t cmd) { | |
176 int i; | |
177 | |
178 OWTouchReset(); | |
179 | |
180 if (ROM == NULL) | |
181 OWWriteByte(OW_SKIP_ROM_CMD); | |
182 else { | |
183 OWWriteByte(OW_MATCH_ROM_CMD); | |
184 for (i = 0; i < 8; i++) | |
185 OWWriteByte(ROM[i]); | |
186 } | |
187 | |
188 OWWriteByte(cmd); | |
189 } | |
190 | |
191 /*----------------------------------------------------------------------------- | |
192 * Search algorithm from App note 187 (and 162) | |
193 * | |
10 | 194 * OWFirst/OWNext return.. |
195 * 1 when something is found, | |
196 * 0 no more modules | |
197 * -1 if no presense pulse, | |
198 * -2 if bad CRC, | |
199 * -3 if bad wiring. | |
0 | 200 */ |
201 int | |
202 OWFirst(uint8_t *ROM, uint8_t do_reset, uint8_t alarm_only) { | |
203 /* Reset state */ | |
204 OW_LastDiscrepancy = 0; | |
205 OW_LastDevice = 0; | |
206 OW_LastFamilyDiscrepancy = 0; | |
207 | |
208 /* Go looking */ | |
209 return (OWNext(ROM, do_reset, alarm_only)); | |
210 } | |
211 | |
212 /* Returns 1 when something is found, 0 if nothing left */ | |
213 int | |
214 OWNext(uint8_t *ROM, uint8_t do_reset, uint8_t alarm_only) { | |
215 uint8_t bit_test, search_direction, bit_number; | |
10 | 216 uint8_t last_zero, rom_byte_number, rom_byte_mask; |
0 | 217 uint8_t lastcrc8, crcaccum; |
10 | 218 int next_result; |
0 | 219 char errstr[30]; |
220 | |
221 /* Init for search */ | |
222 bit_number = 1; | |
223 last_zero = 0; | |
224 rom_byte_number = 0; | |
225 rom_byte_mask = 1; | |
10 | 226 next_result = OW_NOMODULES; |
0 | 227 lastcrc8 = 0; |
228 crcaccum = 0; | |
229 | |
230 /* if the last call was not the last one */ | |
231 if (!OW_LastDevice) { | |
232 /* check if reset first is requested */ | |
233 if (do_reset) { | |
234 /* reset the 1-wire | |
235 * if there are no parts on 1-wire, return 0 */ | |
236 #if OW_DEBUG | |
237 uart_putsP(PSTR("Resetting\n\r")); | |
238 #endif | |
239 if (OWTouchReset()) { | |
240 /* reset the search */ | |
241 OW_LastDiscrepancy = 0; | |
242 OW_LastFamilyDiscrepancy = 0; | |
243 #if OW_DEBUG | |
244 uart_putsP(PSTR("No devices on bus\n\r")); | |
245 #endif | |
10 | 246 return OW_NOPRESENCE; |
0 | 247 } |
248 } | |
249 | |
250 /* If finding alarming devices issue a different command */ | |
251 if (alarm_only) | |
252 OWWriteByte(OW_SEARCH_ALRM_CMD); /* issue the alarming search command */ | |
253 else | |
254 OWWriteByte(OW_SEARCH_ROM_CMD); /* issue the search command */ | |
255 | |
256 /* pause before beginning the search */ | |
257 OWdelay(); | |
258 OWdelay(); | |
259 OWdelay(); | |
260 | |
261 /* loop to do the search */ | |
262 do { | |
263 /* read a bit and its compliment */ | |
264 bit_test = OWReadBit() << 1; | |
265 bit_test |= OWReadBit(); | |
266 | |
267 #if OW_DEBUG | |
268 sprintf_P(errstr, PSTR("bit_test = %d\n\r"), bit_test); | |
269 uart_puts(errstr); | |
270 #endif | |
271 | |
272 /* check for no devices on 1-wire */ | |
273 if (bit_test == 3) { | |
10 | 274 #if OW_DEBUG |
0 | 275 sprintf_P(errstr, PSTR("bit_test = %d\n\r"), bit_test); |
276 uart_puts(errstr); | |
10 | 277 #endif |
278 return(OW_BADWIRE); | |
0 | 279 } |
280 else { | |
281 /* all devices coupled have 0 or 1 */ | |
282 if (bit_test > 0) | |
283 search_direction = !(bit_test & 0x01); /* bit write value for search */ | |
284 else { | |
285 /* if this discrepancy is before the Last Discrepancy | |
286 * on a previous OWNext then pick the same as last time */ | |
287 if (bit_number < OW_LastDiscrepancy) | |
288 search_direction = ((ROM[rom_byte_number] & rom_byte_mask) > 0); | |
289 else | |
290 /* if equal to last pick 1, if not then pick 0 */ | |
291 search_direction = (bit_number == OW_LastDiscrepancy); | |
292 | |
293 /* if 0 was picked then record its position in LastZero */ | |
294 if (search_direction == 0) { | |
295 last_zero = bit_number; | |
296 | |
297 /* check for Last discrepancy in family */ | |
298 if (last_zero < 9) | |
299 OW_LastFamilyDiscrepancy = last_zero; | |
300 } | |
301 } | |
302 | |
303 /* set or clear the bit in the ROM byte rom_byte_number | |
304 * with mask rom_byte_mask */ | |
305 if (search_direction == 1) | |
306 ROM[rom_byte_number] |= rom_byte_mask; | |
307 else | |
308 ROM[rom_byte_number] &= ~rom_byte_mask; | |
309 | |
310 /* serial number search direction write bit */ | |
311 OWWriteBit(search_direction); | |
312 | |
313 /* increment the byte counter bit_number | |
314 * and shift the mask rom_byte_mask */ | |
315 bit_number++; | |
316 rom_byte_mask <<= 1; | |
317 | |
318 /* if the mask is 0 then go to new ROM byte rom_byte_number | |
319 * and reset mask */ | |
320 if (rom_byte_mask == 0) { | |
321 OWCRC(ROM[rom_byte_number], &crcaccum); /* accumulate the CRC */ | |
322 lastcrc8 = crcaccum; | |
323 | |
324 rom_byte_number++; | |
325 rom_byte_mask = 1; | |
326 } | |
327 } | |
328 } while (rom_byte_number < 8); /* loop until through all ROM bytes 0-7 */ | |
329 | |
330 /* if the search was successful then */ | |
331 if (!(bit_number < 65) || lastcrc8) { | |
332 if (lastcrc8) { | |
333 sprintf_P(errstr, PSTR("Bad CRC (%d)\n\r"), lastcrc8); | |
334 uart_puts(errstr); | |
10 | 335 next_result = OW_BADCRC; |
0 | 336 } else { |
337 /* search successful so set LastDiscrepancy,LastDevice,next_result */ | |
338 OW_LastDiscrepancy = last_zero; | |
339 OW_LastDevice = (OW_LastDiscrepancy == 0); | |
340 #if OW_DEBUG | |
341 sprintf_P(errstr, PSTR("Last device = %d\n\r"), OW_LastDevice); | |
342 uart_puts(errstr); | |
343 #endif | |
10 | 344 next_result = OW_FOUND; |
0 | 345 } |
346 } | |
347 } | |
348 | |
349 /* if no device found then reset counters so next 'next' will be | |
350 * like a first */ | |
10 | 351 if (next_result != OW_FOUND || ROM[0] == 0) { |
0 | 352 OW_LastDiscrepancy = 0; |
353 OW_LastDevice = 0; | |
354 OW_LastFamilyDiscrepancy = 0; | |
355 } | |
356 | |
10 | 357 if (next_result == OW_FOUND && ROM[0] == 0x00) |
358 next_result = OW_BADWIRE; | |
359 | |
0 | 360 return next_result; |
361 | |
362 } | |
363 | |
364 uint8_t PROGMEM dscrc_table[] = { | |
365 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, | |
366 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, | |
367 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98, | |
368 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255, | |
369 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, | |
370 219, 133,103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154, | |
371 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36, | |
372 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185, | |
373 140,210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113,147, 205, | |
374 17, 79, 173, 243, 112, 46, 204, 146, 211,141, 111, 49, 178, 236, 14, 80, | |
375 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82,176, 238, | |
376 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115, | |
377 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, | |
378 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22, | |
379 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, | |
380 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 | |
381 }; | |
382 | |
383 void | |
384 OWCRC(uint8_t x, uint8_t *crc) { | |
385 *crc = pgm_read_byte(&dscrc_table[(*crc) ^ x]); | |
386 } |