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 // mbEPROM.c - Include memory bank EPROM functions.
28 //
29 // Version: 2.10
30 //
31
32 // Include Files
33 #include "ownet.h"
34 #include "mbeprom.h"
35
36 // External functions
37 extern SMALLINT owBlock(int,int,uchar *,int);
38 extern SMALLINT owReadByte(int);
39 extern SMALLINT owWriteByte(int,int);
40 extern void output_status(int, char *);
41 extern void msDelay(int);
42 extern void owSerialNum(int,uchar *,int);
43 extern SMALLINT owAccess(int);
44 extern SMALLINT owWriteByte(int,int);
45 extern void setcrc16(int,ushort);
46 extern ushort docrc16(int,ushort);
47 extern void setcrc8(int,uchar);
48 extern uchar docrc8(int,uchar);
49 extern SMALLINT owWriteBytePower(int,int);
50 extern SMALLINT owLevel(int,int);
51 extern SMALLINT owProgramByte(int,SMALLINT,int,SMALLINT,SMALLINT,SMALLINT);
52 extern SMALLINT owHasProgramPulse(int);
53
54 // general command defines
55 #define READ_MEMORY_COMMAND_EPROM 0xF0
56 #define MAIN_READ_PAGE_COMMAND_EPROM 0xA5
57 #define STATUS_READ_PAGE_COMMAND_EPROM 0xAA
58 #define MAIN_WRITE_COMMAND_EPROM 0x0F
59 #define STATUS_WRITE_COMMAND_EPROM 0x55
60
61 // Local defines
62 #define SIZE_EPROM 2048
63 #define PAGE_LENGTH_EPROM 32
64
65 // Local functions
66 uchar writeMemCmd(SMALLINT bank, uchar *SNum);
67 SMALLINT numCRCbytes(SMALLINT bank, uchar *SNum);
68 SMALLINT writeVerify(SMALLINT bank, int portnum, uchar *SNum, int page);
69 SMALLINT crcAfterAdd(SMALLINT bank, uchar *SNum);
70 uchar readPageWithCRC(SMALLINT bank, uchar *SNum);
71 SMALLINT isRedirectPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page);
72 SMALLINT lockRedirectPage(SMALLINT bank, int portnum, uchar *SNum, int page);
73 SMALLINT getRedirectedPage(SMALLINT bank, int portnum, uchar *SNum, int page);
74 SMALLINT redirectPage(SMALLINT bank, int portnum, uchar *SNum, int page, int newPage);
75 SMALLINT isPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page);
76 SMALLINT lockPage(SMALLINT bank, int portnum, uchar *SNum, int page);
77 SMALLINT redirectOffset(SMALLINT bank, uchar *SNum);
78
79 // Global variables
80 char *bankDescription_eprom = "Main Memory";
81 SMALLINT writeVerification_eprom = TRUE;
82 SMALLINT generalPurposeMemory_eprom = TRUE;
83 SMALLINT readWrite_eprom = FALSE;
84 SMALLINT writeOnce_eprom = TRUE;
85 SMALLINT readOnly_eprom = FALSE;
86 SMALLINT nonVolatile_eprom = TRUE;
87 SMALLINT needsProgramPulse_eprom = TRUE;
88 SMALLINT needsPowerDelivery_eprom = FALSE;
89 SMALLINT hasExtraInfo_eprom = TRUE;
90 SMALLINT extraInfoLength_eprom = 1;
91 char *extraInfoDesc_eprom = "Inverted redirection page";
92 SMALLINT pageAutoCRC_eprom = TRUE;
93 SMALLINT lockOffset = 0;
94 SMALLINT lockRedirectOffset = 0;
95 SMALLINT canredirectPage = FALSE;
96 SMALLINT canlockPage = FALSE;
97 SMALLINT canlockRedirectPage = FALSE;
98 SMALLINT numPages = 64;
99 SMALLINT CRCbytes = 2;
100
101
102 /**
103 * Read memory in the current bank with no CRC checking (device or
104 * data). The resulting data from this API may or may not be what is on
105 * the 1-Wire device. It is recommends that the data contain some kind
106 * of checking (CRC) like in the readPagePacketEPROM() method or have
107 * the 1-Wire device provide the CRC as in readPageCRCEPROM(). readPageCRCEPROM()
108 * however is not supported on all memory types, see 'hasPageAutoCRCEPROM()'.
109 * If neither is an option then this method could be called more
110 * then once to at least verify that the same thing is read consistantly.
111 *
112 * bank to tell what memory bank of the ibutton to use.
113 * portnum the port number of the port being used for the
114 * 1-Wire Network.
115 * SNum the serial number for the part that the read is
116 * to be done on.
117 * str_add starting physical address
118 * rd_cont if 'true' then device read is continued without
119 * re-selecting. This can only be used if the new
120 * read() continious where the last one led off
121 * and it is inside a 'beginExclusive/endExclusive'
122 * block.
123 * buff byte array to place read data into
124 * len length in bytes to read
125 *
126 * @return 'true' if the read was complete
127 */
readEPROM(SMALLINT bank,int portnum,uchar * SNum,int str_add,SMALLINT rd_cont,uchar * buff,int len)128 SMALLINT readEPROM(SMALLINT bank, int portnum, uchar *SNum, int str_add,
129 SMALLINT rd_cont, uchar *buff, int len)
130 {
131 int i;
132 int start_pg, end_pg, num_bytes, pg;
133 uchar raw_buf[256];
134
135 // check if read exceeds memory
136 if ((str_add + len) > getSizeEPROM(bank,SNum))
137 {
138 OWERROR(OWERROR_READ_OUT_OF_RANGE);
139 return FALSE;
140 }
141
142 // check if status memory
143 if(readPageWithCRC(bank,SNum) == STATUS_READ_PAGE_COMMAND_EPROM)
144 {
145 // no regular read memory so must use readPageCRC
146 start_pg = str_add / getPageLengthEPROM(bank,SNum);
147 end_pg = ((str_add + len) / getPageLengthEPROM(bank,SNum)) - 1;
148
149 if (((str_add + len) % getPageLengthEPROM(bank,SNum)) > 0)
150 end_pg++;
151
152 // loop to read the pages
153 for (pg = start_pg; pg <= end_pg; pg++)
154 readPageCRCEPROM(bank,portnum,SNum,pg,
155 &raw_buf[(pg-start_pg)*getPageLengthEPROM(bank,SNum)]);
156
157 // extract out the data
158 for(i=0;i<len;i++)
159 buff[i] = raw_buf[i];
160 }
161 // regular memory so use standard read memory command
162 else
163 {
164
165 // see if need to access the device
166 if (!rd_cont)
167 {
168
169 // select the device
170 if (!owAccess(portnum))
171 {
172 OWERROR(OWERROR_DEVICE_SELECT_FAIL);
173 return FALSE;
174 }
175
176 // build start reading memory block
177 raw_buf[0] = READ_MEMORY_COMMAND_EPROM;
178 raw_buf[1] = (str_add + getStartingAddressEPROM(bank,SNum)) & 0xFF;
179 raw_buf[2] = (((str_add + getStartingAddressEPROM(bank,SNum)) & 0xFFFF) >> 8)
180 & 0xFF;
181 raw_buf[3] = 0xFF;
182
183 // check if get a 1 byte crc in a normal read.
184 if(SNum[0] == 0x09)
185 num_bytes = 4;
186 else
187 num_bytes = 3;
188
189 // do the first block for command, address
190 if(!owBlock(portnum,FALSE,raw_buf,num_bytes))
191 {
192 OWERROR(OWERROR_BLOCK_FAILED);
193 return FALSE;
194 }
195 }
196
197 // pre-fill readBuf with 0xFF
198 for (i=0;i<len;i++)
199 buff[i] = 0xFF;
200
201 // send second block to read data, return result
202 if(!owBlock(portnum,FALSE,buff,len))
203 {
204 OWERROR(OWERROR_DEVICE_SELECT_FAIL);
205 return FALSE;
206 }
207 }
208
209 return TRUE;
210 }
211
212 /**
213 * Write memory in the current bank. It is recommended that
214 * when writing data that some structure in the data is created
215 * to provide error free reading back with readEPROM(). Or the
216 * method 'writePagePacketEPROM()' could be used which automatically
217 * wraps the data in a length and CRC.
218 *
219 * When using on Write-Once devices care must be taken to write into
220 * into empty space. If write() is used to write over an unlocked
221 * page on a Write-Once device it will fail.
222 *
223 * bank to tell what memory bank of the ibutton to use.
224 * portnum the port number of the port being used for the
225 * 1-Wire Network.
226 * SNum the serial number for the part that the write is
227 * to be done on.
228 * str_add starting address
229 * buff byte array containing data to write
230 * len length in bytes to write
231 *
232 * @return 'true' if the write was complete.
233 */
writeEPROM(SMALLINT bank,int portnum,uchar * SNum,int str_add,uchar * buff,int len)234 SMALLINT writeEPROM(SMALLINT bank, int portnum, uchar *SNum, int str_add,
235 uchar *buff, int len)
236 {
237 int i;
238 int result;
239 SMALLINT write_continue;
240 int crc_type;
241 int verify[256];
242
243 // return if nothing to do
244 if (len == 0)
245 return TRUE;
246
247 // check if power delivery is available
248 if(!owHasProgramPulse(portnum))
249 {
250 OWERROR(OWERROR_NO_PROGRAM_PULSE);
251 return FALSE;
252 }
253
254 // check if trying to write read only bank
255 if(isReadOnlyEPROM(bank,portnum,SNum))
256 {
257 OWERROR(OWERROR_READ_ONLY);
258 return FALSE;
259 }
260
261 for(i=0;i<len;i++)
262 {
263 verify[0] = writeVerify(bank,portnum,SNum,
264 ((str_add+i+getStartingAddressEPROM(bank,SNum))/getPageLengthEPROM(bank,SNum)));
265
266 if(isPageLocked(bank,portnum,SNum,(str_add+i+getStartingAddressEPROM(bank,SNum))/
267 getPageLengthEPROM(bank,SNum)))
268 {
269 OWERROR(OWERROR_PAGE_LOCKED);
270 return FALSE;
271 }
272 }
273
274 // check if write exceeds memory
275 if((str_add + len) > (getPageLengthEPROM(bank,SNum) * getNumberPagesEPROM(bank,SNum)))
276 {
277 OWERROR(OWERROR_WRITE_OUT_OF_RANGE);
278 return FALSE;
279 }
280
281 // loop while still have bytes to write
282 write_continue = TRUE;
283
284 crc_type = numCRCbytes(bank,SNum) - 1;
285
286 for (i=0;i<len;i++)
287 {
288 result = owProgramByte(portnum,buff[i],str_add+i+getStartingAddressEPROM(bank,SNum),
289 writeMemCmd(bank,SNum),crc_type,write_continue);
290 if(verify[i])
291 {
292 if((result == -1) || ((uchar) result != buff[i]))
293 {
294 OWERROR(OWERROR_READBACK_EPROM_FAILED);
295 return FALSE;
296 }
297 else
298 write_continue = FALSE;
299 }
300 }
301
302 return TRUE;
303 }
304
305 /**
306 * Read page in the current bank with no
307 * CRC checking (device or data). The resulting data from this API
308 * may or may not be what is on the 1-Wire device. It is recommends
309 * that the data contain some kind of checking (CRC) like in the
310 * readPagePacketEPROM() method or have the 1-Wire device provide the
311 * CRC as in readPageCRCEPROM(). readPageCRCEPROM() however is not
312 * supported on all memory types, see 'hasPageAutoCRCEPROM()'.
313 * If neither is an option then this method could be called more
314 * then once to at least verify that the same thing is read consistantly.
315 *
316 * bank to tell what memory bank of the ibutton to use.
317 * portnum the port number of the port being used for the
318 * 1-Wire Network.
319 * SNum the serial number for the part.
320 * page the page to read
321 * rd_cont if 'true' then device read is continued without
322 * re-selecting. This can only be used if the new
323 * read() continious where the last one led off
324 * and it is inside a 'beginExclusive/endExclusive'
325 * block.
326 * buff byte array containing data that was read.
327 * len length in bytes to write
328 *
329 * @return - returns '0' if the read page wasn't completed.
330 * '1' if the operation is complete.
331 */
readPageEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,SMALLINT rd_cont,uchar * buff)332 SMALLINT readPageEPROM(SMALLINT bank, int portnum, uchar *SNum, int page,
333 SMALLINT rd_cont, uchar *buff)
334 {
335 uchar extra[1];
336
337 if(hasPageAutoCRCEPROM(bank,SNum))
338 {
339 if(!readPageExtraCRCEPROM(bank,portnum,SNum,page,buff,extra))
340 return FALSE;
341 }
342 else
343 {
344 if(!readEPROM(bank,portnum,SNum,(page*getPageLengthEPROM(bank,SNum)),FALSE,
345 buff,getPageLengthEPROM(bank,SNum)))
346 return FALSE;
347 }
348
349 return TRUE;
350 }
351
352 /**
353 * Read page with extra information in the current bank with no
354 * CRC checking (device or data). The resulting data from this API
355 * may or may not be what is on the 1-Wire device. It is recommends
356 * that the data contain some kind of checking (CRC) like in the
357 * readPagePacketEPROM() method or have the 1-Wire device provide the
358 * CRC as in readPageCRCEPROM(). readPageCRCEPROM() however is not
359 * supported on all memory types, see 'hasPageAutoCRCEPROM()'.
360 * If neither is an option then this method could be called more
361 * then once to at least verify that the same thing is read consistantly.
362 * See the method 'hasExtraInfoEPROM()' for a description of the optional
363 * extra information some devices have.
364 *
365 * bank to tell what memory bank of the ibutton to use.
366 * portnum the port number of the port being used for the
367 * 1-Wire Network.
368 * SNum the serial number for the part.
369 * page the page to read
370 * rd_cont if 'true' then device read is continued without
371 * re-selecting. This can only be used if the new
372 * read() continious where the last one led off
373 * and it is inside a 'beginExclusive/endExclusive'
374 * block.
375 * buff byte array containing data that was read
376 * len length in bytes to write
377 * extra the extra information
378 *
379 * @return - returns '0' if the read page wasn't completed with extra info.
380 * '1' if the operation is complete.
381 */
readPageExtraEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,SMALLINT rd_cont,uchar * buff,uchar * extra)382 SMALLINT readPageExtraEPROM(SMALLINT bank, int portnum, uchar *SNum, int page,
383 SMALLINT rd_cont, uchar *buff, uchar *extra)
384 {
385 // check if current bank is not scratchpad bank, or not page 0
386 if(!hasExtraInfoEPROM(bank,SNum))
387 {
388 OWERROR(OWERROR_EXTRA_INFO_NOT_SUPPORTED);
389 return FALSE;
390 }
391
392 return readPageExtraCRCEPROM(bank,portnum,SNum,page,buff,extra);
393 }
394
395 /**
396 * Read a complete memory page with CRC verification provided by the
397 * device with extra information. Not supported by all devices.
398 * See the method 'hasPageAutoCRCEPROM()'.
399 * See the method 'haveExtraInfoEPROM()' for a description of the optional
400 * extra information.
401 *
402 * bank to tell what memory bank of the ibutton to use.
403 * portnum the port number of the port being used for the
404 * 1-Wire Network.
405 * SNum the serial number for the part.
406 * page the page to read
407 * buff byte array containing data that was read.
408 * extra the extra information
409 *
410 * @return - returns '0' if the read page wasn't completed with extra info.
411 * '1' if the operation is complete.
412 */
readPageExtraCRCEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,uchar * read_buff,uchar * extra)413 SMALLINT readPageExtraCRCEPROM(SMALLINT bank, int portnum, uchar *SNum, int page,
414 uchar *read_buff, uchar *extra)
415 {
416 int i, len = 0, lastcrc = 0, addr, extractPnt;
417 uchar raw_buf[PAGE_LENGTH_EPROM + 6];
418
419 owSerialNum(portnum,SNum,FALSE);
420
421 // only needs to be implemented if supported by hardware
422 if(!hasPageAutoCRCEPROM(bank,SNum))
423 {
424 OWERROR(OWERROR_CRC_NOT_SUPPORTED);
425 return FALSE;
426 }
427
428 // check if read exceeds memory
429 if(page > (getNumberPagesEPROM(bank,SNum)))
430 {
431 OWERROR(OWERROR_READ_OUT_OF_RANGE);
432 return FALSE;
433 }
434
435
436 // select the device
437 if (!owAccess(portnum))
438 {
439 OWERROR(OWERROR_DEVICE_SELECT_FAIL);
440 return FALSE;
441 }
442
443 // build start reading memory block with: command, address, (extraInfo?), (crc?)
444 len = 3 + getExtraInfoLengthEPROM(bank,SNum);
445
446 if(crcAfterAdd(bank,SNum))
447 {
448 len += numCRCbytes(bank,SNum);
449 }
450
451 for(i=0;i<len;i++)
452 raw_buf[i] = 0xFF;
453
454 raw_buf[0] = readPageWithCRC(bank,SNum);
455
456 addr = page * getPageLengthEPROM(bank,SNum) + getStartingAddressEPROM(bank,SNum);
457
458 raw_buf[1] = addr & 0xFF;
459 raw_buf[2] = ((addr & 0xFFFF) >> 8) & 0xFF;
460
461 // do the first block
462 if(!owBlock(portnum,FALSE,&raw_buf[0],len))
463 {
464 OWERROR(OWERROR_BLOCK_FAILED);
465 return FALSE;
466 }
467
468 // check CRC
469 if (numCRCbytes(bank,SNum) == 2)
470 {
471 setcrc16(portnum,0);
472 for(i=0;i<len;i++)
473 lastcrc = docrc16(portnum,raw_buf[i]);
474 }
475 else
476 {
477 setcrc8(portnum,0);
478 for(i=0;i<len;i++)
479 lastcrc = docrc8(portnum,raw_buf[i]);
480 }
481
482 if((getExtraInfoLengthEPROM(bank,SNum) > 0) || (crcAfterAdd(bank,SNum)))
483 {
484 // check CRC
485 if(numCRCbytes(bank,SNum) == 2)
486 {
487 if (lastcrc != 0xB001)
488 {
489 OWERROR(OWERROR_CRC_FAILED);
490 return FALSE;
491 }
492 }
493 else
494 {
495 if (lastcrc != 0)
496 {
497 return FALSE;
498 }
499 }
500
501 lastcrc = 0;
502
503 // extract the extra information
504 extractPnt = len - getExtraInfoLengthEPROM(bank,SNum) - numCRCbytes(bank,SNum);
505 if(getExtraInfoLengthEPROM(bank,SNum))
506 for(i=extractPnt;i<(extractPnt+getExtraInfoLengthEPROM(bank,SNum));i++)
507 extra[i-extractPnt] = raw_buf[i];
508 }
509
510 // pre-fill with 0xFF
511 for(i=0;i<(getPageLengthEPROM(bank,SNum) + numCRCbytes(bank,SNum));i++)
512 raw_buf[i] = 0xFF;
513
514 // send block to read data + crc
515 if(!owBlock(portnum,FALSE,&raw_buf[0],(getPageLengthEPROM(bank,SNum)+numCRCbytes(bank,SNum))))
516 {
517 OWERROR(OWERROR_BLOCK_FAILED);
518 return FALSE;
519 }
520
521 // check the CRC
522 if (numCRCbytes(bank,SNum) == 2)
523 {
524 setcrc16(portnum, (ushort) lastcrc);
525 for(i=0;i<(getPageLengthEPROM(bank,SNum)+numCRCbytes(bank,SNum));i++)
526 lastcrc = docrc16(portnum,raw_buf[i]);
527
528 if (lastcrc != 0xB001)
529 {
530 OWERROR(OWERROR_CRC_FAILED);
531 return FALSE;
532 }
533 }
534 else
535 {
536 setcrc8(portnum, (uchar) lastcrc);
537 for(i=0;i<(getPageLengthEPROM(bank,SNum)+numCRCbytes(bank,SNum));i++)
538 lastcrc = docrc8(portnum,raw_buf[i]);
539
540 if (lastcrc != 0)
541 {
542 OWERROR(OWERROR_CRC_FAILED);
543 return FALSE;
544 }
545 }
546
547 // extract the page data
548 for(i=0;i<getPageLengthEPROM(bank,SNum);i++)
549 {
550 read_buff[i] = raw_buf[i];
551 }
552
553 return TRUE;
554 }
555
556 /**
557 * Read a complete memory page with CRC verification provided by the
558 * device. Not supported by all devices. See the method
559 * 'hasPageAutoCRCEPROM()'.
560 *
561 * bank to tell what memory bank of the ibutton to use.
562 * portnum the port number of the port being used for the
563 * 1-Wire Network.
564 * SNum the serial number for the part.
565 * page the page to read
566 * buff byte array containing data that was read
567 *
568 * @return - returns '0' if the read page wasn't completed.
569 * '1' if the operation is complete.
570 */
readPageCRCEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,uchar * buff)571 SMALLINT readPageCRCEPROM(SMALLINT bank, int portnum, uchar *SNum, int page, uchar *buff)
572 {
573 uchar extra[1];
574
575 return readPageExtraCRCEPROM(bank,portnum,SNum,page,buff,extra);
576 }
577
578 /**
579 * Read a Universal Data Packet.
580 *
581 * The Universal Data Packet always starts on page boundaries but
582 * can end anywhere in the page. The structure specifies the length of
583 * data bytes not including the length byte and the CRC16 bytes.
584 * There is one length byte. The CRC16 is first initialized to
585 * the page number. This provides a check to verify the page that
586 * was intended is being read. The CRC16 is then calculated over
587 * the length and data bytes. The CRC16 is then inverted and stored
588 * low byte first followed by the high byte. This is structure is
589 * used by this method to verify the data but is not returned, only
590 * the data payload is returned.
591 *
592 * bank to tell what memory bank of the ibutton to use.
593 * portnum the port number of the port being used for the
594 * 1-Wire Network.
595 * SNum the serial number for the part.
596 * page the page to read
597 * rd_cont if 'true' then device read is continued without
598 * re-selecting. This can only be used if the new
599 * read() continious where the last one led off
600 * and it is inside a 'beginExclusive/endExclusive'
601 * block.
602 * buff byte array containing data that was read.
603 * len length of the packet
604 *
605 * @return - returns '0' if the read page packet wasn't completed
606 * '1' if the operation is complete.
607 */
readPagePacketEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,SMALLINT rd_cont,uchar * buff,int * len)608 SMALLINT readPagePacketEPROM(SMALLINT bank, int portnum, uchar *SNum, int page,
609 SMALLINT rd_cont, uchar *buff, int *len)
610 {
611 uchar raw_buf[PAGE_LENGTH_EPROM];
612 uchar extra[1];
613 ushort lastcrc16;
614 int i;
615
616 // read entire page with read page CRC
617 if(!readPageExtraCRCEPROM(bank,portnum,SNum,page,&raw_buf[0],&extra[0]))
618 return FALSE;
619
620 // check if length is realistic
621 if ((raw_buf[0] & 0xFF) > getMaxPacketDataLengthEPROM(bank,SNum))
622 {
623 OWERROR(OWERROR_INVALID_PACKET_LENGTH);
624 return FALSE;
625 }
626
627 // verify the CRC is correct
628 setcrc16(portnum,(ushort) ((getStartingAddressEPROM(bank,SNum)/PAGE_LENGTH_EPROM) + page));
629 for(i=0;i<(raw_buf[0]+3);i++)
630 lastcrc16 = docrc16(portnum,raw_buf[i]);
631
632 if(lastcrc16 == 0xB001)
633 {
634 // extract the data out of the packet
635 for(i=0;i<raw_buf[0];i++)
636 buff[i] = raw_buf[i+1];
637
638 // return the length
639 *len = raw_buf[0];
640 }
641 else
642 {
643 OWERROR(OWERROR_CRC_FAILED);
644 return FALSE;
645 }
646
647 return TRUE;
648 }
649
650 /**
651 * Read a Universal Data Packet and extra information. See the
652 * method 'readPagePacketEPROM()' for a description of the packet structure.
653 * See the method 'hasExtraInfoEPROM()' for a description of the optional
654 * extra information some devices have.
655 *
656 * bank to tell what memory bank of the ibutton to use.
657 * portnum the port number of the port being used for the
658 * 1-Wire Network.
659 * SNum the serial number for the part.
660 * page the page to read
661 * rd_cont if 'true' then device read is continued without
662 * re-selecting. This can only be used if the new
663 * read() continious where the last one led off
664 * and it is inside a 'beginExclusive/endExclusive'
665 * block.
666 * buff byte array containing data that was read.
667 * len length of the packet
668 * extra extra information
669 *
670 * @return - returns '0' if the read page packet wasn't completed
671 * '1' if the operation is complete.
672 */
readPagePacketExtraEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,SMALLINT rd_cont,uchar * buff,int * len,uchar * extra)673 SMALLINT readPagePacketExtraEPROM(SMALLINT bank, int portnum, uchar *SNum,
674 int page, SMALLINT rd_cont, uchar *buff,
675 int *len, uchar *extra)
676 {
677 uchar raw_buf[PAGE_LENGTH_EPROM];
678 ushort lastcrc16;
679 int i;
680
681 // check if current bank is not scratchpad bank, or not page 0
682 if (!hasExtraInfoEPROM(bank,SNum))
683 {
684 OWERROR(OWERROR_EXTRA_INFO_NOT_SUPPORTED);
685 return FALSE;
686 }
687
688 // read entire page with read page CRC
689 if(!readPageExtraCRCEPROM(bank,portnum,SNum,page,raw_buf,extra))
690 return FALSE;
691
692 // check if length is realistic
693 if ((raw_buf[0] & 0xFF) > getMaxPacketDataLengthEPROM(bank,SNum))
694 {
695 OWERROR(OWERROR_INVALID_PACKET_LENGTH);
696 return FALSE;
697 }
698
699 // verify the CRC is correct
700 setcrc16(portnum,(ushort) ((getStartingAddressEPROM(bank,SNum)/PAGE_LENGTH_EPROM) + page));
701 for(i=0;i<(raw_buf[0]+3);i++)
702 lastcrc16 = docrc16(portnum,raw_buf[i]);
703
704 if(lastcrc16 == 0xB001)
705 {
706 // extract the data out of the packet
707 for(i=0;i<raw_buf[0];i++)
708 buff[i] = raw_buf[i+1];
709
710 // return the length
711 *len = raw_buf [0];
712 }
713 else
714 {
715 OWERROR(OWERROR_CRC_FAILED);
716 return FALSE;
717 }
718
719 return TRUE;
720 }
721
722 /**
723 * Write a Universal Data Packet. See the method 'readPagePacketEPROM()'
724 * for a description of the packet structure.
725 *
726 * bank to tell what memory bank of the ibutton to use.
727 * portnum the port number of the port being used for the
728 * 1-Wire Network.
729 * SNum the serial number for the part.
730 * page the page the packet is being written to.
731 * rd_cont if 'true' then device read is continued without
732 * re-selecting. This can only be used if the new
733 * read() continious where the last one led off
734 * and it is inside a 'beginExclusive/endExclusive'
735 * block.
736 * buff byte array containing data that to write.
737 * len length of the packet
738 *
739 * @return - returns '0' if the write page packet wasn't completed
740 * '1' if the operation is complete.
741 */
writePagePacketEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,uchar * buff,int len)742 SMALLINT writePagePacketEPROM(SMALLINT bank, int portnum, uchar *SNum, int page,
743 uchar *buff, int len)
744 {
745 uchar raw_buf[PAGE_LENGTH_EPROM];
746 int crc, i;
747
748 // make sure length does not exceed max
749 if (len > getMaxPacketDataLengthEPROM(bank,SNum))
750 {
751 OWERROR(OWERROR_INVALID_PACKET_LENGTH);
752 return FALSE;
753 }
754
755 // see if this bank is general read/write
756 if (!isGeneralPurposeMemoryEPROM(bank,SNum))
757 {
758 OWERROR(OWERROR_NOT_GENERAL_PURPOSE);
759 return FALSE;
760 }
761
762 // construct the packet to write
763 raw_buf[0] = (uchar) len;
764
765 for(i=0;i<len;i++)
766 raw_buf[i+1] = buff[i];
767
768 setcrc16(portnum,(ushort) ((getStartingAddressEPROM(bank,SNum)/PAGE_LENGTH_EPROM) + page));
769 for(i=0;i<len+1;i++)
770 crc = docrc16(portnum,raw_buf[i]);
771
772 raw_buf[len + 1] = ~crc & 0xFF;
773 raw_buf[len + 2] = ((~crc & 0xFFFF) >> 8) & 0xFF;
774
775 // write the packet, return result
776 if(!writeEPROM(bank,portnum,SNum,page*getPageLengthEPROM(bank,SNum)+
777 getStartingAddressEPROM(bank,SNum),&raw_buf[0],len+3))
778 return FALSE;
779
780 return TRUE;
781 }
782
783 /**
784 * Query to get the number of pages in current memory bank.
785 *
786 * bank to tell what memory bank of the ibutton to use.
787 * SNum the serial number for the part.
788 *
789 * @return number of pages in current memory bank
790 */
getNumberPagesEPROM(SMALLINT bank,uchar * SNum)791 SMALLINT getNumberPagesEPROM(SMALLINT bank, uchar *SNum)
792 {
793 int pages = numPages;
794
795 switch(SNum[0])
796 {
797 case 0x09:
798 if(bank == 0)
799 pages = 4;
800 else if(bank == 1)
801 pages = 1;
802 break;
803
804 case 0x0B:
805 if((bank == 1) || (bank == 2) || (bank == 3))
806 pages = 1;
807 else if(bank == 4)
808 pages = 8;
809 break;
810
811 case 0x0F:
812 if(bank == 0)
813 pages = 256;
814 else if((bank == 1) || (bank == 2))
815 pages = 4;
816 else if(bank == 3)
817 pages = 3;
818 else if(bank == 4)
819 pages = 32;
820 break;
821
822 case 0x12:
823 if(bank == 0)
824 pages = 4;
825 else if(bank == 1)
826 pages = 1;
827 break;
828
829 case 0x13:
830 if(bank == 0)
831 pages = 16;
832 else if(bank == 4)
833 pages = 2;
834 else if((bank == 1) || (bank == 2) || (bank == 3))
835 pages = 1;
836 break;
837
838 default:
839 pages = numPages;
840 break;
841 }
842
843 return pages;
844 }
845
846 /**
847 * Query to get the memory bank size in bytes.
848 *
849 * bank to tell what memory bank of the ibutton to use.
850 * SNum the serial number for the part.
851 *
852 * @return memory bank size in bytes.
853 */
getSizeEPROM(SMALLINT bank,uchar * SNum)854 int getSizeEPROM(SMALLINT bank, uchar *SNum)
855 {
856 int size = SIZE_EPROM;
857
858 switch(SNum[0])
859 {
860 case 0x09:
861 if(bank == 0)
862 size = 128;
863 else if(bank == 1)
864 size = 8;
865 break;
866
867 case 0x0B:
868 if((bank == 1) || (bank == 2) || (bank == 3))
869 size = 8;
870 else if(bank == 4)
871 size = 64;
872 break;
873
874 case 0x0F:
875 if(bank == 0)
876 size = 8192;
877 else if((bank == 1) || (bank == 2))
878 size = 32;
879 else if(bank == 3)
880 size = 24;
881 else if(bank == 4)
882 size = 256;
883 break;
884
885 case 0x12:
886 if(bank == 0)
887 size = 128;
888 else if(bank == 1)
889 size = 8;
890 break;
891
892 case 0x13:
893 if(bank == 0)
894 size = 512;
895 else if(bank == 4)
896 size = 16;
897 else if((bank == 1) || (bank == 2) || (bank == 3))
898 size = 8;
899 break;
900
901 default:
902 size = SIZE_EPROM;
903 break;
904 }
905
906 return size;
907 }
908
909 /**
910 * Query to get the starting physical address of this bank. Physical
911 * banks are sometimes sub-divided into logical banks due to changes
912 * in attributes.
913 *
914 * bank to tell what memory bank of the ibutton to use.
915 * SNum the serial number for the part.
916 *
917 * @return physical starting address of this logical bank.
918 */
getStartingAddressEPROM(SMALLINT bank,uchar * SNum)919 int getStartingAddressEPROM(SMALLINT bank, uchar *SNum)
920 {
921 int addr = 0;
922
923 switch(SNum[0])
924 {
925 case 0x0B:
926 if(bank == 2)
927 addr = 32;
928 else if(bank == 3)
929 addr = 64;
930 else if(bank == 4)
931 addr = 256;
932 break;
933
934 case 0x0F:
935 if(bank == 2)
936 addr = 32;
937 else if(bank == 3)
938 addr = 64;
939 else if(bank == 4)
940 addr = 256;
941 break;
942
943 case 0x13:
944 if(bank == 2)
945 addr = 32;
946 else if(bank == 3)
947 addr = 64;
948 else if(bank == 4)
949 addr = 256;
950 break;
951
952 default:
953 addr = 0;
954 break;
955 }
956
957 return addr;
958 }
959
960 /**
961 * Query to get page length in bytes in current memory bank.
962 *
963 * bank to tell what memory bank of the ibutton to use.
964 * SNum the serial number for the part.
965 *
966 * @return page length in bytes in current memory bank
967 */
getPageLengthEPROM(SMALLINT bank,uchar * SNum)968 SMALLINT getPageLengthEPROM(SMALLINT bank, uchar *SNum)
969 {
970 int len = PAGE_LENGTH_EPROM;
971
972 switch(SNum[0])
973 {
974 case 0x09:
975 if(bank == 1)
976 len = 8;
977 break;
978
979 case 0x0B:
980 if((bank > 0) && (bank < 5))
981 len = 8;
982
983 case 0x0F:
984 if((bank > 0) && (bank <5))
985 len = 8;
986 break;
987
988 case 0x12:
989 if(bank == 1)
990 len = 8;
991 break;
992
993 case 0x13:
994 if((bank > 0) && (bank < 5))
995 len = 8;
996 break;
997
998 default:
999 len = PAGE_LENGTH_EPROM;
1000 break;
1001 }
1002
1003 return len;
1004 }
1005
1006 /**
1007 * Query to see get a string description of the current memory bank.
1008 *
1009 * bank to tell what memory bank of the ibutton to use.
1010 * SNum the serial number for the part.
1011 *
1012 * @return String containing the memory bank description
1013 */
getBankDescriptionEPROM(SMALLINT bank,uchar * SNum)1014 char *getBankDescriptionEPROM(SMALLINT bank, uchar *SNum)
1015 {
1016 switch(SNum[0])
1017 {
1018 case 0x09:
1019 if(bank == 1)
1020 return "Write protect pages and page redirection";
1021 break;
1022
1023 case 0x0B:
1024 if(bank == 1)
1025 return "Write protect pages";
1026 else if(bank == 2)
1027 return "Write protect redirection";
1028 else if(bank == 3)
1029 return "Bitmap of used pages for file structure";
1030 else if(bank == 4)
1031 return "Page redirection bytes";
1032 break;
1033
1034 case 0x0F:
1035 if(bank == 1)
1036 return "Write protect pages";
1037 else if(bank == 2)
1038 return "Write protect redirection";
1039 else if(bank == 3)
1040 return "Bitmap of used pages for file structure";
1041 else if(bank == 4)
1042 return "Pages redirection bytes";
1043 break;
1044
1045 case 0x12:
1046 if(bank == 1)
1047 return "Write protect pages, page redirection, switch control";
1048 break;
1049
1050 case 0x13:
1051 if(bank == 1)
1052 return "Write protect pages";
1053 else if(bank == 2)
1054 return "Write protect redirection";
1055 else if(bank == 3)
1056 return "Bitmap of used pages for file structure";
1057 else if(bank == 4)
1058 return "Page redirection bytes";
1059 break;
1060
1061 default:
1062 return bankDescription_eprom;
1063 break;
1064 }
1065
1066 return bankDescription_eprom;
1067 }
1068
1069 /**
1070 * Query to see if the current memory bank is general purpose
1071 * user memory. If it is NOT then it is Memory-Mapped and writing
1072 * values to this memory will affect the behavior of the 1-Wire
1073 * device.
1074 *
1075 * bank to tell what memory bank of the ibutton to use.
1076 * SNum the serial number for the part.
1077 *
1078 * @return 'true' if current memory bank is general purpose
1079 */
isGeneralPurposeMemoryEPROM(SMALLINT bank,uchar * SNum)1080 SMALLINT isGeneralPurposeMemoryEPROM(SMALLINT bank, uchar *SNum)
1081 {
1082 int gp_mem = generalPurposeMemory_eprom;
1083
1084 switch(SNum[0])
1085 {
1086 case 0x09:
1087 if(bank == 1)
1088 gp_mem = FALSE;
1089 break;
1090
1091 case 0x0B:
1092 if((bank > 0) && (bank < 5))
1093 gp_mem = FALSE;
1094
1095 case 0x0F:
1096 if((bank > 0) && (bank <5))
1097 gp_mem = FALSE;
1098 break;
1099
1100 case 0x12:
1101 if(bank == 1)
1102 gp_mem = FALSE;
1103 break;
1104
1105 case 0x13:
1106 if((bank > 0) && (bank < 5))
1107 gp_mem = FALSE;
1108 break;
1109
1110 default:
1111 gp_mem = generalPurposeMemory_eprom;
1112 break;
1113 }
1114
1115 return gp_mem;
1116 }
1117
1118 /**
1119 * Query to see if current memory bank is read/write.
1120 *
1121 * bank to tell what memory bank of the ibutton to use.
1122 * SNum the serial number for the part.
1123 *
1124 * @return 'true' if current memory bank is read/write
1125 */
isReadWriteEPROM(SMALLINT bank,int portnum,uchar * SNum)1126 SMALLINT isReadWriteEPROM(SMALLINT bank, int portnum, uchar *SNum)
1127 {
1128 return readWrite_eprom;
1129 }
1130
1131 /**
1132 * Query to see if current memory bank is write write once such
1133 * as with EPROM technology.
1134 *
1135 * bank to tell what memory bank of the ibutton to use.
1136 * SNum the serial number for the part.
1137 *
1138 * @return 'true' if current memory bank can only be written once
1139 */
isWriteOnceEPROM(SMALLINT bank,int portnum,uchar * SNum)1140 SMALLINT isWriteOnceEPROM(SMALLINT bank, int portnum, uchar *SNum)
1141 {
1142 return writeOnce_eprom;
1143 }
1144
1145 /**
1146 * Query to see if current memory bank is read only.
1147 *
1148 * @return 'true' if current memory bank can only be read
1149 */
isReadOnlyEPROM(SMALLINT bank,int portnum,uchar * SNum)1150 SMALLINT isReadOnlyEPROM(SMALLINT bank, int portnum, uchar *SNum)
1151 {
1152 return readOnly_eprom;
1153 }
1154
1155 /**
1156 * Query to see if current memory bank non-volatile. Memory is
1157 * non-volatile if it retains its contents even when removed from
1158 * the 1-Wire network.
1159 *
1160 * bank to tell what memory bank of the ibutton to use.
1161 * SNum the serial number for the part.
1162 *
1163 * @return 'true' if current memory bank non volatile.
1164 */
isNonVolatileEPROM(SMALLINT bank,uchar * SNum)1165 SMALLINT isNonVolatileEPROM(SMALLINT bank, uchar *SNum)
1166 {
1167 return nonVolatile_eprom;
1168 }
1169
1170 /**
1171 * Query to see if current memory bank pages need the adapter to
1172 * have a 'ProgramPulse' in order to write to the memory.
1173 *
1174 * bank to tell what memory bank of the ibutton to use.
1175 * SNum the serial number for the part.
1176 *
1177 * @return 'true' if writing to the current memory bank pages
1178 * requires a 'ProgramPulse'.
1179 */
needsProgramPulseEPROM(SMALLINT bank,uchar * SNum)1180 SMALLINT needsProgramPulseEPROM(SMALLINT bank, uchar *SNum)
1181 {
1182 return needsProgramPulse_eprom;
1183 }
1184
1185 /**
1186 * Query to see if current memory bank pages need the adapter to
1187 * have a 'PowerDelivery' feature in order to write to the memory.
1188 *
1189 * bank to tell what memory bank of the ibutton to use.
1190 * SNum the serial number for the part.
1191 *
1192 * @return 'true' if writing to the current memory bank pages
1193 * requires 'PowerDelivery'.
1194 */
needsPowerDeliveryEPROM(SMALLINT bank,uchar * SNum)1195 SMALLINT needsPowerDeliveryEPROM(SMALLINT bank, uchar *SNum)
1196 {
1197 return needsPowerDelivery_eprom;
1198 }
1199
1200 /**
1201 * Checks to see if this memory bank's pages deliver extra
1202 * information outside of the normal data space, when read. Examples
1203 * of this may be a redirection byte, counter, tamper protection
1204 * bytes, or SHA-1 result. If this method returns true then the
1205 * methods with an 'extraInfo' parameter can be used.
1206 *
1207 * bank to tell what memory bank of the ibutton to use.
1208 * SNum the serial number for the part.
1209 *
1210 * @return true if reading the this memory bank's
1211 * pages provides extra information
1212 */
hasExtraInfoEPROM(SMALLINT bank,uchar * SNum)1213 SMALLINT hasExtraInfoEPROM(SMALLINT bank, uchar *SNum)
1214 {
1215 SMALLINT hasExtra = hasExtraInfo_eprom;
1216
1217 switch(SNum[0])
1218 {
1219 case 0x09:
1220 hasExtra = FALSE;
1221 break;
1222
1223 case 0x0B:
1224 if((bank > 0) && (bank < 5))
1225 hasExtra = FALSE;
1226 break;
1227
1228 case 0x0F:
1229 if((bank > 0) && (bank < 5))
1230 hasExtra = FALSE;
1231 break;
1232
1233 case 0x12:
1234 if(bank == 1)
1235 hasExtra = FALSE;
1236 break;
1237
1238 case 0x13:
1239 if((bank > 0) && (bank < 5))
1240 hasExtra = FALSE;
1241 break;
1242
1243 default:
1244 hasExtra = hasExtraInfo_eprom;
1245 break;
1246 }
1247
1248 return hasExtra;
1249 }
1250
1251 /**
1252 * Query to get the length in bytes of extra information that
1253 * is read when read a page in the current memory bank. See
1254 * 'hasExtraInfoEPROM()'.
1255 *
1256 * bank to tell what memory bank of the ibutton to use.
1257 * SNum the serial number for the part.
1258 *
1259 * @return number of bytes in Extra Information read when reading
1260 * pages in the current memory bank.
1261 */
getExtraInfoLengthEPROM(SMALLINT bank,uchar * SNum)1262 SMALLINT getExtraInfoLengthEPROM(SMALLINT bank, uchar *SNum)
1263 {
1264 SMALLINT len = extraInfoLength_eprom;
1265
1266 switch(SNum[0])
1267 {
1268 case 0x09:
1269 len = 0;
1270 break;
1271
1272 case 0x0B:
1273 if((bank > 0) && (bank < 5))
1274 len = 0;
1275 break;
1276
1277 case 0x0F:
1278 if((bank > 0) && (bank < 5))
1279 len = 0;
1280 break;
1281
1282 case 0x12:
1283 if(bank == 1)
1284 len = 0;
1285 break;
1286
1287 case 0x13:
1288 if((bank > 0) && (bank < 5))
1289 len = 0;
1290 break;
1291
1292 default:
1293 len = extraInfoLength_eprom;
1294 break;
1295 }
1296
1297 return len;
1298 }
1299
1300 /**
1301 * Query to get a string description of what is contained in
1302 * the Extra Informationed return when reading pages in the current
1303 * memory bank. See 'hasExtraInfoEPROM()'.
1304 *
1305 * bank to tell what memory bank of the ibutton to use.
1306 * SNum the serial number for the part.
1307 *
1308 * @return string describing extra information.
1309 */
getExtraInfoDescEPROM(SMALLINT bank,uchar * SNum)1310 char *getExtraInfoDescEPROM(SMALLINT bank, uchar *SNum)
1311 {
1312 switch(SNum[0])
1313 {
1314 case 0x09:
1315 return " ";
1316 break;
1317
1318 case 0x0B:
1319 if((bank > 0) && (bank < 5))
1320 return " ";
1321 break;
1322
1323 case 0x0F:
1324 if((bank > 0) && (bank < 5))
1325 return " ";
1326 break;
1327
1328 case 0x12:
1329 if(bank == 1)
1330 return " ";
1331 break;
1332
1333 case 0x13:
1334 if((bank > 0) && (bank < 5))
1335 return " ";
1336 break;
1337
1338 default:
1339 return extraInfoDesc_eprom;
1340 break;
1341 }
1342
1343
1344 return extraInfoDesc_eprom;
1345 }
1346
1347 /**
1348 * Query to see if current memory bank pages can be read with
1349 * the contents being verified by a device generated CRC.
1350 * This is used to see if the 'ReadPageCRCEPROM()' can be used.
1351 *
1352 * bank to tell what memory bank of the ibutton to use.
1353 * SNum the serial number for the part.
1354 *
1355 * @return 'true' if current memory bank can be read with self
1356 * generated CRC.
1357 */
hasPageAutoCRCEPROM(SMALLINT bank,uchar * SNum)1358 SMALLINT hasPageAutoCRCEPROM(SMALLINT bank, uchar *SNum)
1359 {
1360 return pageAutoCRC_eprom;
1361 }
1362
1363 /**
1364 * Query to get Maximum data page length in bytes for a packet
1365 * read or written in the current memory bank. See the 'ReadPagePacket()'
1366 * and 'WritePagePacket()' methods. This method is only usefull
1367 * if the current memory bank is general purpose memory.
1368 *
1369 * @return max packet page length in bytes in current memory bank
1370 */
getMaxPacketDataLengthEPROM(SMALLINT bank,uchar * SNum)1371 SMALLINT getMaxPacketDataLengthEPROM(SMALLINT bank, uchar *SNum)
1372 {
1373 return getPageLengthEPROM(bank,SNum) - 3;
1374 }
1375
1376 //--------
1377 //-------- OTPMemoryBank I/O methods
1378 //--------
1379
1380 /**
1381 * Lock the specifed page in the current memory bank. Not supported
1382 * by all devices. See the method 'canLockPageEPROM()'.
1383 *
1384 * bank to tell what memory bank of the ibutton to use.
1385 * portnum the port number of the port being used for the
1386 * 1-Wire Network.
1387 * SNum the serial number for the part.
1388 * page the page to be locked
1389 *
1390 * @return true if the page was locked
1391 * false otherwise
1392 */
lockPage(SMALLINT bank,int portnum,uchar * SNum,int page)1393 SMALLINT lockPage(SMALLINT bank, int portnum, uchar *SNum, int page)
1394 {
1395 int nbyt,nbit;
1396 SMALLINT write_bank;
1397 uchar wr_byte[1];
1398
1399 // setting the bank to write
1400 // and since all the page lock info is in
1401 // bank 1 for all the EPROM parts.
1402 write_bank = 1;
1403
1404 if(isPageLocked(write_bank,portnum,SNum,page))
1405 {
1406 OWERROR(OWERROR_PAGE_ALREADY_LOCKED);
1407 return FALSE;
1408 }
1409
1410 // create byte to write to mlLock to lock page
1411 nbyt = (page >> 3);
1412 nbit = page - (nbyt << 3);
1413
1414 wr_byte[0] = (uchar) ~(0x01 << nbit);
1415
1416 // write the lock bit
1417 if(!writeEPROM(write_bank,portnum,SNum,nbyt + lockOffset,wr_byte,1))
1418 return FALSE;
1419
1420 // read back to verify
1421 if(!isPageLocked(write_bank,portnum,SNum,page))
1422 {
1423 OWERROR(OWERROR_READ_BACK_NOT_VALID);
1424 return FALSE;
1425 }
1426
1427 return TRUE;
1428 }
1429
1430 /**
1431 * Query to see if the specified page is locked.
1432 * See the method 'canLockPage()'.
1433 *
1434 * bank to tell what memory bank of the ibutton to use.
1435 * portnum the port number of the port being used for the
1436 * 1-Wire Network.
1437 * SNum the serial number for the part.
1438 * page the page to check if locked
1439 *
1440 * @return true if page locked.
1441 */
isPageLocked(SMALLINT bank,int portnum,uchar * SNum,int page)1442 SMALLINT isPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page)
1443 {
1444 int pg_len, read_pg, index, nbyt, nbit;
1445 SMALLINT read_bank;
1446 uchar read_buf[PAGE_LENGTH_EPROM];
1447
1448 // setting the bank to read for information
1449 // and since all the page lock info is in
1450 // bank 1 for all the EPROM parts.
1451 read_bank = 1;
1452
1453 // read page that locked bit is on
1454 pg_len = getPageLengthEPROM(read_bank,SNum);
1455 read_pg = (page + lockOffset) / (pg_len * 8);
1456
1457 if(!readPageCRCEPROM(read_bank,portnum,SNum,read_pg,read_buf))
1458 return FALSE;
1459
1460 // return boolean on locked bit
1461 index = (page + lockOffset) - (read_pg * 8 * pg_len);
1462 nbyt = (index >> 3);
1463 nbit = index - (nbyt << 3);
1464
1465 return !(((read_buf[nbyt] >> nbit) & 0x01) == 0x01);
1466 }
1467
1468 /**
1469 * Redirect the specifed page in the current memory bank to a new page.
1470 * Not supported by all devices. See the method 'canRedirectPage()'.
1471 *
1472 * bank to tell what memory bank of the ibutton to use.
1473 * portnum the port number of the port being used for the
1474 * 1-Wire Network.
1475 * SNum the serial number for the part.
1476 * page the page to be locked
1477 * newPage new page number to redirect to
1478 *
1479 * @return true if the page was redirected
1480 */
redirectPage(SMALLINT bank,int portnum,uchar * SNum,int page,int newPage)1481 SMALLINT redirectPage(SMALLINT bank, int portnum, uchar *SNum, int page, int newPage)
1482 {
1483 uchar wr_byte[1]; // create byte to redirect page
1484 SMALLINT write_bank;
1485
1486 if(isRedirectPageLocked(bank,portnum,SNum,page))
1487 {
1488 OWERROR(OWERROR_REDIRECTED_PAGE);
1489 return FALSE;
1490 }
1491
1492 // setting the bank to write
1493 switch(SNum[0])
1494 {
1495 case 0x09: case 0x12:
1496 write_bank = 1;
1497 break;
1498
1499 case 0x0B: case 0x0F: case 0x13:
1500 write_bank = 4;
1501 break;
1502
1503 default:
1504 write_bank = 4;
1505 break;
1506 }
1507
1508 wr_byte[0] = (uchar) ~newPage;
1509
1510 // write the redirection byte
1511 if(!writeEPROM(write_bank,portnum,SNum,page + redirectOffset(bank,SNum),wr_byte,1))
1512 return FALSE;
1513
1514 return TRUE;
1515 }
1516
1517
1518 /**
1519 * Gets the page redirection of the specified page.
1520 * Not supported by all devices.
1521 *
1522 * bank to tell what memory bank of the ibutton to use.
1523 * portnum the port number of the port being used for the
1524 * 1-Wire Network.
1525 * SNum the serial number for the part.
1526 * page number of page check for redirection
1527 *
1528 * @return the new page number or 0 if not redirected
1529 */
getRedirectedPage(SMALLINT bank,int portnum,uchar * SNum,int page)1530 SMALLINT getRedirectedPage(SMALLINT bank, int portnum, uchar *SNum, int page)
1531 {
1532 int pg_len, read_pg;
1533 SMALLINT read_bank;
1534 uchar read_buf[PAGE_LENGTH_EPROM];
1535
1536 // setting the bank to read for information
1537 switch(SNum[0])
1538 {
1539 case 0x09: case 0x12:
1540 read_bank = 1;
1541 break;
1542
1543 case 0x0B: case 0x0F: case 0x13:
1544 read_bank = 4;
1545 break;
1546
1547 default:
1548 read_bank = 4;
1549 break;
1550 }
1551
1552 // read page that redirect byte is on
1553 pg_len = getPageLengthEPROM(read_bank,SNum);
1554 read_pg = (page + redirectOffset(bank,SNum)) / pg_len;
1555
1556 if(!readPageCRCEPROM(read_bank,portnum,SNum,read_pg,read_buf))
1557 return FALSE;
1558
1559 // return page
1560 return (SMALLINT) (~read_buf[(page + redirectOffset(bank,SNum)) % pg_len] & 0x000000FF);
1561 }
1562
1563 /**
1564 * Lock the redirection option for the specifed page in the current
1565 * memory bank. Not supported by all devices. See the method
1566 * 'canLockRedirectPage()'.
1567 *
1568 * bank to tell what memory bank of the ibutton to use.
1569 * portnum the port number of the port being used for the
1570 * 1-Wire Network.
1571 * SNum the serial number for the part.
1572 * page number of page to redirect
1573 *
1574 * @return true if the redirected page is locked.
1575 */
lockRedirectPage(SMALLINT bank,int portnum,uchar * SNum,int page)1576 SMALLINT lockRedirectPage(SMALLINT bank, int portnum, uchar *SNum, int page)
1577 {
1578 int nbyt, nbit;
1579 SMALLINT write_bank;
1580 uchar wr_byte[1];
1581
1582 if(isRedirectPageLocked(bank,portnum,SNum,page))
1583 {
1584 OWERROR(OWERROR_LOCKING_REDIRECTED_PAGE_AGAIN);
1585 return FALSE;
1586 }
1587
1588 // setting the bank to write
1589 switch(SNum[0])
1590 {
1591 case 0x0B: case 0x0F: case 0x13:
1592 write_bank = 2;
1593 break;
1594
1595 default:
1596 write_bank = 0;
1597 break;
1598 }
1599
1600 // create byte to write to mlLock to lock page
1601 nbyt = (page >> 3);
1602 nbit = page - (nbyt << 3);
1603
1604 wr_byte[0] = (uchar) ~(0x01 << nbit);
1605
1606 // write the lock bit
1607 if(!writeEPROM(write_bank,portnum,SNum,nbyt + lockRedirectOffset,wr_byte,1))
1608 return FALSE;
1609
1610 // read back to verify
1611 if (!isRedirectPageLocked(bank,portnum,SNum,page) || (write_bank == 0))
1612 {
1613 OWERROR(OWERROR_COULD_NOT_LOCK_REDIRECT);
1614 return FALSE;
1615 }
1616
1617 return TRUE;
1618 }
1619
1620 /**
1621 * Query to see if the specified page has redirection locked.
1622 * Not supported by all devices. See the method 'canRedirectPage()'.
1623 *
1624 * bank to tell what memory bank of the ibutton to use.
1625 * portnum the port number of the port being used for the
1626 * 1-Wire Network.
1627 * SNum the serial number for the part.
1628 * page number of page to check for redirection
1629 *
1630 * @return true if redirection is locked for this page
1631 */
isRedirectPageLocked(SMALLINT bank,int portnum,uchar * SNum,int page)1632 SMALLINT isRedirectPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page)
1633 {
1634 int pg_len, read_pg, index, nbyt, nbit;
1635 SMALLINT read_bank;
1636 uchar read_buf[PAGE_LENGTH_EPROM];
1637
1638 // setting the bank to read for information
1639 switch(SNum[0])
1640 {
1641 case 0x0B: case 0x0F: case 0x13:
1642 read_bank = 2;
1643 break;
1644
1645 default:
1646 return FALSE;
1647 break;
1648 }
1649
1650 // read page that lock redirect bit is on
1651 pg_len = getPageLengthEPROM(read_bank,SNum);
1652 read_pg = (page + lockRedirectOffset) / (pg_len * 8);
1653
1654 if(!readPageCRCEPROM(read_bank,portnum,SNum,read_pg,read_buf))
1655 return FALSE;
1656
1657 // return boolean on lock redirect bit
1658 index = (page + lockRedirectOffset) - (read_pg * 8 * pg_len);
1659 nbyt = (index >> 3);
1660 nbit = index - (nbyt << 3);
1661
1662 return !(((read_buf[nbyt] >> nbit) & 0x01) == 0x01);
1663 }
1664
1665 /**
1666 * Query to see if current memory bank pages can be redirected
1667 * to another pages. This is mostly used in Write-Once memory
1668 * to provide a means to update.
1669 *
1670 * bank to tell what memory bank of the ibutton to use.
1671 * SNum the serial number for the part.
1672 *
1673 * @return 'true' if current memory bank pages can be redirected
1674 * to a new page.
1675 */
canRedirectPageEPROM(SMALLINT bank,uchar * SNum)1676 SMALLINT canRedirectPageEPROM(SMALLINT bank, uchar *SNum)
1677 {
1678 SMALLINT canRedirect = canredirectPage;
1679
1680 switch(SNum[0])
1681 {
1682 case 0x09:
1683 if(bank == 0)
1684 canRedirect = TRUE;
1685 break;
1686
1687 case 0x0B:
1688 if(bank == 0)
1689 canRedirect = TRUE;
1690 break;
1691
1692 case 0x0F:
1693 if(bank == 0)
1694 canRedirect = TRUE;
1695 break;
1696
1697 case 0x12:
1698 if(bank == 0)
1699 canRedirect = TRUE;
1700 break;
1701
1702 case 0x13:
1703 if(bank == 0)
1704 canRedirect = TRUE;
1705 break;
1706
1707 default:
1708 canRedirect = canredirectPage;
1709 break;
1710 }
1711
1712 return canRedirect;
1713 }
1714
1715 /**
1716 * Query to see if current memory bank pages can be locked. A
1717 * locked page would prevent any changes to the memory.
1718 *
1719 * bank to tell what memory bank of the ibutton to use.
1720 * SNum the serial number for the part.
1721 *
1722 * @return 'true' if current memory bank pages can be redirected
1723 * to a new page.
1724 */
canLockPageEPROM(SMALLINT bank,uchar * SNum)1725 SMALLINT canLockPageEPROM(SMALLINT bank, uchar *SNum)
1726 {
1727 SMALLINT canLock = canlockPage;
1728
1729 switch(SNum[0])
1730 {
1731 case 0x09:
1732 if(bank == 0)
1733 canLock = TRUE;
1734 break;
1735
1736 case 0x0B:
1737 if(bank == 0)
1738 canLock = TRUE;
1739 break;
1740
1741 case 0x0F:
1742 if(bank == 0)
1743 canLock = TRUE;
1744 break;
1745
1746 case 0x12:
1747 if(bank == 0)
1748 canLock = TRUE;
1749 break;
1750
1751 case 0x13:
1752 if(bank == 0)
1753 canLock = TRUE;
1754 break;
1755
1756 default:
1757 canLock = canlockPage;
1758 break;
1759 }
1760
1761 return canLock;
1762 }
1763
1764 /**
1765 * Query to see if current memory bank pages can be locked from
1766 * being redirected. This would prevent a Write-Once memory from
1767 * being updated.
1768 *
1769 * bank to tell what memory bank of the ibutton to use.
1770 * SNum the serial number for the part.
1771 *
1772 * @return 'true' if current memory bank pages can be locked from
1773 * being redirected to a new page.
1774 */
canLockRedirectPageEPROM(SMALLINT bank,uchar * SNum)1775 SMALLINT canLockRedirectPageEPROM(SMALLINT bank, uchar *SNum)
1776 {
1777 SMALLINT lockRedirect = canlockRedirectPage;
1778
1779 switch(SNum[0])
1780 {
1781 case 0x0B:
1782 if(bank == 0)
1783 lockRedirect = TRUE;
1784 break;
1785
1786 case 0x0F:
1787 if(bank == 0)
1788 lockRedirect = TRUE;
1789 break;
1790
1791 case 0x13:
1792 if(bank == 0)
1793 lockRedirect = TRUE;
1794 break;
1795
1796 default:
1797 lockRedirect = canlockRedirectPage;
1798 break;
1799 }
1800
1801 return lockRedirect;
1802 }
1803
1804
1805 //--------
1806 //-------- Local functions
1807 //--------
1808
1809 /**
1810 * Send the command for writing to memory for a device given
1811 * the memory bank and serial number.
1812 *
1813 * bank to tell what memory bank of the ibutton to use.
1814 * SNum the serial number for the part.
1815 *
1816 * @return the command for writing to the memory bank.
1817 */
writeMemCmd(SMALLINT bank,uchar * SNum)1818 uchar writeMemCmd(SMALLINT bank, uchar *SNum)
1819 {
1820 uchar command = MAIN_WRITE_COMMAND_EPROM;
1821
1822 switch(SNum[0])
1823 {
1824 case 0x09:
1825 if(bank == 1)
1826 command = STATUS_WRITE_COMMAND_EPROM;
1827 break;
1828
1829 case 0x0B:
1830 if((bank > 0) && (bank < 5))
1831 command = STATUS_WRITE_COMMAND_EPROM;
1832 break;
1833
1834 case 0x0F:
1835 if((bank > 0) && (bank < 5))
1836 command = STATUS_WRITE_COMMAND_EPROM;
1837 break;
1838
1839 case 0x12:
1840 if(bank == 1)
1841 command = STATUS_WRITE_COMMAND_EPROM;
1842 break;
1843
1844 case 0x13:
1845 if((bank > 0) && (bank < 5))
1846 command = STATUS_WRITE_COMMAND_EPROM;
1847 break;
1848
1849 default:
1850 command = MAIN_WRITE_COMMAND_EPROM;
1851 break;
1852 }
1853
1854 return command;
1855 }
1856
1857 /**
1858 * Get the number of CRC bytes for the device.
1859 *
1860 * bank to tell what memory bank of the ibutton to use.
1861 * SNum the serial number for the part.
1862 *
1863 * @return the number of CRC bytes.
1864 */
numCRCbytes(SMALLINT bank,uchar * SNum)1865 SMALLINT numCRCbytes(SMALLINT bank, uchar *SNum)
1866 {
1867 SMALLINT numbytes = CRCbytes;
1868
1869 switch(SNum[0])
1870 {
1871 case 0x09:
1872 if((bank == 0) || (bank == 1))
1873 numbytes = 1;
1874 break;
1875
1876 default:
1877 numbytes = CRCbytes;
1878 break;
1879 }
1880
1881 return numbytes;
1882 }
1883
1884 /**
1885 * Get the status of the page the pages write verification
1886 *
1887 * bank to tell what memory bank of the ibutton to use.
1888 * SNum the serial number for the part.
1889 *
1890 * @return true if write verification is used and
1891 * false if it is not used.
1892 */
writeVerify(SMALLINT bank,int portnum,uchar * SNum,int page)1893 SMALLINT writeVerify(SMALLINT bank, int portnum, uchar *SNum, int page)
1894 {
1895 if(isPageLocked(bank,portnum,SNum,page) ||
1896 isRedirectPageLocked(bank,portnum,SNum,page))
1897 return FALSE;
1898
1899 return writeVerification_eprom;
1900 }
1901
1902 /**
1903 * Get crc after sending command,address
1904 *
1905 * bank to tell what memory bank of the ibutton to use.
1906 * SNum the serial number for the part.
1907 *
1908 * @return true if crc is can be gotten after sending command,address
1909 * false otherwise
1910 */
crcAfterAdd(SMALLINT bank,uchar * SNum)1911 SMALLINT crcAfterAdd(SMALLINT bank, uchar *SNum)
1912 {
1913 SMALLINT crcAfter = TRUE;
1914
1915 switch(SNum[0])
1916 {
1917 case 0x0B:
1918 if((bank > 0) && (bank < 5))
1919 crcAfter = FALSE;
1920 break;
1921
1922 case 0x0F:
1923 if((bank > 0) && (bank < 5))
1924 crcAfter = FALSE;
1925 break;
1926
1927 case 0x12:
1928 if(bank == 1)
1929 crcAfter = FALSE;
1930 break;
1931
1932 case 0x13:
1933 if((bank > 0) && (bank < 5))
1934 crcAfter = FALSE;
1935 break;
1936
1937 default:
1938 crcAfter = TRUE;
1939 break;
1940 }
1941
1942 return crcAfter;
1943 }
1944
1945 /**
1946 * Get the byte command for reading the page with crc.
1947 *
1948 * bank to tell what memory bank of the ibutton to use.
1949 * SNum the serial number for the part.
1950 *
1951 * @return the byte command for reading the page
1952 */
readPageWithCRC(SMALLINT bank,uchar * SNum)1953 uchar readPageWithCRC(SMALLINT bank, uchar *SNum)
1954 {
1955 uchar readPage = MAIN_READ_PAGE_COMMAND_EPROM;
1956
1957 switch(SNum[0])
1958 {
1959 case 0x09:
1960 if(bank == 0)
1961 readPage = 0xC3;
1962 else if(bank == 1)
1963 readPage = STATUS_READ_PAGE_COMMAND_EPROM;
1964 break;
1965
1966 case 0x0B:
1967 if((bank > 0) && (bank < 5))
1968 readPage = STATUS_READ_PAGE_COMMAND_EPROM;
1969 break;
1970
1971 case 0x0F:
1972 if((bank > 0) && (bank < 5))
1973 readPage = STATUS_READ_PAGE_COMMAND_EPROM;
1974 break;
1975
1976 case 0x12:
1977 if(bank == 1)
1978 readPage = STATUS_READ_PAGE_COMMAND_EPROM;
1979 break;
1980
1981 case 0x13:
1982 if((bank > 0) && (bank < 5))
1983 readPage = STATUS_READ_PAGE_COMMAND_EPROM;
1984 break;
1985
1986 default:
1987 readPage = MAIN_READ_PAGE_COMMAND_EPROM;
1988 break;
1989 }
1990
1991 return readPage;
1992 }
1993
1994 /**
1995 * Get the offset into the redirection status information.
1996 *
1997 * bank to tell what memory bank of the ibutton to use.
1998 * SNum the serial number for the part.
1999 *
2000 * @return the offset into the redirection status
2001 */
redirectOffset(SMALLINT bank,uchar * SNum)2002 SMALLINT redirectOffset(SMALLINT bank, uchar *SNum)
2003 {
2004 int offset = 0;
2005
2006 switch(SNum[0])
2007 {
2008 case 0x09:
2009 if(bank == 0)
2010 offset = 1;
2011 break;
2012
2013 case 0x12:
2014 if(bank == 0)
2015 offset = 1;
2016 break;
2017
2018 default:
2019 offset = 0;
2020 break;
2021 }
2022
2023 return offset;
2024 }
2025