441df0e5937ba6c5ccb59431c0beaff81c3821f6
[fw/sdcc] / device / examples / ds390 / ow390 / owtrnu.c
1 #define DEBUG_OW_TRNU 0
2 #if DEBUG_OW_TRNU
3 #include <stdio.h>
4 #endif
5 //---------------------------------------------------------------------------
6 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
7 // 
8 // Permission is hereby granted, free of charge, to any person obtaining a 
9 // copy of this software and associated documentation files (the "Software"), 
10 // to deal in the Software without restriction, including without limitation 
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 
12 // and/or sell copies of the Software, and to permit persons to whom the 
13 // Software is furnished to do so, subject to the following conditions:
14 // 
15 // The above copyright notice and this permission notice shall be included 
16 // in all copies or substantial portions of the Software.
17 // 
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
19 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
20 // MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
21 // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES 
22 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
23 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
24 // OTHER DEALINGS IN THE SOFTWARE.
25 // 
26 // Except as contained in this notice, the name of Dallas Semiconductor 
27 // shall not be used except as stated in the Dallas Semiconductor 
28 // Branding Policy. 
29 //---------------------------------------------------------------------------
30 //
31 //  owTranU.C - Transport functions for 1-Wire Net
32 //              using the DS2480 (U) serial interface chip.
33 //
34 //  Version: 2.00
35 //
36 //  History: 1.02 -> 1.03  Removed caps in #includes for Linux capatibility
37 //           1.03 -> 2.00  Changed 'MLan' to 'ow'. Added support for 
38 //                         multiple ports.  
39 //
40
41 #include "ownet.h"
42 #include "ds2480.h"
43
44 // local functions       
45 static int Write_Scratchpad(int,uchar *,int,int);
46 static int Copy_Scratchpad(int,int,int);
47
48 //--------------------------------------------------------------------------
49 // The 'owBlock' transfers a block of data to and from the 
50 // 1-Wire Net with an optional reset at the begining of communication.
51 // The result is returned in the same buffer.
52 //
53 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number is provided to
54 //              indicate the symbolic port number.
55 // 'do_reset' - cause a owTouchReset to occure at the begining of 
56 //              communication TRUE(1) or not FALSE(0)
57 // 'tran_buf' - pointer to a block of unsigned
58 //              chars of length 'tran_len' that will be sent 
59 //              to the 1-Wire Net
60 // 'tran_len' - length in bytes to transfer
61
62 // Supported devices: all 
63 //
64 // Returns:   TRUE (1) : The optional reset returned a valid 
65 //                       presence (do_reset == TRUE) or there
66 //                       was no reset required.
67 //            FALSE (0): The reset did not return a valid prsence
68 //                       (do_reset == TRUE).
69 //
70 //  The maximum tran_length is 64
71 //
72 int owBlock(int portnum, int do_reset, uchar *tran_buf, int tran_len)
73 {
74    uchar sendpacket[150];
75    int sendlen=0,pos,i;
76
77    // check for a block too big
78    if (tran_len > 64)
79       return FALSE;
80
81    // check if need to do a owTouchReset first
82    if (do_reset)
83    {
84       if (!owTouchReset(portnum))
85          return FALSE;
86    }  
87
88    // construct the packet to send to the DS2480
89    // check if correct mode 
90    if (UMode[portnum] != MODSEL_DATA)
91    {
92       UMode[portnum] = MODSEL_DATA;
93       sendpacket[sendlen++] = MODE_DATA;
94    }
95
96    // add the bytes to send
97    pos = sendlen;
98    for (i = 0; i < tran_len; i++)
99    {
100       sendpacket[sendlen++] = tran_buf[i];
101
102       // check for duplication of data that looks like COMMAND mode 
103       if (tran_buf[i] == MODE_COMMAND) 
104          sendpacket[sendlen++] = tran_buf[i];
105    }
106
107    // flush the buffers
108    FlushCOM(portnum);
109
110    // send the packet 
111    if (WriteCOM(portnum,sendlen,sendpacket)) 
112    {
113       // read back the response 
114      if (ReadCOM(portnum,tran_len,tran_buf) == tran_len) {
115        return TRUE;
116      }
117    }
118
119    // an error occured so re-sync with DS2480
120    DS2480Detect(portnum);
121
122    return FALSE;
123 }
124   
125 //--------------------------------------------------------------------------
126 // Read a Universal Data Packet from a standard NVRAM iButton 
127 // and return it in the provided buffer. The page that the 
128 // packet resides on is 'start_page'.  Note that this function is limited 
129 // to single page packets. The buffer 'read_buf' must be at least 
130 // 29 bytes long.  
131 //
132 // The Universal Data Packet always start on page boundaries but 
133 // can end anywhere.  The length is the number of data bytes not 
134 // including the length byte and the CRC16 bytes.  There is one 
135 // length byte. The CRC16 is first initialized to the starting 
136 // page number.  This provides a check to verify the page that 
137 // was intended is being read.  The CRC16 is then calculated over 
138 // the length and data bytes.  The CRC16 is then inverted and stored 
139 // low byte first followed by the high byte. 
140 //
141 // Supported devices: DS1992, DS1993, DS1994, DS1995, DS1996, DS1982, 
142 //                    DS1985, DS1986, DS2407, and DS1971. 
143 //
144 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
145 //                indicate the symbolic port number.
146 // 'do_access'  - flag to indicate if an 'owAccess' should be
147 //                peformed at the begining of the read.  This may
148 //                be FALSE (0) if the previous call was to read the
149 //                previous page (start_page-1).
150 // 'start_page' - page number to start the read from 
151 // 'read_buf'   - pointer to a location to store the data read
152 //
153 // Returns:  >=0 success, number of data bytes in the buffer
154 //           -1  failed to read a valid UDP 
155 //     
156 //
157 int owReadPacketStd(int portnum, int do_access, int start_page, uchar *read_buf)
158 {
159    int i,length,sendlen=0,head_len=0;
160    uchar sendpacket[50];
161    ushort lastcrc16;
162
163 #if DEBUG_OW_TRNU
164    printf ("owReadPacketStd: %d %d\n", do_access, start_page);
165 #endif
166    // check if access header is done 
167    // (only use if in sequention read with one access at begining)
168    if (do_access)
169    {
170       // match command
171       sendpacket[sendlen++] = 0x55;    
172       for (i = 0; i < 8; i++)
173          sendpacket[sendlen++] = SerialNum[portnum][i];
174       // read memory command
175       sendpacket[sendlen++] = 0xF0;     
176       // write the target address
177       sendpacket[sendlen++] = ((start_page << 5) & 0xFF);    
178       sendpacket[sendlen++] = (start_page >> 3);
179       // check for DS1982 exception (redirection byte)
180       if (SerialNum[portnum][0] == 0x09)
181          sendpacket[sendlen++] = 0xFF;
182       // record the header length
183       head_len = sendlen;
184    }
185    // read the entire page length byte
186    for (i = 0; i < 32; i++)      
187       sendpacket[sendlen++] = 0xFF;   
188
189    // send/recieve the transfer buffer   
190    if (owBlock(portnum,do_access,sendpacket,sendlen))
191    {
192       // seed crc with page number
193       setcrc16(portnum,(ushort)start_page);               
194
195       // attempt to read UDP from sendpacket
196       length = sendpacket[head_len];            
197       docrc16(portnum,(ushort)length);
198
199       // verify length is not too large
200       if (length <= 29)                
201       {
202          // loop to read packet including CRC
203          for (i = 0; i < length; i++)     
204          {
205              read_buf[i] = sendpacket[i+1+head_len];
206              docrc16(portnum,read_buf[i]);           
207          }
208             
209          // read and compute the CRC16 
210          docrc16(portnum,sendpacket[i+1+head_len]);
211          lastcrc16 = docrc16(portnum,sendpacket[i+2+head_len]);
212          
213          // verify the CRC16 is correct           
214          if (lastcrc16 == 0xB001) 
215            return length;        // return number of byte in record
216 #if DEBUG_OW_TRNU
217          printf ("owReadPacketStd: crc error in page %d\n", start_page);
218 #endif
219       }  
220    }
221 #if DEBUG_OW_TRNU
222    printf ("owReadPacketStd: block>29 : %d\n", length);
223 #endif
224    // failed block or incorrect CRC
225    return -1;
226 }
227
228 //--------------------------------------------------------------------------
229 // Write a Universal Data Packet onto a standard NVRAM 1-Wire device
230 // on page 'start_page'.  This function is limited to UDPs that
231 // fit on one page.  The data to write is provided as a buffer
232 // 'write_buf' with a length 'write_len'.
233 //
234 // The Universal Data Packet always start on page boundaries but 
235 // can end anywhere.  The length is the number of data bytes not 
236 // including the length byte and the CRC16 bytes.  There is one 
237 // length byte. The CRC16 is first initialized to the starting 
238 // page number.  This provides a check to verify the page that 
239 // was intended is being read.  The CRC16 is then calculated over 
240 // the length and data bytes.  The CRC16 is then inverted and stored 
241 // low byte first followed by the high byte. 
242 //
243 // Supported devices: is_eprom=0 
244 //                        DS1992, DS1993, DS1994, DS1995, DS1996
245 //                    is_eprom=1, crc_type=0(CRC8)
246 //                        DS1982
247 //                    is_eprom=1, crc_type=1(CRC16) 
248 //                        DS1985, DS1986, DS2407 
249 //
250 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
251 //                indicate the symbolic port number.
252 // 'start_page' - page number to write packet to
253 // 'write_buf'  - pointer to buffer containing data to write
254 // 'write_len'  - number of data byte in write_buf
255 // 'is_eprom'   - flag set if device is an EPROM (1 EPROM, 0 NVRAM)
256 // 'crc_type'   - if is_eprom=1 then indicates CRC type 
257 //                (0 CRC8, 1 CRC16)
258 //
259 // Returns: TRUE(1)  success, packet written
260 //          FALSE(0) failure to write, contact lost or device locked
261 //
262 //
263 int owWritePacketStd(int portnum, int start_page, uchar *write_buf, 
264                        int write_len, int is_eprom, int crc_type)
265 {
266    uchar construct_buffer[32];
267    int i,buffer_cnt=0,start_address,do_access;
268    ushort lastcrc16;
269
270 #if DEBUG_OW_TRNU
271    printf ("owWritePacketStd: %d %d\n", start_page, write_len);
272 #endif
273    // check to see if data too long to fit on device
274    if (write_len > 29) {
275 #if DEBUG_OW_TRNU
276      printf ("owWritePacketStd: too long\n");
277 #endif
278      return FALSE;
279    }
280               
281    // seed crc with page number           
282    setcrc16(portnum,(ushort)start_page); 
283       
284    // set length byte
285    construct_buffer[buffer_cnt++] = (uchar)(write_len);
286    docrc16(portnum,(ushort)write_len);
287       
288    // fill in the data to write
289    for (i = 0; i < write_len; i++)
290    {
291      lastcrc16 = docrc16(portnum,write_buf[i]);
292      construct_buffer[buffer_cnt++] = write_buf[i];
293    }  
294       
295    // add the crc
296    construct_buffer[buffer_cnt++] = (uchar)(~(lastcrc16 & 0xFF));
297    construct_buffer[buffer_cnt++] = (uchar)(~((lastcrc16 & 0xFF00) >> 8));
298    
299    // check if not EPROM                 
300    if (!is_eprom)
301    {
302       // write the page
303      if (!Write_Scratchpad(portnum,construct_buffer,start_page,buffer_cnt)) {
304 #if DEBUG_OW_TRNU
305        printf ("owWritePacketStd: couldn't Write_Scratchpad\n");
306 #endif
307        return FALSE;
308      }
309    
310       // copy the scratchpad            
311      if (!Copy_Scratchpad(portnum,start_page,buffer_cnt)) {
312 #if DEBUG_OW_TRNU
313        printf ("owWritePacketStd: couldn't Copy_Scratchpad\n");
314 #endif
315        return FALSE;
316      }
317      
318       // copy scratch pad was good then success
319       return TRUE;
320    }
321    // is EPROM
322    else
323    {  
324       // calculate the start address
325       start_address = ((start_page >> 3) << 8) | ((start_page << 5) & 0xFF);
326       do_access = TRUE;
327       // loop to program each byte
328       for (i = 0; i < buffer_cnt; i++)
329       {
330          if (owProgramByte(portnum,construct_buffer[i], start_address + i, 
331              0x0F, crc_type, do_access) != construct_buffer[i])
332             return FALSE;
333          do_access = FALSE;
334       }
335       return TRUE;
336    }
337 }
338
339 //--------------------------------------------------------------------------
340 // Write a byte to an EPROM 1-Wire device.
341 //
342 // Supported devices: crc_type=0(CRC8)
343 //                        DS1982
344 //                    crc_type=1(CRC16) 
345 //                        DS1985, DS1986, DS2407 
346 //
347 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
348 //                indicate the symbolic port number.
349 // 'write_byte' - byte to program
350 // 'addr'       - address of byte to program
351 // 'write_cmd'  - command used to write (0x0F reg mem, 0x55 status)
352 // 'crc_type'   - CRC used (0 CRC8, 1 CRC16)
353 // 'do_access'  - Flag to access device for each byte 
354 //                (0 skip access, 1 do the access)
355 //                WARNING, only use do_access=0 if programing the NEXT
356 //                byte immediatly after the previous byte.
357 //
358 // Returns: >=0   success, this is the resulting byte from the program
359 //                effort
360 //          -1    error, device not connected or program pulse voltage
361 //                not available
362 //
363 int owProgramByte(int portnum, int write_byte, int addr, int write_cmd, 
364                     int crc_type, int do_access)
365 {                                
366    ushort lastcrc16;
367    uchar lastcrc8;
368
369    // optionally access the device
370    if (do_access)
371    {
372       if (!owAccess(portnum))
373          return -1;
374
375       // send the write command
376       if (!owWriteByte(portnum,write_cmd))
377          return -1;
378
379       // send the address
380       if (!owWriteByte(portnum,addr & 0xFF))
381          return -1;
382       if (!owWriteByte(portnum,addr >> 8))
383          return -1;
384    }
385
386    // send the data to write
387    if (!owWriteByte(portnum,write_byte))
388       return -1;
389
390    // read the CRC
391    if (crc_type == 0)
392    {
393       // calculate CRC8
394       if (do_access)
395       {
396          setcrc8(portnum,0);
397          docrc8(portnum,(uchar)write_cmd);
398          docrc8(portnum,(uchar)(addr & 0xFF));
399          docrc8(portnum,(uchar)(addr >> 8));
400       }
401       else
402          setcrc8(portnum,(uchar)(addr & 0xFF));
403
404       docrc8(portnum,(uchar)write_byte);
405       // read and calculate the read crc
406       lastcrc8 = docrc8(portnum,(uchar)owReadByte(portnum));
407       // crc should now be 0x00
408       if (lastcrc8 != 0)
409          return -1;
410    }
411    else
412    {
413       // CRC16
414       if (do_access)
415       {
416          setcrc16(portnum,0);
417          docrc16(portnum,(ushort)write_cmd);
418          docrc16(portnum,(ushort)(addr & 0xFF));
419          docrc16(portnum,(ushort)(addr >> 8));
420       }
421       else
422          setcrc16(portnum,(ushort)addr);
423       docrc16(portnum,(ushort)write_byte);
424       // read and calculate the read crc
425       docrc16(portnum,(ushort)owReadByte(portnum));
426       lastcrc16 = docrc16(portnum,(ushort)owReadByte(portnum));
427       // crc should now be 0xB001
428       if (lastcrc16 != 0xB001)
429          return -1;
430    }
431
432    // send the program pulse
433    if (!owProgramPulse(portnum))
434       return -1;
435
436    // read back and return the resulting byte   
437    return owReadByte(portnum);
438 }
439
440 //--------------------------------------------------------------------------
441 // Write the scratchpad of a standard NVRam device such as the DS1992,3,4
442 // and verify its contents. 
443 //
444 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
445 //                indicate the symbolic port number.
446 // 'write_buf'  - pointer to buffer containing data to write
447 // 'start_page'    - page number to write packet to
448 // 'write_len'  - number of data byte in write_buf
449 //
450 // Returns: TRUE(1)  success, the data was written and verified
451 //          FALSE(0) failure, the data could not be written
452 // 
453 //
454 int Write_Scratchpad(int portnum, uchar *write_buf, int start_page, int write_len)
455 {
456    int i,sendlen=0;
457    uchar sendpacket[50];
458    
459 #if DEBUG_OW_TRNU
460    printf ("Write_Scratchpad: %d %d\n", start_page, write_len);
461 #endif
462    // match command
463    sendpacket[sendlen++] = 0x55;    
464    for (i = 0; i < 8; i++)
465       sendpacket[sendlen++] = SerialNum[portnum][i];
466    // write scratchpad command
467    sendpacket[sendlen++] = 0x0F;     
468    // write the target address
469    sendpacket[sendlen++] = ((start_page << 5) & 0xFF);    
470    sendpacket[sendlen++] = (start_page >> 3);
471
472    // write packet bytes 
473    for (i = 0; i < write_len; i++)
474       sendpacket[sendlen++] = write_buf[i];
475    
476    // send/recieve the transfer buffer   
477    if (owBlock(portnum,TRUE,sendpacket,sendlen))
478    {
479       // now attempt to read back to check
480       sendlen = 0;
481       // match command
482       sendpacket[sendlen++] = 0x55;    
483       for (i = 0; i < 8; i++)
484          sendpacket[sendlen++] = SerialNum[portnum][i];
485       // read scratchpad command
486       sendpacket[sendlen++] = 0xAA;     
487       // read the target address, offset and data
488       for (i = 0; i < (write_len + 3); i++)
489          sendpacket[sendlen++] = 0xFF;
490    
491       // send/recieve the transfer buffer   
492       if (owBlock(portnum,TRUE,sendpacket,sendlen))
493       {
494          // check address and offset of scratchpad read
495         if ((sendpacket[10] != (int)((start_page << 5) & 0xFF)) ||
496             (sendpacket[11] != (int)(start_page >> 3)) ||
497             (sendpacket[12] != (int)(write_len - 1))) {
498 #if DEBUG_OW_TRNU
499            printf ("\nWrite_Scratchpad: check failed\n");
500 #endif
501            //return FALSE;
502          }
503
504          // verify each data byte
505          for (i = 0; i < write_len; i++)
506            if (sendpacket[i+13] != write_buf[i]) {
507 #if DEBUG_OW_TRNU
508              printf ("\nWrite_Scratchpad: data check failed\n");
509 #endif
510              return FALSE;
511            }
512
513          // must have verified
514          return TRUE;
515       }
516    } 
517 #if DEBUG_OW_TRNU
518    printf ("\nWrite_Scratchpad: owBlock failed\n");
519 #endif
520    
521    // failed a block tranfer
522    return FALSE;
523 }
524
525 //--------------------------------------------------------------------------
526 // Copy the contents of the scratchpad to its intended nv ram page.  The
527 // page and length of the data is needed to build the authorization bytes
528 // to copy.
529 //
530 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
531 //                indicate the symbolic port number.
532 // 'start_page' - page number to write packet to
533 // 'write_len'  - number of data bytes that are being copied
534 //
535 // Returns: TRUE(1)  success
536 //          FALSE(0) failure
537 //
538 int Copy_Scratchpad(int portnum, int start_page, int write_len)
539 {
540    int i,sendlen=0;
541    uchar sendpacket[50];
542
543 #if DEBUG_OW_TRNU
544    printf ("Copy_Scratchpad: %d %d\n", start_page, write_len);
545 #endif
546    
547    // match command
548    sendpacket[sendlen++] = 0x55;    
549    for (i = 0; i < 8; i++)
550       sendpacket[sendlen++] = SerialNum[portnum][i];
551    // copy scratchpad command
552    sendpacket[sendlen++] = 0x55;     
553    // write the target address
554    sendpacket[sendlen++] = ((start_page << 5) & 0xFF);    
555    sendpacket[sendlen++] = (start_page >> 3);
556    sendpacket[sendlen++] = write_len - 1;
557    // read copy result
558    sendpacket[sendlen++] = 0xFF;
559    
560 #if DEBUG_OW_TRNU
561    printf ("Copy_Scratchpad: %d, %02x %02x %02x %02x\n", sendlen,
562            sendpacket[10],sendpacket[11],sendpacket[12],sendpacket[13]);
563 #endif
564    // send/recieve the transfer buffer   
565    if (owBlock(portnum,TRUE,sendpacket,sendlen))
566    {
567       // check address and offset of scratchpad read
568       if ((sendpacket[10] != (int)((start_page << 5) & 0xFF)) ||
569           (sendpacket[11] != (int)(start_page >> 3)) ||
570           (sendpacket[12] != (int)(write_len - 1)) ||
571           (sendpacket[13] & 0xF0)) {
572 #if DEBUG_OW_TRNU
573         printf ("Copy_Scratchpad: %d, check failed: %02x %02x %02x %02x\n",
574                 sendlen,
575                 sendpacket[10],sendpacket[11],sendpacket[12],sendpacket[13]);
576 #endif
577         return FALSE;
578       }
579       else {
580 #if DEBUG_OW_TRNU
581         printf ("Copy_Scratchpad: %02x %02x %02x %02x\n",
582                 sendpacket[10],sendpacket[11],sendpacket[12],sendpacket[13]);
583 #endif
584          return TRUE;   
585       }
586    }
587 #if DEBUG_OW_TRNU
588    printf ("Copy_Scratchpad: owBlock failed\n");
589 #endif
590    // failed a block tranfer
591    return FALSE;
592 }
593