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