Implementation of 1-Wire with added Alarm Search Functionality
Dependents: Max32630_One_Wire_Interface
OneWire_Memory/Authenticators/DS28E15_22_25/DS28E15_22_25.cpp
- Committer:
- IanBenzMaxim
- Date:
- 2016-03-30
- Revision:
- 32:bce180b544ed
- Parent:
- 27:d5aaefa252f1
- Child:
- 33:a4c015046956
File content as of revision 32:bce180b544ed:
//------------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, manIdLen); } 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; 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, reinterpret_cast<std::uint8_t (&)[macLen]>(buf)); if (result != ISha256MacCoprocessor::Success) return OperationFailure; cnt = macLen; // send the MAC m_OW_master.OWWriteBlock(&buf[0], macLen); // 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 std::uint8_t (&challenge)[scratchpadSize], const std::uint8_t (&pageData)[pageSize], const RomId & romId, const std::uint8_t (&manId)[manIdLen], bool anon, std::uint8_t (&mac)[macLen]) { std::uint8_t pageBuf[pageSize], challengeBuf[scratchpadSize], AuthMAC_data[ISha256MacCoprocessor::AuthMAC_data_len]; // insert page data std::memcpy(pageBuf, pageData, pageSize); // insert challenge std::memcpy(challengeBuf, challenge, scratchpadSize); // insert ROM number or FF if (anon) std::memset(AuthMAC_data, 0xFF, RomId::byteLen); else std::memcpy(AuthMAC_data, romId, RomId::byteLen); AuthMAC_data[10] = pageNum; AuthMAC_data[9] = manId[0]; AuthMAC_data[8] = manId[1]; AuthMAC_data[11] = 0x00; return MacCoproc.ComputeAndRead_AuthMAC(pageBuf, challengeBuf, AuthMAC_data, 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 std::uint8_t (&challenge)[scratchpadSize], const std::uint8_t (&pageData)[pageSize], const RomId & romId, const std::uint8_t (&manId)[manIdLen], bool anon, const std::uint8_t (&mac)[macLen]) { std::uint8_t calc_mac[macLen]; ISha256MacCoprocessor::CmdResult result; result = CalculateAuthMAC256(MacCoproc, page_num, challenge, pageData, romId, manId, anon, calc_mac); if (result == ISha256MacCoprocessor::Success) { if (memcmp(mac, calc_mac, macLen) != 0) 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, std::uint8_t (&mac)[macLen]) 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], (macLen + 2)); // check CRC16 if (OneWireMaster::calculateCRC16(buf, 0, (macLen + 2)) != 0xB001) return CommunicationError; // copy MAC to return buffer memcpy(mac, buf, macLen); 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 uint8_t (&data)[scratchpadSize]) 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, scratchpadSize); cnt += scratchpadSize; // Send the data m_OW_master.OWWriteBlock(data, scratchpadSize); // 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, std::uint8_t (&rdbuf)[pageSize], 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], (pageSize + 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], pageSize); 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 std::uint8_t (&newData)[segmentSize], const std::uint8_t (&mac)[macLen], 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 < 4; i++) buf[cnt++] = newData[i]; // Send data m_OW_master.OWWriteBlock(newData, segmentSize); // 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, macLen); // calculate CRC on MAC CRC16 = OneWireMaster::calculateCRC16(mac, 0, macLen); // 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 std::uint8_t (&newData)[segmentSize], const std::uint8_t (&oldData)[segmentSize], const RomId & romId, const std::uint8_t (&manId)[manIdLen], std::uint8_t (&mac)[macLen]) { std::uint8_t MT[ISha256MacCoprocessor::WriteMAC_data_len]; // 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, segmentSize); // insert new data memcpy(&MT[16], newData, segmentSize); return MacCoproc.ComputeAndRead_WriteMAC(MT, mac); } ISha256MacCoprocessor::CmdResult DS28E15_22_25::CalculateProtectionWriteMAC256(const ISha256MacCoprocessor & MacCoproc, std::uint8_t newProtection, std::uint8_t oldProtection, const RomId & romId, const std::uint8_t (&manId)[manIdLen], std::uint8_t (&mac)[macLen]) { std::uint8_t MT[ISha256MacCoprocessor::WriteMAC_data_len]; // 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.ComputeAndRead_WriteMAC(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 std::uint8_t (&newData)[segmentSize], const std::uint8_t (&oldData)[segmentSize], 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 < segmentSize; i++) buf[cnt++] = newData[i]; // Send data m_OW_master.OWWriteBlock(newData, segmentSize); // 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; result = CalculateSegmentWriteMAC256(MacCoproc, pageNum, segmentNum, newData, oldData, romId, manId, reinterpret_cast<std::uint8_t (&)[macLen]>(buf)); if (result != ISha256MacCoprocessor::Success) return OperationFailure; // transmit MAC as a block cnt = 0; m_OW_master.OWWriteBlock(buf, macLen); // calculate CRC on MAC CRC16 = OneWireMaster::calculateCRC16(buf, 0, macLen); // 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, std::uint8_t (&data)[segmentSize]) 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, segmentSize); 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 std::uint8_t (&data)[segmentSize], 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 < segmentSize; i++) buf[cnt++] = data[i]; // Send data m_OW_master.OWWriteBlock(data, segmentSize); // 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 std::uint8_t (&binding)[pageSize], const std::uint8_t (&partial)[scratchpadSize], const RomId & romId, const std::uint8_t (&manId)[manIdLen], unsigned int pageNum) { std::uint8_t devicePage[pageSize], deviceScratchpad[scratchpadSize], SSecret_data[ISha256MacCoprocessor::SSecret_data_len]; // insert page data memcpy(devicePage, binding, pageSize); // insert challenge memcpy(deviceScratchpad, partial, scratchpadSize); // insert ROM number std::memcpy(SSecret_data, romId, RomId::byteLen); SSecret_data[11] = 0x00; SSecret_data[10] = pageNum; SSecret_data[9] = manId[0]; SSecret_data[8] = manId[1]; return MacCoproc.Compute_SSecret(devicePage, deviceScratchpad, SSecret_data); }