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.
Diff: Authenticators/DS28E15_22_25/DS28E15_22_25.cpp
- Revision:
- 73:2cecc1372acc
- Parent:
- 62:43039aeca2ab
- Child:
- 74:23be10c32fa3
diff -r 6892702709ee -r 2cecc1372acc Authenticators/DS28E15_22_25/DS28E15_22_25.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Authenticators/DS28E15_22_25/DS28E15_22_25.cpp Thu May 12 14:38:16 2016 -0500 @@ -0,0 +1,1031 @@ +//------------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.h" +#include "Masters/OneWireMaster.h" +#include "wait_api.h" + +using OneWire::Authenticators::DS28E15_22_25; +using OneWire::Authenticators::ISha256MacCoproc; +using OneWire::OneWireSlave; +using OneWire::Masters::OneWireMaster; + +/// 1-Wire device commands. +enum Command +{ + CMD_WRITE_MEMORY = 0x55, + CMD_READ_MEMORY = 0xF0, + CMD_LOAD_LOCK_SECRET = 0x33, + CMD_COMPUTE_LOCK_SECRET = 0x3C, + CMD_READ_WRITE_SCRATCHPAD = 0x0F, + CMD_COMPUTE_PAGEMAC = 0xA5, + CMD_READ_STATUS = 0xAA, + CMD_WRITE_BLOCK_PROTECT = 0xC3, + CMD_WRITE_AUTH_MEMORY = 0x5A, + CMD_WRITE_AUTH_PROTECT = 0xCC, +}; + +DS28E15_22_25::Segment DS28E15_22_25::Page::toSegment(unsigned int segmentNum) const +{ + if (segmentNum > (segmentsPerPage - 1)) + segmentNum = (segmentsPerPage - 1); + return Segment(*reinterpret_cast<const Segment::Buffer *>(&m_data[segmentNum * sizeof(Segment::Buffer)])); +} + +void DS28E15_22_25::Page::fromSegment(unsigned int segmentNum, const Segment & segment) +{ + if (segmentNum > (segmentsPerPage - 1)) + segmentNum = (segmentsPerPage - 1); + std::memcpy(&m_data[segmentNum * sizeof(Segment::Buffer)], &static_cast<const Segment::Buffer &>(segment), Segment::length); +} + +DS28E15_22_25::BlockProtection::BlockProtection(bool readProtection, bool writeProtection, bool eepromEmulation, bool authProtection, uint8_t blockNum) +{ + setReadProtection(readProtection); + setWriteProtection(writeProtection); + setEepromEmulation(eepromEmulation); + setAuthProtection(authProtection); + setBlockNum(blockNum); +} + +void DS28E15_22_25::BlockProtection::setBlockNum(uint8_t blockNum) +{ + m_status &= ~blockNumMask; + m_status |= (blockNum & blockNumMask); +} + +bool DS28E15_22_25::BlockProtection::noProtection() const +{ + return !readProtection() && !writeProtection() && !eepromEmulation() && !authProtection(); +} + +void DS28E15_22_25::BlockProtection::setReadProtection(bool readProtection) +{ + if (readProtection) + m_status |= readProtectionMask; + else + m_status &= ~readProtectionMask; +} + +void DS28E15_22_25::BlockProtection::setWriteProtection(bool writeProtection) +{ + if (writeProtection) + m_status |= writeProtectionMask; + else + m_status &= ~writeProtectionMask; +} + +void DS28E15_22_25::BlockProtection::setEepromEmulation(bool eepromEmulation) +{ + if (eepromEmulation) + m_status |= eepromEmulationMask; + else + m_status &= ~eepromEmulationMask; +} + +void DS28E15_22_25::BlockProtection::setAuthProtection(bool authProtection) +{ + if (authProtection) + m_status |= authProtectionMask; + else + m_status &= ~authProtectionMask; +} + +DS28E15_22_25::DS28E15_22_25(OneWireMaster& OW_master, bool lowVoltage) + : lowVoltage(lowVoltage), m_OW_master(OW_master) +{ + std::memset(manId, 0x00, manId.length); +} + +DS28E15_22_25::MemoryPages DS28E15_22_25::memoryPages() +{ + MemoryPages 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::ProtectionBlocks DS28E15_22_25::protectionBlocks() +{ + ProtectionBlocks 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; +} + +OneWireSlave::CmdResult DS28E15_22_25::writeAuthBlockProtection(const ISha256MacCoproc & MacCoproc, const BlockProtection & newProtection, const BlockProtection & oldProtection) +{ + uint8_t buf[256], cs; + int cnt = 0; + Mac mac; + + buf[cnt++] = CMD_WRITE_AUTH_PROTECT; + buf[cnt++] = newProtection.statusByte(); + + // 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(shaComputationDelayMs); + + // disable strong pullup + m_OW_master.OWSetLevel(OneWireMaster::LEVEL_NORMAL); + + // check CRC16 + if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001) + return CommunicationError; + + ISha256MacCoproc::CmdResult result; + result = computeProtectionWriteMac(MacCoproc, newProtection, oldProtection, romId, manId, mac); + if (result != ISha256MacCoproc::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; + + // check CRC16 + if (OneWireMaster::calculateCRC16(buf, 0, (cnt - 1), OneWireMaster::calculateCRC16(mac, 0, mac.length)) != 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 programming. + wait_ms(eepromWriteDelayMs); + + // 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::writeBlockProtection(const BlockProtection & protection) +{ + uint8_t buf[256], cs; + int cnt = 0; + + buf[cnt++] = CMD_WRITE_BLOCK_PROTECT; + + // compute parameter byte + buf[cnt++] = protection.statusByte(); + + 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; + + // sent release + m_OW_master.OWWriteBytePower(0xAA); + + // now wait for the programming. + wait_ms(eepromWriteDelayMs); + + // 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::readBlockProtection(unsigned int blockNum, BlockProtection & protection) +{ + uint8_t buf; + CmdResult result = readStatus(false, false, blockNum, &buf); + if (result == Success) + protection.setStatusByte(buf); + return result; +} + +template <DS28E15_22_25::ProtectionBlocks blocks> OneWireSlave::CmdResult DS28E15_22_25::readAllBlockProtection(BlockProtection (&protection)[blocks]) const +{ + uint8_t buf[blocks]; + CmdResult result = readStatus(false, true, 0, buf); + if (result == Success) + { + for (size_t i = 0; i < blocks; i++) + protection[i].setStatusByte(buf[i]); + } + return result; +} + +OneWireSlave::CmdResult DS28E15_22_25::readAllBlockProtection(BlockProtection (&protection)[DS28E15_BLOCKS]) const +{ + return readAllBlockProtection<DS28E15_BLOCKS>(protection); +} + +OneWireSlave::CmdResult DS28E15_22_25::readAllBlockProtection(BlockProtection (&protection)[DS28E25_BLOCKS]) const +{ + return readAllBlockProtection<DS28E25_BLOCKS>(protection); +} + +OneWireSlave::CmdResult DS28E15_22_25::readPersonality(Personality & personality) const +{ + return readStatus(true, false, 0, personality.bytes); +} + +OneWireSlave::CmdResult DS28E15_22_25::readStatus(bool personality, bool allpages, unsigned int blockNum, uint8_t * rdbuf) const +{ + const size_t crcLen = 4, ds28e22_25_pagesPerBlock = 2; + + uint8_t buf[256]; + size_t cnt = 0, offset = 0; + + buf[cnt++] = CMD_READ_STATUS; + if (personality) + buf[cnt++] = 0xE0; + else if (allpages) + buf[cnt++] = 0; + else + { + // Convert to page number for DS28E22 and DS28E25 + buf[cnt] = blockNum; + if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY)) + buf[cnt] *= ds28e22_25_pagesPerBlock; + cnt++; + } + + // send the command + m_OW_master.OWWriteBlock(&buf[0], 2); + + offset = cnt + 2; + + // Set data length + size_t rdnum; + if (personality) + rdnum = 4; + else if (!allpages) + rdnum = 1; + else if ((romId.familyCode() == DS28E22_FAMILY) || (romId.familyCode() == DS28E25_FAMILY)) + rdnum = DS28E25_PAGES; // Need to read extra data on DS28E22 to get CRC16. + else // DS28E15 + rdnum = DS28E15_BLOCKS; + rdnum += crcLen; // Add in CRC length + + // 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 (personality || allpages) + { + // check the second CRC16 + if (OneWireMaster::calculateCRC16(buf, offset, (cnt - offset)) != 0xB001) + return CommunicationError; + } + + // copy the data to the read buffer + rdnum -= crcLen; + if (allpages && ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY))) + { + if (romId.familyCode() == DS28E22_FAMILY) + rdnum -= (DS28E25_PAGES - DS28E22_PAGES); + + for (size_t i = 0; i < (rdnum / ds28e22_25_pagesPerBlock); i++) + { + rdbuf[i] = (buf[offset + (i * ds28e22_25_pagesPerBlock)] & 0xF0); // Upper nibble + rdbuf[i] |= ((buf[offset + (i * ds28e22_25_pagesPerBlock)] & 0x0F) / ds28e22_25_pagesPerBlock); // Lower nibble + } + } + else + { + std::memcpy(rdbuf, &buf[offset], rdnum); + } + + return Success; +} + +ISha256MacCoproc::CmdResult DS28E15_22_25::computeAuthMac(const ISha256MacCoproc & MacCoproc, const Page & pageData, unsigned int pageNum, const Scratchpad & challenge, const RomId & romId, const ManId & manId, Mac & mac) +{ + ISha256MacCoproc::AuthMacData authMacData; + + // insert ROM number or FF + std::memcpy(authMacData, romId, RomId::byteLen); + + authMacData[10] = pageNum; + + authMacData[9] = manId[0]; + authMacData[8] = manId[1]; + + authMacData[11] = 0x00; + + return MacCoproc.computeAuthMac(ISha256MacCoproc::DevicePage(pageData), challenge, authMacData, mac); +} + +ISha256MacCoproc::CmdResult DS28E15_22_25::computeAuthMacAnon(const ISha256MacCoproc & MacCoproc, const Page & pageData, unsigned int pageNum, const Scratchpad & challenge, const ManId & manId, Mac & mac) +{ + RomId romId; + std::memset(romId, 0xFF, RomId::byteLen); + return computeAuthMac(MacCoproc, pageData, pageNum, challenge, romId, manId, mac); +} + +OneWireSlave::CmdResult DS28E15_22_25::computeReadPageMac(unsigned int page_num, bool anon, Mac & mac) const +{ + 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(shaComputationDelayMs * 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 + std::memcpy(mac, buf, Mac::length); + + return Success; +} + +OneWireSlave::CmdResult DS28E15_22_25::computeSecret(unsigned int page_num, bool lock) +{ + 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 computations and secret programming. + wait_ms(shaComputationDelayMs * 2 + secretEepromWriteDelayMs()); + + // 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::writeScratchpad(const Scratchpad & data) const +{ + uint8_t buf[256]; + int cnt = 0, offset; + + buf[cnt++] = CMD_READ_WRITE_SCRATCHPAD; + 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 + std::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; +} + +OneWireSlave::CmdResult DS28E15_22_25::readScratchpad(Scratchpad & data) const +{ + uint8_t buf[256]; + int cnt = 0, offset; + + buf[cnt++] = CMD_READ_WRITE_SCRATCHPAD; + if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY)) + buf[cnt++] = 0x2F; + else + buf[cnt++] = 0x0F; + + // Send command + m_OW_master.OWWriteBlock(&buf[0], 2); + + // Read CRC + m_OW_master.OWReadBlock(&buf[cnt], 2); + cnt += 2; + + offset = cnt; + + // Receive the data + m_OW_master.OWReadBlock(&buf[cnt], data.length); + cnt += 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; + + // Copy to output + std::memcpy(data, &buf[offset], data.length); + + return Success; +} + +OneWireSlave::CmdResult DS28E15_22_25::loadSecret(bool lock) +{ + 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 secret programming. + wait_ms(secretEepromWriteDelayMs()); + + // 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::readPage(unsigned int page, Page & rdbuf, bool continuing) const +{ + 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 + std::memcpy(rdbuf, &buf[offset], rdbuf.length); + + return Success; +} + +OneWireSlave::CmdResult DS28E15_22_25::writeAuthSegmentMac(unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Mac & mac, bool continuing) +{ + 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(shaComputationDelayMs); + + // 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 programming. + wait_ms(eepromWriteDelayMs); + + // 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; +} + +ISha256MacCoproc::CmdResult DS28E15_22_25::computeSegmentWriteMac(const ISha256MacCoproc & MacCoproc, unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Segment & oldData, const RomId & romId, const ManId & manId, Mac & mac) +{ + ISha256MacCoproc::WriteMacData MT; + + // insert ROM number + std::memcpy(&MT[0], romId, RomId::byteLen); + + MT[11] = segmentNum; + MT[10] = pageNum; + MT[9] = manId[0]; + MT[8] = manId[1]; + + // insert old data + std::memcpy(&MT[12], oldData, Segment::length); + + // insert new data + std::memcpy(&MT[16], newData, Segment::length); + + return MacCoproc.computeWriteMac(MT, mac); +} + +ISha256MacCoproc::CmdResult DS28E15_22_25::computeProtectionWriteMac(const ISha256MacCoproc & MacCoproc, const BlockProtection & newProtection, const BlockProtection & oldProtection, const RomId & romId, const ManId & manId, Mac & mac) +{ + ISha256MacCoproc::WriteMacData MT; + + // insert ROM number + std::memcpy(MT, romId, RomId::byteLen); + + // instert block and page + MT[11] = 0; + MT[10] = newProtection.blockNum(); + + MT[9] = manId[0]; + MT[8] = manId[1]; + + // old data + MT[12] = oldProtection.authProtection() ? 0x01 : 0x00; + MT[13] = oldProtection.eepromEmulation() ? 0x01 : 0x00; + MT[14] = oldProtection.writeProtection() ? 0x01 : 0x00; + MT[15] = oldProtection.readProtection() ? 0x01 : 0x00; + // new data + MT[16] = newProtection.authProtection() ? 0x01 : 0x00; + MT[17] = newProtection.eepromEmulation() ? 0x01 : 0x00; + MT[18] = newProtection.writeProtection() ? 0x01 : 0x00; + MT[19] = newProtection.readProtection() ? 0x01 : 0x00; + + // compute the mac + return MacCoproc.computeWriteMac(MT, mac); +} + +OneWireSlave::CmdResult DS28E15_22_25::writeAuthSegment(const ISha256MacCoproc & MacCoproc, unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Segment & oldData, bool continuing) +{ + 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(shaComputationDelayMs); + + // 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 + ISha256MacCoproc::CmdResult result; + Mac mac; + result = computeSegmentWriteMac(MacCoproc, pageNum, segmentNum, newData, oldData, romId, manId, mac); + if (result != ISha256MacCoproc::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 programming. + wait_ms(eepromWriteDelayMs); + + // 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, bool continuing) const +{ + OneWireMaster::CmdResult result; + uint8_t buf[2]; + + if (!continuing) + { + 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); + } + else if (segment == 0) + { + // Receive CRC from previous read + 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); +} + +OneWireSlave::CmdResult DS28E15_22_25::writeSegment(unsigned int page, unsigned int block, const Segment & data, bool continuing) +{ + 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 programming. + wait_ms(eepromWriteDelayMs); + + // 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; +} + +ISha256MacCoproc::CmdResult DS28E15_22_25::computeNextSecret(ISha256MacCoproc & MacCoproc, const Page & bindingPage, unsigned int bindingPageNum, const Scratchpad & partialSecret, const RomId & romId, const ManId & manId) +{ + ISha256MacCoproc::SlaveSecretData slaveSecretData; + + // insert ROM number + std::memcpy(slaveSecretData, romId, RomId::byteLen); + + slaveSecretData[11] = 0x00; + slaveSecretData[10] = bindingPageNum; + slaveSecretData[9] = manId[0]; + slaveSecretData[8] = manId[1]; + + return MacCoproc.computeSlaveSecret(ISha256MacCoproc::DevicePage(bindingPage), partialSecret, slaveSecretData); +}