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