//--------------------------------------------------------------------------- // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of Dallas Semiconductor // shall not be used except as stated in the Dallas Semiconductor // Branding Policy. //--------------------------------------------------------------------------- // // mbEPROM.c - Include memory bank EPROM functions. // // Version: 2.10 // // Include Files #include "ownet.h" #include "mbeprom.h" // External functions extern SMALLINT owBlock(int,int,uchar *,int); extern SMALLINT owReadByte(int); extern SMALLINT owWriteByte(int,int); extern void output_status(int, char *); extern void msDelay(int); extern void owSerialNum(int,uchar *,int); extern SMALLINT owAccess(int); extern SMALLINT owWriteByte(int,int); extern void setcrc16(int,ushort); extern ushort docrc16(int,ushort); extern void setcrc8(int,uchar); extern uchar docrc8(int,uchar); extern SMALLINT owWriteBytePower(int,int); extern SMALLINT owLevel(int,int); extern SMALLINT owProgramByte(int,SMALLINT,int,SMALLINT,SMALLINT,SMALLINT); extern SMALLINT owHasProgramPulse(int); // general command defines #define READ_MEMORY_COMMAND_EPROM 0xF0 #define MAIN_READ_PAGE_COMMAND_EPROM 0xA5 #define STATUS_READ_PAGE_COMMAND_EPROM 0xAA #define MAIN_WRITE_COMMAND_EPROM 0x0F #define STATUS_WRITE_COMMAND_EPROM 0x55 // Local defines #define SIZE_EPROM 2048 #define PAGE_LENGTH_EPROM 32 // Local functions uchar writeMemCmd(SMALLINT bank, uchar *SNum); SMALLINT numCRCbytes(SMALLINT bank, uchar *SNum); SMALLINT writeVerify(SMALLINT bank, int portnum, uchar *SNum, int page); SMALLINT crcAfterAdd(SMALLINT bank, uchar *SNum); uchar readPageWithCRC(SMALLINT bank, uchar *SNum); SMALLINT isRedirectPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page); SMALLINT lockRedirectPage(SMALLINT bank, int portnum, uchar *SNum, int page); SMALLINT getRedirectedPage(SMALLINT bank, int portnum, uchar *SNum, int page); SMALLINT redirectPage(SMALLINT bank, int portnum, uchar *SNum, int page, int newPage); SMALLINT isPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page); SMALLINT lockPage(SMALLINT bank, int portnum, uchar *SNum, int page); SMALLINT redirectOffset(SMALLINT bank, uchar *SNum); // Global variables char *bankDescription_eprom = "Main Memory"; SMALLINT writeVerification_eprom = TRUE; SMALLINT generalPurposeMemory_eprom = TRUE; SMALLINT readWrite_eprom = FALSE; SMALLINT writeOnce_eprom = TRUE; SMALLINT readOnly_eprom = FALSE; SMALLINT nonVolatile_eprom = TRUE; SMALLINT needsProgramPulse_eprom = TRUE; SMALLINT needsPowerDelivery_eprom = FALSE; SMALLINT hasExtraInfo_eprom = TRUE; SMALLINT extraInfoLength_eprom = 1; char *extraInfoDesc_eprom = "Inverted redirection page"; SMALLINT pageAutoCRC_eprom = TRUE; SMALLINT lockOffset = 0; SMALLINT lockRedirectOffset = 0; SMALLINT canredirectPage = FALSE; SMALLINT canlockPage = FALSE; SMALLINT canlockRedirectPage = FALSE; SMALLINT numPages = 64; SMALLINT CRCbytes = 2; /** * Read memory in the current bank with no CRC checking (device or * data). The resulting data from this API may or may not be what is on * the 1-Wire device. It is recommends that the data contain some kind * of checking (CRC) like in the readPagePacketEPROM() method or have * the 1-Wire device provide the CRC as in readPageCRCEPROM(). readPageCRCEPROM() * however is not supported on all memory types, see 'hasPageAutoCRCEPROM()'. * If neither is an option then this method could be called more * then once to at least verify that the same thing is read consistantly. * * bank to tell what memory bank of the ibutton to use. * portnum the port number of the port being used for the * 1-Wire Network. * SNum the serial number for the part that the read is * to be done on. * str_add starting physical address * rd_cont if 'true' then device read is continued without * re-selecting. This can only be used if the new * read() continious where the last one led off * and it is inside a 'beginExclusive/endExclusive' * block. * buff byte array to place read data into * len length in bytes to read * * @return 'true' if the read was complete */ SMALLINT readEPROM(SMALLINT bank, int portnum, uchar *SNum, int str_add, SMALLINT rd_cont, uchar *buff, int len) { int i; int start_pg, end_pg, num_bytes, pg; uchar raw_buf[256]; // check if read exceeds memory if ((str_add + len) > getSizeEPROM(bank,SNum)) { OWERROR(OWERROR_READ_OUT_OF_RANGE); return FALSE; } // check if status memory if(readPageWithCRC(bank,SNum) == STATUS_READ_PAGE_COMMAND_EPROM) { // no regular read memory so must use readPageCRC start_pg = str_add / getPageLengthEPROM(bank,SNum); end_pg = ((str_add + len) / getPageLengthEPROM(bank,SNum)) - 1; if (((str_add + len) % getPageLengthEPROM(bank,SNum)) > 0) end_pg++; // loop to read the pages for (pg = start_pg; pg <= end_pg; pg++) readPageCRCEPROM(bank,portnum,SNum,pg, &raw_buf[(pg-start_pg)*getPageLengthEPROM(bank,SNum)]); // extract out the data for(i=0;i> 8) & 0xFF; raw_buf[3] = 0xFF; // check if get a 1 byte crc in a normal read. if(SNum[0] == 0x09) num_bytes = 4; else num_bytes = 3; // do the first block for command, address if(!owBlock(portnum,FALSE,raw_buf,num_bytes)) { OWERROR(OWERROR_BLOCK_FAILED); return FALSE; } } // pre-fill readBuf with 0xFF for (i=0;i (getPageLengthEPROM(bank,SNum) * getNumberPagesEPROM(bank,SNum))) { OWERROR(OWERROR_WRITE_OUT_OF_RANGE); return FALSE; } // loop while still have bytes to write write_continue = TRUE; crc_type = numCRCbytes(bank,SNum) - 1; for (i=0;i (getNumberPagesEPROM(bank,SNum))) { OWERROR(OWERROR_READ_OUT_OF_RANGE); return FALSE; } // select the device if (!owAccess(portnum)) { OWERROR(OWERROR_DEVICE_SELECT_FAIL); return FALSE; } // build start reading memory block with: command, address, (extraInfo?), (crc?) len = 3 + getExtraInfoLengthEPROM(bank,SNum); if(crcAfterAdd(bank,SNum)) { len += numCRCbytes(bank,SNum); } for(i=0;i> 8) & 0xFF; // do the first block if(!owBlock(portnum,FALSE,&raw_buf[0],len)) { OWERROR(OWERROR_BLOCK_FAILED); return FALSE; } // check CRC if (numCRCbytes(bank,SNum) == 2) { setcrc16(portnum,0); for(i=0;i 0) || (crcAfterAdd(bank,SNum))) { // check CRC if(numCRCbytes(bank,SNum) == 2) { if (lastcrc != 0xB001) { OWERROR(OWERROR_CRC_FAILED); return FALSE; } } else { if (lastcrc != 0) { return FALSE; } } lastcrc = 0; // extract the extra information extractPnt = len - getExtraInfoLengthEPROM(bank,SNum) - numCRCbytes(bank,SNum); if(getExtraInfoLengthEPROM(bank,SNum)) for(i=extractPnt;i<(extractPnt+getExtraInfoLengthEPROM(bank,SNum));i++) extra[i-extractPnt] = raw_buf[i]; } // pre-fill with 0xFF for(i=0;i<(getPageLengthEPROM(bank,SNum) + numCRCbytes(bank,SNum));i++) raw_buf[i] = 0xFF; // send block to read data + crc if(!owBlock(portnum,FALSE,&raw_buf[0],(getPageLengthEPROM(bank,SNum)+numCRCbytes(bank,SNum)))) { OWERROR(OWERROR_BLOCK_FAILED); return FALSE; } // check the CRC if (numCRCbytes(bank,SNum) == 2) { setcrc16(portnum, (ushort) lastcrc); for(i=0;i<(getPageLengthEPROM(bank,SNum)+numCRCbytes(bank,SNum));i++) lastcrc = docrc16(portnum,raw_buf[i]); if (lastcrc != 0xB001) { OWERROR(OWERROR_CRC_FAILED); return FALSE; } } else { setcrc8(portnum, (uchar) lastcrc); for(i=0;i<(getPageLengthEPROM(bank,SNum)+numCRCbytes(bank,SNum));i++) lastcrc = docrc8(portnum,raw_buf[i]); if (lastcrc != 0) { OWERROR(OWERROR_CRC_FAILED); return FALSE; } } // extract the page data for(i=0;i getMaxPacketDataLengthEPROM(bank,SNum)) { OWERROR(OWERROR_INVALID_PACKET_LENGTH); return FALSE; } // verify the CRC is correct setcrc16(portnum,(ushort) ((getStartingAddressEPROM(bank,SNum)/PAGE_LENGTH_EPROM) + page)); for(i=0;i<(raw_buf[0]+3);i++) lastcrc16 = docrc16(portnum,raw_buf[i]); if(lastcrc16 == 0xB001) { // extract the data out of the packet for(i=0;i getMaxPacketDataLengthEPROM(bank,SNum)) { OWERROR(OWERROR_INVALID_PACKET_LENGTH); return FALSE; } // verify the CRC is correct setcrc16(portnum,(ushort) ((getStartingAddressEPROM(bank,SNum)/PAGE_LENGTH_EPROM) + page)); for(i=0;i<(raw_buf[0]+3);i++) lastcrc16 = docrc16(portnum,raw_buf[i]); if(lastcrc16 == 0xB001) { // extract the data out of the packet for(i=0;i getMaxPacketDataLengthEPROM(bank,SNum)) { OWERROR(OWERROR_INVALID_PACKET_LENGTH); return FALSE; } // see if this bank is general read/write if (!isGeneralPurposeMemoryEPROM(bank,SNum)) { OWERROR(OWERROR_NOT_GENERAL_PURPOSE); return FALSE; } // construct the packet to write raw_buf[0] = (uchar) len; for(i=0;i> 8) & 0xFF; // write the packet, return result if(!writeEPROM(bank,portnum,SNum,page*getPageLengthEPROM(bank,SNum)+ getStartingAddressEPROM(bank,SNum),&raw_buf[0],len+3)) return FALSE; return TRUE; } /** * Query to get the number of pages in current memory bank. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return number of pages in current memory bank */ SMALLINT getNumberPagesEPROM(SMALLINT bank, uchar *SNum) { int pages = numPages; switch(SNum[0]) { case 0x09: if(bank == 0) pages = 4; else if(bank == 1) pages = 1; break; case 0x0B: if((bank == 1) || (bank == 2) || (bank == 3)) pages = 1; else if(bank == 4) pages = 8; break; case 0x0F: if(bank == 0) pages = 256; else if((bank == 1) || (bank == 2)) pages = 4; else if(bank == 3) pages = 3; else if(bank == 4) pages = 32; break; case 0x12: if(bank == 0) pages = 4; else if(bank == 1) pages = 1; break; case 0x13: if(bank == 0) pages = 16; else if(bank == 4) pages = 2; else if((bank == 1) || (bank == 2) || (bank == 3)) pages = 1; break; default: pages = numPages; break; } return pages; } /** * Query to get the memory bank size in bytes. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return memory bank size in bytes. */ int getSizeEPROM(SMALLINT bank, uchar *SNum) { int size = SIZE_EPROM; switch(SNum[0]) { case 0x09: if(bank == 0) size = 128; else if(bank == 1) size = 8; break; case 0x0B: if((bank == 1) || (bank == 2) || (bank == 3)) size = 8; else if(bank == 4) size = 64; break; case 0x0F: if(bank == 0) size = 8192; else if((bank == 1) || (bank == 2)) size = 32; else if(bank == 3) size = 24; else if(bank == 4) size = 256; break; case 0x12: if(bank == 0) size = 128; else if(bank == 1) size = 8; break; case 0x13: if(bank == 0) size = 512; else if(bank == 4) size = 16; else if((bank == 1) || (bank == 2) || (bank == 3)) size = 8; break; default: size = SIZE_EPROM; break; } return size; } /** * Query to get the starting physical address of this bank. Physical * banks are sometimes sub-divided into logical banks due to changes * in attributes. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return physical starting address of this logical bank. */ int getStartingAddressEPROM(SMALLINT bank, uchar *SNum) { int addr = 0; switch(SNum[0]) { case 0x0B: if(bank == 2) addr = 32; else if(bank == 3) addr = 64; else if(bank == 4) addr = 256; break; case 0x0F: if(bank == 2) addr = 32; else if(bank == 3) addr = 64; else if(bank == 4) addr = 256; break; case 0x13: if(bank == 2) addr = 32; else if(bank == 3) addr = 64; else if(bank == 4) addr = 256; break; default: addr = 0; break; } return addr; } /** * Query to get page length in bytes in current memory bank. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return page length in bytes in current memory bank */ SMALLINT getPageLengthEPROM(SMALLINT bank, uchar *SNum) { int len = PAGE_LENGTH_EPROM; switch(SNum[0]) { case 0x09: if(bank == 1) len = 8; break; case 0x0B: if((bank > 0) && (bank < 5)) len = 8; case 0x0F: if((bank > 0) && (bank <5)) len = 8; break; case 0x12: if(bank == 1) len = 8; break; case 0x13: if((bank > 0) && (bank < 5)) len = 8; break; default: len = PAGE_LENGTH_EPROM; break; } return len; } /** * Query to see get a string description of the current memory bank. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return String containing the memory bank description */ char *getBankDescriptionEPROM(SMALLINT bank, uchar *SNum) { switch(SNum[0]) { case 0x09: if(bank == 1) return "Write protect pages and page redirection"; break; case 0x0B: if(bank == 1) return "Write protect pages"; else if(bank == 2) return "Write protect redirection"; else if(bank == 3) return "Bitmap of used pages for file structure"; else if(bank == 4) return "Page redirection bytes"; break; case 0x0F: if(bank == 1) return "Write protect pages"; else if(bank == 2) return "Write protect redirection"; else if(bank == 3) return "Bitmap of used pages for file structure"; else if(bank == 4) return "Pages redirection bytes"; break; case 0x12: if(bank == 1) return "Write protect pages, page redirection, switch control"; break; case 0x13: if(bank == 1) return "Write protect pages"; else if(bank == 2) return "Write protect redirection"; else if(bank == 3) return "Bitmap of used pages for file structure"; else if(bank == 4) return "Page redirection bytes"; break; default: return bankDescription_eprom; break; } return bankDescription_eprom; } /** * Query to see if the current memory bank is general purpose * user memory. If it is NOT then it is Memory-Mapped and writing * values to this memory will affect the behavior of the 1-Wire * device. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return 'true' if current memory bank is general purpose */ SMALLINT isGeneralPurposeMemoryEPROM(SMALLINT bank, uchar *SNum) { int gp_mem = generalPurposeMemory_eprom; switch(SNum[0]) { case 0x09: if(bank == 1) gp_mem = FALSE; break; case 0x0B: if((bank > 0) && (bank < 5)) gp_mem = FALSE; case 0x0F: if((bank > 0) && (bank <5)) gp_mem = FALSE; break; case 0x12: if(bank == 1) gp_mem = FALSE; break; case 0x13: if((bank > 0) && (bank < 5)) gp_mem = FALSE; break; default: gp_mem = generalPurposeMemory_eprom; break; } return gp_mem; } /** * Query to see if current memory bank is read/write. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return 'true' if current memory bank is read/write */ SMALLINT isReadWriteEPROM(SMALLINT bank, int portnum, uchar *SNum) { return readWrite_eprom; } /** * Query to see if current memory bank is write write once such * as with EPROM technology. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return 'true' if current memory bank can only be written once */ SMALLINT isWriteOnceEPROM(SMALLINT bank, int portnum, uchar *SNum) { return writeOnce_eprom; } /** * Query to see if current memory bank is read only. * * @return 'true' if current memory bank can only be read */ SMALLINT isReadOnlyEPROM(SMALLINT bank, int portnum, uchar *SNum) { return readOnly_eprom; } /** * Query to see if current memory bank non-volatile. Memory is * non-volatile if it retains its contents even when removed from * the 1-Wire network. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return 'true' if current memory bank non volatile. */ SMALLINT isNonVolatileEPROM(SMALLINT bank, uchar *SNum) { return nonVolatile_eprom; } /** * Query to see if current memory bank pages need the adapter to * have a 'ProgramPulse' in order to write to the memory. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return 'true' if writing to the current memory bank pages * requires a 'ProgramPulse'. */ SMALLINT needsProgramPulseEPROM(SMALLINT bank, uchar *SNum) { return needsProgramPulse_eprom; } /** * Query to see if current memory bank pages need the adapter to * have a 'PowerDelivery' feature in order to write to the memory. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return 'true' if writing to the current memory bank pages * requires 'PowerDelivery'. */ SMALLINT needsPowerDeliveryEPROM(SMALLINT bank, uchar *SNum) { return needsPowerDelivery_eprom; } /** * Checks to see if this memory bank's pages deliver extra * information outside of the normal data space, when read. Examples * of this may be a redirection byte, counter, tamper protection * bytes, or SHA-1 result. If this method returns true then the * methods with an 'extraInfo' parameter can be used. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return true if reading the this memory bank's * pages provides extra information */ SMALLINT hasExtraInfoEPROM(SMALLINT bank, uchar *SNum) { SMALLINT hasExtra = hasExtraInfo_eprom; switch(SNum[0]) { case 0x09: hasExtra = FALSE; break; case 0x0B: if((bank > 0) && (bank < 5)) hasExtra = FALSE; break; case 0x0F: if((bank > 0) && (bank < 5)) hasExtra = FALSE; break; case 0x12: if(bank == 1) hasExtra = FALSE; break; case 0x13: if((bank > 0) && (bank < 5)) hasExtra = FALSE; break; default: hasExtra = hasExtraInfo_eprom; break; } return hasExtra; } /** * Query to get the length in bytes of extra information that * is read when read a page in the current memory bank. See * 'hasExtraInfoEPROM()'. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return number of bytes in Extra Information read when reading * pages in the current memory bank. */ SMALLINT getExtraInfoLengthEPROM(SMALLINT bank, uchar *SNum) { SMALLINT len = extraInfoLength_eprom; switch(SNum[0]) { case 0x09: len = 0; break; case 0x0B: if((bank > 0) && (bank < 5)) len = 0; break; case 0x0F: if((bank > 0) && (bank < 5)) len = 0; break; case 0x12: if(bank == 1) len = 0; break; case 0x13: if((bank > 0) && (bank < 5)) len = 0; break; default: len = extraInfoLength_eprom; break; } return len; } /** * Query to get a string description of what is contained in * the Extra Informationed return when reading pages in the current * memory bank. See 'hasExtraInfoEPROM()'. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return string describing extra information. */ char *getExtraInfoDescEPROM(SMALLINT bank, uchar *SNum) { switch(SNum[0]) { case 0x09: return " "; break; case 0x0B: if((bank > 0) && (bank < 5)) return " "; break; case 0x0F: if((bank > 0) && (bank < 5)) return " "; break; case 0x12: if(bank == 1) return " "; break; case 0x13: if((bank > 0) && (bank < 5)) return " "; break; default: return extraInfoDesc_eprom; break; } return extraInfoDesc_eprom; } /** * Query to see if current memory bank pages can be read with * the contents being verified by a device generated CRC. * This is used to see if the 'ReadPageCRCEPROM()' can be used. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return 'true' if current memory bank can be read with self * generated CRC. */ SMALLINT hasPageAutoCRCEPROM(SMALLINT bank, uchar *SNum) { return pageAutoCRC_eprom; } /** * Query to get Maximum data page length in bytes for a packet * read or written in the current memory bank. See the 'ReadPagePacket()' * and 'WritePagePacket()' methods. This method is only usefull * if the current memory bank is general purpose memory. * * @return max packet page length in bytes in current memory bank */ SMALLINT getMaxPacketDataLengthEPROM(SMALLINT bank, uchar *SNum) { return getPageLengthEPROM(bank,SNum) - 3; } //-------- //-------- OTPMemoryBank I/O methods //-------- /** * Lock the specifed page in the current memory bank. Not supported * by all devices. See the method 'canLockPageEPROM()'. * * bank to tell what memory bank of the ibutton to use. * portnum the port number of the port being used for the * 1-Wire Network. * SNum the serial number for the part. * page the page to be locked * * @return true if the page was locked * false otherwise */ SMALLINT lockPage(SMALLINT bank, int portnum, uchar *SNum, int page) { int nbyt,nbit; SMALLINT write_bank; uchar wr_byte[1]; // setting the bank to write // and since all the page lock info is in // bank 1 for all the EPROM parts. write_bank = 1; if(isPageLocked(write_bank,portnum,SNum,page)) { OWERROR(OWERROR_PAGE_ALREADY_LOCKED); return FALSE; } // create byte to write to mlLock to lock page nbyt = (page >> 3); nbit = page - (nbyt << 3); wr_byte[0] = (uchar) ~(0x01 << nbit); // write the lock bit if(!writeEPROM(write_bank,portnum,SNum,nbyt + lockOffset,wr_byte,1)) return FALSE; // read back to verify if(!isPageLocked(write_bank,portnum,SNum,page)) { OWERROR(OWERROR_READ_BACK_NOT_VALID); return FALSE; } return TRUE; } /** * Query to see if the specified page is locked. * See the method 'canLockPage()'. * * bank to tell what memory bank of the ibutton to use. * portnum the port number of the port being used for the * 1-Wire Network. * SNum the serial number for the part. * page the page to check if locked * * @return true if page locked. */ SMALLINT isPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page) { int pg_len, read_pg, index, nbyt, nbit; SMALLINT read_bank; uchar read_buf[PAGE_LENGTH_EPROM]; // setting the bank to read for information // and since all the page lock info is in // bank 1 for all the EPROM parts. read_bank = 1; // read page that locked bit is on pg_len = getPageLengthEPROM(read_bank,SNum); read_pg = (page + lockOffset) / (pg_len * 8); if(!readPageCRCEPROM(read_bank,portnum,SNum,read_pg,read_buf)) return FALSE; // return boolean on locked bit index = (page + lockOffset) - (read_pg * 8 * pg_len); nbyt = (index >> 3); nbit = index - (nbyt << 3); return !(((read_buf[nbyt] >> nbit) & 0x01) == 0x01); } /** * Redirect the specifed page in the current memory bank to a new page. * Not supported by all devices. See the method 'canRedirectPage()'. * * bank to tell what memory bank of the ibutton to use. * portnum the port number of the port being used for the * 1-Wire Network. * SNum the serial number for the part. * page the page to be locked * newPage new page number to redirect to * * @return true if the page was redirected */ SMALLINT redirectPage(SMALLINT bank, int portnum, uchar *SNum, int page, int newPage) { uchar wr_byte[1]; // create byte to redirect page SMALLINT write_bank; if(isRedirectPageLocked(bank,portnum,SNum,page)) { OWERROR(OWERROR_REDIRECTED_PAGE); return FALSE; } // setting the bank to write switch(SNum[0]) { case 0x09: case 0x12: write_bank = 1; break; case 0x0B: case 0x0F: case 0x13: write_bank = 4; break; default: write_bank = 4; break; } wr_byte[0] = (uchar) ~newPage; // write the redirection byte if(!writeEPROM(write_bank,portnum,SNum,page + redirectOffset(bank,SNum),wr_byte,1)) return FALSE; return TRUE; } /** * Gets the page redirection of the specified page. * Not supported by all devices. * * bank to tell what memory bank of the ibutton to use. * portnum the port number of the port being used for the * 1-Wire Network. * SNum the serial number for the part. * page number of page check for redirection * * @return the new page number or 0 if not redirected */ SMALLINT getRedirectedPage(SMALLINT bank, int portnum, uchar *SNum, int page) { int pg_len, read_pg; SMALLINT read_bank; uchar read_buf[PAGE_LENGTH_EPROM]; // setting the bank to read for information switch(SNum[0]) { case 0x09: case 0x12: read_bank = 1; break; case 0x0B: case 0x0F: case 0x13: read_bank = 4; break; default: read_bank = 4; break; } // read page that redirect byte is on pg_len = getPageLengthEPROM(read_bank,SNum); read_pg = (page + redirectOffset(bank,SNum)) / pg_len; if(!readPageCRCEPROM(read_bank,portnum,SNum,read_pg,read_buf)) return FALSE; // return page return (SMALLINT) (~read_buf[(page + redirectOffset(bank,SNum)) % pg_len] & 0x000000FF); } /** * Lock the redirection option for the specifed page in the current * memory bank. Not supported by all devices. See the method * 'canLockRedirectPage()'. * * bank to tell what memory bank of the ibutton to use. * portnum the port number of the port being used for the * 1-Wire Network. * SNum the serial number for the part. * page number of page to redirect * * @return true if the redirected page is locked. */ SMALLINT lockRedirectPage(SMALLINT bank, int portnum, uchar *SNum, int page) { int nbyt, nbit; SMALLINT write_bank; uchar wr_byte[1]; if(isRedirectPageLocked(bank,portnum,SNum,page)) { OWERROR(OWERROR_LOCKING_REDIRECTED_PAGE_AGAIN); return FALSE; } // setting the bank to write switch(SNum[0]) { case 0x0B: case 0x0F: case 0x13: write_bank = 2; break; default: write_bank = 0; break; } // create byte to write to mlLock to lock page nbyt = (page >> 3); nbit = page - (nbyt << 3); wr_byte[0] = (uchar) ~(0x01 << nbit); // write the lock bit if(!writeEPROM(write_bank,portnum,SNum,nbyt + lockRedirectOffset,wr_byte,1)) return FALSE; // read back to verify if (!isRedirectPageLocked(bank,portnum,SNum,page) || (write_bank == 0)) { OWERROR(OWERROR_COULD_NOT_LOCK_REDIRECT); return FALSE; } return TRUE; } /** * Query to see if the specified page has redirection locked. * Not supported by all devices. See the method 'canRedirectPage()'. * * bank to tell what memory bank of the ibutton to use. * portnum the port number of the port being used for the * 1-Wire Network. * SNum the serial number for the part. * page number of page to check for redirection * * @return true if redirection is locked for this page */ SMALLINT isRedirectPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page) { int pg_len, read_pg, index, nbyt, nbit; SMALLINT read_bank; uchar read_buf[PAGE_LENGTH_EPROM]; // setting the bank to read for information switch(SNum[0]) { case 0x0B: case 0x0F: case 0x13: read_bank = 2; break; default: return FALSE; break; } // read page that lock redirect bit is on pg_len = getPageLengthEPROM(read_bank,SNum); read_pg = (page + lockRedirectOffset) / (pg_len * 8); if(!readPageCRCEPROM(read_bank,portnum,SNum,read_pg,read_buf)) return FALSE; // return boolean on lock redirect bit index = (page + lockRedirectOffset) - (read_pg * 8 * pg_len); nbyt = (index >> 3); nbit = index - (nbyt << 3); return !(((read_buf[nbyt] >> nbit) & 0x01) == 0x01); } /** * Query to see if current memory bank pages can be redirected * to another pages. This is mostly used in Write-Once memory * to provide a means to update. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return 'true' if current memory bank pages can be redirected * to a new page. */ SMALLINT canRedirectPageEPROM(SMALLINT bank, uchar *SNum) { SMALLINT canRedirect = canredirectPage; switch(SNum[0]) { case 0x09: if(bank == 0) canRedirect = TRUE; break; case 0x0B: if(bank == 0) canRedirect = TRUE; break; case 0x0F: if(bank == 0) canRedirect = TRUE; break; case 0x12: if(bank == 0) canRedirect = TRUE; break; case 0x13: if(bank == 0) canRedirect = TRUE; break; default: canRedirect = canredirectPage; break; } return canRedirect; } /** * Query to see if current memory bank pages can be locked. A * locked page would prevent any changes to the memory. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return 'true' if current memory bank pages can be redirected * to a new page. */ SMALLINT canLockPageEPROM(SMALLINT bank, uchar *SNum) { SMALLINT canLock = canlockPage; switch(SNum[0]) { case 0x09: if(bank == 0) canLock = TRUE; break; case 0x0B: if(bank == 0) canLock = TRUE; break; case 0x0F: if(bank == 0) canLock = TRUE; break; case 0x12: if(bank == 0) canLock = TRUE; break; case 0x13: if(bank == 0) canLock = TRUE; break; default: canLock = canlockPage; break; } return canLock; } /** * Query to see if current memory bank pages can be locked from * being redirected. This would prevent a Write-Once memory from * being updated. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return 'true' if current memory bank pages can be locked from * being redirected to a new page. */ SMALLINT canLockRedirectPageEPROM(SMALLINT bank, uchar *SNum) { SMALLINT lockRedirect = canlockRedirectPage; switch(SNum[0]) { case 0x0B: if(bank == 0) lockRedirect = TRUE; break; case 0x0F: if(bank == 0) lockRedirect = TRUE; break; case 0x13: if(bank == 0) lockRedirect = TRUE; break; default: lockRedirect = canlockRedirectPage; break; } return lockRedirect; } //-------- //-------- Local functions //-------- /** * Send the command for writing to memory for a device given * the memory bank and serial number. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return the command for writing to the memory bank. */ uchar writeMemCmd(SMALLINT bank, uchar *SNum) { uchar command = MAIN_WRITE_COMMAND_EPROM; switch(SNum[0]) { case 0x09: if(bank == 1) command = STATUS_WRITE_COMMAND_EPROM; break; case 0x0B: if((bank > 0) && (bank < 5)) command = STATUS_WRITE_COMMAND_EPROM; break; case 0x0F: if((bank > 0) && (bank < 5)) command = STATUS_WRITE_COMMAND_EPROM; break; case 0x12: if(bank == 1) command = STATUS_WRITE_COMMAND_EPROM; break; case 0x13: if((bank > 0) && (bank < 5)) command = STATUS_WRITE_COMMAND_EPROM; break; default: command = MAIN_WRITE_COMMAND_EPROM; break; } return command; } /** * Get the number of CRC bytes for the device. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return the number of CRC bytes. */ SMALLINT numCRCbytes(SMALLINT bank, uchar *SNum) { SMALLINT numbytes = CRCbytes; switch(SNum[0]) { case 0x09: if((bank == 0) || (bank == 1)) numbytes = 1; break; default: numbytes = CRCbytes; break; } return numbytes; } /** * Get the status of the page the pages write verification * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return true if write verification is used and * false if it is not used. */ SMALLINT writeVerify(SMALLINT bank, int portnum, uchar *SNum, int page) { if(isPageLocked(bank,portnum,SNum,page) || isRedirectPageLocked(bank,portnum,SNum,page)) return FALSE; return writeVerification_eprom; } /** * Get crc after sending command,address * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return true if crc is can be gotten after sending command,address * false otherwise */ SMALLINT crcAfterAdd(SMALLINT bank, uchar *SNum) { SMALLINT crcAfter = TRUE; switch(SNum[0]) { case 0x0B: if((bank > 0) && (bank < 5)) crcAfter = FALSE; break; case 0x0F: if((bank > 0) && (bank < 5)) crcAfter = FALSE; break; case 0x12: if(bank == 1) crcAfter = FALSE; break; case 0x13: if((bank > 0) && (bank < 5)) crcAfter = FALSE; break; default: crcAfter = TRUE; break; } return crcAfter; } /** * Get the byte command for reading the page with crc. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return the byte command for reading the page */ uchar readPageWithCRC(SMALLINT bank, uchar *SNum) { uchar readPage = MAIN_READ_PAGE_COMMAND_EPROM; switch(SNum[0]) { case 0x09: if(bank == 0) readPage = 0xC3; else if(bank == 1) readPage = STATUS_READ_PAGE_COMMAND_EPROM; break; case 0x0B: if((bank > 0) && (bank < 5)) readPage = STATUS_READ_PAGE_COMMAND_EPROM; break; case 0x0F: if((bank > 0) && (bank < 5)) readPage = STATUS_READ_PAGE_COMMAND_EPROM; break; case 0x12: if(bank == 1) readPage = STATUS_READ_PAGE_COMMAND_EPROM; break; case 0x13: if((bank > 0) && (bank < 5)) readPage = STATUS_READ_PAGE_COMMAND_EPROM; break; default: readPage = MAIN_READ_PAGE_COMMAND_EPROM; break; } return readPage; } /** * Get the offset into the redirection status information. * * bank to tell what memory bank of the ibutton to use. * SNum the serial number for the part. * * @return the offset into the redirection status */ SMALLINT redirectOffset(SMALLINT bank, uchar *SNum) { int offset = 0; switch(SNum[0]) { case 0x09: if(bank == 0) offset = 1; break; case 0x12: if(bank == 0) offset = 1; break; default: offset = 0; break; } return offset; }