Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed_DS28EC20_GPIO
Diff: Devices/DS28C36_DS2476.cpp
- Revision:
- 6:a8c83a2e6fa4
- Parent:
- 3:f818ea5172ed
- Child:
- 7:471901a04573
diff -r caf56f265a13 -r a8c83a2e6fa4 Devices/DS28C36_DS2476.cpp
--- a/Devices/DS28C36_DS2476.cpp Fri Jan 19 10:25:02 2018 -0600
+++ b/Devices/DS28C36_DS2476.cpp Wed Jan 23 13:11:04 2019 -0600
@@ -1,731 +1,709 @@
-/*******************************************************************************
-* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
-*
-* Permission is hereby granted, free of charge, to any person obtaining a
-* copy of this software and associated documentation files (the "Software"),
-* to deal in the Software without restriction, including without limitation
-* the rights to use, copy, modify, merge, publish, distribute, sublicense,
-* and/or sell copies of the Software, and to permit persons to whom the
-* Software is furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included
-* in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-* IN NO EVENT SHALL MAXIM INTEGRATED 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, Inc. shall not be used except as stated in the Maxim Integrated
-* Products, Inc. Branding Policy.
-*
-* The mere transfer of this software does not imply any licenses
-* of trade secrets, proprietary technology, copyrights, patents,
-* trademarks, maskwork rights, or any other form of intellectual
-* property whatsoever. Maxim Integrated Products, Inc. retains all
-* ownership rights.
-*******************************************************************************/
-
-#include <MaximInterface/Links/I2CMaster.hpp>
-#include <MaximInterface/Utilities/Error.hpp>
-#include <MaximInterface/Utilities/RomId.hpp>
-#include "DS28C36_DS2476.hpp"
-
-using std::copy;
-
-namespace MaximInterface {
-using namespace Ecc256;
-
-// DS28C36 commands.
-enum Command {
- WriteMemory = 0x96,
- ReadMemory = 0x69,
- WriteBuffer = 0x87,
- ReadBuffer = 0x5A,
- ReadPageProtection = 0xAA,
- SetPageProtection = 0xC3,
- DecrementCounter = 0xC9,
- ReadRng = 0xD2,
- EncryptedReadMemory = 0x4B,
- ComputeAndReadPathAuthentication = 0xA5,
- AuthenticatedSha2WriteMemory = 0x99,
- ComputeAndLockSha2Secret = 0x3C,
- GenerateEcc256KeyPair = 0xCB,
- ComputeMultiblockHash = 0x33,
- VerifyEcdsaSignature = 0x59,
- AuthenticateEcdsaPublicKey = 0xA8,
- AuthenticatedEcdsaWriteMemory = 0x89
-};
-
-static error_code convertResultByte(uint_least8_t resultByte) {
- error_code errorCode;
- if (resultByte != 0xAA) {
- errorCode.assign((resultByte == 0x00)
- ? static_cast<int>(DS28C36::AuthenticationError)
- : resultByte,
- DS28C36::errorCategory());
- }
- return errorCode;
-}
-
-error_code DS28C36::writeMemory(int pageNum, const Page & page) {
- if (pageNum < 0 || pageNum >= memoryPages) {
- return make_error_code(InvalidParameterError);
- }
-
- array<uint_least8_t, 1 + Page::csize> buffer;
- buffer[0] = pageNum;
- copy(page.begin(), page.end(), buffer.begin() + 1);
- error_code result = writeCommand(WriteMemory, buffer.data(), buffer.size());
- if (!result) {
- sleep(writeMemoryTimeMs);
- result = readFixedLengthResponse(buffer.data(), 1);
- if (!result) {
- result = convertResultByte(buffer[0]);
- }
- }
- return result;
-}
-
-error_code DS28C36::readMemory(int pageNum, Page & page) {
- if (pageNum < 0 || pageNum >= memoryPages) {
- return make_error_code(InvalidParameterError);
- }
-
- const uint_least8_t parameter = pageNum;
- error_code result = writeCommand(ReadMemory, ¶meter, 1);
- if (!result) {
- sleep(readMemoryTimeMs);
- array<uint_least8_t, 1 + Page::csize> response;
- result = readFixedLengthResponse(response.data(), response.size());
- if (!result) {
- result = convertResultByte(response[0]);
- copy(response.begin() + 1, response.end(), page.begin());
- }
- }
- return result;
-}
-
-error_code DS28C36::writeBuffer(const uint_least8_t * data, size_t dataSize) {
- return writeCommand(WriteBuffer, data, dataSize);
-}
-
-error_code DS28C36::readBuffer(std::vector<uint_least8_t> & data) {
- error_code result = writeCommand(ReadBuffer);
- if (!result) {
- data.resize(80);
- size_t dataSize = data.size();
- result = readVariableLengthResponse(&data[0], dataSize);
- if (result) {
- data.clear();
- } else {
- data.resize(dataSize);
- }
- }
- return result;
-}
-
-error_code DS28C36::readPageProtection(int pageNum,
- PageProtection & protection) {
- if (pageNum < 0 || pageNum >= memoryPages) {
- return make_error_code(InvalidParameterError);
- }
-
- uint_least8_t buffer = pageNum;
- error_code result = writeCommand(ReadPageProtection, &buffer, 1);
- if (!result) {
- sleep(readMemoryTimeMs);
- result = readFixedLengthResponse(&buffer, 1);
- if (!result) {
- protection = buffer;
- }
- }
- return result;
-}
-
-error_code DS28C36::setPageProtection(int pageNum,
- const PageProtection & protection) {
- if (pageNum < 0 || pageNum >= memoryPages) {
- return make_error_code(InvalidParameterError);
- }
-
- array<uint_least8_t, 2> buffer = {
- static_cast<uint_least8_t>(pageNum),
- static_cast<uint_least8_t>(protection.to_ulong())};
- error_code result =
- writeCommand(SetPageProtection, buffer.data(), buffer.size());
- if (!result) {
- sleep(writeMemoryTimeMs);
- result = readFixedLengthResponse(buffer.data(), 1);
- if (!result) {
- result = convertResultByte(buffer[0]);
- }
- }
- return result;
-}
-
-error_code DS28C36::decrementCounter() {
- error_code result = writeCommand(DecrementCounter);
- if (!result) {
- sleep(writeMemoryTimeMs);
- uint_least8_t response;
- result = readFixedLengthResponse(&response, 1);
- if (!result) {
- result = convertResultByte(response);
- }
- }
- return result;
-}
-
-error_code DS28C36::readRng(uint_least8_t * data, size_t dataSize) {
- if ((dataSize < 1) || (dataSize > 64)) {
- return make_error_code(InvalidParameterError);
- }
-
- data[0] = static_cast<uint_least8_t>(dataSize - 1);
- error_code result = writeCommand(ReadRng, data, 1);
- if (!result) {
- sleep(sha256ComputationTimeMs);
- result = readFixedLengthResponse(data, dataSize);
- }
- return result;
-}
-
-error_code DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum,
- EncryptedPage & page) {
- if (pageNum < 0 || pageNum >= memoryPages) {
- return make_error_code(InvalidParameterError);
- }
-
- const uint_least8_t parameter = (secretNum << 6) | pageNum;
- error_code result = writeCommand(EncryptedReadMemory, ¶meter, 1);
- if (!result) {
- sleep(readMemoryTimeMs + sha256ComputationTimeMs);
- typedef array<uint_least8_t, 1 + EncryptedPage::size> Response;
- Response response;
- result = readFixedLengthResponse(response.data(), response.size());
- if (!result) {
- result = convertResultByte(response[0]);
- Response::const_iterator begin = response.begin() + 1;
- Response::const_iterator end = begin + page.challenge.size();
- copy(begin, end, page.challenge.begin());
- begin = end;
- end = begin + page.data.size();
- copy(begin, end, page.data.begin());
- }
- }
- return result;
-}
-
-error_code DS28C36::computeAndReadPageAuthentication(int pageNum,
- AuthType authType) {
- if (pageNum < 0 || pageNum >= memoryPages) {
- return make_error_code(InvalidParameterError);
- }
-
- const uint_least8_t parameter = (authType << 5) | pageNum;
- return writeCommand(ComputeAndReadPathAuthentication, ¶meter, 1);
-}
-
-error_code
-DS28C36::computeAndReadEcdsaPageAuthentication(int pageNum, KeyNum keyNum,
- Signature & signature) {
- AuthType authType;
- switch (keyNum) {
- case KeyNumA:
- authType = EcdsaWithKeyA;
- break;
- case KeyNumB:
- authType = EcdsaWithKeyB;
- break;
- case KeyNumC:
- authType = EcdsaWithKeyC;
- break;
- default:
- return make_error_code(InvalidParameterError);
- }
- error_code result = computeAndReadPageAuthentication(pageNum, authType);
- if (!result) {
- sleep(sha256ComputationTimeMs);
- typedef array<uint_least8_t, 1 + Signature::size> Response;
- Response response;
- result = readFixedLengthResponse(response.data(), response.size());
- if (!result) {
- result = convertResultByte(response[0]);
- Response::const_iterator begin = response.begin() + 1;
- Response::const_iterator end = begin + signature.s.size();
- copy(begin, end, signature.s.begin());
- begin = end;
- end = begin + signature.r.size();
- copy(begin, end, signature.r.begin());
- }
- }
- return result;
-}
-
-error_code DS28C36::computeAndReadHmacPageAuthentication(int pageNum,
- SecretNum secretNum,
- Sha256::Hash & hmac) {
- AuthType authType;
- switch (secretNum) {
- case SecretNumA:
- authType = HmacWithSecretA;
- break;
- case SecretNumB:
- authType = HmacWithSecretB;
- break;
- case SecretNumS:
- authType = HmacWithSecretS;
- break;
- default:
- return make_error_code(InvalidParameterError);
- }
- error_code result = computeAndReadPageAuthentication(pageNum, authType);
- if (!result) {
- sleep(generateEcdsaSignatureTimeMs);
- array<uint_least8_t, 1 + Sha256::Hash::csize> response;
- result = readFixedLengthResponse(response.data(), response.size());
- if (!result) {
- result = convertResultByte(response[0]);
- copy(response.begin() + 1, response.end(), hmac.begin());
- }
- }
- return result;
-}
-
-error_code DS28C36::authenticatedSha2WriteMemory(int pageNum,
- SecretNum secretNum,
- const Page & page) {
- if (pageNum < 0 || pageNum >= memoryPages) {
- return make_error_code(InvalidParameterError);
- }
-
- array<uint_least8_t, 1 + Page::csize> buffer;
- buffer[0] = (secretNum << 6) | pageNum;
- copy(page.begin(), page.end(), buffer.begin() + 1);
- error_code result =
- writeCommand(AuthenticatedSha2WriteMemory, buffer.data(), buffer.size());
- if (!result) {
- sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs));
- result = readFixedLengthResponse(buffer.data(), 1);
- if (!result) {
- result = convertResultByte(buffer[0]);
- }
- }
- return result;
-}
-
-error_code DS28C36::computeAndLockSha2Secret(int pageNum, SecretNum msecretNum,
- SecretNum dsecretNum,
- bool writeProtectEnable) {
- // User pages only
- if (pageNum < UserData0 || pageNum > UserData15) {
- return make_error_code(InvalidParameterError);
- }
-
- array<uint_least8_t, 2> buffer = {
- static_cast<uint_least8_t>((dsecretNum << 6) | (msecretNum << 4) |
- pageNum),
- static_cast<uint_least8_t>(writeProtectEnable ? 0x80 : 0x00)};
- error_code result =
- writeCommand(ComputeAndLockSha2Secret, buffer.data(), buffer.size());
- if (!result) {
- sleep(sha256ComputationTimeMs +
- ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs));
- result = readFixedLengthResponse(buffer.data(), 1);
- if (!result) {
- result = convertResultByte(buffer[0]);
- }
- }
- return result;
-}
-
-error_code DS28C36::generateEcc256KeyPair(KeyNum keyNum,
- bool writeProtectEnable) {
- if (keyNum == KeyNumS) {
- return make_error_code(InvalidParameterError);
- }
-
- uint_least8_t buffer = keyNum;
- if (writeProtectEnable) {
- buffer |= 0x80;
- }
- error_code result = writeCommand(GenerateEcc256KeyPair, &buffer, 1);
- if (!result) {
- sleep(generateEccKeyPairTimeMs);
- result = readFixedLengthResponse(&buffer, 1);
- if (!result) {
- result = convertResultByte(buffer);
- }
- }
- return result;
-}
-
-error_code DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock,
- const uint_least8_t * data,
- size_t dataSize) {
- const size_t maxDataSize = 64;
-
- if (dataSize < 1 || dataSize > maxDataSize) {
- return make_error_code(InvalidParameterError);
- }
-
- array<uint_least8_t, 1 + maxDataSize> buffer;
- buffer[0] = 0;
- if (firstBlock) {
- buffer[0] |= 0x40;
- }
- if (lastBlock) {
- buffer[0] |= 0x80;
- }
- copy(data, data + dataSize, buffer.begin() + 1);
- error_code result =
- writeCommand(ComputeMultiblockHash, buffer.data(), dataSize + 1);
- if (!result) {
- sleep(sha256ComputationTimeMs);
- result = readFixedLengthResponse(buffer.data(), 1);
- if (!result) {
- result = convertResultByte(buffer[0]);
- }
- }
- return result;
-}
-
-error_code DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType,
- const Signature & signature,
- PioState pioa, PioState piob) {
- typedef array<uint_least8_t, 1 + Signature::size> Buffer;
- Buffer buffer;
- buffer[0] = keyNum | (hashType << 2);
- if (pioa != Unchanged) {
- buffer[0] |= 0x20;
- }
- if (pioa == Conducting) {
- buffer[0] |= 0x10;
- }
- if (piob != Unchanged) {
- buffer[0] |= 0x80;
- }
- if (piob == Conducting) {
- buffer[0] |= 0x40;
- }
- Buffer::iterator bufferIt =
- copy(signature.r.begin(), signature.r.end(), buffer.begin() + 1);
- copy(signature.s.begin(), signature.s.end(), bufferIt);
- error_code result =
- writeCommand(VerifyEcdsaSignature, buffer.data(), buffer.size());
- if (!result) {
- sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs +
- ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0));
- result = readFixedLengthResponse(buffer.data(), 1);
- if (!result) {
- result = convertResultByte(buffer[0]);
- }
- }
- return result;
-}
-
-error_code DS28C36::authenticateEcdsaPublicKey(bool authWrites, bool ecdh,
- KeyNum keyNum, int csOffset,
- const Signature & signature) {
- if (((keyNum != KeyNumA) && (keyNum != KeyNumB)) || (csOffset < 0) ||
- (csOffset > 31)) {
- return make_error_code(InvalidParameterError);
- }
-
- typedef array<uint_least8_t, 1 + Signature::size> Buffer;
- Buffer buffer;
- buffer[0] = (csOffset << 3) | (keyNum << 2);
- if (ecdh) {
- buffer[0] |= 0x02;
- }
- if (authWrites) {
- buffer[0] |= 0x01;
- }
- Buffer::iterator bufferIt =
- copy(signature.r.begin(), signature.r.end(), buffer.begin() + 1);
- copy(signature.s.begin(), signature.s.end(), bufferIt);
- error_code result =
- writeCommand(AuthenticateEcdsaPublicKey, buffer.data(), buffer.size());
- if (!result) {
- sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs);
- result = readFixedLengthResponse(buffer.data(), 1);
- if (!result) {
- result = convertResultByte(buffer[0]);
- }
- }
- return result;
-}
-
-error_code DS28C36::authenticatedEcdsaWriteMemory(int pageNum,
- const Page & page) {
- if (pageNum < 0 || pageNum >= memoryPages) {
- return make_error_code(InvalidParameterError);
- }
-
- array<uint_least8_t, 1 + Page::csize> buffer;
- buffer[0] = pageNum;
- copy(page.begin(), page.end(), buffer.begin() + 1);
- error_code result =
- writeCommand(AuthenticatedEcdsaWriteMemory, buffer.data(), buffer.size());
- if (!result) {
- sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs +
- sha256ComputationTimeMs);
- result = readFixedLengthResponse(buffer.data(), 1);
- if (!result) {
- result = convertResultByte(buffer[0]);
- }
- }
- return result;
-}
-
-error_code DS28C36::writeCommand(uint_least8_t command,
- const uint_least8_t * parameters,
- size_t parametersSize) {
- error_code result = master->start(address_);
- if (result) {
- master->stop();
- return result;
- }
- result = master->writeByte(command);
- if (result) {
- master->stop();
- return result;
- }
- if (parameters) {
- result = master->writeByte(static_cast<uint_least8_t>(parametersSize));
- if (result) {
- master->stop();
- return result;
- }
- result = master->writeBlock(parameters, parametersSize);
- if (result) {
- master->stop();
- return result;
- }
- }
- result = master->stop();
- return result;
-}
-
-error_code DS28C36::readVariableLengthResponse(uint_least8_t * response,
- size_t & responseSize) {
- error_code result = master->start(address_ | 1);
- if (result) {
- master->stop();
- return result;
- }
- uint_least8_t length;
- result = master->readByte(I2CMaster::Ack, length);
- if (result) {
- master->stop();
- return result;
- }
- if (length > responseSize) {
- master->stop();
- return make_error_code(InvalidResponseError);
- }
- if (length > 0) {
- result = master->readBlock(I2CMaster::Nack, response, length);
- if (result) {
- master->stop();
- return result;
- }
- }
- responseSize = length;
- result = master->stop();
- return result;
-}
-
-error_code DS28C36::readFixedLengthResponse(uint_least8_t * response,
- size_t responseSize) {
- const size_t requestedResponseSize = responseSize;
- error_code result = readVariableLengthResponse(response, responseSize);
- if (!result && responseSize != requestedResponseSize) {
- result = make_error_code(InvalidResponseError);
- }
- return result;
-}
-
-DS28C36::PageAuthenticationData
-DS28C36::createPageAuthenticationData(const RomId & romId, const Page & page,
- const Page & challenge, int pageNum,
- const ManId & manId) {
- PageAuthenticationData data;
- PageAuthenticationData::iterator dataIt = data.begin();
- dataIt = copy(romId.begin(), romId.end(), dataIt);
- dataIt = copy(page.begin(), page.end(), dataIt);
- dataIt = copy(challenge.begin(), challenge.end(), dataIt);
- *dataIt = static_cast<uint_least8_t>(pageNum);
- ++dataIt;
- copy(manId.begin(), manId.end(), dataIt);
- return data;
-}
-
-const error_category & DS28C36::errorCategory() {
- static class : public error_category {
- public:
- virtual const char * name() const { return "DS28C36"; }
-
- virtual std::string message(int condition) const {
- switch (condition) {
- case ProtectionError:
- return "Protection Error";
-
- case InvalidParameterError:
- return "Invalid Parameter Error";
-
- case InvalidSequenceError:
- return "Invalid Sequence Error";
-
- case InvalidEcdsaInputOrResultError:
- return "Invalid ECDSA Input or Result Error";
-
- case AuthenticationError:
- return "Authentication Error";
-
- case InvalidResponseError:
- return "Invalid Response Error";
-
- default:
- return defaultErrorMessage(condition);
- }
- }
- } instance;
- return instance;
-}
-
-error_code readRomIdAndManId(DS28C36 & ds28c36, RomId * romId, ManId * manId) {
- DS28C36::Page page;
- const error_code result = ds28c36.readMemory(DS28C36::RomOptions, page);
- if (!result) {
- DS28C36::Page::const_iterator pageIt = page.begin() + 22;
- if (manId) {
- copy(pageIt, pageIt + ManId::size(), manId->begin());
- }
- pageIt += ManId::size();
- if (romId) {
- copy(pageIt, pageIt + RomId::size(), romId->begin());
- }
- }
- return result;
-}
-
-error_code computeMultiblockHash(DS28C36 & ds28c36, const uint_least8_t * data,
- const size_t dataSize) {
- error_code result;
- size_t remainingSize = dataSize;
- while ((remainingSize > 0) && !result) {
- const size_t chunkSize = std::min<size_t>(remainingSize, 64);
- result = ds28c36.computeMultiblockHash(
- remainingSize == dataSize, remainingSize == chunkSize, data, chunkSize);
- data += chunkSize;
- remainingSize -= chunkSize;
- }
- return result;
-}
-
-error_code verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey,
- const uint_least8_t * data, size_t dataSize,
- const Signature & signature,
- DS28C36::PioState pioa,
- DS28C36::PioState piob) {
- error_code result = computeMultiblockHash(ds28c36, data, dataSize);
- if (!result) {
- result = ds28c36.verifyEcdsaSignature(publicKey, DS28C36::THASH, signature,
- pioa, piob);
- }
- return result;
-}
-
-error_code verifyEcdsaSignature(DS28C36 & ds28c36, const PublicKey & publicKey,
- const uint_least8_t * data, size_t dataSize,
- const Signature & signature,
- DS28C36::PioState pioa,
- DS28C36::PioState piob) {
- error_code result = ds28c36.writeMemory(DS28C36::PublicKeySX, publicKey.x);
- if (!result) {
- result = ds28c36.writeMemory(DS28C36::PublicKeySY, publicKey.y);
- }
- if (!result) {
- result = verifyEcdsaSignature(ds28c36, DS28C36::KeyNumS, data, dataSize,
- signature, pioa, piob);
- }
- return result;
-}
-
-// DS2476 additional commands.
-enum DS2476_Command {
- GenerateEcdsaSignature = 0x1E,
- ComputeSha2UniqueSecret = 0x55,
- ComputeSha2Hmac = 0x2D
-};
-
-error_code DS2476::generateEcdsaSignature(KeyNum keyNum,
- Signature & signature) {
- if (keyNum == KeyNumS) {
- return make_error_code(InvalidParameterError);
- }
-
- const uint_least8_t parameter = keyNum;
- error_code result = writeCommand(GenerateEcdsaSignature, ¶meter, 1);
- if (!result) {
- sleep(generateEcdsaSignatureTimeMs);
- typedef array<uint_least8_t, 1 + Signature::size> Response;
- Response response;
- result = readFixedLengthResponse(response.data(), response.size());
- if (!result) {
- result = convertResultByte(response[0]);
- Response::const_iterator begin = response.begin() + 1;
- Response::const_iterator end = begin + signature.s.size();
- copy(begin, end, signature.s.begin());
- begin = end;
- end = begin + signature.r.size();
- copy(begin, end, signature.r.begin());
- }
- }
- return result;
-}
-
-error_code DS2476::computeSha2UniqueSecret(SecretNum msecretNum) {
- uint_least8_t buffer = msecretNum << 4;
- error_code result = writeCommand(ComputeSha2UniqueSecret, &buffer, 1);
- if (!result) {
- sleep(sha256ComputationTimeMs);
- result = readFixedLengthResponse(&buffer, 1);
- if (!result) {
- convertResultByte(buffer);
- }
- }
- return result;
-}
-
-error_code DS2476::computeSha2Hmac(Sha256::Hash & hmac) {
- error_code result = writeCommand(ComputeSha2Hmac);
- if (!result) {
- sleep(sha256ComputationTimeMs);
- array<uint_least8_t, 1 + Sha256::Hash::csize> response;
- result = readFixedLengthResponse(response.data(), response.size());
- if (!result) {
- result = convertResultByte(response[0]);
- copy(response.begin() + 1, response.end(), hmac.begin());
- }
- }
- return result;
-}
-
-error_code enableCoprocessor(DS2476 & ds2476) {
- DS2476::Page gpioControl;
- error_code result = ds2476.readMemory(DS2476::GpioControl, gpioControl);
- if (!result && gpioControl[0] != 0xAA) {
- gpioControl[0] = 0xAA;
- result = ds2476.writeMemory(DS2476::GpioControl, gpioControl);
- }
- return result;
-}
-
-} // namespace MaximInterface
+/*******************************************************************************
+* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL MAXIM INTEGRATED 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, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************/
+
+#include <algorithm>
+#include <MaximInterface/Links/I2CMaster.hpp>
+#include <MaximInterface/Utilities/Error.hpp>
+#include <MaximInterface/Utilities/RomId.hpp>
+#include "DS28C36_DS2476.hpp"
+
+namespace MaximInterface {
+
+using namespace Ecc256;
+using std::copy;
+
+static error_code convertResultByte(uint_least8_t resultByte) {
+ error_code errorCode;
+ if (resultByte != 0xAA) {
+ errorCode.assign((resultByte == 0x00)
+ ? static_cast<int>(DS28C36::AuthenticationError)
+ : resultByte,
+ DS28C36::errorCategory());
+ }
+ return errorCode;
+}
+
+const int DS28C36::publicKeyAxPage;
+const int DS28C36::publicKeyAyPage;
+const int DS28C36::publicKeyBxPage;
+const int DS28C36::publicKeyByPage;
+const int DS28C36::publicKeyCxPage;
+const int DS28C36::publicKeyCyPage;
+const int DS28C36::privateKeyAPage;
+const int DS28C36::privateKeyBPage;
+const int DS28C36::privateKeyCPage;
+const int DS28C36::secretAPage;
+const int DS28C36::secretBPage;
+const int DS28C36::decrementCounterPage;
+const int DS28C36::romOptionsPage;
+const int DS28C36::gpioControlPage;
+const int DS28C36::publicKeySxPage;
+const int DS28C36::publicKeySyPage;
+const int DS28C36::memoryPages;
+
+error_code DS28C36::writeMemory(int pageNum, Page::const_span page) {
+ if (pageNum < 0 || pageNum >= memoryPages) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ uint_least8_t buffer[1 + Page::size];
+ buffer[0] = pageNum;
+ copy(page.begin(), page.end(), buffer + 1);
+ error_code result = writeCommand(0x96, buffer);
+ if (!result) {
+ sleep(writeMemoryTimeMs);
+ result = readFixedLengthResponse(make_span(buffer, 1));
+ if (!result) {
+ result = convertResultByte(buffer[0]);
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::readMemory(int pageNum, Page::span page) {
+ if (pageNum < 0 || pageNum >= memoryPages) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ const uint_least8_t parameter = pageNum;
+ error_code result = writeCommand(0x69, make_span(¶meter, 1));
+ if (!result) {
+ sleep(readMemoryTimeMs);
+ array<uint_least8_t, 1 + Page::size> response;
+ result = readFixedLengthResponse(response);
+ if (!result) {
+ result = convertResultByte(response[0]);
+ copy(response.begin() + 1, response.end(), page.begin());
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::writeBuffer(span<const uint_least8_t> data) {
+ return writeCommand(0x87, data);
+}
+
+error_code DS28C36::readBuffer(std::vector<uint_least8_t> & data) {
+ error_code result = writeCommand(0x5A);
+ if (!result) {
+ data.resize(80);
+ span<uint_least8_t> dataSpan(data);
+ result = readVariableLengthResponse(dataSpan);
+ if (result) {
+ data.clear();
+ } else {
+ data.resize(dataSpan.size());
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::readPageProtection(int pageNum,
+ PageProtection & protection) {
+ if (pageNum < 0 || pageNum >= memoryPages) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ uint_least8_t buffer = pageNum;
+ error_code result = writeCommand(0xAA, make_span(&buffer, 1));
+ if (!result) {
+ sleep(readMemoryTimeMs);
+ result = readFixedLengthResponse(make_span(&buffer, 1));
+ if (!result) {
+ protection = buffer;
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::setPageProtection(int pageNum,
+ const PageProtection & protection) {
+ if (pageNum < 0 || pageNum >= memoryPages) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ uint_least8_t buffer[] = {static_cast<uint_least8_t>(pageNum),
+ static_cast<uint_least8_t>(protection.to_ulong())};
+ error_code result = writeCommand(0xC3, buffer);
+ if (!result) {
+ sleep(writeMemoryTimeMs);
+ result = readFixedLengthResponse(make_span(buffer, 1));
+ if (!result) {
+ result = convertResultByte(buffer[0]);
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::decrementCounter() {
+ error_code result = writeCommand(0xC9);
+ if (!result) {
+ sleep(writeMemoryTimeMs);
+ uint_least8_t response;
+ result = readFixedLengthResponse(make_span(&response, 1));
+ if (!result) {
+ result = convertResultByte(response);
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::readRng(span<uint_least8_t> data) {
+ if ((data.size() < 1) || (data.size() > 64)) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ data[0] = static_cast<uint_least8_t>(data.size() - 1);
+ error_code result = writeCommand(0xD2, data.first(1));
+ if (!result) {
+ sleep(sha256ComputationTimeMs);
+ result = readFixedLengthResponse(data);
+ }
+ return result;
+}
+
+error_code DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum,
+ EncryptionChallenge::span challenge,
+ Page::span data) {
+ if (pageNum < 0 || pageNum >= memoryPages) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ const uint_least8_t parameter = (secretNum << 6) | pageNum;
+ error_code result = writeCommand(0x4B, make_span(¶meter, 1));
+ if (!result) {
+ sleep(readMemoryTimeMs + sha256ComputationTimeMs);
+ uint_least8_t response[1 + EncryptionChallenge::size + Page::size];
+ result = readFixedLengthResponse(response);
+ if (!result) {
+ result = convertResultByte(response[0]);
+ const uint_least8_t * begin = response + 1;
+ const uint_least8_t * end = begin + challenge.size();
+ copy(begin, end, challenge.begin());
+ begin = end;
+ end = begin + data.size();
+ copy(begin, end, data.begin());
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::computeAndReadPageAuthentication(int pageNum,
+ AuthType authType) {
+ if (pageNum < 0 || pageNum >= memoryPages) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ const uint_least8_t parameter = (authType << 5) | pageNum;
+ return writeCommand(0xA5, make_span(¶meter, 1));
+}
+
+error_code
+DS28C36::computeAndReadPageAuthentication(int pageNum, KeyNum keyNum,
+ Signature::span signature) {
+ AuthType authType;
+ switch (keyNum) {
+ case KeyNumA:
+ authType = EcdsaWithKeyA;
+ break;
+ case KeyNumB:
+ authType = EcdsaWithKeyB;
+ break;
+ case KeyNumC:
+ authType = EcdsaWithKeyC;
+ break;
+ default:
+ return make_error_code(InvalidParameterError);
+ }
+ error_code result = computeAndReadPageAuthentication(pageNum, authType);
+ if (!result) {
+ sleep(readMemoryTimeMs + generateEcdsaSignatureTimeMs);
+ uint_least8_t response[1 + 2 * Scalar::size];
+ result = readFixedLengthResponse(response);
+ if (!result) {
+ result = convertResultByte(response[0]);
+ const uint_least8_t * begin = response + 1;
+ const uint_least8_t * end = begin + signature.s.size();
+ copy(begin, end, signature.s.begin());
+ begin = end;
+ end = begin + signature.r.size();
+ copy(begin, end, signature.r.begin());
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::computeAndReadPageAuthentication(int pageNum,
+ SecretNum secretNum,
+ Sha256::Hash::span hmac) {
+ AuthType authType;
+ switch (secretNum) {
+ case SecretNumA:
+ authType = HmacWithSecretA;
+ break;
+ case SecretNumB:
+ authType = HmacWithSecretB;
+ break;
+ case SecretNumS:
+ authType = HmacWithSecretS;
+ break;
+ default:
+ return make_error_code(InvalidParameterError);
+ }
+ error_code result = computeAndReadPageAuthentication(pageNum, authType);
+ if (!result) {
+ sleep(readMemoryTimeMs + sha256ComputationTimeMs);
+ array<uint_least8_t, 1 + Sha256::Hash::size> response;
+ result = readFixedLengthResponse(response);
+ if (!result) {
+ result = convertResultByte(response[0]);
+ copy(response.begin() + 1, response.end(), hmac.begin());
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::authenticatedSha2WriteMemory(int pageNum,
+ SecretNum secretNum,
+ Page::const_span page) {
+ if (pageNum < 0 || pageNum >= memoryPages) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ uint_least8_t buffer[1 + Page::size];
+ buffer[0] = (secretNum << 6) | pageNum;
+ copy(page.begin(), page.end(), buffer + 1);
+ error_code result = writeCommand(0x99, buffer);
+ if (!result) {
+ sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs));
+ result = readFixedLengthResponse(make_span(buffer, 1));
+ if (!result) {
+ result = convertResultByte(buffer[0]);
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::computeAndLockSha2Secret(int pageNum, SecretNum msecretNum,
+ SecretNum dsecretNum,
+ bool writeProtectEnable) {
+ // User pages only
+ if (pageNum < 0 || pageNum > 15) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ uint_least8_t buffer[] = {
+ static_cast<uint_least8_t>((dsecretNum << 6) | (msecretNum << 4) |
+ pageNum),
+ static_cast<uint_least8_t>(writeProtectEnable ? 0x80 : 0x00)};
+ error_code result = writeCommand(0x3C, buffer);
+ if (!result) {
+ sleep(sha256ComputationTimeMs +
+ ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs));
+ result = readFixedLengthResponse(make_span(buffer, 1));
+ if (!result) {
+ result = convertResultByte(buffer[0]);
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::generateEcc256KeyPair(KeyNum keyNum,
+ bool writeProtectEnable) {
+ if (keyNum == KeyNumS) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ uint_least8_t buffer = keyNum;
+ if (writeProtectEnable) {
+ buffer |= 0x80;
+ }
+ error_code result = writeCommand(0xCB, make_span(&buffer, 1));
+ if (!result) {
+ sleep(generateEccKeyPairTimeMs);
+ result = readFixedLengthResponse(make_span(&buffer, 1));
+ if (!result) {
+ result = convertResultByte(buffer);
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock,
+ span<const uint_least8_t> data) {
+ const span<const uint_least8_t>::index_type maxDataSize = 64;
+
+ if (data.size() < 1 || data.size() > maxDataSize) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ uint_least8_t buffer[1 + maxDataSize];
+ buffer[0] = 0;
+ if (firstBlock) {
+ buffer[0] |= 0x40;
+ }
+ if (lastBlock) {
+ buffer[0] |= 0x80;
+ }
+ copy(data.begin(), data.end(), buffer + 1);
+ error_code result = writeCommand(0x33, make_span(buffer, data.size() + 1));
+ if (!result) {
+ sleep(sha256ComputationTimeMs);
+ result = readFixedLengthResponse(make_span(buffer, 1));
+ if (!result) {
+ result = convertResultByte(buffer[0]);
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType,
+ Signature::const_span signature,
+ PioState pioa, PioState piob) {
+ uint_least8_t buffer[1 + 2 * Scalar::size];
+ buffer[0] = keyNum | (hashType << 2);
+ if (pioa != Unchanged) {
+ buffer[0] |= 0x20;
+ }
+ if (pioa == Conducting) {
+ buffer[0] |= 0x10;
+ }
+ if (piob != Unchanged) {
+ buffer[0] |= 0x80;
+ }
+ if (piob == Conducting) {
+ buffer[0] |= 0x40;
+ }
+ uint_least8_t * bufferIt =
+ copy(signature.r.begin(), signature.r.end(), buffer + 1);
+ copy(signature.s.begin(), signature.s.end(), bufferIt);
+ error_code result = writeCommand(0x59, buffer);
+ if (!result) {
+ sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs +
+ ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0));
+ result = readFixedLengthResponse(make_span(buffer, 1));
+ if (!result) {
+ result = convertResultByte(buffer[0]);
+ }
+ }
+ return result;
+}
+
+error_code
+DS28C36::authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum,
+ int csOffset,
+ Signature::const_span signature) {
+ if (((keyNum != KeyNumA) && (keyNum != KeyNumB)) || (csOffset < 0) ||
+ (csOffset > 31)) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ uint_least8_t buffer[1 + 2 * Scalar::size];
+ buffer[0] = (csOffset << 3) | (keyNum << 2);
+ if (ecdh) {
+ buffer[0] |= 0x02;
+ }
+ if (authWrites) {
+ buffer[0] |= 0x01;
+ }
+ uint_least8_t * bufferIt =
+ copy(signature.r.begin(), signature.r.end(), buffer + 1);
+ copy(signature.s.begin(), signature.s.end(), bufferIt);
+ error_code result = writeCommand(0xA8, buffer);
+ if (!result) {
+ sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs);
+ result = readFixedLengthResponse(make_span(buffer, 1));
+ if (!result) {
+ result = convertResultByte(buffer[0]);
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::authenticatedEcdsaWriteMemory(int pageNum,
+ Page::const_span page) {
+ if (pageNum < 0 || pageNum >= memoryPages) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ uint_least8_t buffer[1 + Page::size];
+ buffer[0] = pageNum;
+ copy(page.begin(), page.end(), buffer + 1);
+ error_code result = writeCommand(0x89, buffer);
+ if (!result) {
+ sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs +
+ sha256ComputationTimeMs);
+ result = readFixedLengthResponse(make_span(buffer, 1));
+ if (!result) {
+ result = convertResultByte(buffer[0]);
+ }
+ }
+ return result;
+}
+
+error_code DS28C36::writeCommand(uint_least8_t command,
+ span<const uint_least8_t> parameters) {
+ error_code result = master->start(address_);
+ if (result) {
+ master->stop();
+ return result;
+ }
+ result = master->writeByte(command);
+ if (result) {
+ master->stop();
+ return result;
+ }
+ if (!parameters.empty()) {
+ result = master->writeByte(static_cast<uint_least8_t>(parameters.size()));
+ if (result) {
+ master->stop();
+ return result;
+ }
+ result = master->writeBlock(parameters);
+ if (result) {
+ master->stop();
+ return result;
+ }
+ }
+ result = master->stop();
+ return result;
+}
+
+error_code DS28C36::readVariableLengthResponse(span<uint_least8_t> & response) {
+ error_code result = master->start(address_ | 1);
+ if (result) {
+ master->stop();
+ return result;
+ }
+ uint_least8_t length;
+ result = master->readByte(I2CMaster::Ack, length);
+ if (result) {
+ master->stop();
+ return result;
+ }
+ if (length > response.size()) {
+ master->stop();
+ return make_error_code(InvalidResponseError);
+ }
+ response = response.first(length);
+ if (!response.empty()) {
+ result = master->readBlock(I2CMaster::Nack, response);
+ if (result) {
+ master->stop();
+ return result;
+ }
+ }
+ result = master->stop();
+ return result;
+}
+
+error_code DS28C36::readFixedLengthResponse(span<uint_least8_t> response) {
+ const span<uint_least8_t>::index_type requestedResponseSize = response.size();
+ error_code result = readVariableLengthResponse(response);
+ if (!result && response.size() != requestedResponseSize) {
+ result = make_error_code(InvalidResponseError);
+ }
+ return result;
+}
+
+const error_category & DS28C36::errorCategory() {
+ static class : public error_category {
+ public:
+ virtual const char * name() const { return "DS28C36"; }
+
+ virtual std::string message(int condition) const {
+ switch (condition) {
+ case ProtectionError:
+ return "Protection Error";
+
+ case InvalidParameterError:
+ return "Invalid Parameter Error";
+
+ case InvalidSequenceError:
+ return "Invalid Sequence Error";
+
+ case InvalidEcdsaInputOrResultError:
+ return "Invalid ECDSA Input or Result Error";
+
+ case AuthenticationError:
+ return "Authentication Error";
+
+ case InvalidResponseError:
+ return "Invalid Response Error";
+
+ default:
+ return defaultErrorMessage(condition);
+ }
+ }
+ } instance;
+ return instance;
+}
+
+error_code DS2476::generateEcdsaSignature(KeyNum keyNum,
+ Signature::span signature) {
+ if (keyNum == KeyNumS) {
+ return make_error_code(InvalidParameterError);
+ }
+
+ const uint_least8_t parameter = keyNum;
+ error_code result = writeCommand(0x1E, make_span(¶meter, 1));
+ if (!result) {
+ sleep(generateEcdsaSignatureTimeMs);
+ uint_least8_t response[1 + 2 * Scalar::size];
+ result = readFixedLengthResponse(response);
+ if (!result) {
+ result = convertResultByte(response[0]);
+ const uint_least8_t * begin = response + 1;
+ const uint_least8_t * end = begin + signature.s.size();
+ copy(begin, end, signature.s.begin());
+ begin = end;
+ end = begin + signature.r.size();
+ copy(begin, end, signature.r.begin());
+ }
+ }
+ return result;
+}
+
+error_code DS2476::computeSha2UniqueSecret(SecretNum msecretNum) {
+ uint_least8_t buffer = msecretNum << 4;
+ error_code result = writeCommand(0x55, make_span(&buffer, 1));
+ if (!result) {
+ sleep(sha256ComputationTimeMs);
+ result = readFixedLengthResponse(make_span(&buffer, 1));
+ if (!result) {
+ convertResultByte(buffer);
+ }
+ }
+ return result;
+}
+
+error_code DS2476::computeSha2Hmac(Sha256::Hash::span hmac) {
+ error_code result = writeCommand(0x2D);
+ if (!result) {
+ sleep(sha256ComputationTimeMs);
+ array<uint_least8_t, 1 + Sha256::Hash::size> response;
+ result = readFixedLengthResponse(response);
+ if (!result) {
+ result = convertResultByte(response[0]);
+ copy(response.begin() + 1, response.end(), hmac.begin());
+ }
+ }
+ return result;
+}
+
+error_code computeMultiblockHash(DS28C36 & ds28c36,
+ span<const uint_least8_t> data) {
+ error_code result;
+ span<const uint_least8_t>::index_type dataIdx = 0;
+ while (dataIdx < data.size() && !result) {
+ const span<const uint_least8_t>::index_type remainingSize =
+ data.size() - dataIdx;
+ const span<const uint_least8_t>::index_type chunkSize =
+ std::min<span<const uint_least8_t>::index_type>(remainingSize, 64);
+ result =
+ ds28c36.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
+ data.subspan(dataIdx, chunkSize));
+ dataIdx += chunkSize;
+ }
+ return result;
+}
+
+error_code verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey,
+ span<const uint_least8_t> data,
+ Signature::const_span signature,
+ DS28C36::PioState pioa,
+ DS28C36::PioState piob) {
+ error_code result = computeMultiblockHash(ds28c36, data);
+ if (!result) {
+ result = ds28c36.verifyEcdsaSignature(publicKey, DS28C36::THASH, signature,
+ pioa, piob);
+ }
+ return result;
+}
+
+error_code verifyEcdsaSignature(DS28C36 & ds28c36,
+ PublicKey::const_span publicKey,
+ span<const uint_least8_t> data,
+ Signature::const_span signature,
+ DS28C36::PioState pioa,
+ DS28C36::PioState piob) {
+ error_code result =
+ ds28c36.writeMemory(DS28C36::publicKeySxPage, publicKey.x);
+ if (!result) {
+ result = ds28c36.writeMemory(DS28C36::publicKeySyPage, publicKey.y);
+ }
+ if (!result) {
+ result = verifyEcdsaSignature(ds28c36, DS28C36::KeyNumS, data, signature,
+ pioa, piob);
+ }
+ return result;
+}
+
+error_code readRomIdAndManId(DS28C36 & ds28c36, RomId::span romId,
+ ManId::span manId) {
+ DS28C36::RomOptions romOptions;
+ error_code result = ds28c36.readMemory(DS28C36::romOptionsPage, romOptions);
+ if (!result) {
+ copy(romOptions.romId(), romId);
+ copy(romOptions.manId(), manId);
+ }
+ return result;
+}
+
+error_code enableCoprocessor(DS2476 & ds2476) {
+ DS2476::GpioControl gpioControl;
+ error_code result = ds2476.readMemory(DS2476::gpioControlPage, gpioControl);
+ if (!result) {
+ if (!gpioControl.pioaConducting()) {
+ gpioControl.setPioaConducting(true);
+ result = ds2476.writeMemory(DS2476::gpioControlPage, gpioControl);
+ }
+ }
+ return result;
+}
+
+static void setAnonymous(RomId::span romId) {
+ std::fill(romId.begin(), romId.end(), 0xFF);
+}
+
+DS28C36::PageAuthenticationData &
+DS28C36::PageAuthenticationData::setAnonymousRomId() {
+ setAnonymous(romId());
+ return *this;
+}
+
+DS28C36::EncryptionHmacData & DS28C36::EncryptionHmacData::setAnonymousRomId() {
+ setAnonymous(romId());
+ return *this;
+}
+
+} // namespace MaximInterface