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 //  owTranU.C - Transport functions for 1-Wire Net
28 //              using the DS2480B (U) serial interface chip.
29 //
30 //  Version: 2.01
31 //
32 //  History: 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 support for owError library
36 //           2.01 -> 2.10  Added SMALLINT for small processors and error
37 //                         handling plus the raw memory utilities.
38 //           2.10 -> 3.00 Added memory bank functionality
39 //                        Added file I/O operations
40 //
41 
42 #include "ownet.h"
43 #include "ds2480.h"
44 
45 // external functions defined in owllu.c
46 extern SMALLINT owTouchReset(int);
47 extern SMALLINT owWriteByte(int,SMALLINT);
48 extern SMALLINT owReadByte(int);
49 extern SMALLINT owProgramPulse(int);
50 
51 // external network-level functions defined in owsesu.c
52 extern SMALLINT owAccess(int);
53 
54 // external COM functions required defined in system specific link file
55 extern SMALLINT WriteCOM(int,int,uchar *);
56 extern int      ReadCOM(int,int,uchar *);
57 extern void     FlushCOM(int);
58 
59 // external defined in ds2480ut.c
60 extern SMALLINT DS2480Detect(int);
61 extern SMALLINT UBaud[MAX_PORTNUM];
62 extern SMALLINT UMode[MAX_PORTNUM];
63 extern SMALLINT USpeed[MAX_PORTNUM];
64 extern uchar SerialNum[MAX_PORTNUM][8];
65 
66 // external functions defined in crcutil.c
67 extern void setcrc16(int,ushort);
68 extern ushort docrc16(int,ushort);
69 extern void setcrc8(int,uchar);
70 extern uchar docrc8(int,uchar);
71 
72 // exportable functions defined in owtrnu.c
73 SMALLINT owBlock(int,SMALLINT,uchar *,SMALLINT);
74 SMALLINT owReadPacketStd(int,SMALLINT,int,uchar *);
75 SMALLINT owWritePacketStd(int,int,uchar *,SMALLINT,SMALLINT,SMALLINT);
76 SMALLINT owProgramByte(int,SMALLINT,int,SMALLINT,SMALLINT,SMALLINT);
77 
78 // local static functions
79 static SMALLINT Write_Scratchpad(int,uchar *,int,SMALLINT);
80 static SMALLINT Copy_Scratchpad(int,int,SMALLINT);
81 
82 //--------------------------------------------------------------------------
83 // The 'owBlock' transfers a block of data to and from the
84 // 1-Wire Net with an optional reset at the begining of communication.
85 // The result is returned in the same buffer.
86 //
87 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number is provided to
88 //              indicate the symbolic port number.
89 // 'do_reset' - cause a owTouchReset to occur at the begining of
90 //              communication TRUE(1) or not FALSE(0)
91 // 'tran_buf' - pointer to a block of unsigned
92 //              chars of length 'tran_len' that will be sent
93 //              to the 1-Wire Net
94 // 'tran_len' - length in bytes to transfer
95 
96 // Supported devices: all
97 //
98 // Returns:   TRUE (1) : The optional reset returned a valid
99 //                       presence (do_reset == TRUE) or there
100 //                       was no reset required.
101 //            FALSE (0): The reset did not return a valid prsence
102 //                       (do_reset == TRUE).
103 //
104 //  The maximum tran_length is 64
105 //
owBlock(int portnum,SMALLINT do_reset,uchar * tran_buf,SMALLINT tran_len)106 SMALLINT owBlock(int portnum, SMALLINT do_reset, uchar *tran_buf, SMALLINT tran_len)
107 {
108    uchar sendpacket[150];
109    uchar sendlen=0,pos,i;
110 
111    // check for a block too big
112    if (tran_len > 64)
113    {
114       OWERROR(OWERROR_BLOCK_TOO_BIG);
115       return FALSE;
116    }
117 
118    // check if need to do a owTouchReset first
119    if (do_reset)
120    {
121       if (!owTouchReset(portnum))
122       {
123          OWERROR(OWERROR_NO_DEVICES_ON_NET);
124          return FALSE;
125       }
126    }
127 
128    // construct the packet to send to the DS2480
129    // check if correct mode
130    if (UMode[portnum] != MODSEL_DATA)
131    {
132       UMode[portnum] = MODSEL_DATA;
133       sendpacket[sendlen++] = MODE_DATA;
134    }
135 
136    // add the bytes to send
137    pos = sendlen;
138    for (i = 0; i < tran_len; i++)
139    {
140       sendpacket[sendlen++] = tran_buf[i];
141 
142       // check for duplication of data that looks like COMMAND mode
143       if (tran_buf[i] == MODE_COMMAND)
144          sendpacket[sendlen++] = tran_buf[i];
145    }
146 
147    // flush the buffers
148    FlushCOM(portnum);
149 
150    // send the packet
151    if (WriteCOM(portnum,sendlen,sendpacket))
152    {
153       // read back the response
154       if (ReadCOM(portnum,tran_len,tran_buf) == tran_len)
155          return TRUE;
156       else
157          OWERROR(OWERROR_READCOM_FAILED);
158    }
159    else
160       OWERROR(OWERROR_WRITECOM_FAILED);
161 
162    // an error occurred so re-sync with DS2480
163    DS2480Detect(portnum);
164 
165    return FALSE;
166 }
167 
168 //--------------------------------------------------------------------------
169 // Read a Universal Data Packet from a standard NVRAM iButton
170 // and return it in the provided buffer. The page that the
171 // packet resides on is 'start_page'.  Note that this function is limited
172 // to single page packets. The buffer 'read_buf' must be at least
173 // 29 bytes long.
174 //
175 // The Universal Data Packet always start on page boundaries but
176 // can end anywhere.  The length is the number of data bytes not
177 // including the length byte and the CRC16 bytes.  There is one
178 // length byte. The CRC16 is first initialized to the starting
179 // page number.  This provides a check to verify the page that
180 // was intended is being read.  The CRC16 is then calculated over
181 // the length and data bytes.  The CRC16 is then inverted and stored
182 // low byte first followed by the high byte.
183 //
184 // Supported devices: DS1992, DS1993, DS1994, DS1995, DS1996, DS1982,
185 //                    DS1985, DS1986, DS2407, and DS1971.
186 //
187 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
188 //                indicate the symbolic port number.
189 // 'do_access'  - flag to indicate if an 'owAccess' should be
190 //                peformed at the begining of the read.  This may
191 //                be FALSE (0) if the previous call was to read the
192 //                previous page (start_page-1).
193 // 'start_page' - page number to start the read from
194 // 'read_buf'   - pointer to a location to store the data read
195 //
196 // Returns:  >=0 success, number of data bytes in the buffer
197 //           -1  failed to read a valid UDP
198 //
199 //
owReadPacketStd(int portnum,SMALLINT do_access,int start_page,uchar * read_buf)200 SMALLINT owReadPacketStd(int portnum, SMALLINT do_access, int start_page, uchar *read_buf)
201 {
202    uchar i,length,sendlen=0,head_len=0;
203    uchar sendpacket[50];
204    ushort lastcrc16;
205 
206    // check if access header is done
207    // (only use if in sequention read with one access at begining)
208    if (do_access)
209    {
210       // match command
211       sendpacket[sendlen++] = 0x55;
212       for (i = 0; i < 8; i++)
213          sendpacket[sendlen++] = SerialNum[portnum][i];
214       // read memory command
215       sendpacket[sendlen++] = 0xF0;
216       // write the target address
217       sendpacket[sendlen++] = ((start_page << 5) & 0xFF);
218       sendpacket[sendlen++] = (start_page >> 3);
219       // check for DS1982 exception (redirection byte)
220       if (SerialNum[portnum][0] == 0x09)
221          sendpacket[sendlen++] = 0xFF;
222       // record the header length
223       head_len = sendlen;
224    }
225    // read the entire page length byte
226    for (i = 0; i < 32; i++)
227       sendpacket[sendlen++] = 0xFF;
228 
229    // send/recieve the transfer buffer
230    if (owBlock(portnum,do_access,sendpacket,sendlen))
231    {
232       // seed crc with page number
233       setcrc16(portnum,(ushort)start_page);
234 
235       // attempt to read UDP from sendpacket
236       length = sendpacket[head_len];
237       docrc16(portnum,(ushort)length);
238 
239       // verify length is not too large
240       if (length <= 29)
241       {
242          // loop to read packet including CRC
243          for (i = 0; i < length; i++)
244          {
245              read_buf[i] = sendpacket[i+1+head_len];
246              docrc16(portnum,read_buf[i]);
247          }
248 
249          // read and compute the CRC16
250          docrc16(portnum,sendpacket[i+1+head_len]);
251          lastcrc16 = docrc16(portnum,sendpacket[i+2+head_len]);
252 
253          // verify the CRC16 is correct
254          if (lastcrc16 == 0xB001)
255            return length;        // return number of byte in record
256          else
257             OWERROR(OWERROR_CRC_FAILED);
258       }
259       else
260          OWERROR(OWERROR_INCORRECT_CRC_LENGTH);
261    }
262    else
263       OWERROR(OWERROR_BLOCK_FAILED);
264 
265    // failed block or incorrect CRC
266    return -1;
267 }
268 
269 //--------------------------------------------------------------------------
270 // Write a Universal Data Packet onto a standard NVRAM 1-Wire device
271 // on page 'start_page'.  This function is limited to UDPs that
272 // fit on one page.  The data to write is provided as a buffer
273 // 'write_buf' with a length 'write_len'.
274 //
275 // The Universal Data Packet always start on page boundaries but
276 // can end anywhere.  The length is the number of data bytes not
277 // including the length byte and the CRC16 bytes.  There is one
278 // length byte. The CRC16 is first initialized to the starting
279 // page number.  This provides a check to verify the page that
280 // was intended is being read.  The CRC16 is then calculated over
281 // the length and data bytes.  The CRC16 is then inverted and stored
282 // low byte first followed by the high byte.
283 //
284 // Supported devices: is_eprom=0
285 //                        DS1992, DS1993, DS1994, DS1995, DS1996
286 //                    is_eprom=1, crc_type=0(CRC8)
287 //                        DS1982
288 //                    is_eprom=1, crc_type=1(CRC16)
289 //                        DS1985, DS1986, DS2407
290 //
291 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
292 //                indicate the symbolic port number.
293 // 'start_page' - page number to write packet to
294 // 'write_buf'  - pointer to buffer containing data to write
295 // 'write_len'  - number of data byte in write_buf
296 // 'is_eprom'   - flag set if device is an EPROM (1 EPROM, 0 NVRAM)
297 // 'crc_type'   - if is_eprom=1 then indicates CRC type
298 //                (0 CRC8, 1 CRC16)
299 //
300 // Returns: TRUE(1)  success, packet written
301 //          FALSE(0) failure to write, contact lost or device locked
302 //
owWritePacketStd(int portnum,int start_page,uchar * write_buf,SMALLINT write_len,SMALLINT is_eprom,SMALLINT crc_type)303 SMALLINT owWritePacketStd(int portnum, int start_page, uchar *write_buf,
304                         SMALLINT write_len, SMALLINT is_eprom, SMALLINT crc_type)
305 {
306    uchar construct_buffer[32];
307    uchar i,buffer_cnt=0,start_address,do_access;
308    ushort lastcrc16=0;
309 
310    // check to see if data too long to fit on device
311    if (write_len > 29)
312      return FALSE;
313 
314    // seed crc with page number
315    setcrc16(portnum,(ushort)start_page);
316 
317    // set length byte
318    construct_buffer[buffer_cnt++] = (uchar)(write_len);
319    docrc16(portnum,(ushort)write_len);
320 
321    // fill in the data to write
322    for (i = 0; i < write_len; i++)
323    {
324      lastcrc16 = docrc16(portnum,write_buf[i]);
325      construct_buffer[buffer_cnt++] = write_buf[i];
326    }
327 
328    // add the crc
329    construct_buffer[buffer_cnt++] = (uchar)(~(lastcrc16 & 0xFF));
330    construct_buffer[buffer_cnt++] = (uchar)(~((lastcrc16 & 0xFF00) >> 8));
331 
332    // check if not EPROM
333    if (!is_eprom)
334    {
335       // write the page
336       if (!Write_Scratchpad(portnum,construct_buffer,start_page,buffer_cnt))
337       {
338          OWERROR(OWERROR_WRITE_SCRATCHPAD_FAILED);
339          return FALSE;
340       }
341 
342       // copy the scratchpad
343       if (!Copy_Scratchpad(portnum,start_page,buffer_cnt))
344       {
345          OWERROR(OWERROR_COPY_SCRATCHPAD_FAILED);
346          return FALSE;
347       }
348 
349       // copy scratch pad was good then success
350       return TRUE;
351    }
352    // is EPROM
353    else
354    {
355       // calculate the start address
356       start_address = ((start_page >> 3) << 8) | ((start_page << 5) & 0xFF);
357       do_access = TRUE;
358       // loop to program each byte
359       for (i = 0; i < buffer_cnt; i++)
360       {
361          if (owProgramByte(portnum,construct_buffer[i], start_address + i,
362              0x0F, crc_type, do_access) != construct_buffer[i])
363          {
364             OWERROR(OWERROR_PROGRAM_BYTE_FAILED);
365             return FALSE;
366          }
367          do_access = FALSE;
368       }
369       return TRUE;
370    }
371 }
372 
373 //--------------------------------------------------------------------------
374 // Write a byte to an EPROM 1-Wire device.
375 //
376 // Supported devices: crc_type=0(CRC8)
377 //                        DS1982
378 //                    crc_type=1(CRC16)
379 //                        DS1985, DS1986, DS2407
380 //
381 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
382 //                indicate the symbolic port number.
383 // 'write_byte' - byte to program
384 // 'addr'       - address of byte to program
385 // 'write_cmd'  - command used to write (0x0F reg mem, 0x55 status)
386 // 'crc_type'   - CRC used (0 CRC8, 1 CRC16)
387 // 'do_access'  - Flag to access device for each byte
388 //                (0 skip access, 1 do the access)
389 //                WARNING, only use do_access=0 if programing the NEXT
390 //                byte immediatly after the previous byte.
391 //
392 // Returns: >=0   success, this is the resulting byte from the program
393 //                effort
394 //          -1    error, device not connected or program pulse voltage
395 //                not available
396 //
owProgramByte(int portnum,SMALLINT write_byte,int addr,SMALLINT write_cmd,SMALLINT crc_type,SMALLINT do_access)397 SMALLINT owProgramByte(int portnum, SMALLINT write_byte, int addr, SMALLINT write_cmd,
398                     SMALLINT crc_type, SMALLINT do_access)
399 {
400    ushort lastcrc16;
401    uchar lastcrc8;
402 
403    // optionally access the device
404    if (do_access)
405    {
406       if (!owAccess(portnum))
407       {
408          OWERROR(OWERROR_ACCESS_FAILED);
409          return -1;
410       }
411 
412       // send the write command
413       if (!owWriteByte(portnum,write_cmd))
414       {
415          OWERROR(OWERROR_WRITE_BYTE_FAILED);
416          return -1;
417       }
418 
419       // send the address
420       if (!owWriteByte(portnum,addr & 0xFF) || !owWriteByte(portnum,addr >> 8))
421       {
422          OWERROR(OWERROR_WRITE_BYTE_FAILED);
423          return -1;
424       }
425    }
426 
427    // send the data to write
428    if (!owWriteByte(portnum,write_byte))
429    {
430       OWERROR(OWERROR_WRITE_BYTE_FAILED);
431       return -1;
432    }
433 
434    // read the CRC
435    if (crc_type == 0)
436    {
437       // calculate CRC8
438       if (do_access)
439       {
440          setcrc8(portnum,0);
441          docrc8(portnum,(uchar)write_cmd);
442          docrc8(portnum,(uchar)(addr & 0xFF));
443          docrc8(portnum,(uchar)(addr >> 8));
444       }
445       else
446          setcrc8(portnum,(uchar)(addr & 0xFF));
447 
448       docrc8(portnum,(uchar)write_byte);
449       // read and calculate the read crc
450       lastcrc8 = docrc8(portnum,(uchar)owReadByte(portnum));
451       // crc should now be 0x00
452       if (lastcrc8 != 0)
453       {
454          OWERROR(OWERROR_CRC_FAILED);
455          return -1;
456       }
457    }
458    else
459    {
460       // CRC16
461       if (do_access)
462       {
463          setcrc16(portnum,0);
464          docrc16(portnum,(ushort)write_cmd);
465          docrc16(portnum,(ushort)(addr & 0xFF));
466          docrc16(portnum,(ushort)(addr >> 8));
467       }
468       else
469          setcrc16(portnum,(ushort)addr);
470       docrc16(portnum,(ushort)write_byte);
471       // read and calculate the read crc
472       docrc16(portnum,(ushort)owReadByte(portnum));
473       lastcrc16 = docrc16(portnum,(ushort)owReadByte(portnum));
474       // crc should now be 0xB001
475       if (lastcrc16 != 0xB001)
476       {
477          OWERROR(OWERROR_CRC_FAILED);
478          return -1;
479       }
480    }
481 
482    // send the program pulse
483    if (!owProgramPulse(portnum))
484    {
485       OWERROR(OWERROR_PROGRAM_PULSE_FAILED);
486       return -1;
487    }
488 
489    // read back and return the resulting byte
490    return owReadByte(portnum);
491 }
492 
493 //--------------------------------------------------------------------------
494 // Write the scratchpad of a standard NVRam device such as the DS1992,3,4
495 // and verify its contents.
496 //
497 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
498 //                indicate the symbolic port number.
499 // 'write_buf'  - pointer to buffer containing data to write
500 // 'start_page'    - page number to write packet to
501 // 'write_len'  - number of data byte in write_buf
502 //
503 // Returns: TRUE(1)  success, the data was written and verified
504 //          FALSE(0) failure, the data could not be written
505 //
506 //
Write_Scratchpad(int portnum,uchar * write_buf,int start_page,SMALLINT write_len)507 SMALLINT Write_Scratchpad(int portnum, uchar *write_buf, int start_page, SMALLINT write_len)
508 {
509    uchar i,sendlen=0;
510    uchar sendpacket[50];
511 
512    // match command
513    sendpacket[sendlen++] = 0x55;
514    for (i = 0; i < 8; i++)
515       sendpacket[sendlen++] = SerialNum[portnum][i];
516    // write scratchpad command
517    sendpacket[sendlen++] = 0x0F;
518    // write the target address
519    sendpacket[sendlen++] = ((start_page << 5) & 0xFF);
520    sendpacket[sendlen++] = (start_page >> 3);
521 
522    // write packet bytes
523    for (i = 0; i < write_len; i++)
524       sendpacket[sendlen++] = write_buf[i];
525 
526    // send/recieve the transfer buffer
527    if (owBlock(portnum,TRUE,sendpacket,sendlen))
528    {
529       // now attempt to read back to check
530       sendlen = 0;
531       // match command
532       sendpacket[sendlen++] = 0x55;
533       for (i = 0; i < 8; i++)
534          sendpacket[sendlen++] = SerialNum[portnum][i];
535       // read scratchpad command
536       sendpacket[sendlen++] = 0xAA;
537       // read the target address, offset and data
538       for (i = 0; i < (write_len + 3); i++)
539          sendpacket[sendlen++] = 0xFF;
540 
541       // send/recieve the transfer buffer
542       if (owBlock(portnum,TRUE,sendpacket,sendlen))
543       {
544          // check address and offset of scratchpad read
545          if ((sendpacket[10] != ((start_page << 5) & 0xFF)) ||
546              (sendpacket[11] != (start_page >> 3)) ||
547              (sendpacket[12] != (write_len - 1)))
548          {
549             OWERROR(OWERROR_READ_VERIFY_FAILED);
550             return FALSE;
551          }
552 
553          // verify each data byte
554          for (i = 0; i < write_len; i++)
555             if (sendpacket[i+13] != write_buf[i])
556             {
557                OWERROR(OWERROR_WRITE_VERIFY_FAILED);
558                return FALSE;
559             }
560 
561          // must have verified
562          return TRUE;
563       }
564       else
565          OWERROR(OWERROR_BLOCK_FAILED);
566    }
567    else
568       OWERROR(OWERROR_BLOCK_FAILED);
569 
570    // failed a block tranfer
571    return FALSE;
572 }
573 
574 //--------------------------------------------------------------------------
575 // Copy the contents of the scratchpad to its intended nv ram page.  The
576 // page and length of the data is needed to build the authorization bytes
577 // to copy.
578 //
579 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
580 //                indicate the symbolic port number.
581 // 'start_page' - page number to write packet to
582 // 'write_len'  - number of data bytes that are being copied
583 //
584 // Returns: TRUE(1)  success
585 //          FALSE(0) failure
586 //
Copy_Scratchpad(int portnum,int start_page,SMALLINT write_len)587 SMALLINT Copy_Scratchpad(int portnum, int start_page, SMALLINT write_len)
588 {
589    uchar i,sendlen=0;
590    uchar sendpacket[50];
591 
592    // match command
593    sendpacket[sendlen++] = 0x55;
594    for (i = 0; i < 8; i++)
595       sendpacket[sendlen++] = SerialNum[portnum][i];
596    // copy scratchpad command
597    sendpacket[sendlen++] = 0x55;
598    // write the target address
599    sendpacket[sendlen++] = ((start_page << 5) & 0xFF);
600    sendpacket[sendlen++] = (start_page >> 3);
601    sendpacket[sendlen++] = write_len - 1;
602    // read copy result
603    sendpacket[sendlen++] = 0xFF;
604 
605    // send/recieve the transfer buffer
606    if (owBlock(portnum,TRUE,sendpacket,sendlen))
607    {
608       // check address and offset of scratchpad read
609       if ((sendpacket[10] != ((start_page << 5) & 0xFF)) ||
610           (sendpacket[11] != (start_page >> 3)) ||
611           (sendpacket[12] != (write_len - 1)) ||
612           (sendpacket[13] & 0xF0))
613       {
614          OWERROR(OWERROR_READ_VERIFY_FAILED);
615          return FALSE;
616       }
617       else
618          return TRUE;
619    }
620    else
621       OWERROR(OWERROR_BLOCK_FAILED);
622 
623    // failed a block tranfer
624    return FALSE;
625 }
626 
627