Device interface library for multiple platforms including Mbed.

Dependents:   DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#

Maxim Interface is a library framework focused on providing flexible and expressive hardware interfaces. Both communication interfaces such as I2C and 1-Wire and device interfaces such as DS18B20 are supported. Modern C++ concepts are used extensively while keeping compatibility with C++98/C++03 and requiring no external dependencies. The embedded-friendly design does not depend on exceptions or RTTI.

The full version of the project is hosted on GitLab: https://gitlab.com/iabenz/MaximInterface

Revision:
8:5ea891c7d1a1
Parent:
7:9cd16581b578
Child:
11:3f3bf6bf5e6c
--- a/MaximInterfaceDevices/DS28C40.cpp	Mon Jul 22 11:44:07 2019 -0500
+++ b/MaximInterfaceDevices/DS28C40.cpp	Mon Sep 16 11:13:37 2019 -0500
@@ -1,5 +1,5 @@
 /*******************************************************************************
-* Copyright (C) 2019 Maxim Integrated Products, Inc., All Rights Reserved.
+* Copyright (C) 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"),
@@ -39,6 +39,7 @@
 
 using namespace Core;
 using std::copy;
+using std::pair;
 
 static const int readMemoryTimeMs = 2;
 static const int writeMemoryTimeMs = 150;
@@ -73,9 +74,9 @@
 const int DS28C40::memoryPages;
 const int DS28C40::protectionBlocks;
 
-error_code DS28C40::writeMemory(int pageNum, Page::const_span page) {
+Result<void> DS28C40::writeMemory(int pageNum, Page::const_span page) {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t request[2 + Page::size];
@@ -85,29 +86,28 @@
   return runCommand(request, writeMemoryTimeMs);
 }
 
-error_code DS28C40::readMemory(int pageNum, Page::span page) {
+Result<DS28C40::Page::array> DS28C40::readMemory(int pageNum) const {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer[1 + Page::size];
   buffer[0] = 0x44;
   buffer[1] = pageNum;
-  span<uint_least8_t> response(buffer);
-  const error_code result =
-      runCommand(make_span(buffer, 2), readMemoryTimeMs, response);
-  if (!result) {
-    copy(response.begin(), response.end(), page.begin());
+  const Result<span<uint_least8_t> > response =
+      runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer);
+  if (!response) {
+    return response.error();
   }
-  return result;
+  Page::array page;
+  copy(response.value().begin(), response.value().end(), page.begin());
+  return page;
 }
 
-error_code
-DS28C40::encryptedReadMemory(int pageNum, KeySecret secret,
-                             EncryptionChallenge::span encryptionChallenge,
-                             Page::span encryptedPage) {
+Result<pair<DS28C40::EncryptionChallenge::array, DS28C40::Page::array> >
+DS28C40::encryptedReadMemory(int pageNum, KeySecret secret) const {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const size_t requestSize = 3;
@@ -116,27 +116,26 @@
   buffer[0] = 0x4B;
   buffer[1] = pageNum;
   buffer[2] = secret;
-  span<uint_least8_t> response(buffer, responseSize);
-  const error_code result =
-      runCommand(make_span(buffer, requestSize),
-                 readMemoryTimeMs + computeTimeMs, response);
-  if (!result) {
-    span<uint_least8_t>::const_iterator begin = response.begin();
-    span<uint_least8_t>::const_iterator end =
-        begin + encryptionChallenge.size();
-    copy(begin, end, encryptionChallenge.begin());
-    begin = end;
-    end = begin + encryptedPage.size();
-    copy(begin, end, encryptedPage.begin());
+  const Result<span<uint_least8_t> > response = runCommand(
+      make_span(buffer, requestSize), readMemoryTimeMs + computeTimeMs,
+      make_span(buffer, responseSize));
+  if (!response) {
+    return response.error();
   }
-  return result;
+  pair<EncryptionChallenge::array, Page::array> data;
+  span<uint_least8_t>::const_iterator begin = response.value().begin();
+  span<uint_least8_t>::const_iterator end = begin + data.first.size();
+  copy(begin, end, data.first.begin());
+  begin = end;
+  end = begin + data.second.size();
+  copy(begin, end, data.second.begin());
+  return data;
 }
 
-error_code DS28C40::readBlockProtection(int blockNumber,
-                                        Optional<KeySecret> & keySecret,
-                                        BlockProtection & protection) {
+Result<pair<Optional<DS28C40::KeySecret>, DS28C40::BlockProtection> >
+DS28C40::readBlockProtection(int blockNumber) const {
   if (blockNumber < 0 || blockNumber >= protectionBlocks) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const size_t requestSize = 2;
@@ -144,39 +143,40 @@
   uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
   buffer[0] = 0xAA;
   buffer[1] = blockNumber;
-  span<uint_least8_t> response(buffer, responseSize);
-  const error_code result =
-      runCommand(make_span(buffer, requestSize), readMemoryTimeMs, response);
-  if (result) {
-    return result;
+  const Result<span<uint_least8_t> > response =
+      runCommand(make_span(buffer, requestSize), readMemoryTimeMs,
+                 make_span(buffer, responseSize));
+  if (!response) {
+    return response.error();
   }
-  if ((response[0] & 0x3F) != blockNumber) {
-    return make_error_code(InvalidResponseError);
+  if ((response.value()[0] & 0x3F) != blockNumber) {
+    return InvalidResponseError;
   }
-  switch (response[0] >> 6) {
+  pair<Optional<KeySecret>, BlockProtection> data;
+  switch (response.value()[0] >> 6) {
   case 0:
-    keySecret = none;
+    data.first = none;
     break;
   case 1:
-    keySecret = KeySecretA;
+    data.first = KeySecretA;
     break;
   case 2:
-    keySecret = KeySecretB;
+    data.first = KeySecretB;
     break;
   default:
-    return make_error_code(InvalidResponseError);
+    return InvalidResponseError;
   }
-  if ((response[1] & 0x20) != 0) {
-    return make_error_code(InvalidResponseError);
+  if ((response.value()[1] & 0x20) != 0) {
+    return InvalidResponseError;
   }
-  protection = response[1];
-  return error_code();
+  data.second = response.value()[1];
+  return data;
 }
 
-error_code DS28C40::setBlockProtection(int blockNum, KeySecret keySecret,
-                                       const BlockProtection & protection) {
+Result<void> DS28C40::setBlockProtection(int blockNum, KeySecret keySecret,
+                                         const BlockProtection & protection) {
   if (blockNum < 0 || blockNum >= protectionBlocks || keySecret == KeySecretS) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const uint_least8_t request[] = {
@@ -187,12 +187,10 @@
   return runCommand(request, writeStateTimeMs);
 }
 
-error_code
-DS28C40::computeAndReadPageAuthentication(int pageNum, KeySecret key,
-                                          Page::const_span challenge,
-                                          Ecc256::Signature::span signature) {
+Result<Ecc256::Signature::array> DS28C40::computeAndReadEcdsaPageAuthentication(
+    int pageNum, KeySecret key, Page::const_span challenge) const {
   if (pageNum < 0 || pageNum >= memoryPages || key == KeySecretS) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const size_t requestSize = 3 + Page::size;
@@ -202,26 +200,26 @@
   buffer[1] = pageNum;
   buffer[2] = key + 3;
   copy(challenge.begin(), challenge.end(), buffer + 3);
-  span<uint_least8_t> response(buffer, responseSize);
-  const error_code result = runCommand(make_span(buffer, requestSize),
-                                       generateEcdsaSignatureTimeMs, response);
-  if (!result) {
-    span<uint_least8_t>::const_iterator begin = response.begin();
-    span<uint_least8_t>::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());
+  const Result<span<uint_least8_t> > response =
+      runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs,
+                 make_span(buffer, responseSize));
+  if (!response) {
+    return response.error();
   }
-  return result;
+  Ecc256::Signature::array signature;
+  span<uint_least8_t>::const_iterator begin = response.value().begin();
+  span<uint_least8_t>::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 signature;
 }
 
-error_code DS28C40::computeAndReadPageAuthentication(int pageNum,
-                                                     KeySecret secret,
-                                                     Page::const_span challenge,
-                                                     Page::span hmac) {
+Result<DS28C40::Page::array> DS28C40::computeAndReadSha256PageAuthentication(
+    int pageNum, KeySecret secret, Page::const_span challenge) const {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const size_t requestSize = 3 + Page::size;
@@ -231,21 +229,23 @@
   buffer[1] = pageNum;
   buffer[2] = secret;
   copy(challenge.begin(), challenge.end(), buffer + 3);
-  span<uint_least8_t> response(buffer, responseSize);
-  const error_code result =
-      runCommand(make_span(buffer, requestSize), computeTimeMs, response);
-  if (!result) {
-    copy(response.begin(), response.end(), hmac.begin());
+  const Result<span<uint_least8_t> > response =
+      runCommand(make_span(buffer, requestSize), computeTimeMs,
+                 make_span(buffer, responseSize));
+  if (!response) {
+    return response.error();
   }
-  return result;
+  Page::array hmac;
+  copy(response.value().begin(), response.value().end(), hmac.begin());
+  return hmac;
 }
 
-error_code DS28C40::computeMultiblockHash(bool firstBlock, bool lastBlock,
-                                          span<const uint_least8_t> data) {
+Result<void> DS28C40::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);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer[2 + maxDataSize];
@@ -261,21 +261,21 @@
   return runCommand(make_span(buffer, 2 + data.size()), computeTimeMs);
 }
 
-error_code DS28C40::verifyEcdsaSignature(
+Result<void> DS28C40::verifyEcdsaSignature(
     KeySecret key, bool authorityKey, GpioState gpioState,
     Ecc256::Signature::const_span signature, span<const uint_least8_t> data) {
   return verifyEcdsaSignature(key, authorityKey, DataInput, gpioState,
                               signature, data);
 }
 
-error_code DS28C40::verifyEcdsaSignature(
+Result<void> DS28C40::verifyEcdsaSignature(
     KeySecret key, bool authorityKey, GpioState gpioState,
     Ecc256::Signature::const_span signature, Page::const_span hash) {
   return verifyEcdsaSignature(key, authorityKey, HashInput, gpioState,
                               signature, hash);
 }
 
-error_code
+Result<void>
 DS28C40::verifyEcdsaSignature(KeySecret key, bool authorityKey,
                               GpioState gpioState,
                               Ecc256::Signature::const_span signature) {
@@ -283,13 +283,13 @@
                               span<const uint_least8_t>());
 }
 
-error_code DS28C40::verifyEcdsaSignature(
+Result<void> DS28C40::verifyEcdsaSignature(
     KeySecret key, bool authorityKey, HashType hashType, GpioState gpioState,
     Ecc256::Signature::const_span signature, span<const uint_least8_t> buffer) {
   const span<const uint_least8_t>::index_type maxBufferSize = 61;
 
   if (buffer.size() > maxBufferSize) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t request[2 + 2 * Ecc256::Scalar::size + maxBufferSize];
@@ -317,7 +317,7 @@
     }
     // else: Go to default case.
   default:
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
   *requestIt |= hashType << 3;
   if (gpioState != Unchanged) {
@@ -334,13 +334,13 @@
                         (hashType == DataInput ? computeTimeMs : 0));
 }
 
-error_code DS28C40::authenticateEcdsaPublicKey(
+Result<void> DS28C40::authenticateEcdsaPublicKey(
     KeySecret key, Ecc256::Signature::const_span cert,
     span<const uint_least8_t> certCustomization) {
   return authenticateEcdsaPublicKey(key, true, cert, certCustomization, NULL);
 }
 
-error_code DS28C40::authenticateEcdsaPublicKey(
+Result<void> DS28C40::authenticateEcdsaPublicKey(
     KeySecret key, bool authWrites, Ecc256::Signature::const_span cert,
     span<const uint_least8_t> certCustomization,
     span<const uint_least8_t> ecdhCustomization) {
@@ -348,7 +348,7 @@
                                     &ecdhCustomization);
 }
 
-error_code DS28C40::authenticateEcdsaPublicKey(
+Result<void> DS28C40::authenticateEcdsaPublicKey(
     KeySecret key, bool authWrites, Ecc256::Signature::const_span cert,
     span<const uint_least8_t> certCustomization,
     const span<const uint_least8_t> * ecdhCustomization) {
@@ -364,11 +364,11 @@
           ecdhCustomization->size() <= maxEcdhCustomizationSize &&
           certCustomization.size() + ecdhCustomization->size() <=
               maxTotalCustomizationSize)))) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   if (key == KeySecretS) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t
@@ -395,14 +395,14 @@
   return runCommand(make_span(request, requestIt), delay);
 }
 
-error_code DS28C40::authenticatedEcdsaWriteMemory(
+Result<void> DS28C40::authenticatedEcdsaWriteMemory(
     int pageNum, bool useKeyS, Page::const_span newPageData,
     Ecc256::Signature::const_span signature) {
   return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature,
                                        NULL);
 }
 
-error_code DS28C40::authenticatedEcdsaWriteMemory(
+Result<void> DS28C40::authenticatedEcdsaWriteMemory(
     int pageNum, bool useKeyS, Page::const_span newPageData,
     Ecc256::Signature::const_span signature,
     EncryptionChallenge::const_span challenge) {
@@ -410,12 +410,12 @@
                                        &challenge);
 }
 
-error_code DS28C40::authenticatedEcdsaWriteMemory(
+Result<void> DS28C40::authenticatedEcdsaWriteMemory(
     int pageNum, bool useKeyS, Page::const_span newPageData,
     Ecc256::Signature::const_span signature,
     const EncryptionChallenge::const_span * challenge) {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size +
@@ -437,25 +437,26 @@
   return runCommand(make_span(request, requestIt), delay);
 }
 
-error_code DS28C40::authenticatedSha256WriteMemory(int pageNum, bool useSecretS,
-                                                   Page::const_span newPageData,
-                                                   Page::const_span hmac) {
+Result<void>
+DS28C40::authenticatedSha256WriteMemory(int pageNum, bool useSecretS,
+                                        Page::const_span newPageData,
+                                        Page::const_span hmac) {
   return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac,
                                         NULL);
 }
 
-error_code DS28C40::authenticatedSha256WriteMemory(
+Result<void> DS28C40::authenticatedSha256WriteMemory(
     int pageNum, bool useSecretS, Page::const_span newPageData,
     Page::const_span hmac, EncryptionChallenge::const_span challenge) {
   return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac,
                                         &challenge);
 }
 
-error_code DS28C40::authenticatedSha256WriteMemory(
+Result<void> DS28C40::authenticatedSha256WriteMemory(
     int pageNum, bool useSecretS, Page::const_span newPageData,
     Page::const_span hmac, const EncryptionChallenge::const_span * challenge) {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t request[3 + 2 * Page::size + EncryptionChallenge::size];
@@ -473,12 +474,12 @@
   return runCommand(make_span(request, requestIt), delay);
 }
 
-error_code
+Result<void>
 DS28C40::computeAndWriteSha256Secret(int pageNum, KeySecret masterSecret,
                                      KeySecret destinationSecret,
                                      Page::const_span partialSecret) {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t request[3 + Page::size];
@@ -489,75 +490,73 @@
   return runCommand(request, writeMemoryTimeMs + computeTimeMs);
 }
 
-error_code DS28C40::generateEcc256KeyPair(KeySecret key) {
+Result<void> DS28C40::generateEcc256KeyPair(KeySecret key) {
   if (key == KeySecretS) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const uint_least8_t request[] = {0xCB, key == KeySecretB};
   return runCommand(request, generateEccKeyPairTimeMs);
 }
 
-error_code DS28C40::readRng(span<uint_least8_t> data) {
+Result<void> DS28C40::readRng(span<uint_least8_t> data) const {
   const span<uint_least8_t>::index_type maxDataSize = 64;
   if ((data.size() < 1) || (data.size() > maxDataSize)) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t buffer[1 + maxDataSize];
   buffer[0] = readRngCmd;
   buffer[1] = static_cast<uint_least8_t>(data.size() - 1);
-  span<uint_least8_t> response(buffer, 1 + data.size());
-  const error_code result =
-      runCommand(make_span(buffer, 2), trngGenerationTimeMs, response);
-  if (!result) {
-    copy(response.begin(), response.end(), data.begin());
+  const Result<span<uint_least8_t> > response =
+      runCommand(make_span(buffer, 2), trngGenerationTimeMs,
+                 make_span(buffer, 1 + data.size()));
+  if (!response) {
+    return response.error();
   }
-  return result;
+  copy(response.value().begin(), response.value().end(), data.begin());
+  return none;
 }
 
-error_code DS28C40::entropyHealthTest() {
+Result<void> DS28C40::entropyHealthTest() const {
   const uint_least8_t request[] = {readRngCmd, 0x80};
   return runCommand(request, trngOnDemandCheckTimeMs);
 }
 
-error_code DS28C40::runCommand(span<const uint_least8_t> request, int delayTime,
-                               span<uint_least8_t> & response) {
-  const span<const uint_least8_t>::index_type responseInputSize =
-      response.size();
-  error_code result = doRunCommand(request, delayTime, response);
-  if (result) {
-    return result;
+Result<span<uint_least8_t> >
+DS28C40::runCommand(span<const uint_least8_t> request, int delayTime,
+                    span<uint_least8_t> response) const {
+  const Result<span<uint_least8_t> > responseOutput =
+      doRunCommand(request, delayTime, response);
+  if (!responseOutput) {
+    return responseOutput;
   }
-  if (response.empty()) {
-    return make_error_code(InvalidResponseError);
+  if (responseOutput.value().empty()) {
+    return InvalidResponseError;
   }
   // Parse command result byte.
-  switch (response[0]) {
+  switch (responseOutput.value().front()) {
   case 0xAA:
     // Success response.
-    if (response.size() != responseInputSize) {
-      result = make_error_code(InvalidResponseError);
-    }
     break;
 
   case 0x00:
-    result = make_error_code(AuthenticationError);
-    break;
+    return AuthenticationError;
 
   default:
-    result.assign(response[0], errorCategory());
-    break;
+    return error_code(responseOutput.value().front(), errorCategory());
   }
-  response = response.subspan(1);
-  return result;
+  if (responseOutput.value().size() != response.size()) {
+    return InvalidResponseError;
+  }
+  return responseOutput.value().subspan(1);
 }
 
-error_code DS28C40::runCommand(span<const uint_least8_t> request,
-                               int delayTime) {
+Result<void> DS28C40::runCommand(span<const uint_least8_t> request,
+                                 int delayTime) const {
   uint_least8_t buffer;
-  span<uint_least8_t> response(&buffer, 1);
-  return runCommand(request, delayTime, response);
+  MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1)));
+  return none;
 }
 
 const error_category & DS28C40::errorCategory() {
@@ -594,33 +593,20 @@
   return instance;
 }
 
-error_code computeMultiblockHash(DS28C40 & device,
-                                 span<const uint_least8_t> data) {
-  error_code result;
+Result<void> computeMultiblockHash(DS28C40 & device,
+                                   span<const uint_least8_t> data) {
   span<const uint_least8_t>::index_type dataIdx = 0;
-  while (dataIdx < data.size() && !result) {
+  while (dataIdx < data.size()) {
     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 =
+    MaximInterfaceCore_TRY(
         device.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
-                                     data.subspan(dataIdx, chunkSize));
+                                     data.subspan(dataIdx, chunkSize)));
     dataIdx += chunkSize;
   }
-  return result;
-}
-
-error_code readRomIdAndManId(DS28C40 & device, RomId::span romId,
-                             ManId::span manId) {
-  DS28C40::Page::array page;
-  error_code result = device.readMemory(DS28C40::romOptionsPage, page);
-  if (!result) {
-    const DS28C40::RomOptions romOptions(page);
-    copy(romOptions.romId(), romId);
-    copy(romOptions.manId(), manId);
-  }
-  return result;
+  return none;
 }
 
 static void setAnonymous(RomId::span romId) {