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: OneWire_Memory/Authenticators/DS28E15_22_25/DS28E15_22_25.cpp
- Revision:
- 25:bdb1c5a53b58
- Child:
- 27:d5aaefa252f1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OneWire_Memory/Authenticators/DS28E15_22_25/DS28E15_22_25.cpp Tue Mar 22 15:18:00 2016 -0500 @@ -0,0 +1,1117 @@ +//------------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 "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.OWLevel(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.OWLevel(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.OWLevel(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.OWLevel(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.OWLevel(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.OWLevel(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.OWLevel(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.OWLevel(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.OWLevel(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.OWLevel(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.OWLevel(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); +}