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/DS28C39.cpp	Mon Jul 22 11:44:07 2019 -0500
+++ b/MaximInterfaceDevices/DS28C39.cpp	Mon Sep 16 11:13:37 2019 -0500
@@ -1,5 +1,5 @@
 /*******************************************************************************
-* Copyright (C) 2018 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"),
@@ -55,9 +55,9 @@
 const int DS28C39::writePublicKeyYPage;
 const int DS28C39::memoryPages;
 
-error_code DS28C39::writeMemory(int pageNum, Page::const_span page) {
+Result<void> DS28C39::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];
@@ -67,72 +67,74 @@
   return runCommand(request, writeMemoryTimeMs);
 }
 
-error_code DS28C39::readMemory(int pageNum, Page::span page) {
+Result<DS28C39::Page::array> DS28C39::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 DS28C39::readStatus(bool entropyHealthTest, Status & status) {
+Result<DS28C39::Status> DS28C39::readStatus(bool entropyHealthTest) const {
   int delay = readMemoryTimeMs;
   if (entropyHealthTest) {
     delay += trngOnDemandCheckTimeMs;
   }
-  uint_least8_t buffer[Status::PageProtectionList::csize + RomId::size +
-                       ManId::size + Status::RomVersion::csize + 2];
+  uint_least8_t buffer[Status::PageProtectionList::size + RomId::size +
+                       ManId::size + Status::RomVersion::size + 2];
   buffer[0] = 0xAA;
   buffer[1] = entropyHealthTest ? 0x01 : 0x00;
-  span<uint_least8_t> response(buffer);
-  error_code result = runCommand(make_span(buffer, 2), delay, response);
-  if (!result) {
-    span<uint_least8_t>::const_iterator responseIt = response.begin();
-    for (Status::PageProtectionList::iterator it =
-             status.pageProtection.begin();
-         it != status.pageProtection.end(); ++it) {
-      *it = *responseIt;
-      ++responseIt;
-    }
-    span<uint_least8_t>::const_iterator responseItEnd =
-        responseIt + status.romId.size();
-    copy(responseIt, responseItEnd, status.romId.begin());
-    responseIt = responseItEnd;
-    responseItEnd = responseIt + status.manId.size();
-    copy(responseIt, responseItEnd, status.manId.begin());
-    responseIt = responseItEnd;
-    responseItEnd = responseIt + status.romVersion.size();
-    copy(responseIt, responseItEnd, status.romVersion.begin());
-    responseIt = responseItEnd;
-    switch (*responseIt) {
-    case Status::TestNotPerformed:
-    case Status::EntropyHealthy:
-    case Status::EntropyNotHealthy:
-      status.entropyHealthTestStatus =
-          static_cast<Status::EntropyHealthTestStatus>(*responseIt);
-      break;
+  const Result<span<uint_least8_t> > response =
+      runCommand(make_span(buffer, 2), delay, buffer);
+  if (!response) {
+    return response.error();
+  }
+  Status status;
+  span<uint_least8_t>::const_iterator responseIt = response.value().begin();
+  for (Status::PageProtectionList::array::iterator it =
+           status.pageProtection.begin();
+       it != status.pageProtection.end(); ++it) {
+    *it = *responseIt;
+    ++responseIt;
+  }
+  span<uint_least8_t>::const_iterator responseItEnd =
+      responseIt + status.romId.size();
+  copy(responseIt, responseItEnd, status.romId.begin());
+  responseIt = responseItEnd;
+  responseItEnd = responseIt + status.manId.size();
+  copy(responseIt, responseItEnd, status.manId.begin());
+  responseIt = responseItEnd;
+  responseItEnd = responseIt + status.romVersion.size();
+  copy(responseIt, responseItEnd, status.romVersion.begin());
+  responseIt = responseItEnd;
+  switch (*responseIt) {
+  case Status::TestNotPerformed:
+  case Status::EntropyHealthy:
+  case Status::EntropyNotHealthy:
+    status.entropyHealthTestStatus =
+        static_cast<Status::EntropyHealthTestStatus>(*responseIt);
+    break;
 
-    default:
-      result = make_error_code(InvalidResponseError);
-      break;
-    }
+  default:
+    return InvalidResponseError;
   }
-  return result;
+  return status;
 }
 
-error_code DS28C39::setPageProtection(int pageNum,
-                                      const PageProtection & protection) {
+Result<void> DS28C39::setPageProtection(int pageNum,
+                                        const PageProtection & protection) {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const uint_least8_t request[] = {
@@ -141,12 +143,11 @@
   return runCommand(request, writeStateTimeMs);
 }
 
-error_code
+Result<Ecc256::Signature::array>
 DS28C39::computeAndReadPageAuthentication(int pageNum, bool anonymous,
-                                          Page::const_span challenge,
-                                          Ecc256::Signature::span signature) {
+                                          Page::const_span challenge) const {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   const size_t requestSize = 2 + Page::size;
@@ -155,63 +156,66 @@
   buffer[0] = 0xA5;
   buffer[1] = pageNum | (anonymous ? 0xE0 : 0x00);
   copy(challenge.begin(), challenge.end(), buffer + 2);
-  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 DS28C39::disableDevice() {
+Result<void> DS28C39::disableDevice() {
   const uint_least8_t request[] = {0x33, 0x9E, 0xA7, 0x49, 0xFB,
                                    0x10, 0x62, 0x0A, 0x26};
   return runCommand(request, writeStateTimeMs);
 }
 
-error_code
-DS28C39::readDevicePublicKey(Ecc256::PublicKey::span devicePublicKey) {
+Result<Ecc256::PublicKey::array> DS28C39::readDevicePublicKey() const {
   uint_least8_t buffer[1 + 2 * Ecc256::Scalar::size];
   buffer[0] = 0xCB;
-  span<uint_least8_t> response(buffer);
-  const error_code result =
-      runCommand(make_span(buffer, 1), generateEccKeyPairTimeMs, response);
-  if (!result) {
-    span<uint_least8_t>::const_iterator begin = response.begin();
-    span<uint_least8_t>::const_iterator end = begin + devicePublicKey.x.size();
-    copy(begin, end, devicePublicKey.x.begin());
-    begin = end;
-    end = begin + devicePublicKey.y.size();
-    copy(begin, end, devicePublicKey.y.begin());
+  const Result<span<uint_least8_t> > response =
+      runCommand(make_span(buffer, 1), generateEccKeyPairTimeMs, buffer);
+  if (!response) {
+    return response.error();
   }
-  return result;
+  Ecc256::PublicKey::array devicePublicKey;
+  span<uint_least8_t>::const_iterator begin = response.value().begin();
+  span<uint_least8_t>::const_iterator end = begin + devicePublicKey.x.size();
+  copy(begin, end, devicePublicKey.x.begin());
+  begin = end;
+  end = begin + devicePublicKey.y.size();
+  copy(begin, end, devicePublicKey.y.begin());
+  return devicePublicKey;
 }
 
-error_code DS28C39::readRng(span<uint_least8_t> data) {
+Result<void> DS28C39::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] = 0xD2;
   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
+Result<void>
 DS28C39::authenticatePublicKey(Ecc256::Signature::const_span certificate,
                                span<const uint_least8_t> customization) {
   static const span<const uint_least8_t>::index_type maxCustomizationSize = 32;
@@ -219,7 +223,7 @@
       2 * Ecc256::Scalar::size;
 
   if (customization.size() < 1 || customization.size() > maxCustomizationSize) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t request[1 + signatureSize + maxCustomizationSize];
@@ -231,11 +235,11 @@
   return runCommand(make_span(request, requestIt), verifyEcdsaSignatureTimeMs);
 }
 
-error_code
+Result<void>
 DS28C39::authenticatedWriteMemory(int pageNum, Page::const_span page,
                                   Ecc256::Signature::const_span signature) {
   if (pageNum < 0 || pageNum >= memoryPages) {
-    return make_error_code(InvalidParameterError);
+    return InvalidParameterError;
   }
 
   uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size];
@@ -248,43 +252,40 @@
   return runCommand(request, verifyEcdsaSignatureTimeMs + writeMemoryTimeMs);
 }
 
-error_code DS28C39::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> >
+DS28C39::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 DS28C39::runCommand(span<const uint_least8_t> request,
-                               int delayTime) {
+Result<void> DS28C39::runCommand(span<const uint_least8_t> request,
+                                 int delayTime) {
   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 & DS28C39::errorCategory() {
@@ -321,17 +322,6 @@
   return instance;
 }
 
-error_code readRomIdAndManId(DS28C39 & ds28c39, Core::RomId::span romId,
-                             Core::ManId::span manId) {
-  DS28C39::Status status;
-  const error_code result = ds28c39.readStatus(false, status);
-  if (!result) {
-    copy(make_span(status.romId), romId);
-    copy(make_span(status.manId), manId);
-  }
-  return result;
-}
-
 DS28C39::PageAuthenticationData &
 DS28C39::PageAuthenticationData::setAnonymousRomId() {
   std::fill(romId().begin(), romId().end(), 0xFF);