1 //---------------------------------------------------------------------------
2 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
18 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22 // Except as contained in this notice, the name of Dallas Semiconductor
23 // shall not be used except as stated in the Dallas Semiconductor
24 // Branding Policy.
25 //---------------------------------------------------------------------------
26 //
27 // owNetU.C - Network functions for 1-Wire Net devices
28 // using the DS2480/DS2480B (U) serial interface chip.
29 //
30 // Version: 2.01
31 //
32 // 1.02 -> 1.03 Removed caps in #includes for Linux capatibility
33 // 1.03 -> 2.00 Changed 'MLan' to 'ow'. Added support for
34 // multiple ports.
35 // 2.00 -> 2.01 Added error handling. Added circular-include check.
36 // 2.01 -> 2.10 Added raw memory error handling and SMALLINT
37 // 2.10 -> 3.00 Added memory bank functionality
38 // Added file I/O operations
39 //
40
41 #include "ownet.h"
42 #include "ds2480.h"
43
44 // external functions defined in owllu.c
45 extern SMALLINT owTouchReset(int);
46 extern SMALLINT owTouchBit(int,SMALLINT);
47 extern SMALLINT owWriteByte(int,SMALLINT);
48 extern SMALLINT owReadByte(int);
49 extern SMALLINT owSpeed(int,SMALLINT);
50 extern SMALLINT owLevel(int,SMALLINT);
51
52 // external functions defined in owltrnu.c
53 extern SMALLINT owBlock(int,SMALLINT,uchar *,SMALLINT);
54
55 // external COM functions defined in system specific link file
56 extern SMALLINT WriteCOM(int,int,uchar *);
57 extern int ReadCOM(int,int,uchar *);
58 extern void FlushCOM(int);
59
60 // external functions defined in ds2480ut.c
61 extern SMALLINT DS2480Detect(int);
62
63 // external functions defined in crcutil.c
64 extern void setcrc8(int,uchar);
65 extern uchar docrc8(int,uchar);
66
67 // exportable functions defined in ownetu.c
68 SMALLINT owFirst(int,SMALLINT,SMALLINT);
69 SMALLINT owNext(int,SMALLINT,SMALLINT);
70 void owSerialNum(int,uchar *,SMALLINT);
71 void owFamilySearchSetup(int,SMALLINT);
72 void owSkipFamily(int);
73 SMALLINT owAccess(int);
74 SMALLINT owVerify(int,SMALLINT);
75 SMALLINT owOverdriveAccess(int);
76
77 // local functions defined in ownetu.c
78 SMALLINT bitacc(SMALLINT,SMALLINT,SMALLINT,uchar *);
79
80 // global variables for this module to hold search state information
81 static int LastDiscrepancy[MAX_PORTNUM];
82 static int LastFamilyDiscrepancy[MAX_PORTNUM];
83 static uchar LastDevice[MAX_PORTNUM];
84 uchar SerialNum[MAX_PORTNUM][8];
85
86 // external globals
87 extern int UMode[MAX_PORTNUM];
88 extern SMALLINT USpeed[MAX_PORTNUM];
89
90 //--------------------------------------------------------------------------
91 // The 'owFirst' finds the first device on the 1-Wire Net This function
92 // contains one parameter 'alarm_only'. When
93 // 'alarm_only' is TRUE (1) the find alarm command 0xEC is
94 // sent instead of the normal search command 0xF0.
95 // Using the find alarm command 0xEC will limit the search to only
96 // 1-Wire devices that are in an 'alarm' state.
97 //
98 // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to
99 // indicate the symbolic port number.
100 // 'do_reset' - TRUE (1) perform reset before search, FALSE (0) do not
101 // perform reset before search.
102 // 'alarm_only' - TRUE (1) the find alarm command 0xEC is
103 // sent instead of the normal search command 0xF0
104 //
105 // Returns: TRUE (1) : when a 1-Wire device was found and it's
106 // Serial Number placed in the global SerialNum
107 // FALSE (0): There are no devices on the 1-Wire Net.
108 //
owFirst(int portnum,SMALLINT do_reset,SMALLINT alarm_only)109 SMALLINT owFirst(int portnum, SMALLINT do_reset, SMALLINT alarm_only)
110 {
111 // reset the search state
112 LastDiscrepancy[portnum] = 0;
113 LastDevice[portnum] = FALSE;
114 LastFamilyDiscrepancy[portnum] = 0;
115
116 return owNext(portnum, do_reset, alarm_only);
117 }
118
119 //--------------------------------------------------------------------------
120 // The 'owNext' function does a general search. This function
121 // continues from the previos search state. The search state
122 // can be reset by using the 'owFirst' function.
123 // This function contains one parameter 'alarm_only'.
124 // When 'alarm_only' is TRUE (1) the find alarm command
125 // 0xEC is sent instead of the normal search command 0xF0.
126 // Using the find alarm command 0xEC will limit the search to only
127 // 1-Wire devices that are in an 'alarm' state.
128 //
129 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
130 // OpenCOM to indicate the port number.
131 // 'do_reset' - TRUE (1) perform reset before search, FALSE (0) do not
132 // perform reset before search.
133 // 'alarm_only' - TRUE (1) the find alarm command 0xEC is
134 // sent instead of the normal search command 0xF0
135 //
136 // Returns: TRUE (1) : when a 1-Wire device was found and it's
137 // Serial Number placed in the global SerialNum
138 // FALSE (0): when no new device was found. Either the
139 // last search was the last device or there
140 // are no devices on the 1-Wire Net.
141 //
owNext(int portnum,SMALLINT do_reset,SMALLINT alarm_only)142 SMALLINT owNext(int portnum, SMALLINT do_reset, SMALLINT alarm_only)
143 {
144 uchar tmp_last_desc,pos;
145 uchar tmp_serial_num[8];
146 uchar readbuffer[20],sendpacket[40];
147 uchar i,sendlen=0;
148 uchar lastcrc8;
149
150 // if the last call was the last one
151 if (LastDevice[portnum])
152 {
153 // reset the search
154 LastDiscrepancy[portnum] = 0;
155 LastDevice[portnum] = FALSE;
156 LastFamilyDiscrepancy[portnum] = 0;
157 return FALSE;
158 }
159
160 // check if reset first is requested
161 if (do_reset)
162 {
163 // reset the 1-wire
164 // if there are no parts on 1-wire, return FALSE
165 if (!owTouchReset(portnum))
166 {
167 // reset the search
168 LastDiscrepancy[portnum] = 0;
169 LastFamilyDiscrepancy[portnum] = 0;
170 OWERROR(OWERROR_NO_DEVICES_ON_NET);
171 return FALSE;
172 }
173 }
174
175 // build the command stream
176 // call a function that may add the change mode command to the buff
177 // check if correct mode
178 if (UMode[portnum] != MODSEL_DATA)
179 {
180 UMode[portnum] = MODSEL_DATA;
181 sendpacket[sendlen++] = MODE_DATA;
182 }
183
184 // search command
185 if (alarm_only)
186 sendpacket[sendlen++] = 0xEC; // issue the alarming search command
187 else
188 sendpacket[sendlen++] = 0xF0; // issue the search command
189
190 // change back to command mode
191 UMode[portnum] = MODSEL_COMMAND;
192 sendpacket[sendlen++] = MODE_COMMAND;
193
194 // search mode on
195 sendpacket[sendlen++] = (uchar)(CMD_COMM | FUNCTSEL_SEARCHON | USpeed[portnum]);
196
197 // change back to data mode
198 UMode[portnum] = MODSEL_DATA;
199 sendpacket[sendlen++] = MODE_DATA;
200
201 // set the temp Last Descrep to none
202 tmp_last_desc = 0xFF;
203
204 // add the 16 bytes of the search
205 pos = sendlen;
206 for (i = 0; i < 16; i++)
207 sendpacket[sendlen++] = 0;
208
209 // only modify bits if not the first search
210 if (LastDiscrepancy[portnum] != 0xFF)
211 {
212 // set the bits in the added buffer
213 for (i = 0; i < 64; i++)
214 {
215 // before last discrepancy
216 if (i < (LastDiscrepancy[portnum] - 1))
217 bitacc(WRITE_FUNCTION,
218 bitacc(READ_FUNCTION,0,i,&SerialNum[portnum][0]),
219 (short)(i * 2 + 1),
220 &sendpacket[pos]);
221 // at last discrepancy
222 else if (i == (LastDiscrepancy[portnum] - 1))
223 bitacc(WRITE_FUNCTION,1,
224 (short)(i * 2 + 1),
225 &sendpacket[pos]);
226 // after last discrepancy so leave zeros
227 }
228 }
229
230 // change back to command mode
231 UMode[portnum] = MODSEL_COMMAND;
232 sendpacket[sendlen++] = MODE_COMMAND;
233
234 // search OFF
235 sendpacket[sendlen++] = (uchar)(CMD_COMM | FUNCTSEL_SEARCHOFF | USpeed[portnum]);
236
237 // flush the buffers
238 FlushCOM(portnum);
239
240 // send the packet
241 if (WriteCOM(portnum,sendlen,sendpacket))
242 {
243 // read back the 1 byte response
244 if (ReadCOM(portnum,17,readbuffer) == 17)
245 {
246 // interpret the bit stream
247 for (i = 0; i < 64; i++)
248 {
249 // get the SerialNum bit
250 bitacc(WRITE_FUNCTION,
251 bitacc(READ_FUNCTION,0,(short)(i * 2 + 1),&readbuffer[1]),
252 i,
253 &tmp_serial_num[0]);
254 // check LastDiscrepancy
255 if ((bitacc(READ_FUNCTION,0,(short)(i * 2),&readbuffer[1]) == 1) &&
256 (bitacc(READ_FUNCTION,0,(short)(i * 2 + 1),&readbuffer[1]) == 0))
257 {
258 tmp_last_desc = i + 1;
259 // check LastFamilyDiscrepancy
260 if (i < 8)
261 LastFamilyDiscrepancy[portnum] = i + 1;
262 }
263 }
264
265 // do dowcrc
266 setcrc8(portnum,0);
267 for (i = 0; i < 8; i++)
268 lastcrc8 = docrc8(portnum,tmp_serial_num[i]);
269
270 // check results
271 if ((lastcrc8 != 0) || (LastDiscrepancy[portnum] == 63) || (tmp_serial_num[0] == 0))
272 {
273 // error during search
274 // reset the search
275 LastDiscrepancy[portnum] = 0;
276 LastDevice[portnum] = FALSE;
277 LastFamilyDiscrepancy[portnum] = 0;
278 OWERROR(OWERROR_SEARCH_ERROR);
279 return FALSE;
280 }
281 // successful search
282 else
283 {
284 // check for lastone
285 if ((tmp_last_desc == LastDiscrepancy[portnum]) || (tmp_last_desc == 0xFF))
286 LastDevice[portnum] = TRUE;
287
288 // copy the SerialNum to the buffer
289 for (i = 0; i < 8; i++)
290 SerialNum[portnum][i] = tmp_serial_num[i];
291
292 // set the count
293 LastDiscrepancy[portnum] = tmp_last_desc;
294 return TRUE;
295 }
296 }
297 else
298 OWERROR(OWERROR_READCOM_FAILED);
299 }
300 else
301 OWERROR(OWERROR_WRITECOM_FAILED);
302
303 // an error occurred so re-sync with DS2480
304 DS2480Detect(portnum);
305
306 // reset the search
307 LastDiscrepancy[portnum] = 0;
308 LastDevice[portnum] = FALSE;
309 LastFamilyDiscrepancy[portnum] = 0;
310
311 return FALSE;
312 }
313
314 //--------------------------------------------------------------------------
315 // The 'owSerialNum' function either reads or sets the SerialNum buffer
316 // that is used in the search functions 'owFirst' and 'owNext'.
317 // This function contains two parameters, 'serialnum_buf' is a pointer
318 // to a buffer provided by the caller. 'serialnum_buf' should point to
319 // an array of 8 unsigned chars. The second parameter is a flag called
320 // 'do_read' that is TRUE (1) if the operation is to read and FALSE
321 // (0) if the operation is to set the internal SerialNum buffer from
322 // the data in the provided buffer.
323 //
324 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
325 // OpenCOM to indicate the port number.
326 // 'serialnum_buf' - buffer to that contains the serial number to set
327 // when do_read = FALSE (0) and buffer to get the serial
328 // number when do_read = TRUE (1).
329 // 'do_read' - flag to indicate reading (1) or setting (0) the current
330 // serial number.
331 //
owSerialNum(int portnum,uchar * serialnum_buf,SMALLINT do_read)332 void owSerialNum(int portnum, uchar *serialnum_buf, SMALLINT do_read)
333 {
334 uchar i;
335
336 // read the internal buffer and place in 'serialnum_buf'
337 if (do_read)
338 {
339 for (i = 0; i < 8; i++)
340 serialnum_buf[i] = SerialNum[portnum][i];
341 }
342 // set the internal buffer from the data in 'serialnum_buf'
343 else
344 {
345 for (i = 0; i < 8; i++)
346 SerialNum[portnum][i] = serialnum_buf[i];
347 }
348 }
349
350 //--------------------------------------------------------------------------
351 // Setup the search algorithm to find a certain family of devices
352 // the next time a search function is called 'owNext'.
353 //
354 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
355 // OpenCOM to indicate the port number.
356 // 'search_family' - family code type to set the search algorithm to find
357 // next.
358 //
owFamilySearchSetup(int portnum,SMALLINT search_family)359 void owFamilySearchSetup(int portnum, SMALLINT search_family)
360 {
361 uchar i;
362
363 // set the search state to find search_family type devices
364 SerialNum[portnum][0] = search_family;
365 for (i = 1; i < 8; i++)
366 SerialNum[portnum][i] = 0;
367 LastDiscrepancy[portnum] = 64;
368 LastDevice[portnum] = FALSE;
369 }
370
371 //--------------------------------------------------------------------------
372 // Set the current search state to skip the current family code.
373 //
374 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
375 // OpenCOM to indicate the port number.
376 //
owSkipFamily(int portnum)377 void owSkipFamily(int portnum)
378 {
379 // set the Last discrepancy to last family discrepancy
380 LastDiscrepancy[portnum] = LastFamilyDiscrepancy[portnum];
381
382 // check for end of list
383 if (LastDiscrepancy[portnum] == 0)
384 LastDevice[portnum] = TRUE;
385 }
386
387 //--------------------------------------------------------------------------
388 // The 'owAccess' function resets the 1-Wire and sends a MATCH Serial
389 // Number command followed by the current SerialNum code. After this
390 // function is complete the 1-Wire device is ready to accept device-specific
391 // commands.
392 //
393 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
394 // OpenCOM to indicate the port number.
395 //
396 // Returns: TRUE (1) : reset indicates present and device is ready
397 // for commands.
398 // FALSE (0): reset does not indicate presence or echos 'writes'
399 // are not correct.
400 //
owAccess(int portnum)401 SMALLINT owAccess(int portnum)
402 {
403 uchar sendpacket[9];
404 uchar i;
405
406 // reset the 1-wire
407 if (owTouchReset(portnum))
408 {
409 // create a buffer to use with block function
410 // match Serial Number command 0x55
411 sendpacket[0] = 0x55;
412 // Serial Number
413 for (i = 1; i < 9; i++)
414 sendpacket[i] = SerialNum[portnum][i-1];
415
416 // send/recieve the transfer buffer
417 if (owBlock(portnum,FALSE,sendpacket,9))
418 {
419 // verify that the echo of the writes was correct
420 for (i = 1; i < 9; i++)
421 if (sendpacket[i] != SerialNum[portnum][i-1])
422 return FALSE;
423 if (sendpacket[0] != 0x55)
424 {
425 OWERROR(OWERROR_WRITE_VERIFY_FAILED);
426 return FALSE;
427 }
428 else
429 return TRUE;
430 }
431 else
432 OWERROR(OWERROR_BLOCK_FAILED);
433 }
434 else
435 OWERROR(OWERROR_NO_DEVICES_ON_NET);
436
437 // reset or match echo failed
438 return FALSE;
439 }
440
441 //----------------------------------------------------------------------
442 // The function 'owVerify' verifies that the current device
443 // is in contact with the 1-Wire Net.
444 // Using the find alarm command 0xEC will verify that the device
445 // is in contact with the 1-Wire Net and is in an 'alarm' state.
446 //
447 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
448 // OpenCOM to indicate the port number.
449 // 'alarm_only' - TRUE (1) the find alarm command 0xEC
450 // is sent instead of the normal search
451 // command 0xF0.
452 //
453 // Returns: TRUE (1) : when the 1-Wire device was verified
454 // to be on the 1-Wire Net
455 // with alarm_only == FALSE
456 // or verified to be on the 1-Wire Net
457 // AND in an alarm state when
458 // alarm_only == TRUE.
459 // FALSE (0): the 1-Wire device was not on the
460 // 1-Wire Net or if alarm_only
461 // == TRUE, the device may be on the
462 // 1-Wire Net but in a non-alarm state.
463 //
owVerify(int portnum,SMALLINT alarm_only)464 SMALLINT owVerify(int portnum, SMALLINT alarm_only)
465 {
466 uchar i,sendlen=0,goodbits=0,cnt=0,s,tst;
467 uchar sendpacket[50];
468
469 // construct the search rom
470 if (alarm_only)
471 sendpacket[sendlen++] = 0xEC; // issue the alarming search command
472 else
473 sendpacket[sendlen++] = 0xF0; // issue the search command
474 // set all bits at first
475 for (i = 1; i <= 24; i++)
476 sendpacket[sendlen++] = 0xFF;
477 // now set or clear apropriate bits for search
478 for (i = 0; i < 64; i++)
479 bitacc(WRITE_FUNCTION,bitacc(READ_FUNCTION,0,i,&SerialNum[portnum][0]),(int)((i+1)*3-1),&sendpacket[1]);
480
481 // send/recieve the transfer buffer
482 if (owBlock(portnum,TRUE,sendpacket,sendlen))
483 {
484 // check results to see if it was a success
485 for (i = 0; i < 192; i += 3)
486 {
487 tst = (bitacc(READ_FUNCTION,0,i,&sendpacket[1]) << 1) |
488 bitacc(READ_FUNCTION,0,(int)(i+1),&sendpacket[1]);
489
490 s = bitacc(READ_FUNCTION,0,cnt++,&SerialNum[portnum][0]);
491
492 if (tst == 0x03) // no device on line
493 {
494 goodbits = 0; // number of good bits set to zero
495 break; // quit
496 }
497
498 if (((s == 0x01) && (tst == 0x02)) ||
499 ((s == 0x00) && (tst == 0x01)) ) // correct bit
500 goodbits++; // count as a good bit
501 }
502
503 // check too see if there were enough good bits to be successful
504 if (goodbits >= 8)
505 return TRUE;
506 }
507 else
508 OWERROR(OWERROR_BLOCK_FAILED);
509
510 // block fail or device not present
511 return FALSE;
512 }
513
514 //----------------------------------------------------------------------
515 // Perform a overdrive MATCH command to select the 1-Wire device with
516 // the address in the ID data register.
517 //
518 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
519 // OpenCOM to indicate the port number.
520 //
521 // Returns: TRUE: If the device is present on the 1-Wire Net and
522 // can do overdrive then the device is selected.
523 // FALSE: Device is not present or not capable of overdrive.
524 //
525 // *Note: This function could be converted to send DS2480
526 // commands in one packet.
527 //
owOverdriveAccess(int portnum)528 SMALLINT owOverdriveAccess(int portnum)
529 {
530 uchar sendpacket[8];
531 uchar i, bad_echo = FALSE;
532
533 // make sure normal level
534 owLevel(portnum,MODE_NORMAL);
535
536 // force to normal communication speed
537 owSpeed(portnum,MODE_NORMAL);
538
539 // call the 1-Wire Net reset function
540 if (owTouchReset(portnum))
541 {
542 // send the match command 0x69
543 if (owWriteByte(portnum,0x69))
544 {
545 // switch to overdrive communication speed
546 owSpeed(portnum,MODE_OVERDRIVE);
547
548 // create a buffer to use with block function
549 // Serial Number
550 for (i = 0; i < 8; i++)
551 sendpacket[i] = SerialNum[portnum][i];
552
553 // send/recieve the transfer buffer
554 if (owBlock(portnum,FALSE,sendpacket,8))
555 {
556 // verify that the echo of the writes was correct
557 for (i = 0; i < 8; i++)
558 if (sendpacket[i] != SerialNum[portnum][i])
559 bad_echo = TRUE;
560 // if echo ok then success
561 if (!bad_echo)
562 return TRUE;
563 else
564 OWERROR(OWERROR_WRITE_VERIFY_FAILED);
565 }
566 else
567 OWERROR(OWERROR_BLOCK_FAILED);
568 }
569 else
570 OWERROR(OWERROR_WRITE_BYTE_FAILED);
571 }
572 else
573 OWERROR(OWERROR_NO_DEVICES_ON_NET);
574
575 // failure, force back to normal communication speed
576 owSpeed(portnum,MODE_NORMAL);
577
578 return FALSE;
579 }
580
581 //--------------------------------------------------------------------------
582 // Bit utility to read and write a bit in the buffer 'buf'.
583 //
584 // 'op' - operation (1) to set and (0) to read
585 // 'state' - set (1) or clear (0) if operation is write (1)
586 // 'loc' - bit number location to read or write
587 // 'buf' - pointer to array of bytes that contains the bit
588 // to read or write
589 //
590 // Returns: 1 if operation is set (1)
591 // 0/1 state of bit number 'loc' if operation is reading
592 //
bitacc(SMALLINT op,SMALLINT state,SMALLINT loc,uchar * buf)593 SMALLINT bitacc(SMALLINT op, SMALLINT state, SMALLINT loc, uchar *buf)
594 {
595 SMALLINT nbyt,nbit;
596
597 nbyt = (loc / 8);
598 nbit = loc - (nbyt * 8);
599
600 if (op == WRITE_FUNCTION)
601 {
602 if (state)
603 buf[nbyt] |= (0x01 << nbit);
604 else
605 buf[nbyt] &= ~(0x01 << nbit);
606
607 return 1;
608 }
609 else
610 return ((buf[nbyt] >> nbit) & 0x01);
611 }
612