Mercurial > code > home > repos > homeauto
comparison service/arduinoNode/arduino-libraries/OneWire/OneWire.cpp @ 970:4f5825a9fc47
some external arduino libs, minus examples and docs
Ignore-this: 444126f11a1755109b3b29cbeaa6b9bd
darcs-hash:20150411084314-312f9-165a2a8d6ee806950c8a7ae2145364d286fd50b4
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Sat, 11 Apr 2015 01:43:14 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
969:70a5392b24d3 | 970:4f5825a9fc47 |
---|---|
1 /* | |
2 Copyright (c) 2007, Jim Studt (original old version - many contributors since) | |
3 | |
4 The latest version of this library may be found at: | |
5 http://www.pjrc.com/teensy/td_libs_OneWire.html | |
6 | |
7 OneWire has been maintained by Paul Stoffregen (paul@pjrc.com) since | |
8 January 2010. At the time, it was in need of many bug fixes, but had | |
9 been abandoned the original author (Jim Studt). None of the known | |
10 contributors were interested in maintaining OneWire. Paul typically | |
11 works on OneWire every 6 to 12 months. Patches usually wait that | |
12 long. If anyone is interested in more actively maintaining OneWire, | |
13 please contact Paul. | |
14 | |
15 Version 2.2: | |
16 Teensy 3.0 compatibility, Paul Stoffregen, paul@pjrc.com | |
17 Arduino Due compatibility, http://arduino.cc/forum/index.php?topic=141030 | |
18 Fix DS18B20 example negative temperature | |
19 Fix DS18B20 example's low res modes, Ken Butcher | |
20 Improve reset timing, Mark Tillotson | |
21 Add const qualifiers, Bertrik Sikken | |
22 Add initial value input to crc16, Bertrik Sikken | |
23 Add target_search() function, Scott Roberts | |
24 | |
25 Version 2.1: | |
26 Arduino 1.0 compatibility, Paul Stoffregen | |
27 Improve temperature example, Paul Stoffregen | |
28 DS250x_PROM example, Guillermo Lovato | |
29 PIC32 (chipKit) compatibility, Jason Dangel, dangel.jason AT gmail.com | |
30 Improvements from Glenn Trewitt: | |
31 - crc16() now works | |
32 - check_crc16() does all of calculation/checking work. | |
33 - Added read_bytes() and write_bytes(), to reduce tedious loops. | |
34 - Added ds2408 example. | |
35 Delete very old, out-of-date readme file (info is here) | |
36 | |
37 Version 2.0: Modifications by Paul Stoffregen, January 2010: | |
38 http://www.pjrc.com/teensy/td_libs_OneWire.html | |
39 Search fix from Robin James | |
40 http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27 | |
41 Use direct optimized I/O in all cases | |
42 Disable interrupts during timing critical sections | |
43 (this solves many random communication errors) | |
44 Disable interrupts during read-modify-write I/O | |
45 Reduce RAM consumption by eliminating unnecessary | |
46 variables and trimming many to 8 bits | |
47 Optimize both crc8 - table version moved to flash | |
48 | |
49 Modified to work with larger numbers of devices - avoids loop. | |
50 Tested in Arduino 11 alpha with 12 sensors. | |
51 26 Sept 2008 -- Robin James | |
52 http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27 | |
53 | |
54 Updated to work with arduino-0008 and to include skip() as of | |
55 2007/07/06. --RJL20 | |
56 | |
57 Modified to calculate the 8-bit CRC directly, avoiding the need for | |
58 the 256-byte lookup table to be loaded in RAM. Tested in arduino-0010 | |
59 -- Tom Pollard, Jan 23, 2008 | |
60 | |
61 Jim Studt's original library was modified by Josh Larios. | |
62 | |
63 Tom Pollard, pollard@alum.mit.edu, contributed around May 20, 2008 | |
64 | |
65 Permission is hereby granted, free of charge, to any person obtaining | |
66 a copy of this software and associated documentation files (the | |
67 "Software"), to deal in the Software without restriction, including | |
68 without limitation the rights to use, copy, modify, merge, publish, | |
69 distribute, sublicense, and/or sell copies of the Software, and to | |
70 permit persons to whom the Software is furnished to do so, subject to | |
71 the following conditions: | |
72 | |
73 The above copyright notice and this permission notice shall be | |
74 included in all copies or substantial portions of the Software. | |
75 | |
76 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
77 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
78 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
79 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
80 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
81 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
82 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
83 | |
84 Much of the code was inspired by Derek Yerger's code, though I don't | |
85 think much of that remains. In any event that was.. | |
86 (copyleft) 2006 by Derek Yerger - Free to distribute freely. | |
87 | |
88 The CRC code was excerpted and inspired by the Dallas Semiconductor | |
89 sample code bearing this copyright. | |
90 //--------------------------------------------------------------------------- | |
91 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. | |
92 // | |
93 // Permission is hereby granted, free of charge, to any person obtaining a | |
94 // copy of this software and associated documentation files (the "Software"), | |
95 // to deal in the Software without restriction, including without limitation | |
96 // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
97 // and/or sell copies of the Software, and to permit persons to whom the | |
98 // Software is furnished to do so, subject to the following conditions: | |
99 // | |
100 // The above copyright notice and this permission notice shall be included | |
101 // in all copies or substantial portions of the Software. | |
102 // | |
103 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
104 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
105 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
106 // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES | |
107 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
108 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
109 // OTHER DEALINGS IN THE SOFTWARE. | |
110 // | |
111 // Except as contained in this notice, the name of Dallas Semiconductor | |
112 // shall not be used except as stated in the Dallas Semiconductor | |
113 // Branding Policy. | |
114 //-------------------------------------------------------------------------- | |
115 */ | |
116 | |
117 #include "OneWire.h" | |
118 | |
119 | |
120 OneWire::OneWire(uint8_t pin) | |
121 { | |
122 pinMode(pin, INPUT); | |
123 bitmask = PIN_TO_BITMASK(pin); | |
124 baseReg = PIN_TO_BASEREG(pin); | |
125 #if ONEWIRE_SEARCH | |
126 reset_search(); | |
127 #endif | |
128 } | |
129 | |
130 | |
131 // Perform the onewire reset function. We will wait up to 250uS for | |
132 // the bus to come high, if it doesn't then it is broken or shorted | |
133 // and we return a 0; | |
134 // | |
135 // Returns 1 if a device asserted a presence pulse, 0 otherwise. | |
136 // | |
137 uint8_t OneWire::reset(void) | |
138 { | |
139 IO_REG_TYPE mask = bitmask; | |
140 volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; | |
141 uint8_t r; | |
142 uint8_t retries = 125; | |
143 | |
144 noInterrupts(); | |
145 DIRECT_MODE_INPUT(reg, mask); | |
146 interrupts(); | |
147 // wait until the wire is high... just in case | |
148 do { | |
149 if (--retries == 0) return 0; | |
150 delayMicroseconds(2); | |
151 } while ( !DIRECT_READ(reg, mask)); | |
152 | |
153 noInterrupts(); | |
154 DIRECT_WRITE_LOW(reg, mask); | |
155 DIRECT_MODE_OUTPUT(reg, mask); // drive output low | |
156 interrupts(); | |
157 delayMicroseconds(480); | |
158 noInterrupts(); | |
159 DIRECT_MODE_INPUT(reg, mask); // allow it to float | |
160 delayMicroseconds(70); | |
161 r = !DIRECT_READ(reg, mask); | |
162 interrupts(); | |
163 delayMicroseconds(410); | |
164 return r; | |
165 } | |
166 | |
167 // | |
168 // Write a bit. Port and bit is used to cut lookup time and provide | |
169 // more certain timing. | |
170 // | |
171 void OneWire::write_bit(uint8_t v) | |
172 { | |
173 IO_REG_TYPE mask=bitmask; | |
174 volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; | |
175 | |
176 if (v & 1) { | |
177 noInterrupts(); | |
178 DIRECT_WRITE_LOW(reg, mask); | |
179 DIRECT_MODE_OUTPUT(reg, mask); // drive output low | |
180 delayMicroseconds(10); | |
181 DIRECT_WRITE_HIGH(reg, mask); // drive output high | |
182 interrupts(); | |
183 delayMicroseconds(55); | |
184 } else { | |
185 noInterrupts(); | |
186 DIRECT_WRITE_LOW(reg, mask); | |
187 DIRECT_MODE_OUTPUT(reg, mask); // drive output low | |
188 delayMicroseconds(65); | |
189 DIRECT_WRITE_HIGH(reg, mask); // drive output high | |
190 interrupts(); | |
191 delayMicroseconds(5); | |
192 } | |
193 } | |
194 | |
195 // | |
196 // Read a bit. Port and bit is used to cut lookup time and provide | |
197 // more certain timing. | |
198 // | |
199 uint8_t OneWire::read_bit(void) | |
200 { | |
201 IO_REG_TYPE mask=bitmask; | |
202 volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; | |
203 uint8_t r; | |
204 | |
205 noInterrupts(); | |
206 DIRECT_MODE_OUTPUT(reg, mask); | |
207 DIRECT_WRITE_LOW(reg, mask); | |
208 delayMicroseconds(3); | |
209 DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise | |
210 delayMicroseconds(10); | |
211 r = DIRECT_READ(reg, mask); | |
212 interrupts(); | |
213 delayMicroseconds(53); | |
214 return r; | |
215 } | |
216 | |
217 // | |
218 // Write a byte. The writing code uses the active drivers to raise the | |
219 // pin high, if you need power after the write (e.g. DS18S20 in | |
220 // parasite power mode) then set 'power' to 1, otherwise the pin will | |
221 // go tri-state at the end of the write to avoid heating in a short or | |
222 // other mishap. | |
223 // | |
224 void OneWire::write(uint8_t v, uint8_t power /* = 0 */) { | |
225 uint8_t bitMask; | |
226 | |
227 for (bitMask = 0x01; bitMask; bitMask <<= 1) { | |
228 OneWire::write_bit( (bitMask & v)?1:0); | |
229 } | |
230 if ( !power) { | |
231 noInterrupts(); | |
232 DIRECT_MODE_INPUT(baseReg, bitmask); | |
233 DIRECT_WRITE_LOW(baseReg, bitmask); | |
234 interrupts(); | |
235 } | |
236 } | |
237 | |
238 void OneWire::write_bytes(const uint8_t *buf, uint16_t count, bool power /* = 0 */) { | |
239 for (uint16_t i = 0 ; i < count ; i++) | |
240 write(buf[i]); | |
241 if (!power) { | |
242 noInterrupts(); | |
243 DIRECT_MODE_INPUT(baseReg, bitmask); | |
244 DIRECT_WRITE_LOW(baseReg, bitmask); | |
245 interrupts(); | |
246 } | |
247 } | |
248 | |
249 // | |
250 // Read a byte | |
251 // | |
252 uint8_t OneWire::read() { | |
253 uint8_t bitMask; | |
254 uint8_t r = 0; | |
255 | |
256 for (bitMask = 0x01; bitMask; bitMask <<= 1) { | |
257 if ( OneWire::read_bit()) r |= bitMask; | |
258 } | |
259 return r; | |
260 } | |
261 | |
262 void OneWire::read_bytes(uint8_t *buf, uint16_t count) { | |
263 for (uint16_t i = 0 ; i < count ; i++) | |
264 buf[i] = read(); | |
265 } | |
266 | |
267 // | |
268 // Do a ROM select | |
269 // | |
270 void OneWire::select(const uint8_t rom[8]) | |
271 { | |
272 uint8_t i; | |
273 | |
274 write(0x55); // Choose ROM | |
275 | |
276 for (i = 0; i < 8; i++) write(rom[i]); | |
277 } | |
278 | |
279 // | |
280 // Do a ROM skip | |
281 // | |
282 void OneWire::skip() | |
283 { | |
284 write(0xCC); // Skip ROM | |
285 } | |
286 | |
287 void OneWire::depower() | |
288 { | |
289 noInterrupts(); | |
290 DIRECT_MODE_INPUT(baseReg, bitmask); | |
291 interrupts(); | |
292 } | |
293 | |
294 #if ONEWIRE_SEARCH | |
295 | |
296 // | |
297 // You need to use this function to start a search again from the beginning. | |
298 // You do not need to do it for the first search, though you could. | |
299 // | |
300 void OneWire::reset_search() | |
301 { | |
302 // reset the search state | |
303 LastDiscrepancy = 0; | |
304 LastDeviceFlag = FALSE; | |
305 LastFamilyDiscrepancy = 0; | |
306 for(int i = 7; ; i--) { | |
307 ROM_NO[i] = 0; | |
308 if ( i == 0) break; | |
309 } | |
310 } | |
311 | |
312 // Setup the search to find the device type 'family_code' on the next call | |
313 // to search(*newAddr) if it is present. | |
314 // | |
315 void OneWire::target_search(uint8_t family_code) | |
316 { | |
317 // set the search state to find SearchFamily type devices | |
318 ROM_NO[0] = family_code; | |
319 for (uint8_t i = 1; i < 8; i++) | |
320 ROM_NO[i] = 0; | |
321 LastDiscrepancy = 64; | |
322 LastFamilyDiscrepancy = 0; | |
323 LastDeviceFlag = FALSE; | |
324 } | |
325 | |
326 // | |
327 // Perform a search. If this function returns a '1' then it has | |
328 // enumerated the next device and you may retrieve the ROM from the | |
329 // OneWire::address variable. If there are no devices, no further | |
330 // devices, or something horrible happens in the middle of the | |
331 // enumeration then a 0 is returned. If a new device is found then | |
332 // its address is copied to newAddr. Use OneWire::reset_search() to | |
333 // start over. | |
334 // | |
335 // --- Replaced by the one from the Dallas Semiconductor web site --- | |
336 //-------------------------------------------------------------------------- | |
337 // Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing | |
338 // search state. | |
339 // Return TRUE : device found, ROM number in ROM_NO buffer | |
340 // FALSE : device not found, end of search | |
341 // | |
342 uint8_t OneWire::search(uint8_t *newAddr) | |
343 { | |
344 uint8_t id_bit_number; | |
345 uint8_t last_zero, rom_byte_number, search_result; | |
346 uint8_t id_bit, cmp_id_bit; | |
347 | |
348 unsigned char rom_byte_mask, search_direction; | |
349 | |
350 // initialize for search | |
351 id_bit_number = 1; | |
352 last_zero = 0; | |
353 rom_byte_number = 0; | |
354 rom_byte_mask = 1; | |
355 search_result = 0; | |
356 | |
357 // if the last call was not the last one | |
358 if (!LastDeviceFlag) | |
359 { | |
360 // 1-Wire reset | |
361 if (!reset()) | |
362 { | |
363 // reset the search | |
364 LastDiscrepancy = 0; | |
365 LastDeviceFlag = FALSE; | |
366 LastFamilyDiscrepancy = 0; | |
367 return FALSE; | |
368 } | |
369 | |
370 // issue the search command | |
371 write(0xF0); | |
372 | |
373 // loop to do the search | |
374 do | |
375 { | |
376 // read a bit and its complement | |
377 id_bit = read_bit(); | |
378 cmp_id_bit = read_bit(); | |
379 | |
380 // check for no devices on 1-wire | |
381 if ((id_bit == 1) && (cmp_id_bit == 1)) | |
382 break; | |
383 else | |
384 { | |
385 // all devices coupled have 0 or 1 | |
386 if (id_bit != cmp_id_bit) | |
387 search_direction = id_bit; // bit write value for search | |
388 else | |
389 { | |
390 // if this discrepancy if before the Last Discrepancy | |
391 // on a previous next then pick the same as last time | |
392 if (id_bit_number < LastDiscrepancy) | |
393 search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); | |
394 else | |
395 // if equal to last pick 1, if not then pick 0 | |
396 search_direction = (id_bit_number == LastDiscrepancy); | |
397 | |
398 // if 0 was picked then record its position in LastZero | |
399 if (search_direction == 0) | |
400 { | |
401 last_zero = id_bit_number; | |
402 | |
403 // check for Last discrepancy in family | |
404 if (last_zero < 9) | |
405 LastFamilyDiscrepancy = last_zero; | |
406 } | |
407 } | |
408 | |
409 // set or clear the bit in the ROM byte rom_byte_number | |
410 // with mask rom_byte_mask | |
411 if (search_direction == 1) | |
412 ROM_NO[rom_byte_number] |= rom_byte_mask; | |
413 else | |
414 ROM_NO[rom_byte_number] &= ~rom_byte_mask; | |
415 | |
416 // serial number search direction write bit | |
417 write_bit(search_direction); | |
418 | |
419 // increment the byte counter id_bit_number | |
420 // and shift the mask rom_byte_mask | |
421 id_bit_number++; | |
422 rom_byte_mask <<= 1; | |
423 | |
424 // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask | |
425 if (rom_byte_mask == 0) | |
426 { | |
427 rom_byte_number++; | |
428 rom_byte_mask = 1; | |
429 } | |
430 } | |
431 } | |
432 while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 | |
433 | |
434 // if the search was successful then | |
435 if (!(id_bit_number < 65)) | |
436 { | |
437 // search successful so set LastDiscrepancy,LastDeviceFlag,search_result | |
438 LastDiscrepancy = last_zero; | |
439 | |
440 // check for last device | |
441 if (LastDiscrepancy == 0) | |
442 LastDeviceFlag = TRUE; | |
443 | |
444 search_result = TRUE; | |
445 } | |
446 } | |
447 | |
448 // if no device found then reset counters so next 'search' will be like a first | |
449 if (!search_result || !ROM_NO[0]) | |
450 { | |
451 LastDiscrepancy = 0; | |
452 LastDeviceFlag = FALSE; | |
453 LastFamilyDiscrepancy = 0; | |
454 search_result = FALSE; | |
455 } | |
456 for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i]; | |
457 return search_result; | |
458 } | |
459 | |
460 #endif | |
461 | |
462 #if ONEWIRE_CRC | |
463 // The 1-Wire CRC scheme is described in Maxim Application Note 27: | |
464 // "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products" | |
465 // | |
466 | |
467 #if ONEWIRE_CRC8_TABLE | |
468 // This table comes from Dallas sample code where it is freely reusable, | |
469 // though Copyright (C) 2000 Dallas Semiconductor Corporation | |
470 static const uint8_t PROGMEM dscrc_table[] = { | |
471 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, | |
472 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, | |
473 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, | |
474 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, | |
475 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, | |
476 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, | |
477 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, | |
478 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, | |
479 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, | |
480 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, | |
481 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, | |
482 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, | |
483 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, | |
484 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, | |
485 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, | |
486 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; | |
487 | |
488 // | |
489 // Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM | |
490 // and the registers. (note: this might better be done without to | |
491 // table, it would probably be smaller and certainly fast enough | |
492 // compared to all those delayMicrosecond() calls. But I got | |
493 // confused, so I use this table from the examples.) | |
494 // | |
495 uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) | |
496 { | |
497 uint8_t crc = 0; | |
498 | |
499 while (len--) { | |
500 crc = pgm_read_byte(dscrc_table + (crc ^ *addr++)); | |
501 } | |
502 return crc; | |
503 } | |
504 #else | |
505 // | |
506 // Compute a Dallas Semiconductor 8 bit CRC directly. | |
507 // this is much slower, but much smaller, than the lookup table. | |
508 // | |
509 uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) | |
510 { | |
511 uint8_t crc = 0; | |
512 | |
513 while (len--) { | |
514 uint8_t inbyte = *addr++; | |
515 for (uint8_t i = 8; i; i--) { | |
516 uint8_t mix = (crc ^ inbyte) & 0x01; | |
517 crc >>= 1; | |
518 if (mix) crc ^= 0x8C; | |
519 inbyte >>= 1; | |
520 } | |
521 } | |
522 return crc; | |
523 } | |
524 #endif | |
525 | |
526 #if ONEWIRE_CRC16 | |
527 bool OneWire::check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc) | |
528 { | |
529 crc = ~crc16(input, len, crc); | |
530 return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1]; | |
531 } | |
532 | |
533 uint16_t OneWire::crc16(const uint8_t* input, uint16_t len, uint16_t crc) | |
534 { | |
535 static const uint8_t oddparity[16] = | |
536 { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; | |
537 | |
538 for (uint16_t i = 0 ; i < len ; i++) { | |
539 // Even though we're just copying a byte from the input, | |
540 // we'll be doing 16-bit computation with it. | |
541 uint16_t cdata = input[i]; | |
542 cdata = (cdata ^ crc) & 0xff; | |
543 crc >>= 8; | |
544 | |
545 if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4]) | |
546 crc ^= 0xC001; | |
547 | |
548 cdata <<= 6; | |
549 crc ^= cdata; | |
550 cdata <<= 1; | |
551 crc ^= cdata; | |
552 } | |
553 return crc; | |
554 } | |
555 #endif | |
556 | |
557 #endif |