1-Wire® library for mbed. Complete 1-Wire library that supports our silicon masters along with a bit-bang master on the MAX32600MBED platform with one common interface for mbed. Slave support has also been included and more slaves will be added as time permits.
Dependents: MAXREFDES131_Qt_Demo MAX32630FTHR_iButton_uSD_Logger MAX32630FTHR_DS18B20_uSD_Logger MAXREFDES130_131_Demo ... more
Superseded by MaximInterface.
OneWire_Memory/Authenticators/DS28E15_22_25/DS28E15_22_25.cpp
- Committer:
- IanBenzMaxim
- Date:
- 2016-03-31
- Revision:
- 33:a4c015046956
- Parent:
- 32:bce180b544ed
- Child:
- 34:11fffbe98ef9
File content as of revision 33:a4c015046956:
//------------Copyright (C) 2013 Maxim Integrated Products -------------- // // 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 MAXIM INTEGRATED PRODCUTS 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 Maxim Integrated Products // shall not be used except as stated in the Maxim Integrated Products // Branding Policy. // --------------------------------------------------------------------------- #include "DS28E15_22_25.hpp" #include "OneWire_Masters/OneWireMaster.h" #include "mbed.h" // delay durations #ifdef LOW_VOLTAGE #define SHA_COMPUTATION_DELAY 4 #define EEPROM_WRITE_DELAY 15 #define SECRET_EEPROM_DELAY 200 #else #define SHA_COMPUTATION_DELAY 3 #define EEPROM_WRITE_DELAY 10 #define SECRET_EEPROM_DELAY 90 #endif // 1-Wire commands #define CMD_WRITE_MEMORY 0x55 #define CMD_READ_MEMORY 0xF0 #define CMD_LOAD_LOCK_SECRET 0x33 #define CMD_COMPUTE_LOCK_SECRET 0x3C #define CMD_SELECT_SECRET 0x0F #define CMD_COMPUTE_PAGEMAC 0xA5 #define CMD_READ_STATUS 0xAA #define CMD_WRITE_BLOCK_PROTECT 0xC3 #define CMD_WRITE_AUTH_MEMORY 0x5A #define CMD_WRITE_AUTH_PROTECT 0xCC #define CMD_PIO_READ 0xDD #define CMD_PIO_WRITE 0x96 #define BLOCK_READ_PROTECT 0x80 #define BLOCK_WRITE_PROTECT 0x40 #define BLOCK_EPROM_PROTECT 0x20 #define BLOCK_WRITE_AUTH_PROTECT 0x10 #define PROT_BIT_AUTHWRITE 0x10 #define PROT_BIT_EPROM 0x20 #define PROT_BIT_WRITE 0x40 #define PROT_BIT_READ 0x80 DS28E15_22_25::DS28E15_22_25(OneWireMaster& OW_master) : m_OW_master(OW_master) { std::memset(manId, 0x00, manId.length); } DS28E15_22_25::DevicePages DS28E15_22_25::devicePages() { DevicePages pages; switch (romId.familyCode()) { case DS28E25_FAMILY: pages = DS28E25_PAGES; break; case DS28E22_FAMILY: pages = DS28E22_PAGES; break; case DS28E15_FAMILY: pages = DS28E15_PAGES; break; default: pages = UNKNOWN_PAGES; break; } return pages; } DS28E15_22_25::DeviceBlocks DS28E15_22_25::deviceBlocks() { DeviceBlocks blocks; switch (romId.familyCode()) { case DS28E25_FAMILY: blocks = DS28E25_BLOCKS; break; case DS28E22_FAMILY: blocks = DS28E22_BLOCKS; break; case DS28E15_FAMILY: blocks = DS28E15_BLOCKS; break; default: blocks = UNKNOWN_BLOCKS; break; } return blocks; } //-------------------------------------------------------------------------- // Write page protection byte. // // Parameters // block - block number (0 to 7) which covers two pages each // new_value - new protection byte // old_value - old protection byte // manid - manufacturer ID // contflag - Flag to indicate the write is continued from the last // // Returns: true - protection written // false - Failed to set protection // OneWireSlave::CmdResult DS28E15_22_25::WriteAuthBlockProtection(const ISha256MacCoprocessor & MacCoproc, std::uint8_t newProtection, std::uint8_t oldProtection, bool contflag) { std::uint8_t buf[256], cs; int cnt = 0; Mac mac; buf[cnt++] = CMD_WRITE_AUTH_PROTECT; buf[cnt++] = newProtection; // Send command m_OW_master.OWWriteBlock(&buf[0], 2); // read first CRC byte m_OW_master.OWReadByte(buf[cnt++]); // read the last CRC and enable m_OW_master.OWReadBytePower(buf[cnt++]); // now wait for the MAC computation. wait_ms(SHA_COMPUTATION_DELAY); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // check CRC16 if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001) return CommunicationError; ISha256MacCoprocessor::CmdResult result; result = CalculateProtectionWriteMAC256(MacCoproc, newProtection, oldProtection, romId, manId, mac); if (result != ISha256MacCoprocessor::Success) return OperationFailure; cnt = 0; // send the MAC m_OW_master.OWWriteBlock(mac, mac.length); // Read CRC and CS byte m_OW_master.OWReadBlock(&buf[cnt], 3); cnt += 3; // ckeck CRC16 if (OneWireMaster::calculateCRC16(buf, 0, (cnt - 1)) != 0xB001) return CommunicationError; // check CS if (buf[cnt-1] != 0xAA) return OperationFailure; // send release and strong pull-up // DATASHEET_CORRECTION - last bit in release is a read-zero so don't check echo of write byte m_OW_master.OWWriteBytePower(0xAA); // now wait for the MAC computation. wait_ms(EEPROM_WRITE_DELAY); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // read the CS byte m_OW_master.OWReadByte(cs); if (cs == 0xAA) return Success; // else return OperationFailure; } //-------------------------------------------------------------------------- // Write page protection byte. // // Parameters // block - block number (0 to 7) which covers two pages each // prot - protection byte // contflag - Flag to indicate the write is continued from the last // // Returns: true - protection written // false - Failed to set protection // OneWireSlave::CmdResult DS28E15_22_25::WriteBlockProtection(std::uint8_t protection, bool continuing) { std::uint8_t buf[256], cs; int cnt = 0; // check if not continuing a previous block write if (!continuing) { buf[cnt++] = CMD_WRITE_BLOCK_PROTECT; } // compute parameter byte buf[cnt++] = protection; m_OW_master.OWWriteBlock(&buf[0], cnt); // Read CRC m_OW_master.OWReadBlock(&buf[cnt], 2); cnt += 2; // check CRC16 if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001) return CommunicationError; // DATASHEET_CORRECTION, on continue need second release byte if (continuing) m_OW_master.OWWriteByte(0xAA); // sent release m_OW_master.OWWriteBytePower(0xAA); // now wait for programming wait_ms(EEPROM_WRITE_DELAY); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // read the CS byte m_OW_master.OWReadByte(cs); if (cs == 0xAA) return Success; // else return OperationFailure; } OneWireSlave::CmdResult DS28E15_22_25::ReadBlockProtectionStatus(unsigned int blockNum, std::uint8_t & status) { unsigned char buf; CmdResult result = ReadStatus(false, false, blockNum, &buf); if (result == Success) status = buf; return result; } //-------------------------------------------------------------------------- // Read status bytes, either personality or page protection. // // Parameters // personality - flag to indicate the read is the 4 personality bytes (true) // or page page protection (false) // allpages - flag to indicate if just one page (false) or all (true) page protection // bytes. // page_num - page number if reading protection 0 to 1 // rdbuf - 16 byte buffer personality bytes (length 4) or page protection // (length 1 or 16) // // Returns: true - status read // false - Failed to read status // OneWireSlave::CmdResult DS28E15_22_25::ReadStatus(bool personality, bool allpages, unsigned int pageNum, unsigned char *rdbuf) const { unsigned char buf[256]; int cnt, offset, rdnum; cnt = 0; offset = 0; buf[cnt++] = CMD_READ_STATUS; if (personality) buf[cnt++] = 0xE0; else if (!allpages) buf[cnt++] = pageNum; else buf[cnt++] = 0; // send the command m_OW_master.OWWriteBlock(&buf[0], 2); offset = cnt + 2; // adjust data length if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY)) { if (personality) rdnum = 8; else if (allpages) rdnum = 20; else rdnum = 5; } else { if ((personality) || (allpages)) rdnum = 8; else rdnum = 5; } // Read the bytes m_OW_master.OWReadBlock(&buf[cnt],rdnum); cnt += rdnum; // check the first CRC16 if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001) return CommunicationError; if ((((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY)) && (allpages || (pageNum == 15))) || (personality || allpages || (pageNum == 1))) { // check the second CRC16 if (OneWireMaster::calculateCRC16(buf, offset, (cnt - offset)) != 0xB001) return CommunicationError; } // copy the data to the read buffer memcpy(rdbuf, &buf[offset], rdnum - 4); return Success; } ISha256MacCoprocessor::CmdResult DS28E15_22_25::CalculateAuthMAC256(const ISha256MacCoprocessor & MacCoproc, unsigned int pageNum, const Scratchpad & challenge, const Page & pageData, const RomId & romId, const ManId & manId, bool anon, Mac & mac) { ISha256MacCoprocessor::AuthMacData authMacData; // insert ROM number or FF if (anon) std::memset(authMacData, 0xFF, RomId::byteLen); else std::memcpy(authMacData, romId, RomId::byteLen); authMacData[10] = pageNum; authMacData[9] = manId[0]; authMacData[8] = manId[1]; authMacData[11] = 0x00; return MacCoproc.computeAuthMac(pageData, challenge, authMacData, mac); } //-------------------------------------------------------------------------- // Verify provided MAC and page data. Optionally do // annonymous mode (anon != 0). // // Parameters // page_num - page number to read 0 - 16 // challange - 32 byte buffer containing the challenge // page_data - 32 byte buffer to contain the data read // manid - 2 byte buffer containing the manufacturer ID (general device: 00h,00h) // mac - 32 byte buffer of mac read // anon - Flag to indicate Annonymous mode // // Returns: true - page read has correct MAC // false - Failed to read page or incorrect MAC // ISha256MacCoprocessor::CmdResult DS28E15_22_25::AuthVerify(const ISha256MacCoprocessor & MacCoproc, unsigned int page_num, const Scratchpad & challenge, const Page & pageData, const RomId & romId, const ManId & manId, bool anon, const Mac & mac) { Mac calc_mac; ISha256MacCoprocessor::CmdResult result; result = CalculateAuthMAC256(MacCoproc, page_num, challenge, pageData, romId, manId, anon, calc_mac); if (result == ISha256MacCoprocessor::Success) { if (mac != calc_mac) result = ISha256MacCoprocessor::OperationFailure; } return result; } //-------------------------------------------------------------------------- // Do Compute Page MAC command and return MAC. Optionally do // annonymous mode (anon != 0). // // Parameters // sn - secret number 0 or 1 // page_num - page number to read 0 - 16 // challange - 32 byte buffer containing the challenge // mac - 32 byte buffer for page data read // anon - Flag to indicate Annonymous mode // // Returns: true - page read has correct MAC // false - Failed to read page or incorrect MAC // OneWireSlave::CmdResult DS28E15_22_25::ComputeReadPageMAC(unsigned int page_num, bool anon, Mac & mac) const { std::uint8_t buf[256],cs; int cnt = 0; buf[cnt++] = CMD_COMPUTE_PAGEMAC; buf[cnt++] = ((anon) ? 0xE0 : 0x00) | page_num; // Send command m_OW_master.OWWriteBlock(&buf[0], 2); // read first CRC byte m_OW_master.OWReadByte(buf[cnt++]); // read the last CRC and enable m_OW_master.OWReadBytePower(buf[cnt++]); // now wait for the MAC computation. wait_ms(SHA_COMPUTATION_DELAY * 2); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // check CRC16 if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001) return CommunicationError; // read the CS byte m_OW_master.OWReadByte(cs); if (cs != 0xAA) return OperationFailure; // read the MAC and CRC m_OW_master.OWReadBlock(&buf[0], (Mac::length + 2)); // check CRC16 if (OneWireMaster::calculateCRC16(buf, 0, (Mac::length + 2)) != 0xB001) return CommunicationError; // copy MAC to return buffer memcpy(mac, buf, Mac::length); return Success; } //---------------------------------------------------------------------- // Compute secret operation on the DS28E25/DS28E22/DS28E15. // // 'sn' - secret number 0 or 1 // 'partial' - partial secret to load (32 bytes) // 'pagedata' - page data to compute (32 bytes) // 'lock' - option to lock the secret after the load (lock = true) // // Return: true - load complete // false - error during load, device not present // OneWireSlave::CmdResult DS28E15_22_25::ComputeSecret(unsigned int page_num, bool lock) { std::uint8_t buf[256], cs; int cnt = 0; buf[cnt++] = CMD_COMPUTE_LOCK_SECRET; buf[cnt++] = (lock) ? (0xE0 | page_num) : page_num; // lock flag // Send command m_OW_master.OWWriteBlock(&buf[0], 2); // Read CRC m_OW_master.OWReadBlock(&buf[cnt], 2); cnt += 2; // check CRC16 if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001) return CommunicationError; // send release and strong pull-up m_OW_master.OWWriteBytePower(0xAA); // now wait for the MAC computation. wait_ms(SHA_COMPUTATION_DELAY * 2 + SECRET_EEPROM_DELAY); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // read the CS byte m_OW_master.OWReadByte(cs); if (cs == 0xAA) return Success; // else return OperationFailure; } //---------------------------------------------------------------------- // Write the scratchpad (challenge or secret) // // 'sn' - secret number 0 or 1 // 'data' - data to write to the scratchpad (32 bytes) // // Return: true - select complete // false - error during select, device not present // OneWireSlave::CmdResult DS28E15_22_25::WriteScratchpad(const Scratchpad & data) const { std::uint8_t buf[256]; int cnt = 0, offset; buf[cnt++] = CMD_SELECT_SECRET; if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY)) buf[cnt++] = 0x20; else buf[cnt++] = 0x00; // Send command m_OW_master.OWWriteBlock(&buf[0], 2); // Read CRC m_OW_master.OWReadBlock(&buf[cnt], 2); cnt += 2; offset = cnt; // add the data memcpy(&buf[cnt], data, data.length); cnt += data.length; // Send the data m_OW_master.OWWriteBlock(data, data.length); // Read CRC m_OW_master.OWReadBlock(&buf[cnt], 2); cnt += 2; // check first CRC16 if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001) return CommunicationError; // check the second CRC16 if (OneWireMaster::calculateCRC16(buf, offset, (cnt - offset)) != 0xB001) return CommunicationError; return Success; } //---------------------------------------------------------------------- // Load first secret operation on the DS28E25/DS28E22/DS28E15. // // 'sn' - secret number 0 or 1 // 'secret' - secret to load (32 bytes) // 'lock' - option to lock the secret after the load (lock = true) // // Return: true - load complete // false - error during load, device not present // OneWireSlave::CmdResult DS28E15_22_25::LoadSecret(bool lock) { std::uint8_t buf[256], cs; int cnt = 0; buf[cnt++] = CMD_LOAD_LOCK_SECRET; buf[cnt++] = (lock) ? 0xE0 : 0x00; // lock flag // Send command m_OW_master.OWWriteBlock(&buf[0], 2); // Read CRC m_OW_master.OWReadBlock(&buf[cnt], 2); cnt += 2; // check CRC16 if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001) return CommunicationError; // send release and strong pull-up m_OW_master.OWWriteBytePower(0xAA); // now wait for the MAC computation. wait_ms(SECRET_EEPROM_DELAY); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // read the CS byte m_OW_master.OWReadByte(cs); if (cs == 0xAA) return Success; // else return OperationFailure; } //-------------------------------------------------------------------------- // Read page and verify CRC. Multiple pages can // be read without re-selecting the device using the continue flag. // // Parameters // page - page number where the block to write is located (0 to 15) // rdbuf - 32 byte buffer to contain the data to read // contflag - Flag to indicate the write is continued from the last // // Returns: true - block read and verified CRC // false - Failed to write block (no presence or invalid CRC16) // OneWireSlave::CmdResult DS28E15_22_25::readPage(unsigned int page, Page & rdbuf, bool continuing) const { std::uint8_t buf[256]; int cnt, offset; cnt = 0; offset = 0; // check if not continuing a previous block write if (!continuing) { buf[cnt++] = CMD_READ_MEMORY; buf[cnt++] = page; // address // Send command m_OW_master.OWWriteBlock(&buf[0], 2); // Read CRC m_OW_master.OWReadBlock(&buf[cnt], 2); cnt += 2; offset = cnt; } // read data and CRC16 m_OW_master.OWReadBlock(&buf[cnt], (rdbuf.length + 2)); cnt += 34; // check the first CRC16 if (!continuing) { if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001) return CommunicationError; } // check the second CRC16 if (OneWireMaster::calculateCRC16(buf, offset, (cnt - offset)) != 0xB001) return CommunicationError; // copy the data to the read buffer memcpy(rdbuf, &buf[offset], rdbuf.length); return Success; } //-------------------------------------------------------------------------- // Write a 4 byte memory block using an authenticated write (with MAC). // The MAC must be pre-calculated. // // Parameters // page - page number where the block to write is located (0 to 15) // block - block number in page (0 to 7) // new_data - 4 byte buffer containing the data to write // mac - mac to use for the write // contflag - Flag to indicate the write is continued from the last // // Returns: true - block written // false - Failed to write block (no presence or invalid CRC16) // OneWireSlave::CmdResult DS28E15_22_25::writeAuthSegmentMAC(unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Mac & mac, bool continuing) { std::uint8_t buf[256], cs; int cnt, i, offset; cnt = 0; offset = 0; // check if not continuing a previous block write if (!continuing) { buf[cnt++] = CMD_WRITE_AUTH_MEMORY; buf[cnt++] = (segmentNum << 5) | pageNum; // address // Send command m_OW_master.OWWriteBlock(&buf[0], 2); // Read CRC m_OW_master.OWReadBlock(&buf[cnt], 2); cnt += 2; offset = cnt; } // add the data for (i = 0; i < newData.length; i++) buf[cnt++] = newData[i]; // Send data m_OW_master.OWWriteBlock(newData, newData.length); // read first CRC byte m_OW_master.OWReadByte(buf[cnt++]); // read the last CRC and enable power m_OW_master.OWReadBytePower(buf[cnt++]); // now wait for the MAC computation. wait_ms(SHA_COMPUTATION_DELAY); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // check the first CRC16 if (!continuing) { if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001) return CommunicationError; } // check the second CRC16 unsigned short CRC16 = 0; // DS28E25/DS28E22, crc gets calculagted with CS byte if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY)) { if (continuing) CRC16 = OneWireMaster::calculateCRC16(CRC16, 0xAA); } CRC16 = OneWireMaster::calculateCRC16(buf, offset, (cnt - offset), CRC16); if (CRC16 != 0xB001) return CommunicationError; // transmit MAC as a block m_OW_master.OWWriteBlock(mac, mac.length); // calculate CRC on MAC CRC16 = OneWireMaster::calculateCRC16(mac, 0, mac.length); // append read of CRC16 and CS byte m_OW_master.OWReadBlock(&buf[0], 3); cnt = 3; // ckeck CRC16 CRC16 = OneWireMaster::calculateCRC16(buf, 0, (cnt - 1), CRC16); if (CRC16 != 0xB001) return CommunicationError; // check CS if (buf[cnt-1] != 0xAA) return OperationFailure; // send release and strong pull-up m_OW_master.OWWriteBytePower(0xAA); // now wait for the MAC computation. wait_ms(EEPROM_WRITE_DELAY); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // read the CS byte m_OW_master.OWReadByte(cs); if (cs == 0xAA) return Success; // else return OperationFailure; } //-------------------------------------------------------------------------- // Compute MAC to write a 4 byte memory block using an authenticated // write. // // Parameters // page - page number where the block to write is located (0 to 15) // block - block number in page (0 to 7) // new_data - 4 byte buffer containing the data to write // old_data - 4 byte buffer containing the data to write // manid - 2 byte buffer containing the manufacturer ID (general device: 00h,00h) // mac - buffer to put the calculated mac into // // Returns: true - mac calculated // false - Failed to calculate // ISha256MacCoprocessor::CmdResult DS28E15_22_25::CalculateSegmentWriteMAC256(const ISha256MacCoprocessor & MacCoproc, unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Segment & oldData, const RomId & romId, const ManId & manId, Mac & mac) { ISha256MacCoprocessor::WriteMacData MT; // insert ROM number memcpy(&MT[0], romId, RomId::byteLen); MT[11] = segmentNum; MT[10] = pageNum; MT[9] = manId[0]; MT[8] = manId[1]; // insert old data memcpy(&MT[12], oldData, Segment::length); // insert new data memcpy(&MT[16], newData, Segment::length); return MacCoproc.computeWriteMac(MT, mac); } ISha256MacCoprocessor::CmdResult DS28E15_22_25::CalculateProtectionWriteMAC256(const ISha256MacCoprocessor & MacCoproc, std::uint8_t newProtection, std::uint8_t oldProtection, const RomId & romId, const ManId & manId, Mac & mac) { ISha256MacCoprocessor::WriteMacData MT; // insert ROM number std::memcpy(MT, romId, RomId::byteLen); // instert block and page MT[11] = 0; MT[10] = newProtection & 0x0F; MT[9] = manId[0]; MT[8] = manId[1]; // old data MT[12] = (oldProtection & PROT_BIT_AUTHWRITE) ? 0x01 : 0x00; MT[13] = (oldProtection & PROT_BIT_EPROM) ? 0x01 : 0x00; MT[14] = (oldProtection & PROT_BIT_WRITE) ? 0x01 : 0x00; MT[15] = (oldProtection & PROT_BIT_READ) ? 0x01 : 0x00; // new data MT[16] = (newProtection & PROT_BIT_AUTHWRITE) ? 0x01 : 0x00; MT[17] = (newProtection & PROT_BIT_EPROM) ? 0x01 : 0x00; MT[18] = (newProtection & PROT_BIT_WRITE) ? 0x01 : 0x00; MT[19] = (newProtection & PROT_BIT_READ) ? 0x01 : 0x00; // compute the mac return MacCoproc.computeWriteMac(MT, mac); } //-------------------------------------------------------------------------- // Write a 4 byte memory block using an authenticated write (with MAC). // The block location is selected by the // page number and offset block within the page. Multiple blocks can // be programmed without re-selecting the device using the continue flag. // This function does not use the Authenticated Write operation. // // Parameters // page - page number where the block to write is located (0 to 15) // block - block number in page (0 to 7) // new_data - 4 byte buffer containing the data to write // old_data - 4 byte buffer containing the data to write // manid - 2 byte buffer containing the manufacturer ID (general device: 00h,00h) // contflag - Flag to indicate the write is continued from the last // // Returns: true - block written // false - Failed to write block (no presence or invalid CRC16) // OneWireSlave::CmdResult DS28E15_22_25::writeAuthSegment(const ISha256MacCoprocessor & MacCoproc, unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Segment & oldData, bool continuing) { std::uint8_t buf[256], cs; int cnt, offset; cnt = 0; offset = 0; // check if not continuing a previous block write if (!continuing) { buf[cnt++] = CMD_WRITE_AUTH_MEMORY; buf[cnt++] = (segmentNum << 5) | pageNum; // address // Send command m_OW_master.OWWriteBlock(&buf[0], 2); // Read CRC m_OW_master.OWReadBlock(&buf[cnt], 2); cnt += 2; offset = cnt; } // add the data for (size_t i = 0; i < newData.length; i++) buf[cnt++] = newData[i]; // Send data m_OW_master.OWWriteBlock(newData, newData.length); // read first CRC byte m_OW_master.OWReadByte(buf[cnt++]); // read the last CRC and enable power m_OW_master.OWReadBytePower(buf[cnt++]); // now wait for the MAC computation. wait_ms(SHA_COMPUTATION_DELAY); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // check the first CRC16 if (!continuing) { if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001) return CommunicationError; } // check the second CRC16 unsigned short CRC16 = 0; // DS28E25/DS28E22, crc gets calculagted with CS byte if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY)) { if (continuing) CRC16 = OneWireMaster::calculateCRC16(CRC16, 0xAA); } CRC16 = OneWireMaster::calculateCRC16(buf, offset, (cnt - offset), CRC16); if (CRC16 != 0xB001) return CommunicationError; // compute the mac ISha256MacCoprocessor::CmdResult result; Mac mac; result = CalculateSegmentWriteMAC256(MacCoproc, pageNum, segmentNum, newData, oldData, romId, manId, mac); if (result != ISha256MacCoprocessor::Success) return OperationFailure; // transmit MAC as a block m_OW_master.OWWriteBlock(mac, mac.length); // calculate CRC on MAC CRC16 = OneWireMaster::calculateCRC16(mac, 0, mac.length); // append read of CRC16 and CS byte m_OW_master.OWReadBlock(&buf[0], 3); cnt = 3; // ckeck CRC16 CRC16 = OneWireMaster::calculateCRC16(buf, 0, (cnt - 1), CRC16); if (CRC16 != 0xB001) return CommunicationError; // check CS if (buf[cnt-1] != 0xAA) return OperationFailure; // send release and strong pull-up m_OW_master.OWWriteBytePower(0xAA); // now wait for the MAC computation. wait_ms(EEPROM_WRITE_DELAY); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // read the CS byte m_OW_master.OWReadByte(cs); if (cs == 0xAA) return Success; // else return OperationFailure; } OneWireSlave::CmdResult DS28E15_22_25::readSegment(unsigned int page, unsigned int segment, Segment & data) const { OneWireMaster::CmdResult result; std::uint8_t buf[2]; buf[0] = CMD_READ_MEMORY; buf[1] = (segment << 5) | page; // Transmit command m_OW_master.OWWriteBlock(buf, 2); // Receive CRC result = m_OW_master.OWReadBlock(buf, 2); // Receive data if (result == OneWireMaster::Success) result = m_OW_master.OWReadBlock(data, data.length); return (result == OneWireMaster::Success ? OneWireSlave::Success : OneWireSlave::CommunicationError); } //-------------------------------------------------------------------------- // Write a 4 byte memory block. The block location is selected by the // page number and offset blcok within the page. Multiple blocks can // be programmed without re-selecting the device using the continue flag. // This function does not use the Authenticated Write operation. // // Parameters // page - page number where the block to write is located (0 to 15) // block - block number in page (0 to 7) // data - 4 byte buffer containing the data to write // contflag - Flag to indicate the write is continued from the last // // Returns: true - block written // false - Failed to write block (no presence or invalid CRC16) // OneWireSlave::CmdResult DS28E15_22_25::writeSegment(unsigned int page, unsigned int block, const Segment & data, bool continuing) { std::uint8_t buf[256], cs; int cnt, offset; cnt = 0; offset = 0; // check if not continuing a previous block write if (!continuing) { buf[cnt++] = CMD_WRITE_MEMORY; buf[cnt++] = (block << 5) | page; // address // Send command m_OW_master.OWWriteBlock(&buf[0], 2); // Read CRC m_OW_master.OWReadBlock(&buf[cnt], 2); cnt += 2; offset = cnt; } // add the data for (size_t i = 0; i < data.length; i++) buf[cnt++] = data[i]; // Send data m_OW_master.OWWriteBlock(data, data.length); // Read CRC m_OW_master.OWReadBlock(&buf[cnt], 2); cnt += 2; // check the first CRC16 if (!continuing) { if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001) return CommunicationError; } // check the second CRC16 if (OneWireMaster::calculateCRC16(buf, offset, (cnt - offset)) != 0xB001) return CommunicationError; // send release and strong pull-up m_OW_master.OWWriteBytePower(0xAA); // now wait for the MAC computation. wait_ms(EEPROM_WRITE_DELAY); // disable strong pullup m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); // read the CS byte m_OW_master.OWReadByte(cs); if (cs == 0xAA) return Success; // else return OperationFailure; } //---------------------------------------------------------------------- // Performs a Compute Next SHA-256 calculation given the provided 32-bytes // of binding data and 8 byte partial secret. The first 8 bytes of the // resulting MAC is set as the new secret. // // 'binding' - 32 byte buffer containing the binding data // 'partial' - 8 byte buffer with new partial secret // 'page_num' - page number that the compute is calculated on // 'manid' - manufacturer ID // // Globals used : SECRET used in calculation and set to new secret // // Returns: true if compute successful // false failed to do compute // ISha256MacCoprocessor::CmdResult DS28E15_22_25::CalculateNextSecret(ISha256MacCoprocessor & MacCoproc, const Page & binding, const Scratchpad & partial, const RomId & romId, const ManId & manId, unsigned int pageNum) { ISha256MacCoprocessor::SlaveSecretData slaveSecretData; // insert ROM number std::memcpy(slaveSecretData, romId, RomId::byteLen); slaveSecretData[11] = 0x00; slaveSecretData[10] = pageNum; slaveSecretData[9] = manId[0]; slaveSecretData[8] = manId[1]; return MacCoproc.computeSlaveSecret(binding, partial, slaveSecretData); }