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