Extended MaximInterface

Dependents:   mbed_DS28EC20_GPIO

Files at this revision

API Documentation at this revision

Comitter:
reARMnimator
Date:
Wed Apr 03 12:33:10 2019 +0000
Parent:
5:3523abdda8ed
Parent:
7:471901a04573
Child:
9:aeda90624ad0
Commit message:
Merge with version 1.7;

Changed in this revision

CMakeLists.txt Show diff for this revision Revisions of this file
Links/SelectRom.hpp Show annotated file Show diff for this revision Revisions of this file
Platforms/Qt/.mbedignore Show diff for this revision Revisions of this file
Platforms/Qt/SerialPort.cpp Show diff for this revision Revisions of this file
Platforms/Qt/SerialPort.hpp Show diff for this revision Revisions of this file
Platforms/Qt/Sleep.cpp Show diff for this revision Revisions of this file
Platforms/Qt/Sleep.hpp Show diff for this revision Revisions of this file
Platforms/dotnet/.mbedignore Show diff for this revision Revisions of this file
Platforms/dotnet/ChangeSizeType.hpp Show diff for this revision Revisions of this file
Platforms/dotnet/DelegateWrapper.hpp Show diff for this revision Revisions of this file
Platforms/dotnet/MoveOnly.hpp Show diff for this revision Revisions of this file
Platforms/dotnet/OneWireLinkLayerMaster.cpp Show diff for this revision Revisions of this file
Platforms/dotnet/OneWireLinkLayerMaster.hpp Show diff for this revision Revisions of this file
Platforms/dotnet/SerialPort.cpp Show diff for this revision Revisions of this file
Platforms/dotnet/SerialPort.hpp Show diff for this revision Revisions of this file
Platforms/dotnet/Sleep.cpp Show diff for this revision Revisions of this file
Platforms/dotnet/Sleep.hpp Show diff for this revision Revisions of this file
Platforms/mxc/.mbedignore Show diff for this revision Revisions of this file
Platforms/mxc/Error.cpp Show diff for this revision Revisions of this file
Platforms/mxc/Error.hpp Show diff for this revision Revisions of this file
Platforms/mxc/I2CMaster.cpp Show diff for this revision Revisions of this file
Platforms/mxc/I2CMaster.hpp Show diff for this revision Revisions of this file
Platforms/mxc/OneWireMaster.cpp Show diff for this revision Revisions of this file
Platforms/mxc/OneWireMaster.hpp Show diff for this revision Revisions of this file
Platforms/mxc/Sleep.cpp Show diff for this revision Revisions of this file
Platforms/mxc/Sleep.hpp Show diff for this revision Revisions of this file
clr.cmake Show diff for this revision Revisions of this file
--- a/CMakeLists.txt	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-#[[*****************************************************************************
-* 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.
-******************************************************************************]]
-
-cmake_minimum_required(VERSION 3.10)
-
-include("clr.cmake")
-
-project("MaximInterface" VERSION 1.1)
-option(BUILD_SHARED_LIBS "Build ${CMAKE_PROJECT_NAME} as a shared library." ON)
-set(MaximInterface_Platforms "" CACHE STRING
-	"List of platforms to build. Available platforms are dotnet and Qt.")
-
-if("dotnet" IN_LIST MaximInterface_Platforms)
-	# Require shared library for the dotnet platform.
-	if(NOT BUILD_SHARED_LIBS)
-		message(SEND_ERROR "BUILD_SHARED_LIBS must be enabled to build the dotnet platform.")
-	endif()
-	
-	# Initialize CLR compilation flags that all targets should use.
-	initializeClr()
-endif()
-
-# Search in parent directory for includes.
-get_filename_component(baseIncludeDir ${CMAKE_SOURCE_DIR} DIRECTORY)
-include_directories(${baseIncludeDir})
-
-# Prepend a path to all items in a list.
-macro(prependPath var path)
-	unset(${var})
-	foreach(arg ${ARGN})
-		list(APPEND ${var} "${path}/${arg}")
-	endforeach()
-endmacro(prependPath)
-
-# Add base components.
-set(resourceDirs "Devices" "Links" "Utilities")
-prependPath(DevicesSources "Devices"
-	"DS18B20.cpp"
-	"DS28C36_DS2476.cpp"
-	"DS28E15_22_25.cpp"
-	"DS28E17.cpp"
-	"DS28E38.cpp"
-	"DS1920.cpp"
-	"DS2413.cpp"
-	"DS2431.cpp"
-	"DS2465.cpp"
-	"DS2480B.cpp"
-	"DS2482_DS2484.cpp"
-	"DS9400.cpp"
-	"DS9481P_300.cpp")
-prependPath(LinksSources "Links"
-	"I2CMaster.cpp"
-	"I2CMasterDecorator.cpp"
-	"LoggingI2CMaster.cpp"
-	"LoggingOneWireMaster.cpp"
-	"LoggingSleep.cpp"
-	"OneWireMaster.cpp"
-	"OneWireMasterDecorator.cpp"
-	"RomCommands.cpp"
-	"SelectRom.cpp"
-	"SleepDecorator.cpp"
-	"Uart.cpp")
-prependPath(UtilitiesSources "Utilities"
-	"crc.cpp"
-	"Ecc256.cpp"
-	"Error.cpp"
-	"HexConversions.cpp"
-	"system_error.cpp")
-add_library(${CMAKE_PROJECT_NAME} ${DevicesSources} ${LinksSources} ${UtilitiesSources})
-
-# Add selected platforms.
-foreach(platform ${MaximInterface_Platforms})
-	if(platform STREQUAL "dotnet")
-		# Add CLR support to target.
-		enableClr(${CMAKE_PROJECT_NAME} "v4.5"
-			"System.dll"
-			"${CMAKE_SOURCE_DIR}/Platforms/dotnet/OneWireLinkLayer/OneWireLinkLayer.dll")
-		
-		# Add files to top-level target since CLR objects do not support static linking.
-		list(APPEND resourceDirs "Platforms/dotnet")
-		prependPath(dotnetSources "Platforms/dotnet"
-			"OneWireLinkLayerMaster.cpp"
-			"SerialPort.cpp"
-			"Sleep.cpp")
-		target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${dotnetSources})
-	elseif(platform STREQUAL "Qt")
-		find_package(Qt5 COMPONENTS Core SerialPort)
-		list(APPEND resourceDirs "Platforms/Qt")
-		prependPath(QtSources "Platforms/Qt"
-			"SerialPort.cpp"
-			"Sleep.cpp")
-		add_library(Qt OBJECT ${QtSources})
-		target_include_directories(Qt PRIVATE ${Qt5Core_INCLUDE_DIRS} ${Qt5SerialPort_INCLUDE_DIRS})
-		target_sources(${CMAKE_PROJECT_NAME} PRIVATE $<TARGET_OBJECTS:Qt>)
-		target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Qt5::Core Qt5::SerialPort)
-	else()
-		message(SEND_ERROR "\"${platform}\" is not a supported platform.")
-	endif()
-endforeach()
-
-# Set up build and install exports.
-target_include_directories(${CMAKE_PROJECT_NAME} INTERFACE
-	$<BUILD_INTERFACE:${baseIncludeDir}>
-	$<INSTALL_INTERFACE:.>)
-foreach(resourceDir ${resourceDirs})
-	get_filename_component(resourceInstallDir "${CMAKE_PROJECT_NAME}/${resourceDir}" DIRECTORY)
-	install(DIRECTORY ${resourceDir} DESTINATION ${resourceInstallDir}
-		FILES_MATCHING PATTERN "*.h*" PATTERN "*.dll")
-endforeach()
-install(TARGETS ${CMAKE_PROJECT_NAME} EXPORT "${CMAKE_PROJECT_NAME}Config"
-	ARCHIVE DESTINATION $<CONFIG>
-	LIBRARY DESTINATION $<CONFIG>
-	RUNTIME DESTINATION $<CONFIG>)
-install(EXPORT "${CMAKE_PROJECT_NAME}Config" DESTINATION "cmake")
-export(TARGETS ${CMAKE_PROJECT_NAME} FILE "${CMAKE_PROJECT_NAME}Config.cmake")
-
-# Set up source groups.
-get_property(${CMAKE_PROJECT_NAME}Sources TARGET ${CMAKE_PROJECT_NAME} PROPERTY SOURCES)
-source_group(TREE ${CMAKE_SOURCE_DIR} FILES ${${CMAKE_PROJECT_NAME}Sources})
\ No newline at end of file
--- a/Devices/DS18B20.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS18B20.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -36,27 +36,22 @@
 
 namespace MaximInterface {
 
-enum DS18B20_CMDS {
-  WRITE_SCRATCHPAD = 0x4E,
-  READ_SCRATCHPAD = 0xBE,
-  COPY_SCRATCHPAD = 0x48,
-  CONV_TEMPERATURE = 0x44,
-  READ_POWER_SUPPY = 0xB4,
-  RECALL = 0xB8
-};
+const uint_least8_t DS18B20::nineBitResolution;
+const uint_least8_t DS18B20::tenBitResolution;
+const uint_least8_t DS18B20::elevenBitResolution;
+const uint_least8_t DS18B20::twelveBitResolution;
 
 error_code DS18B20::initialize() {
-  Scratchpad scratchpad;
+  Scratchpad::array scratchpad;
   return readScratchpad(scratchpad);
 }
 
 error_code DS18B20::writeScratchpad(uint_least8_t th, uint_least8_t tl,
-                                    uint_least8_t res) {
+                                    uint_least8_t res) {  
   error_code result = selectRom(*master);
   if (!result) {
-    const uint_least8_t sendBlock[] = {WRITE_SCRATCHPAD, th, tl, res};
-    result =
-        master->writeBlock(sendBlock, sizeof(sendBlock) / sizeof(sendBlock[0]));
+    const uint_least8_t sendBlock[] = {0x4E, th, tl, res};
+    result = master->writeBlock(sendBlock);
     if (!result) {
       resolution = res;
     }
@@ -64,17 +59,16 @@
   return result;
 }
 
-error_code DS18B20::readScratchpad(Scratchpad & scratchpad) {
+error_code DS18B20::readScratchpad(Scratchpad::span scratchpad) {  
   error_code result = selectRom(*master);
   if (result) {
     return result;
   }
-  result =
-      master->writeByteSetLevel(READ_SCRATCHPAD, OneWireMaster::NormalLevel);
+  result = master->writeByte(0xBE);
   if (result) {
     return result;
   }
-  result = master->readBlock(scratchpad.data(), scratchpad.size());
+  result = master->readBlock(scratchpad);
   if (result) {
     return result;
   }
@@ -83,7 +77,7 @@
   if (result) {
     return result;
   }
-  if (receivedCrc == calculateCrc8(scratchpad.data(), scratchpad.size())) {
+  if (receivedCrc == calculateCrc8(scratchpad)) {
     resolution = scratchpad[4];
   } else {
     result = make_error_code(CrcError);
@@ -91,21 +85,22 @@
   return result;
 }
 
-error_code DS18B20::readPowerSupply(bool & localPower) {
+error_code DS18B20::readPowerSupply(bool & localPower) {  
   error_code result = selectRom(*master);
   if (result) {
     return result;
   }
-  result =
-      master->writeByteSetLevel(READ_POWER_SUPPY, OneWireMaster::NormalLevel);
+  result = master->writeByte(0xB4);
   if (result) {
     return result;
   }
-  result = master->touchBitSetLevel(localPower, OneWireMaster::NormalLevel);
+  result = master->touchBit(localPower);
   return result;
 }
 
 error_code DS18B20::copyScratchpad() {
+  const uint_least8_t copyScratchpadCmd = 0x48;
+  
   bool hasLocalPower;
   error_code result = readPowerSupply(hasLocalPower);
   if (result) {
@@ -116,17 +111,16 @@
     return result;
   }
   if (hasLocalPower) {
-    result =
-        master->writeByteSetLevel(COPY_SCRATCHPAD, OneWireMaster::NormalLevel);
+    result = master->writeByte(copyScratchpadCmd);
     bool recvbit = 0;
     while (!recvbit && !result) {
-      result = master->touchBitSetLevel(recvbit, OneWireMaster::NormalLevel);
+      result = master->touchBit(recvbit);
     }
   } else {
-    result =
-        master->writeByteSetLevel(COPY_SCRATCHPAD, OneWireMaster::StrongLevel);
+    result = master->writeByteSetLevel(copyScratchpadCmd,
+                                       OneWireMaster::StrongLevel);
     if (!result) {
-      (*sleep)(10);
+      sleep->invoke(10);
       result = master->setLevel(OneWireMaster::NormalLevel);
     }
   }
@@ -134,6 +128,8 @@
 }
 
 error_code DS18B20::convertTemperature() {
+  const uint_least8_t convertTemperatureCmd = 0x44;
+  
   bool hasLocalPower;
   error_code result = readPowerSupply(hasLocalPower);
   if (result) {
@@ -144,15 +140,14 @@
     return result;
   }
   if (hasLocalPower) {
-    result =
-        master->writeByteSetLevel(CONV_TEMPERATURE, OneWireMaster::NormalLevel);
+    result = master->writeByte(convertTemperatureCmd);
     bool recvbit = 0;
     while (!result && !recvbit) {
-      result = master->touchBitSetLevel(recvbit, OneWireMaster::NormalLevel);
+      result = master->touchBit(recvbit);
     }
   } else {
-    result =
-        master->writeByteSetLevel(CONV_TEMPERATURE, OneWireMaster::StrongLevel);
+    result = master->writeByteSetLevel(convertTemperatureCmd,
+                                       OneWireMaster::StrongLevel);
     if (!result) {
       int sleepTime;
       switch (resolution) {
@@ -173,17 +168,17 @@
         sleepTime = 750;
         break;
       }
-      (*sleep)(sleepTime);
+      sleep->invoke(sleepTime);
       result = master->setLevel(OneWireMaster::NormalLevel);
     }
   }
   return result;
 }
 
-error_code DS18B20::recallEeprom() {
+error_code DS18B20::recallEeprom() {  
   error_code result = selectRom(*master);
   if (!result) {
-    result = master->writeByte(RECALL);
+    result = master->writeByte(0xB8);
   }
   return result;
 }
@@ -214,13 +209,13 @@
   if (result) {
     return result;
   }
-  DS18B20::Scratchpad scratchpad;
+  DS18B20::Scratchpad::array scratchpad;
   result = ds18b20.readScratchpad(scratchpad);
   if (result) {
     return result;
   }
 
-  unsigned int tempData =
+  const unsigned int tempData =
       (static_cast<unsigned int>(scratchpad[1]) << 8) | scratchpad[0];
   const unsigned int signMask = 0xF800;
   if ((tempData & signMask) == signMask) {
--- a/Devices/DS18B20.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS18B20.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,11 +35,12 @@
 
 #include <MaximInterface/Links/SelectRom.hpp>
 #include <MaximInterface/Links/Sleep.hpp>
+#include <MaximInterface/Utilities/array_span.hpp>
 #include <MaximInterface/Utilities/Export.h>
 
 namespace MaximInterface {
 
-/// DS18B20 Programmable Resolution 1-Wire Digital Thermometer
+/// @brief DS18B20 Programmable Resolution 1-Wire Digital Thermometer
 /// @details The DS18B20 digital thermometer provides 9-bit to 12-bit
 /// Celsius temperature measurements and has an alarm function with
 /// nonvolatile user-programmable upper and lower trigger points. The
@@ -58,14 +59,15 @@
   static const uint_least8_t twelveBitResolution = 0x7F;
 
   /// Holds the contents of the device scratchpad.
-  typedef array<uint_least8_t, 8> Scratchpad;
+  typedef array_span<uint_least8_t, 8> Scratchpad;
 
-  DS18B20(const Sleep & sleep, OneWireMaster & master,
-          const SelectRom & selectRom)
+  DS18B20(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom)
       : selectRom(selectRom), master(&master), sleep(&sleep), resolution(0) {}
 
-  void setSleep(const Sleep & sleep) { this->sleep = &sleep; }
+  void setSleep(Sleep & sleep) { this->sleep = &sleep; }
+  
   void setMaster(OneWireMaster & master) { this->master = &master; }
+  
   void setSelectRom(const SelectRom & selectRom) {
     this->selectRom = selectRom;
   }
@@ -88,7 +90,7 @@
 
   /// Read Scratchpad Command
   /// @param[out] scratchpad Contents of scratchpad.
-  MaximInterface_EXPORT error_code readScratchpad(Scratchpad & scratchpad);
+  MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span scratchpad);
 
   /// Copy Scratchpad Command
   /// @details This command copies from the scratchpad into the
@@ -123,7 +125,8 @@
 };
 
 /// Reads the current temperature as an integer value with decimal.
-/// @param[out] temperature Temperature in degrees Celsius multiplied by 2.
+/// @param ds18b20 Device to read.
+/// @param[out] temperature Temperature in degrees Celsius multiplied by 16.
 MaximInterface_EXPORT error_code readTemperature(DS18B20 & ds18b20,
                                                  int & temperature);
 
--- a/Devices/DS1920.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS1920.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -36,35 +36,25 @@
 
 namespace MaximInterface {
 
-enum DS1920_CMDS {
-  WRITE_SCRATCHPAD = 0x4E,
-  READ_SCRATCHPAD = 0xBE,
-  COPY_SCRATCHPAD = 0x48,
-  CONV_TEMPERATURE = 0x44,
-  RECALL = 0xB8
-};
-
-error_code DS1920::writeScratchpad(uint_least8_t th, uint_least8_t tl) {
+error_code DS1920::writeScratchpad(uint_least8_t th, uint_least8_t tl) {  
   error_code result = selectRom(*master);
   if (!result) {
-    const uint_least8_t sendBlock[] = {WRITE_SCRATCHPAD, th, tl};
-    result =
-        master->writeBlock(sendBlock, sizeof(sendBlock) / sizeof(sendBlock[0]));
+    const uint_least8_t sendBlock[] = {0x4E, th, tl};
+    result = master->writeBlock(sendBlock);
   }
   return result;
 }
 
-error_code DS1920::readScratchpad(Scratchpad & scratchpad) {
+error_code DS1920::readScratchpad(Scratchpad::span scratchpad) {  
   error_code result = selectRom(*master);
   if (!result) {
-    result = master->writeByte(READ_SCRATCHPAD);
+    result = master->writeByte(0xBE);
     if (!result) {
-      result = master->readBlock(scratchpad.data(), scratchpad.size());
+      result = master->readBlock(scratchpad);
       if (!result) {
         uint_least8_t receivedCrc;
         result = master->readByte(receivedCrc);
-        if (!result && (receivedCrc !=
-                        calculateCrc8(scratchpad.data(), scratchpad.size()))) {
+        if (!result && (receivedCrc != calculateCrc8(scratchpad))) {
           result = make_error_code(CrcError);
         }
       }
@@ -73,36 +63,34 @@
   return result;
 }
 
-error_code DS1920::copyScratchpad() {
+error_code DS1920::copyScratchpad() {  
   error_code result = selectRom(*master);
   if (!result) {
-    result =
-        master->writeByteSetLevel(COPY_SCRATCHPAD, OneWireMaster::StrongLevel);
+    result = master->writeByteSetLevel(0x48, OneWireMaster::StrongLevel);
     if (!result) {
-      (*sleep)(10);
+      sleep->invoke(10);
       result = master->setLevel(OneWireMaster::NormalLevel);
     }
   }
   return result;
 }
 
-error_code DS1920::convertTemperature() {
+error_code DS1920::convertTemperature() {  
   error_code result = selectRom(*master);
   if (!result) {
-    result =
-        master->writeByteSetLevel(CONV_TEMPERATURE, OneWireMaster::StrongLevel);
+    result = master->writeByteSetLevel(0x44, OneWireMaster::StrongLevel);
     if (!result) {
-      (*sleep)(750);
+      sleep->invoke(750);
       result = master->setLevel(OneWireMaster::NormalLevel);
     }
   }
   return result;
 }
 
-error_code DS1920::recallEeprom() {
+error_code DS1920::recallEeprom() {  
   error_code result = selectRom(*master);
   if (!result) {
-    result = master->writeByte(RECALL);
+    result = master->writeByte(0xB8);
   }
   return result;
 }
@@ -133,7 +121,7 @@
   if (result) {
     return result;
   }
-  DS1920::Scratchpad scratchpad;
+  DS1920::Scratchpad::array scratchpad;
   result = ds1920.readScratchpad(scratchpad);
   if (result) {
     return result;
--- a/Devices/DS1920.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS1920.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,11 +35,12 @@
 
 #include <MaximInterface/Links/SelectRom.hpp>
 #include <MaximInterface/Links/Sleep.hpp>
+#include <MaximInterface/Utilities/array_span.hpp>
 #include <MaximInterface/Utilities/Export.h>
 
 namespace MaximInterface {
 
-/// DS1920 1-Wire Temperature iButton
+/// @brief DS1920 1-Wire Temperature iButton
 /// @details The iButton® temperature logger (DS1920) provides
 /// direct-to-digital 9-bit temperature readings over a range of
 /// -55°C to +100°C in 0.5° increments. The iButton communicates with
@@ -54,19 +55,20 @@
   enum ErrorValue { CrcError = 1, DataError };
 
   /// Holds the contents of the device scratchpad.
-  typedef array<uint_least8_t, 8> Scratchpad;
+  typedef array_span<uint_least8_t, 8> Scratchpad;
 
-  DS1920(const Sleep & sleep, OneWireMaster & master,
-         const SelectRom & selectRom)
+  DS1920(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom)
       : selectRom(selectRom), master(&master), sleep(&sleep) {}
 
-  void setSleep(const Sleep & sleep) { this->sleep = &sleep; }
+  void setSleep(Sleep & sleep) { this->sleep = &sleep; }
+  
   void setMaster(OneWireMaster & master) { this->master = &master; }
+  
   void setSelectRom(const SelectRom & selectRom) {
     this->selectRom = selectRom;
   }
 
-  /// Write Scratchpad Command
+  /// @brief Write Scratchpad Command
   /// @details If the result of a temperature measurement is higher
   /// than TH or lower than TL, an alarm flag inside the device is
   /// set. This flag is updated with every temperature measurement.
@@ -77,21 +79,21 @@
   MaximInterface_EXPORT error_code writeScratchpad(uint_least8_t th,
                                                    uint_least8_t tl);
 
-  /// Read Scratchpad Command
+  /// @brief Read Scratchpad Command
   /// @param[out] scratchpad Contents of scratchpad.
-  MaximInterface_EXPORT error_code readScratchpad(Scratchpad & scratchpad);
+  MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span scratchpad);
 
-  /// Copy Scratchpad Command
+  /// @brief Copy Scratchpad Command
   /// @details This command copies from the scratchpad into the
   /// EEPROM of the DS1920, storing the temperature trigger bytes
   /// in nonvolatile memory.
   MaximInterface_EXPORT error_code copyScratchpad();
 
-  /// Convert Temperature Command
+  /// @brief Convert Temperature Command
   /// @details This command begins a temperature conversion.
   MaximInterface_EXPORT error_code convertTemperature();
 
-  /// Recall Command
+  /// @brief Recall Command
   /// @details This command recalls the temperature trigger values
   /// stored in EEPROM to the scratchpad.
   MaximInterface_EXPORT error_code recallEeprom();
@@ -104,8 +106,9 @@
   const Sleep * sleep;
 };
 
-/// Reads the current temperature as an integer value.
-/// @param[out] temperature Temperature in degrees Celsius multiplied by 16.
+/// @brief Reads the current temperature as an integer value.
+/// @param ds1920 Device to read.
+/// @param[out] temperature Temperature in degrees Celsius multiplied by 2.
 MaximInterface_EXPORT error_code readTemperature(DS1920 & ds1920,
                                                  int & temperature);
 
--- a/Devices/DS2413.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS2413.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -40,10 +40,7 @@
   uint_least8_t val;
   const error_code result = pioAccessRead(val);
   if (!result) {
-    status.pioAInputState = (val & 0x1) == 0x1;
-    status.pioAOutputState = (val & 0x2) == 0x2;
-    status.pioBInputState = (val & 0x4) == 0x4;
-    status.pioBOutputState = (val & 0x8) == 0x8;
+    status = val;
   }
   return result;
 }
@@ -77,7 +74,7 @@
   error_code result = selectRom(*master);
   if (!result) {
     uint_least8_t block[] = {0x5A, val, static_cast<uint_least8_t>(val ^ 0xFF)};
-    result = master->writeBlock(block, sizeof(block) / sizeof(block[0]));
+    result = master->writeBlock(block);
     if (!result) {
       result = master->readByte(block[0]);
       if (!result && block[0] != 0xAA) {
@@ -97,10 +94,8 @@
       switch (condition) {
       case CommunicationError:
         return "Communication Error";
-
-      default:
-        return defaultErrorMessage(condition);
       }
+      return defaultErrorMessage(condition);
     }
   } instance;
   return instance;
@@ -109,8 +104,9 @@
 error_code writePioAOutputState(DS2413 & ds2413, bool pioAState) {
   DS2413::Status status;
   error_code result = ds2413.readStatus(status);
-  if (!result && pioAState != status.pioAOutputState) {
-    result = ds2413.writeOutputState(pioAState, status.pioBOutputState);
+  if (!result && pioAState != status[DS2413::PioAOutputState]) {
+    result =
+        ds2413.writeOutputState(pioAState, status[DS2413::PioBOutputState]);
   }
   return result;
 }
@@ -118,8 +114,9 @@
 error_code writePioBOutputState(DS2413 & ds2413, bool pioBState) {
   DS2413::Status status;
   error_code result = ds2413.readStatus(status);
-  if (!result && pioBState != status.pioBOutputState) {
-    result = ds2413.writeOutputState(status.pioAOutputState, pioBState);
+  if (!result && pioBState != status[DS2413::PioBOutputState]) {
+    result =
+        ds2413.writeOutputState(status[DS2413::PioAOutputState], pioBState);
   }
   return result;
 }
--- a/Devices/DS2413.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS2413.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -36,10 +36,11 @@
 #include <stdint.h>
 #include <MaximInterface/Links/SelectRom.hpp>
 #include <MaximInterface/Utilities/Export.h>
+#include <MaximInterface/Utilities/FlagSet.hpp>
 
 namespace MaximInterface {
 
-/// DS2413 1-Wire Dual Channel Addressable Switch
+/// @brief DS2413 1-Wire Dual Channel Addressable Switch
 /// @details The DS2413 is a dual-channel programmable I/O 1-Wire®
 /// chip. The PIO outputs are configured as open-drain and provide up
 /// to 20mA continuous sink capability and off-state operating voltage
@@ -53,17 +54,19 @@
 public:
   enum ErrorValue { CommunicationError = 1 };
 
-  struct Status {
-    bool pioAInputState;
-    bool pioAOutputState;
-    bool pioBInputState;
-    bool pioBOutputState;
+  enum StatusFlags {
+    PioAInputState = 0x1,
+    PioAOutputState = 0x2,
+    PioBInputState = 0x4,
+    PioBOutputState = 0x8
   };
+  typedef FlagSet<StatusFlags, 4> Status;
 
   DS2413(OneWireMaster & master, const SelectRom & selectRom)
       : selectRom(selectRom), master(&master) {}
 
   void setMaster(OneWireMaster & master) { this->master = &master; }
+  
   void setSelectRom(const SelectRom & selectRom) {
     this->selectRom = selectRom;
   }
@@ -85,13 +88,13 @@
   OneWireMaster * master;
 };
 
-/// @{
-/// Write the output logic state for only a single PIO pin.
+/// Write the output logic state for only PIOA.
 MaximInterface_EXPORT error_code writePioAOutputState(DS2413 & ds2413,
                                                       bool pioAState);
+
+/// Write the output logic state for only PIOB.
 MaximInterface_EXPORT error_code writePioBOutputState(DS2413 & ds2413,
                                                       bool pioBState);
-/// @}
 
 inline error_code make_error_code(DS2413::ErrorValue e) {
   return error_code(e, DS2413::errorCategory());
--- a/Devices/DS2431.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS2431.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -37,20 +37,13 @@
 
 namespace MaximInterface {
 
-enum Command {
-  WriteScratchpad = 0x0F,
-  ReadScratchpad = 0xAA,
-  CopyScratchpad = 0x55,
-  ReadMemory = 0xF0
-};
-
 error_code writeMemory(DS2431 & device, DS2431::Address targetAddress,
-                       const DS2431::Scratchpad & data) {
+                       DS2431::Scratchpad::const_span data) {
   error_code result = device.writeScratchpad(targetAddress, data);
   if (result) {
     return result;
   }
-  DS2431::Scratchpad readData;
+  DS2431::Scratchpad::array readData;
   uint_least8_t esByte;
   result = device.readScratchpad(readData, esByte);
   if (result) {
@@ -60,107 +53,105 @@
   return result;
 }
 
-error_code DS2431::readMemory(Address beginAddress, uint_least8_t * data,
-                              size_t dataLen) const {
-  error_code owmResult = selectRom(*master);
-  if (owmResult) {
-    return owmResult;
+error_code DS2431::readMemory(Address beginAddress,
+                              span<uint_least8_t> data) const {  
+  error_code result = selectRom(*master);
+  if (result) {
+    return result;
   }
-  const uint_least8_t sendBlock[] = {ReadMemory, beginAddress, 0x00};
-  owmResult =
-      master->writeBlock(sendBlock, sizeof(sendBlock) / sizeof(sendBlock[0]));
-  if (owmResult) {
-    return owmResult;
+  const uint_least8_t sendBlock[] = {0xF0, beginAddress, 0x00};
+  result = master->writeBlock(sendBlock);
+  if (result) {
+    return result;
   }
-  owmResult = master->readBlock(data, dataLen);
-  return owmResult;
+  result = master->readBlock(data);
+  return result;
 }
 
 error_code DS2431::writeScratchpad(Address targetAddress,
-                                   const Scratchpad & data) {
-  error_code owmResult = selectRom(*master);
-  if (owmResult) {
-    return owmResult;
+                                   Scratchpad::const_span data) {  
+  error_code result = selectRom(*master);
+  if (result) {
+    return result;
   }
-  array<uint_least8_t, 3 + Scratchpad::csize> block = {WriteScratchpad,
-                                                       targetAddress, 0x00};
-  std::copy(data.begin(), data.end(), block.begin() + 3);
-  owmResult = master->writeBlock(block.data(), block.size());
-  if (owmResult) {
-    return owmResult;
+  uint_least8_t block[3 + Scratchpad::size] = {0x0F, targetAddress, 0x00};
+  std::copy(data.begin(), data.end(), block + 3);
+  result = master->writeBlock(block);
+  if (result) {
+    return result;
   }
-  const uint_fast16_t calculatedCrc =
-      calculateCrc16(block.data(), block.size()) ^ 0xFFFFU;
-  owmResult = master->readBlock(block.data(), 2);
-  if (owmResult) {
-    return owmResult;
+  const uint_fast16_t calculatedCrc = calculateCrc16(block) ^ 0xFFFFU;
+  result = master->readBlock(make_span(block, 2));
+  if (result) {
+    return result;
   }
   if (calculatedCrc !=
       ((static_cast<uint_fast16_t>(block[1]) << 8) | block[0])) {
-    owmResult = make_error_code(CrcError);
+    result = make_error_code(CrcError);
   }
-  return owmResult;
+  return result;
 }
 
-error_code DS2431::readScratchpad(Scratchpad & data, uint_least8_t & esByte) {
-  typedef array<uint_least8_t, 6 + Scratchpad::csize> Block;
+error_code DS2431::readScratchpad(Scratchpad::span data,
+                                  uint_least8_t & esByte) {
+  typedef array<uint_least8_t, 6 + Scratchpad::size> Block;
 
-  error_code owmResult = selectRom(*master);
-  if (owmResult) {
-    return owmResult;
+  error_code result = selectRom(*master);
+  if (result) {
+    return result;
   }
-  Block block = {ReadScratchpad};
-  owmResult = master->writeByte(block.front());
-  if (owmResult) {
-    return owmResult;
+  Block block = {0xAA};
+  result = master->writeByte(block.front());
+  if (result) {
+    return result;
   }
-  owmResult = master->readBlock(block.data() + 1, block.size() - 1);
-  if (owmResult) {
-    return owmResult;
+  result = master->readBlock(make_span(block).subspan(1));
+  if (result) {
+    return result;
   }
   Block::const_iterator blockIt = block.end();
   uint_fast16_t receivedCrc = static_cast<uint_fast16_t>(*(--blockIt)) << 8;
   receivedCrc |= *(--blockIt);
   const uint_fast16_t expectedCrc =
-      calculateCrc16(block.data(), block.size() - 2) ^ 0xFFFFU;
+      calculateCrc16(make_span(block.data(), block.size() - 2)) ^ 0xFFFFU;
   if (expectedCrc == receivedCrc) {
     Block::const_iterator blockItEnd = blockIt;
     blockIt -= data.size();
     std::copy(blockIt, blockItEnd, data.begin());
     esByte = *(--blockIt);
   } else {
-    owmResult = make_error_code(CrcError);
+    result = make_error_code(CrcError);
   }
-  return owmResult;
+  return result;
 }
 
-error_code DS2431::copyScratchpad(Address targetAddress, uint_least8_t esByte) {
-  error_code owmResult = selectRom(*master);
-  if (owmResult) {
-    return owmResult;
+error_code DS2431::copyScratchpad(Address targetAddress, uint_least8_t esByte) {  
+  error_code result = selectRom(*master);
+  if (result) {
+    return result;
   }
-  uint_least8_t block[] = {CopyScratchpad, targetAddress, 0x00};
-  owmResult = master->writeBlock(block, sizeof(block) / sizeof(block[0]));
-  if (owmResult) {
-    return owmResult;
+  uint_least8_t block[] = {0x55, targetAddress, 0x00};
+  result = master->writeBlock(block);
+  if (result) {
+    return result;
   }
-  owmResult = master->writeByteSetLevel(esByte, OneWireMaster::StrongLevel);
-  if (owmResult) {
-    return owmResult;
+  result = master->writeByteSetLevel(esByte, OneWireMaster::StrongLevel);
+  if (result) {
+    return result;
   }
-  (*sleep)(10);
-  owmResult = master->setLevel(OneWireMaster::NormalLevel);
-  if (owmResult) {
-    return owmResult;
+  sleep->invoke(10);
+  result = master->setLevel(OneWireMaster::NormalLevel);
+  if (result) {
+    return result;
   }
-  owmResult = master->readByte(block[0]);
-  if (owmResult) {
-    return owmResult;
+  result = master->readByte(block[0]);
+  if (result) {
+    return result;
   }
   if (block[0] != 0xAA) {
-    owmResult = make_error_code(OperationFailure);
+    result = make_error_code(OperationFailure);
   }
-  return owmResult;
+  return result;
 }
 
 const error_category & DS2431::errorCategory() {
@@ -174,11 +165,9 @@
         return "CRC Error";
 
       case OperationFailure:
-        return "Operation Failure";
-
-      default:
-        return defaultErrorMessage(condition);
+        return "Operation Failure";        
       }
+      return defaultErrorMessage(condition);
     }
   } instance;
   return instance;
--- a/Devices/DS2431.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS2431.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,11 +35,12 @@
 
 #include <MaximInterface/Links/SelectRom.hpp>
 #include <MaximInterface/Links/Sleep.hpp>
+#include <MaximInterface/Utilities/array_span.hpp>
 #include <MaximInterface/Utilities/Export.h>
 
 namespace MaximInterface {
 
-/// DS2431 1024-bit 1-Wire EEPROM
+/// @brief DS2431 1024-bit 1-Wire EEPROM
 /// @details The DS2431 is a 1024-bit, 1-Wire® EEPROM chip organized
 /// as four memory pages of 256 bits each. Data is written to an 8-byte
 /// scratchpad, verified, and then copied to the EEPROM memory. As a
@@ -55,41 +56,41 @@
 public:
   enum ErrorValue { CrcError = 1, OperationFailure };
 
-  typedef array<uint_least8_t, 8> Scratchpad;
+  typedef array_span<uint_least8_t, 8> Scratchpad;
   typedef uint_least8_t Address;
 
-  DS2431(const Sleep & sleep, OneWireMaster & master,
-         const SelectRom & selectRom)
+  DS2431(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom)
       : selectRom(selectRom), master(&master), sleep(&sleep) {}
 
-  void setSleep(const Sleep & sleep) { this->sleep = &sleep; }
+  void setSleep(Sleep & sleep) { this->sleep = &sleep; }
+  
   void setMaster(OneWireMaster & master) { this->master = &master; }
+  
   void setSelectRom(const SelectRom & selectRom) {
     this->selectRom = selectRom;
   }
 
-  /// Reads block of data from EEPROM memory.
+  /// @brief Reads block of data from EEPROM memory.
   /// @param[in] beginAddress EEPROM memory address to start reading from.
   /// @param[out] data EEPROM data read from the device.
-  /// @param[in] dataLen Length of data parameter and number of bytes to read.
   MaximInterface_EXPORT error_code readMemory(Address beginAddress,
-                                              uint_least8_t * data,
-                                              size_t dataLen) const;
+                                              span<uint_least8_t> data) const;
 
-  /// Writes 8 bytes to the scratchpad.
-  /// @param[in] targetAddress EEPROM memory address that this data.
-  /// will be copied to.  Must be on row boundary.
+  /// @brief Writes 8 bytes to the scratchpad.
+  /// @param[in] targetAddress
+  /// EEPROM memory address that this data will be copied to.
+  /// Must be on row boundary.
   /// @param[in] data Data to write to scratchpad.
   MaximInterface_EXPORT error_code writeScratchpad(Address targetAddress,
-                                                   const Scratchpad & data);
+                                                   Scratchpad::const_span data);
 
-  /// Reads contents of scratchpad.
+  /// @brief Reads contents of scratchpad.
   /// @param[out] data Data read from scratchpad.
   /// @param[out] esByte E/S byte read before scratchpad data.
-  MaximInterface_EXPORT error_code readScratchpad(Scratchpad & data,
+  MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span data,
                                                   uint_least8_t & esByte);
 
-  /// Copies contents of scratchpad to EEPROM.
+  /// @brief Copies contents of scratchpad to EEPROM.
   /// @param[in] targetAddress EEPROM memory address that scratchpad
   /// will be copied to. Must be on row boundary.
   /// @param[in] esByte E/S byte from preceding Read Scratchpad command.
@@ -104,13 +105,15 @@
   const Sleep * sleep;
 };
 
+/// @brief
 /// Writes data to EEPROM using Write Scratchpad, Read Scratchpad,
 /// and Copy Scratchpad commands.
+/// @param device Device to write.
 /// @param[in] targetAddress EEPROM memory address to start writing at.
 /// @param[in] data Data to write to EEPROM.
 MaximInterface_EXPORT error_code writeMemory(DS2431 & device,
                                              DS2431::Address targetAddress,
-                                             const DS2431::Scratchpad & data);
+                                             DS2431::Scratchpad::const_span data);
 
 inline error_code make_error_code(DS2431::ErrorValue e) {
   return error_code(e, DS2431::errorCategory());
--- a/Devices/DS2465.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS2465.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -37,24 +37,6 @@
 
 using namespace Sha256;
 
-enum MemoryAddress {
-  Scratchpad = 0x00,
-  CommandReg = 0x60,
-  StatusReg = 0x61,
-  ReadDataReg = 0x62,
-  MacReadoutReg = 0x63,
-  MemoryProtectionReg = 0x64,
-  ConfigReg = 0x67,
-  tRSTL_Reg = 0x68,
-  tMSP_Reg = 0x69,
-  tW0L_Reg = 0x6A,
-  tREC0_Reg = 0x6B,
-  RWPU_Reg = 0x6C,
-  tW1L_Reg = 0x6D,
-  UserMemoryPage0 = 0x80,
-  UserMemoryPage1 = 0xA0
-};
-
 /// Delay required after writing an EEPROM segment.
 static const int eepromSegmentWriteDelayMs = 10;
 /// Delay required after writing an EEPROM page such as the secret memory.
@@ -62,26 +44,12 @@
 /// Delay required for a SHA computation to complete.
 static const int shaComputationDelayMs = 2;
 
-/// DS2465 Commands
-enum Command {
-  DeviceResetCmd = 0xF0,
-  WriteDeviceConfigCmd = 0xD2,
-  OwResetCmd = 0xB4,
-  OwWriteByteCmd = 0xA5,
-  OwReadByteCmd = 0x96,
-  OwSingleBitCmd = 0x87,
-  OwTripletCmd = 0x78,
-  OwTransmitBlockCmd = 0x69,
-  OwReceiveBlockCmd = 0xE1,
-  CopyScratchpadCmd = 0x5A,
-  ComputeSlaveSecretCmd = 0x4B,
-  ComputeSlaveAuthMacCmd = 0x3C,
-  ComputeSlaveWriteMacCmd = 0x2D,
-  ComputeNextMasterSecretCmd = 0x1E,
-  SetProtectionCmd = 0x0F
-};
+static const uint_least8_t scratchpad = 0x00;
+static const uint_least8_t commandReg = 0x60;
 
-/// DS2465 Status Bits
+static const uint_least8_t owTransmitBlockCmd = 0x69;
+
+/// DS2465 Status bits.
 enum StatusBit {
   Status_1WB = 0x01,
   Status_PPD = 0x02,
@@ -93,7 +61,10 @@
   Status_DIR = 0x80
 };
 
-static const size_t maxBlockSize = 63;
+static const int maxBlockSize = 63;
+
+const int DS2465::memoryPages;
+const int DS2465::segmentsPerPage;
 
 error_code DS2465::initialize(Config config) {
   // reset DS2465
@@ -109,12 +80,10 @@
                                            PageRegion region) {
   error_code result = make_error_code(ArgumentOutOfRangeError);
   if (pageNum >= 0) {
-    uint_least8_t command[] = {
-        ComputeNextMasterSecretCmd,
-        static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region)
-                                        : 0xBF)};
-    result =
-        writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0]));
+    const uint_least8_t command[] = {
+        0x1E, static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region)
+                                              : 0xBF)};
+    result = writeMemory(commandReg, command);
   }
   return result;
 }
@@ -123,14 +92,12 @@
                                    int segmentNum) const {
   error_code result = make_error_code(ArgumentOutOfRangeError);
   if (pageNum >= 0 && segmentNum >= 0) {
-    uint_least8_t command[] = {
-        ComputeSlaveWriteMacCmd,
-        static_cast<uint_least8_t>((regwrite << 7) | (swap << 6) |
-                                   (pageNum << 4) | segmentNum)};
-    result =
-        writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0]));
+    const uint_least8_t command[] = {
+        0x2D, static_cast<uint_least8_t>((regwrite << 7) | (swap << 6) |
+                                         (pageNum << 4) | segmentNum)};
+    result = writeMemory(commandReg, command);
     if (!result) {
-      (*sleep)(shaComputationDelayMs);
+      sleep->invoke(shaComputationDelayMs);
     }
   }
   return result;
@@ -140,14 +107,12 @@
                                   PageRegion region) const {
   error_code result = make_error_code(ArgumentOutOfRangeError);
   if (pageNum >= 0) {
-    uint_least8_t command[] = {
-        ComputeSlaveAuthMacCmd,
-        static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region)
-                                        : 0xBF)};
-    result =
-        writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0]));
+    const uint_least8_t command[] = {
+        0x3C, static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region)
+                                              : 0xBF)};
+    result = writeMemory(commandReg, command);
     if (!result) {
-      (*sleep)(shaComputationDelayMs * 2);
+      sleep->invoke(shaComputationDelayMs * 2);
     }
   }
   return result;
@@ -157,65 +122,62 @@
                                       PageRegion region) {
   error_code result = make_error_code(ArgumentOutOfRangeError);
   if (pageNum >= 0) {
-    uint_least8_t command[] = {
-        ComputeSlaveSecretCmd,
-        static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region)
-                                        : 0xBF)};
-    result =
-        writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0]));
+    const uint_least8_t command[] = {
+        0x4B, static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region)
+                                              : 0xBF)};
+    result = writeMemory(commandReg, command);
     if (!result) {
-      (*sleep)(shaComputationDelayMs * 2);
+      sleep->invoke(shaComputationDelayMs * 2);
     }
   }
   return result;
 }
 
-error_code DS2465::readPage(int pageNum, Page & data) const {
+error_code DS2465::readPage(int pageNum, Page::span data) const {
   uint_least8_t addr;
   switch (pageNum) {
   case 0:
-    addr = UserMemoryPage0;
+    addr = 0x80;
     break;
   case 1:
-    addr = UserMemoryPage1;
+    addr = 0xA0;
     break;
   default:
     return make_error_code(ArgumentOutOfRangeError);
   }
-  return readMemory(addr, data.data(), data.size());
+  return readMemory(addr, data);
 }
 
-error_code DS2465::writePage(int pageNum, const Page & data) {
-  error_code result = writeMemory(Scratchpad, data.data(), data.size());
+error_code DS2465::writePage(int pageNum, Page::const_span data) {
+  error_code result = writeMemory(scratchpad, data);
   if (!result) {
     result = copyScratchpad(false, pageNum, false, 0);
   }
   if (!result) {
-    (*sleep)(eepromPageWriteDelayMs);
+    sleep->invoke(eepromPageWriteDelayMs);
   }
   return result;
 }
 
 error_code DS2465::writeSegment(int pageNum, int segmentNum,
-                                const Segment & data) {
-  error_code result = writeMemory(Scratchpad, data.data(), data.size());
+                                Segment::const_span data) {
+  error_code result = writeMemory(scratchpad, data);
   if (!result) {
     result = copyScratchpad(false, pageNum, true, segmentNum);
   }
   if (!result) {
-    (*sleep)(eepromSegmentWriteDelayMs);
+    sleep->invoke(eepromSegmentWriteDelayMs);
   }
   return result;
 }
 
-error_code DS2465::writeMasterSecret(const Hash & masterSecret) {
-  error_code result =
-      writeMemory(Scratchpad, masterSecret.data(), masterSecret.size());
+error_code DS2465::writeMasterSecret(Hash::const_span masterSecret) {
+  error_code result = writeMemory(scratchpad, masterSecret);
   if (!result) {
     result = copyScratchpad(true, 0, false, 0);
   }
   if (!result) {
-    (*sleep)(eepromPageWriteDelayMs);
+    sleep->invoke(eepromPageWriteDelayMs);
   }
   return result;
 }
@@ -224,13 +186,12 @@
                                   int segmentNum) {
   error_code result = make_error_code(ArgumentOutOfRangeError);
   if (pageNum >= 0 && segmentNum >= 0) {
-    uint_least8_t command[] = {
-        CopyScratchpadCmd,
+    const uint_least8_t command[] = {
+        0x5A,
         static_cast<uint_least8_t>(destSecret ? 0
                                               : (0x80 | (pageNum << 4) |
                                                  (notFull << 3) | segmentNum))};
-    result =
-        writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0]));
+    result = writeMemory(commandReg, command);
   }
   return result;
 }
@@ -245,9 +206,7 @@
     return error_code();
   }
   // Set the level
-  Config newConfig = curConfig;
-  newConfig.setSPU(level == StrongLevel);
-  return writeConfig(newConfig);
+  return writeConfig(Config(curConfig).setSPU(level == StrongLevel));
 }
 
 error_code DS2465::setLevel(Level newLevel) {
@@ -268,9 +227,7 @@
     return error_code();
   }
   // Set the speed
-  Config newConfig = curConfig;
-  newConfig.set1WS(newSpeed == OverdriveSpeed);
-  return writeConfig(newConfig);
+  return writeConfig(Config(curConfig).set1WS(newSpeed == OverdriveSpeed));
 }
 
 error_code DS2465::triplet(TripletData & data) {
@@ -282,9 +239,8 @@
   //  SS indicates byte containing search direction bit value in msbit
 
   const uint_least8_t command[] = {
-      OwTripletCmd, static_cast<uint_least8_t>(data.writeBit ? 0x80 : 0x00)};
-  error_code result =
-      writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0]));
+      0x78, static_cast<uint_least8_t>(data.writeBit ? 0x80 : 0x00)};
+  error_code result = writeMemory(commandReg, command);
   if (!result) {
     uint_least8_t status;
     result = pollBusy(&status);
@@ -298,54 +254,54 @@
   return result;
 }
 
-error_code DS2465::readBlock(uint_least8_t * recvBuf, size_t recvLen) {
+error_code DS2465::readBlock(span<uint_least8_t> recvBuf) {
   // 1-Wire Receive Block (Case A)
   //   S AD,0 [A] CommandReg [A] 1WRF [A] PR [A] P
   //  [] indicates from slave
   //  PR indicates byte containing parameter
 
   error_code result;
-  while ((recvLen > 0) && !result) {
+  span<uint_least8_t>::index_type recvIdx = 0;
+  while (recvIdx < recvBuf.size() && !result) {
     const uint_least8_t command[] = {
-        OwReceiveBlockCmd,
-        static_cast<uint_least8_t>(std::min(recvLen, maxBlockSize))};
-    result =
-        writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0]));
+        0xE1,
+        static_cast<uint_least8_t>(std::min<span<uint_least8_t>::index_type>(
+            recvBuf.size() - recvIdx, maxBlockSize))};
+    result = writeMemory(commandReg, command);
     if (!result) {
       result = pollBusy();
     }
     if (!result) {
-      result = readMemory(Scratchpad, recvBuf, command[1]);
+      result = readMemory(scratchpad, recvBuf.subspan(recvIdx, command[1]));
     }
-    recvBuf += command[1];
-    recvLen -= command[1];
+    recvIdx += command[1];
   }
   return result;
 }
 
-error_code DS2465::writeBlock(const uint_least8_t * sendBuf, size_t sendLen) {
+error_code DS2465::writeBlock(span<const uint_least8_t> sendBuf) {
   error_code result;
-  while ((sendLen > 0) && !result) {
+  span<const uint_least8_t>::index_type sendIdx = 0;
+  while (sendIdx < sendBuf.size() && !result) {
     const uint_least8_t command[] = {
-        OwTransmitBlockCmd,
-        static_cast<uint_least8_t>(std::min(sendLen, maxBlockSize))};
+        owTransmitBlockCmd, static_cast<uint_least8_t>(
+                                std::min<span<const uint_least8_t>::index_type>(
+                                    sendBuf.size() - sendIdx, maxBlockSize))};
 
     // prefill scratchpad with required data
-    result = writeMemory(Scratchpad, sendBuf, command[1]);
+    result = writeMemory(scratchpad, sendBuf.subspan(sendIdx, command[1]));
 
     // 1-Wire Transmit Block (Case A)
     //   S AD,0 [A] CommandReg [A] 1WTB [A] PR [A] P
     //  [] indicates from slave
     //  PR indicates byte containing parameter
     if (!result) {
-      result = writeMemory(CommandReg, command,
-                           sizeof(command) / sizeof(command[0]));
+      result = writeMemory(commandReg, command);
     }
     if (!result) {
       result = pollBusy();
     }
-    sendBuf += command[1];
-    sendLen -= command[1];
+    sendIdx += command[1];
   }
   return result;
 }
@@ -356,9 +312,8 @@
   //  [] indicates from slave
   //  PR indicates byte containing parameter
 
-  const uint_least8_t command[] = {OwTransmitBlockCmd, 0xFF};
-  error_code result =
-      writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0]));
+  const uint_least8_t command[] = {owTransmitBlockCmd, 0xFF};
+  error_code result = writeMemory(commandReg, command);
   if (!result) {
     result = pollBusy();
   }
@@ -381,21 +336,18 @@
     return result;
   }
 
-  uint_least8_t buf = OwReadByteCmd;
-  result = writeMemory(CommandReg, &buf, 1);
-
-  if (!result) {
-    result = pollBusy();
+  const uint_least8_t command = 0x96;
+  result = writeMemory(commandReg, make_span(&command, 1));
+  if (result) {
+    return result;
   }
 
-  if (!result) {
-    result = readMemory(ReadDataReg, &buf, 1);
+  result = pollBusy();
+  if (result) {
+    return result;
   }
 
-  if (!result) {
-    recvByte = buf;
-  }
-
+  result = readMemory(0x62, make_span(&recvByte, 1));
   return result;
 }
 
@@ -413,14 +365,13 @@
     return result;
   }
 
-  const uint_least8_t command[] = {OwWriteByteCmd, sendByte};
-
-  result =
-      writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0]));
-  if (!result) {
-    result = pollBusy();
+  const uint_least8_t command[] = {0xA5, sendByte};
+  result = writeMemory(commandReg, command);
+  if (result) {
+    return result;
   }
 
+  result = pollBusy();
   return result;
 }
 
@@ -439,25 +390,22 @@
   }
 
   const uint_least8_t command[] = {
-      OwSingleBitCmd, static_cast<uint_least8_t>(sendRecvBit ? 0x80 : 0x00)};
-  uint_least8_t status;
-
-  result =
-      writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0]));
-
-  if (!result) {
-    result = pollBusy(&status);
+      0x87, static_cast<uint_least8_t>(sendRecvBit ? 0x80 : 0x00)};
+  result = writeMemory(commandReg, command);
+  if (result) {
+    return result;
   }
 
+  uint_least8_t status;
+  result = pollBusy(&status);
   if (!result) {
     sendRecvBit = ((status & Status_SBR) == Status_SBR);
   }
-
   return result;
 }
 
-error_code DS2465::writeMemory(uint_least8_t addr, const uint_least8_t * buf,
-                               size_t bufLen) const {
+error_code DS2465::writeMemory(uint_least8_t addr,
+                               span<const uint_least8_t> buf) const {
   // Write SRAM (Case A)
   //   S AD,0 [A] VSA [A] DD [A]  P
   //                      \-----/
@@ -466,27 +414,27 @@
   //  VSA valid SRAM memory address
   //  DD memory data to write
 
-  error_code result = i2cMaster->start(i2cAddress_);
+  error_code result = master->start(address_);
   if (result) {
-    i2cMaster->stop();
+    master->stop();
     return result;
   }
-  result = i2cMaster->writeByte(addr);
+  result = master->writeByte(addr);
   if (result) {
-    i2cMaster->stop();
+    master->stop();
     return result;
   }
-  result = i2cMaster->writeBlock(buf, bufLen);
+  result = master->writeBlock(buf);
   if (result) {
-    i2cMaster->stop();
+    master->stop();
     return result;
   }
-  result = i2cMaster->stop();
+  result = master->stop();
   return result;
 }
 
-error_code DS2465::readMemory(uint_least8_t addr, uint_least8_t * buf,
-                              size_t bufLen) const {
+error_code DS2465::readMemory(uint_least8_t addr,
+                              span<uint_least8_t> buf) const {
   // Read (Case A)
   //   S AD,0 [A] MA [A] Sr AD,1 [A] [DD] A [DD] A\ P
   //                                 \-----/
@@ -495,40 +443,42 @@
   //  MA memory address
   //  DD memory data read
 
-  error_code result = i2cMaster->start(i2cAddress_);
+  error_code result = master->start(address_);
   if (result) {
-    i2cMaster->stop();
+    master->stop();
     return result;
   }
-  result = i2cMaster->writeByte(addr);
+  result = master->writeByte(addr);
   if (result) {
-    i2cMaster->stop();
+    master->stop();
     return result;
   }
-  result = readMemory(buf, bufLen);
+  result = readMemory(buf);
   return result;
 }
 
-error_code DS2465::readMemory(uint_least8_t * buf, size_t bufLen) const {
-  error_code result = i2cMaster->start(i2cAddress_ | 1);
+error_code DS2465::readMemory(span<uint_least8_t> buf) const {
+  error_code result = master->start(address_ | 1);
   if (result) {
-    i2cMaster->stop();
+    master->stop();
     return result;
   }
-  result = i2cMaster->readBlock(I2CMaster::Nack, buf, bufLen);
+  result = master->readBlock(I2CMaster::Nack, buf);
   if (result) {
-    i2cMaster->stop();
+    master->stop();
     return result;
   }
-  result = i2cMaster->stop();
+  result = master->stop();
   return result;
 }
 
 error_code DS2465::writeConfig(Config config) {
-  uint_least8_t configBuf = ((config.readByte() ^ 0xF) << 4) | config.readByte();
-  error_code result = writeMemory(ConfigReg, &configBuf, 1);
+  const uint_least8_t configReg = 0x67;
+  uint_least8_t configBuf =
+      ((config.readByte() ^ 0xF) << 4) | config.readByte();
+  error_code result = writeMemory(configReg, make_span(&configBuf, 1));
   if (!result) {
-    result = readMemory(ConfigReg, &configBuf, 1);
+    result = readMemory(configReg, make_span(&configBuf, 1));
   }
   if (!result) {
     if (configBuf != config.readByte())
@@ -549,29 +499,29 @@
   switch (param) {
   case tRSTL_STD:
   case tRSTL_OD:
-    addr = tRSTL_Reg;
+    addr = 0x68;
     break;
   case tMSP_STD:
   case tMSP_OD:
-    addr = tMSP_Reg;
+    addr = 0x69;
     break;
   case tW0L_STD:
   case tW0L_OD:
-    addr = tW0L_Reg;
+    addr = 0x6A;
     break;
   case tREC0:
-    addr = tREC0_Reg;
+    addr = 0x6B;
     break;
   case RWPU:
-    addr = RWPU_Reg;
+    addr = 0x6C;
     break;
   case tW1L_OD:
-    addr = tW1L_Reg;
+    addr = 0x6D;
     break;
   }
 
   uint_least8_t data;
-  error_code result = readMemory(addr, &data, 1);
+  error_code result = readMemory(addr, make_span(&data, 1));
   if (result) {
     return result;
   }
@@ -584,7 +534,7 @@
   }
 
   if (newData != data) {
-    result = writeMemory(addr, &newData, 1);
+    result = writeMemory(addr, make_span(&newData, 1));
   }
   return result;
 }
@@ -595,7 +545,7 @@
   int pollCount = 0;
   uint_least8_t status;
   do {
-    error_code result = readMemory(&status, 1);
+    error_code result = readMemory(make_span(&status, 1));
     if (result) {
       return result;
     }
@@ -617,8 +567,8 @@
   //                       Repeat until 1WB bit has changed to 0
   //  [] indicates from slave
 
-  uint_least8_t buf = OwResetCmd;
-  error_code result = writeMemory(CommandReg, &buf, 1);
+  uint_least8_t buf = 0xB4;
+  error_code result = writeMemory(commandReg, make_span(&buf, 1));
 
   if (!result) {
     result = pollBusy(&buf);
@@ -627,8 +577,7 @@
   if (!result) {
     if ((buf & Status_SD) == Status_SD) {
       result = make_error_code(ShortDetectedError);
-    }
-    else if ((buf & Status_PPD) != Status_PPD) {
+    } else if ((buf & Status_PPD) != Status_PPD) {
       result = make_error_code(NoSlaveError);
     }
   }
@@ -642,11 +591,11 @@
   //  [] indicates from slave
   //  SS status byte to read to verify state
 
-  uint_least8_t buf = DeviceResetCmd;
-  error_code result = writeMemory(CommandReg, &buf, 1);
+  uint_least8_t buf = 0xF0;
+  error_code result = writeMemory(commandReg, make_span(&buf, 1));
 
   if (!result) {
-    result = readMemory(&buf, 1);
+    result = readMemory(make_span(&buf, 1));
   }
 
   if (!result) {
@@ -662,42 +611,44 @@
   return result;
 }
 
-error_code DS2465::computeNextMasterSecret(const SlaveSecretData & data) {
-  error_code result = writeMemory(Scratchpad, data.data(), data.size());
+error_code
+DS2465::computeNextMasterSecret(AuthenticationData::const_span data) {
+  error_code result = writeMemory(scratchpad, data);
   if (!result) {
     result = computeNextMasterSecret(false, 0, FullPage);
   }
   return result;
 }
 
-error_code DS2465::computeNextMasterSecretWithSwap(const SlaveSecretData & data,
-                                                   int pageNum,
-                                                   PageRegion region) {
-  error_code result = writeMemory(Scratchpad, data.data(), data.size());
+error_code
+DS2465::computeNextMasterSecretWithSwap(AuthenticationData::const_span data,
+                                        int pageNum, PageRegion region) {
+  error_code result = writeMemory(scratchpad, data);
   if (!result) {
     result = computeNextMasterSecret(true, pageNum, region);
   }
   return result;
 }
 
-error_code DS2465::computeWriteMac(const WriteMacData & data) const {
-  error_code result = writeMemory(Scratchpad, data.data(), data.size());
+error_code DS2465::computeWriteMac(WriteMacData::const_span data) const {
+  error_code result = writeMemory(scratchpad, data);
   if (!result) {
     result = computeWriteMac(false, false, 0, 0);
   }
   return result;
 }
 
-error_code DS2465::computeWriteMac(const WriteMacData & data,
-                                   Hash & mac) const {
+error_code DS2465::computeWriteMac(WriteMacData::const_span data,
+                                   Hash::span mac) const {
   error_code result = computeWriteMac(data);
   if (!result) {
-    result = readMemory(mac.data(), mac.size());
+    result = readMemory(mac);
   }
   return result;
 }
 
-error_code DS2465::computeAndTransmitWriteMac(const WriteMacData & data) const {
+error_code
+DS2465::computeAndTransmitWriteMac(WriteMacData::const_span data) const {
   error_code result = computeWriteMac(data);
   if (!result) {
     result = writeMacBlock();
@@ -705,28 +656,28 @@
   return result;
 }
 
-error_code DS2465::computeWriteMacWithSwap(const WriteMacData & data,
+error_code DS2465::computeWriteMacWithSwap(WriteMacData::const_span data,
                                            int pageNum, int segmentNum) const {
-  error_code result = writeMemory(Scratchpad, data.data(), data.size());
+  error_code result = writeMemory(scratchpad, data);
   if (!result) {
     result = computeWriteMac(false, true, pageNum, segmentNum);
   }
   return result;
 }
 
-error_code DS2465::computeWriteMacWithSwap(const WriteMacData & data,
+error_code DS2465::computeWriteMacWithSwap(WriteMacData::const_span data,
                                            int pageNum, int segmentNum,
-                                           Hash & mac) const {
+                                           Hash::span mac) const {
   error_code result = computeWriteMacWithSwap(data, pageNum, segmentNum);
   if (!result) {
-    result = readMemory(mac.data(), mac.size());
+    result = readMemory(mac);
   }
   return result;
 }
 
-error_code DS2465::computeAndTransmitWriteMacWithSwap(const WriteMacData & data,
-                                                      int pageNum,
-                                                      int segmentNum) const {
+error_code
+DS2465::computeAndTransmitWriteMacWithSwap(WriteMacData::const_span data,
+                                           int pageNum, int segmentNum) const {
   error_code result = computeWriteMacWithSwap(data, pageNum, segmentNum);
   if (!result) {
     result = writeMacBlock();
@@ -734,40 +685,43 @@
   return result;
 }
 
-error_code DS2465::computeSlaveSecret(const SlaveSecretData & data) {
-  error_code result = writeMemory(Scratchpad, data.data(), data.size());
+error_code DS2465::computeSlaveSecret(AuthenticationData::const_span data) {
+  error_code result = writeMemory(scratchpad, data);
   if (!result) {
     result = computeSlaveSecret(false, 0, FullPage);
   }
   return result;
 }
 
-error_code DS2465::computeSlaveSecretWithSwap(const SlaveSecretData & data,
-                                              int pageNum, PageRegion region) {
-  error_code result = writeMemory(Scratchpad, data.data(), data.size());
+error_code
+DS2465::computeSlaveSecretWithSwap(AuthenticationData::const_span data,
+                                   int pageNum, PageRegion region) {
+  error_code result = writeMemory(scratchpad, data);
   if (!result) {
     result = computeSlaveSecret(true, pageNum, region);
   }
   return result;
 }
 
-error_code DS2465::computeAuthMac(const AuthMacData & data) const {
-  error_code result = writeMemory(Scratchpad, data.data(), data.size());
+error_code DS2465::computeAuthMac(AuthenticationData::const_span data) const {
+  error_code result = writeMemory(scratchpad, data);
   if (!result) {
     result = computeAuthMac(false, 0, FullPage);
   }
   return result;
 }
 
-error_code DS2465::computeAuthMac(const AuthMacData & data, Hash & mac) const {
+error_code DS2465::computeAuthMac(AuthenticationData::const_span data,
+                                  Hash::span mac) const {
   error_code result = computeAuthMac(data);
   if (!result) {
-    result = readMemory(mac.data(), mac.size());
+    result = readMemory(mac);
   }
   return result;
 }
 
-error_code DS2465::computeAndTransmitAuthMac(const AuthMacData & data) const {
+error_code
+DS2465::computeAndTransmitAuthMac(AuthenticationData::const_span data) const {
   error_code result = computeAuthMac(data);
   if (!result) {
     result = writeMacBlock();
@@ -775,27 +729,28 @@
   return result;
 }
 
-error_code DS2465::computeAuthMacWithSwap(const AuthMacData & data, int pageNum,
+error_code DS2465::computeAuthMacWithSwap(AuthenticationData::const_span data,
+                                          int pageNum,
                                           PageRegion region) const {
-  error_code result = writeMemory(Scratchpad, data.data(), data.size());
+  error_code result = writeMemory(scratchpad, data);
   if (!result) {
     result = computeAuthMac(true, pageNum, region);
   }
   return result;
 }
 
-error_code DS2465::computeAuthMacWithSwap(const AuthMacData & data, int pageNum,
-                                          PageRegion region, Hash & mac) const {
+error_code DS2465::computeAuthMacWithSwap(AuthenticationData::const_span data,
+                                          int pageNum, PageRegion region,
+                                          Hash::span mac) const {
   error_code result = computeAuthMacWithSwap(data, pageNum, region);
   if (!result) {
-    result = readMemory(mac.data(), mac.size());
+    result = readMemory(mac);
   }
   return result;
 }
 
-error_code DS2465::computeAndTransmitAuthMacWithSwap(const AuthMacData & data,
-                                                     int pageNum,
-                                                     PageRegion region) const {
+error_code DS2465::computeAndTransmitAuthMacWithSwap(
+    AuthenticationData::const_span data, int pageNum, PageRegion region) const {
   error_code result = computeAuthMacWithSwap(data, pageNum, region);
   if (!result) {
     result = writeMacBlock();
--- a/Devices/DS2465.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS2465.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -36,6 +36,7 @@
 #include <MaximInterface/Links/I2CMaster.hpp>
 #include <MaximInterface/Links/OneWireMaster.hpp>
 #include <MaximInterface/Links/Sleep.hpp>
+#include <MaximInterface/Utilities/array_span.hpp>
 #include <MaximInterface/Utilities/Export.h>
 #include <MaximInterface/Utilities/Sha256.hpp>
 
@@ -46,7 +47,7 @@
 public:
   enum ErrorValue { HardwareError = 1, ArgumentOutOfRangeError };
 
-  /// 1-Wire port adjustment parameters.
+  /// @brief 1-Wire port adjustment parameters.
   /// @note See datasheet page 13.
   enum PortParameter {
     tRSTL_STD,
@@ -64,13 +65,13 @@
   enum PageRegion { FullPage = 0x03, FirstHalf = 0x01, SecondHalf = 0x02 };
 
   /// Holds the contents of a device memory segment.
-  typedef array<uint_least8_t, 4> Segment;
+  typedef array_span<uint_least8_t, 4> Segment;
 
   /// Holds the contents of a device memory page.
-  typedef array<uint_least8_t, 32> Page;
+  typedef array_span<uint_least8_t, 32> Page;
 
   static const int memoryPages = 2;
-  static const int segmentsPerPage = Page::csize / Segment::csize;
+  static const int segmentsPerPage = Page::size / Segment::size;
 
   /// Represents a DS2465 configuration.
   class Config {
@@ -79,52 +80,80 @@
     explicit Config(uint_least8_t readByte = optionAPU)
         : readByte_(readByte & 0xF) {}
 
+    /// @name 1WS
+    /// @brief 1-Wire Speed
     /// @{
-    /// 1-Wire Speed
+    
+    /// Get 1WS bit.
     bool get1WS() const { return (readByte_ & option1WS) == option1WS; }
-    void set1WS(bool new1WS) {
+    
+    /// Set 1WS bit.
+    Config & set1WS(bool new1WS) {
       if (new1WS) {
         readByte_ |= option1WS;
       } else {
         readByte_ &= ~option1WS;
       }
+      return *this;
     }
+    
     /// @}
 
+    /// @name SPU
+    /// @brief Strong Pullup
     /// @{
-    /// Strong Pullup
+    
+    /// Get SPU bit.
     bool getSPU() const { return (readByte_ & optionSPU) == optionSPU; }
-    void setSPU(bool newSPU) {
+    
+    /// Set SPU bit.
+    Config & setSPU(bool newSPU) {
       if (newSPU) {
         readByte_ |= optionSPU;
       } else {
         readByte_ &= ~optionSPU;
       }
+      return *this;
     }
+    
     /// @}
 
+    /// @name PDN
+    /// @brief 1-Wire Power Down
     /// @{
-    /// 1-Wire Power Down
+    
+    /// Get PDN bit.
     bool getPDN() const { return (readByte_ & optionPDN) == optionPDN; }
-    void setPDN(bool newPDN) {
+    
+    /// Set PDN bit.
+    Config & setPDN(bool newPDN) {
       if (newPDN) {
         readByte_ |= optionPDN;
       } else {
         readByte_ &= ~optionPDN;
       }
+      return *this;
     }
+    
     /// @}
 
+    /// @name APU
+    /// @brief Active Pullup
     /// @{
-    /// Active Pullup
+    
+    /// Get APU bit.
     bool getAPU() const { return (readByte_ & optionAPU) == optionAPU; }
-    void setAPU(bool newAPU) {
+    
+    /// Set APU bit.
+    Config & setAPU(bool newAPU) {
       if (newAPU) {
         readByte_ |= optionAPU;
       } else {
         readByte_ &= ~optionAPU;
       }
+      return *this;
     }
+    
     /// @}
 
     /// Byte representation that is read from the DS2465.
@@ -143,196 +172,213 @@
   // affect the state of the 1-Wire bus. Read pointer, scratchpad, MAC output
   // register, and command register on the DS2465 are considered mutable.
 
-  DS2465(const Sleep & sleep, I2CMaster & i2cMaster,
-         uint_least8_t i2cAddress = 0x30)
-      : sleep(&sleep), i2cMaster(&i2cMaster), i2cAddress_(i2cAddress & 0xFE) {}
+  DS2465(Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x30)
+      : sleep(&sleep), master(&master), address_(address & 0xFE) {}
 
-  void setSleep(const Sleep & sleep) { this->sleep = &sleep; }
-  void setI2CMaster(I2CMaster & i2cMaster) { this->i2cMaster = &i2cMaster; }
-  uint_least8_t i2cAddress() const { return i2cAddress_; }
-  void setI2CAddress(uint_least8_t i2cAddress) {
-    this->i2cAddress_ = (i2cAddress & 0xFE);
-  }
+  void setSleep(Sleep & sleep) { this->sleep = &sleep; }
+  
+  void setMaster(I2CMaster & master) { this->master = &master; }
+  
+  uint_least8_t address() const { return address_; }
+  
+  void setAddress(uint_least8_t address) { address_ = address & 0xFE; }
 
   /// Initialize hardware for use.
   MaximInterface_EXPORT error_code initialize(Config config = Config());
 
-  /// Write a new configuration to the DS2465.
+  /// @brief Write a new configuration to the DS2465.
   /// @param[in] config New configuration to write.
   MaximInterface_EXPORT error_code writeConfig(Config config);
 
-  /// Write a new port configuration parameter to the DS2465.
+  /// @brief Write a new port configuration parameter to the DS2465.
   /// @param[in] param Parameter to adjust.
-  /// @param[in] val New parameter value to set. Consult datasheet for value
-  /// mappings.
+  /// @param[in] val
+  /// New parameter value to set. Consult datasheet for value mappings.
   MaximInterface_EXPORT error_code writePortParameter(PortParameter param,
                                                       int val);
 
   // 1-Wire Master Commands
 
   MaximInterface_EXPORT virtual error_code reset();
+  
   MaximInterface_EXPORT virtual error_code touchBitSetLevel(bool & sendRecvBit,
                                                             Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
   readByteSetLevel(uint_least8_t & recvByte, Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
   writeByteSetLevel(uint_least8_t sendByte, Level afterLevel);
-  MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * recvBuf,
-                                                     size_t recvLen);
+  
+  MaximInterface_EXPORT virtual error_code
+  readBlock(span<uint_least8_t> recvBuf);
+  
   MaximInterface_EXPORT virtual error_code
-  writeBlock(const uint_least8_t * sendBuf, size_t sendLen);
+  writeBlock(span<const uint_least8_t> sendBuf);
+  
   MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed);
-  /// @note The DS2465 only supports enabling strong pullup following a 1-Wire
-  /// read or write operation.
+  
+  /// @copydoc OneWireMaster::setLevel
+  /// @note
+  /// The DS2465 only supports enabling strong pullup following a 1-Wire read or
+  /// write operation.
   MaximInterface_EXPORT virtual error_code setLevel(Level newLevel);
+  
   MaximInterface_EXPORT virtual error_code triplet(TripletData & data);
 
   // DS2465 Coprocessor Commands
-  
-  /// Read data from an EEPROM memory page.
+
+  /// @brief Read data from an EEPROM memory page.
   /// @param pageNum Page number to read from.
-  MaximInterface_EXPORT error_code readPage(int pageNum, Page & data) const;
+  /// @param[out] data Data that was read.
+  MaximInterface_EXPORT error_code readPage(int pageNum, Page::span data) const;
 
-  /// Write data to an EEPROM memory page.
+  /// @brief Write data to an EEPROM memory page.
   /// @param pageNum Page number to copy to.
-  MaximInterface_EXPORT error_code writePage(int pageNum, const Page & data);
+  /// @param data Data to write.
+  MaximInterface_EXPORT error_code writePage(int pageNum,
+                                             Page::const_span data);
 
-  /// Write data to an EEPROM memory segment.
+  /// @brief Write data to an EEPROM memory segment.
   /// @param pageNum Page number to copy to.
   /// @param segmentNum Segment number to copy to.
+  /// @param data Data to write.
   MaximInterface_EXPORT error_code writeSegment(int pageNum, int segmentNum,
-                                                const Segment & data);
+                                                Segment::const_span data);
 
   /// Write data to the secret EEPROM memory page.
   MaximInterface_EXPORT error_code
-  writeMasterSecret(const Sha256::Hash & masterSecret);
+  writeMasterSecret(Sha256::Hash::const_span masterSecret);
 
-  /// Compute Next Master Secret.
+  /// @brief Compute Next Master Secret.
   /// @param data Combined data fields for computation.
   MaximInterface_EXPORT error_code
-  computeNextMasterSecret(const Sha256::SlaveSecretData & data);
+  computeNextMasterSecret(Sha256::AuthenticationData::const_span data);
 
-  /// Compute Next Master Secret with page swapping.
+  /// @brief Compute Next Master Secret with page swapping.
   /// @param data Combined data fields for computation.
   /// @param pageNum Page number to swap in.
   /// @param region Region of the page to swap in.
-  MaximInterface_EXPORT error_code computeNextMasterSecretWithSwap(
-      const Sha256::SlaveSecretData & data, int pageNum, PageRegion region);
+  MaximInterface_EXPORT error_code
+  computeNextMasterSecretWithSwap(Sha256::AuthenticationData::const_span data,
+                                  int pageNum, PageRegion region);
 
-  /// Compute Write MAC.
+  /// @brief Compute Write MAC.
   /// @param data Combined data fields for computation.
   /// @param[out] mac Computed Write MAC.
-  MaximInterface_EXPORT error_code
-  computeWriteMac(const Sha256::WriteMacData & data, Sha256::Hash & mac) const;
+  MaximInterface_EXPORT error_code computeWriteMac(
+      Sha256::WriteMacData::const_span data, Sha256::Hash::span mac) const;
 
-  /// Compute Write MAC.
+  /// @brief Compute Write MAC.
   /// @param data Combined data fields for computation.
   MaximInterface_EXPORT error_code
-  computeAndTransmitWriteMac(const Sha256::WriteMacData & data) const;
+  computeAndTransmitWriteMac(Sha256::WriteMacData::const_span data) const;
 
-  /// Compute Write MAC with page swapping.
+  /// @brief Compute Write MAC with page swapping.
   /// @param data Combined data fields for computation.
   /// @param pageNum Page number to swap in.
   /// @param segmentNum Segment number to swap in.
   /// @param[out] mac Computed Write MAC.
   MaximInterface_EXPORT error_code
-  computeWriteMacWithSwap(const Sha256::WriteMacData & data, int pageNum,
-                          int segmentNum, Sha256::Hash & mac) const;
+  computeWriteMacWithSwap(Sha256::WriteMacData::const_span data, int pageNum,
+                          int segmentNum, Sha256::Hash::span mac) const;
 
-  /// Compute Write MAC with page swapping.
+  /// @brief Compute Write MAC with page swapping.
   /// @param data Combined data fields for computation.
   /// @param pageNum Page number to swap in.
   /// @param segmentNum Segment number to swap in.
   MaximInterface_EXPORT error_code computeAndTransmitWriteMacWithSwap(
-      const Sha256::WriteMacData & data, int pageNum, int segmentNum) const;
+      Sha256::WriteMacData::const_span data, int pageNum, int segmentNum) const;
 
-  /// Compute Slave Secret (S-Secret).
+  /// @brief Compute Slave Secret (S-Secret).
   /// @param data Combined data fields for computation.
   MaximInterface_EXPORT error_code
-  computeSlaveSecret(const Sha256::SlaveSecretData & data);
+  computeSlaveSecret(Sha256::AuthenticationData::const_span data);
 
-  /// Compute Slave Secret (S-Secret) with page swapping.
+  /// @brief Compute Slave Secret (S-Secret) with page swapping.
   /// @param data Combined data fields for computation.
   /// @param pageNum Page number to swap in.
   /// @param region Region of the page to swap in.
-  MaximInterface_EXPORT error_code computeSlaveSecretWithSwap(
-      const Sha256::SlaveSecretData & data, int pageNum, PageRegion region);
+  MaximInterface_EXPORT error_code
+  computeSlaveSecretWithSwap(Sha256::AuthenticationData::const_span data,
+                             int pageNum, PageRegion region);
 
-  /// Compute Authentication MAC.
+  /// @brief Compute Authentication MAC.
   /// @param data Combined data fields for computation.
   /// @param[out] mac Computed Auth MAC.
   MaximInterface_EXPORT error_code
-  computeAuthMac(const Sha256::AuthMacData & data, Sha256::Hash & mac) const;
+  computeAuthMac(Sha256::AuthenticationData::const_span data,
+                 Sha256::Hash::span mac) const;
 
-  /// Compute Authentication MAC.
+  /// @brief Compute Authentication MAC.
   /// @param data Combined data fields for computation.
   MaximInterface_EXPORT error_code
-  computeAndTransmitAuthMac(const Sha256::AuthMacData & data) const;
+  computeAndTransmitAuthMac(Sha256::AuthenticationData::const_span data) const;
 
-  /// Compute Authentication MAC with page swapping.
+  /// @brief Compute Authentication MAC with page swapping.
   /// @param data Combined data fields for computation.
   /// @param pageNum Page number to swap in.
   /// @param region Region of the page to swap in.
   /// @param[out] mac Computed Auth MAC.
-  MaximInterface_EXPORT error_code
-  computeAuthMacWithSwap(const Sha256::AuthMacData & data, int pageNum,
-                         PageRegion region, Sha256::Hash & mac) const;
+  MaximInterface_EXPORT error_code computeAuthMacWithSwap(
+      Sha256::AuthenticationData::const_span data, int pageNum,
+      PageRegion region, Sha256::Hash::span mac) const;
 
-  /// Compute Authentication MAC with page swapping.
+  /// @brief Compute Authentication MAC with page swapping.
   /// @param data Combined data fields for computation.
   /// @param pageNum Page number to swap in.
   /// @param region Region of the page to swap in.
-  MaximInterface_EXPORT error_code computeAndTransmitAuthMacWithSwap(
-      const Sha256::AuthMacData & data, int pageNum, PageRegion region) const;
+  MaximInterface_EXPORT error_code
+  computeAndTransmitAuthMacWithSwap(Sha256::AuthenticationData::const_span data,
+                                    int pageNum, PageRegion region) const;
 
   MaximInterface_EXPORT static const error_category & errorCategory();
 
 private:
   const Sleep * sleep;
-  I2CMaster * i2cMaster;
-  uint_least8_t i2cAddress_;
+  I2CMaster * master;
+  uint_least8_t address_;
   Config curConfig;
 
-  /// Performs a soft reset on the DS2465.
+  /// @brief Performs a soft reset on the DS2465.
   /// @note This is not a 1-Wire Reset.
   error_code resetDevice();
 
-  /// Polls the DS2465 status waiting for the 1-Wire Busy bit (1WB) to be cleared.
+  /// @brief
+  /// Polls the DS2465 status waiting for the 1-Wire Busy bit (1WB) to be
+  /// cleared.
   /// @param[out] pStatus Optionally retrive the status byte when 1WB cleared.
   /// @returns Success or TimeoutError if poll limit reached.
   error_code pollBusy(uint_least8_t * pStatus = NULL) const;
 
-  /// Ensure that the desired 1-Wire level is set in the configuration.
+  /// @brief Ensure that the desired 1-Wire level is set in the configuration.
   /// @param level Desired 1-Wire level.
   error_code configureLevel(Level level);
 
-  /// Const since only for internal use.
-  error_code writeMemory(uint_least8_t addr, const uint_least8_t * buf,
-                         size_t bufLen) const;
+  /// @note Const since only for internal use.
+  error_code writeMemory(uint_least8_t addr,
+                         span<const uint_least8_t> buf) const;
 
-  /// Read memory from the DS2465.
+  /// @brief Read memory from the DS2465.
   /// @param addr Address to begin reading from.
   /// @param[out] buf Buffer to hold read data.
-  /// @param bufLen Length of buffer, buf, and number of bytes to read.
-  error_code readMemory(uint_least8_t addr, uint_least8_t * buf,
-                        size_t bufLen) const;
+  error_code readMemory(uint_least8_t addr, span<uint_least8_t> buf) const;
 
-  /// Read memory from the DS2465 at the current pointer.
+  /// @brief Read memory from the DS2465 at the current pointer.
   /// @param[out] buf Buffer to hold read data.
-  /// @param bufLen Length of buffer, buf, and number of bytes to read.
-  error_code readMemory(uint_least8_t * buf, size_t bufLen) const;
+  error_code readMemory(span<uint_least8_t> buf) const;
 
   /// Write the last computed MAC to the 1-Wire bus.
   error_code writeMacBlock() const;
 
-  error_code computeWriteMac(const Sha256::WriteMacData & data) const;
+  error_code computeWriteMac(Sha256::WriteMacData::const_span data) const;
 
-  error_code computeWriteMacWithSwap(const Sha256::WriteMacData & data,
+  error_code computeWriteMacWithSwap(Sha256::WriteMacData::const_span data,
                                      int pageNum, int segmentNum) const;
 
-  error_code computeAuthMac(const Sha256::AuthMacData & data) const;
+  error_code computeAuthMac(Sha256::AuthenticationData::const_span data) const;
 
-  error_code computeAuthMacWithSwap(const Sha256::AuthMacData & data,
+  error_code computeAuthMacWithSwap(Sha256::AuthenticationData::const_span data,
                                     int pageNum, PageRegion region) const;
 
   // Legacy implementations
--- a/Devices/DS2480B.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS2480B.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -160,516 +160,23 @@
 #define PARMSET_PullUp3p0us 0x0C
 #define PARMSET_PullUp3p5us 0x0E
 
+// Baud rate bits
+#define PARMSET_9600 0x00
+#define PARMSET_19200 0x02
+#define PARMSET_57600 0x04
+#define PARMSET_115200 0x06
+
 // DS2480B program voltage available
 #define DS2480BPROG_MASK 0x20
 
 namespace MaximInterface {
 
 error_code DS2480B::initialize() {
-  // reset modes
   level = NormalLevel;
-  baud = Baud9600bps;
   mode = MODSEL_COMMAND;
-  speed = SPEEDSEL_FLEX;
-
-  // set the baud rate to 9600
-  error_code result = setComBaud(baud);
-  if (result) {
-    return result;
-  }
-
-  // send a break to reset the DS2480B
-  result = breakCom();
-  if (result) {
-    return result;
-  }
-
-  // delay to let line settle
-  (*sleep)(2);
-
-  // flush the buffers
-  result = uart->clearReadBuffer();
-  if (result) {
-    return result;
-  }
-
-  // send the timing byte
-  uint_least8_t packet[5];
-  packet[0] = 0xC1;
-  result = uart->writeBlock(packet, 1);
-  if (result) {
-    return result;
-  }
-
-  // delay to let line settle
-  (*sleep)(2);
-
-  // set the FLEX configuration parameters
-  // default PDSRC = 1.37Vus
-  int packetLen = 0;
-  packet[packetLen++] = CMD_CONFIG | PARMSEL_SLEW | PARMSET_Slew1p37Vus;
-  // default W1LT = 10us
-  packet[packetLen++] = CMD_CONFIG | PARMSEL_WRITE1LOW | PARMSET_Write10us;
-  // default DSO/WORT = 8us
-  packet[packetLen++] = CMD_CONFIG | PARMSEL_SAMPLEOFFSET | PARMSET_SampOff8us;
-
-  // construct the command to read the baud rate (to test command block)
-  packet[packetLen++] = CMD_CONFIG | PARMSEL_PARMREAD | (PARMSEL_BAUDRATE >> 3);
-
-  // also do 1 bit operation (to test 1-Wire block)
-  packet[packetLen++] = CMD_COMM | FUNCTSEL_BIT | baud | BITPOL_ONE;
-
-  // flush the buffers
-  result = uart->clearReadBuffer();
-  if (result) {
-    return result;
-  }
-
-  // send the packet
-  result = uart->writeBlock(packet, packetLen);
-  if (result) {
-    return result;
-  }
-
-  // read back the response
-  result = uart->readBlock(packet, sizeof(packet) / sizeof(packet[0]));
-  if (result) {
-    return result;
-  }
-
-  // look at the baud rate and bit operation
-  // to see if the response makes sense
-  if (!(((packet[3] & 0xF1) == 0x00) && ((packet[3] & 0x0E) == baud) &&
-        ((packet[4] & 0xF0) == 0x90) && ((packet[4] & 0x0C) == baud))) {
-    result = make_error_code(HardwareError);
-  }
-
-  return result;
-}
-
-error_code DS2480B::reset() {
-  uint_least8_t packet[2];
-  int packetLen = 0;
-
-  // check for correct mode
-  if (mode != MODSEL_COMMAND) {
-    mode = MODSEL_COMMAND;
-    packet[packetLen++] = MODE_COMMAND;
-  }
-
-  // construct the command
-  packet[packetLen++] = (CMD_COMM | FUNCTSEL_RESET | speed);
-
-  // flush the buffers
-  error_code result = uart->clearReadBuffer();
-  if (result) {
-    return result;
-  }
-
-  // send the packet
-  result = uart->writeBlock(packet, packetLen);
-  if (result) {
-    return result;
-  }
-
-  // read back the 1 byte response
-  result = uart->readBlock(packet, 1);
-  if (result) {
-    return result;
-  }
-
-  // make sure this byte looks like a reset byte
-  if ((packet[0] & RB_RESET_MASK) == RB_1WIRESHORT) {
-    result = make_error_code(ShortDetectedError);
-  }
-  else if ((packet[0] & RB_RESET_MASK) == RB_NOPRESENCE) {
-    result = make_error_code(NoSlaveError);
-  }
-
-  return result;
-}
-
-error_code DS2480B::touchBitSetLevel(bool & sendRecvBit, Level afterLevel) {
-  uint_least8_t packet[2];
-  int packetLen = 0;
-
-  // check for correct mode
-  if (mode != MODSEL_COMMAND) {
-    mode = MODSEL_COMMAND;
-    packet[packetLen++] = MODE_COMMAND;
-  }
-
-  // construct the command
-  packet[packetLen++] = (sendRecvBit ? BITPOL_ONE : BITPOL_ZERO) | CMD_COMM |
-                        FUNCTSEL_BIT | speed;
-
-  // flush the buffers
-  error_code result = uart->clearReadBuffer();
-  if (result) {
-    return result;
-  }
-
-  // send the packet
-  result = uart->writeBlock(packet, packetLen);
-  if (result) {
-    return result;
-  }
-
-  // read back the response
-  result = uart->readBlock(packet, 1);
-  if (result) {
-    return result;
-  }
-
-  // interpret the response
-  if ((packet[0] & 0xE0) == 0x80) {
-    sendRecvBit = ((packet[0] & RB_BIT_MASK) == RB_BIT_ONE);
-    result = setLevel(afterLevel);
-  } else {
-    result = make_error_code(HardwareError);
-  }
-
-  return result;
-}
-
-error_code DS2480B::writeByteSetLevel(uint_least8_t sendByte,
-                                      Level afterLevel) {
-  uint_least8_t packet[3];
-  int packetLen = 0;
-
-  // check for correct mode
-  if (mode != MODSEL_DATA) {
-    mode = MODSEL_DATA;
-    packet[packetLen++] = MODE_DATA;
-  }
-
-  // add the byte to send
-  packet[packetLen++] = sendByte;
-
-  // check for duplication of data that looks like COMMAND mode
-  if (sendByte == MODE_COMMAND) {
-    packet[packetLen++] = sendByte;
-  }
-
-  // flush the buffers
-  error_code result = uart->clearReadBuffer();
-  if (result) {
-    return result;
-  }
-
-  // send the packet
-  result = uart->writeBlock(packet, packetLen);
-  if (result) {
-    return result;
-  }
-
-  // read back the 1 byte response
-  result = uart->readBlock(packet, 1);
-  if (result) {
-    return result;
-  }
-
-  if (packet[0] == sendByte) {
-    result = setLevel(afterLevel);
-  } else {
-    result = make_error_code(HardwareError);
-  }
-
-  return result;
-}
-
-error_code DS2480B::readByteSetLevel(uint_least8_t & recvByte,
-                                     Level afterLevel) {
-  uint_least8_t packet[2];
-  int packetLen = 0;
-
-  // check for correct mode
-  if (mode != MODSEL_DATA) {
-    mode = MODSEL_DATA;
-    packet[packetLen++] = MODE_DATA;
-  }
-
-  // add the byte to send
-  packet[packetLen++] = 0xFF;
-
-  // flush the buffers
-  error_code result = uart->clearReadBuffer();
-  if (result) {
-    return result;
-  }
-
-  // send the packet
-  result = uart->writeBlock(packet, packetLen);
-  if (result) {
-    return result;
-  }
-
-  // read back the 1 byte response
-  result = uart->readBlock(packet, 1);
-  if (result) {
-    return result;
-  }
-
-  recvByte = packet[0];
-  result = setLevel(afterLevel);
-
-  return result;
-}
+  speed = SPEEDSEL_STD;
 
-error_code DS2480B::setSpeed(Speed newSpeed) {
-  error_code result;
-  bool setSpeed = false;
-
-  // check if supported speed
-  switch (newSpeed) {
-  case OverdriveSpeed:
-    // check if change from current mode
-    if (speed != SPEEDSEL_OD) {
-      result = changeBaud(Baud115200bps);
-      if (!result) {
-        speed = SPEEDSEL_OD;
-        setSpeed = true;
-      }
-    }
-    break;
-
-  case StandardSpeed:
-    // check if change from current mode
-    if (speed != SPEEDSEL_STD) {
-      result = changeBaud(Baud9600bps);
-      if (!result) {
-        speed = SPEEDSEL_STD;
-        setSpeed = true;
-      }
-    }
-    break;
-
-  default:
-    result = make_error_code(InvalidSpeedError);
-    break;
-  }
-
-  // if baud rate is set correctly then change DS2480 speed
-  if (setSpeed) {
-    uint_least8_t packet[2];
-    int packetLen = 0;
-
-    // check if correct mode
-    if (mode != MODSEL_COMMAND) {
-      mode = MODSEL_COMMAND;
-      packet[packetLen++] = MODE_COMMAND;
-    }
-
-    // proceed to set the DS2480 communication speed
-    packet[packetLen++] = CMD_COMM | FUNCTSEL_SEARCHOFF | speed;
-
-    // send the packet
-    result = uart->writeBlock(packet, packetLen);
-  }
-
-  return result;
-}
-
-error_code DS2480B::setLevel(Level newLevel) {
-  error_code result;
-  // check if need to change level
-  if (newLevel != level) {
-    uint_least8_t packet[4];
-    int packetLen = 0;
-
-    // check for correct mode
-    if (mode != MODSEL_COMMAND) {
-      mode = MODSEL_COMMAND;
-      packet[packetLen++] = MODE_COMMAND;
-    }
-
-    switch (newLevel) {
-    case NormalLevel:
-      // stop pulse command
-      packet[packetLen++] = MODE_STOP_PULSE;
-
-      // add the command to begin the pulse WITHOUT prime
-      packet[packetLen++] = CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE |
-                            BITPOL_5V | PRIME5V_FALSE;
-
-      // stop pulse command
-      packet[packetLen++] = MODE_STOP_PULSE;
-
-      // flush the buffers
-      result = uart->clearReadBuffer();
-      if (result) {
-        return result;
-      }
-
-      // send the packet
-      result = uart->writeBlock(packet, packetLen);
-      if (result) {
-        return result;
-      }
-
-      // read back the 1 byte response
-      result = uart->readBlock(packet, 2);
-      if (result) {
-        return result;
-      }
-
-      // check response byte
-      if (((packet[0] & 0xE0) == 0xE0) && ((packet[1] & 0xE0) == 0xE0)) {
-        level = NormalLevel;
-      } else {
-        result = make_error_code(HardwareError);
-      }
-      break;
-
-    case StrongLevel:
-      // set the SPUD time value
-      packet[packetLen++] = CMD_CONFIG | PARMSEL_5VPULSE | PARMSET_infinite;
-      // add the command to begin the pulse
-      packet[packetLen++] =
-          CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V;
-
-      // flush the buffers
-      result = uart->clearReadBuffer();
-      if (result) {
-        return result;
-      }
-
-      // send the packet
-      result = uart->writeBlock(packet, packetLen);
-      if (result) {
-        return result;
-      }
-
-      // read back the 1 byte response from setting time limit
-      result = uart->readBlock(packet, 1);
-      if (result) {
-        return result;
-      }
-
-      // check response byte
-      if ((packet[0] & 0x81) == 0) {
-        level = newLevel;
-      } else {
-        result = make_error_code(HardwareError);
-      }
-      break;
-
-    default:
-      result = make_error_code(InvalidLevelError);
-      break;
-    }
-  }
-  return result;
-}
-
-error_code DS2480B::sendCommand(uint_least8_t command) {
-  uint_least8_t packet[2];
-  int packetLen = 0;
-  
-  // check for correct mode
-  if (mode != MODSEL_COMMAND) {
-    mode = MODSEL_COMMAND;
-    packet[packetLen++] = MODE_COMMAND;
-  }
-
-  // add command
-  packet[packetLen++] = command;
-
-  // send the packet
-  return uart->writeBlock(packet, packetLen);
-}
-
-error_code DS2480B::changeBaud(BaudRate newBaud) {
-  error_code result;
-
-  //see if different then current baud rate
-  if (baud != newBaud) {
-    uint_least8_t packet[2];
-    int packetLen = 0;
-
-    // build the command packet
-    // check for correct mode
-    if (mode != MODSEL_COMMAND) {
-      mode = MODSEL_COMMAND;
-      packet[packetLen++] = MODE_COMMAND;
-    }
-    // build the command
-    const uint_least8_t baudByte = CMD_CONFIG | PARMSEL_BAUDRATE | newBaud;
-    packet[packetLen++] = baudByte;
-
-    // flush the buffers
-    result = uart->clearReadBuffer();
-    if (result) {
-      return result;
-    }
-
-    // send the packet
-    result = uart->writeBlock(packet, packetLen);
-    if (result) {
-      return result;
-    }
-
-    // make sure buffer is flushed
-    (*sleep)(5);
-
-    // change our baud rate
-    result = setComBaud(newBaud);
-    if (result) {
-      return result;
-    }
-    baud = newBaud;
-
-    // wait for things to settle
-    (*sleep)(5);
-
-    // build a command packet to read back baud rate
-    packet[0] = CMD_CONFIG | PARMSEL_PARMREAD | (PARMSEL_BAUDRATE >> 3);
-
-    // flush the buffers
-    result = uart->clearReadBuffer();
-    if (result) {
-      return result;
-    }
-
-    // send the packet
-    result = uart->writeBlock(packet, 1);
-    if (result) {
-      return result;
-    }
-
-    // read back the 1 byte response
-    result = uart->readBlock(packet, 1);
-    if (result) {
-      return result;
-    }
-
-    // verify correct baud
-    if (!((packet[0] & 0x0E) == (baudByte & 0x0E))) {
-      result = make_error_code(HardwareError);
-    }
-  }
-
-  return result;
-}
-
-error_code DS2480B::setComBaud(BaudRate newBaud) {
-  switch (newBaud) {
-  case Baud115200bps:
-    return uart->setBaudRate(115200);
-
-  case Baud57600bps:
-    return uart->setBaudRate(57600);
-
-  case Baud19200bps:
-    return uart->setBaudRate(19200);
-
-  case Baud9600bps:
-  default:
-    return uart->setBaudRate(9600);
-  }
-}
-
-error_code DS2480B::breakCom() {
+  // Send a break to reset the DS2480B.
   // Switch to lower baud rate to ensure break is longer than 2 ms.
   error_code result = uart->setBaudRate(4800);
   if (result) {
@@ -679,10 +186,358 @@
   if (result) {
     return result;
   }
-  result = setComBaud(baud);
+  result = uart->setBaudRate(9600);
+  if (result) {
+    return result;
+  }
+
+  // Wait for master reset.
+  sleep->invoke(1);
+
+  // Flush the read buffer.
+  result = uart->clearReadBuffer();
+  if (result) {
+    return result;
+  }
+
+  // Send the timing byte.
+  result = uart->writeByte(CMD_COMM | FUNCTSEL_RESET | SPEEDSEL_STD);
+  if (result) {
+    return result;
+  }
+
+  // Change the DS2480 baud rate.
+  result = uart->writeByte(CMD_CONFIG | PARMSEL_BAUDRATE | PARMSET_115200);
+  if (result) {
+    return result;
+  }
+
+  // Change our baud rate.
+  result = uart->setBaudRate(115200);
+  if (result) {
+    return result;
+  }
+
+  uint_least8_t response;
+
+  // Verify response.
+  result = uart->readByte(response);
+  if (result) {
+    return result;
+  }
+  if ((response & (PARMSEL_MASK | PARMSET_MASK)) !=
+      (PARMSEL_BAUDRATE | PARMSET_115200)) {
+    return make_error_code(HardwareError);
+  }
+
+  // Set the SPUD time value.
+  result = uart->writeByte(CMD_CONFIG | PARMSEL_5VPULSE | PARMSET_infinite);
+  if (result) {
+    return result;
+  }
+
+  // Verify response.
+  result = uart->readByte(response);
+  if (result) {
+    return result;
+  }
+  if ((response & (PARMSEL_MASK | PARMSET_MASK)) !=
+      (PARMSEL_5VPULSE | PARMSET_infinite)) {
+    return make_error_code(HardwareError);
+  }
+
+  return result;
+}
+
+error_code DS2480B::reset() {
+  if (level != NormalLevel) {
+    return make_error_code(InvalidLevelError);
+  }
+
+  uint_least8_t packet[2];
+  int packetLen = 0;
+
+  // Check for correct mode.
+  if (mode != MODSEL_COMMAND) {
+    mode = MODSEL_COMMAND;
+    packet[packetLen++] = MODE_COMMAND;
+  }
+
+  // Construct the command.
+  packet[packetLen++] = CMD_COMM | FUNCTSEL_RESET | speed;
+
+  // Send the packet.
+  error_code result = uart->writeBlock(make_span(packet, packetLen));
+  if (result) {
+    return result;
+  }
+
+  // Read back the response.
+  result = uart->readByte(packet[0]);
+  if (result) {
+    return result;
+  }
+
+  // Make sure this byte looks like a reset byte.
+  if ((packet[0] & RB_RESET_MASK) == RB_1WIRESHORT) {
+    result = make_error_code(ShortDetectedError);
+  } else if ((packet[0] & RB_RESET_MASK) == RB_NOPRESENCE) {
+    result = make_error_code(NoSlaveError);
+  }
+  return result;
+}
+
+error_code DS2480B::touchBitSetLevel(bool & sendRecvBit, Level afterLevel) {
+  if (level != NormalLevel) {
+    return make_error_code(InvalidLevelError);
+  }
+
+  uint_least8_t packet[3];
+  int packetLen = 0;
+
+  // Check for correct mode.
+  if (mode != MODSEL_COMMAND) {
+    mode = MODSEL_COMMAND;
+    packet[packetLen++] = MODE_COMMAND;
+  }
+
+  // Construct the command.
+  packet[packetLen++] = CMD_COMM | FUNCTSEL_BIT |
+                        (sendRecvBit ? BITPOL_ONE : BITPOL_ZERO) | speed;
+  switch (afterLevel) {
+  case NormalLevel:
+    break;
+
+  case StrongLevel:
+    // Add the command to begin the pulse.
+    packet[packetLen++] =
+        CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V | PRIME5V_FALSE;
+    break;
+
+  default:
+    return make_error_code(InvalidLevelError);
+  }
+
+  // Send the packet.
+  error_code result = uart->writeBlock(make_span(packet, packetLen));
+  if (result) {
+    return result;
+  }
+
+  // Read back the response.
+  result = uart->readByte(packet[0]);
+  if (result) {
+    return result;
+  }
+
+  // Interpret the response.
+  if ((packet[0] & 0xE0) == 0x80) {
+    sendRecvBit = ((packet[0] & RB_BIT_MASK) == RB_BIT_ONE);
+    level = afterLevel;
+  } else {
+    result = make_error_code(HardwareError);
+  }
   return result;
 }
 
+error_code DS2480B::writeByteSetLevel(uint_least8_t sendByte,
+                                      Level afterLevel) {
+  if (level != NormalLevel) {
+    return make_error_code(InvalidLevelError);
+  }
+
+  switch (afterLevel) {
+  case NormalLevel:
+    break;
+
+  case StrongLevel:
+    return OneWireMaster::writeByteSetLevel(sendByte, afterLevel);
+
+  default:
+    return make_error_code(InvalidLevelError);
+  }
+
+  uint_least8_t packet[3];
+  int packetLen = 0;
+
+  // Check for correct mode.
+  if (mode != MODSEL_DATA) {
+    mode = MODSEL_DATA;
+    packet[packetLen++] = MODE_DATA;
+  }
+
+  // Add the byte to send.
+  packet[packetLen++] = sendByte;
+
+  // Check for duplication of data that looks like COMMAND mode.
+  if (sendByte == MODE_COMMAND) {
+    packet[packetLen++] = sendByte;
+  }
+
+  // Send the packet.
+  error_code result = uart->writeBlock(make_span(packet, packetLen));
+  if (result) {
+    return result;
+  }
+
+  // Read back the response.
+  result = uart->readByte(packet[0]);
+  if (result) {
+    return result;
+  }
+
+  // Interpret the response.
+  if (packet[0] != sendByte) {
+    result = make_error_code(HardwareError);
+  }
+  return result;
+}
+
+error_code DS2480B::readByteSetLevel(uint_least8_t & recvByte,
+                                     Level afterLevel) {
+  if (level != NormalLevel) {
+    return make_error_code(InvalidLevelError);
+  }
+
+  switch (afterLevel) {
+  case NormalLevel:
+    break;
+
+  case StrongLevel:
+    return OneWireMaster::readByteSetLevel(recvByte, afterLevel);
+
+  default:
+    return make_error_code(InvalidLevelError);
+  }
+
+  uint_least8_t packet[2];
+  int packetLen = 0;
+
+  // Check for correct mode.
+  if (mode != MODSEL_DATA) {
+    mode = MODSEL_DATA;
+    packet[packetLen++] = MODE_DATA;
+  }
+
+  // Add the byte to send.
+  packet[packetLen++] = 0xFF;
+
+  // Send the packet.
+  error_code result = uart->writeBlock(make_span(packet, packetLen));
+  if (result) {
+    return result;
+  }
+
+  // Read back the response.
+  result = uart->readByte(recvByte);
+  return result;
+}
+
+error_code DS2480B::setSpeed(Speed newSpeed) {
+  uint_least8_t newSpeedByte;
+  switch (newSpeed) {
+  case OverdriveSpeed:
+    newSpeedByte = SPEEDSEL_OD;
+    break;
+
+  case StandardSpeed:
+    newSpeedByte = SPEEDSEL_STD;
+    break;
+
+  default:
+    return make_error_code(InvalidSpeedError);
+  }
+  if (speed == newSpeedByte) {
+    return error_code();
+  }
+  speed = newSpeedByte;
+
+  uint_least8_t packet[2];
+  int packetLen = 0;
+
+  // Check for correct mode.
+  if (mode != MODSEL_COMMAND) {
+    mode = MODSEL_COMMAND;
+    packet[packetLen++] = MODE_COMMAND;
+  }
+
+  // Change DS2480 speed.
+  packet[packetLen++] = CMD_COMM | FUNCTSEL_SEARCHOFF | speed;
+
+  // Send the packet.
+  return uart->writeBlock(make_span(packet, packetLen));
+}
+
+error_code DS2480B::setLevel(Level newLevel) {
+  if (level == newLevel) {
+    return error_code();
+  }
+
+  uint_least8_t packet[2];
+  int packetLen = 0;
+
+  switch (newLevel) {
+  case NormalLevel:
+    // Stop pulse command.
+    packet[packetLen++] = MODE_STOP_PULSE;
+    break;
+
+  case StrongLevel:
+    // Check for correct mode.
+    if (mode != MODSEL_COMMAND) {
+      mode = MODSEL_COMMAND;
+      packet[packetLen++] = MODE_COMMAND;
+    }
+
+    // Add the command to begin the pulse.
+    packet[packetLen++] =
+        CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V | PRIME5V_FALSE;
+    break;
+
+  default:
+    return make_error_code(InvalidLevelError);
+  }
+
+  // Send the packet.
+  error_code result = uart->writeBlock(make_span(packet, packetLen));
+  if (result) {
+    return result;
+  }
+
+  if (newLevel == NormalLevel) {
+    // Read back the response.
+    result = uart->readByte(packet[0]);
+    if (result) {
+      return result;
+    }
+
+    // Interpret the response.
+    if ((packet[0] & 0xE0) != 0xE0) {
+      return make_error_code(HardwareError);
+    }
+  }
+
+  level = newLevel;
+  return result;
+}
+
+error_code DS2480B::sendCommand(uint_least8_t command) {
+  uint_least8_t packet[2];
+  int packetLen = 0;
+
+  // Check for correct mode.
+  if (mode != MODSEL_COMMAND) {
+    mode = MODSEL_COMMAND;
+    packet[packetLen++] = MODE_COMMAND;
+  }
+
+  // Add command.
+  packet[packetLen++] = command;
+
+  // Send the packet.
+  return uart->writeBlock(make_span(packet, packetLen));
+}
+
 const error_category & DS2480B::errorCategory() {
   static class : public error_category {
   public:
--- a/Devices/DS2480B.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS2480B.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -43,25 +43,28 @@
 /// Serial to 1-Wire Line Driver
 class DS2480B : public OneWireMaster {
 public:
-  enum ErrorValue {
-    HardwareError = 1
-  };
+  enum ErrorValue { HardwareError = 1 };
 
-  DS2480B(const Sleep & sleep, Uart & uart) : sleep(&sleep), uart(&uart) {}
+  DS2480B(Sleep & sleep, Uart & uart) : sleep(&sleep), uart(&uart) {}
 
-  void setSleep(const Sleep & sleep) { this->sleep = &sleep; }
+  void setSleep(Sleep & sleep) { this->sleep = &sleep; }
   void setUart(Uart & uart) { this->uart = &uart; }
 
   MaximInterface_EXPORT error_code initialize();
 
   MaximInterface_EXPORT virtual error_code reset();
+  
   MaximInterface_EXPORT virtual error_code touchBitSetLevel(bool & sendRecvBit,
                                                             Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
   writeByteSetLevel(uint_least8_t sendByte, Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
   readByteSetLevel(uint_least8_t & recvByte, Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed);
+  
   MaximInterface_EXPORT virtual error_code setLevel(Level newLevel);
 
   MaximInterface_EXPORT static const error_category & errorCategory();
@@ -70,23 +73,10 @@
   MaximInterface_EXPORT error_code sendCommand(uint_least8_t command);
 
 private:
-  /// Baud rates for DS2480B
-  enum BaudRate {
-    Baud9600bps = 0,  ///< 9600 bps
-    Baud19200bps = 2, ///< 19200 bps
-    Baud57600bps = 4, ///< 57600 bps
-    Baud115200bps = 6 ///< 115200 bps
-  };
-
-  error_code changeBaud(BaudRate newBaud);
-  error_code setComBaud(BaudRate newBaud);
-  error_code breakCom();
-
   const Sleep * sleep;
   Uart * uart;
 
   Level level;
-  BaudRate baud;
   uint_least8_t mode;
   uint_least8_t speed;
 };
--- a/Devices/DS2482_DS2484.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS2482_DS2484.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,26 +35,6 @@
 
 namespace MaximInterface {
 
-enum Command {
-  DeviceResetCmd = 0xF0,
-  WriteDeviceConfigCmd = 0xD2,
-  AdjustOwPortCmd = 0xC3,  // DS2484 only
-  ChannelSelectCmd = 0xC3, // DS2482-800 only
-  SetReadPointerCmd = 0xE1,
-  OwResetCmd = 0xB4,
-  OwWriteByteCmd = 0xA5,
-  OwReadByteCmd = 0x96,
-  OwSingleBitCmd = 0x87,
-  OwTripletCmd = 0x78
-};
-
-// Device register pointers.
-enum Register {
-  ConfigReg = 0xC3,
-  StatusReg = 0xF0,
-  ReadDataReg = 0xE1
-};
-
 // Device Status bits
 enum StatusBit {
   Status_1WB = 0x01,
@@ -68,13 +48,11 @@
 };
 
 error_code DS2482_DS2484::initialize(Config config) {
-  // reset device
   error_code result = resetDevice();
   if (result) {
     return result;
   }
-
-  // write the default configuration setup
+  // Write the default configuration setup.
   result = writeConfig(config);
   return result;
 }
@@ -85,23 +63,24 @@
   //  [] indicates from slave
   //  SS status byte to read to verify state
 
-  uint_least8_t buf;
-  error_code result = sendCommand(DeviceResetCmd);
-
-  if (!result) {
-    result = readRegister(buf);
+  error_code result = sendCommand(0xF0);
+  if (result) {
+    return result;
   }
 
-  if (!result) {
-    if ((buf & 0xF7) != 0x10) {
-      result = make_error_code(HardwareError);
-    }
+  uint_least8_t buf;
+  result = readRegister(buf);
+  if (result) {
+    return result;
   }
 
-  if (!result) {
-    reset(); // do a command to get 1-Wire master reset out of holding state
+  if ((buf & 0xF7) != 0x10) {
+    return make_error_code(HardwareError);
   }
 
+  // Do a command to get 1-Wire master reset out of holding state.
+  reset();
+
   return result;
 }
 
@@ -113,12 +92,11 @@
   //  [] indicates from slave
   //  SS indicates byte containing search direction bit value in msbit
 
-  error_code result = sendCommand(OwTripletCmd, data.writeBit ? 0x80 : 0x00);
+  error_code result = sendCommand(0x78, data.writeBit ? 0x80 : 0x00);
   if (!result) {
     uint_least8_t status;
     result = pollBusy(&status);
     if (!result) {
-      // check bit results in status byte
       data.readBit = ((status & Status_SBR) == Status_SBR);
       data.readBitComplement = ((status & Status_TSB) == Status_TSB);
       data.writeBit = ((status & Status_DIR) == Status_DIR);
@@ -134,26 +112,28 @@
   //                       Repeat until 1WB bit has changed to 0
   //  [] indicates from slave
 
-  error_code result = sendCommand(OwResetCmd);
-  uint_least8_t buf;
-
-  if (!result) {
-    result = pollBusy(&buf);
+  error_code result = sendCommand(0xB4);
+  if (result) {
+    return result;
   }
 
-  if (!result) {
-    if ((buf & Status_SD) == Status_SD) {
-      result = make_error_code(ShortDetectedError);
-    }
-    else if ((buf & Status_PPD) != Status_PPD) {
-      result = make_error_code(NoSlaveError);
-    }
+  uint_least8_t buf;
+  result = pollBusy(&buf);
+  if (result) {
+    return result;
+  }
+
+  if ((buf & Status_SD) == Status_SD) {
+    result = make_error_code(ShortDetectedError);
+  } else if ((buf & Status_PPD) != Status_PPD) {
+    result = make_error_code(NoSlaveError);
   }
 
   return result;
 }
 
-error_code DS2482_DS2484::touchBitSetLevel(bool & sendRecvBit, Level afterLevel) {
+error_code DS2482_DS2484::touchBitSetLevel(bool & sendRecvBit,
+                                           Level afterLevel) {
   // 1-Wire bit (Case B)
   //   S AD,0 [A] 1WSB [A] BB [A] Sr AD,1 [A] [Status] A [Status] A\ P
   //                                          \--------/
@@ -162,25 +142,25 @@
   //  BB indicates byte containing bit value in msbit
 
   error_code result = configureLevel(afterLevel);
+  if (result) {
+    return result;
+  }
 
-  if (!result) {
-    result = sendCommand(OwSingleBitCmd, sendRecvBit ? 0x80 : 0x00);
+  result = sendCommand(0x87, sendRecvBit ? 0x80 : 0x00);
+  if (result) {
+    return result;
   }
 
   uint_least8_t status;
-
-  if (!result) {
-    result = pollBusy(&status);
-  }
-
+  result = pollBusy(&status);
   if (!result) {
     sendRecvBit = ((status & Status_SBR) == Status_SBR);
   }
-
   return result;
 }
 
-error_code DS2482_DS2484::writeByteSetLevel(uint_least8_t sendByte, Level afterLevel) {
+error_code DS2482_DS2484::writeByteSetLevel(uint_least8_t sendByte,
+                                            Level afterLevel) {
   // 1-Wire Write Byte (Case B)
   //   S AD,0 [A] 1WWB [A] DD [A] Sr AD,1 [A] [Status] A [Status] A\ P
   //                                          \--------/
@@ -193,16 +173,17 @@
     return result;
   }
 
-  result = sendCommand(OwWriteByteCmd, sendByte);
-  if (!result) {
-    result = pollBusy();
+  result = sendCommand(0xA5, sendByte);
+  if (result) {
+    return result;
   }
 
+  result = pollBusy();
   return result;
 }
 
 error_code DS2482_DS2484::readByteSetLevel(uint_least8_t & recvByte,
-                                    Level afterLevel) {
+                                           Level afterLevel) {
   // 1-Wire Read Bytes (Case C)
   //   S AD,0 [A] 1WRB [A] Sr AD,1 [A] [Status] A [Status] A
   //                                   \--------/
@@ -217,22 +198,17 @@
     return result;
   }
 
-  result = sendCommand(OwReadByteCmd);
-
-  if (!result) {
-    result = pollBusy();
+  result = sendCommand(0x96);
+  if (result) {
+    return result;
   }
 
-  uint_least8_t buf;
-
-  if (!result) {
-    result = readRegister(ReadDataReg, buf);
+  result = pollBusy();
+  if (result) {
+    return result;
   }
 
-  if (!result) {
-    recvByte = buf;
-  }
-
+  result = readRegister(0xE1, recvByte);
   return result;
 }
 
@@ -246,9 +222,7 @@
     return error_code();
   }
   // Set the speed
-  Config newConfig = curConfig;
-  newConfig.set1WS(newSpeed == OverdriveSpeed);
-  return writeConfig(newConfig);
+  return writeConfig(Config(curConfig).set1WS(newSpeed == OverdriveSpeed));
 }
 
 error_code DS2482_DS2484::setLevel(Level newLevel) {
@@ -260,10 +234,11 @@
 }
 
 error_code DS2482_DS2484::writeConfig(Config config) {
-  uint_least8_t configBuf = ((config.readByte() ^ 0xF) << 4) | config.readByte();
-  error_code result = sendCommand(WriteDeviceConfigCmd, configBuf);
+  uint_least8_t configBuf =
+      ((config.readByte() ^ 0xF) << 4) | config.readByte();
+  error_code result = sendCommand(0xD2, configBuf);
   if (!result) {
-    result = readRegister(ConfigReg, configBuf);
+    result = readRegister(0xC3, configBuf);
   }
   if (!result) {
     if (configBuf != config.readByte()) {
@@ -276,8 +251,9 @@
   return result;
 }
 
-error_code DS2482_DS2484::readRegister(uint_least8_t reg, uint_least8_t & buf) const {
-  error_code result = sendCommand(SetReadPointerCmd, reg);
+error_code DS2482_DS2484::readRegister(uint_least8_t reg,
+                                       uint_least8_t & buf) const {
+  error_code result = sendCommand(0xE1, reg);
   if (!result) {
     result = readRegister(buf);
   }
@@ -285,7 +261,7 @@
 }
 
 error_code DS2482_DS2484::readRegister(uint_least8_t & buf) const {
-  return i2cMaster->readPacket(i2cAddress_, &buf, 1);
+  return master->readPacket(address_, make_span(&buf, 1));
 }
 
 error_code DS2482_DS2484::pollBusy(uint_least8_t * pStatus) {
@@ -319,18 +295,17 @@
     return error_code();
   }
   // Set the level
-  Config newConfig = curConfig;
-  newConfig.setSPU(level == StrongLevel);
-  return writeConfig(newConfig);
+  return writeConfig(Config(curConfig).setSPU(level == StrongLevel));
 }
 
 error_code DS2482_DS2484::sendCommand(uint_least8_t cmd) const {
-  return i2cMaster->writePacket(i2cAddress_, &cmd, 1);
+  return master->writePacket(address_, make_span(&cmd, 1));
 }
 
-error_code DS2482_DS2484::sendCommand(uint_least8_t cmd, uint_least8_t param) const {
+error_code DS2482_DS2484::sendCommand(uint_least8_t cmd,
+                                      uint_least8_t param) const {
   uint_least8_t buf[] = {cmd, param};
-  return i2cMaster->writePacket(i2cAddress_, buf, sizeof(buf) / sizeof(buf[0]));
+  return master->writePacket(address_, buf);
 }
 
 const error_category & DS2482_DS2484::errorCategory() {
@@ -408,7 +383,7 @@
     return make_error_code(ArgumentOutOfRangeError);
   };
 
-  error_code result = sendCommand(ChannelSelectCmd, ch);
+  error_code result = sendCommand(0xC3, ch);
   if (!result) {
     result = readRegister(ch);
     if (!result) {
@@ -427,13 +402,13 @@
     return make_error_code(ArgumentOutOfRangeError);
   }
 
-  error_code result = sendCommand(AdjustOwPortCmd, (param << 4) | val);
+  error_code result = sendCommand(0xC3, (param << 4) | val);
   if (result) {
     return result;
   }
 
-  uint_least8_t portConfig;
-  for (int paramNum = param + 1; paramNum > 0; paramNum--) {
+  uint_least8_t portConfig = val + 1;
+  for (int reads = -1; reads < param; ++reads) {
     result = readRegister(portConfig);
     if (result) {
       return result;
--- a/Devices/DS2482_DS2484.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS2482_DS2484.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -51,52 +51,80 @@
     explicit Config(uint_least8_t readByte = optionAPU)
         : readByte_(readByte & 0xF) {}
 
+    /// @name 1WS
+    /// @brief 1-Wire Speed
     /// @{
-    /// 1-Wire Speed
+    
+    /// Get 1WS bit.
     bool get1WS() const { return (readByte_ & option1WS) == option1WS; }
-    void set1WS(bool new1WS) {
+    
+    /// Set 1WS bit.
+    Config & set1WS(bool new1WS) {
       if (new1WS) {
         readByte_ |= option1WS;
       } else {
         readByte_ &= ~option1WS;
       }
+      return *this;
     }
+    
     /// @}
 
+    /// @name SPU
+    /// @brief Strong Pullup
     /// @{
-    /// Strong Pullup
+    
+    /// Get SPU bit.
     bool getSPU() const { return (readByte_ & optionSPU) == optionSPU; }
-    void setSPU(bool newSPU) {
+    
+    /// Set SPU bit.
+    Config & setSPU(bool newSPU) {
       if (newSPU) {
         readByte_ |= optionSPU;
       } else {
         readByte_ &= ~optionSPU;
       }
+      return *this;
     }
+    
     /// @}
 
+    /// @name PDN
+    /// @brief 1-Wire Power Down
     /// @{
-    /// 1-Wire Power Down
+    
+    /// Get PDN bit.
     bool getPDN() const { return (readByte_ & optionPDN) == optionPDN; }
-    void setPDN(bool newPDN) {
+    
+    /// Set PDN bit.
+    Config & setPDN(bool newPDN) {
       if (newPDN) {
         readByte_ |= optionPDN;
       } else {
         readByte_ &= ~optionPDN;
       }
+      return *this;
     }
+    
     /// @}
 
+    /// @name APU
+    /// @brief Active Pullup
     /// @{
-    /// Active Pullup
+    
+    /// Get APU bit.
     bool getAPU() const { return (readByte_ & optionAPU) == optionAPU; }
-    void setAPU(bool newAPU) {
+    
+    /// Set APU bit.
+    Config & setAPU(bool newAPU) {
       if (newAPU) {
         readByte_ |= optionAPU;
       } else {
         readByte_ &= ~optionAPU;
       }
+      return *this;
     }
+    
     /// @}
 
     /// Byte representation that is read from the device.
@@ -111,37 +139,41 @@
     uint_least8_t readByte_;
   };
 
-  void setI2CMaster(I2CMaster & i2cMaster) { this->i2cMaster = &i2cMaster; }
-  uint_least8_t i2cAddress() const { return i2cAddress_; }
-  void setI2CAddress(uint_least8_t i2cAddress) {
-    this->i2cAddress_ = i2cAddress;
-  }
+  void setMaster(I2CMaster & master) { this->master = &master; }
+  
+  uint_least8_t address() const { return address_; }
+  
+  void setAddress(uint_least8_t address) { address_ = address; }
 
   /// Initialize hardware for use.
   MaximInterface_EXPORT error_code initialize(Config config = Config());
 
-  /// Write a new configuration to the device.
+  /// @brief Write a new configuration to the device.
   /// @param[in] config New configuration to write.
   MaximInterface_EXPORT error_code writeConfig(Config config);
 
-  /// @note Perform a 1-Wire triplet using the device command.
   MaximInterface_EXPORT virtual error_code triplet(TripletData & data);
 
   MaximInterface_EXPORT virtual error_code reset();
+  
   MaximInterface_EXPORT virtual error_code touchBitSetLevel(bool & sendRecvBit,
                                                             Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
   readByteSetLevel(uint_least8_t & recvByte, Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
   writeByteSetLevel(uint_least8_t sendByte, Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed);
+  
   MaximInterface_EXPORT virtual error_code setLevel(Level newLevel);
 
   MaximInterface_EXPORT static const error_category & errorCategory();
 
 protected:
-  DS2482_DS2484(I2CMaster & i2cMaster, uint_least8_t i2cAddress)
-      : i2cMaster(&i2cMaster), i2cAddress_(i2cAddress) {}
+  DS2482_DS2484(I2CMaster & master, uint_least8_t address)
+      : master(&master), address_(address) {}
 
   /// @note Allow marking const since not public.
   error_code sendCommand(uint_least8_t cmd) const;
@@ -149,31 +181,32 @@
   /// @note Allow marking const since not public.
   error_code sendCommand(uint_least8_t cmd, uint_least8_t param) const;
 
-  /// Reads a register from the device.
+  /// @brief Reads a register from the device.
   /// @param reg Register to read from.
   /// @param[out] buf Buffer to hold read data.
   error_code readRegister(uint_least8_t reg, uint_least8_t & buf) const;
 
-  /// Reads the current register from the device.
+  /// @brief Reads the current register from the device.
   /// @param[out] buf Buffer to hold read data.
   error_code readRegister(uint_least8_t & buf) const;
 
 private:
-  /// Performs a soft reset on the device.
+  /// @brief Performs a soft reset on the device.
   /// @note This is not a 1-Wire Reset.
   error_code resetDevice();
 
+  /// @brief
   /// Polls the device status waiting for the 1-Wire Busy bit (1WB) to be cleared.
   /// @param[out] pStatus Optionally retrieve the status byte when 1WB cleared.
   /// @returns Success or TimeoutError if poll limit reached.
   error_code pollBusy(uint_least8_t * pStatus = NULL);
 
-  /// Ensure that the desired 1-Wire level is set in the configuration.
+  /// @brief Ensure that the desired 1-Wire level is set in the configuration.
   /// @param level Desired 1-Wire level.
   error_code configureLevel(Level level);
 
-  I2CMaster * i2cMaster;
-  uint_least8_t i2cAddress_;
+  I2CMaster * master;
+  uint_least8_t address_;
   Config curConfig;
 };
 
@@ -193,7 +226,7 @@
   DS2482_800(I2CMaster & i2c_bus, uint_least8_t adrs)
       : DS2482_DS2484(i2c_bus, adrs) {}
 
-  /// Select the active 1-Wire channel.
+  /// @brief Select the active 1-Wire channel.
   /// @param channel Channel number to select from 0 to 7.
   MaximInterface_EXPORT error_code selectChannel(int channel);
 };
@@ -201,7 +234,7 @@
 /// DS2484 I2C to 1-Wire Master
 class DS2484 : public DS2482_DS2484 {
 public:
-  /// 1-Wire port adjustment parameters.
+  /// @brief 1-Wire port adjustment parameters.
   /// @note See datasheet page 13.
   enum PortParameter {
     tRSTL = 0,
@@ -217,7 +250,7 @@
   explicit DS2484(I2CMaster & i2c_bus, uint_least8_t adrs = 0x30)
       : DS2482_DS2484(i2c_bus, adrs) {}
 
-  /// Adjust 1-Wire port parameters.
+  /// @brief Adjust 1-Wire port parameters.
   /// @param param Parameter to adjust.
   /// @param val New parameter value to set. Consult datasheet for value mappings.
   MaximInterface_EXPORT error_code adjustPort(PortParameter param, int val);
--- a/Devices/DS28C36_DS2476.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS28C36_DS2476.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -1,731 +1,724 @@
-/*******************************************************************************
-* 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, &parameter, 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, &parameter, 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, &parameter, 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, &parameter, 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(&parameter, 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(&parameter, 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(&parameter, 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(&parameter, 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::Page::array page;
+  error_code result = ds28c36.readMemory(DS28C36::romOptionsPage, page);
+  if (!result) {
+    const DS28C36::RomOptions romOptions(page);
+    copy(romOptions.romId(), romId);
+    copy(romOptions.manId(), manId);
+  }
+  return result;
+}
+
+error_code enableCoprocessor(DS2476 & ds2476) {
+  DS2476::Page::array page;
+  error_code result = ds2476.readMemory(DS2476::gpioControlPage, page);
+  if (!result) {
+    DS2476::GpioControl gpioControl(page);
+    if (!gpioControl.pioaConducting()) {
+      gpioControl.setPioaConducting(true);
+      result = ds2476.writeMemory(DS2476::gpioControlPage, page);
+    }
+  }
+  return result;
+}
+
+error_code enableRomId(DS2476 & ds2476) {
+  DS2476::Page::array page;
+  error_code result = ds2476.readMemory(DS2476::romOptionsPage, page);
+  if (!result) {
+    DS2476::RomOptions romOptions(page);
+    if (!romOptions.romBlockDisable()) {
+      romOptions.setRomBlockDisable(true);
+      result = ds2476.writeMemory(DS2476::romOptionsPage, page);
+    }
+  }
+  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
--- a/Devices/DS28C36_DS2476.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS28C36_DS2476.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -1,411 +1,923 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#ifndef MaximInterface_DS28C36_DS2476
-#define MaximInterface_DS28C36_DS2476
-
-#include <stddef.h>
-#include <stdint.h>
-#include <vector>
-#include <MaximInterface/Links/I2CMaster.hpp>
-#include <MaximInterface/Links/Sleep.hpp>
-#include <MaximInterface/Utilities/array.hpp>
-#include <MaximInterface/Utilities/Ecc256.hpp>
-#include <MaximInterface/Utilities/Export.h>
-#include <MaximInterface/Utilities/RomId.hpp>
-#include <MaximInterface/Utilities/ManId.hpp>
-#include <MaximInterface/Utilities/Sha256.hpp>
-#include <MaximInterface/Utilities/system_error.hpp>
-#include <MaximInterface/Utilities/FlagSet.hpp>
-
-namespace MaximInterface {
-
-/// Interface to the DS28C36 authenticator.
-class DS28C36 {
-public:
-  /// Device command results.
-  enum ErrorValue {
-    ProtectionError = 0x55,
-    InvalidParameterError = 0x77,
-    InvalidSequenceError = 0x33,
-    InvalidEcdsaInputOrResultError = 0x22,
-    AuthenticationError = 0x100,
-    InvalidResponseError = 0x101 ///< Response does not match expected format.
-  };
-
-  /// Device memory pages.
-  enum PageNum {
-    UserData0 = 0,
-    UserData1,
-    UserData2,
-    UserData3,
-    UserData4,
-    UserData5,
-    UserData6,
-    UserData7,
-    UserData8,
-    UserData9,
-    UserData10,
-    UserData11,
-    UserData12,
-    UserData13,
-    UserData14,
-    UserData15,
-    PublicKeyAX,
-    PublicKeyAY,
-    PublicKeyBX,
-    PublicKeyBY,
-    PublicKeyCX,
-    PublicKeyCY,
-    PrivateKeyA,
-    PrivateKeyB,
-    PrivateKeyC,
-    SecretA,
-    SecretB,
-    DecrementCounter,
-    RomOptions,
-    GpioControl,
-    PublicKeySX,
-    PublicKeySY
-  };
-
-  /// Available keys for ECDSA operations.
-  enum KeyNum { KeyNumA = 0, KeyNumB = 1, KeyNumC = 2, KeyNumS = 3 };
-
-  /// Available secrets for HMAC operations.
-  enum SecretNum { SecretNumA = 0, SecretNumB = 1, SecretNumS = 2 };
-
-  /// Data hash type when verifying an ECDSA signature.
-  enum HashType {
-    HashInBuffer = 0, ///< Hash is loaded in the buffer.
-    DataInBuffer = 1, ///< Compute hash from data loaded in the buffer.
-    THASH = 2         ///< Use THASH from Compute Multiblock Hash command.
-  };
-
-  /// Available PIO states when verifying an ECDSA signature.
-  enum PioState { Unchanged, Conducting, HighImpedance };
-
-  /// Holds a device memory page.
-  typedef array<uint_least8_t, 32> Page;
-
-  /// Holds page authentication input data.
-  typedef array<uint_least8_t, 75> PageAuthenticationData;
-
-  /// Page protection types.
-  enum PageProtectionType {
-    RP = 0x01,   ///< Read protection.
-    WP = 0x02,   ///< Write protection.
-    EM = 0x04,   ///< EPROM emulation mode.
-    APH = 0x08,  ///< Authentication write protection HMAC.
-    EPH = 0x10,  ///< Encryption and authenticated write protection HMAC.
-    AUTH = 0x20, ///< Public Key C is set to authority public key.
-    ECH = 0x40,  ///< Encrypted read and write using shared key from ECDH.
-    ECW = 0x80   ///< Authentication write protection ECDSA.
-  };
-  typedef FlagSet<PageProtectionType, 8> PageProtection;
-
-  /// Holds an encrypted device memory page.
-  struct EncryptedPage {
-    typedef array<uint_least8_t, 8> Challenge;
-
-    /// Total size of all elements in bytes.
-    static const size_t size = Challenge::csize + Page::csize;
-
-    Challenge challenge;
-    Page data;
-  };
-
-  /// Number of memory pages on the device.
-  static const int memoryPages = 32;
-
-  DS28C36(const Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x36)
-      : sleep_(&sleep), master(&master), address_(address & 0xFE) {}
-
-  void setSleep(const Sleep & sleep) { this->sleep_ = &sleep; }
-  void setMaster(I2CMaster & master) { this->master = &master; }
-  uint_least8_t address() const { return address_; }
-  void setAddress(uint_least8_t address) { this->address_ = (address & 0xFE); }
-
-  /// Write memory with no protection.
-  /// @param pageNum Number of page to write.
-  /// @param page Data to write.
-  MaximInterface_EXPORT error_code writeMemory(int pageNum, const Page & page);
-
-  /// Read memory with no protection.
-  /// @param pageNum Number of page to read.
-  /// @param[out] page Data that was read.
-  MaximInterface_EXPORT error_code readMemory(int pageNum, Page & page);
-
-  /// Write the temporary buffer.
-  /// @param data Data to write.
-  /// @param dataSize Size of data to write.
-  MaximInterface_EXPORT error_code writeBuffer(const uint_least8_t * data,
-                                               size_t dataSize);
-
-  /// Read the temporary buffer.
-  /// @param[out] data Data that was read.
-  MaximInterface_EXPORT error_code
-  readBuffer(std::vector<uint_least8_t> & data);
-
-  /// Read the protection settings of a page.
-  /// @param pageNum Number of page to read.
-  /// @param[out] protection Protection that was read.
-  MaximInterface_EXPORT error_code
-  readPageProtection(int pageNum, PageProtection & protection);
-
-  /// Set the protection settings of a page.
-  /// @param pageNum Number of page to write.
-  /// @param protection Protection to write.
-  MaximInterface_EXPORT error_code
-  setPageProtection(int pageNum, const PageProtection & protection);
-
-  /// Decrement the decrement-only counter.
-  MaximInterface_EXPORT error_code decrementCounter();
-
-  /// Read a block of random data from the RNG.
-  /// @param[out] data Buffer to hold random data from RNG.
-  /// @param dataSize Number of bytes to read from 1 to 64 and length of data.
-  MaximInterface_EXPORT error_code readRng(uint_least8_t * data,
-                                           size_t dataSize);
-
-  /// Read memory with encryption.
-  /// @param pageNum Number of page to read from.
-  /// @param secretNum Secret to use for encryption.
-  /// @param[out] page Data that was read.
-  MaximInterface_EXPORT error_code encryptedReadMemory(int pageNum,
-                                                       SecretNum secretNum,
-                                                       EncryptedPage & page);
-
-  /// Compute and read page authentication with ECDSA.
-  /// @param pageNum Number of page to authenticate.
-  /// @param keyNum Private key to use for authentication.
-  /// Key S cannot be used with this command.
-  /// @param[out] signature Computed page signature.
-  MaximInterface_EXPORT error_code computeAndReadEcdsaPageAuthentication(
-      int pageNum, KeyNum keyNum, Ecc256::Signature & signature);
-
-  /// Compute and read page authentication with HMAC.
-  /// @param pageNum Number of page to authenticate.
-  /// @param secretNum Secret to use for authentication.
-  /// @param[out] hmac Computed page HMAC.
-  MaximInterface_EXPORT error_code computeAndReadHmacPageAuthentication(
-      int pageNum, SecretNum secretNum, Sha256::Hash & hmac);
-
-  /// Write with SHA2 authentication.
-  /// @param pageNum Number of page to write.
-  /// @param secretNum Secret to use for authentication.
-  /// @param page Data to write.
-  MaximInterface_EXPORT error_code authenticatedSha2WriteMemory(
-      int pageNum, SecretNum secretNum, const Page & page);
-
-  /// Compute SHA2 secret and optionally lock.
-  /// @param pageNum Number of page to use in computation.
-  /// @param msecretNum Master secret to use in computation.
-  /// @param dsecretNum Destination secret to receive the computation result.
-  /// @param writeProtectEnable
-  /// True to lock the destination secret against further writes.
-  MaximInterface_EXPORT error_code
-  computeAndLockSha2Secret(int pageNum, SecretNum msecretNum,
-                           SecretNum dsecretNum, bool writeProtectEnable);
-
-  /// Generate a new ECDSA key pair.
-  /// @param keyNum Key to generate. Key S cannot be used with this command.
-  /// @param writeProtectEnable True to lock the key against further writes.
-  MaximInterface_EXPORT error_code
-  generateEcc256KeyPair(KeyNum keyNum, bool writeProtectEnable);
-
-  /// Compute a hash over multiple blocks.
-  /// @param firstBlock True if this is the first block being hashed.
-  /// @param lastBlock True if this is the last block being hashed.
-  /// @param data Data block to hash.
-  /// @param dataSize Size of data to hash.
-  /// Should be 64 bytes unless this is the last block.
-  MaximInterface_EXPORT error_code
-  computeMultiblockHash(bool firstBlock, bool lastBlock,
-                        const uint_least8_t * data, size_t dataSize);
-
-  /// Verify ECDSA signature.
-  /// @param keyNum Public key to use for verification.
-  /// @param hashType Source of the data hash input.
-  /// @param signature Signature to verify.
-  /// @param pioa New state of PIOA if verification successful.
-  /// @param piob New state of PIOB if verification successful.
-  MaximInterface_EXPORT error_code verifyEcdsaSignature(
-      KeyNum keyNum, HashType hashType, const Ecc256::Signature & signature,
-      PioState pioa = Unchanged, PioState piob = Unchanged);
-
-  /// Authenticate a public key for authenticated writes or encrypted reads with ECDH.
-  /// @param authWrites True to select authentication for writes.
-  /// @param ecdh True to select ECDH key exchange.
-  /// @param keyNum Private key to use for ECDH key exchange.
-  /// Key A or B can be selected.
-  /// @param csOffset Certificate customization field ending offset in buffer.
-  /// @param signature Signature to use for authentication of public key S.
-  MaximInterface_EXPORT error_code
-  authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum,
-                             int csOffset, const Ecc256::Signature & signature);
-
-  /// Write with ECDSA authentication.
-  /// @param pageNum Number of page to write.
-  /// @param page Data to write.
-  MaximInterface_EXPORT error_code
-  authenticatedEcdsaWriteMemory(int pageNum, const Page & page);
-
-  /// Create data used by the Compute and Read Page Authentication command to
-  /// generate a signature.
-  MaximInterface_EXPORT static PageAuthenticationData
-  createPageAuthenticationData(const RomId & romId, const Page & page,
-                               const Page & challenge, int pageNum,
-                               const ManId & manId);
-
-  MaximInterface_EXPORT static const error_category & errorCategory();
-
-protected:
-  // Timing constants.
-  static const int generateEcdsaSignatureTimeMs = 50;
-  static const int generateEccKeyPairTimeMs = 100;
-  static const int verifyEsdsaSignatureOrComputeEcdhTimeMs = 150;
-  static const int sha256ComputationTimeMs = 3;
-  static const int readMemoryTimeMs = /*1*/ 2;
-  static const int writeMemoryTimeMs = 15;
-
-  error_code writeCommand(uint_least8_t command,
-                          const uint_least8_t * parameters,
-                          size_t parametersSize);
-
-  error_code writeCommand(uint_least8_t command) {
-    return writeCommand(command, NULL, 0);
-  }
-
-  error_code readVariableLengthResponse(uint_least8_t * response,
-                                        size_t & responseSize);
-
-  error_code readFixedLengthResponse(uint_least8_t * response,
-                                     size_t responseSize);
-
-  void sleep(int ms) const { (*sleep_)(ms); }
-
-private:
-  enum AuthType {
-    HmacWithSecretA = 0,
-    HmacWithSecretB = 1,
-    HmacWithSecretS = 2,
-    EcdsaWithKeyA = 3,
-    EcdsaWithKeyB = 4,
-    EcdsaWithKeyC = 5
-  };
-
-  const Sleep * sleep_;
-  I2CMaster * master;
-  uint_least8_t address_;
-
-  error_code computeAndReadPageAuthentication(int pageNum, AuthType authType);
-};
-
-/// Read the device ROM ID and MAN ID using the Read Memory command on the
-/// ROM Options page.
-/// @param[out] romId
-/// Read ROM ID valid when operation is successful. May be set to NULL.
-/// @param[out] manId
-/// Read MAN ID valid when operation is successful. May be set to NULL.
-MaximInterface_EXPORT error_code readRomIdAndManId(DS28C36 & ds28c36,
-                                                   RomId * romId,
-                                                   ManId * manId);
-
-/// Hash arbitrary length data with successive Compute Multiblock Hash commands.
-/// @param data Data to hash.
-/// @param dataSize Size of data to hash.
-MaximInterface_EXPORT error_code computeMultiblockHash(
-    DS28C36 & ds28c36, const uint_least8_t * data, const size_t dataSize);
-
-/// Verify ECDSA signature.
-/// @param publicKey Public key to use for verification.
-/// @param data Data to verify.
-/// @param dataSize Size of data to verify.
-/// @param signature Signature to verify.
-/// @param pioa New state of PIOA if verification successful.
-/// @param piob New state of PIOB if verification successful.
-MaximInterface_EXPORT error_code verifyEcdsaSignature(
-    DS28C36 & ds28c36, DS28C36::KeyNum publicKey, const uint_least8_t * data,
-    size_t dataSize, const Ecc256::Signature & signature,
-    DS28C36::PioState pioa = DS28C36::Unchanged,
-    DS28C36::PioState piob = DS28C36::Unchanged);
-
-/// Verify ECDSA signature.
-/// @param publicKey
-/// Public key to use for verification which is loaded into Public Key S.
-/// @param data Data to verify.
-/// @param dataSize Size of data to verify.
-/// @param signature Signature to verify.
-/// @param pioa New state of PIOA if verification successful.
-/// @param piob New state of PIOB if verification successful.
-MaximInterface_EXPORT error_code
-verifyEcdsaSignature(DS28C36 & ds28c36, const Ecc256::PublicKey & publicKey,
-                     const uint_least8_t * data, size_t dataSize,
-                     const Ecc256::Signature & signature,
-                     DS28C36::PioState pioa = DS28C36::Unchanged,
-                     DS28C36::PioState piob = DS28C36::Unchanged);
-
-inline error_code make_error_code(DS28C36::ErrorValue e) {
-  return error_code(e, DS28C36::errorCategory());
-}
-
-/// Interface to the DS2476 coprocessor.
-class DS2476 : public DS28C36 {
-public:
-  DS2476(const Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x76)
-      : DS28C36(sleep, master, address) {}
-
-  /// Generate ECDSA signature.
-  /// @param keyNum Private key to use to create signature.
-  /// Key S cannot be used with this command.
-  /// @param[out] signature Computed signature.
-  MaximInterface_EXPORT error_code
-  generateEcdsaSignature(KeyNum keyNum, Ecc256::Signature & signature);
-
-  /// Compute unique SHA2 secret.
-  /// @param msecretNum Master secret to use in computation.
-  MaximInterface_EXPORT error_code
-  computeSha2UniqueSecret(SecretNum msecretNum);
-
-  /// Compute SHA2 HMAC.
-  /// @param[out] hmac Computed HMAC.
-  MaximInterface_EXPORT error_code computeSha2Hmac(Sha256::Hash & hmac);
-};
-
-/// Enable coprocessor functionality on the DS2476 by writing to the
-/// ROM Options page.
-MaximInterface_EXPORT error_code enableCoprocessor(DS2476 & ds2476);
-
-} // namespace MaximInterface
-
-#endif
+/*******************************************************************************
+* 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.
+*******************************************************************************/
+
+#ifndef MaximInterface_DS28C36_DS2476
+#define MaximInterface_DS28C36_DS2476
+
+#include <stdint.h>
+#include <vector>
+#include <MaximInterface/Links/I2CMaster.hpp>
+#include <MaximInterface/Links/Sleep.hpp>
+#include <MaximInterface/Utilities/array_span.hpp>
+#include <MaximInterface/Utilities/Ecc256.hpp>
+#include <MaximInterface/Utilities/Export.h>
+#include <MaximInterface/Utilities/RomId.hpp>
+#include <MaximInterface/Utilities/ManId.hpp>
+#include <MaximInterface/Utilities/Sha256.hpp>
+#include <MaximInterface/Utilities/system_error.hpp>
+#include <MaximInterface/Utilities/FlagSet.hpp>
+
+namespace MaximInterface {
+
+/// Interface to the DS28C36 authenticator.
+class DS28C36 {
+public:
+  /// Device command results.
+  enum ErrorValue {
+    ProtectionError = 0x55,
+    InvalidParameterError = 0x77,
+    InvalidSequenceError = 0x33,
+    InvalidEcdsaInputOrResultError = 0x22,
+    AuthenticationError = 0x100,
+    InvalidResponseError = 0x101 ///< Response does not match expected format.
+  };
+
+  /// @name Device memory pages
+  /// @{
+  
+  static const int publicKeyAxPage = 16;
+  static const int publicKeyAyPage = 17;
+  static const int publicKeyBxPage = 18;
+  static const int publicKeyByPage = 19;
+  static const int publicKeyCxPage = 20;
+  static const int publicKeyCyPage = 21;
+  static const int privateKeyAPage = 22;
+  static const int privateKeyBPage = 23;
+  static const int privateKeyCPage = 24;
+  static const int secretAPage = 25;
+  static const int secretBPage = 26;
+  static const int decrementCounterPage = 27;
+  static const int romOptionsPage = 28;
+  static const int gpioControlPage = 29;
+  static const int publicKeySxPage = 30;
+  static const int publicKeySyPage = 31;
+  
+  /// @}
+
+  /// Number of memory pages on the device.
+  static const int memoryPages = 32;
+
+  /// Available keys for ECDSA operations.
+  enum KeyNum { KeyNumA = 0, KeyNumB = 1, KeyNumC = 2, KeyNumS = 3 };
+
+  /// Available secrets for HMAC operations.
+  enum SecretNum { SecretNumA = 0, SecretNumB = 1, SecretNumS = 2 };
+
+  /// Data hash type when verifying an ECDSA signature.
+  enum HashType {
+    HashInBuffer = 0, ///< Hash is loaded in the buffer.
+    DataInBuffer = 1, ///< Compute hash from data loaded in the buffer.
+    THASH = 2         ///< Use THASH from Compute Multiblock Hash command.
+  };
+
+  /// Available PIO states when verifying an ECDSA signature.
+  enum PioState { Unchanged, Conducting, HighImpedance };
+
+  /// Holds a device memory page.
+  typedef array_span<uint_least8_t, 32> Page;
+
+  // Format page authentication input data.
+  class PageAuthenticationData;
+
+  // Format authenticated write input data.
+  class WriteAuthenticationData;
+
+  // Format compute secret input data.
+  class ComputeSecretData;
+
+  // Format encryption or decryption HMAC input data.
+  class EncryptionHmacData;
+
+  // Access fields in the ROM Options page.
+  class RomOptions;
+
+  // Access fields in the GPIO Control page.
+  class GpioControl;
+
+  /// Page protection types.
+  enum PageProtectionType {
+    RP = 0x01,   ///< Read protection.
+    WP = 0x02,   ///< Write protection.
+    EM = 0x04,   ///< EPROM emulation mode.
+    APH = 0x08,  ///< Authentication write protection HMAC.
+    EPH = 0x10,  ///< Encryption and authenticated write protection HMAC.
+    AUTH = 0x20, ///< Public Key C is set to authority public key.
+    ECH = 0x40,  ///< Encrypted read and write using shared key from ECDH.
+    ECW = 0x80   ///< Authentication write protection ECDSA.
+  };
+  typedef FlagSet<PageProtectionType, 8> PageProtection;
+
+  /// Challenge for an encrypted device memory page.
+  typedef array_span<uint_least8_t, 8> EncryptionChallenge;
+
+  DS28C36(Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x36)
+      : sleep_(&sleep), master(&master), address_(address & 0xFE) {}
+
+  void setSleep(Sleep & sleep) { sleep_ = &sleep; }
+
+  void setMaster(I2CMaster & master) { this->master = &master; }
+
+  uint_least8_t address() const { return address_; }
+
+  void setAddress(uint_least8_t address) { address_ = address & 0xFE; }
+
+  /// @brief Write memory with no protection.
+  /// @param pageNum Number of page to write.
+  /// @param page Data to write.
+  MaximInterface_EXPORT error_code writeMemory(int pageNum,
+                                               Page::const_span page);
+
+  /// @brief Read memory with no protection.
+  /// @param pageNum Number of page to read.
+  /// @param[out] page Data that was read.
+  MaximInterface_EXPORT error_code readMemory(int pageNum, Page::span page);
+
+  /// @brief Write the temporary buffer.
+  /// @param data Data to write.
+  MaximInterface_EXPORT error_code writeBuffer(span<const uint_least8_t> data);
+
+  /// @brief Read the temporary buffer.
+  /// @param[out] data Data that was read.
+  MaximInterface_EXPORT error_code
+  readBuffer(std::vector<uint_least8_t> & data);
+
+  /// @brief Read the protection settings of a page.
+  /// @param pageNum Number of page to read.
+  /// @param[out] protection Protection that was read.
+  MaximInterface_EXPORT error_code
+  readPageProtection(int pageNum, PageProtection & protection);
+
+  /// @brief Set the protection settings of a page.
+  /// @param pageNum Number of page to write.
+  /// @param protection Protection to write.
+  MaximInterface_EXPORT error_code
+  setPageProtection(int pageNum, const PageProtection & protection);
+
+  /// Decrement the decrement-only counter.
+  MaximInterface_EXPORT error_code decrementCounter();
+
+  /// @brief Read a block of random data from the RNG.
+  /// @param[out] data Random data from RNG with length from 1 to 64.
+  MaximInterface_EXPORT error_code readRng(span<uint_least8_t> data);
+
+  /// @brief Read memory with encryption.
+  /// @param pageNum Number of page to read from.
+  /// @param secretNum Secret to use for encryption.
+  /// @param[out] challenge Encryption challenge that was read.
+  /// @param[out] data Encrypted page data that was read.
+  MaximInterface_EXPORT error_code
+  encryptedReadMemory(int pageNum, SecretNum secretNum,
+                      EncryptionChallenge::span challenge, Page::span data);
+
+  /// @brief Compute and read page authentication with ECDSA.
+  /// @param pageNum Number of page to authenticate.
+  /// @param keyNum
+  /// Private key to use for authentication.
+  /// Key S cannot be used with this command.
+  /// @param[out] signature Computed page signature.
+  MaximInterface_EXPORT error_code computeAndReadPageAuthentication(
+      int pageNum, KeyNum keyNum, Ecc256::Signature::span signature);
+
+  /// @brief Compute and read page authentication with HMAC.
+  /// @param pageNum Number of page to authenticate.
+  /// @param secretNum Secret to use for authentication.
+  /// @param[out] hmac Computed page HMAC.
+  MaximInterface_EXPORT error_code computeAndReadPageAuthentication(
+      int pageNum, SecretNum secretNum, Sha256::Hash::span hmac);
+
+  /// @brief Write with SHA2 authentication.
+  /// @param pageNum Number of page to write.
+  /// @param secretNum Secret to use for authentication.
+  /// @param page Data to write.
+  MaximInterface_EXPORT error_code authenticatedSha2WriteMemory(
+      int pageNum, SecretNum secretNum, Page::const_span page);
+
+  /// @brief Compute SHA2 secret and optionally lock.
+  /// @param pageNum Number of page to use in computation.
+  /// @param msecretNum Master secret to use in computation.
+  /// @param dsecretNum Destination secret to receive the computation result.
+  /// @param writeProtectEnable
+  /// True to lock the destination secret against further writes.
+  MaximInterface_EXPORT error_code
+  computeAndLockSha2Secret(int pageNum, SecretNum msecretNum,
+                           SecretNum dsecretNum, bool writeProtectEnable);
+
+  /// @brief Generate a new ECDSA key pair.
+  /// @param keyNum Key to generate. Key S cannot be used with this command.
+  /// @param writeProtectEnable True to lock the key against further writes.
+  MaximInterface_EXPORT error_code
+  generateEcc256KeyPair(KeyNum keyNum, bool writeProtectEnable);
+
+  /// @brief Compute a hash over multiple blocks.
+  /// @param firstBlock True if this is the first block being hashed.
+  /// @param lastBlock True if this is the last block being hashed.
+  /// @param data
+  /// Data block to hash. Should be 64 bytes unless this is the last block.
+  MaximInterface_EXPORT error_code computeMultiblockHash(
+      bool firstBlock, bool lastBlock, span<const uint_least8_t> data);
+
+  /// @brief Verify ECDSA signature.
+  /// @param keyNum Public key to use for verification.
+  /// @param hashType Source of the data hash input.
+  /// @param signature Signature to verify.
+  /// @param pioa New state of PIOA if verification successful.
+  /// @param piob New state of PIOB if verification successful.
+  MaximInterface_EXPORT error_code verifyEcdsaSignature(
+      KeyNum keyNum, HashType hashType, Ecc256::Signature::const_span signature,
+      PioState pioa = Unchanged, PioState piob = Unchanged);
+
+  /// @brief
+  /// Authenticate a public key for authenticated writes or encrypted reads
+  /// with ECDH.
+  /// @param authWrites True to select authentication for writes.
+  /// @param ecdh True to select ECDH key exchange.
+  /// @param keyNum
+  /// Private key to use for ECDH key exchange. Key A or B can be selected.
+  /// @param csOffset Certificate customization field ending offset in buffer.
+  /// @param signature Signature to use for authentication of public key S.
+  MaximInterface_EXPORT error_code authenticateEcdsaPublicKey(
+      bool authWrites, bool ecdh, KeyNum keyNum, int csOffset,
+      Ecc256::Signature::const_span signature);
+
+  /// @brief Write with ECDSA authentication.
+  /// @param pageNum Number of page to write.
+  /// @param page Data to write.
+  MaximInterface_EXPORT error_code
+  authenticatedEcdsaWriteMemory(int pageNum, Page::const_span page);
+
+  MaximInterface_EXPORT static const error_category & errorCategory();
+
+protected:
+  // Timing constants.
+  static const int generateEcdsaSignatureTimeMs = 50;
+  static const int generateEccKeyPairTimeMs = 100;
+  static const int verifyEsdsaSignatureOrComputeEcdhTimeMs = 150;
+  static const int sha256ComputationTimeMs = 3;
+  static const int readMemoryTimeMs = /*1*/ 2;
+  static const int writeMemoryTimeMs = 15;
+
+  error_code writeCommand(uint_least8_t command,
+                          span<const uint_least8_t> parameters);
+
+  error_code writeCommand(uint_least8_t command) {
+    return writeCommand(command, span<const uint_least8_t>());
+  }
+
+  error_code readVariableLengthResponse(span<uint_least8_t> & response);
+
+  error_code readFixedLengthResponse(span<uint_least8_t> response);
+
+  void sleep(int ms) const { sleep_->invoke(ms); }
+
+private:
+  enum AuthType {
+    HmacWithSecretA = 0,
+    HmacWithSecretB = 1,
+    HmacWithSecretS = 2,
+    EcdsaWithKeyA = 3,
+    EcdsaWithKeyB = 4,
+    EcdsaWithKeyC = 5
+  };
+
+  const Sleep * sleep_;
+  I2CMaster * master;
+  uint_least8_t address_;
+
+  error_code computeAndReadPageAuthentication(int pageNum, AuthType authType);
+};
+
+/// Interface to the DS2476 coprocessor.
+class DS2476 : public DS28C36 {
+public:
+  DS2476(Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x76)
+      : DS28C36(sleep, master, address) {}
+
+  /// @brief Generate ECDSA signature.
+  /// @param keyNum
+  /// Private key to use to create signature.
+  /// Key S cannot be used with this command.
+  /// @param[out] signature Computed signature.
+  MaximInterface_EXPORT error_code
+  generateEcdsaSignature(KeyNum keyNum, Ecc256::Signature::span signature);
+
+  /// @brief Compute unique SHA2 secret.
+  /// @param msecretNum Master secret to use in computation.
+  MaximInterface_EXPORT error_code
+  computeSha2UniqueSecret(SecretNum msecretNum);
+
+  /// @brief Compute SHA2 HMAC.
+  /// @param[out] hmac Computed HMAC.
+  MaximInterface_EXPORT error_code computeSha2Hmac(Sha256::Hash::span hmac);
+};
+
+inline error_code make_error_code(DS28C36::ErrorValue e) {
+  return error_code(e, DS28C36::errorCategory());
+}
+
+/// @brief
+/// Hash arbitrary length data with successive Compute Multiblock Hash commands.
+/// @param ds28c36 Device for computation.
+/// @param data Data to hash.
+MaximInterface_EXPORT error_code
+computeMultiblockHash(DS28C36 & ds28c36, span<const uint_least8_t> data);
+
+/// @brief Verify ECDSA signature.
+/// @param ds28c36 Device for computation.
+/// @param publicKey Public key to use for verification.
+/// @param data Data to verify.
+/// @param signature Signature to verify.
+/// @param pioa New state of PIOA if verification successful.
+/// @param piob New state of PIOB if verification successful.
+MaximInterface_EXPORT error_code verifyEcdsaSignature(
+    DS28C36 & ds28c36, DS28C36::KeyNum publicKey,
+    span<const uint_least8_t> data, Ecc256::Signature::const_span signature,
+    DS28C36::PioState pioa = DS28C36::Unchanged,
+    DS28C36::PioState piob = DS28C36::Unchanged);
+
+/// @brief Verify ECDSA signature.
+/// @param ds28c36 Device for computation.
+/// @param publicKey
+/// Public key to use for verification which is loaded into Public Key S.
+/// @param data Data to verify.
+/// @param signature Signature to verify.
+/// @param pioa New state of PIOA if verification successful.
+/// @param piob New state of PIOB if verification successful.
+MaximInterface_EXPORT error_code verifyEcdsaSignature(
+    DS28C36 & ds28c36, Ecc256::PublicKey::const_span publicKey,
+    span<const uint_least8_t> data, Ecc256::Signature::const_span signature,
+    DS28C36::PioState pioa = DS28C36::Unchanged,
+    DS28C36::PioState piob = DS28C36::Unchanged);
+
+/// @brief
+/// Read the device ROM ID and MAN ID using the Read Memory command on the
+/// ROM Options page.
+/// @param ds28c36 Device to read.
+/// @param[out] romId Read ROM ID valid when operation is successful.
+/// @param[out] manId Read MAN ID valid when operation is successful.
+MaximInterface_EXPORT error_code readRomIdAndManId(DS28C36 & ds28c36,
+                                                   RomId::span romId,
+                                                   ManId::span manId);
+
+/// @brief
+/// Enable coprocessor functionality on the DS2476 by writing to the
+/// GPIO Control page.
+MaximInterface_EXPORT error_code enableCoprocessor(DS2476 & ds2476);
+
+/// @brief
+/// Disable blocking of the ROM ID on the DS2476 by writing to the
+/// ROM Options page.
+MaximInterface_EXPORT error_code enableRomId(DS2476 & ds2476);
+
+/// Format page authentication input data.
+class DS28C36::PageAuthenticationData {
+public:
+  typedef array_span<uint_least8_t,
+                     RomId::size + 2 * Page::size + 1 + ManId::size>
+      Result;
+
+  PageAuthenticationData() : result_() {}
+
+  /// Formatted data result.
+  Result::const_span result() const { return result_; }
+
+  /// @name ROM ID
+  /// @brief 1-Wire ROM ID of the device.
+  /// @{
+  
+  /// Get mutable ROM ID.
+  RomId::span romId() {
+    return make_span(result_).subspan<romIdIdx, RomId::size>();
+  }
+
+  /// Get immutable ROM ID.
+  RomId::const_span romId() const {
+    return const_cast<PageAuthenticationData &>(*this).romId();
+  }
+
+  /// Set ROM ID.
+  PageAuthenticationData & setRomId(RomId::const_span romId) {
+    copy(romId, this->romId());
+    return *this;
+  }
+
+  /// Set ROM ID for use in anonymous mode.
+  MaximInterface_EXPORT PageAuthenticationData & setAnonymousRomId();
+  
+  /// @}
+
+  /// @name Page
+  /// @brief Data from a device memory page.
+  /// @{
+
+  /// Get mutable page.
+  Page::span page() {
+    return make_span(result_).subspan<pageIdx, Page::size>();
+  }
+
+  /// Get immutable page.
+  Page::const_span page() const {
+    return const_cast<PageAuthenticationData &>(*this).page();
+  }
+
+  /// Set page.
+  PageAuthenticationData & setPage(Page::const_span page) {
+    copy(page, this->page());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Challenge
+  /// @brief Random challenge used to prevent replay attacks.
+  /// @{
+  
+  /// Get mutable Challenge.
+  Page::span challenge() {
+    return make_span(result_).subspan<challengeIdx, Page::size>();
+  }
+
+  /// Get immutable Challenge.
+  Page::const_span challenge() const {
+    return const_cast<PageAuthenticationData &>(*this).challenge();
+  }
+
+  /// Set Challenge.
+  PageAuthenticationData & setChallenge(Page::const_span challenge) {
+    copy(challenge, this->challenge());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Page number
+  /// @brief Number of the page to use data from.
+  /// @{
+  
+  /// Get page number.
+  int pageNum() const { return result_[pageNumIdx]; }
+
+  /// Set page number.
+  PageAuthenticationData & setPageNum(int pageNum) {
+    result_[pageNumIdx] = pageNum;
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name MAN ID
+  /// @brief Manufacturer ID of the device.
+  /// @{
+  
+  /// Get mutable MAN ID.
+  ManId::span manId() {
+    return make_span(result_).subspan<manIdIdx, ManId::size>();
+  }
+
+  /// Get immutable MAN ID.
+  ManId::const_span manId() const {
+    return const_cast<PageAuthenticationData &>(*this).manId();
+  }
+
+  /// Set MAN ID.
+  PageAuthenticationData & setManId(ManId::const_span manId) {
+    copy(manId, this->manId());
+    return *this;
+  }
+  
+  /// @}
+
+private:
+  typedef Result::span::index_type index;
+
+  static const index romIdIdx = 0;
+  static const index pageIdx = romIdIdx + RomId::size;
+  static const index challengeIdx = pageIdx + Page::size;
+  static const index pageNumIdx = challengeIdx + Page::size;
+  static const index manIdIdx = pageNumIdx + 1;
+
+  Result::array result_;
+};
+
+/// Format authenticated write input data.
+class DS28C36::WriteAuthenticationData {
+public:
+  typedef PageAuthenticationData::Result Result;
+
+  WriteAuthenticationData() : data() {}
+
+  /// Formatted data result.
+  Result::const_span result() const { return data.result(); }
+
+  /// @name ROM ID
+  /// @brief 1-Wire ROM ID of the device.
+  /// @{
+  
+  /// Get mutable ROM ID.
+  RomId::span romId() { return data.romId(); }
+
+  /// Get immutable ROM ID.
+  RomId::const_span romId() const { return data.romId(); }
+
+  /// Set ROM ID.
+  WriteAuthenticationData & setRomId(RomId::const_span romId) {
+    data.setRomId(romId);
+    return *this;
+  }
+
+  /// Set ROM ID for use in anonymous mode.
+  WriteAuthenticationData & setAnonymousRomId() {
+    data.setAnonymousRomId();
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Old page
+  /// @brief Existing data contained in the page.
+  /// @{
+  
+  /// Get mutable old page.
+  Page::span oldPage() { return data.page(); }
+
+  /// Get immutable old page.
+  Page::const_span oldPage() const { return data.page(); }
+
+  /// Set old page.
+  WriteAuthenticationData & setOldPage(Page::const_span oldPage) {
+    data.setPage(oldPage);
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name New page
+  /// @brief New data to write to the page.
+  /// @{
+  
+  /// Get mutable new page.
+  Page::span newPage() { return data.challenge(); }
+
+  /// Get immutable new page.
+  Page::const_span newPage() const { return data.challenge(); }
+
+  /// Set new page.
+  WriteAuthenticationData & setNewPage(Page::const_span newPage) {
+    data.setChallenge(newPage);
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Page number
+  /// @brief Page number for write operation.
+  /// @{
+
+  /// Get page number.
+  int pageNum() const { return data.pageNum(); }
+
+  /// Set page number.
+  WriteAuthenticationData & setPageNum(int pageNum) {
+    data.setPageNum(pageNum);
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name MAN ID
+  /// @brief Manufacturer ID of the device.
+  /// @{
+
+  /// Get mutable MAN ID.
+  ManId::span manId() { return data.manId(); }
+
+  /// Get immutable MAN ID.
+  ManId::const_span manId() const { return data.manId(); }
+
+  /// Set MAN ID.
+  WriteAuthenticationData & setManId(ManId::const_span manId) {
+    data.setManId(manId);
+    return *this;
+  }
+  
+  /// @}
+
+private:
+  PageAuthenticationData data;
+};
+
+/// Format compute secret input data.
+class DS28C36::ComputeSecretData {
+public:
+  typedef PageAuthenticationData::Result Result;
+
+  ComputeSecretData() : data() {}
+
+  /// Formatted data result.
+  Result::const_span result() const { return data.result(); }
+
+  /// @name ROM ID
+  /// @brief 1-Wire ROM ID of the device.
+  /// @{
+  
+  /// Get mutable ROM ID.
+  RomId::span romId() { return data.romId(); }
+
+  /// Get immutable ROM ID.
+  RomId::const_span romId() const { return data.romId(); }
+
+  /// Set ROM ID.
+  ComputeSecretData & setRomId(RomId::const_span romId) {
+    data.setRomId(romId);
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Binding Data
+  /// @brief Binding Data contained in the selected page.
+  /// @{
+  
+  /// Get mutable Binding Data.
+  Page::span bindingData() { return data.page(); }
+
+  /// Get immutable Binding Data.
+  Page::const_span bindingData() const { return data.page(); }
+
+  /// Set Binding Data.
+  ComputeSecretData & setBindingData(Page::const_span bindingData) {
+    data.setPage(bindingData);
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Partial Secret
+  /// @brief Partial Secret used for customization.
+  /// @{
+  
+  /// Get mutable Partial Secret.
+  Page::span partialSecret() { return data.challenge(); }
+
+  /// Get immutable Partial Secret.
+  Page::const_span partialSecret() const { return data.challenge(); }
+
+  /// Set Partial Secret.
+  ComputeSecretData & setPartialSecret(Page::const_span partialSecret) {
+    data.setChallenge(partialSecret);
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Page number
+  /// @brief Page number for Binding Data.
+  /// @{
+  
+  /// Get page number.
+  int pageNum() const { return data.pageNum(); }
+
+  /// Set page number.
+  ComputeSecretData & setPageNum(int pageNum) {
+    data.setPageNum(pageNum);
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name MAN ID
+  /// @brief Manufacturer ID of the device.
+  /// @{
+  
+  /// Get mutable MAN ID.
+  ManId::span manId() { return data.manId(); }
+
+  /// Get immutable MAN ID.
+  ManId::const_span manId() const { return data.manId(); }
+
+  /// Set MAN ID.
+  ComputeSecretData & setManId(ManId::const_span manId) {
+    data.setManId(manId);
+    return *this;
+  }
+  
+  /// @}
+
+private:
+  PageAuthenticationData data;
+};
+
+/// Format encryption or decryption HMAC input data.
+class DS28C36::EncryptionHmacData {
+public:
+  typedef array_span<uint_least8_t,
+                     EncryptionChallenge::size + RomId::size + 1 + ManId::size>
+      Result;
+
+  EncryptionHmacData() : result_() {}
+
+  /// Formatted data result.
+  Result::const_span result() const { return result_; }
+
+  /// @name Encryption Challenge
+  /// @brief Random challenge used to prevent replay attacks.
+  /// @{
+  
+  /// Get mutable Encryption Challenge.
+  EncryptionChallenge::span encryptionChallenge() {
+    return make_span(result_)
+        .subspan<encryptionChallengeIdx, EncryptionChallenge::size>();
+  }
+
+  /// Get immutable Encryption Challenge.
+  EncryptionChallenge::const_span encryptionChallenge() const {
+    return const_cast<EncryptionHmacData &>(*this).encryptionChallenge();
+  }
+
+  /// Set Encryption Challenge.
+  EncryptionHmacData &
+  setEncryptionChallenge(EncryptionChallenge::const_span encryptionChallenge) {
+    copy(encryptionChallenge, this->encryptionChallenge());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name ROM ID
+  /// @brief 1-Wire ROM ID of the device.
+  /// @{
+  
+  /// Get mutable ROM ID.
+  RomId::span romId() {
+    return make_span(result_).subspan<romIdIdx, RomId::size>();
+  }
+
+  /// Get immutable ROM ID.
+  RomId::const_span romId() const {
+    return const_cast<EncryptionHmacData &>(*this).romId();
+  }
+
+  /// Set ROM ID.
+  EncryptionHmacData & setRomId(RomId::const_span romId) {
+    copy(romId, this->romId());
+    return *this;
+  }
+
+  /// Set ROM ID for use in anonymous mode.
+  MaximInterface_EXPORT EncryptionHmacData & setAnonymousRomId();
+  
+  /// @}
+
+  /// @name Page number
+  /// @brief Number of the page to use data from.
+  /// @{
+  
+  /// Get page number.
+  int pageNum() const { return result_[pageNumIdx]; }
+
+  /// Set page number.
+  EncryptionHmacData & setPageNum(int pageNum) {
+    result_[pageNumIdx] = pageNum;
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name MAN ID
+  /// @brief Manufacturer ID of the device.
+  /// @{
+
+  /// Get mutable MAN ID.
+  ManId::span manId() {
+    return make_span(result_).subspan<manIdIdx, ManId::size>();
+  }
+
+  /// Get immutable MAN ID.
+  ManId::const_span manId() const {
+    return const_cast<EncryptionHmacData &>(*this).manId();
+  }
+
+  /// Set MAN ID.
+  EncryptionHmacData & setManId(ManId::const_span manId) {
+    copy(manId, this->manId());
+    return *this;
+  }
+  
+  /// @}
+
+private:
+  typedef Result::span::index_type index;
+
+  static const index encryptionChallengeIdx = 0;
+  static const index romIdIdx =
+      encryptionChallengeIdx + EncryptionChallenge::size;
+  static const index pageNumIdx = romIdIdx + RomId::size;
+  static const index manIdIdx = pageNumIdx + 1;
+
+  Result::array result_;
+};
+
+/// Access fields in the ROM Options page.
+class DS28C36::RomOptions {
+public:
+  explicit RomOptions(Page::span page) : page(page) {}
+
+  bool romBlockDisable() const {
+    return page[romBlockDisableIdx] == enabledValue;
+  }
+  
+  RomOptions & setRomBlockDisable(bool romBlockDisable) {
+    page[romBlockDisableIdx] = (romBlockDisable ? enabledValue : 0);
+    return *this;
+  }
+  
+  bool anonymous() const { return page[anonymousIdx] == enabledValue; }
+
+  RomOptions & setAnonymous(bool anonymous) {
+    page[anonymousIdx] = (anonymous ? enabledValue : 0);
+    return *this;
+  }
+
+  ManId::const_span manId() const {
+    return page.subspan<22, ManId::size>();
+  }
+
+  RomId::const_span romId() const {
+    return page.subspan<24, RomId::size>();
+  }
+
+private:
+  static const Page::span::index_type romBlockDisableIdx = 0;
+  static const Page::span::index_type anonymousIdx = 1;
+  static const Page::span::value_type enabledValue = 0xAA;
+
+  Page::span page;
+};
+
+/// Access fields in the GPIO Control page.
+class DS28C36::GpioControl {
+public:
+  explicit GpioControl(Page::span page) : page(page) {}
+
+  bool pioaConducting() const {
+    return page[pioaConductingIdx] == pioConductingValue;
+  }
+
+  GpioControl & setPioaConducting(bool pioaConducting) {
+    page[pioaConductingIdx] = (pioaConducting ? pioConductingValue : 0x55);
+    return *this;
+  }
+
+  bool piobConducting() const {
+    return page[piobConductingIdx] == pioConductingValue;
+  }
+
+  GpioControl & setPiobConducting(bool piobConducting) {
+    page[piobConductingIdx] = (piobConducting ? pioConductingValue : 0x55);
+    return *this;
+  }
+
+  bool pioaLevel() const { return page[2] == pioLevelValue; }
+
+  bool piobLevel() const { return page[3] == pioLevelValue; }
+
+private:
+  static const Page::span::index_type pioaConductingIdx = 0;
+  static const Page::span::index_type piobConductingIdx = 1;
+  static const Page::span::value_type pioConductingValue = 0xAA;
+  static const Page::span::value_type pioLevelValue = 0x55;
+
+  Page::span page;
+};
+
+} // namespace MaximInterface
+
+#endif
--- a/Devices/DS28E15_22_25.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS28E15_22_25.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -31,29 +31,28 @@
 *******************************************************************************/
 
 #include <algorithm>
-#include "DS28E15_22_25.hpp"
 #include <MaximInterface/Utilities/crc.hpp>
 #include <MaximInterface/Utilities/Error.hpp>
-
-using std::copy;
+#include "DS28E15_22_25.hpp"
 
 namespace MaximInterface {
 
 using namespace Sha256;
+using std::copy;
 
 static const int shaComputationDelayMs = 3;
 static const int eepromWriteDelayMs = 10;
 static inline int secretEepromWriteDelayMs(bool lowPower) {
   return lowPower ? 200 : 100;
 }
+
 static const int ds28e22_25_pagesPerBlock = 2;
 
 static error_code
-writeDataWithCrc(OneWireMaster & master, const uint_least8_t * data,
-                 size_t dataLen,
+writeDataWithCrc(OneWireMaster & master, span<const uint_least8_t> data,
                  OneWireMaster::Level level = OneWireMaster::NormalLevel,
                  uint_fast16_t crcStart = 0) {
-  error_code result = master.writeBlock(data, dataLen);
+  error_code result = master.writeBlock(data);
   if (result) {
     return result;
   }
@@ -66,13 +65,20 @@
   if (result) {
     return result;
   }
-  if (calculateCrc16(response, sizeof(response) / sizeof(response[0]),
-                     calculateCrc16(data, dataLen, crcStart)) != 0xB001) {
+  if (calculateCrc16(response, calculateCrc16(data, crcStart)) != 0xB001) {
     result = make_error_code(DS28E15_22_25::CrcError);
   }
   return result;
 }
 
+const int DS28E15_22_25::segmentsPerPage;
+
+DS28E15_22_25::AuthenticationData &
+DS28E15_22_25::AuthenticationData::setAnonymousRomId() {
+  std::fill(romId().begin(), romId().end(), 0xFF);
+  return *this;
+}
+
 error_code
 DS28E15_22_25::writeCommandWithCrc(Command command, uint_least8_t parameter,
                                    OneWireMaster::Level level) const {
@@ -80,26 +86,23 @@
   if (!result) {
     const uint_least8_t data[] = {static_cast<uint_least8_t>(command),
                                   parameter};
-    result =
-        writeDataWithCrc(*master, data, sizeof(data) / sizeof(data[0]), level);
+    result = writeDataWithCrc(*master, data);
   }
   return result;
 }
 
-static error_code readDataWithCrc(OneWireMaster & master, uint_least8_t * data,
-                                  size_t dataLen) {
-  error_code result = master.readBlock(data, dataLen);
+static error_code readDataWithCrc(OneWireMaster & master,
+                                  span<uint_least8_t> data) {
+  error_code result = master.readBlock(data);
   if (result) {
     return result;
   }
   uint_least8_t response[2];
-  const size_t responseLen = sizeof(response) / sizeof(response[0]);
-  result = master.readBlock(response, responseLen);
+  result = master.readBlock(response);
   if (result) {
     return result;
   }
-  if (calculateCrc16(response, responseLen, calculateCrc16(data, dataLen)) !=
-      0xB001) {
+  if (calculateCrc16(response, calculateCrc16(data)) != 0xB001) {
     result = make_error_code(DS28E15_22_25::CrcError);
   }
   return result;
@@ -117,7 +120,7 @@
   return result;
 }
 
-static error_code releaseSequence(OneWireMaster & master, const Sleep & sleep,
+static error_code releaseSequence(OneWireMaster & master, Sleep & sleep,
                                   int delayTimeMs) {
   error_code result = master.writeBytePower(0xAA);
   if (result) {
@@ -131,21 +134,11 @@
   return readCsByte(master);
 }
 
-DS28E15_22_25::BlockProtection::BlockProtection(bool readProtection,
-                                                bool writeProtection,
-                                                bool eepromEmulation,
-                                                bool authProtection,
-                                                int blockNum) {
-  setReadProtection(readProtection);
-  setWriteProtection(writeProtection);
-  setEepromEmulation(eepromEmulation);
-  setAuthProtection(authProtection);
-  setBlockNum(blockNum);
-}
-
-void DS28E15_22_25::BlockProtection::setBlockNum(int blockNum) {
+DS28E15_22_25::BlockProtection &
+DS28E15_22_25::BlockProtection::setBlockNum(int blockNum) {
   status &= ~blockNumMask;
   status |= (blockNum & blockNumMask);
+  return *this;
 }
 
 bool DS28E15_22_25::BlockProtection::noProtection() const {
@@ -153,41 +146,78 @@
          !authProtection();
 }
 
-void DS28E15_22_25::BlockProtection::setReadProtection(bool readProtection) {
+DS28E15_22_25::BlockProtection &
+DS28E15_22_25::BlockProtection::setReadProtection(bool readProtection) {
   if (readProtection) {
     status |= readProtectionMask;
   } else {
     status &= ~readProtectionMask;
   }
+  return *this;
 }
 
-void DS28E15_22_25::BlockProtection::setWriteProtection(bool writeProtection) {
+DS28E15_22_25::BlockProtection &
+DS28E15_22_25::BlockProtection::setWriteProtection(bool writeProtection) {
   if (writeProtection) {
     status |= writeProtectionMask;
   } else {
     status &= ~writeProtectionMask;
   }
+  return *this;
 }
 
-void DS28E15_22_25::BlockProtection::setEepromEmulation(bool eepromEmulation) {
+DS28E15_22_25::BlockProtection &
+DS28E15_22_25::BlockProtection::setEepromEmulation(bool eepromEmulation) {
   if (eepromEmulation) {
     status |= eepromEmulationMask;
   } else {
     status &= ~eepromEmulationMask;
   }
+  return *this;
 }
 
-void DS28E15_22_25::BlockProtection::setAuthProtection(bool authProtection) {
+DS28E15_22_25::BlockProtection &
+DS28E15_22_25::BlockProtection::setAuthProtection(bool authProtection) {
   if (authProtection) {
     status |= authProtectionMask;
   } else {
     status &= ~authProtectionMask;
   }
+  return *this;
+}
+
+DS28E15_22_25::ProtectionWriteMacData::ProtectionWriteMacData()
+    : result_(), oldProtection_(), newProtection_() {
+  setOldProtection(oldProtection_);
+  setNewProtection(newProtection_);
+}
+
+DS28E15_22_25::ProtectionWriteMacData &
+DS28E15_22_25::ProtectionWriteMacData::setOldProtection(
+    BlockProtection oldProtection) {
+  result_[oldProtectionIdx] = oldProtection.authProtection() ? 1 : 0;
+  result_[oldProtectionIdx + 1] = oldProtection.eepromEmulation() ? 1 : 0;
+  result_[oldProtectionIdx + 2] = oldProtection.writeProtection() ? 1 : 0;
+  result_[oldProtectionIdx + 3] = oldProtection.readProtection() ? 1 : 0;
+  oldProtection_ = oldProtection;
+  return *this;
+}
+
+DS28E15_22_25::ProtectionWriteMacData &
+DS28E15_22_25::ProtectionWriteMacData::setNewProtection(
+    BlockProtection newProtection) {
+  result_[blockNumIdx] = newProtection.blockNum();
+  result_[newProtectionIdx] = newProtection.authProtection() ? 1 : 0;
+  result_[newProtectionIdx + 1] = newProtection.eepromEmulation() ? 1 : 0;
+  result_[newProtectionIdx + 2] = newProtection.writeProtection() ? 1 : 0;
+  result_[newProtectionIdx + 3] = newProtection.readProtection() ? 1 : 0;
+  newProtection_ = newProtection;
+  return *this;
 }
 
 error_code
-DS28E15_22_25::writeAuthBlockProtection(const BlockProtection & newProtection,
-                                        const Hash & mac) {
+DS28E15_22_25::writeAuthBlockProtection(BlockProtection newProtection,
+                                        Hash::const_span mac) {
   error_code result =
       writeCommandWithCrc(AuthWriteBlockProtection, newProtection.statusByte(),
                           OneWireMaster::StrongLevel);
@@ -195,13 +225,13 @@
     return result;
   }
 
-  (*sleep)(shaComputationDelayMs);
+  sleep->invoke(shaComputationDelayMs);
   result = master->setLevel(OneWireMaster::NormalLevel);
   if (result) {
     return result;
   }
 
-  result = writeDataWithCrc(*master, mac.data(), mac.size());
+  result = writeDataWithCrc(*master, mac);
   if (result) {
     return result;
   }
@@ -215,8 +245,7 @@
   return result;
 }
 
-error_code
-DS28E15_22_25::writeBlockProtection(const BlockProtection & protection) {
+error_code DS28E15_22_25::writeBlockProtection(BlockProtection protection) {
   error_code result =
       writeCommandWithCrc(WriteBlockProtection, protection.statusByte());
   if (result) {
@@ -244,33 +273,8 @@
   return result;
 }
 
-AuthMacData DS28E15_22_25::createAuthMacData(const Page & pageData, int pageNum,
-                                             const Scratchpad & challenge,
-                                             const RomId & romId,
-                                             const ManId & manId) {
-  AuthMacData authMacData;
-  AuthMacData::iterator authMacDataIt = authMacData.begin();
-  authMacDataIt = copy(pageData.begin(), pageData.end(), authMacDataIt);
-  authMacDataIt = copy(challenge.begin(), challenge.end(), authMacDataIt);
-  authMacDataIt = copy(romId.begin(), romId.end(), authMacDataIt);
-  *authMacDataIt = manId[1];
-  *(++authMacDataIt) = manId[0];
-  *(++authMacDataIt) = pageNum;
-  *(++authMacDataIt) = 0x00;
-  return authMacData;
-}
-
-AuthMacData DS28E15_22_25::createAnonAuthMacData(const Page & pageData,
-                                                 int pageNum,
-                                                 const Scratchpad & challenge,
-                                                 const ManId & manId) {
-  RomId romId;
-  romId.fill(0xFF);
-  return createAuthMacData(pageData, pageNum, challenge, romId, manId);
-}
-
 error_code DS28E15_22_25::computeReadPageMac(int page_num, bool anon,
-                                             Hash & mac) const {
+                                             Hash::span mac) const {
   error_code result =
       writeCommandWithCrc(ComputePageMac, (anon ? 0xE0 : 0x00) | page_num,
                           OneWireMaster::StrongLevel);
@@ -278,7 +282,7 @@
     return result;
   }
 
-  (*sleep)(shaComputationDelayMs * 2);
+  sleep->invoke(shaComputationDelayMs * 2);
   result = master->setLevel(OneWireMaster::NormalLevel);
   if (result) {
     return result;
@@ -289,7 +293,7 @@
     return result;
   }
 
-  result = readDataWithCrc(*master, mac.data(), mac.size());
+  result = readDataWithCrc(*master, mac);
   return result;
 }
 
@@ -307,7 +311,7 @@
   return result;
 }
 
-error_code DS28E15_22_25::doWriteScratchpad(const Scratchpad & data,
+error_code DS28E15_22_25::doWriteScratchpad(Scratchpad::const_span data,
                                             Variant variant) {
   const uint_least8_t parameter =
       (variant == DS28E22 || variant == DS28E25) ? 0x20 : 0x00;
@@ -316,11 +320,11 @@
     return result;
   }
 
-  result = writeDataWithCrc(*master, data.data(), data.size());
+  result = writeDataWithCrc(*master, data);
   return result;
 }
 
-error_code DS28E15_22_25::doReadScratchpad(Scratchpad & data,
+error_code DS28E15_22_25::doReadScratchpad(Scratchpad::span data,
                                            Variant variant) const {
   const uint_least8_t parameter =
       (variant == DS28E22 || variant == DS28E25) ? 0x2F : 0x0F;
@@ -329,7 +333,7 @@
     return result;
   }
 
-  result = readDataWithCrc(*master, data.data(), data.size());
+  result = readDataWithCrc(*master, data);
   return result;
 }
 
@@ -344,7 +348,7 @@
   return result;
 }
 
-error_code DS28E15_22_25::readPage(int page, Page & rdbuf) const {
+error_code DS28E15_22_25::readPage(int page, Page::span rdbuf) const {
   error_code result = writeCommandWithCrc(ReadMemory, page);
   if (result) {
     return result;
@@ -354,31 +358,31 @@
   return result;
 }
 
-error_code DS28E15_22_25::continueReadPage(Page & rdbuf) const {
-  return readDataWithCrc(*master, rdbuf.data(), rdbuf.size());
+error_code DS28E15_22_25::continueReadPage(Page::span rdbuf) const {
+  return readDataWithCrc(*master, rdbuf);
 }
 
-error_code DS28E15_22_25::doWriteAuthSegment(const Segment & newData,
-                                             const Hash & mac, Variant variant,
-                                             bool continuing) {
+error_code DS28E15_22_25::doWriteAuthSegment(Segment::const_span newData,
+                                             Hash::const_span mac,
+                                             Variant variant, bool continuing) {
   // CRC gets calculated with CS byte when continuing on DS28E22 and DS28E25.
   const uint_fast16_t crcStart =
       ((variant == DS28E22 || variant == DS28E25) && continuing)
           ? calculateCrc16(0xAA)
           : 0;
-  error_code result = writeDataWithCrc(*master, newData.data(), newData.size(),
-                                       OneWireMaster::StrongLevel, crcStart);
+  error_code result =
+      writeDataWithCrc(*master, newData, OneWireMaster::StrongLevel, crcStart);
   if (result) {
     return result;
   }
 
-  (*sleep)(shaComputationDelayMs);
+  sleep->invoke(shaComputationDelayMs);
   result = master->setLevel(OneWireMaster::NormalLevel);
   if (result) {
     return result;
   }
 
-  result = writeDataWithCrc(*master, mac.data(), mac.size());
+  result = writeDataWithCrc(*master, mac);
   if (result) {
     return result;
   }
@@ -393,8 +397,8 @@
 }
 
 error_code DS28E15_22_25::doWriteAuthSegment(int pageNum, int segmentNum,
-                                             const Segment & newData,
-                                             const Hash & mac,
+                                             Segment::const_span newData,
+                                             Hash::const_span mac,
                                              Variant variant) {
   error_code result =
       writeCommandWithCrc(AuthWriteMemory, (segmentNum << 5) | pageNum);
@@ -406,67 +410,13 @@
   return result;
 }
 
-error_code DS28E15_22_25::doContinueWriteAuthSegment(const Segment & newData,
-                                                     const Hash & mac,
-                                                     Variant variant) {
+error_code DS28E15_22_25::doContinueWriteAuthSegment(
+    Segment::const_span newData, Hash::const_span mac, Variant variant) {
   return doWriteAuthSegment(newData, mac, variant, true);
 }
 
-WriteMacData DS28E15_22_25::createSegmentWriteMacData(
-    int pageNum, int segmentNum, const Segment & newData,
-    const Segment & oldData, const RomId & romId, const ManId & manId) {
-  WriteMacData MT;
-
-  // insert ROM number
-  copy(romId.begin(), romId.end(), MT.begin());
-
-  MT[11] = segmentNum;
-  MT[10] = pageNum;
-  MT[9] = manId[0];
-  MT[8] = manId[1];
-
-  // insert old data
-  copy(oldData.begin(), oldData.end(), MT.begin() + 12);
-
-  // insert new data
-  copy(newData.begin(), newData.end(), MT.begin() + 16);
-
-  return MT;
-}
-
-WriteMacData DS28E15_22_25::createProtectionWriteMacData(
-    const BlockProtection & newProtection,
-    const BlockProtection & oldProtection, const RomId & romId,
-    const ManId & manId) {
-  WriteMacData MT;
-
-  // insert ROM number
-  copy(romId.begin(), romId.end(), MT.begin());
-
-  // instert block and page
-  MT[11] = 0;
-  MT[10] = newProtection.blockNum();
-
-  MT[9] = manId[0];
-  MT[8] = manId[1];
-
-  // old data
-  MT[12] = oldProtection.authProtection() ? 0x01 : 0x00;
-  MT[13] = oldProtection.eepromEmulation() ? 0x01 : 0x00;
-  MT[14] = oldProtection.writeProtection() ? 0x01 : 0x00;
-  MT[15] = oldProtection.readProtection() ? 0x01 : 0x00;
-  // new data
-  MT[16] = newProtection.authProtection() ? 0x01 : 0x00;
-  MT[17] = newProtection.eepromEmulation() ? 0x01 : 0x00;
-  MT[18] = newProtection.writeProtection() ? 0x01 : 0x00;
-  MT[19] = newProtection.readProtection() ? 0x01 : 0x00;
-
-  // compute the mac
-  return MT;
-}
-
 error_code DS28E15_22_25::readSegment(int page, int segment,
-                                      Segment & data) const {
+                                      Segment::span data) const {
   error_code result = writeCommandWithCrc(ReadMemory, (segment << 5) | page);
   if (result) {
     return result;
@@ -476,12 +426,12 @@
   return result;
 }
 
-error_code DS28E15_22_25::continueReadSegment(Segment & data) const {
-  return master->readBlock(data.data(), data.size());
+error_code DS28E15_22_25::continueReadSegment(Segment::span data) const {
+  return master->readBlock(data);
 }
 
 error_code DS28E15_22_25::writeSegment(int page, int block,
-                                       const Segment & data) {
+                                       Segment::const_span data) {
   error_code result = writeCommandWithCrc(WriteMemory, (block << 5) | page);
   if (result) {
     return result;
@@ -491,8 +441,8 @@
   return result;
 }
 
-error_code DS28E15_22_25::continueWriteSegment(const Segment & data) {
-  error_code result = writeDataWithCrc(*master, data.data(), data.size());
+error_code DS28E15_22_25::continueWriteSegment(Segment::const_span data) {
+  error_code result = writeDataWithCrc(*master, data);
   if (result) {
     return result;
   }
@@ -501,55 +451,37 @@
   return result;
 }
 
-SlaveSecretData
-DS28E15_22_25::createSlaveSecretData(const Page & bindingPage,
-                                     int bindingPageNum,
-                                     const Scratchpad & partialSecret,
-                                     const RomId & romId, const ManId & manId) {
-  SlaveSecretData slaveSecretData;
-  SlaveSecretData::iterator slaveSecretDataIt = slaveSecretData.begin();
-  slaveSecretDataIt =
-      copy(bindingPage.begin(), bindingPage.end(), slaveSecretDataIt);
-  slaveSecretDataIt =
-      copy(partialSecret.begin(), partialSecret.end(), slaveSecretDataIt);
-  slaveSecretDataIt = copy(romId.begin(), romId.end(), slaveSecretDataIt);
-  *slaveSecretDataIt = manId[1];
-  *(++slaveSecretDataIt) = manId[0];
-  *(++slaveSecretDataIt) = bindingPageNum;
-  *(++slaveSecretDataIt) = 0x00;
-  return slaveSecretData;
-}
-
-error_code DS28E15_22_25::doReadAllBlockProtection(BlockProtection * protection,
-                                                   const size_t protectionLen,
-                                                   Variant variant) const {
+error_code
+DS28E15_22_25::doReadAllBlockProtection(span<BlockProtection> protection,
+                                        Variant variant) const {
   error_code result = writeCommandWithCrc(ReadStatus, 0);
   if (!result) {
     if (variant == DS28E22 || variant == DS28E25) {
       // Need to read extra data on DS28E22 to get CRC16.
       uint_least8_t buf[DS28E25::memoryPages];
-      result = readDataWithCrc(*master, buf, DS28E25::memoryPages);
+      result = readDataWithCrc(*master, buf);
       if (!result) {
         const int blocks = ((variant == DS28E22) ? DS28E22::memoryPages
                                                  : DS28E25::memoryPages) /
                            ds28e22_25_pagesPerBlock;
-        for (size_t i = 0;
-             i < std::min(protectionLen, static_cast<size_t>(blocks)); i++) {
+        for (span<BlockProtection>::index_type i = 0;
+             i < std::min<span<BlockProtection>::index_type>(protection.size(),
+                                                             blocks);
+             ++i) {
           protection[i].setStatusByte(
               (buf[i * ds28e22_25_pagesPerBlock] & 0xF0) | // Upper nibble
               ((buf[i * ds28e22_25_pagesPerBlock] & 0x0F) /
                ds28e22_25_pagesPerBlock)); // Lower nibble
         }
       }
-    } else // DS28E15
-    {
+    } else { // DS28E15
       uint_least8_t buf[DS28E15::protectionBlocks];
-      result = readDataWithCrc(*master, buf, DS28E15::protectionBlocks);
+      result = readDataWithCrc(*master, buf);
       if (!result) {
-        for (size_t i = 0;
-             i < std::min(protectionLen,
-                          static_cast<size_t>(DS28E15::protectionBlocks));
-             i++) {
+        for (span<BlockProtection>::index_type i = 0;
+             i < std::min<span<BlockProtection>::index_type>(
+                     protection.size(), DS28E15::protectionBlocks);
+             ++i) {
           protection[i].setStatusByte(buf[i]);
         }
       }
@@ -592,8 +524,8 @@
 error_code DS28E15_22_25::readPersonality(Personality & personality) const {
   error_code result = writeCommandWithCrc(ReadStatus, 0xE0);
   if (!result) {
-    array<uint_least8_t, 4> data;
-    result = readDataWithCrc(*master, data.data(), data.size());
+    uint_least8_t data[4];
+    result = readDataWithCrc(*master, data);
     if (!result) {
       personality.PB1 = data[0];
       personality.PB2 = data[1];
@@ -604,11 +536,14 @@
   return result;
 }
 
-error_code DS28EL15::writeScratchpad(const Scratchpad & data) {
+const int DS28EL15::memoryPages;
+const int DS28EL15::protectionBlocks;
+
+error_code DS28EL15::writeScratchpad(Scratchpad::const_span data) {
   return doWriteScratchpad(data, DS28E15);
 }
 
-error_code DS28EL15::readScratchpad(Scratchpad & data) const {
+error_code DS28EL15::readScratchpad(Scratchpad::span data) const {
   return doReadScratchpad(data, DS28E15);
 }
 
@@ -618,20 +553,19 @@
 }
 
 error_code DS28EL15::writeAuthSegment(int pageNum, int segmentNum,
-                                      const Segment & newData,
-                                      const Hash & mac) {
+                                      Segment::const_span newData,
+                                      Hash::const_span mac) {
   return doWriteAuthSegment(pageNum, segmentNum, newData, mac, DS28E15);
 }
 
-error_code DS28EL15::continueWriteAuthSegment(const Segment & newData,
-                                              const Hash & mac) {
+error_code DS28EL15::continueWriteAuthSegment(Segment::const_span newData,
+                                              Hash::const_span mac) {
   return doContinueWriteAuthSegment(newData, mac, DS28E15);
 }
 
 error_code DS28EL15::readAllBlockProtection(
-    array<BlockProtection, protectionBlocks> & protection) const {
-  return doReadAllBlockProtection(protection.data(), protection.size(),
-                                  DS28E15);
+    span<BlockProtection, protectionBlocks> protection) const {
+  return doReadAllBlockProtection(protection, DS28E15);
 }
 
 error_code DS28E15::loadSecret(bool lock) { return doLoadSecret(lock, false); }
@@ -640,11 +574,14 @@
   return doComputeSecret(pageNum, lock, false);
 }
 
-error_code DS28EL22::writeScratchpad(const Scratchpad & data) {
+const int DS28EL22::memoryPages;
+const int DS28EL22::protectionBlocks;
+
+error_code DS28EL22::writeScratchpad(Scratchpad::const_span data) {
   return doWriteScratchpad(data, DS28E22);
 }
 
-error_code DS28EL22::readScratchpad(Scratchpad & data) const {
+error_code DS28EL22::readScratchpad(Scratchpad::span data) const {
   return doReadScratchpad(data, DS28E22);
 }
 
@@ -654,20 +591,19 @@
 }
 
 error_code DS28EL22::writeAuthSegment(int pageNum, int segmentNum,
-                                      const Segment & newData,
-                                      const Hash & mac) {
+                                      Segment::const_span newData,
+                                      Hash::const_span mac) {
   return doWriteAuthSegment(pageNum, segmentNum, newData, mac, DS28E22);
 }
 
-error_code DS28EL22::continueWriteAuthSegment(const Segment & newData,
-                                              const Hash & mac) {
+error_code DS28EL22::continueWriteAuthSegment(Segment::const_span newData,
+                                              Hash::const_span mac) {
   return doContinueWriteAuthSegment(newData, mac, DS28E22);
 }
 
 error_code DS28EL22::readAllBlockProtection(
-    array<BlockProtection, protectionBlocks> & protection) const {
-  return doReadAllBlockProtection(protection.data(), protection.size(),
-                                  DS28E22);
+    span<BlockProtection, protectionBlocks> protection) const {
+  return doReadAllBlockProtection(protection, DS28E22);
 }
 
 error_code DS28E22::loadSecret(bool lock) { return doLoadSecret(lock, false); }
@@ -676,11 +612,14 @@
   return doComputeSecret(pageNum, lock, false);
 }
 
-error_code DS28EL25::writeScratchpad(const Scratchpad & data) {
+const int DS28EL25::memoryPages;
+const int DS28EL25::protectionBlocks;
+
+error_code DS28EL25::writeScratchpad(Scratchpad::const_span data) {
   return doWriteScratchpad(data, DS28E25);
 }
 
-error_code DS28EL25::readScratchpad(Scratchpad & data) const {
+error_code DS28EL25::readScratchpad(Scratchpad::span data) const {
   return doReadScratchpad(data, DS28E25);
 }
 
@@ -690,20 +629,19 @@
 }
 
 error_code DS28EL25::writeAuthSegment(int pageNum, int segmentNum,
-                                      const Segment & newData,
-                                      const Hash & mac) {
+                                      Segment::const_span newData,
+                                      Hash::const_span mac) {
   return doWriteAuthSegment(pageNum, segmentNum, newData, mac, DS28E25);
 }
 
-error_code DS28EL25::continueWriteAuthSegment(const Segment & newData,
-                                              const Hash & mac) {
+error_code DS28EL25::continueWriteAuthSegment(Segment::const_span newData,
+                                              Hash::const_span mac) {
   return doContinueWriteAuthSegment(newData, mac, DS28E25);
 }
 
 error_code DS28EL25::readAllBlockProtection(
-    array<BlockProtection, protectionBlocks> & protection) const {
-  return doReadAllBlockProtection(protection.data(), protection.size(),
-                                  DS28E25);
+    span<BlockProtection, protectionBlocks> protection) const {
+  return doReadAllBlockProtection(protection, DS28E25);
 }
 
 error_code DS28E25::loadSecret(bool lock) { return doLoadSecret(lock, false); }
--- a/Devices/DS28E15_22_25.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS28E15_22_25.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -33,16 +33,18 @@
 #ifndef MaximInterface_DS28E15_22_25
 #define MaximInterface_DS28E15_22_25
 
+#include <stdint.h>
 #include <MaximInterface/Links/OneWireMaster.hpp>
 #include <MaximInterface/Links/SelectRom.hpp>
 #include <MaximInterface/Links/Sleep.hpp>
-#include <MaximInterface/Utilities/array.hpp>
+#include <MaximInterface/Utilities/array_span.hpp>
 #include <MaximInterface/Utilities/Export.h>
 #include <MaximInterface/Utilities/ManId.hpp>
 #include <MaximInterface/Utilities/Sha256.hpp>
 
 namespace MaximInterface {
 
+/// @brief
 /// Interface to the DS28E15/22/25 series of authenticators
 /// including low power variants.
 class DS28E15_22_25 {
@@ -50,146 +52,43 @@
   enum ErrorValue { CrcError = 1, OperationFailure };
 
   /// Holds the contents of a device memory segment.
-  typedef array<uint_least8_t, 4> Segment;
+  typedef array_span<uint_least8_t, 4> Segment;
 
   /// Holds the contents of a device memory page.
-  typedef array<uint_least8_t, 32> Page;
+  typedef array_span<uint_least8_t, 32> Page;
 
   /// Number of segments per page.
-  static const int segmentsPerPage = Page::csize / Segment::csize;
+  static const int segmentsPerPage = Page::size / Segment::size;
 
   /// Holds the contents of the device scratchpad.
-  typedef array<uint_least8_t, 32> Scratchpad;
+  typedef array_span<uint_least8_t, 32> Scratchpad;
 
-  /// Container for the device personality. 
+  /// Container for the device personality.
   struct Personality {
     uint_least8_t PB1;
     uint_least8_t PB2;
-    ManId manId;
-    
+    ManId::array manId;
+
     bool secretLocked() const { return PB2 & 0x01; }
   };
 
-  /// Represents the status of a memory protection block.
-  class BlockProtection {
-  private:
-    static const unsigned int readProtectionMask = 0x80,
-                              writeProtectionMask = 0x40,
-                              eepromEmulationMask = 0x20,
-                              authProtectionMask = 0x10,
-                              blockNumMask = 0x0F;
-    uint_least8_t status;
-
-  public:
-    explicit BlockProtection(uint_least8_t status = 0x00) : status(status) {}
-    MaximInterface_EXPORT BlockProtection(bool readProtection,
-                                          bool writeProtection,
-                                          bool eepromEmulation,
-                                          bool authProtection,
-                                          int blockNum);
-
-    /// Get the byte representation used by the device.
-    uint_least8_t statusByte() const { return status; }
-    /// Set the byte representation used by the device.
-    void setStatusByte(uint_least8_t status) { this->status = status; }
-
-    /// Get the Block Number which is indexed from zero.
-    int blockNum() const { return (status & blockNumMask); }
-    /// Set the Block Number which is indexed from zero.
-    MaximInterface_EXPORT void setBlockNum(int blockNum);
+  // Represents the status of a memory protection block.
+  class BlockProtection;
 
-    /// Get the Read Protection status.
-    /// @returns True if Read Protection is enabled.
-    bool readProtection() const {
-      return ((status & readProtectionMask) == readProtectionMask);
-    }
-    /// Set the Read Protection status.
-    MaximInterface_EXPORT void setReadProtection(bool readProtection);
-
-    /// Get the Write Protection status.
-    /// @returns True if Write Protection is enabled.
-    bool writeProtection() const {
-      return ((status & writeProtectionMask) == writeProtectionMask);
-    }
-    /// Set the Write Protection status.
-    MaximInterface_EXPORT void setWriteProtection(bool writeProtection);
+  // Format data to hash for an Authenticated Write to a memory segment.
+  class SegmentWriteMacData;
 
-    /// Get the EEPROM Emulation Mode status.
-    /// @returns True if EEPROM Emulation Mode is enabled.
-    bool eepromEmulation() const {
-      return ((status & eepromEmulationMask) == eepromEmulationMask);
-    }
-    /// Set the EEPROM Emulation Mode status.
-    MaximInterface_EXPORT void setEepromEmulation(bool eepromEmulation);
-
-    /// Get the Authentication Protection status.
-    /// @returns True if Authentication Protection is enabled.
-    bool authProtection() const {
-      return ((status & authProtectionMask) == authProtectionMask);
-    }
-    /// Set the Authentication Protection status.
-    MaximInterface_EXPORT void setAuthProtection(bool authProtection);
+  // Format data to hash for an Authenticated Write to a memory protection block.
+  class ProtectionWriteMacData;
 
-    /// Check if no protection options are enabled.
-    /// @returns True if no protection options are enabled.
-    MaximInterface_EXPORT bool noProtection() const;
-  };
-
-  /// Format data to hash for an Authenticated Write to a memory segment.
-  /// @param pageNum Page number for write operation.
-  /// @param segmentNum Segment number within page for write operation.
-  /// @param[in] newData New data to write to the segment.
-  /// @param[in] oldData Existing data contained in the segment.
-  /// @param[in] romId 1-Wire ROM ID of the device.
-  /// @param[in] manId Manufacturer ID of the device.
-  MaximInterface_EXPORT static Sha256::WriteMacData
-  createSegmentWriteMacData(int pageNum, int segmentNum,
-                            const Segment & newData, const Segment & oldData,
-                            const RomId & romId, const ManId & manId);
-
-  /// Format data to hash for an Authenticated Write to a memory protection block.
-  /// @param[in] newProtection New protection status to write.
-  /// @param[in] oldProtection Existing protection status in device.
-  /// @param[in] romId 1-Wire ROM ID of the device.
-  /// @param[in] manId Manufacturer ID of the device.
-  MaximInterface_EXPORT static Sha256::WriteMacData
-  createProtectionWriteMacData(const BlockProtection & newProtection,
-                               const BlockProtection & oldProtection,
-                               const RomId & romId, const ManId & manId);
+  // Format data to hash for device authentication or computing the next secret
+  // from the existing secret.
+  class AuthenticationData;
 
-  /// Format data to hash to compute the next secret from the existing secret.
-  /// @param[in] bindingPage Binding data from a device memory page.
-  /// @param bindingPageNum Number of the page where the binding data is from.
-  /// @param[in] partialSecret Partial secret data from the device scratchpad.
-  /// @param[in] romId 1-Wire ROM ID of the device.
-  /// @param[in] manId Manufacturer ID of the device.
-  MaximInterface_EXPORT static Sha256::SlaveSecretData
-  createSlaveSecretData(const Page & bindingPage, int bindingPageNum,
-                        const Scratchpad & partialSecret, const RomId & romId,
-                        const ManId & manId);
-
-  /// Format data to hash for device authentication.
-  /// @param[in] pageData Data from a device memory page.
-  /// @param pageNum Number of the page to use data from.
-  /// @param[in] challenge Random challenge to prevent replay attacks.
-  /// @param[in] romId 1-Wire ROM ID of the device.
-  /// @param[in] manId Manufacturer ID of the device.
-  MaximInterface_EXPORT static Sha256::AuthMacData
-  createAuthMacData(const Page & pageData, int pageNum,
-                    const Scratchpad & challenge, const RomId & romId,
-                    const ManId & manId);
-
-  /// Format datat to hash for device authentication using anonymous mode.
-  /// @param[in] pageData Data from a device memory page.
-  /// @param pageNum Number of the page to use data from.
-  /// @param[in] challenge Random challenge to prevent replay attacks.
-  /// @param[in] manId Manufacturer ID of the device.
-  MaximInterface_EXPORT static Sha256::AuthMacData
-  createAnonAuthMacData(const Page & pageData, int pageNum,
-                        const Scratchpad & challenge, const ManId & manId);
-
-  void setSleep(const Sleep & sleep) { this->sleep = &sleep; }
+  void setSleep(Sleep & sleep) { this->sleep = &sleep; }
+  
   void setMaster(OneWireMaster & master) { this->master = &master; }
+  
   void setSelectRom(const SelectRom & selectRom) {
     this->selectRom = selectRom;
   }
@@ -197,74 +96,81 @@
   // Const member functions should not affect the state of the memory,
   // block protection, or secret on the device.
 
-  /// Read memory segment using the Read Memory command on the device.
+  /// @brief Read memory segment using the Read Memory command on the device.
   /// @param pageNum Page number for read operation.
   /// @param segmentNum Segment number within page for read operation.
   /// @param[out] data Buffer to read data from the segment into.
   MaximInterface_EXPORT error_code readSegment(int pageNum, int segmentNum,
-                                               Segment & data) const;
+                                               Segment::span data) const;
 
-  /// Continue an in-progress readSegment operation.
+  /// @brief Continue an in-progress readSegment operation.
   /// @note A CRC16 will encountered after reading the last segment of a page.
   /// @param[out] data Buffer to read data from the segment into.
-  MaximInterface_EXPORT error_code continueReadSegment(Segment & data) const;
+  MaximInterface_EXPORT error_code
+  continueReadSegment(Segment::span data) const;
 
-  /// Write memory segment using the Write Memory command.
+  /// @brief Write memory segment using the Write Memory command.
   /// @note 1-Wire ROM selection should have already occurred.
   /// @param pageNum Page number for write operation.
   /// @param segmentNum Segment number within page for write operation.
   /// @param[in] data Data to write to the memory segment.
   MaximInterface_EXPORT error_code writeSegment(int pageNum, int segmentNum,
-                                                const Segment & data);
+                                                Segment::const_span data);
 
-  /// Continue an in-progress Write Memory command.
+  /// @brief Continue an in-progress Write Memory command.
   /// @param[in] data Data to write to the memory segment.
-  MaximInterface_EXPORT error_code continueWriteSegment(const Segment & data);
+  MaximInterface_EXPORT error_code
+  continueWriteSegment(Segment::const_span data);
 
-  /// Read memory page using the Read Memory command on the device.
+  /// @brief Read memory page using the Read Memory command on the device.
   /// @param pageNum Page number for write operation.
   /// @param[out] rdbuf Buffer to read data from the page into.
-  MaximInterface_EXPORT error_code readPage(int pageNum, Page & rdbuf) const;
+  MaximInterface_EXPORT error_code readPage(int pageNum,
+                                            Page::span rdbuf) const;
 
-  /// Continue an in-progress readPageOperation.
+  /// @brief Continue an in-progress readPageOperation.
   /// @param[out] rdbuf Buffer to read data from the page into.
-  MaximInterface_EXPORT error_code continueReadPage(Page & rdbuf) const;
+  MaximInterface_EXPORT error_code continueReadPage(Page::span rdbuf) const;
 
+  /// @brief
   /// Perform a Compute Page MAC command on the device.
   /// Read back the MAC and verify the CRC16.
   /// @param pageNum Page number to use for the computation.
   /// @param anon True to compute in anonymous mode where ROM ID is not used.
   /// @param[out] mac The device computed MAC.
-  MaximInterface_EXPORT error_code computeReadPageMac(int pageNum, bool anon,
-                                                      Sha256::Hash & mac) const;
+  MaximInterface_EXPORT error_code
+  computeReadPageMac(int pageNum, bool anon, Sha256::Hash::span mac) const;
 
+  /// @brief
   /// Update the status of a memory protection block using the
   /// Write Page Protection command.
-  /// @param[in] Desired protection status for the block.
-  ///            It is not possible to disable existing protections.
-  /// @param continuing True to continue a previous Write Page Protection command.
-  ///                   False to begin a new command.
+  /// @param protection
+  /// Desired protection status for the block.
+  /// It is not possible to disable existing protections.
   MaximInterface_EXPORT error_code
-  writeBlockProtection(const BlockProtection & protection);
+  writeBlockProtection(BlockProtection protection);
 
+  /// @brief
   /// Update the status of a memory protection block using the
   /// Authenticated Write Page Protection command.
-  /// @param[in] newProtection New protection status to write.
+  /// @param newProtection New protection status to write.
   /// @param[in] mac Write MAC computed for this operation.
   MaximInterface_EXPORT error_code writeAuthBlockProtection(
-      const BlockProtection & newProtection, const Sha256::Hash & mac);
+      BlockProtection newProtection, Sha256::Hash::const_span mac);
 
-  /// Perform Load and Lock Secret command on the device.
+  /// @brief Perform Load and Lock Secret command on the device.
   /// @note The secret should already be stored in the scratchpad on the device.
-  /// @param lock Prevent further changes to the secret on the device after loading.
+  /// @param lock
+  /// Prevent further changes to the secret on the device after loading.
   MaximInterface_EXPORT error_code loadSecret(bool lock);
 
-  /// Perform a Compute and Lock Secret command on the device.
+  /// @brief Perform a Compute and Lock Secret command on the device.
   /// @param pageNum Page number to use as the binding data.
-  /// @param lock Prevent further changes to the secret on the device after computing.
+  /// @param lock
+  /// Prevent further changes to the secret on the device after computing.
   MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock);
 
-  /// Read the personality bytes using the Read Status command.
+  /// @brief Read the personality bytes using the Read Status command.
   /// @param[out] personality Receives personality read from device.
   MaximInterface_EXPORT error_code
   readPersonality(Personality & personality) const;
@@ -274,27 +180,28 @@
 protected:
   enum Variant { DS28E15, DS28E22, DS28E25 };
 
-  DS28E15_22_25(const Sleep & sleep, OneWireMaster & master,
+  DS28E15_22_25(Sleep & sleep, OneWireMaster & master,
                 const SelectRom & selectRom)
       : selectRom(selectRom), master(&master), sleep(&sleep) {}
+      
+  ~DS28E15_22_25() {}
 
-  error_code doWriteScratchpad(const Scratchpad & data, Variant variant);
+  error_code doWriteScratchpad(Scratchpad::const_span data, Variant variant);
 
-  error_code doReadScratchpad(Scratchpad & data, Variant variant) const;
+  error_code doReadScratchpad(Scratchpad::span data, Variant variant) const;
 
   error_code doReadBlockProtection(int blockNum, BlockProtection & protection,
                                    Variant variant) const;
 
   error_code doWriteAuthSegment(int pageNum, int segmentNum,
-                                const Segment & newData,
-                                const Sha256::Hash & mac, Variant variant);
+                                Segment::const_span newData,
+                                Sha256::Hash::const_span mac, Variant variant);
 
-  error_code doContinueWriteAuthSegment(const Segment & newData,
-                                        const Sha256::Hash & mac,
+  error_code doContinueWriteAuthSegment(Segment::const_span newData,
+                                        Sha256::Hash::const_span mac,
                                         Variant variant);
 
-  error_code doReadAllBlockProtection(BlockProtection * protection,
-                                      size_t protectionLen,
+  error_code doReadAllBlockProtection(span<BlockProtection> protection,
                                       Variant variant) const;
 
   error_code doLoadSecret(bool lock, bool lowPower);
@@ -315,8 +222,8 @@
     AuthWriteBlockProtection = 0xCC,
   };
 
-  error_code doWriteAuthSegment(const Segment & newData,
-                                const Sha256::Hash & mac, Variant variant,
+  error_code doWriteAuthSegment(Segment::const_span newData,
+                                Sha256::Hash::const_span mac, Variant variant,
                                 bool continuing);
 
   error_code writeCommandWithCrc(
@@ -325,23 +232,13 @@
 
   SelectRom selectRom;
   OneWireMaster * master;
-  const Sleep * sleep;
+  Sleep * sleep;
 };
 
 inline error_code make_error_code(DS28E15_22_25::ErrorValue e) {
   return error_code(e, DS28E15_22_25::errorCategory());
 }
 
-inline bool operator==(DS28E15_22_25::BlockProtection lhs,
-                       DS28E15_22_25::BlockProtection rhs) {
-  return lhs.statusByte() == rhs.statusByte();
-}
-
-inline bool operator!=(DS28E15_22_25::BlockProtection lhs,
-                       DS28E15_22_25::BlockProtection rhs) {
-  return !operator==(lhs, rhs);
-}
-
 /// Interface to the DS28EL15 (low power) authenticator.
 class DS28EL15 : public DS28E15_22_25 {
 public:
@@ -349,18 +246,150 @@
   static const int memoryPages = 2;
   static const int protectionBlocks = 4;
 
-  DS28EL15(const Sleep & sleep, OneWireMaster & master,
-           const SelectRom & selectRom)
+  DS28EL15(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom)
+      : DS28E15_22_25(sleep, master, selectRom) {}
+
+  /// @brief Perform Write Scratchpad operation on the device.
+  /// @param[in] data Data to write to the scratchpad.
+  MaximInterface_EXPORT error_code writeScratchpad(Scratchpad::const_span data);
+
+  /// @brief Perform a Read Scratchpad operation on the device.
+  /// @param[out] data Buffer to read data from the scratchpad into.
+  MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span data) const;
+
+  /// @brief
+  /// Read the status of a memory protection block using the Read Status command.
+  /// @param blockNum Block number to to read status of.
+  /// @param[out] protection Receives protection status read from device.
+  MaximInterface_EXPORT error_code
+  readBlockProtection(int blockNum, BlockProtection & protection) const;
+
+  /// @brief Write memory segment using the Authenticated Write Memory command.
+  /// @param pageNum Page number for write operation.
+  /// @param segmentNum Segment number within page for write operation.
+  /// @param[in] newData New data to write to the segment.
+  /// @param[in] mac Write MAC computed for this operation.
+  MaximInterface_EXPORT error_code
+  writeAuthSegment(int pageNum, int segmentNum, Segment::const_span newData,
+                   Sha256::Hash::const_span mac);
+
+  /// @brief Continue an in-progress Authenticated Write Memory command.
+  /// @param[in] newData New data to write to the segment.
+  /// @param[in] mac Write MAC computed for this operation.
+  MaximInterface_EXPORT error_code continueWriteAuthSegment(
+      Segment::const_span newData, Sha256::Hash::const_span mac);
+
+  /// @brief
+  /// Read the status of all memory protection blocks using the Read Status command.
+  /// @param[out] protection Receives protection statuses read from device.
+  MaximInterface_EXPORT error_code readAllBlockProtection(
+      span<BlockProtection, protectionBlocks> protection) const;
+};
+
+/// Interface to the DS28E15 authenticator.
+class DS28E15 : public DS28EL15 {
+public:
+  DS28E15(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom)
+      : DS28EL15(sleep, master, selectRom) {}
+
+  /// @brief Perform Load and Lock Secret command on the device.
+  /// @note The secret should already be stored in the scratchpad on the device.
+  /// @param lock
+  /// Prevent further changes to the secret on the device after loading.
+  MaximInterface_EXPORT error_code loadSecret(bool lock);
+
+  /// @brief Perform a Compute and Lock Secret command on the device.
+  /// @param pageNum Page number to use as the binding data.
+  /// @param lock
+  /// Prevent further changes to the secret on the device after computing.
+  MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock);
+};
+
+/// Interface to the DS28EL22 (low power) authenticator.
+class DS28EL22 : public DS28E15_22_25 {
+public:
+  // DS28E15_22_25 traits
+  static const int memoryPages = 8;
+  static const int protectionBlocks = 4;
+
+  DS28EL22(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom)
       : DS28E15_22_25(sleep, master, selectRom) {}
 
-  /// Perform Write Scratchpad operation on the device.
+  /// @brief Perform Write Scratchpad operation on the device.
   /// @param[in] data Data to write to the scratchpad.
-  MaximInterface_EXPORT error_code writeScratchpad(const Scratchpad & data);
+  MaximInterface_EXPORT error_code writeScratchpad(Scratchpad::const_span data);
+
+  /// @brief Perform a Read Scratchpad operation on the device.
+  /// @param[out] data Buffer to read data from the scratchpad into.
+  MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span data) const;
+
+  /// @brief
+  /// Read the status of a memory protection block using the Read Status command.
+  /// @param blockNum Block number to to read status of.
+  /// @param[out] protection Receives protection status read from device.
+  MaximInterface_EXPORT error_code
+  readBlockProtection(int blockNum, BlockProtection & protection) const;
+
+  /// @brief Write memory segment using the Authenticated Write Memory command.
+  /// @param pageNum Page number for write operation.
+  /// @param segmentNum Segment number within page for write operation.
+  /// @param[in] newData New data to write to the segment.
+  /// @param[in] mac Write MAC computed for this operation.
+  MaximInterface_EXPORT error_code
+  writeAuthSegment(int pageNum, int segmentNum, Segment::const_span newData,
+                   Sha256::Hash::const_span mac);
+
+  /// @brief Continue an in-progress Authenticated Write Memory command.
+  /// @param[in] newData New data to write to the segment.
+  /// @param[in] mac Write MAC computed for this operation.
+  MaximInterface_EXPORT error_code continueWriteAuthSegment(
+      Segment::const_span newData, Sha256::Hash::const_span mac);
+
+  /// @brief
+  /// Read the status of all memory protection blocks using the Read Status command.
+  /// @param[out] protection Receives protection statuses read from device.
+  MaximInterface_EXPORT error_code readAllBlockProtection(
+      span<BlockProtection, protectionBlocks> protection) const;
+};
 
-  /// Perform a Read Scratchpad operation on the device.
+/// Interface to the DS28E22 authenticator.
+class DS28E22 : public DS28EL22 {
+public:
+  DS28E22(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom)
+      : DS28EL22(sleep, master, selectRom) {}
+
+  /// @brief Perform Load and Lock Secret command on the device.
+  /// @note The secret should already be stored in the scratchpad on the device.
+  /// @param lock
+  /// Prevent further changes to the secret on the device after loading.
+  MaximInterface_EXPORT error_code loadSecret(bool lock);
+
+  /// @brief Perform a Compute and Lock Secret command on the device.
+  /// @param pageNum Page number to use as the binding data.
+  /// @param lock
+  /// Prevent further changes to the secret on the device after computing.
+  MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock);
+};
+
+/// Interface to the DS28EL25 (low power) authenticator.
+class DS28EL25 : public DS28E15_22_25 {
+public:
+  // DS28E15_22_25 traits
+  static const int memoryPages = 16;
+  static const int protectionBlocks = 8;
+
+  DS28EL25(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom)
+      : DS28E15_22_25(sleep, master, selectRom) {}
+
+  /// @brief Perform Write Scratchpad operation on the device.
+  /// @param[in] data Data to write to the scratchpad.
+  MaximInterface_EXPORT error_code writeScratchpad(Scratchpad::const_span data);
+
+  /// @brief Perform a Read Scratchpad operation on the device.
   /// @param[out] data Buffer to read data from the scratchpad into.
-  MaximInterface_EXPORT error_code readScratchpad(Scratchpad & data) const;
+  MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span data) const;
 
+  /// @brief
   /// Read the status of a memory protection block using the Read Status command.
   /// @param blockNum Block number to to read status of.
   /// @param[out] protection Receives protection status read from device.
@@ -372,168 +401,485 @@
   /// @param segmentNum Segment number within page for write operation.
   /// @param[in] newData New data to write to the segment.
   /// @param[in] mac Write MAC computed for this operation.
-  MaximInterface_EXPORT error_code writeAuthSegment(int pageNum, int segmentNum,
-                                                    const Segment & newData,
-                                                    const Sha256::Hash & mac);
+  MaximInterface_EXPORT error_code
+  writeAuthSegment(int pageNum, int segmentNum, Segment::const_span newData,
+                   Sha256::Hash::const_span mac);
 
-  /// Continue an in-progress Authenticated Write Memory command.
+  /// @brief Continue an in-progress Authenticated Write Memory command.
   /// @param[in] newData New data to write to the segment.
   /// @param[in] mac Write MAC computed for this operation.
-  MaximInterface_EXPORT error_code
-  continueWriteAuthSegment(const Segment & newData, const Sha256::Hash & mac);
+  MaximInterface_EXPORT error_code continueWriteAuthSegment(
+      Segment::const_span newData, Sha256::Hash::const_span mac);
 
+  /// @brief
   /// Read the status of all memory protection blocks using the Read Status command.
   /// @param[out] protection Receives protection statuses read from device.
   MaximInterface_EXPORT error_code readAllBlockProtection(
-      array<BlockProtection, protectionBlocks> & protection) const;
-};
-
-/// Interface to the DS28E15 authenticator.
-class DS28E15 : public DS28EL15 {
-public:
-  DS28E15(const Sleep & sleep, OneWireMaster & master,
-          const SelectRom & selectRom)
-      : DS28EL15(sleep, master, selectRom) {}
-
-  /// Perform Load and Lock Secret command on the device.
-  /// @note The secret should already be stored in the scratchpad on the device.
-  /// @param lock Prevent further changes to the secret on the device after loading.
-  MaximInterface_EXPORT error_code loadSecret(bool lock);
-
-  /// Perform a Compute and Lock Secret command on the device.
-  /// @param pageNum Page number to use as the binding data.
-  /// @param lock Prevent further changes to the secret on the device after computing.
-  MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock);
-};
-
-/// Interface to the DS28EL22 (low power) authenticator.
-class DS28EL22 : public DS28E15_22_25 {
-public:
-  // DS28E15_22_25 traits
-  static const int memoryPages = 8;
-  static const int protectionBlocks = 4;
-
-  DS28EL22(const Sleep & sleep, OneWireMaster & master,
-           const SelectRom & selectRom)
-      : DS28E15_22_25(sleep, master, selectRom) {}
-
-  /// Perform Write Scratchpad operation on the device.
-  /// @param[in] data Data to write to the scratchpad.
-  MaximInterface_EXPORT error_code writeScratchpad(const Scratchpad & data);
-
-  /// Perform a Read Scratchpad operation on the device.
-  /// @param[out] data Buffer to read data from the scratchpad into.
-  MaximInterface_EXPORT error_code readScratchpad(Scratchpad & data) const;
-
-  /// Read the status of a memory protection block using the Read Status command.
-  /// @param blockNum Block number to to read status of.
-  /// @param[out] protection Receives protection status read from device.
-  MaximInterface_EXPORT error_code
-  readBlockProtection(int blockNum, BlockProtection & protection) const;
-
-  /// Write memory segment using the Authenticated Write Memory command.
-  /// @param pageNum Page number for write operation.
-  /// @param segmentNum Segment number within page for write operation.
-  /// @param[in] newData New data to write to the segment.
-  /// @param[in] mac Write MAC computed for this operation.
-  MaximInterface_EXPORT error_code writeAuthSegment(int pageNum, int segmentNum,
-                                                    const Segment & newData,
-                                                    const Sha256::Hash & mac);
-
-  /// Continue an in-progress Authenticated Write Memory command.
-  /// @param[in] newData New data to write to the segment.
-  /// @param[in] mac Write MAC computed for this operation.
-  MaximInterface_EXPORT error_code
-  continueWriteAuthSegment(const Segment & newData, const Sha256::Hash & mac);
-
-  /// Read the status of all memory protection blocks using the Read Status command.
-  /// @param[out] protection Receives protection statuses read from device.
-  MaximInterface_EXPORT error_code readAllBlockProtection(
-      array<BlockProtection, protectionBlocks> & protection) const;
-};
-
-/// Interface to the DS28E22 authenticator.
-class DS28E22 : public DS28EL22 {
-public:
-  DS28E22(const Sleep & sleep, OneWireMaster & master,
-          const SelectRom & selectRom)
-      : DS28EL22(sleep, master, selectRom) {}
-
-  /// Perform Load and Lock Secret command on the device.
-  /// @note The secret should already be stored in the scratchpad on the device.
-  /// @param lock Prevent further changes to the secret on the device after loading.
-  MaximInterface_EXPORT error_code loadSecret(bool lock);
-
-  /// Perform a Compute and Lock Secret command on the device.
-  /// @param pageNum Page number to use as the binding data.
-  /// @param lock Prevent further changes to the secret on the device after computing.
-  MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock);
-};
-
-/// Interface to the DS28EL25 (low power) authenticator.
-class DS28EL25 : public DS28E15_22_25 {
-public:
-  // DS28E15_22_25 traits
-  static const int memoryPages = 16;
-  static const int protectionBlocks = 8;
-
-  DS28EL25(const Sleep & sleep, OneWireMaster & master,
-           const SelectRom & selectRom)
-      : DS28E15_22_25(sleep, master, selectRom) {}
-
-  /// Perform Write Scratchpad operation on the device.
-  /// @param[in] data Data to write to the scratchpad.
-  MaximInterface_EXPORT error_code writeScratchpad(const Scratchpad & data);
-
-  /// Perform a Read Scratchpad operation on the device.
-  /// @param[out] data Buffer to read data from the scratchpad into.
-  MaximInterface_EXPORT error_code readScratchpad(Scratchpad & data) const;
-
-  /// Read the status of a memory protection block using the Read Status command.
-  /// @param blockNum Block number to to read status of.
-  /// @param[out] protection Receives protection status read from device.
-  MaximInterface_EXPORT error_code
-  readBlockProtection(int blockNum, BlockProtection & protection) const;
-
-  /// Write memory segment using the Authenticated Write Memory command.
-  /// @param pageNum Page number for write operation.
-  /// @param segmentNum Segment number within page for write operation.
-  /// @param[in] newData New data to write to the segment.
-  /// @param[in] mac Write MAC computed for this operation.
-  MaximInterface_EXPORT error_code writeAuthSegment(int pageNum, int segmentNum,
-                                                    const Segment & newData,
-                                                    const Sha256::Hash & mac);
-
-  /// Continue an in-progress Authenticated Write Memory command.
-  /// @param[in] newData New data to write to the segment.
-  /// @param[in] mac Write MAC computed for this operation.
-  MaximInterface_EXPORT error_code
-  continueWriteAuthSegment(const Segment & newData, const Sha256::Hash & mac);
-
-  /// Read the status of all memory protection blocks using the Read Status command.
-  /// @param[out] protection Receives protection statuses read from device.
-  MaximInterface_EXPORT error_code readAllBlockProtection(
-      array<BlockProtection, protectionBlocks> & protection) const;
+      span<BlockProtection, protectionBlocks> protection) const;
 };
 
 /// Interface to the DS28E25 authenticator.
 class DS28E25 : public DS28EL25 {
 public:
-  DS28E25(const Sleep & sleep, OneWireMaster & master,
-          const SelectRom & selectRom)
+  DS28E25(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom)
       : DS28EL25(sleep, master, selectRom) {}
 
-  /// Perform Load and Lock Secret command on the device.
+  /// @brief Perform Load and Lock Secret command on the device.
   /// @note The secret should already be stored in the scratchpad on the device.
   /// @param lock Prevent further changes to the secret on the device after loading.
   MaximInterface_EXPORT error_code loadSecret(bool lock);
 
-  /// Perform a Compute and Lock Secret command on the device.
+  /// @brief Perform a Compute and Lock Secret command on the device.
   /// @param pageNum Page number to use as the binding data.
-  /// @param lock Prevent further changes to the secret on the device after computing.
+  /// @param lock
+  /// Prevent further changes to the secret on the device after computing.
   MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock);
 };
 
+/// Represents the status of a memory protection block.
+class DS28E15_22_25::BlockProtection {
+public:
+  explicit BlockProtection(uint_least8_t status = 0x00) : status(status) {}
+
+  /// Get the byte representation used by the device.
+  uint_least8_t statusByte() const { return status; }
+  
+  /// Set the byte representation used by the device.
+  BlockProtection & setStatusByte(uint_least8_t status) {
+    this->status = status;
+    return *this;
+  }
+
+  /// Get the Block Number which is indexed from zero.
+  int blockNum() const { return (status & blockNumMask); }
+  
+  /// Set the Block Number which is indexed from zero.
+  MaximInterface_EXPORT BlockProtection & setBlockNum(int blockNum);
+
+  /// @brief Get the Read Protection status.
+  /// @returns True if Read Protection is enabled.
+  bool readProtection() const {
+    return ((status & readProtectionMask) == readProtectionMask);
+  }
+  
+  /// Set the Read Protection status.
+  MaximInterface_EXPORT BlockProtection &
+  setReadProtection(bool readProtection);
+
+  /// @brief Get the Write Protection status.
+  /// @returns True if Write Protection is enabled.
+  bool writeProtection() const {
+    return ((status & writeProtectionMask) == writeProtectionMask);
+  }
+  
+  /// Set the Write Protection status.
+  MaximInterface_EXPORT BlockProtection &
+  setWriteProtection(bool writeProtection);
+
+  /// @brief Get the EEPROM Emulation Mode status.
+  /// @returns True if EEPROM Emulation Mode is enabled.
+  bool eepromEmulation() const {
+    return ((status & eepromEmulationMask) == eepromEmulationMask);
+  }
+  
+  /// Set the EEPROM Emulation Mode status.
+  MaximInterface_EXPORT BlockProtection &
+  setEepromEmulation(bool eepromEmulation);
+
+  /// @brief Get the Authentication Protection status.
+  /// @returns True if Authentication Protection is enabled.
+  bool authProtection() const {
+    return ((status & authProtectionMask) == authProtectionMask);
+  }
+  
+  /// Set the Authentication Protection status.
+  MaximInterface_EXPORT BlockProtection &
+  setAuthProtection(bool authProtection);
+
+  /// @brief Check if no protection options are enabled.
+  /// @returns True if no protection options are enabled.
+  MaximInterface_EXPORT bool noProtection() const;
+
+private:
+  static const unsigned int readProtectionMask = 0x80,
+                            writeProtectionMask = 0x40,
+                            eepromEmulationMask = 0x20,
+                            authProtectionMask = 0x10,
+                            blockNumMask = 0x0F;
+  uint_least8_t status;
+};
+
+inline bool operator==(DS28E15_22_25::BlockProtection lhs,
+                       DS28E15_22_25::BlockProtection rhs) {
+  return lhs.statusByte() == rhs.statusByte();
+}
+
+inline bool operator!=(DS28E15_22_25::BlockProtection lhs,
+                       DS28E15_22_25::BlockProtection rhs) {
+  return !operator==(lhs, rhs);
+}
+
+/// Format data to hash for an Authenticated Write to a memory segment.
+class DS28E15_22_25::SegmentWriteMacData {
+public:
+  SegmentWriteMacData() : result_() {}
+
+  /// Formatted data result.
+  Sha256::WriteMacData::const_span result() const { return result_; }
+
+  /// @name ROM ID
+  /// @brief 1-Wire ROM ID of the device.
+  /// @{
+
+  /// Get mutable ROM ID.
+  RomId::span romId() {
+    return make_span(result_).subspan<romIdIdx, RomId::size>();
+  }
+  
+  /// Get immutable ROM ID.
+  RomId::const_span romId() const {
+    return const_cast<SegmentWriteMacData &>(*this).romId();
+  }
+  
+  /// Set ROM ID.
+  SegmentWriteMacData & setRomId(RomId::const_span romId) {
+    copy(romId, this->romId());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name MAN ID
+  /// @brief Manufacturer ID of the device.
+  /// @{
+  
+  /// Get mutable MAN ID.
+  ManId::span manId() {
+    return make_span(result_).subspan<manIdIdx, ManId::size>();
+  }
+  
+  /// Get immutable MAN ID.
+  ManId::const_span manId() const {
+    return const_cast<SegmentWriteMacData &>(*this).manId();
+  }
+  
+  /// Set MAN ID.
+  SegmentWriteMacData & setManId(ManId::const_span manId) {
+    copy(manId, this->manId());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Page number
+  /// @brief Page number for write operation.
+  /// @{
+
+  /// Get page number.
+  int pageNum() const { return result_[pageNumIdx]; }
+  
+  /// Set page number.
+  SegmentWriteMacData & setPageNum(int pageNum) {
+    result_[pageNumIdx] = pageNum;
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Segment number
+  /// @brief Segment number within page for write operation.
+  /// @{
+  
+  /// Get segment number.
+  int segmentNum() const { return result_[segmentNumIdx]; }
+  
+  /// Set segment number.
+  SegmentWriteMacData & setSegmentNum(int segmentNum) {
+    result_[segmentNumIdx] = segmentNum;
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Old data
+  /// @brief Existing data contained in the segment.
+  /// @{
+  
+  /// Get mutable old data.
+  Segment::span oldData() {
+    return make_span(result_).subspan<oldDataIdx, Segment::size>();
+  }
+  
+  /// Get immutable old data.
+  Segment::const_span oldData() const {
+    return const_cast<SegmentWriteMacData &>(*this).oldData();
+  }
+  
+  /// Set old data.
+  SegmentWriteMacData & setOldData(Segment::const_span oldData) {
+    copy(oldData, this->oldData());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name New data
+  /// @brief New data to write to the segment.
+  /// @{
+  
+  /// Get mutable new data.
+  Segment::span newData() {
+    return make_span(result_).subspan<newDataIdx, Segment::size>();
+  }
+  
+  /// Get immutable new data.
+  Segment::const_span newData() const {
+    return const_cast<SegmentWriteMacData &>(*this).newData();
+  }
+  
+  /// Set new data.
+  SegmentWriteMacData & setNewData(Segment::const_span newData) {
+    copy(newData, this->newData());
+    return *this;
+  }
+  
+  /// @}
+
+private:
+  typedef Sha256::WriteMacData::span::index_type index;
+
+  static const index romIdIdx = 0;
+  static const index manIdIdx = romIdIdx + RomId::size;
+  static const index pageNumIdx = manIdIdx + ManId::size;
+  static const index segmentNumIdx = pageNumIdx + 1;
+  static const index oldDataIdx = segmentNumIdx + 1;
+  static const index newDataIdx = oldDataIdx + Segment::size;
+
+  Sha256::WriteMacData::array result_;
+};
+
+/// Format data to hash for an Authenticated Write to a memory protection block.
+class DS28E15_22_25::ProtectionWriteMacData {
+public:
+  MaximInterface_EXPORT ProtectionWriteMacData();
+
+  /// Formatted data result.
+  Sha256::WriteMacData::const_span result() const { return result_; }
+
+  /// @name ROM ID
+  /// @brief 1-Wire ROM ID of the device.
+  /// @{
+  
+  /// Get mutable ROM ID.
+  RomId::span romId() {
+    return make_span(result_).subspan<romIdIdx, RomId::size>();
+  }
+  
+  /// Get immutable ROM ID.
+  RomId::const_span romId() const {
+    return const_cast<ProtectionWriteMacData &>(*this).romId();
+  }
+  
+  /// Set ROM ID.
+  ProtectionWriteMacData & setRomId(RomId::const_span romId) {
+    copy(romId, this->romId());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name MAN ID
+  /// @brief Manufacturer ID of the device.
+  /// @{
+  
+  /// Get mutable MAN ID.
+  ManId::span manId() {
+    return make_span(result_).subspan<manIdIdx, ManId::size>();
+  }
+  
+  /// Get immutable MAN ID.
+  ManId::const_span manId() const {
+    return const_cast<ProtectionWriteMacData &>(*this).manId();
+  }
+  
+  /// Set MAN ID.
+  ProtectionWriteMacData & setManId(ManId::const_span manId) {
+    copy(manId, this->manId());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Old protection
+  /// @brief Existing protection status in device.
+  /// @{
+  
+  /// Get old protection.
+  BlockProtection oldProtection() const { return oldProtection_; }
+  
+  /// Set old protection.
+  MaximInterface_EXPORT ProtectionWriteMacData &
+  setOldProtection(BlockProtection oldProtection);
+  
+  /// @}
+
+  /// @name New protection
+  /// @brief New protection status to write.
+  /// @{
+  
+  /// Get new protection.
+  BlockProtection newProtection() const { return newProtection_; }
+  
+  /// Set new protection.
+  MaximInterface_EXPORT ProtectionWriteMacData &
+  setNewProtection(BlockProtection newProtection);
+  
+  /// @}
+
+private:
+  typedef Sha256::WriteMacData::span::index_type index;
+
+  static const index romIdIdx = 0;
+  static const index manIdIdx = romIdIdx + RomId::size;
+  static const index blockNumIdx = manIdIdx + ManId::size;
+  static const index oldProtectionIdx = blockNumIdx + 2;
+  static const index newProtectionIdx = oldProtectionIdx + 4;
+
+  Sha256::WriteMacData::array result_;
+  BlockProtection oldProtection_;
+  BlockProtection newProtection_;
+};
+
+/// @brief
+/// Format data to hash for device authentication or computing the next secret
+/// from the existing secret.
+class DS28E15_22_25::AuthenticationData {
+public:
+  AuthenticationData() : result_() {}
+
+  /// Formatted data result.
+  Sha256::AuthenticationData::const_span result() const { return result_; }
+
+  /// @name Page
+  /// @brief Data from a device memory page.
+  /// @{
+  
+  /// Get mutable page.
+  Page::span page() {
+    return make_span(result_).subspan<pageIdx, Page::size>();
+  }
+  
+  /// Get immutable page.
+  Page::const_span page() const {
+    return const_cast<AuthenticationData &>(*this).page();
+  }
+  
+  /// Set page.
+  AuthenticationData & setPage(Page::const_span page) {
+    copy(page, this->page());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Scratchpad
+  /// @brief
+  /// Data from device scratchpad used as a random challenge in device
+  /// authentication and a partial secret in secret computation.
+  /// @{
+
+  /// Get mutable scratchpad.
+  Scratchpad::span scratchpad() {
+    return make_span(result_).subspan<scratchpadIdx, Scratchpad::size>();
+  }
+  
+  /// Get immutable scratchpad.
+  Scratchpad::const_span scratchpad() const {
+    return const_cast<AuthenticationData &>(*this).scratchpad();
+  }
+  
+  /// Set scratchpad.
+  AuthenticationData & setScratchpad(Scratchpad::const_span scratchpad) {
+    copy(scratchpad, this->scratchpad());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name ROM ID
+  /// @brief 1-Wire ROM ID of the device.
+  /// @{
+  
+  /// Get mutable ROM ID.
+  RomId::span romId() {
+    return make_span(result_).subspan<romIdIdx, RomId::size>();
+  }
+  
+  /// Get immutable ROM ID.
+  RomId::const_span romId() const {
+    return const_cast<AuthenticationData &>(*this).romId();
+  }
+  
+  /// Set ROM ID.
+  AuthenticationData & setRomId(RomId::const_span romId) {
+    copy(romId, this->romId());
+    return *this;
+  }
+  
+  /// Set ROM ID for use in anonymous mode.
+  MaximInterface_EXPORT AuthenticationData & setAnonymousRomId();
+  
+  /// @}
+
+  /// @name MAN ID
+  /// @brief Manufacturer ID of the device.
+  /// @{
+  
+  /// Get mutable MAN ID.
+  ManId::span manId() {
+    return make_span(result_).subspan<manIdIdx, ManId::size>();
+  }
+  
+  /// Get immutable MAN ID.
+  ManId::const_span manId() const {
+    return const_cast<AuthenticationData &>(*this).manId();
+  }
+  
+  /// Set MAN ID.
+  AuthenticationData & setManId(ManId::const_span manId) {
+    copy(manId, this->manId());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Page number
+  /// @brief Number of the page to use data from.
+  /// @{
+  
+  /// Get page number.
+  int pageNum() const { return result_[pageNumIdx]; }
+  
+  /// Set page number.
+  AuthenticationData & setPageNum(int pageNum) {
+    result_[pageNumIdx] = pageNum;
+    return *this;
+  }
+  
+  /// @}
+
+private:
+  typedef Sha256::AuthenticationData::span::index_type index;
+
+  static const index pageIdx = 0;
+  static const index scratchpadIdx = pageIdx + Page::size;
+  static const index romIdIdx = scratchpadIdx + Scratchpad::size;
+  static const index manIdIdx = romIdIdx + RomId::size;
+  static const index pageNumIdx = manIdIdx + ManId::size;
+
+  Sha256::AuthenticationData::array result_;
+};
+
 } // namespace MaximInterface
 
 #endif
--- a/Devices/DS28E17.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS28E17.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -39,46 +39,43 @@
 namespace MaximInterface {
 
 error_code DS28E17::writeDataWithStop(uint_least8_t I2C_addr,
-                                      const uint_least8_t * data,
-                                      size_t data_len,
+                                      span<const uint_least8_t> data,
                                       uint_least8_t * wr_status) {
-  return sendPacket(WriteDataWithStopCmd, &I2C_addr, data, data_len, NULL, 0,
-                    wr_status);
+  return sendPacket(WriteDataWithStopCmd, &I2C_addr, data,
+                    span<uint_least8_t>(), wr_status);
 }
 
 error_code DS28E17::writeDataNoStop(uint_least8_t I2C_addr,
-                                    const uint_least8_t * data, size_t data_len,
+                                    span<const uint_least8_t> data,
                                     uint_least8_t * wr_status) {
-  return sendPacket(WriteDataNoStopCmd, &I2C_addr, data, data_len, NULL, 0,
+  return sendPacket(WriteDataNoStopCmd, &I2C_addr, data, span<uint_least8_t>(),
                     wr_status);
 }
 
-error_code DS28E17::writeDataOnly(const uint_least8_t * data, size_t data_len,
+error_code DS28E17::writeDataOnly(span<const uint_least8_t> data,
                                   uint_least8_t * wr_status) {
-  return sendPacket(WriteDataOnlyCmd, NULL, data, data_len, NULL, 0, wr_status);
+  return sendPacket(WriteDataOnlyCmd, NULL, data, span<uint_least8_t>(),
+                    wr_status);
 }
 
-error_code DS28E17::writeDataOnlyWithStop(const uint_least8_t * data,
-                                          size_t data_len,
+error_code DS28E17::writeDataOnlyWithStop(span<const uint_least8_t> data,
                                           uint_least8_t * wr_status) {
-  return sendPacket(WriteDataOnlyWithStopCmd, NULL, data, data_len, NULL, 0,
+  return sendPacket(WriteDataOnlyWithStopCmd, NULL, data, span<uint_least8_t>(),
                     wr_status);
 }
 
 error_code DS28E17::writeReadDataWithStop(uint_least8_t I2C_addr,
-                                          const uint_least8_t * write_data,
-                                          size_t write_data_len,
-                                          uint_least8_t * read_data,
-                                          size_t read_data_len,
+                                          span<const uint_least8_t> write_data,
+                                          span<uint_least8_t> read_data,
                                           uint_least8_t * wr_status) {
-  return sendPacket(WriteReadDataWithStopCmd, &I2C_addr, write_data,
-                    write_data_len, read_data, read_data_len, wr_status);
+  return sendPacket(WriteReadDataWithStopCmd, &I2C_addr, write_data, read_data,
+                    wr_status);
 }
 
 error_code DS28E17::readDataWithStop(uint_least8_t I2C_addr,
-                                     uint_least8_t * data, size_t data_len) {
-  return sendPacket(ReadDataWithStopCmd, &I2C_addr, NULL, 0, data, data_len,
-                    NULL);
+                                     span<uint_least8_t> data) {
+  return sendPacket(ReadDataWithStopCmd, &I2C_addr, span<const uint_least8_t>(),
+                    data, NULL);
 }
 
 error_code DS28E17::writeConfigReg(I2CSpeed speed) {
@@ -87,8 +84,7 @@
     // Send CMD and Data
     const uint_least8_t send_block[] = {WriteConfigurationCmd,
                                         static_cast<uint_least8_t>(speed)};
-    result = master->writeBlock(send_block,
-                                sizeof(send_block) / sizeof(send_block[0]));
+    result = master->writeBlock(send_block);
   }
   return result;
 }
@@ -141,18 +137,14 @@
 }
 
 error_code DS28E17::sendPacket(Command command, const uint_least8_t * I2C_addr,
-                               const uint_least8_t * write_data,
-                               size_t write_data_len, uint_least8_t * read_data,
-                               size_t read_data_len,
+                               span<const uint_least8_t> write_data,
+                               span<uint_least8_t> read_data,
                                uint_least8_t * wr_status) {
   const int pollLimit = 10000;
-  const size_t minDataLen = 1;
-  const size_t maxDataLen = 255;
+  const span<const uint_least8_t>::index_type maxDataLen = 255;
 
-  if ((write_data &&
-       (write_data_len < minDataLen || write_data_len > maxDataLen)) ||
-      (read_data &&
-       (read_data_len < minDataLen || read_data_len > maxDataLen))) {
+  if ((!write_data.empty() && write_data.size() > maxDataLen) ||
+      (!read_data.empty() && read_data.size() > maxDataLen)) {
     return make_error_code(OutOfRangeError);
   }
 
@@ -172,21 +164,21 @@
       return result;
     }
   }
-  if (write_data) {
-    crc16 = calculateCrc16(static_cast<uint_fast8_t>(write_data_len), crc16);
-    result = master->writeByte(static_cast<uint_least8_t>(write_data_len));
+  if (!write_data.empty()) {
+    crc16 = calculateCrc16(static_cast<uint_fast8_t>(write_data.size()), crc16);
+    result = master->writeByte(static_cast<uint_least8_t>(write_data.size()));
     if (result) {
       return result;
     }
-    crc16 = calculateCrc16(write_data, write_data_len, crc16);
-    result = master->writeBlock(write_data, write_data_len);
+    crc16 = calculateCrc16(write_data, crc16);
+    result = master->writeBlock(write_data);
     if (result) {
       return result;
     }
   }
-  if (read_data) {
-    crc16 = calculateCrc16(static_cast<uint_fast8_t>(read_data_len), crc16);
-    result = master->writeByte(static_cast<uint_least8_t>(read_data_len));
+  if (!read_data.empty()) {
+    crc16 = calculateCrc16(static_cast<uint_fast8_t>(read_data.size()), crc16);
+    result = master->writeByte(static_cast<uint_least8_t>(read_data.size()));
     if (result) {
       return result;
     }
@@ -194,8 +186,7 @@
   crc16 ^= 0xFFFFU;
   const uint_least8_t crc16Bytes[] = {static_cast<uint_least8_t>(crc16),
                                       static_cast<uint_least8_t>(crc16 >> 8)};
-  result = master->writeBlock(crc16Bytes,
-                              sizeof(crc16Bytes) / sizeof(crc16Bytes[0]));
+  result = master->writeBlock(crc16Bytes);
   if (result) {
     return result;
   }
@@ -225,7 +216,7 @@
   if ((status & 0x8) == 0x8) {
     return make_error_code(InvalidStartError);
   }
-  if (write_data) {
+  if (!write_data.empty()) {
     result = master->readByte(status);
     if (result) {
       return result;
@@ -237,8 +228,8 @@
       return make_error_code(WriteNackError);
     }
   }
-  if (read_data) {
-    result = master->readBlock(read_data, read_data_len);
+  if (!read_data.empty()) {
+    result = master->readBlock(read_data);
   }
   return result;
 }
--- a/Devices/DS28E17.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS28E17.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -36,10 +36,11 @@
 #include <stdint.h>
 #include <MaximInterface/Links/SelectRom.hpp>
 #include <MaximInterface/Utilities/Export.h>
+#include <MaximInterface/Utilities/span.hpp>
 
 namespace MaximInterface {
 
-/// DS28E17 1-Wire®-to-I2C Master Bridge
+/// @brief DS28E17 1-Wire®-to-I2C Master Bridge
 /// @details The DS28E17 is a 1-Wire slave to I2C master bridge
 /// device that interfaces directly to I2C slaves at standard
 /// (100kHz max) or fast (400kHz max). Data transfers serially by
@@ -69,110 +70,102 @@
       : selectRom(selectRom), master(&master) {}
 
   void setMaster(OneWireMaster & master) { this->master = &master; }
+  
   void setSelectRom(const SelectRom & selectRom) {
     this->selectRom = selectRom;
   }
 
-  /// Write Data With Stop command.
+  /// @brief Write Data With Stop command.
   /// @details Output on I2C: S, Address + Write, Write Data [1-255], P
   /// @param[in] I2C_addr
   /// I2C slave address. The least significant bit of the I2C
   /// address is automatically cleared by the command.
-  /// @param[in] data I2C data to write.
-  /// @param[in] data_len Length of data. Valid from 1-255.
+  /// @param[in] data I2C data to write with length 1-255.
   /// @param[out] wr_status
   /// Indicates which write byte NACK’d. A value of 00h indicates all bytes
   /// were acknowledged by the slave. A non-zero value indicates the byte number
   /// that NACK’d. May be set to NULL.
   MaximInterface_EXPORT error_code
-  writeDataWithStop(uint_least8_t I2C_addr, const uint_least8_t * data,
-                    size_t data_len, uint_least8_t * wr_status = NULL);
+  writeDataWithStop(uint_least8_t I2C_addr, span<const uint_least8_t> data,
+                    uint_least8_t * wr_status = NULL);
 
-  /// Write Data No Stop command.
+  /// @brief Write Data No Stop command.
   /// @details Output on I2C: S, Address + Write, Write Data [1-255]
   /// @param[in] I2C_addr
   /// I2C slave address. The least significant bit of the I2C address
   /// is automatically cleared by the command.
-  /// @param[in] data I2C data to write.
-  /// @param[in] data_len Length of data. Valid from 1-255.
+  /// @param[in] data I2C data to write with length 1-255.
   /// @param[out] wr_status
   /// Indicates which write byte NACK’d. A value of 00h indicates all bytes
   /// were acknowledged by the slave. A non-zero value indicates the byte number
   /// that NACK’d. May be set to NULL.
   MaximInterface_EXPORT error_code
-  writeDataNoStop(uint_least8_t I2C_addr, const uint_least8_t * data,
-                  size_t data_len, uint_least8_t * wr_status = NULL);
+  writeDataNoStop(uint_least8_t I2C_addr, span<const uint_least8_t> data,
+                  uint_least8_t * wr_status = NULL);
 
-  /// Write Data Only command.
+  /// @brief Write Data Only command.
   /// @details Output on I2C: Write Data [1-255]
-  /// @param[in] data I2C data to write.
-  /// @param[in] data_len Length of data. Valid from 1-255.
+  /// @param[in] data I2C data to write with length 1-255.
   /// @param[out] wr_status
   /// Indicates which write byte NACK’d. A value of 00h indicates all bytes
   /// were acknowledged by the slave. A non-zero value indicates the byte number
   /// that NACK’d. May be set to NULL.
   MaximInterface_EXPORT error_code
-  writeDataOnly(const uint_least8_t * data, size_t data_len,
+  writeDataOnly(span<const uint_least8_t> data,
                 uint_least8_t * wr_status = NULL);
 
-  /// Write Data Only With Stop command.
+  /// @brief Write Data Only With Stop command.
   /// @details Output on I2C: Write Data [1-255], P
-  /// @param[in] data I2C data to write.
-  /// @param[in] data_len Length of data. Valid from 1-255.
+  /// @param[in] data I2C data to write with length 1-255.
   /// @param[out] wr_status
   /// Indicates which write byte NACK’d. A value of 00h indicates all bytes
   /// were acknowledged by the slave. A non-zero value indicates the byte number
   /// that NACK’d. May be set to NULL.
   MaximInterface_EXPORT error_code
-  writeDataOnlyWithStop(const uint_least8_t * data, size_t data_len,
+  writeDataOnlyWithStop(span<const uint_least8_t> data,
                         uint_least8_t * wr_status = NULL);
 
-  /// Write, Read Data With Stop command.
+  /// @brief Write, Read Data With Stop command.
   /// @details Output on I2C:
   /// S, Slave Address + Write, Write Data [1-255],
   /// Sr, Address + Read, Read Data [1-255], P (NACK last read byte)
   /// @param[in] I2C_addr
   /// I2C slave address. The least significant bit of the I2C address
   /// is automatically cleared and set by the command.
-  /// @param[in] write_data I2C data to write.
-  /// @param[in] write_data_len Length of write_data. Valid from 1-255.
-  /// @param[out] read_data I2C data that was read.
-  /// @param[in] read_data_len Length of read_data. Valid from 1-255.
+  /// @param[in] write_data I2C data to write with length 1-255.
+  /// @param[out] read_data I2C data that was read with length 1-255.
   /// @param[out] wr_status
   /// Indicates which write byte NACK’d. A value of 00h indicates all bytes
   /// were acknowledged by the slave. A non-zero value indicates the byte number
   /// that NACK’d. May be set to NULL.
   MaximInterface_EXPORT error_code writeReadDataWithStop(
-      uint_least8_t I2C_addr, const uint_least8_t * write_data,
-      size_t write_data_len, uint_least8_t * read_data, size_t read_data_len,
-      uint_least8_t * wr_status = NULL);
+      uint_least8_t I2C_addr, span<const uint_least8_t> write_data,
+      span<uint_least8_t> read_data, uint_least8_t * wr_status = NULL);
 
-  /// Read Data With Stop command.
+  /// @brief Read Data With Stop command.
   /// @details Output on I2C:
   /// S, Slave Address + Read, Read Data [1-255], P (NACK last read byte)
   /// @param[in]  I2C_addr
   /// I2C slave address. The least significant bit of the I2C address
   /// is automatically set by the command.
-  /// @param[out] data I2C data that was read.
-  /// @param[in] data_len Length of data. Valid from 1-255.
+  /// @param[out] data I2C data that was read with length 1-255.
   MaximInterface_EXPORT error_code readDataWithStop(uint_least8_t I2C_addr,
-                                                    uint_least8_t * data,
-                                                    size_t data_len);
+                                                    span<uint_least8_t> data);
 
   /// Write to Configuration Register of DS28E17.
   MaximInterface_EXPORT error_code writeConfigReg(I2CSpeed speed);
 
-  /// Read the Configuration Register of DS28E17.
+  /// @brief Read the Configuration Register of DS28E17.
   /// @param[out] speed Speed read from configuration register.
   MaximInterface_EXPORT error_code readConfigReg(I2CSpeed & speed);
 
-  /// The Enable Sleep Mode command puts the device into a low current mode.
+  /// @brief Put the device into a low current mode.
   /// @details All 1-Wire communication is ignored until woken up. Immediately
   /// after the command, the device monitors the WAKEUP input pin and exits
   /// sleep mode on a rising edge.
   MaximInterface_EXPORT error_code enableSleepMode();
 
-  /// Read the Device Revision of DS28E17.
+  /// @brief Read the Device Revision of DS28E17.
   /// @details The upper nibble is the major revision,
   /// and the lower nibble is the minor revision.
   /// @param[out] rev Device Revision.
@@ -195,8 +188,8 @@
   };
 
   error_code sendPacket(Command command, const uint_least8_t * I2C_addr,
-                        const uint_least8_t * write_data, size_t write_data_len,
-                        uint_least8_t * read_data, size_t read_data_len,
+                        span<const uint_least8_t> write_data,
+                        span<uint_least8_t> read_data,
                         uint_least8_t * wr_status);
 
   SelectRom selectRom;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Devices/DS28E38.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -0,0 +1,302 @@
+/*******************************************************************************
+* 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 <stddef.h>
+#include <algorithm>
+#include <MaximInterface/Utilities/Algorithm.hpp>
+#include <MaximInterface/Utilities/Error.hpp>
+#include "DS28E38.hpp"
+
+namespace MaximInterface {
+
+using std::copy;
+
+static const int readMemoryTimeMs = 30;
+static const int writeMemoryTimeMs = 65;
+static const int writeStateTimeMs = 15;
+static const int generateEccKeyPairTimeMs = 200;
+static const int generateEcdsaSignatureTimeMs = 130;
+static const int trngOnDemandCheckTimeMs = 20;
+static const int trngGenerationTimeMs = 10;
+
+const int DS28E38::decrementCounterPage;
+const int DS28E38::publicKeyXPage;
+const int DS28E38::publicKeyYPage;
+const int DS28E38::privateKeyPage;
+const int DS28E38::memoryPages;
+
+error_code DS28E38::writeMemory(int pageNum, Page::const_span page) {
+  if (pageNum < 0 || pageNum >= memoryPages) {
+    return make_error_code(InvalidParameterError);
+  }
+
+  uint_least8_t command[2 + Page::size];
+  command[0] = 0x96;
+  command[1] = pageNum;
+  copy(page.begin(), page.end(), command + 2);
+  return runCommand(command, writeMemoryTimeMs);
+}
+
+error_code DS28E38::readMemory(int pageNum, Page::span page) {
+  if (pageNum < 0 || pageNum >= memoryPages) {
+    return make_error_code(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());
+  }
+  return result;
+}
+
+error_code DS28E38::readStatus(bool entropyHealthTest, Status & status) {
+  int delay = readMemoryTimeMs;
+  if (entropyHealthTest) {
+    delay += trngOnDemandCheckTimeMs;
+  }
+  uint_least8_t buffer[Status::PageProtectionList::csize + ManId::size +
+                       Status::RomVersion::csize + 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.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;
+    }
+  }
+  return result;
+}
+
+error_code DS28E38::setPageProtection(int pageNum,
+                                      const PageProtection & protection) {
+  if (pageNum < 0 || pageNum >= memoryPages) {
+    return make_error_code(InvalidParameterError);
+  }
+
+  int delay = writeStateTimeMs;
+  if (pageNum == decrementCounterPage) {
+    delay += writeMemoryTimeMs;
+  }
+  const uint_least8_t command[] = {
+      0xC3, static_cast<uint_least8_t>(pageNum),
+      static_cast<uint_least8_t>(protection.to_ulong())};
+  return runCommand(command, delay);
+}
+
+error_code
+DS28E38::computeAndReadPageAuthentication(int pageNum, bool anonymous,
+                                          Page::const_span challenge,
+                                          Ecc256::Signature::span signature) {
+  if (pageNum < 0 || pageNum >= memoryPages) {
+    return make_error_code(InvalidParameterError);
+  }
+
+  const size_t commandSize = 2 + Page::size;
+  const size_t responseSize = 1 + 2 * Ecc256::Scalar::size;
+  uint_least8_t buffer[MaximInterface_MAX(commandSize, responseSize)];
+  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, commandSize),
+                                       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());
+  }
+  return result;
+}
+
+error_code DS28E38::decrementCounter() {
+  const uint_least8_t command = 0xC9;
+  return runCommand(make_span(&command, 1), writeMemoryTimeMs);
+}
+
+error_code DS28E38::disableDevice() {
+  const uint_least8_t command[] = {0x33, 0x9E, 0xA7, 0x49, 0xFB,
+                                   0x10, 0x62, 0x0A, 0x26};
+  return runCommand(command, writeStateTimeMs);
+}
+
+error_code DS28E38::generateEcc256KeyPair(bool privateKeyPuf,
+                                          bool writeProtectEnable) {
+  int delay = generateEccKeyPairTimeMs;
+  if (writeProtectEnable) {
+    delay += writeStateTimeMs;
+  }
+  uint_least8_t command[] = {0xCB, 0x00};
+  if (privateKeyPuf) {
+    command[1] |= 0x01;
+  }
+  if (writeProtectEnable) {
+    command[1] |= 0x80;
+  }
+  return runCommand(command, delay);
+}
+
+error_code DS28E38::readRng(span<uint_least8_t> data) {
+  const span<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] = 0xD2;
+  buffer[1] = 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());
+  }
+  return result;
+}
+
+error_code DS28E38::runCommand(span<const uint_least8_t> command, int delayTime,
+                               span<uint_least8_t> & response) {
+  const span<const uint_least8_t>::index_type responseInputSize =
+      response.size();
+  error_code result = doRunCommand(command, delayTime, response);
+  if (result) {
+    return result;
+  }
+  if (response.empty()) {
+    return make_error_code(InvalidResponseError);
+  }
+  // Parse command result byte.
+  switch (response[0]) {
+  case 0xAA:
+    // Success response.
+    if (response.size() != responseInputSize) {
+      result = make_error_code(InvalidResponseError);
+    }
+    break;
+
+  case 0x00:
+    result = make_error_code(InvalidResponseError);
+    break;
+
+  default:
+    result.assign(response[0], errorCategory());
+    break;
+  }
+  response = response.subspan(1);
+  return result;
+}
+
+error_code DS28E38::runCommand(span<const uint_least8_t> command,
+                               int delayTime) {
+  uint_least8_t buffer;
+  span<uint_least8_t> response(&buffer, 1);
+  return runCommand(command, delayTime, response);
+}
+
+const error_category & DS28E38::errorCategory() {
+  static class : public error_category {
+  public:
+    virtual const char * name() const { return "DS28E38"; }
+
+    virtual std::string message(int condition) const {
+      switch (condition) {
+      case InvalidOperationError:
+        return "Invalid Operation Error";
+
+      case InvalidParameterError:
+        return "Invalid Parameter Error";
+
+      case InvalidSequenceError:
+        return "Invalid Sequence Error";
+
+      case InternalError:
+        return "Internal Error";
+
+      case DeviceDisabledError:
+        return "Device Disabled Error";
+
+      case InvalidResponseError:
+        return "Invalid Response Error";
+      }
+      return defaultErrorMessage(condition);
+    }
+  } instance;
+  return instance;
+}
+
+error_code readManId(DS28E38 & ds28e38, ManId::span manId) {
+  DS28E38::Status status;
+  const error_code result = ds28e38.readStatus(false, status);
+  if (!result) {
+    copy(make_span(status.manId), manId);
+  }
+  return result;
+}
+
+DS28E38::PageAuthenticationData &
+DS28E38::PageAuthenticationData::setAnonymousRomId() {
+  std::fill(romId().begin(), romId().end(), 0xFF);
+  return *this;
+}
+
+} // namespace MaximInterface
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Devices/DS28E38.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -0,0 +1,316 @@
+/*******************************************************************************
+* 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.
+*******************************************************************************/
+
+#ifndef MaximInterface_DS28E38
+#define MaximInterface_DS28E38
+
+#include <stdint.h>
+#include <MaximInterface/Links/RunCommand.hpp>
+#include <MaximInterface/Utilities/array_span.hpp>
+#include <MaximInterface/Utilities/Ecc256.hpp>
+#include <MaximInterface/Utilities/Export.h>
+#include <MaximInterface/Utilities/FlagSet.hpp>
+#include <MaximInterface/Utilities/ManId.hpp>
+#include <MaximInterface/Utilities/system_error.hpp>
+
+namespace MaximInterface {
+
+class DS28E38 {
+public:
+  /// Device command results.
+  enum ErrorValue {
+    InvalidOperationError = 0x55,
+    InvalidParameterError = 0x77,
+    InvalidSequenceError = 0x33,
+    InternalError = 0x22,
+    DeviceDisabledError = 0x88,
+    InvalidResponseError =
+        0x100 ///< Command response does not match expected format.
+  };
+
+  /// @name Device memory pages
+  /// @{
+  
+  static const int decrementCounterPage = 3;
+  static const int publicKeyXPage = 4;
+  static const int publicKeyYPage = 5;
+  static const int privateKeyPage = 6;
+  
+  /// @}
+
+  static const int memoryPages = 7;
+
+  /// Holds a device memory page.
+  typedef array_span<uint_least8_t, 32> Page;
+
+  // Format page authentication input data.
+  class PageAuthenticationData;
+
+  /// Page protection types.
+  enum PageProtectionType {
+    RP = 0x01, ///< Read protection.
+    WP = 0x02, ///< Write protection.
+    EM = 0x04, ///< EPROM emulation mode.
+    DC = 0x08, ///< Decrement counter.
+    PF = 0x10  ///< PUF used as private key.
+  };
+  typedef FlagSet<PageProtectionType, 5> PageProtection;
+
+  struct Status {
+    enum EntropyHealthTestStatus {
+      TestNotPerformed = 0xFF,
+      EntropyHealthy = 0xAA,
+      EntropyNotHealthy = 0xDD
+    };
+
+    typedef array<PageProtection, memoryPages> PageProtectionList;
+    typedef array<uint_least8_t, 2> RomVersion;
+
+    PageProtectionList pageProtection;
+    ManId::array manId;
+    RomVersion romVersion;
+    EntropyHealthTestStatus entropyHealthTestStatus;
+  };
+
+  explicit DS28E38(const RunCommand & runCommand) : doRunCommand(runCommand) {}
+
+  void setRunCommand(const RunCommand & runCommand) {
+    doRunCommand = runCommand;
+  }
+
+  /// @brief Write memory with no protection.
+  /// @param pageNum Number of page to write.
+  /// @param page Data to write.
+  MaximInterface_EXPORT error_code writeMemory(int pageNum,
+                                               Page::const_span page);
+
+  /// @brief Read memory with no protection.
+  /// @param pageNum Number of page to read.
+  /// @param[out] page Data that was read.
+  MaximInterface_EXPORT error_code readMemory(int pageNum, Page::span page);
+
+  /// @brief
+  /// Reads the current status of the device and optionally performs an
+  /// entropy health test.
+  /// @param entropyHealthTest True to perform an entropy health test.
+  /// @param[out] status Status that was read.
+  MaximInterface_EXPORT error_code readStatus(bool entropyHealthTest,
+                                              Status & status);
+
+  /// @brief Set the protection settings of a page.
+  /// @param pageNum Number of page to write.
+  /// @param protection Protection to write.
+  MaximInterface_EXPORT error_code
+  setPageProtection(int pageNum, const PageProtection & protection);
+
+  /// @brief Compute and read page authentication with ECDSA.
+  /// @param pageNum Number of page to authenticate.
+  /// @param anonymous True to disable use of ROM ID in computation.
+  /// @param challenge Random challenge used to prevent replay attacks.
+  /// @param[out] signature Computed page signature.
+  MaximInterface_EXPORT error_code computeAndReadPageAuthentication(
+      int pageNum, bool anonymous, Page::const_span challenge,
+      Ecc256::Signature::span signature);
+
+  /// Decrement the decrement-only counter.
+  MaximInterface_EXPORT error_code decrementCounter();
+
+  /// Permanently disable the device.
+  MaximInterface_EXPORT error_code disableDevice();
+
+  /// @brief Generate a new ECDSA public key from an existing private key.
+  /// @param privateKeyPuf True if PUF is used as the private key.
+  /// @param writeProtectEnable True to lock the key against further writes.
+  MaximInterface_EXPORT error_code
+  generateEcc256KeyPair(bool privateKeyPuf, bool writeProtectEnable);
+
+  /// @brief Read a block of random data from the RNG.
+  /// @param[out] data Random data from RNG with length from 1 to 64.
+  MaximInterface_EXPORT error_code readRng(span<uint_least8_t> data);
+
+  MaximInterface_EXPORT static const error_category & errorCategory();
+
+protected:
+  MaximInterface_EXPORT error_code runCommand(span<const uint_least8_t> command,
+                                              int delayTime,
+                                              span<uint_least8_t> & response);
+
+  MaximInterface_EXPORT error_code runCommand(span<const uint_least8_t> command,
+                                              int delayTime);
+
+private:
+  RunCommand doRunCommand;
+};
+
+inline error_code make_error_code(DS28E38::ErrorValue e) {
+  return error_code(e, DS28E38::errorCategory());
+}
+
+/// @brief Read the device MAN ID using the Read Status command.
+/// @param ds28e38 Device to read.
+/// @param[out] manId Read MAN ID valid when operation is successful.
+MaximInterface_EXPORT error_code readManId(DS28E38 & ds28e38,
+                                           ManId::span manId);
+
+/// Format page authentication input data.
+class DS28E38::PageAuthenticationData {
+public:
+  typedef array_span<uint_least8_t,
+                     RomId::size + 2 * Page::size + 1 + ManId::size>
+      Result;
+
+  PageAuthenticationData() : result_() {}
+
+  /// Formatted data result.
+  Result::const_span result() const { return result_; }
+
+  /// @name ROM ID
+  /// @brief 1-Wire ROM ID of the device.
+  /// @{
+  
+  /// Get mutable ROM ID.
+  RomId::span romId() {
+    return make_span(result_).subspan<romIdIdx, RomId::size>();
+  }
+  
+  /// Get immutable ROM ID.
+  RomId::const_span romId() const {
+    return const_cast<PageAuthenticationData &>(*this).romId();
+  }
+  
+  /// Set ROM ID.
+  PageAuthenticationData & setRomId(RomId::const_span romId) {
+    copy(romId, this->romId());
+    return *this;
+  }
+  
+  /// Set ROM ID for use in anonymous mode.
+  MaximInterface_EXPORT PageAuthenticationData & setAnonymousRomId();
+  
+  /// @}
+
+  /// @name Page
+  /// @brief Data from a device memory page.
+  /// @{
+  
+  /// Get mutable page.
+  Page::span page() {
+    return make_span(result_).subspan<pageIdx, Page::size>();
+  }
+  
+  /// Get immutable page.
+  Page::const_span page() const {
+    return const_cast<PageAuthenticationData &>(*this).page();
+  }
+  
+  /// Set page.
+  PageAuthenticationData & setPage(Page::const_span page) {
+    copy(page, this->page());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Challenge
+  /// @brief Random challenge used to prevent replay attacks.
+  /// @{
+
+  /// Get mutable Challenge.
+  Page::span challenge() {
+    return make_span(result_).subspan<challengeIdx, Page::size>();
+  }
+  
+  /// Get immutable Challenge.
+  Page::const_span challenge() const {
+    return const_cast<PageAuthenticationData &>(*this).challenge();
+  }
+  
+  /// Set Challenge.
+  PageAuthenticationData & setChallenge(Page::const_span challenge) {
+    copy(challenge, this->challenge());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name Page number
+  /// @brief Number of the page to use data from.
+  /// @{
+  
+  /// Get page number.
+  int pageNum() const { return result_[pageNumIdx]; }
+  
+  /// Set page number.
+  PageAuthenticationData & setPageNum(int pageNum) {
+    result_[pageNumIdx] = pageNum;
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name MAN ID
+  /// @brief Manufacturer ID of the device.
+  /// @{
+  
+  /// Get mutable MAN ID.
+  ManId::span manId() {
+    return make_span(result_).subspan<manIdIdx, ManId::size>();
+  }
+  
+  /// Get immutable MAN ID.
+  ManId::const_span manId() const {
+    return const_cast<PageAuthenticationData &>(*this).manId();
+  }
+  
+  /// Set MAN ID.
+  PageAuthenticationData & setManId(ManId::const_span manId) {
+    copy(manId, this->manId());
+    return *this;
+  }
+  
+  /// @}
+
+private:
+  typedef Result::span::index_type index;
+
+  static const index romIdIdx = 0;
+  static const index pageIdx = romIdIdx + RomId::size;
+  static const index challengeIdx = pageIdx + Page::size;
+  static const index pageNumIdx = challengeIdx + Page::size;
+  static const index manIdIdx = pageNumIdx + 1;
+
+  Result::array result_;
+};
+
+} // namespace MaximInterface
+
+#endif
--- a/Devices/DS9400.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS9400.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -59,7 +59,7 @@
   const uint_least8_t packet[] = {'Q', data};
   error_code result = uart->clearReadBuffer();
   if (!result) {
-    result = uart->writeBlock(packet, sizeof(packet) / sizeof(packet[0]));
+    result = uart->writeBlock(packet);
     if (!result) {
       result = uart->readByte(data);
       if (!result && data != 0) {
@@ -83,7 +83,7 @@
 
 error_code DS9400::configure(uint_least8_t config) {
   const uint_least8_t packet[] = {'C', config};
-  return uart->writeBlock(packet, sizeof(packet) / sizeof(packet[0]));
+  return uart->writeBlock(packet);
 }
 
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Devices/DS9400.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS9400.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -48,9 +48,13 @@
   MaximInterface_EXPORT error_code waitAwake();
 
   MaximInterface_EXPORT error_code start();
+  
   MaximInterface_EXPORT virtual error_code start(uint_least8_t address);
+  
   MaximInterface_EXPORT virtual error_code stop();
+  
   MaximInterface_EXPORT virtual error_code writeByte(uint_least8_t data);
+  
   MaximInterface_EXPORT virtual error_code readByte(AckStatus status,
                                                     uint_least8_t & data);
 
@@ -63,4 +67,4 @@
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Devices/DS9481P_300.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS9481P_300.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,7 +35,7 @@
 
 namespace MaximInterface {
 
-DS9481P_300::DS9481P_300(const Sleep & sleep, SerialPort & serialPort)
+DS9481P_300::DS9481P_300(Sleep & sleep, SerialPort & serialPort)
     : serialPort(&serialPort), currentBus(OneWire), ds2480b(sleep, serialPort),
       oneWireMaster_(*this), ds9400(serialPort), i2cMaster_(*this) {}
 
@@ -135,20 +135,19 @@
 }
 
 error_code
-DS9481P_300::OneWireMasterImpl::writeBlock(const uint_least8_t * sendBuf,
-                                           size_t sendLen) {
+DS9481P_300::OneWireMasterImpl::writeBlock(span<const uint_least8_t> sendBuf) {
   error_code result = parent->selectBus(OneWire);
   if (!result) {
-    result = OneWireMasterDecorator::writeBlock(sendBuf, sendLen);
+    result = OneWireMasterDecorator::writeBlock(sendBuf);
   }
   return result;
 }
 
-error_code DS9481P_300::OneWireMasterImpl::readBlock(uint_least8_t * recvBuf,
-                                                     size_t recvLen) {
+error_code
+DS9481P_300::OneWireMasterImpl::readBlock(span<uint_least8_t> recvBuf) {
   error_code result = parent->selectBus(OneWire);
   if (!result) {
-    result = OneWireMasterDecorator::readBlock(recvBuf, recvLen);
+    result = OneWireMasterDecorator::readBlock(recvBuf);
   }
   return result;
 }
@@ -201,22 +200,20 @@
   return result;
 }
 
-error_code DS9481P_300::I2CMasterImpl::writeBlock(const uint_least8_t * data,
-                                                  size_t dataLen) {
+error_code
+DS9481P_300::I2CMasterImpl::writeBlock(span<const uint_least8_t> data) {
   error_code result = parent->selectBus(I2C);
   if (!result) {
-    result = I2CMasterDecorator::writeBlock(data, dataLen);
+    result = I2CMasterDecorator::writeBlock(data);
   }
   return result;
 }
 
 error_code DS9481P_300::I2CMasterImpl::writePacketImpl(
-    uint_least8_t address, const uint_least8_t * data, size_t dataLen,
-    bool sendStop) {
+    uint_least8_t address, span<const uint_least8_t> data, bool sendStop) {
   error_code result = parent->selectBus(I2C);
   if (!result) {
-    result = I2CMasterDecorator::writePacketImpl(address, data, dataLen,
-                                                 sendStop);
+    result = I2CMasterDecorator::writePacketImpl(address, data, sendStop);
   }
   return result;
 }
@@ -231,23 +228,20 @@
 }
 
 error_code DS9481P_300::I2CMasterImpl::readBlock(AckStatus status,
-                                                 uint_least8_t * data,
-                                                 size_t dataLen) {
+                                                 span<uint_least8_t> data) {
   error_code result = parent->selectBus(I2C);
   if (!result) {
-    result = I2CMasterDecorator::readBlock(status, data, dataLen);
+    result = I2CMasterDecorator::readBlock(status, data);
   }
   return result;
 }
 
 error_code DS9481P_300::I2CMasterImpl::readPacketImpl(uint_least8_t address,
-                                                      uint_least8_t * data,
-                                                      size_t dataLen,
+                                                      span<uint_least8_t> data,
                                                       bool sendStop) {
   error_code result = parent->selectBus(I2C);
   if (!result) {
-    result = I2CMasterDecorator::readPacketImpl(address, data, dataLen,
-                                                sendStop);
+    result = I2CMasterDecorator::readPacketImpl(address, data, sendStop);
   }
   return result;
 }
@@ -260,4 +254,4 @@
   return configure('O');
 }
 
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Devices/DS9481P_300.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Devices/DS9481P_300.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -46,10 +46,10 @@
 /// DS9481P-300 USB to 1-Wire and I2C adapter.
 class DS9481P_300 {
 public:
-  MaximInterface_EXPORT DS9481P_300(const Sleep & sleep,
-                                    SerialPort & serialPort);
+  MaximInterface_EXPORT DS9481P_300(Sleep & sleep, SerialPort & serialPort);
 
-  void setSleep(const Sleep & sleep) { ds2480b.setSleep(sleep); }
+  void setSleep(Sleep & sleep) { ds2480b.setSleep(sleep); }
+  
   void setSerialPort(SerialPort & serialPort) {
     this->serialPort = &serialPort;
     ds2480b.setUart(serialPort);
@@ -57,13 +57,16 @@
   }
 
   MaximInterface_EXPORT error_code connect(const std::string & portName);
+  
   MaximInterface_EXPORT error_code disconnect();
+  
   MaximInterface_EXPORT bool connected() const;
+  
   MaximInterface_EXPORT std::string portName() const;
 
   /// Access the 1-Wire master when connected to an adapter.
   OneWireMaster & oneWireMaster() { return oneWireMaster_; }
-  
+
   /// Access the I2C master when connected to an adapter.
   I2CMaster & i2cMaster() { return i2cMaster_; }
 
@@ -73,18 +76,28 @@
     explicit OneWireMasterImpl(DS9481P_300 & parent)
         : OneWireMasterDecorator(parent.ds2480b), parent(&parent) {}
 
-    virtual error_code reset();
-    virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel);
-    virtual error_code writeByteSetLevel(uint_least8_t sendByte,
-                                         Level afterLevel);
-    virtual error_code readByteSetLevel(uint_least8_t & recvByte,
-                                        Level afterLevel);
-    virtual error_code writeBlock(const uint_least8_t * sendBuf,
-                                  size_t sendLen);
-    virtual error_code readBlock(uint_least8_t * recvBuf, size_t recvLen);
-    virtual error_code setSpeed(Speed newSpeed);
-    virtual error_code setLevel(Level newLevel);
-    virtual error_code triplet(TripletData & data);
+    MaximInterface_EXPORT virtual error_code reset();
+    
+    MaximInterface_EXPORT virtual error_code
+    touchBitSetLevel(bool & sendRecvBit, Level afterLevel);
+    
+    MaximInterface_EXPORT virtual error_code
+    writeByteSetLevel(uint_least8_t sendByte, Level afterLevel);
+    
+    MaximInterface_EXPORT virtual error_code
+    readByteSetLevel(uint_least8_t & recvByte, Level afterLevel);
+    
+    MaximInterface_EXPORT virtual error_code
+    writeBlock(span<const uint_least8_t> sendBuf);
+    
+    MaximInterface_EXPORT virtual error_code
+    readBlock(span<uint_least8_t> recvBuf);
+    
+    MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed);
+    
+    MaximInterface_EXPORT virtual error_code setLevel(Level newLevel);
+    
+    MaximInterface_EXPORT virtual error_code triplet(TripletData & data);
 
   private:
     DS9481P_300 * parent;
@@ -95,21 +108,28 @@
     explicit I2CMasterImpl(DS9481P_300 & parent)
         : I2CMasterDecorator(parent.ds9400), parent(&parent) {}
 
-    virtual error_code start(uint_least8_t address);
-    virtual error_code stop();
-    virtual error_code writeByte(uint_least8_t data);
-    virtual error_code writeBlock(const uint_least8_t * data, size_t dataLen);
-    virtual error_code readByte(AckStatus status, uint_least8_t & data);
-    virtual error_code readBlock(AckStatus status, uint_least8_t * data,
-                                 size_t dataLen);
+    MaximInterface_EXPORT virtual error_code start(uint_least8_t address);
+    
+    MaximInterface_EXPORT virtual error_code stop();
+    
+    MaximInterface_EXPORT virtual error_code writeByte(uint_least8_t data);
+    
+    MaximInterface_EXPORT virtual error_code
+    writeBlock(span<const uint_least8_t> data);
+    
+    MaximInterface_EXPORT virtual error_code readByte(AckStatus status,
+                                                      uint_least8_t & data);
+    MaximInterface_EXPORT virtual error_code
+    readBlock(AckStatus status, span<uint_least8_t> data);
 
   protected:
-    virtual error_code writePacketImpl(uint_least8_t address,
-                                       const uint_least8_t * data,
-                                       size_t dataLen, bool sendStop);
-    virtual error_code readPacketImpl(uint_least8_t address,
-                                      uint_least8_t * data, size_t dataLen,
-                                      bool sendStop);
+    MaximInterface_EXPORT virtual error_code
+    writePacketImpl(uint_least8_t address, span<const uint_least8_t> data,
+                    bool sendStop);
+                    
+    MaximInterface_EXPORT virtual error_code
+    readPacketImpl(uint_least8_t address, span<uint_least8_t> data,
+                   bool sendStop);
 
   private:
     DS9481P_300 * parent;
@@ -117,8 +137,7 @@
 
   class DS2480BWithEscape : public DS2480B {
   public:
-    DS2480BWithEscape(const Sleep & sleep, Uart & uart)
-      : DS2480B(sleep, uart) {}
+    DS2480BWithEscape(Sleep & sleep, Uart & uart) : DS2480B(sleep, uart) {}
 
     error_code escape();
   };
@@ -148,4 +167,4 @@
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Links/I2CMaster.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/I2CMaster.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,20 +35,21 @@
 
 namespace MaximInterface {
 
-error_code I2CMaster::writeBlock(const uint_least8_t * data, size_t dataLen) {
+error_code I2CMaster::writeBlock(span<const uint_least8_t> data) {
   error_code result;
-  for (size_t i = 0; (i < dataLen) && !result; i++) {
+  for (span<const uint_least8_t>::index_type i = 0;
+       i < data.size() && !result; ++i) {
     result = writeByte(data[i]);
   }
   return result;
 }
 
 error_code I2CMaster::writePacketImpl(uint_least8_t address,
-                                      const uint_least8_t * data,
-                                      size_t dataLen, bool sendStop) {
+                                      span<const uint_least8_t> data,
+                                      bool sendStop) {
   error_code result = start(address & 0xFE);
   if (!result) {
-    result = writeBlock(data, dataLen);
+    result = writeBlock(data);
   }
   if (sendStop) {
     error_code stopResult = stop();
@@ -59,21 +60,19 @@
   return result;
 }
 
-error_code I2CMaster::readBlock(AckStatus status, uint_least8_t * data,
-                                size_t dataLen) {
+error_code I2CMaster::readBlock(AckStatus status, span<uint_least8_t> data) {
   error_code result;
-  for (size_t i = 0; (i < dataLen) && !result; i++) {
-    result = readByte(i == (dataLen - 1) ? status : Ack, data[i]);
+  for (span<uint_least8_t>::index_type i = 0; i < data.size() && !result; ++i) {
+    result = readByte(i == (data.size() - 1) ? status : Ack, data[i]);
   }
   return result;
 }
 
 error_code I2CMaster::readPacketImpl(uint_least8_t address,
-                                     uint_least8_t * data, size_t dataLen,
-                                     bool sendStop) {
+                                     span<uint_least8_t> data, bool sendStop) {
   error_code result = start(address | 0x01);
   if (!result) {
-    result = readBlock(Nack, data, dataLen);
+    result = readBlock(Nack, data);
   }
   if (sendStop) {
     error_code stopResult = stop();
@@ -102,4 +101,4 @@
   return instance;
 }
 
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Links/I2CMaster.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/I2CMaster.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -33,9 +33,9 @@
 #ifndef MaximInterface_I2CMaster
 #define MaximInterface_I2CMaster
 
-#include <stddef.h>
 #include <stdint.h>
 #include <MaximInterface/Utilities/Export.h>
+#include <MaximInterface/Utilities/span.hpp>
 #include <MaximInterface/Utilities/system_error.hpp>
 
 namespace MaximInterface {
@@ -51,7 +51,7 @@
 
   virtual ~I2CMaster() {}
 
-  /// Send start condition and address on the bus.
+  /// @brief Send start condition and address on the bus.
   /// @param address Address with R/W bit.
   virtual error_code start(uint_least8_t address) = 0;
   
@@ -63,60 +63,63 @@
   
   /// Write data block to the bus.
   MaximInterface_EXPORT virtual error_code
-  writeBlock(const uint_least8_t * data, size_t dataLen);
+  writeBlock(span<const uint_least8_t> data);
   
+  /// @brief
   /// Perform a complete write transaction on the bus with optional stop
   /// condition.
   /// @param address Address in 8-bit format.
+  /// @param data Data to write to the bus.
   /// @param sendStop
   /// True to send a stop condition or false to set up a repeated start.
-  error_code writePacket(uint_least8_t address, const uint_least8_t * data,
-                         size_t dataLen, bool sendStop = true) {
-    return writePacketImpl(address, data, dataLen, sendStop);
+  error_code writePacket(uint_least8_t address, span<const uint_least8_t> data,
+                         bool sendStop = true) {
+    return writePacketImpl(address, data, sendStop);
   }
   
-  /// Read data byte from the bus.
+  /// @brief Read data byte from the bus.
   /// @param status Determines whether an ACK or NACK is sent after reading.
   /// @param[out] data Data read from the bus if successful.
   virtual error_code readByte(AckStatus status, uint_least8_t & data) = 0;
   
-  /// Read data block from the bus.
+  /// @brief Read data block from the bus.
   /// @param status Determines whether an ACK or NACK is sent after reading.
   /// @param[out] data Data read from the bus if successful.
-  /// @param dataLen Number of bytes to read and length of data.
   MaximInterface_EXPORT virtual error_code
-  readBlock(AckStatus status, uint_least8_t * data, size_t dataLen);
+  readBlock(AckStatus status, span<uint_least8_t> data);
   
+  /// @brief
   /// Perform a complete read transaction on the bus with optional stop
   /// condition.
   /// @param address Address in 8-bit format.
+  /// @param[out] data Data read from the bus if successful.
   /// @param sendStop
   /// True to send a stop condition or false to set up a repeated start.
-  error_code readPacket(uint_least8_t address, uint_least8_t * data,
-                        size_t dataLen, bool sendStop = true) {
-    return readPacketImpl(address, data, dataLen, sendStop);
+  error_code readPacket(uint_least8_t address, span<uint_least8_t> data,
+                        bool sendStop = true) {
+    return readPacketImpl(address, data, sendStop);
   }
 
   MaximInterface_EXPORT static const error_category & errorCategory();
 
 protected:
   MaximInterface_EXPORT virtual error_code
-  writePacketImpl(uint_least8_t address, const uint_least8_t * data,
-                  size_t dataLen, bool sendStop);
+  writePacketImpl(uint_least8_t address, span<const uint_least8_t> data,
+                  bool sendStop);
  
-  MaximInterface_EXPORT virtual error_code readPacketImpl(uint_least8_t address,
-                                                          uint_least8_t * data,
-                                                          size_t dataLen,
-                                                          bool sendStop);
+  MaximInterface_EXPORT virtual error_code
+  readPacketImpl(uint_least8_t address, span<uint_least8_t> data,
+                 bool sendStop);
 };
 
 inline error_code make_error_code(I2CMaster::ErrorValue e) {
   return error_code(e, I2CMaster::errorCategory());
 }
+
 inline error_condition make_error_condition(I2CMaster::ErrorValue e) {
   return error_condition(e, I2CMaster::errorCategory());
 }
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Links/I2CMasterDecorator.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/I2CMasterDecorator.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,40 +35,39 @@
 namespace MaximInterface {
 
 error_code I2CMasterDecorator::start(uint_least8_t address) {
-  return i2c->start(address);
+  return master->start(address);
 }
 
-error_code I2CMasterDecorator::stop() { return i2c->stop(); }
+error_code I2CMasterDecorator::stop() { return master->stop(); }
 
 error_code I2CMasterDecorator::writeByte(uint_least8_t data) {
-  return i2c->writeByte(data);
+  return master->writeByte(data);
 }
 
-error_code I2CMasterDecorator::writeBlock(const uint_least8_t * data,
-                                          size_t dataLen) {
-  return i2c->writeBlock(data, dataLen);
+error_code I2CMasterDecorator::writeBlock(span<const uint_least8_t> data) {
+  return master->writeBlock(data);
 }
 
 error_code I2CMasterDecorator::writePacketImpl(uint_least8_t address,
-                                               const uint_least8_t * data,
-                                               size_t dataLen, bool sendStop) {
-  return i2c->writePacket(address, data, dataLen, sendStop);
+                                               span<const uint_least8_t> data,
+                                               bool sendStop) {
+  return master->writePacket(address, data, sendStop);
 }
 
 error_code I2CMasterDecorator::readByte(AckStatus status,
                                         uint_least8_t & data) {
-  return i2c->readByte(status, data);
+  return master->readByte(status, data);
 }
 
-error_code I2CMasterDecorator::readBlock(AckStatus status, uint_least8_t * data,
-                                         size_t dataLen) {
-  return i2c->readBlock(status, data, dataLen);
+error_code I2CMasterDecorator::readBlock(AckStatus status,
+                                         span<uint_least8_t> data) {
+  return master->readBlock(status, data);
 }
 
 error_code I2CMasterDecorator::readPacketImpl(uint_least8_t address,
-                                              uint_least8_t * data,
-                                              size_t dataLen, bool sendStop) {
-  return i2c->readPacket(address, data, dataLen, sendStop);
+                                              span<uint_least8_t> data,
+                                              bool sendStop) {
+  return master->readPacket(address, data, sendStop);
 }
 
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Links/I2CMasterDecorator.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/I2CMasterDecorator.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -40,34 +40,39 @@
 
 class I2CMasterDecorator : public I2CMaster {
 protected:
-  explicit I2CMasterDecorator(I2CMaster & i2c) : i2c(&i2c) {}
+  explicit I2CMasterDecorator(I2CMaster & master) : master(&master) {}
 
 public:
-  void setI2CMaster(I2CMaster & i2c) { this->i2c = &i2c; }
+  void setMaster(I2CMaster & master) { this->master = &master; }
 
   MaximInterface_EXPORT virtual error_code start(uint_least8_t address);
+  
   MaximInterface_EXPORT virtual error_code stop();
+  
   MaximInterface_EXPORT virtual error_code writeByte(uint_least8_t data);
+  
   MaximInterface_EXPORT virtual error_code
-  writeBlock(const uint_least8_t * data, size_t dataLen);
+  writeBlock(span<const uint_least8_t> data);
+  
   MaximInterface_EXPORT virtual error_code readByte(AckStatus status,
                                                     uint_least8_t & data);
+  
   MaximInterface_EXPORT virtual error_code
-  readBlock(AckStatus status, uint_least8_t * data, size_t dataLen);
+  readBlock(AckStatus status, span<uint_least8_t> data);
 
 protected:
   MaximInterface_EXPORT virtual error_code
-  writePacketImpl(uint_least8_t address, const uint_least8_t * data,
-                  size_t dataLen, bool sendStop);
-  MaximInterface_EXPORT virtual error_code readPacketImpl(uint_least8_t address,
-                                                          uint_least8_t * data,
-                                                          size_t dataLen,
-                                                          bool sendStop);
+  writePacketImpl(uint_least8_t address, span<const uint_least8_t> data,
+                  bool sendStop);
+                  
+  MaximInterface_EXPORT virtual error_code
+  readPacketImpl(uint_least8_t address, span<uint_least8_t> data,
+                 bool sendStop);
 
 private:
-  I2CMaster * i2c;
+  I2CMaster * master;
 };
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Links/LoggingI2CMaster.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/LoggingI2CMaster.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -41,14 +41,13 @@
 static const char startString[] = "S ";
 static const char stopString[] = "P";
 
-static string formatDataString(const uint_least8_t * data, size_t dataSize,
-                               bool read) {
+static string formatDataString(span<const uint_least8_t> data, bool read) {
   string dataBuilder;
-  for (size_t i = 0; i < dataSize; i++) {
+  for (span<const uint_least8_t>::index_type i = 0; i < data.size(); ++i) {
     if (read) {
       dataBuilder.append(1, '[');
     }
-    dataBuilder.append(byteArrayToHexString(data + i, 1));
+    dataBuilder.append(byteArrayToHexString(data.subspan(i, 1)));
     if (read) {
       dataBuilder.append(1, ']');
     }
@@ -66,7 +65,7 @@
 
 error_code LoggingI2CMaster::start(uint_least8_t address) {
   messageBuilder.append(startString);
-  messageBuilder.append(formatDataString(&address, 1, false));
+  messageBuilder.append(formatDataString(make_span(&address, 1), false));
   return I2CMasterDecorator::start(address);
 }
 
@@ -77,25 +76,24 @@
 }
 
 error_code LoggingI2CMaster::writeByte(uint_least8_t data) {
-  messageBuilder.append(formatDataString(&data, 1, false));
+  messageBuilder.append(formatDataString(make_span(&data, 1), false));
   return I2CMasterDecorator::writeByte(data);
 }
 
-error_code LoggingI2CMaster::writeBlock(const uint_least8_t * data,
-                                        size_t dataLen) {
-  messageBuilder.append(formatDataString(data, dataLen, false));
-  return I2CMasterDecorator::writeBlock(data, dataLen);
+error_code LoggingI2CMaster::writeBlock(span<const uint_least8_t> data) {
+  messageBuilder.append(formatDataString(data, false));
+  return I2CMasterDecorator::writeBlock(data);
 }
 
 error_code LoggingI2CMaster::writePacketImpl(uint_least8_t address,
-                                             const uint_least8_t * data,
-                                             size_t dataLen, bool sendStop) {
+                                             span<const uint_least8_t> data,
+                                             bool sendStop) {
   messageBuilder.append(startString);
-  messageBuilder.append(formatDataString(&address, 1, false));
+  messageBuilder.append(formatDataString(make_span(&address, 1), false));
   error_code result =
-      I2CMasterDecorator::writePacketImpl(address, data, dataLen, sendStop);
+      I2CMasterDecorator::writePacketImpl(address, data, sendStop);
   if (!result) {
-    messageBuilder.append(formatDataString(data, dataLen, false));
+    messageBuilder.append(formatDataString(data, false));
   }
   if (sendStop || result) {
     messageBuilder.append(stopString);
@@ -107,29 +105,29 @@
 error_code LoggingI2CMaster::readByte(AckStatus status, uint_least8_t & data) {
   error_code result = I2CMasterDecorator::readByte(status, data);
   if (!result) {
-    messageBuilder.append(formatDataString(&data, 1, true));
+    messageBuilder.append(formatDataString(make_span(&data, 1), true));
   }
   return result;
 }
 
-error_code LoggingI2CMaster::readBlock(AckStatus status, uint_least8_t * data,
-                                       size_t dataLen) {
-  error_code result = I2CMasterDecorator::readBlock(status, data, dataLen);
+error_code LoggingI2CMaster::readBlock(AckStatus status,
+                                       span<uint_least8_t> data) {
+  error_code result = I2CMasterDecorator::readBlock(status, data);
   if (!result) {
-    messageBuilder.append(formatDataString(data, dataLen, true));
+    messageBuilder.append(formatDataString(data, true));
   }
   return result;
 }
 
 error_code LoggingI2CMaster::readPacketImpl(uint_least8_t address,
-                                            uint_least8_t * data,
-                                            size_t dataLen, bool sendStop) {
+                                            span<uint_least8_t> data,
+                                            bool sendStop) {
   messageBuilder.append(startString);
-  messageBuilder.append(formatDataString(&address, 1, false));
+  messageBuilder.append(formatDataString(make_span(&address, 1), false));
   error_code result =
-      I2CMasterDecorator::readPacketImpl(address, data, dataLen, sendStop);
+      I2CMasterDecorator::readPacketImpl(address, data, sendStop);
   if (!result) {
-    messageBuilder.append(formatDataString(data, dataLen, true));
+    messageBuilder.append(formatDataString(data, true));
   }
   if (sendStop || result) {
     messageBuilder.append(stopString);
@@ -138,4 +136,4 @@
   return result;
 }
 
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Links/LoggingI2CMaster.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/LoggingI2CMaster.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -51,23 +51,27 @@
   }
 
   MaximInterface_EXPORT virtual error_code start(uint_least8_t address);
+  
   MaximInterface_EXPORT virtual error_code stop();
+  
   MaximInterface_EXPORT virtual error_code writeByte(uint_least8_t data);
+  
   MaximInterface_EXPORT virtual error_code
-  writeBlock(const uint_least8_t * data, size_t dataLen);
+  writeBlock(span<const uint_least8_t> data);
+  
   MaximInterface_EXPORT virtual error_code readByte(AckStatus status,
                                                     uint_least8_t & data);
   MaximInterface_EXPORT virtual error_code
-  readBlock(AckStatus status, uint_least8_t * data, size_t dataLen);
+  readBlock(AckStatus status, span<uint_least8_t> data);
 
 protected:
   MaximInterface_EXPORT virtual error_code
-  writePacketImpl(uint_least8_t address, const uint_least8_t * data,
-                  size_t dataLen, bool sendStop);
-  MaximInterface_EXPORT virtual error_code readPacketImpl(uint_least8_t address,
-                                                          uint_least8_t * data,
-                                                          size_t dataLen,
-                                                          bool sendStop);
+  writePacketImpl(uint_least8_t address, span<const uint_least8_t> data,
+                  bool sendStop);
+                  
+  MaximInterface_EXPORT virtual error_code
+  readPacketImpl(uint_least8_t address, span<uint_least8_t> data,
+                 bool sendStop);
 
 private:
   void tryWriteMessage();
@@ -78,4 +82,4 @@
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Links/LoggingOneWireMaster.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/LoggingOneWireMaster.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -39,14 +39,13 @@
 
 static const char strongLevelString[] = "<SP_ON>";
 
-static string formatDataString(const uint_least8_t * data, size_t dataSize,
-                               bool read) {
+static string formatDataString(span<const uint_least8_t> data, bool read) {
   string dataBuilder;
-  for (size_t i = 0; i < dataSize; i++) {
+  for (span<const uint_least8_t>::index_type i = 0; i < data.size(); ++i) {
     if (read) {
       dataBuilder.append(1, '[');
     }
-    dataBuilder.append(byteArrayToHexString(data + i, 1));
+    dataBuilder.append(byteArrayToHexString(data.subspan(i, 1)));
     if (read) {
       dataBuilder.append(1, ']');
     }
@@ -69,7 +68,7 @@
 
 error_code LoggingOneWireMaster::writeByteSetLevel(uint_least8_t sendByte,
                                                    Level afterLevel) {
-  tryWriteMessage(formatDataString(&sendByte, 1, false));
+  tryWriteMessage(formatDataString(make_span(&sendByte, 1), false));
   if (afterLevel == StrongLevel) {
     tryWriteMessage(strongLevelString);
   }
@@ -81,7 +80,7 @@
   error_code result =
       OneWireMasterDecorator::readByteSetLevel(recvByte, afterLevel);
   if (!result) {
-    tryWriteMessage(formatDataString(&recvByte, 1, true));
+    tryWriteMessage(formatDataString(make_span(&recvByte, 1), true));
     if (afterLevel == StrongLevel) {
       tryWriteMessage(strongLevelString);
     }
@@ -89,17 +88,15 @@
   return result;
 }
 
-error_code LoggingOneWireMaster::writeBlock(const uint_least8_t * sendBuf,
-                                            size_t sendLen) {
-  tryWriteMessage(formatDataString(sendBuf, sendLen, false));
-  return OneWireMasterDecorator::writeBlock(sendBuf, sendLen);
+error_code LoggingOneWireMaster::writeBlock(span<const uint_least8_t> sendBuf) {
+  tryWriteMessage(formatDataString(sendBuf, false));
+  return OneWireMasterDecorator::writeBlock(sendBuf);
 }
 
-error_code LoggingOneWireMaster::readBlock(uint_least8_t * recvBuf,
-                                           size_t recvLen) {
-  error_code result = OneWireMasterDecorator::readBlock(recvBuf, recvLen);
+error_code LoggingOneWireMaster::readBlock(span<uint_least8_t> recvBuf) {
+  error_code result = OneWireMasterDecorator::readBlock(recvBuf);
   if (!result) {
-    tryWriteMessage(formatDataString(recvBuf, recvLen, true));
+    tryWriteMessage(formatDataString(recvBuf, true));
   }
   return result;
 }
@@ -144,4 +141,4 @@
   return result;
 }
 
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Links/LoggingOneWireMaster.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/LoggingOneWireMaster.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -52,15 +52,21 @@
   }
 
   MaximInterface_EXPORT virtual error_code reset();
+  
   MaximInterface_EXPORT virtual error_code
   writeByteSetLevel(uint_least8_t sendByte, Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
   readByteSetLevel(uint_least8_t & recvByte, Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
-  writeBlock(const uint_least8_t * sendBuf, size_t sendLen);
-  MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * recvBuf,
-                                                     size_t recvLen);
+  writeBlock(span<const uint_least8_t> sendBuf);
+  
+  MaximInterface_EXPORT virtual error_code
+  readBlock(span<uint_least8_t> recvBuf);
+  
   MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed);
+  
   MaximInterface_EXPORT virtual error_code setLevel(Level newLevel);
 
 private:
@@ -71,4 +77,4 @@
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Links/LoggingSleep.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/LoggingSleep.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,13 +35,13 @@
 
 namespace MaximInterface {
 
-void LoggingSleep::operator()(int ms) const {
+void LoggingSleep::invoke(int ms) const {
   if (writeMessage) {
     std::ostringstream message;
     message << "<DELAY" << ms << '>';
     writeMessage(message.str());
   }
-  SleepDecorator::operator()(ms);
+  SleepDecorator::invoke(ms);
 }
 
 } // namespace MaximInterface
--- a/Links/LoggingSleep.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/LoggingSleep.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -41,7 +41,7 @@
 
 class LoggingSleep : public SleepDecorator {
 public:
-  LoggingSleep(const Sleep & sleep,
+  LoggingSleep(Sleep & sleep,
                const WriteMessage & writeMessage = WriteMessage())
       : SleepDecorator(sleep), writeMessage(writeMessage) {}
 
@@ -49,7 +49,7 @@
     this->writeMessage = writeMessage;
   }
 
-  MaximInterface_EXPORT virtual void operator()(int ms) const;
+  MaximInterface_EXPORT virtual void invoke(int ms) const;
 
 private:
   WriteMessage writeMessage;
@@ -57,4 +57,4 @@
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Links/OneWireMaster.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/OneWireMaster.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,14 +35,14 @@
 
 namespace MaximInterface {
 
+static const int maxBitNum = 7;
+
 error_code OneWireMaster::writeByteSetLevel(uint_least8_t sendByte,
                                             Level afterLevel) {
   error_code result;
-  for (int idx = 0; (idx < 8) && !result; idx++) {
-    result = writeBit(((sendByte >> idx) & 1) == 1);
-  }
-  if (!result) {
-    result = setLevel(afterLevel);
+  for (int bitNum = 0; (bitNum <= maxBitNum) && !result; ++bitNum) {
+    result = writeBitSetLevel(((sendByte >> bitNum) & 1) == 1,
+                              (bitNum == maxBitNum) ? afterLevel : NormalLevel);
   }
   return result;
 }
@@ -51,35 +51,34 @@
                                            Level afterLevel) {
   recvByte = 0;
   error_code result;
-  for (int idx = 0; idx < 8; idx++) {
+  for (int bitNum = 0; bitNum <= maxBitNum; ++bitNum) {
     bool recvBit;
-    result = readBit(recvBit);
+    result = readBitSetLevel(recvBit,
+                             (bitNum == maxBitNum) ? afterLevel : NormalLevel);
     if (result) {
       break;
     }
     if (recvBit) {
-      recvByte |= (1 << idx);
+      recvByte |= (1 << bitNum);
     }
   }
-  if (!result) {
-    result = setLevel(afterLevel);
-  }
   return result;
 }
 
-error_code OneWireMaster::writeBlock(const uint_least8_t * sendBuf,
-                                     size_t sendLen) {
+error_code OneWireMaster::writeBlock(span<const uint_least8_t> sendBuf) {
   error_code result;
-  for (size_t idx = 0; (idx < sendLen) && !result; idx++) {
-    result = writeByte(sendBuf[idx]);
+  for (span<const uint_least8_t>::index_type i = 0;
+       i < sendBuf.size() && !result; ++i) {
+    result = writeByte(sendBuf[i]);
   }
   return result;
 }
 
-error_code OneWireMaster::readBlock(uint_least8_t * recvBuf, size_t recvLen) {
+error_code OneWireMaster::readBlock(span<uint_least8_t> recvBuf) {
   error_code result;
-  for (size_t idx = 0; (idx < recvLen) && !result; idx++) {
-    result = readByte(recvBuf[idx]);
+  for (span<uint_least8_t>::index_type i = 0; i < recvBuf.size() && !result;
+       ++i) {
+    result = readByte(recvBuf[i]);
   }
   return result;
 }
--- a/Links/OneWireMaster.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/OneWireMaster.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -33,9 +33,9 @@
 #ifndef MaximInterface_OneWireMaster
 #define MaximInterface_OneWireMaster
 
-#include <stddef.h>
 #include <stdint.h>
 #include <MaximInterface/Utilities/Export.h>
+#include <MaximInterface/Utilities/span.hpp>
 #include <MaximInterface/Utilities/system_error.hpp>
 
 namespace MaximInterface {
@@ -65,10 +65,13 @@
 
   virtual ~OneWireMaster() {}
 
+  /// @brief
   /// Reset all of the devices on the 1-Wire bus and check for a presence pulse.
-  /// @returns NoSlaveError if reset was performed but no presence pulse was detected.
+  /// @returns
+  /// NoSlaveError if reset was performed but no presence pulse was detected.
   virtual error_code reset() = 0;
 
+  /// @brief
   /// Send and receive one bit of communication and set a new level on the
   /// 1-Wire bus.
   /// @param[in,out] sendRecvBit
@@ -76,29 +79,29 @@
   /// @param afterLevel Level to set the 1-Wire bus to after communication.
   virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel) = 0;
 
+  /// @brief
   /// Send one byte of communication and set a new level on the 1-Wire bus.
   /// @param sendByte Byte to send on the 1-Wire bus.
   /// @param afterLevel Level to set the 1-Wire bus to after communication.
   MaximInterface_EXPORT virtual error_code
   writeByteSetLevel(uint_least8_t sendByte, Level afterLevel);
 
+  /// @brief
   /// Receive one byte of communication and set a new level on the 1-Wire bus.
   /// @param recvByte Buffer to receive the data from the 1-Wire bus.
   /// @param afterLevel Level to set the 1-Wire bus to after communication.
   MaximInterface_EXPORT virtual error_code
   readByteSetLevel(uint_least8_t & recvByte, Level afterLevel);
 
-  /// Send a block of communication on the 1-Wire bus.
+  /// @brief Send a block of communication on the 1-Wire bus.
   /// @param[in] sendBuf Buffer to send on the 1-Wire bus.
-  /// @param sendLen Length of the buffer to send.
   MaximInterface_EXPORT virtual error_code
-  writeBlock(const uint_least8_t * sendBuf, size_t sendLen);
+  writeBlock(span<const uint_least8_t> sendBuf);
 
-  /// Receive a block of communication on the 1-Wire bus.
+  /// @brief Receive a block of communication on the 1-Wire bus.
   /// @param[out] recvBuf Buffer to receive the data from the 1-Wire bus.
-  /// @param recvLen Length of the buffer to receive.
-  MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * recvBuf,
-                                                     size_t recvLen);
+  MaximInterface_EXPORT virtual error_code
+  readBlock(span<uint_least8_t> recvBuf);
 
   /// Set the 1-Wire bus communication speed.
   virtual error_code setSpeed(Speed newSpeed) = 0;
@@ -106,16 +109,17 @@
   /// Set the 1-Wire bus level.
   virtual error_code setLevel(Level newLevel) = 0;
 
-  /// 1-Wire Triplet operation.
+  /// @brief 1-Wire Triplet operation.
   /// @details Perform one bit of a 1-Wire search. This command
   /// does two read bits and one write bit. The write bit is either
   /// the default direction (all devices have same bit) or in case
   /// of a discrepancy, the data.writeBit parameter is used.
-  ///@param[in,out] data
+  /// @param[in,out] data
   /// Input with desired writeBit in case both read bits are zero.
   /// Output with all data fields set.
   MaximInterface_EXPORT virtual error_code triplet(TripletData & data);
 
+  /// @brief
   /// Send one bit of communication and set a new level on the 1-Wire bus.
   /// @param sendBit Bit to send on the 1-Wire bus.
   /// @param afterLevel Level to set the 1-Wire bus to after communication.
@@ -123,6 +127,7 @@
     return touchBitSetLevel(sendBit, afterLevel);
   }
 
+  /// @brief
   /// Receive one bit of communication and set a new level on the 1-Wire bus.
   /// @param[out] recvBit Received data from the 1-Wire bus.
   /// @param afterLevel Level to set the 1-Wire bus to after communication.
@@ -132,27 +137,39 @@
   }
 
   // Alternate forms of the read and write functions.
+  
+  error_code touchBit(bool & sendRecvBit) {
+    return touchBitSetLevel(sendRecvBit, NormalLevel);
+  }
+  
   error_code writeBit(bool sendBit) {
     return writeBitSetLevel(sendBit, NormalLevel);
   }
+  
   error_code readBit(bool & recvBit) {
     return readBitSetLevel(recvBit, NormalLevel);
   }
+  
   error_code writeBitPower(bool sendBit) {
     return writeBitSetLevel(sendBit, StrongLevel);
   }
+  
   error_code readBitPower(bool & recvBit) {
     return readBitSetLevel(recvBit, StrongLevel);
   }
+  
   error_code writeByte(uint_least8_t sendByte) {
     return writeByteSetLevel(sendByte, NormalLevel);
   }
+  
   error_code readByte(uint_least8_t & recvByte) {
     return readByteSetLevel(recvByte, NormalLevel);
   }
+  
   error_code writeBytePower(uint_least8_t sendByte) {
     return writeByteSetLevel(sendByte, StrongLevel);
   }
+  
   error_code readBytePower(uint_least8_t & recvByte) {
     return readByteSetLevel(recvByte, StrongLevel);
   }
@@ -163,6 +180,7 @@
 inline error_code make_error_code(OneWireMaster::ErrorValue e) {
   return error_code(e, OneWireMaster::errorCategory());
 }
+
 inline error_condition make_error_condition(OneWireMaster::ErrorValue e) {
   return error_condition(e, OneWireMaster::errorCategory());
 }
--- a/Links/OneWireMasterDecorator.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/OneWireMasterDecorator.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -51,14 +51,13 @@
   return master->readByteSetLevel(recvByte, afterLevel);
 }
 
-error_code OneWireMasterDecorator::writeBlock(const uint_least8_t * sendBuf,
-                                              size_t sendLen) {
-  return master->writeBlock(sendBuf, sendLen);
+error_code
+OneWireMasterDecorator::writeBlock(span<const uint_least8_t> sendBuf) {
+  return master->writeBlock(sendBuf);
 }
 
-error_code OneWireMasterDecorator::readBlock(uint_least8_t * recvBuf,
-                                             size_t recvLen) {
-  return master->readBlock(recvBuf, recvLen);
+error_code OneWireMasterDecorator::readBlock(span<uint_least8_t> recvBuf) {
+  return master->readBlock(recvBuf);
 }
 
 error_code OneWireMasterDecorator::setSpeed(Speed newSpeed) {
@@ -73,4 +72,4 @@
   return master->triplet(data);
 }
 
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Links/OneWireMasterDecorator.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/OneWireMasterDecorator.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -43,21 +43,29 @@
   explicit OneWireMasterDecorator(OneWireMaster & master) : master(&master) {}
 
 public:
-  void setOneWireMaster(OneWireMaster & master) { this->master = &master; }
+  void setMaster(OneWireMaster & master) { this->master = &master; }
 
   MaximInterface_EXPORT virtual error_code reset();
+  
   MaximInterface_EXPORT virtual error_code touchBitSetLevel(bool & sendRecvBit,
                                                             Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
   writeByteSetLevel(uint_least8_t sendByte, Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
   readByteSetLevel(uint_least8_t & recvByte, Level afterLevel);
+  
   MaximInterface_EXPORT virtual error_code
-  writeBlock(const uint_least8_t * sendBuf, size_t sendLen);
-  MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * recvBuf,
-                                                     size_t recvLen);
+  writeBlock(span<const uint_least8_t> sendBuf);
+  
+  MaximInterface_EXPORT virtual error_code
+  readBlock(span<uint_least8_t> recvBuf);
+  
   MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed);
+  
   MaximInterface_EXPORT virtual error_code setLevel(Level newLevel);
+  
   MaximInterface_EXPORT virtual error_code triplet(TripletData & data);
 
 private:
@@ -66,4 +74,4 @@
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Links/RomCommands.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/RomCommands.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -30,7 +30,6 @@
 * ownership rights.
 *******************************************************************************/
 
-#include <algorithm>
 #include "RomCommands.hpp"
 
 namespace MaximInterface {
@@ -46,114 +45,106 @@
 };
 
 void skipCurrentFamily(SearchRomState & searchState) {
-  // set the Last discrepancy to last family discrepancy
+  // Set the last discrepancy to last family discrepancy.
   searchState.lastDiscrepancy = searchState.lastFamilyDiscrepancy;
-
-  // clear the last family discrepancy
+  // Clear the last family discrepancy.
   searchState.lastFamilyDiscrepancy = 0;
-
-  // check for end of list
+  // Check for end of list.
   if (searchState.lastDiscrepancy == 0) {
     searchState.lastDevice = true;
   }
 }
 
-error_code verifyRom(OneWireMaster & master, const RomId & romId) {
+error_code verifyRom(OneWireMaster & master, RomId::const_span romId) {
   SearchRomState searchState(romId);
   error_code result = searchRom(master, searchState);
-  if (!result) {
-    // check if same device found
-    if (romId != searchState.romId) {
-      result = make_error_code(OneWireMaster::NoSlaveError);
-    }
+  if (result) {
+    return result;
+  }
+  // Check if same device found.
+  if (romId != make_span(searchState.romId)) {
+    result = make_error_code(OneWireMaster::NoSlaveError);
   }
   return result;
 }
 
-error_code readRom(OneWireMaster & master, RomId & romId) {
+error_code readRom(OneWireMaster & master, RomId::span romId) {
   error_code result = master.reset();
-  if (!result) {
-    result = master.writeByte(ReadRomCmd);
-  }
-
-  // read the ROM
-  RomId readId;
-  if (!result) {
-    result = master.readBlock(readId.data(), readId.size());
+  if (result) {
+    return result;
   }
-
-  // verify CRC8
-  if (!result) {
-    if (valid(readId)) {
-      romId = readId;
-    } else {
-      result = make_error_code(OneWireMaster::NoSlaveError);
-    }
+  result = master.writeByte(ReadRomCmd);
+  if (result) {
+    return result;
   }
-
+  result = master.readBlock(romId);
+  if (result) {
+    return result;
+  }
+  if (!valid(romId)) {
+    result = make_error_code(OneWireMaster::NoSlaveError);
+  }
   return result;
 }
 
 error_code skipRom(OneWireMaster & master) {
   error_code result = master.reset();
-  if (!result) {
-    result = master.writeByte(SkipRomCmd);
+  if (result) {
+    return result;
   }
+  result = master.writeByte(SkipRomCmd);
   return result;
 }
 
-error_code matchRom(OneWireMaster & master, const RomId & romId) {
-  // use MatchROM
+error_code matchRom(OneWireMaster & master, RomId::const_span romId) {
   error_code result = master.reset();
-  if (!result) {
-    uint_least8_t buf[1 + RomId::csize];
-    buf[0] = MatchRomCmd;
-    std::copy(romId.begin(), romId.end(), buf + 1);
-    // send command and rom
-    result = master.writeBlock(buf, sizeof(buf) / sizeof(buf[0]));
+  if (result) {
+    return result;
   }
+  result = master.writeByte(MatchRomCmd);
+  if (result) {
+    return result;
+  }
+  result = master.writeBlock(romId);
   return result;
 }
 
 error_code overdriveSkipRom(OneWireMaster & master) {
-  error_code result = master.setSpeed(OneWireMaster::StandardSpeed);
-
-  if (!result) {
-    result = master.reset();
+  error_code result = master.reset();
+  if (result) {
+    return result;
   }
-
-  if (!result) {
-    result = master.writeByte(OverdriveSkipRomCmd);
+  result = master.writeByte(OverdriveSkipRomCmd);
+  if (result) {
+    return result;
   }
-
-  if (!result) {
-    result = master.setSpeed(OneWireMaster::OverdriveSpeed);
-  }
-
+  result = master.setSpeed(OneWireMaster::OverdriveSpeed);
   return result;
 }
 
-error_code overdriveMatchRom(OneWireMaster & master, const RomId & romId) {
-  // use overdrive MatchROM
-  master.setSpeed(OneWireMaster::StandardSpeed);
-
+error_code overdriveMatchRom(OneWireMaster & master, RomId::const_span romId) {
   error_code result = master.reset();
-  if (!result) {
-    result = master.writeByte(OverdriveMatchRomCmd);
-    if (!result) {
-      master.setSpeed(OneWireMaster::OverdriveSpeed);
-      // send ROM
-      result = master.writeBlock(romId.data(), romId.size());
-    }
+  if (result) {
+    return result;
   }
+  result = master.writeByte(OverdriveMatchRomCmd);
+  if (result) {
+    return result;
+  }
+  result = master.setSpeed(OneWireMaster::OverdriveSpeed);
+  if (result) {
+    return result;
+  }
+  result = master.writeBlock(romId);
   return result;
 }
 
 error_code resumeRom(OneWireMaster & master) {
   error_code result = master.reset();
-  if (!result) {
-    result = master.writeByte(ResumeRomCmd);
+  if (result) {
+    return result;
   }
+  result = master.writeByte(ResumeRomCmd);
   return result;
 }
 
@@ -171,20 +162,20 @@
     return result;
   }
 
-  SearchRomState newSearchState = searchState;
-  for (int idBitNumber = 1; idBitNumber <= 64; idBitNumber++) {
+  SearchRomState newSearchState;
+  newSearchState.lastFamilyDiscrepancy = searchState.lastFamilyDiscrepancy;
+  for (int idBitNumber = 1; idBitNumber <= 64; ++idBitNumber) {
     const int idByteNumber = (idBitNumber - 1) / 8;
     const unsigned int idBitMask = 1 << ((idBitNumber - 1) % 8);
 
     OneWireMaster::TripletData tripletData;
-    if (idBitNumber == newSearchState.lastDiscrepancy) {
+    if (idBitNumber == searchState.lastDiscrepancy) {
       tripletData.writeBit = 1;
-    } else if (idBitNumber > newSearchState.lastDiscrepancy) {
+    } else if (idBitNumber > searchState.lastDiscrepancy) {
       tripletData.writeBit = 0;
-    } else // idBitNumber < searchState.lastDiscrepancy
-    {
+    } else { // idBitNumber < searchState.lastDiscrepancy
       tripletData.writeBit =
-          (newSearchState.romId[idByteNumber] & idBitMask) == idBitMask;
+          (searchState.romId[idByteNumber] & idBitMask) == idBitMask;
     }
 
     result = master.triplet(tripletData);
@@ -197,19 +188,16 @@
 
     if (tripletData.writeBit) {
       newSearchState.romId[idByteNumber] |= idBitMask;
-    } else {
-      newSearchState.romId[idByteNumber] &= ~idBitMask;
-      if (!tripletData.readBit && !tripletData.readBitComplement) {
-        newSearchState.lastDiscrepancy = idBitNumber;
-        if (idBitNumber <= 8) {
-          newSearchState.lastFamilyDiscrepancy = idBitNumber;
-        }
+    } else if (!tripletData.readBit && !tripletData.readBitComplement) {
+      newSearchState.lastDiscrepancy = idBitNumber;
+      if (idBitNumber <= 8) {
+        newSearchState.lastFamilyDiscrepancy = idBitNumber;
       }
     }
   }
 
   if (valid(newSearchState.romId)) {
-    if (newSearchState.lastDiscrepancy == searchState.lastDiscrepancy) {
+    if (newSearchState.lastDiscrepancy == 0) {
       newSearchState.lastDevice = true;
     }
     searchState = newSearchState;
--- a/Links/RomCommands.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/RomCommands.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -30,7 +30,8 @@
 * ownership rights.
 *******************************************************************************/
 
-/// @file ROM Commands for enumerating and selecting 1-Wire devices.
+/// @file
+/// @brief ROM Commands for enumerating and selecting 1-Wire devices.
 
 #ifndef MaximInterface_RomCommands
 #define MaximInterface_RomCommands
@@ -44,7 +45,7 @@
 
 /// State used by Search ROM command.
 struct SearchRomState {
-  RomId romId;
+  RomId::array romId;
   int_least8_t lastDiscrepancy;
   int_least8_t lastFamilyDiscrepancy;
   bool lastDevice;
@@ -53,61 +54,74 @@
       : romId(), lastDiscrepancy(0), lastFamilyDiscrepancy(0),
         lastDevice(false) {}
     
-  explicit SearchRomState(const RomId & romId)
-      : romId(romId), lastDiscrepancy(64), lastFamilyDiscrepancy(0),
-        lastDevice(false) {}
+  explicit SearchRomState(RomId::const_span romId)
+      : lastDiscrepancy(64), lastFamilyDiscrepancy(0), lastDevice(false) {
+    copy(romId, make_span(this->romId));
+  }
       
-  explicit SearchRomState(RomId::value_type familyCode)
+  explicit SearchRomState(RomId::element familyCode)
       : romId(), lastDiscrepancy(64), lastFamilyDiscrepancy(0),
         lastDevice(false) {
     setFamilyCode(romId, familyCode);
   }
 };
 
+/// @brief
 /// Set the search state to skip the current device family on the next
 /// Search ROM command.
 MaximInterface_EXPORT void skipCurrentFamily(SearchRomState & searchState);
 
 /// Verify that the device with the specified ROM ID is present.
 MaximInterface_EXPORT error_code verifyRom(OneWireMaster & master,
-                                           const RomId & romId);
+                                           RomId::const_span romId);
 
-/// Use Read ROM command to read ROM ID from device on bus.
-/// @note Only use this command with a single drop bus, data
-///       collisions will occur if more than 1 device on bus.
+/// @brief Use Read ROM command to read ROM ID from device on bus.
+/// @note
+/// Only use this command with a single-drop bus.
+/// Data collisions will occur if there is more than one device on the bus.
+/// @param master 1-Wire master for operation.
 /// @param[out] romId ROM ID read from device.
-MaximInterface_EXPORT error_code readRom(OneWireMaster & master, RomId & romId);
+MaximInterface_EXPORT error_code readRom(OneWireMaster & master,
+                                         RomId::span romId);
 
-/// Issue Skip ROM command on bus.
-/// @note Only use this command with a single drop bus, data
-///       collisions will occur if more than 1 device on bus.
+/// @brief Issue Skip ROM command on bus.
+/// @note
+/// Only use this command with a single-drop bus.
+/// Data collisions will occur if there is more than one device on the bus.
 MaximInterface_EXPORT error_code skipRom(OneWireMaster & master);
 
-/// Use the Match ROM command to select the device by its known ID.
-/// @note This command causes all devices supporting Overdrive
-///       mode to switch to Overdrive timing.
+/// @brief Use the Match ROM command to select the device by its known ID.
+/// @note
+/// This command causes all devices supporting Overdrive mode to switch to
+/// Overdrive timing.
+/// @param master 1-Wire master for operation.
 /// @param[in] romId ROM ID of device to select.
 MaximInterface_EXPORT error_code matchRom(OneWireMaster & master,
-                                          const RomId & romId);
+                                          RomId::const_span romId);
 
-/// Issue Overdrive Skip ROM command on bus.
-/// @note This command causes all devices supporting Overdrive
-///       mode to switch to Overdrive timing.
-/// @note Only use this command with a single drop bus, data
-///       collisions will occur if more than 1 device on bus.
+/// @brief Issue Overdrive Skip ROM command on bus.
+/// @note
+/// This command causes all devices supporting Overdrive mode to switch to
+/// Overdrive timing.
+/// @note
+/// Only use this command with a single-drop bus.
+/// Data collisions will occur if there is more than one device on the bus.
 MaximInterface_EXPORT error_code overdriveSkipRom(OneWireMaster & master);
 
+/// @brief
 /// Use the Overdrive Match ROM command to select the device by its known ID.
+/// @param master 1-Wire master for operation.
 /// @param[in] romId ROM ID of device to select.
 MaximInterface_EXPORT error_code overdriveMatchRom(OneWireMaster & master,
-                                                   const RomId & romId);
+                                                   RomId::const_span romId);
 
-/// Perform a Resume ROM command on bus.
-/// @details Resumes communication with the last device selected
-///          though a Match ROM or Search ROM operation.
+/// @brief Perform a Resume ROM command on bus.
+/// @details
+/// Resumes communication with the last device selected through a Match ROM or
+/// Search ROM operation.
 MaximInterface_EXPORT error_code resumeRom(OneWireMaster & master);
 
-/// Find device on the 1-Wire bus.
+/// @brief Find device on the 1-Wire bus.
 /// @details
 /// This command uses the Search ROM command to enumerate all 1-Wire devices in
 /// sequence. Begin with a new search state and continue using the same search
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Links/RunCommand.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -0,0 +1,210 @@
+/*******************************************************************************
+* Copyright (C) 2018 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/Utilities/crc.hpp>
+#include <MaximInterface/Utilities/Error.hpp>
+#include "I2CMaster.hpp"
+#include "OneWireMaster.hpp"
+#include "Sleep.hpp"
+#include "RunCommand.hpp"
+
+namespace MaximInterface {
+
+const error_category & RunCommandWithOneWireMaster::errorCategory() {
+  static class : public error_category {
+  public:
+    virtual const char * name() const { return "RunCommandWithOneWireMaster"; }
+
+    virtual std::string message(int condition) const {
+      switch (condition) {
+      case CrcError:
+        return "CRC Error";
+
+      case InvalidResponseError:
+        return "Invalid Response Error";
+      }
+      return defaultErrorMessage(condition);
+    }
+  } instance;
+  return instance;
+}
+
+error_code RunCommandWithOneWireMaster::
+operator()(span<const uint_least8_t> command, int delayTime,
+           span<uint_least8_t> & response) const {
+  // Write command.
+  error_code result = selectRom(*master);
+  if (result) {
+    return result;
+  }
+  uint_least8_t xpcBuffer[2] = {0x66,
+                                static_cast<uint_least8_t>(command.size())};
+  result = master->writeBlock(xpcBuffer);
+  if (result) {
+    return result;
+  }
+  result = master->writeBlock(command);
+  if (result) {
+    return result;
+  }
+  uint_fast16_t expectedCrc =
+      calculateCrc16(command, calculateCrc16(xpcBuffer)) ^ 0xFFFFU;
+  result = master->readBlock(xpcBuffer);
+  if (result) {
+    return result;
+  }
+  if (expectedCrc !=
+      ((static_cast<uint_fast16_t>(xpcBuffer[1]) << 8) | xpcBuffer[0])) {
+    return make_error_code(CrcError);
+  }
+  result = master->writeBytePower(0xAA);
+  if (result) {
+    return result;
+  }
+
+  // Wait for device to process.
+  sleep->invoke(delayTime);
+
+  // Read response.
+  result = master->setLevel(OneWireMaster::NormalLevel);
+  if (result) {
+    return result;
+  }
+  result = master->readBlock(xpcBuffer);
+  if (result) {
+    return result;
+  }
+  if (xpcBuffer[1] > response.size()) {
+    return make_error_code(InvalidResponseError);
+  }
+  response = response.first(xpcBuffer[1]);
+  result = master->readBlock(response);
+  if (result) {
+    return result;
+  }
+  expectedCrc =
+      calculateCrc16(response, calculateCrc16(make_span(xpcBuffer + 1, 1))) ^
+      0xFFFFU;
+  result = master->readBlock(xpcBuffer);
+  if (result) {
+    return result;
+  }
+  if (expectedCrc !=
+      ((static_cast<uint_fast16_t>(xpcBuffer[1]) << 8) | xpcBuffer[0])) {
+    return make_error_code(CrcError);
+  }
+  return result;
+}
+
+const error_category & RunCommandWithI2CMaster::errorCategory() {
+  static class : public error_category {
+  public:
+    virtual const char * name() const { return "RunCommandWithI2CMaster"; }
+
+    virtual std::string message(int condition) const {
+      switch (condition) {
+      case InvalidResponseError:
+        return "Invalid Response Error";
+      }
+      return defaultErrorMessage(condition);
+    }
+  } instance;
+  return instance;
+}
+
+error_code RunCommandWithI2CMaster::
+operator()(span<const uint_least8_t> command, int delayTime,
+           span<uint_least8_t> & response) const {
+  // Write command.
+  error_code result = master->start(address_);
+  if (result == make_error_condition(I2CMaster::NackError) && address_ != 0) {
+    result = master->start(0);
+  }
+  if (result) {
+    master->stop();
+    return result;
+  }
+  if (!command.empty()) {
+    result = master->writeByte(command[0]);
+    if (result) {
+      master->stop();
+      return result;
+    }
+    command = command.subspan(1);
+    if (!command.empty()) {
+      result = master->writeByte(command.size());
+      if (result) {
+        master->stop();
+        return result;
+      }
+      result = master->writeBlock(command);
+      if (result) {
+        master->stop();
+        return result;
+      }
+    }
+  }
+  result = master->stop();
+  if (result) {
+    return result;
+  }
+
+  // Wait for device to process.
+  sleep->invoke(delayTime);
+
+  // Read response.
+  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);
+  result = master->readBlock(I2CMaster::Nack, response);
+  if (result) {
+    master->stop();
+    return result;
+  }
+  result = master->stop();
+  return result;
+}
+
+} // namespace MaximInterface
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Links/RunCommand.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -0,0 +1,120 @@
+/*******************************************************************************
+* Copyright (C) 2018 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.
+*******************************************************************************/
+
+#ifndef MaximInterface_RunCommand
+#define MaximInterface_RunCommand
+
+#include <MaximInterface/Utilities/Export.h>
+#include <MaximInterface/Utilities/Function.hpp>
+#include <MaximInterface/Utilities/span.hpp>
+#include <MaximInterface/Utilities/system_error.hpp>
+#include "SelectRom.hpp"
+
+namespace MaximInterface {
+
+class I2CMaster;
+class OneWireMaster;
+class Sleep;
+
+typedef Function<error_code(span<const uint_least8_t>, int,
+                            span<uint_least8_t> &)>
+    RunCommand;
+
+class RunCommandWithOneWireMaster {
+public:
+  typedef RunCommand::result_type result_type;
+
+  enum ErrorValue { CrcError = 1, InvalidResponseError };
+  MaximInterface_EXPORT static const error_category & errorCategory();
+
+  RunCommandWithOneWireMaster(Sleep & sleep, OneWireMaster & master,
+                              const SelectRom & selectRom)
+      : selectRom(selectRom), master(&master), sleep(&sleep) {}
+
+  void setSleep(Sleep & sleep) { this->sleep = &sleep; }
+  
+  void setMaster(OneWireMaster & master) { this->master = &master; }
+  
+  void setSelectRom(const SelectRom & selectRom) {
+    this->selectRom = selectRom;
+  }
+
+  MaximInterface_EXPORT error_code
+  operator()(span<const uint_least8_t> command, int delayTime,
+             span<uint_least8_t> & response) const;
+
+private:
+  SelectRom selectRom;
+  OneWireMaster * master;
+  const Sleep * sleep;
+};
+
+inline error_code make_error_code(RunCommandWithOneWireMaster::ErrorValue e) {
+  return error_code(e, RunCommandWithOneWireMaster::errorCategory());
+}
+
+class RunCommandWithI2CMaster {
+public:
+  typedef RunCommand::result_type result_type;
+
+  enum ErrorValue { InvalidResponseError = 1 };
+  MaximInterface_EXPORT static const error_category & errorCategory();
+
+  RunCommandWithI2CMaster(Sleep & sleep, I2CMaster & master,
+                          uint_least8_t address)
+      : sleep(&sleep), master(&master), address_(address & 0xFE) {}
+
+  void setSleep(Sleep & sleep) { this->sleep = &sleep; }
+  
+  void setMaster(I2CMaster & master) { this->master = &master; }
+  
+  uint_least8_t address() const { return address_; }
+  
+  void setAddress(uint_least8_t address) { address_ = address & 0xFE; }
+
+  MaximInterface_EXPORT error_code
+  operator()(span<const uint_least8_t> command, int delayTime,
+             span<uint_least8_t> & response) const;
+
+private:
+  const Sleep * sleep;
+  I2CMaster * master;
+  uint_least8_t address_;
+};
+
+inline error_code make_error_code(RunCommandWithI2CMaster::ErrorValue e) {
+  return error_code(e, RunCommandWithI2CMaster::errorCategory());
+}
+
+} // namespace MaximInterface
+
+#endif
--- a/Links/SelectRom.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/SelectRom.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -40,11 +40,11 @@
 
 error_code SelectMatchRomWithResume::operator()(OneWireMaster & master) const {
   error_code result;
-  if (romId_ == data->lastRom) {
+  if (romId_ == data->lastRomId) {
     result = resumeRom(master);
   } else {
     result = matchRom(master, romId_);
-    data->lastRom = romId_;
+    data->lastRomId = romId_;
   }
   return result;
 }
--- a/Links/SelectRom.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/SelectRom.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -43,6 +43,7 @@
 
 class OneWireMaster;
 
+/// Selects a 1-Wire device on the bus for communication.
 typedef Function<error_code(OneWireMaster &)> SelectRom;
 typedef Function<error_code(OneWireMaster &, const RomId & romId)> SelectRomExt;
 
@@ -52,41 +53,47 @@
   typedef SelectRom::argument_type argument_type;
   typedef SelectRom::result_type result_type;
 
-  explicit SelectMatchRom(const RomId & romId = RomId()) : romId_(romId) {}
+  explicit SelectMatchRom(RomId::const_span romId) { setRomId(romId); }
 
-  const RomId & romId() const { return romId_; }
-  void setRomId(const RomId & romId) { romId_ = romId; }
+  RomId::const_span romId() const { return romId_; }
+  
+  void setRomId(RomId::const_span romId) { copy(romId, make_span(romId_)); }
 
   MaximInterface_EXPORT error_code operator()(OneWireMaster & master) const;
 
 private:
-  RomId romId_;
+  RomId::array romId_;
 };
 
-/// Selector for a multidrop 1-Wire bus where slaves support the Resume ROM command.
+/// @brief
+/// Selector for a multidrop 1-Wire bus where slaves support the Resume ROM
+/// command.
 class SelectMatchRomWithResume {
 public:
   typedef SelectRom::argument_type argument_type;
   typedef SelectRom::result_type result_type;
 
   struct SharedData {
-    RomId lastRom;
-
-    SharedData() : lastRom() {}
+    SharedData() : lastRomId() {}
+    RomId::array lastRomId;
   };
 
-  explicit SelectMatchRomWithResume(SharedData & data,
-                                    const RomId & romId = RomId())
-      : romId_(romId), data(&data) {}
+  SelectMatchRomWithResume(SharedData & data, RomId::const_span romId)
+      : data(&data) {
+    setRomId(romId);
+  }
 
-  const RomId & romId() const { return romId_; }
-  void setRomId(const RomId & romId) { romId_ = romId; }
+  void setSharedData(SharedData & data) { this->data = &data; }
+  
+  RomId::const_span romId() const { return romId_; }
+  
+  void setRomId(RomId::const_span romId) { copy(romId, make_span(romId_)); }
 
   MaximInterface_EXPORT error_code operator()(OneWireMaster & master) const;
 
 private:
-  RomId romId_;
   SharedData * data;
+  RomId::array romId_;
 };
 
 } // namespace MaximInterface
--- a/Links/SerialPort.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/SerialPort.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -46,7 +46,7 @@
   /// Disconnect from the current port.
   virtual error_code disconnect() = 0;
   
-  /// Check if currently connected to a port.
+  /// @brief Check if currently connected to a port.
   /// @returns True if connected.
   virtual bool connected() const = 0;
 
@@ -56,4 +56,4 @@
 
 }
 
-#endif
\ No newline at end of file
+#endif
--- a/Links/Sleep.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/Sleep.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -38,10 +38,10 @@
 class Sleep {
 public:
   virtual ~Sleep() {}
-
-  virtual void operator()(int ms) const = 0;
+  virtual void invoke(int ms) const = 0;
+  void operator()(int ms) const { invoke(ms); }
 };
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Links/SleepDecorator.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/SleepDecorator.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -34,6 +34,6 @@
 
 namespace MaximInterface {
 
-void SleepDecorator::operator()(int ms) const { (*sleep)(ms); }
+void SleepDecorator::invoke(int ms) const { sleep->invoke(ms); }
 
-}
\ No newline at end of file
+}
--- a/Links/SleepDecorator.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/SleepDecorator.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -40,11 +40,11 @@
 
 class SleepDecorator : public Sleep {
 protected:
-  explicit SleepDecorator(const Sleep & sleep) : sleep(&sleep) {}
+  explicit SleepDecorator(Sleep & sleep) : sleep(&sleep) {}
 
 public:
-  void setSleep(const Sleep & sleep) { this->sleep = &sleep; }
-  MaximInterface_EXPORT virtual void operator()(int ms) const;
+  void setSleep(Sleep & sleep) { this->sleep = &sleep; }
+  MaximInterface_EXPORT virtual void invoke(int ms) const;
 
 private:
   const Sleep * sleep;
@@ -52,4 +52,4 @@
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Links/Uart.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/Uart.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,17 +35,18 @@
 
 namespace MaximInterface {
 
-error_code Uart::writeBlock(const uint_least8_t * data, size_t dataLen) {
+error_code Uart::writeBlock(span<const uint_least8_t> data) {
   error_code result;
-  for (size_t i = 0; i < dataLen && !result; i++) {
+  for (span<const uint_least8_t>::index_type i = 0;
+       i < data.size() && !result; ++i) {
     result = writeByte(data[i]);
   }
   return result;
 }
 
-error_code Uart::readBlock(uint_least8_t * data, size_t dataLen) {
+error_code Uart::readBlock(span<uint_least8_t> data) {
   error_code result;
-  for (size_t i = 0; i < dataLen && !result; i++) {
+  for (span<uint_least8_t>::index_type i = 0; i < data.size() && !result; ++i) {
     result = readByte(data[i]);
   }
   return result;
@@ -72,4 +73,4 @@
   return instance;
 }
 
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Links/Uart.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Links/Uart.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -34,9 +34,8 @@
 #define MaximInterface_Uart
 
 #include <stdint.h>
-#include <stddef.h>
-
 #include <MaximInterface/Utilities/Export.h>
+#include <MaximInterface/Utilities/span.hpp>
 #include <MaximInterface/Utilities/system_error.hpp>
 
 namespace MaximInterface {
@@ -65,19 +64,19 @@
   
   /// Writes a block of data to the port.
   MaximInterface_EXPORT virtual error_code
-  writeBlock(const uint_least8_t * data, size_t dataLen);
+  writeBlock(span<const uint_least8_t> data);
   
+  /// @brief
   /// Reads a byte of data from the port. Block until data is received or a
   /// timeout is reached.
   /// @param[out] data Data read from the port if successful.
   virtual error_code readByte(uint_least8_t & data) = 0;
   
+  /// @brief
   /// Read a block of data from the port. Block until data is received or a
   /// timeout is reached.
   /// @param[out] data Data read from the port if successful.
-  /// @para dataLen Number of bytes to read and length of data.
-  MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * data,
-                                                     size_t dataLen);
+  MaximInterface_EXPORT virtual error_code readBlock(span<uint_least8_t> data);
 
   MaximInterface_EXPORT static const error_category & errorCategory();
 };
@@ -85,10 +84,11 @@
 inline error_code make_error_code(Uart::ErrorValue e) {
   return error_code(e, Uart::errorCategory());
 }
+
 inline error_condition make_error_condition(Uart::ErrorValue e) {
   return error_condition(e, Uart::errorCategory());
 }
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Platforms/Qt/.mbedignore	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-*
\ No newline at end of file
--- a/Platforms/Qt/SerialPort.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-/*******************************************************************************
-* 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 <QSerialPortInfo>
-#include <MaximInterface/Utilities/Error.hpp>
-#include "SerialPort.hpp"
-#include "Sleep.hpp"
-
-using std::string;
-
-namespace MaximInterface {
-namespace Qt {
-
-static_assert(QSerialPort::NoError == 0, "Remapping required for error_code.");
-
-error_code SerialPort::connect(const string & portName) {
-  port.setPort(QSerialPortInfo(QString::fromStdString(portName)));
-  auto result = port.open(QSerialPort::ReadWrite)
-                    ? error_code()
-                    : make_error_code(port.error());
-  if (result) {
-    return result;
-  }
-  result = port.setDataTerminalReady(true) ? error_code()
-                                           : make_error_code(port.error());
-  if (result) {
-    port.close();
-  }
-  return result;
-}
-
-error_code SerialPort::disconnect() {
-  port.close();
-  return error_code();
-}
-
-bool SerialPort::connected() const { return port.isOpen(); }
-
-string SerialPort::portName() const { return port.portName().toStdString(); }
-
-error_code SerialPort::setBaudRate(int_least32_t baudRate) {
-  return port.setBaudRate(baudRate) ? error_code()
-                                    : make_error_code(port.error());
-}
-
-error_code SerialPort::sendBreak() {
-  auto result =
-      port.setBreakEnabled(true) ? error_code() : make_error_code(port.error());
-  if (!result) {
-    sleep(1);
-    result = port.setBreakEnabled(false) ? error_code()
-                                         : make_error_code(port.error());
-  }
-  return result;
-}
-
-error_code SerialPort::clearReadBuffer() {
-  port.readAll();
-  return error_code();
-}
-
-error_code SerialPort::writeByte(uint_least8_t data) {
-  auto result =
-      port.putChar(data) ? error_code() : make_error_code(port.error());
-  if (!result) {
-    result = port.waitForBytesWritten(1000) ? error_code()
-                                            : make_error_code(port.error());
-  }
-  return result;
-}
-
-error_code SerialPort::readByte(uint_least8_t & data) {
-  if (port.atEnd()) {
-    const auto result = port.waitForReadyRead(1000)
-                            ? error_code()
-                            : make_error_code(port.error());
-    if (result) {
-      return result;
-    }
-  }
-  return port.getChar(reinterpret_cast<char *>(&data))
-             ? error_code()
-             : make_error_code(port.error());
-}
-
-const error_category & SerialPort::errorCategory() {
-  static class : public error_category {
-  public:
-    virtual const char * name() const override { return "Qt SerialPort"; }
-
-    virtual string message(int condition) const override {
-      switch (condition) {
-      case QSerialPort::DeviceNotFoundError:
-        return "Device Not Found";
-
-      case QSerialPort::PermissionError:
-        return "Permission Error";
-
-      case QSerialPort::OpenError:
-        return "Open Error";
-
-      case QSerialPort::NotOpenError:
-        return "Not Open Error";
-
-      case QSerialPort::WriteError:
-        return "Write Error";
-
-      case QSerialPort::ReadError:
-        return "Read Error";
-
-      case QSerialPort::ResourceError:
-        return "Resource Error";
-
-      case QSerialPort::UnsupportedOperationError:
-        return "Unsupported Operation Error";
-
-      case QSerialPort::TimeoutError:
-        return "Timeout Error";
-
-      default:
-        return defaultErrorMessage(condition);
-      }
-    }
-
-    // Make QSerialPort::TimeoutError equivalent to Uart::TimeoutError.
-    virtual bool equivalent(int code,
-                            const error_condition & condition) const override {
-      return (code == QSerialPort::TimeoutError)
-                 ? (condition == make_error_condition(Uart::TimeoutError))
-                 : error_category::equivalent(code, condition);
-    }
-  } instance;
-  return instance;
-}
-
-} // namespace Qt
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/Qt/SerialPort.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*******************************************************************************
-* 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 <QSerialPort>
-#include <MaximInterface/Links/SerialPort.hpp>
-#include <MaximInterface/Utilities/Export.h>
-
-namespace MaximInterface {
-namespace Qt {
-
-class SerialPort : public MaximInterface::SerialPort {
-public:
-  MaximInterface_EXPORT virtual error_code
-  connect(const std::string & portName) override;
-  MaximInterface_EXPORT virtual error_code disconnect() override;
-  MaximInterface_EXPORT virtual bool connected() const override;
-  MaximInterface_EXPORT virtual std::string portName() const override;
-
-  MaximInterface_EXPORT virtual error_code
-  setBaudRate(int_least32_t baudRate) override;
-  MaximInterface_EXPORT virtual error_code sendBreak() override;
-  MaximInterface_EXPORT virtual error_code clearReadBuffer() override;
-  MaximInterface_EXPORT virtual error_code
-  writeByte(uint_least8_t data) override;
-  MaximInterface_EXPORT virtual error_code
-  readByte(uint_least8_t & data) override;
-                                                     
-  MaximInterface_EXPORT static const error_category & errorCategory();
-
-private:
-  QSerialPort port;
-};
-
-inline error_code make_error_code(QSerialPort::SerialPortError e) {
-  return error_code(e, SerialPort::errorCategory());
-}
-
-} // namespace Qt
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/Qt/Sleep.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*******************************************************************************
-* 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 <QThread>
-#include "SerialPort.hpp"
-#include "Sleep.hpp"
-
-namespace MaximInterface {
-namespace Qt {
-
-void sleep(const int ms) {
-  QThread::msleep(ms);
-}
-
-Sleep & Sleep::instance() {
-  static Sleep instance;
-  return instance;
-}
-
-void Sleep::operator()(int ms) const { sleep(ms); }
-
-} // namespace Qt
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/Qt/Sleep.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#ifndef MaximInterface_Qt_SerialPort
-#define MaximInterface_Qt_SerialPort
-
-#include <MaximInterface/Links/Sleep.hpp>
-#include <MaximInterface/Utilities/Export.h>
-#include <MaximInterface/Utilities/Uncopyable.hpp>
-
-namespace MaximInterface {
-namespace Qt {
-
-MaximInterface_EXPORT void sleep(int ms);
-
-class Sleep : public MaximInterface::Sleep, private Uncopyable {
-public:
-  MaximInterface_EXPORT static Sleep & instance();
-
-  MaximInterface_EXPORT virtual void operator()(int ms) const override;
-
-private:
-  Sleep() = default;
-};
-
-} // namespace Qt
-} // namespace MaximInterface
-
-#endif
\ No newline at end of file
--- a/Platforms/dotnet/.mbedignore	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-*
\ No newline at end of file
--- a/Platforms/dotnet/ChangeSizeType.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#pragma once
-
-#include <algorithm>
-#include <limits>
-#include <type_traits>
-
-namespace MaximInterface {
-
-/// Adapts functions taking a data pointer and data size where the size type is
-/// not size_t. The function will be called multiple times if necessary to
-/// process all data.
-template <typename NewSize, typename Func, typename Data>
-void changeSizeType(Func func, Data data, size_t dataSize) {
-  using namespace std;
-
-  // Check if NewSize can represent the maximum value of dataSize.
-  if (numeric_limits<decltype(dataSize)>::max() >
-      static_cast<make_unsigned_t<NewSize>>(numeric_limits<NewSize>::max())) {
-    do {
-      const auto chunkSize =
-          min<decltype(dataSize)>(dataSize, numeric_limits<NewSize>::max());
-      func(data, static_cast<NewSize>(chunkSize));
-      data += chunkSize;
-      dataSize -= chunkSize;
-    } while (dataSize > 0);
-  } else {
-    func(data, static_cast<NewSize>(dataSize));
-  }
-}
-
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/dotnet/DelegateWrapper.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#pragma once
-
-#include <msclr/marshal_cppstd.h>
-#include <vcclr.h>
-
-namespace MaximInterface {
-namespace detail {
-
-template <typename DelegateT> class DelegateWrapperBase {
-public:
-  using Delegate = DelegateT;
-
-protected:
-  DelegateWrapperBase(Delegate ^ target) : target_(target) {}
-  ~DelegateWrapperBase() = default;
-
-public:
-  Delegate ^ target() const { return static_cast<Delegate ^>(target_); }
-  void setTarget(Delegate ^ target) { target_ = target; }
-  void swap(DelegateWrapperBase & other) { target_.swap(other.target_); }
-  explicit operator bool() const { return target() != nullptr; }
-
-private:
-  gcroot<Delegate ^> target_;
-};
-
-template <typename DelegateT>
-inline void swap(DelegateWrapperBase<DelegateT> & lhs,
-                 DelegateWrapperBase<DelegateT> & rhs) {
-  lhs.swap(rhs);
-}
-
-template <typename R, typename... Args>
-class DelegateWrapperImpl
-    : public DelegateWrapperBase<System::Func<Args..., R> > {
-protected:
-  DelegateWrapperImpl(Delegate ^ target) : DelegateWrapperBase(target) {}
-
-public:
-  R operator()(Args... args) { return target()(args...); }
-};
-
-template <typename... Args>
-class DelegateWrapperImpl<void, Args...>
-    : public DelegateWrapperBase<System::Action<Args...> > {
-protected:
-  DelegateWrapperImpl(Delegate ^ target) : DelegateWrapperBase(target) {}
-
-public:
-  void operator()(Args... args) const { target()(args...); }
-};
-
-} // namespace detail
-
-/// @{
-/// Functor wrapper for .NET delegates.
-template <typename> class DelegateWrapper;
-
-template <typename R, typename... Args>
-class DelegateWrapper<R(Args...)>
-    : public detail::DelegateWrapperImpl<R, Args...> {
-public:
-  DelegateWrapper(Delegate ^ target = nullptr) : DelegateWrapperImpl(target) {}
-};
-
-template <typename R, typename... Args>
-class DelegateWrapper<R __clrcall(Args...)>
-    : public detail::DelegateWrapperImpl<R, Args...> {
-public:
-  DelegateWrapper(Delegate ^ target = nullptr) : DelegateWrapperImpl(target) {}
-};
-/// @}
-
-/// Wrapper for using a .NET delegate as a MaximInterface::WriteMessage.
-class WriteMessageDelegateWrapper
-    : public DelegateWrapper<void(System::String ^)> {
-public:
-  WriteMessageDelegateWrapper(Delegate ^ target = nullptr)
-      : DelegateWrapper(target) {}
-
-  void operator()(const std::string & arg) const {
-    target()(msclr::interop::marshal_as<System::String ^>(arg));
-  }
-};
-
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/dotnet/MoveOnly.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#ifndef MaximInterface_MoveOnly
-#define MaximInterface_MoveOnly
-
-namespace MaximInterface {
-
-class MoveOnly {
-protected:
-  MoveOnly() = default;
-  ~MoveOnly() = default;
-
-  MoveOnly(const MoveOnly &) = delete;
-  MoveOnly(MoveOnly &&) = default;
-  const MoveOnly & operator=(const MoveOnly &) = delete;
-  MoveOnly & operator=(MoveOnly &&) = default;
-};
-
-} // namespace MaximInterface
-
-#endif
\ No newline at end of file
--- a/Platforms/dotnet/OneWireLinkLayerMaster.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,337 +0,0 @@
-/*******************************************************************************
-* 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 <stdexcept>
-#include <msclr/auto_gcroot.h>
-#include <msclr/marshal_cppstd.h>
-#include <MaximInterface/Utilities/Error.hpp>
-#include "ChangeSizeType.hpp"
-#include "OneWireLinkLayerMaster.hpp"
-
-using DalSemi::OneWire::Adapter::AdapterException;
-using System::IntPtr;
-using System::Runtime::InteropServices::Marshal;
-using System::String;
-using msclr::interop::marshal_as;
-using std::string;
-
-namespace MaximInterface {
-
-struct OneWireLinkLayerMaster::Data {
-  msclr::auto_gcroot<DalSemi::OneWire::Adapter::PortAdapter ^> adapter;
-  bool connected = false;
-};
-
-OneWireLinkLayerMaster::OneWireLinkLayerMaster(const string & adapterName)
-    : data(std::make_unique<Data>()) {
-  try {
-    data->adapter = DalSemi::OneWire::AccessProvider::GetAdapter(
-        marshal_as<String ^>(adapterName));
-  } catch (AdapterException ^ e) {
-    throw std::invalid_argument(marshal_as<string>(e->Message));
-  }
-}
-
-OneWireLinkLayerMaster::~OneWireLinkLayerMaster() = default;
-
-OneWireLinkLayerMaster::OneWireLinkLayerMaster(
-    OneWireLinkLayerMaster && rhs) noexcept = default;
-
-OneWireLinkLayerMaster & OneWireLinkLayerMaster::
-operator=(OneWireLinkLayerMaster && rhs) noexcept = default;
-
-error_code OneWireLinkLayerMaster::connect(const string & portName) {
-  if (connected()) {
-    return make_error_code(AlreadyConnectedError);
-  }
-
-  error_code result;
-  try {
-    auto adapterResult =
-        data->adapter->OpenPort(marshal_as<String ^>(portName));
-    if (adapterResult) {
-      adapterResult = data->adapter->BeginExclusive(true);
-      if (adapterResult) {
-        data->connected = true;
-      } else {
-        data->adapter->FreePort();
-        result = make_error_code(OpenPortError);
-      }
-    } else {
-      result = make_error_code(OpenPortError);
-    }
-  } catch (AdapterException ^) {
-    result = make_error_code(CommunicationError);
-  }
-  return result;
-}
-
-void OneWireLinkLayerMaster::disconnect() {
-  data->adapter->EndExclusive();
-  data->adapter->FreePort();
-  data->connected = false;
-}
-
-bool OneWireLinkLayerMaster::connected() const { return data->connected; }
-
-string OneWireLinkLayerMaster::adapterName() const {
-  return marshal_as<string>(data->adapter->AdapterName);
-}
-
-string OneWireLinkLayerMaster::portName() const {
-  return connected() ? marshal_as<string>(data->adapter->PortName) : "";
-}
-
-error_code OneWireLinkLayerMaster::reset() {
-  using DalSemi::OneWire::Adapter::OWResetResult;
-
-  error_code result;
-  try {
-    switch (data->adapter->Reset()) {
-    case OWResetResult::RESET_SHORT:
-      result = make_error_code(ShortDetectedError);
-      break;
-
-    case OWResetResult::RESET_NOPRESENCE:
-      result = make_error_code(NoSlaveError);
-      break;
-    }
-  } catch (AdapterException ^) {
-    result = make_error_code(CommunicationError);
-  }
-  return result;
-}
-
-error_code OneWireLinkLayerMaster::touchBitSetLevel(bool & sendRecvBit,
-                                                    Level afterLevel) {
-  error_code result;
-  try {
-    switch (afterLevel) {
-    case StrongLevel: {
-      auto adapterResult = data->adapter->StartPowerDelivery(
-          DalSemi::OneWire::Adapter::OWPowerStart::CONDITION_AFTER_BIT);
-      if (!adapterResult) {
-        result = make_error_code(PowerDeliveryError);
-      }
-    } break;
-
-    case NormalLevel:
-      break;
-
-    default:
-      result = make_error_code(InvalidLevelError);
-      break;
-    }
-    if (!result) {
-      if (sendRecvBit) {
-        sendRecvBit = data->adapter->GetBit();
-      } else {
-        data->adapter->PutBit(0);
-      }
-    }
-  } catch (AdapterException ^) {
-    result = make_error_code(CommunicationError);
-  }
-  return result;
-}
-
-error_code OneWireLinkLayerMaster::writeByteSetLevel(uint_least8_t sendByte,
-                                                     Level afterLevel) {
-  error_code result;
-  try {
-    switch (afterLevel) {
-    case StrongLevel: {
-      auto adapterResult = data->adapter->StartPowerDelivery(
-          DalSemi::OneWire::Adapter::OWPowerStart::CONDITION_AFTER_BYTE);
-      if (!adapterResult) {
-        result = make_error_code(PowerDeliveryError);
-      }
-    } break;
-
-    case NormalLevel:
-      break;
-
-    default:
-      result = make_error_code(InvalidLevelError);
-      break;
-    }
-    if (!result) {
-      data->adapter->PutByte(sendByte);
-    }
-  } catch (AdapterException ^) {
-    result = make_error_code(CommunicationError);
-  }
-  return result;
-}
-
-error_code OneWireLinkLayerMaster::readByteSetLevel(uint_least8_t & recvByte,
-                                                    Level afterLevel) {
-  error_code result;
-  try {
-    switch (afterLevel) {
-    case StrongLevel: {
-      auto adapterResult = data->adapter->StartPowerDelivery(
-          DalSemi::OneWire::Adapter::OWPowerStart::CONDITION_AFTER_BYTE);
-      if (!adapterResult) {
-        result = make_error_code(PowerDeliveryError);
-      }
-    } break;
-
-    case NormalLevel:
-      break;
-
-    default:
-      result = make_error_code(InvalidLevelError);
-      break;
-    }
-    if (!result) {
-      recvByte = data->adapter->GetByte();
-    }
-  } catch (AdapterException ^) {
-    result = make_error_code(CommunicationError);
-  }
-  return result;
-}
-
-error_code OneWireLinkLayerMaster::writeBlock(const uint_least8_t * sendBuf,
-                                              size_t sendLen) {
-  error_code result;
-  try {
-    changeSizeType<int>(
-        [this](const uint_least8_t * data, int dataSize) {
-          auto dataManaged = gcnew array<uint_least8_t>(dataSize);
-          Marshal::Copy(static_cast<IntPtr>(const_cast<uint_least8_t *>(data)),
-                        dataManaged, 0, dataSize);
-          this->data->adapter->DataBlock(dataManaged, 0, dataSize);
-        },
-        sendBuf, sendLen);
-  } catch (AdapterException ^) {
-    result = make_error_code(CommunicationError);
-  }
-  return result;
-}
-
-error_code OneWireLinkLayerMaster::readBlock(uint_least8_t * recvBuf,
-                                             size_t recvLen) {
-  error_code result;
-  try {
-    changeSizeType<int>(
-        [this](uint_least8_t * data, int dataSize) {
-          auto dataManaged = gcnew array<uint_least8_t>(dataSize);
-          this->data->adapter->GetBlock(dataManaged, dataSize);
-          Marshal::Copy(dataManaged, 0, static_cast<IntPtr>(data), dataSize);
-        },
-        recvBuf, recvLen);
-  } catch (AdapterException ^) {
-    result = make_error_code(CommunicationError);
-  }
-  return result;
-}
-
-error_code OneWireLinkLayerMaster::setSpeed(Speed newSpeed) {
-  using DalSemi::OneWire::Adapter::OWSpeed;
-
-  error_code result;
-  try {
-    switch (newSpeed) {
-    case OverdriveSpeed:
-      data->adapter->Speed = OWSpeed::SPEED_OVERDRIVE;
-      break;
-
-    case StandardSpeed:
-      data->adapter->Speed = OWSpeed::SPEED_REGULAR;
-      break;
-
-    default:
-      result = make_error_code(InvalidSpeedError);
-      break;
-    }
-  } catch (AdapterException ^) {
-    result = make_error_code(CommunicationError);
-  }
-  return result;
-}
-
-error_code OneWireLinkLayerMaster::setLevel(Level newLevel) {
-  error_code result;
-  try {
-    switch (newLevel) {
-    case StrongLevel: {
-      auto setResult = data->adapter->StartPowerDelivery(
-          DalSemi::OneWire::Adapter::OWPowerStart::CONDITION_NOW);
-      if (!setResult) {
-        result = make_error_code(PowerDeliveryError);
-      }
-    } break;
-
-    case NormalLevel:
-      data->adapter->SetPowerNormal();
-      break;
-
-    default:
-      result = make_error_code(InvalidLevelError);
-      break;
-    }
-  } catch (AdapterException ^) {
-    result = make_error_code(CommunicationError);
-  }
-  return result;
-}
-
-const error_category & OneWireLinkLayerMaster::errorCategory() {
-  static class : public error_category {
-  public:
-    virtual const char * name() const { return "OneWireLinkLayerMaster"; }
-
-    virtual string message(int condition) const {
-      switch (condition) {
-      case CommunicationError:
-        return "Communication Error";
-
-      case OpenPortError:
-        return "Open Port Error";
-
-      case PowerDeliveryError:
-        return "Power Delivery Error";
-
-      case AlreadyConnectedError:
-        return "Already Connected Error";
-
-      default:
-        return defaultErrorMessage(condition);
-      }
-    }
-  } instance;
-  return instance;
-}
-
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/dotnet/OneWireLinkLayerMaster.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#pragma once
-
-#include <memory>
-#include <string>
-#include <MaximInterface/Links/OneWireMaster.hpp>
-#include <MaximInterface/Utilities/Export.h>
-#include "MoveOnly.hpp"
-
-namespace MaximInterface {
-
-/// 1-Wire interface using the OneWireLinkLayer DLL from the Compact.NET API.
-class OneWireLinkLayerMaster : public OneWireMaster, private MoveOnly {
-public:
-  enum ErrorValue {
-    CommunicationError = 1,
-    OpenPortError,
-    PowerDeliveryError,
-    AlreadyConnectedError
-  };
-
-  /// @param adapterName Adapter type name recogized by OneWireLinkLayer.
-  MaximInterface_EXPORT OneWireLinkLayerMaster(const std::string & adapterName);
-  MaximInterface_EXPORT ~OneWireLinkLayerMaster();
-
-  MaximInterface_EXPORT
-  OneWireLinkLayerMaster(OneWireLinkLayerMaster &&) noexcept;
-  MaximInterface_EXPORT OneWireLinkLayerMaster &
-  operator=(OneWireLinkLayerMaster &&) noexcept;
-
-  /// Connect to an adapter on the specified COM port.
-  MaximInterface_EXPORT error_code connect(const std::string & portName);
-  
-  /// Disconnect from the adapter on the current COM port.
-  MaximInterface_EXPORT void disconnect();
-
-  /// Check if currently connected to an adapter.
-  /// @returns True if connected.
-  MaximInterface_EXPORT bool connected() const;
-  
-  /// Get the adapter type name.
-  MaximInterface_EXPORT std::string adapterName() const;
-  
-  /// Get the currently connected COM port name.
-  MaximInterface_EXPORT std::string portName() const;
-
-  MaximInterface_EXPORT virtual error_code reset() override;
-  MaximInterface_EXPORT virtual error_code
-  touchBitSetLevel(bool & sendRecvBit, Level afterLevel) override;
-  MaximInterface_EXPORT virtual error_code
-  writeByteSetLevel(uint_least8_t sendByte, Level afterLevel) override;
-  MaximInterface_EXPORT virtual error_code
-  readByteSetLevel(uint_least8_t & recvByte, Level afterLevel) override;
-  MaximInterface_EXPORT virtual error_code
-  writeBlock(const uint_least8_t * sendBuf, size_t sendLen) override;
-  MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * recvBuf,
-                                                     size_t recvLen) override;
-  MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed) override;
-  MaximInterface_EXPORT virtual error_code setLevel(Level newLevel) override;
-
-  MaximInterface_EXPORT static const error_category & errorCategory();
-
-private:
-  struct Data;
-  std::unique_ptr<Data> data;
-};
-
-inline error_code make_error_code(OneWireLinkLayerMaster::ErrorValue e) {
-  return error_code(e, OneWireLinkLayerMaster::errorCategory());
-}
-
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/dotnet/SerialPort.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-/*******************************************************************************
-* 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 <msclr/auto_gcroot.h>
-#include <msclr/marshal_cppstd.h>
-#include <MaximInterface/Utilities/Error.hpp>
-#include "ChangeSizeType.hpp"
-#include "Sleep.hpp"
-#include "SerialPort.hpp"
-
-using msclr::interop::marshal_as;
-using std::string;
-using namespace System;
-using System::Runtime::InteropServices::Marshal;
-
-namespace MaximInterface {
-namespace dotnet {
-
-template <typename Type, typename Input> static bool isType(Input in) {
-  return dynamic_cast<Type>(in) != nullptr;
-}
-
-template <typename Func>
-static error_code executeTryCatchOperation(Func tryOperation) {
-  return executeTryCatchOperation(tryOperation, [] {});
-}
-
-template <typename TryFunc, typename CatchFunc>
-static error_code executeTryCatchOperation(TryFunc tryOperation,
-                                           CatchFunc catchOperation) {
-  error_code result;
-  try {
-    tryOperation();
-  } catch (Exception ^ e) {
-    catchOperation();
-    if (isType<ArgumentException ^>(e)) {
-      result = make_error_code(SerialPort::ArgumentError);
-    } else if (isType<InvalidOperationException ^>(e)) {
-      result = make_error_code(SerialPort::InvalidOperationError);
-    } else if (isType<System::IO::IOException ^>(e)) {
-      result = make_error_code(SerialPort::IOError);
-    } else if (isType<UnauthorizedAccessException ^>(e)) {
-      result = make_error_code(SerialPort::UnauthorizedAccessError);
-    } else if (isType<TimeoutException ^>(e)) {
-      result = make_error_code(SerialPort::TimeoutError);
-    } else {
-      throw;
-    }
-  }
-  return result;
-}
-
-template <typename Func>
-static error_code executeIfConnected(const SerialPort & serial,
-                                     Func operation) {
-  return serial.connected() ? operation()
-                            : make_error_code(SerialPort::NotConnectedError);
-}
-
-struct SerialPort::Data {
-  msclr::auto_gcroot<System::IO::Ports::SerialPort ^> port;
-};
-
-SerialPort::SerialPort() : data(std::make_unique<Data>()) {}
-
-SerialPort::~SerialPort() = default;
-
-SerialPort::SerialPort(SerialPort &&) noexcept = default;
-
-SerialPort & SerialPort::operator=(SerialPort &&) noexcept = default;
-
-error_code SerialPort::connect(const string & portName) {
-  data->port = gcnew System::IO::Ports::SerialPort;
-  return executeTryCatchOperation(
-      [this, &portName] {
-        data->port->PortName = marshal_as<String ^>(portName);
-        data->port->DtrEnable = true;
-        data->port->ReadTimeout = 1000;
-        data->port->WriteTimeout = 1000;
-        data->port->Open();
-      },
-      [this] { data->port.reset(); });
-}
-
-error_code SerialPort::disconnect() {
-  data->port.reset();
-  return error_code();
-}
-
-bool SerialPort::connected() const { return data->port.get() != nullptr; }
-
-string SerialPort::portName() const {
-  return connected() ? marshal_as<string>(data->port->PortName) : "";
-}
-
-error_code SerialPort::setBaudRate(int_least32_t baudRate) {
-  return executeIfConnected(*this, [this, baudRate] {
-    return executeTryCatchOperation(
-        [this, baudRate] { data->port->BaudRate = baudRate; });
-  });
-}
-
-error_code SerialPort::sendBreak() {
-  return executeIfConnected(*this, [this] {
-    return executeTryCatchOperation([this] {
-      data->port->BreakState = true;
-      sleep(1);
-      data->port->BreakState = false;
-    });
-  });
-}
-
-error_code SerialPort::clearReadBuffer() {
-  return executeIfConnected(*this, [this] {
-    return executeTryCatchOperation([this] { data->port->ReadExisting(); });
-  });
-}
-
-error_code SerialPort::writeByte(uint_least8_t data) {
-  return writeBlock(&data, 1);
-}
-
-error_code SerialPort::writeBlock(const uint_least8_t * data, size_t dataLen) {
-  return executeIfConnected(*this, [this, data, dataLen] {
-    return executeTryCatchOperation([this, data, dataLen] {
-      changeSizeType<int>(
-          [this](const uint_least8_t * dataChunk, int dataChunkSize) {
-            auto dataManaged = gcnew array<uint_least8_t>(dataChunkSize);
-            Marshal::Copy(
-                static_cast<IntPtr>(const_cast<uint_least8_t *>(dataChunk)),
-                dataManaged, 0, dataChunkSize);
-            this->data->port->Write(dataManaged, 0, dataChunkSize);
-          },
-          data, dataLen);
-    });
-  });
-}
-
-error_code SerialPort::readByte(uint_least8_t & data) {
-  return executeIfConnected(*this, [this, &data] {
-    return executeTryCatchOperation(
-        [this, &data] { data = this->data->port->ReadByte(); });
-  });
-}
-
-error_code SerialPort::readBlock(uint_least8_t * data, size_t dataLen) {
-  return executeIfConnected(*this, [this, data, dataLen] {
-    return executeTryCatchOperation([this, data, dataLen] {
-      changeSizeType<int>(
-          [this](uint_least8_t * dataChunk, int dataChunkSize) {
-            auto dataManaged = gcnew array<uint_least8_t>(dataChunkSize);
-            int bytesRead = 0;
-            do {
-              bytesRead += this->data->port->Read(dataManaged, bytesRead,
-                                                  dataChunkSize - bytesRead);
-            } while (bytesRead < dataChunkSize);
-            Marshal::Copy(dataManaged, 0, static_cast<IntPtr>(dataChunk),
-                          dataChunkSize);
-          },
-          data, dataLen);
-    });
-  });
-}
-
-const error_category & SerialPort::errorCategory() {
-  static class : public error_category {
-  public:
-    virtual const char * name() const override { return "dotnet SerialPort"; }
-
-    virtual string message(int condition) const override {
-      switch (condition) {
-      case NotConnectedError:
-        return "Not Connected Error";
-
-      case ArgumentError:
-        return "Argument Error";
-
-      case InvalidOperationError:
-        return "Invalid Operation Error";
-
-      case IOError:
-        return "IO Error";
-
-      case UnauthorizedAccessError:
-        return "Unauthorized Access Error";
-
-      default:
-        return defaultErrorMessage(condition);
-      }
-    }
-  } instance;
-  return instance;
-}
-
-} // namespace dotnet
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/dotnet/SerialPort.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#pragma once
-
-#include <memory>
-#include <string>
-#include <MaximInterface/Links/SerialPort.hpp>
-#include <MaximInterface/Utilities/Export.h>
-#include "MoveOnly.hpp"
-
-namespace MaximInterface {
-namespace dotnet {
-
-/// Serial port interface using .NET type System::IO::Ports::SerialPort.
-class SerialPort : public MaximInterface::SerialPort, private MoveOnly {
-public:
-  enum ErrorValue {
-    NotConnectedError = 1,
-    ArgumentError,
-    InvalidOperationError,
-    IOError,
-    UnauthorizedAccessError
-  };
-
-  MaximInterface_EXPORT SerialPort();
-  MaximInterface_EXPORT ~SerialPort();
-
-  MaximInterface_EXPORT SerialPort(SerialPort &&) noexcept;
-  MaximInterface_EXPORT SerialPort & operator=(SerialPort &&) noexcept;
-
-  MaximInterface_EXPORT virtual error_code
-  connect(const std::string & portName) override;
-  MaximInterface_EXPORT virtual error_code disconnect() override;
-  MaximInterface_EXPORT virtual bool connected() const override;
-  MaximInterface_EXPORT virtual std::string portName() const override;
-
-  MaximInterface_EXPORT virtual error_code
-  setBaudRate(int_least32_t baudRate) override;
-  MaximInterface_EXPORT virtual error_code sendBreak() override;
-  MaximInterface_EXPORT virtual error_code clearReadBuffer() override;
-  MaximInterface_EXPORT virtual error_code
-  writeByte(uint_least8_t data) override;
-  MaximInterface_EXPORT virtual error_code
-  writeBlock(const uint_least8_t * data, size_t dataLen) override;
-  MaximInterface_EXPORT virtual error_code
-  readByte(uint_least8_t & data) override;
-  MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * data,
-                                                     size_t dataLen) override;
-
-  MaximInterface_EXPORT static const error_category & errorCategory();
-
-private:
-  struct Data;
-  std::unique_ptr<Data> data;
-};
-
-inline error_code make_error_code(SerialPort::ErrorValue e) {
-  return error_code(e, SerialPort::errorCategory());
-}
-
-} // namespace dotnet
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/dotnet/Sleep.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*******************************************************************************
-* 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 "Sleep.hpp"
-
-namespace MaximInterface {
-namespace dotnet {
-
-void sleep(const int ms) {
-  constexpr int timeSlice_ms = 20;
-  if (ms > timeSlice_ms / 2) {
-    System::Threading::Thread::Sleep(ms);
-  } else {
-    auto watch = System::Diagnostics::Stopwatch::StartNew();
-    while (watch->ElapsedMilliseconds < ms);
-    watch->Stop();
-  }
-}
-
-Sleep & Sleep::instance() {
-  static Sleep instance;
-  return instance;
-}
-
-void Sleep::operator()(int ms) const { sleep(ms); }
-
-} // namespace dotnet
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/dotnet/Sleep.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#pragma once
-
-#include <MaximInterface/Links/Sleep.hpp>
-#include <MaximInterface/Utilities/Export.h>
-#include <MaximInterface/Utilities/Uncopyable.hpp>
-
-namespace MaximInterface {
-namespace dotnet {
-
-MaximInterface_EXPORT void sleep(int ms);
-
-class Sleep : public MaximInterface::Sleep, private Uncopyable {
-public:
-  MaximInterface_EXPORT static Sleep & instance();
-
-  MaximInterface_EXPORT virtual void operator()(int ms) const override;
-
-private:
-  Sleep() = default;
-};
-
-} // namespace dotnet
-} // namespace MaximInterface
\ No newline at end of file
--- a/Platforms/mbed/I2CMaster.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Platforms/mbed/I2CMaster.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -50,10 +50,10 @@
 }
 
 error_code I2CMaster::writePacketImpl(uint_least8_t address,
-                                      const uint_least8_t * data,
-                                      size_t dataLen, bool sendStop) {
-  return (i2c->write(address, reinterpret_cast<const char *>(data), dataLen,
-                     !sendStop) == 0)
+                                      span<const uint_least8_t> data,
+                                      bool sendStop) {
+  return (i2c->write(address, reinterpret_cast<const char *>(data.data()),
+                     data.size(), !sendStop) == 0)
              ? error_code()
              : make_error_code(NackError);
 }
@@ -64,13 +64,12 @@
 }
 
 error_code I2CMaster::readPacketImpl(uint_least8_t address,
-                                     uint_least8_t * data, size_t dataLen,
-                                     bool sendStop) {
-  return (i2c->read(address, reinterpret_cast<char *>(data), dataLen,
+                                     span<uint_least8_t> data, bool sendStop) {
+  return (i2c->read(address, reinterpret_cast<char *>(data.data()), data.size(),
                     !sendStop) == 0)
              ? error_code()
              : make_error_code(NackError);
 }
 
 } // namespace mbed
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Platforms/mbed/I2CMaster.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Platforms/mbed/I2CMaster.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -50,12 +50,13 @@
   virtual error_code stop();
   virtual error_code writeByte(uint_least8_t data);
   virtual error_code readByte(AckStatus status, uint_least8_t & data);
-  
+
 protected:
-  virtual error_code readPacketImpl(uint_least8_t address, uint_least8_t * data,
-                                    size_t dataLen, bool sendStop); 
+  virtual error_code readPacketImpl(uint_least8_t address,
+                                    span<uint_least8_t> data, bool sendStop);
+                                    
   virtual error_code writePacketImpl(uint_least8_t address,
-                                     const uint_least8_t * data, size_t dataLen,
+                                     span<const uint_least8_t> data,
                                      bool sendStop);
 
 private:
--- a/Platforms/mbed/Sleep.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Platforms/mbed/Sleep.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -43,7 +43,7 @@
   return instance;
 }
 
-void Sleep::operator()(int ms) const { sleep(ms); }
+void Sleep::invoke(int ms) const { sleep(ms); }
 
 } // namespace mbed
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Platforms/mbed/Sleep.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Platforms/mbed/Sleep.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -44,8 +44,7 @@
 class Sleep : public MaximInterface::Sleep, private Uncopyable {
 public:
   static Sleep & instance();
-
-  virtual void operator()(int ms) const;
+  virtual void invoke(int ms) const;
 
 private:
   Sleep() {}
--- a/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_ARM_STD/owlink.s	Tue Jul 24 08:33:31 2018 +0000
+++ b/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_ARM_STD/owlink.s	Wed Apr 03 12:33:10 2019 +0000
@@ -31,17 +31,25 @@
 **********************************************************************/
 
 // ow_usdelay configuration
-#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000) // Processor clock in MHz
-#define OVERHEAD_TUNING 18 // Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ
-// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP for best results
+//
+// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP
+// for best results
+//
+// Processor clock in MHz
+#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000)
+//
+// Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ
+#define OVERHEAD_TUNING 18
+//
+// ARM specifies 1-3 cycles for pipeline refill following a branch
+#define PIPELINE_REFILL_PROC_CYCLES 1
 
 // ow_usdelay constants
-#define PIPELINE_REFILL_PROC_CYCLES 1 // ARM specifies 1-3 cycles for pipeline refill following a branch
 #define PROC_CYCLES_PER_LOOP (2 + PIPELINE_REFILL_PROC_CYCLES)
-#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP) // Number of loop passes for a 1 us delay
+#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP)
 #define LOOPS_REMOVED_TUNING (OVERHEAD_TUNING / PROC_CYCLES_PER_LOOP)
 
-// OwTiming offsets
+// OneWireTiming offsets
 #define tRSTL_OFFSET    0
 #define tMSP_OFFSET     2
 #define tW0L_OFFSET     4
@@ -65,7 +73,7 @@
 ow_usdelay_return
   bx R14
   
-// static void write_ow_gpio_low(unsigned int * portReg, unsigned int pinMask)
+// void write_ow_gpio_low(volatile uint32_t * portReg, unsigned int pinMask)
   MACRO
 $label write_ow_gpio_low
   ldr R2, [R0]
@@ -73,7 +81,7 @@
   str R2, [R0]
   MEND
   
-// static void write_ow_gpio_high(unsigned int * portReg, unsigned int pinMask)
+// void write_ow_gpio_high(volatile uint32_t * portReg, unsigned int pinMask)
   MACRO
 $label write_ow_gpio_high
   ldr R2, [R0]
@@ -81,7 +89,9 @@
   str R2, [R0]
   MEND
   
-// void ow_bit(uint8_t * sendrecvbit, volatile uint32_t * inPortReg, volatile uint32_t * outPortReg, unsigned int pinMask, const OwTiming * timing)
+// void ow_bit(uint8_t * sendRecvBit, const volatile uint32_t * inReg,
+//             volatile uint32_t * outReg, unsigned int pinMask,
+//             const OneWireTiming * timing)
   EXPORT ow_bit
 ow_bit
   push {R4-R8, R14}
@@ -90,9 +100,9 @@
   ldr R6, [R6] // Load timing struct
   ldrh R4, [R6, #tSLOT_OFFSET]
   ldrh R5, [R6, #tMSR_OFFSET]
-  // R0: sendrecvbit
-  // R1: inPortReg
-  // R2: outPortReg
+  // R0: sendRecvBit
+  // R1: inReg
+  // R2: outReg
   // R3: pinMask
   // R4: tSLOT
   // R5: tMSR
@@ -102,22 +112,22 @@
   // R14: Scratch
   
   // Reorganize registers for upcoming function calls
-  mov R8, R1 // inPortReg to R8
-  mov R7, R2 // outPortReg to R7
+  mov R8, R1 // inReg to R8
+  mov R7, R2 // outReg to R7
   mov R1, R3 // pinMask to R1
-  mov R3, R0 // sendrecvbit to R3
+  mov R3, R0 // sendRecvBit to R3
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tSLOT
   // R5: tMSR
   // R6: timing
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
   
-  // if (*sendrecvbit & 1)
+  // if (*sendRecvBit & 1)
   ldrb R14, [R3]
   tst R14, #1
   beq write_zero
@@ -127,22 +137,22 @@
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tREC
   // R5: delay2
   // R6: tW1L
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_low // Pull low
   mov R0, R6 // tLOW
   bl ow_usdelay // Delay for tLOW
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_high // Release pin
   mov R0, R5 // delay2
   bl ow_usdelay // Delay for sample time
-  ldr R5, [R8] // Read *inPortReg
+  ldr R5, [R8] // Read *inReg
   b recovery_delay
   // else
 write_zero
@@ -152,32 +162,32 @@
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tREC
   // R5: tMSR
   // R6: delay2
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_low // Pull low
   mov R0, R5 // tMSR
   bl ow_usdelay // Delay for tMSR
-  ldr R5, [R8] // Read *inPortReg
+  ldr R5, [R8] // Read *inReg
   mov R0, R6 // delay2
   bl ow_usdelay // Delay for release
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_high // Release pin
-  // endif (*sendrecvbit & 1)
+  // endif (*sendRecvBit & 1)
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tREC
-  // R5: *inPortReg
+  // R5: *inReg
   // R6: Scratch
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
   
 recovery_delay
@@ -185,7 +195,7 @@
   bl ow_usdelay // Delay for tREC
   
   // Parse received bit
-  // *sendrecvbit = ((*inPortReg & pinMask) == pinMask)
+  // *sendRecvBit = ((*inReg & pinMask) == pinMask)
   and R5, R5, R1
   cmp R5, R1
   ite eq
--- a/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_GCC_ARM/owlink.S	Tue Jul 24 08:33:31 2018 +0000
+++ b/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_GCC_ARM/owlink.S	Wed Apr 03 12:33:10 2019 +0000
@@ -31,17 +31,25 @@
 **********************************************************************/
 
 // ow_usdelay configuration
-#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000) // Processor clock in MHz
-#define OVERHEAD_TUNING 18 // Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ
-// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP for best results
+//
+// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP
+// for best results
+//
+// Processor clock in MHz
+#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000)
+//
+// Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ
+#define OVERHEAD_TUNING 18
+//
+// ARM specifies 1-3 cycles for pipeline refill following a branch
+#define PIPELINE_REFILL_PROC_CYCLES 1
 
 // ow_usdelay constants
-#define PIPELINE_REFILL_PROC_CYCLES 1 // ARM specifies 1-3 cycles for pipeline refill following a branch
 #define PROC_CYCLES_PER_LOOP (2 + PIPELINE_REFILL_PROC_CYCLES)
-#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP) // Number of loop passes for a 1 us delay
+#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP)
 #define LOOPS_REMOVED_TUNING (OVERHEAD_TUNING / PROC_CYCLES_PER_LOOP)
 
-// OwTiming offsets
+// OneWireTiming offsets
 #define tRSTL_OFFSET    0
 #define tMSP_OFFSET     2
 #define tW0L_OFFSET     4
@@ -67,21 +75,23 @@
 ow_usdelay_return:
   bx R14
   
-// static void write_ow_gpio_low(unsigned int * portReg, unsigned int pinMask)
+// void write_ow_gpio_low(volatile uint32_t * portReg, unsigned int pinMask)
 .macro write_ow_gpio_low
   ldr R2, [R0]
   bic R2, R2, R1
   str R2, [R0]
   .endm
   
-// static void write_ow_gpio_high(unsigned int * portReg, unsigned int pinMask)
+// void write_ow_gpio_high(volatile uint32_t * portReg, unsigned int pinMask)
 .macro write_ow_gpio_high
   ldr R2, [R0]
   orr R2, R2, R1
   str R2, [R0]
   .endm
   
-// void ow_bit(uint8_t * sendrecvbit, volatile uint32_t * inPortReg, volatile uint32_t * outPortReg, unsigned int pinMask, const OwTiming * timing)
+// void ow_bit(uint8_t * sendRecvBit, const volatile uint32_t * inReg,
+//             volatile uint32_t * outReg, unsigned int pinMask,
+//             const OneWireTiming * timing)
   .thumb_func
   .global ow_bit
 ow_bit:
@@ -91,9 +101,9 @@
   ldr R6, [R6] // Load timing struct
   ldrh R4, [R6, #tSLOT_OFFSET]
   ldrh R5, [R6, #tMSR_OFFSET]
-  // R0: sendrecvbit
-  // R1: inPortReg
-  // R2: outPortReg
+  // R0: sendRecvBit
+  // R1: inReg
+  // R2: outReg
   // R3: pinMask
   // R4: tSLOT
   // R5: tMSR
@@ -103,22 +113,22 @@
   // R14: Scratch
   
   // Reorganize registers for upcoming function calls
-  mov R8, R1 // inPortReg to R8
-  mov R7, R2 // outPortReg to R7
+  mov R8, R1 // inReg to R8
+  mov R7, R2 // outReg to R7
   mov R1, R3 // pinMask to R1
-  mov R3, R0 // sendrecvbit to R3
+  mov R3, R0 // sendRecvBit to R3
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tSLOT
   // R5: tMSR
   // R6: timing
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
   
-  // if (*sendrecvbit & 1)
+  // if (*sendRecvBit & 1)
   ldrb R14, [R3]
   tst R14, #1
   beq write_zero
@@ -128,22 +138,22 @@
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tREC
   // R5: delay2
   // R6: tW1L
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_low // Pull low
   mov R0, R6 // tLOW
   bl ow_usdelay // Delay for tLOW
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_high // Release pin
   mov R0, R5 // delay2
   bl ow_usdelay // Delay for sample time
-  ldr R5, [R8] // Read *inPortReg
+  ldr R5, [R8] // Read *inReg
   b recovery_delay
   // else
 write_zero:
@@ -153,32 +163,32 @@
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tREC
   // R5: tMSR
   // R6: delay2
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_low // Pull low
   mov R0, R5 // tMSR
   bl ow_usdelay // Delay for tMSR
-  ldr R5, [R8] // Read *inPortReg
+  ldr R5, [R8] // Read *inReg
   mov R0, R6 // delay2
   bl ow_usdelay // Delay for release
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_high // Release pin
-  // endif (*sendrecvbit & 1)
+  // endif (*sendRecvBit & 1)
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tREC
-  // R5: *inPortReg
+  // R5: *inReg
   // R6: Scratch
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
   
 recovery_delay:
@@ -186,7 +196,7 @@
   bl ow_usdelay // Delay for tREC
   
   // Parse received bit
-  // *sendrecvbit = ((*inPortReg & pinMask) == pinMask)
+  // *sendRecvBit = ((*inReg & pinMask) == pinMask)
   and R5, R5, R1
   cmp R5, R1
   ite eq
--- a/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_IAR/owlink.s	Tue Jul 24 08:33:31 2018 +0000
+++ b/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_IAR/owlink.s	Wed Apr 03 12:33:10 2019 +0000
@@ -31,17 +31,25 @@
 **********************************************************************/
 
 // ow_usdelay configuration
-#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000) // Processor clock in MHz
-#define OVERHEAD_TUNING 18 // Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ
-// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP for best results
+//
+// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP
+// for best results
+//
+// Processor clock in MHz
+#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000)
+//
+// Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ
+#define OVERHEAD_TUNING 18
+//
+// ARM specifies 1-3 cycles for pipeline refill following a branch
+#define PIPELINE_REFILL_PROC_CYCLES 1
 
 // ow_usdelay constants
-#define PIPELINE_REFILL_PROC_CYCLES 1 // ARM specifies 1-3 cycles for pipeline refill following a branch
 #define PROC_CYCLES_PER_LOOP (2 + PIPELINE_REFILL_PROC_CYCLES)
-#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP) // Number of loop passes for a 1 us delay
+#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP)
 #define LOOPS_REMOVED_TUNING (OVERHEAD_TUNING / PROC_CYCLES_PER_LOOP)
 
-// OwTiming offsets
+// OneWireTiming offsets
 #define tRSTL_OFFSET    0
 #define tMSP_OFFSET     2
 #define tW0L_OFFSET     4
@@ -66,21 +74,23 @@
 ow_usdelay_return
   bx R14
   
-// static void write_ow_gpio_low(unsigned int * portReg, unsigned int pinMask)
+// void write_ow_gpio_low(volatile uint32_t * portReg, unsigned int pinMask)
 write_ow_gpio_low MACRO
   ldr R2, [R0]
   bic R2, R2, R1
   str R2, [R0]
   ENDM
   
-// static void write_ow_gpio_high(unsigned int * portReg, unsigned int pinMask)
+// void write_ow_gpio_high(volatile uint32_t * portReg, unsigned int pinMask)
 write_ow_gpio_high MACRO
   ldr R2, [R0]
   orr R2, R2, R1
   str R2, [R0]
   ENDM
   
-// void ow_bit(uint8_t * sendrecvbit, volatile uint32_t * inPortReg, volatile uint32_t * outPortReg, unsigned int pinMask, const OwTiming * timing)
+// void ow_bit(uint8_t * sendRecvBit, const volatile uint32_t * inReg,
+//             volatile uint32_t * outReg, unsigned int pinMask,
+//             const OneWireTiming * timing)
   EXPORT ow_bit
 ow_bit
   push {R4-R8, R14}
@@ -89,9 +99,9 @@
   ldr R6, [R6] // Load timing struct
   ldrh R4, [R6, #tSLOT_OFFSET]
   ldrh R5, [R6, #tMSR_OFFSET]
-  // R0: sendrecvbit
-  // R1: inPortReg
-  // R2: outPortReg
+  // R0: sendRecvBit
+  // R1: inReg
+  // R2: outReg
   // R3: pinMask
   // R4: tSLOT
   // R5: tMSR
@@ -101,22 +111,22 @@
   // R14: Scratch
   
   // Reorganize registers for upcoming function calls
-  mov R8, R1 // inPortReg to R8
-  mov R7, R2 // outPortReg to R7
+  mov R8, R1 // inReg to R8
+  mov R7, R2 // outReg to R7
   mov R1, R3 // pinMask to R1
-  mov R3, R0 // sendrecvbit to R3
+  mov R3, R0 // sendRecvBit to R3
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tSLOT
   // R5: tMSR
   // R6: timing
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
   
-  // if (*sendrecvbit & 1)
+  // if (*sendRecvBit & 1)
   ldrb R14, [R3]
   tst R14, #1
   beq write_zero
@@ -126,22 +136,22 @@
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tREC
   // R5: delay2
   // R6: tW1L
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_low // Pull low
   mov R0, R6 // tLOW
   bl ow_usdelay // Delay for tLOW
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_high // Release pin
   mov R0, R5 // delay2
   bl ow_usdelay // Delay for sample time
-  ldr R5, [R8] // Read *inPortReg
+  ldr R5, [R8] // Read *inReg
   b recovery_delay
   // else
 write_zero
@@ -151,32 +161,32 @@
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tREC
   // R5: tMSR
   // R6: delay2
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_low // Pull low
   mov R0, R5 // tMSR
   bl ow_usdelay // Delay for tMSR
-  ldr R5, [R8] // Read *inPortReg
+  ldr R5, [R8] // Read *inReg
   mov R0, R6 // delay2
   bl ow_usdelay // Delay for release
-  mov R0, R7 // outPortReg
+  mov R0, R7 // outReg
   write_ow_gpio_high // Release pin
-  // endif (*sendrecvbit & 1)
+  // endif (*sendRecvBit & 1)
   // R0: Scratch
   // R1: pinMask
   // R2: Scratch
-  // R3: sendrecvbit
+  // R3: sendRecvBit
   // R4: tREC
-  // R5: *inPortReg
+  // R5: *inReg
   // R6: Scratch
-  // R7: outPortReg
-  // R8: inPortReg
+  // R7: outReg
+  // R8: inReg
   // R14: Scratch
   
 recovery_delay
@@ -184,7 +194,7 @@
   bl ow_usdelay // Delay for tREC
   
   // Parse received bit
-  // *sendrecvbit = ((*inPortReg & pinMask) == pinMask)
+  // *sendRecvBit = ((*inReg & pinMask) == pinMask)
   and R5, R5, R1
   cmp R5, R1
   ite eq
--- a/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/owlink.h	Tue Jul 24 08:33:31 2018 +0000
+++ b/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/owlink.h	Wed Apr 03 12:33:10 2019 +0000
@@ -39,8 +39,7 @@
 extern "C" {
 #endif
 
-/// Timing parameters for the 1-Wire bus.
-/// @note All times are in terms of microseconds.
+/// Timing parameters for the 1-Wire bus in microseconds.
 struct OneWireTiming {
   uint16_t tRSTL; ///< Reset Low Time
   uint16_t tMSP;  ///< Presence-Detect Sample Time
@@ -53,16 +52,17 @@
 /// Delay for the specified number of microseconds.
 void ow_usdelay(unsigned int time_us);
 
-/// Send and receive one bit of communication and set a new level on the 1-Wire bus.
+/// @brief Send and receive one bit, and set a new level on the 1-Wire bus.
 /// @note GPIO pin must be configured for open drain operation.
-/// @param[in,out] sendRecvBit Buffer containing the bit to send on 1-Wire bus in lsb.
-///                            Read data from 1-Wire bus will be returned in lsb.
-/// @param inReg Input register for GPIO pin.
-/// @param outReg Output register for GPIO pin.
+/// @param[in,out] sendRecvBit
+/// Buffer containing the bit to send on 1-Wire bus in lsb.
+/// Read data from 1-Wire bus will be returned in lsb.
+/// @param[in] inReg Input register for GPIO pin.
+/// @param[in,out] outReg Output register for GPIO pin.
 /// @param pinMask Pin mask for input and output registers.
 /// @param[in] timing 1-Wire timing parameters to use.
-void ow_bit(uint8_t * sendRecvBit, volatile uint32_t * inReg,
-            volatile uint32_t * outPortReg, unsigned int pinMask,
+void ow_bit(uint8_t * sendRecvBit, const volatile uint32_t * inReg,
+            volatile uint32_t * outReg, unsigned int pinMask,
             const OneWireTiming * timing);
 
 #ifdef __cplusplus
--- a/Platforms/mbed/Uart.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Platforms/mbed/Uart.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -103,4 +103,4 @@
 }
 
 } // namespace mbed
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Platforms/mxc/.mbedignore	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-*
\ No newline at end of file
--- a/Platforms/mxc/Error.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*******************************************************************************
-* 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 <mxc_errors.h>
-#include "Error.hpp"
-
-namespace MaximInterface {
-namespace mxc {
-
-const error_category & errorCategory() {
-  static class : public error_category {
-  public:
-    virtual const char * name() const { return "mxc"; }
-
-    virtual std::string message(int condition) const {
-      return defaultErrorMessage(condition);
-    }
-
-    // Make E_COMM_ERR equivalent to I2CMaster::NackError.
-    virtual bool equivalent(int code, const error_condition & condition) const {
-      return (code == E_COMM_ERR)
-                 ? (condition == make_error_condition(I2CMaster::NackError))
-                 : error_category::equivalent(code, condition);
-    }
-  } instance;
-  return instance;
-}
-
-} // namespace mxc
-} // namespace MaximInterface
--- a/Platforms/mxc/Error.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-/// @file Common functionality for mapping mxc return codes to
-/// MaximInterface::error_code.
-
-#ifndef MaximInterface_mxc_Error
-#define MaximInterface_mxc_Error
-
-#include <MaximInterface/Utilities/system_error.hpp>
-
-namespace MaximInterface {
-namespace mxc {
-
-const error_category & errorCategory();
-
-inline error_code makeErrorCode(int mxcResult) {
-  return error_code(mxcResult, errorCategory());
-}
-
-} // namespace mxc
-} // namespace MaximInterface
-
-#endif
--- a/Platforms/mxc/I2CMaster.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/*******************************************************************************
-* 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 <mxc_device.h>
-#include "Error.hpp"
-#include "I2CMaster.hpp"
-
-namespace MaximInterface {
-namespace mxc {
-
-static void verifyTransactionStarted(mxc_i2cm_regs_t & i2cm) {
-  if (!(i2cm.trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) {
-    i2cm.trans |= MXC_F_I2CM_TRANS_TX_START;
-  }
-}
-
-error_code I2CMaster::initialize(const sys_cfg_i2cm_t & sysCfg,
-                                 i2cm_speed_t speed) {
-  return makeErrorCode(I2CM_Init(i2cm, &sysCfg, speed));
-}
-
-error_code I2CMaster::shutdown() { return makeErrorCode(I2CM_Shutdown(i2cm)); }
-
-error_code I2CMaster::writeByte(uint_least8_t data, bool start) {
-  const uint16_t fifoData =
-      static_cast<uint16_t>(data & 0xFF) |
-      (start ? MXC_S_I2CM_TRANS_TAG_START : MXC_S_I2CM_TRANS_TAG_TXDATA_ACK);
-  const error_code result =
-      makeErrorCode(I2CM_WriteTxFifo(i2cm, i2cmFifo, fifoData));
-  if (result) {
-    I2CM_Recover(i2cm);
-  } else {
-    verifyTransactionStarted(*i2cm);
-  }
-  return result;
-}
-
-error_code I2CMaster::start(uint_least8_t address) {
-  return writeByte(address, true);
-}
-
-error_code I2CMaster::stop() {
-  error_code result = makeErrorCode(
-      I2CM_WriteTxFifo(i2cm, i2cmFifo, MXC_S_I2CM_TRANS_TAG_STOP));
-  if (!result) {
-    result = makeErrorCode(I2CM_TxInProgress(i2cm));
-  }
-  return result;
-}
-
-error_code I2CMaster::writeByte(uint_least8_t data) {
-  return writeByte(data, false);
-}
-
-error_code I2CMaster::readByte(AckStatus status, uint_least8_t & data) {
-  uint16_t fifoData = (status == Nack) ? MXC_S_I2CM_TRANS_TAG_RXDATA_NACK
-                                       : MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT;
-  error_code result = makeErrorCode(I2CM_WriteTxFifo(i2cm, i2cmFifo, fifoData));
-  if (!result) {
-    verifyTransactionStarted(*i2cm);
-    do {
-      int timeout = 0x5000;
-      while ((i2cm->bb & MXC_F_I2CM_BB_RX_FIFO_CNT) == 0) {
-        if ((--timeout <= 0) || (i2cm->trans & MXC_F_I2CM_TRANS_TX_TIMEOUT)) {
-          result = makeErrorCode(E_TIME_OUT);
-          goto exit;
-        }
-        if (i2cm->trans &
-            (MXC_F_I2CM_TRANS_TX_LOST_ARBITR | MXC_F_I2CM_TRANS_TX_NACKED)) {
-          result = make_error_code(NackError);
-          goto exit;
-        }
-      }
-      fifoData = i2cmFifo->rx;
-    } while (fifoData & MXC_S_I2CM_RSTLS_TAG_EMPTY);
-    data = fifoData & 0xFF;
-  }
-
-exit:
-  if (result) {
-    I2CM_Recover(i2cm);
-  }
-  return result;
-}
-
-} // namespace mxc
-} // namespace MaximInterface
--- a/Platforms/mxc/I2CMaster.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#ifndef MaximInterface_mxc_I2CMaster
-#define MaximInterface_mxc_I2CMaster
-
-#include <MaximInterface/Links/I2CMaster.hpp>
-#include <i2cm.h>
-
-namespace MaximInterface {
-namespace mxc {
-
-class I2CMaster : public MaximInterface::I2CMaster {
-public:
-  I2CMaster(mxc_i2cm_regs_t & i2cm, mxc_i2cm_fifo_regs_t & i2cmFifo)
-      : i2cm(&i2cm), i2cmFifo(&i2cmFifo) {}
-
-  void set_mxc_i2cm(mxc_i2cm_regs_t & i2cm, mxc_i2cm_fifo_regs_t & i2cmFifo) {
-    this->i2cm = &i2cm;
-    this->i2cmFifo = &i2cmFifo;
-  }
-
-  /// Initialize the hardware interface for use.
-  error_code initialize(const sys_cfg_i2cm_t & sysCfg, i2cm_speed_t speed);
-  
-  /// Shutdown the hardware interface after use.
-  error_code shutdown();
-
-  virtual error_code start(uint_least8_t address);
-  virtual error_code stop();
-  virtual error_code writeByte(uint_least8_t data);
-  virtual error_code readByte(AckStatus status, uint_least8_t & data);
-
-private:
-  error_code writeByte(uint_least8_t data, bool start);
-
-  mxc_i2cm_regs_t * i2cm;
-  mxc_i2cm_fifo_regs_t * i2cmFifo;
-};
-
-} // namespace mxc
-} // namespace MaximInterface
-
-#endif
--- a/Platforms/mxc/OneWireMaster.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*******************************************************************************
-* 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 "Error.hpp"
-#include "OneWireMaster.hpp"
-
-namespace MaximInterface {
-namespace mxc {
-
-error_code OneWireMaster::initialize(const owm_cfg_t & owmCfg,
-                                     const sys_cfg_owm_t & sysCfgOwm) {
-  extStrongPup = (owmCfg.ext_pu_mode != OWM_EXT_PU_UNUSED);
-  return makeErrorCode(OWM_Init(owm, &owmCfg, &sysCfgOwm));
-}
-
-error_code OneWireMaster::shutdown() {
-  return makeErrorCode(OWM_Shutdown(owm));
-}
-
-error_code OneWireMaster::reset() {
-  return OWM_Reset(owm) ? error_code() : make_error_code(NoSlaveError);
-}
-
-error_code OneWireMaster::touchBitSetLevel(bool & sendRecvBit,
-                                           Level afterLevel) {
-  sendRecvBit = OWM_TouchBit(owm, sendRecvBit);
-  return setLevel(afterLevel);
-}
-
-error_code OneWireMaster::writeByteSetLevel(uint_least8_t sendByte,
-                                            Level afterLevel) {
-  error_code result = makeErrorCode(OWM_WriteByte(owm, sendByte));
-  if (!result) {
-    result = setLevel(afterLevel);
-  }
-  return result;
-}
-
-error_code OneWireMaster::readByteSetLevel(uint_least8_t & recvByte,
-                                           Level afterLevel) {
-  recvByte = OWM_ReadByte(owm);
-  return setLevel(afterLevel);
-}
-
-error_code OneWireMaster::setSpeed(Speed newSpeed) {
-  error_code result;
-  if (newSpeed == OverdriveSpeed) {
-    OWM_SetOverdrive(owm, 1);
-  } else if (newSpeed == StandardSpeed) {
-    OWM_SetOverdrive(owm, 0);
-  } else {
-    result = make_error_code(InvalidSpeedError);
-  }
-  return result;
-}
-
-error_code OneWireMaster::setLevel(Level newLevel) {
-  error_code result;
-  if (extStrongPup) {
-    if (newLevel == StrongLevel) {
-      OWM_SetExtPullup(owm, 1);
-    } else if (newLevel == NormalLevel) {
-      OWM_SetExtPullup(owm, 0);
-    } else {
-      result = make_error_code(InvalidLevelError);
-    }
-  } else if (newLevel != NormalLevel) {
-    result = make_error_code(InvalidLevelError);
-  }
-  return result;
-}
-
-} // namespace mxc
-} // namespace MaximInterface
--- a/Platforms/mxc/OneWireMaster.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#ifndef MaximInterface_mxc_OneWireMaster
-#define MaximInterface_mxc_OneWireMaster
-
-#include <MaximInterface/Links/OneWireMaster.hpp>
-#include <owm.h>
-
-namespace MaximInterface {
-namespace mxc {
-
-/// MCU peripheral 1-Wire master (OWM)
-class OneWireMaster : public MaximInterface::OneWireMaster {
-public:
-  explicit OneWireMaster(mxc_owm_regs_t & owm)
-      : owm(&owm), extStrongPup(false) {}
-
-  void set_mxc_owm(mxc_owm_regs_t & owm) { this->owm = &owm; }
-
-  /// Initialize the hardware interface for use.
-  error_code initialize(const owm_cfg_t & owmCfg,
-                        const sys_cfg_owm_t & sysCfgOwm);
-                        
-  /// Shutdown the hardware interface after use.
-  error_code shutdown();
-
-  virtual error_code reset();
-  virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel);
-  virtual error_code writeByteSetLevel(uint_least8_t sendByte,
-                                       Level afterLevel);
-  virtual error_code readByteSetLevel(uint_least8_t & recvByte,
-                                      Level afterLevel);
-  virtual error_code setSpeed(Speed newSpeed);
-  virtual error_code setLevel(Level newLevel);
-
-private:
-  mxc_owm_regs_t * owm;
-  bool extStrongPup;
-};
-
-} // namespace mxc
-} // namespace MaximInterface
-
-#endif /* MaximInterface_mxc_OneWireMaster */
--- a/Platforms/mxc/Sleep.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*******************************************************************************
-* 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 "Sleep.hpp"
-
-namespace MaximInterface {
-namespace mxc {
-
-void Sleep::operator()(int ms) const {
-  if (ms > 0) {
-    TMR_Delay(tmr, MSEC(static_cast<unsigned long>(ms)));
-  }
-}
-
-} // namespace mxc
-} // namespace MaximInterface
--- a/Platforms/mxc/Sleep.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************/
-
-#ifndef MaximInterface_mxc_Sleep
-#define MaximInterface_mxc_Sleep
-
-#include <MaximInterface/Links/Sleep.hpp>
-#include <tmr_utils.h>
-
-namespace MaximInterface {
-namespace mxc {
-
-class Sleep : public MaximInterface::Sleep {
-public:
-  explicit Sleep(mxc_tmr_regs_t & tmr) : tmr(&tmr) {}
-
-  void set_mxc_tmr(mxc_tmr_regs_t & tmr) { this->tmr = &tmr; }
-
-  virtual void operator()(int ms) const;
-
-private:
-  mxc_tmr_regs_t * tmr;
-};
-
-} // namespace mxc
-} // namespace MaximInterface
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utilities/Algorithm.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -0,0 +1,42 @@
+/*******************************************************************************
+* Copyright (C) 2018 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.
+*******************************************************************************/
+
+#ifndef MaximInterface_Algorithm
+#define MaximInterface_Algorithm
+
+/// Alternative to std::max when a constant expression is required.
+#define MaximInterface_MAX(a, b) ((a) < (b) ? (b) : (a))
+
+/// Alternative to std::min when a constant expression is required.
+#define MaximInterface_MIN(a, b) ((b) < (a) ? (b) : (a))
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utilities/ChangeSizeType.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -0,0 +1,77 @@
+/*******************************************************************************
+* 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.
+*******************************************************************************/
+
+#ifndef MaximInterface_ChangeSizeType
+#define MaximInterface_ChangeSizeType
+
+#include <stdint.h>
+#include <algorithm>
+#include <limits>
+#include "span.hpp"
+#include "system_error.hpp"
+
+namespace MaximInterface {
+
+/// @brief
+/// Adapts functions taking an array pointer and size where the size type is
+/// nonstandard.
+/// @tparam NewSize Nonstandard size type.
+/// @tparam Func Must be callable as func(Data *, NewSize).
+/// @tparam Data Array element type.
+/// @param func Callback for processing chunks of data.
+/// @param data Data to process with callback.
+template <typename NewSize, typename Func, typename Data>
+error_code changeSizeType(Func func, span<Data> data) {
+  using namespace std;
+  typedef typename span<Data>::index_type DataSize;
+
+  error_code result;
+  // Check if NewSize can represent the maximum value of DataSize.
+  if (static_cast<uintmax_t>(numeric_limits<DataSize>::max()) >
+      static_cast<uintmax_t>(numeric_limits<NewSize>::max())) {
+    DataSize dataIdx = 0;
+    do {
+      const span<Data> chunk =
+          data.subspan(dataIdx, min<DataSize>(data.size() - dataIdx,
+                                              numeric_limits<NewSize>::max()));
+      result = func(chunk.data(), static_cast<NewSize>(chunk.size()));
+      dataIdx += chunk.size();
+    } while (dataIdx < data.size() && !result);
+  } else {
+    result = func(data.data(), static_cast<NewSize>(data.size()));
+  }
+  return result;
+}
+
+} // namespace MaximInterface
+
+#endif
\ No newline at end of file
--- a/Utilities/Ecc256.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/Ecc256.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -30,24 +30,32 @@
 * ownership rights.
 *******************************************************************************/
 
-#include <algorithm>
 #include "Ecc256.hpp"
 
 namespace MaximInterface {
 namespace Ecc256 {
 
-CertificateData createCertificateData(const PublicKey & publicKey,
-                                      const RomId & romId,
-                                      const ManId & manId) {
-  using std::copy;
+void copy(Point::const_span src, Point::span dst) {
+  copy(src.x, dst.x);
+  copy(src.y, dst.y);
+}
+
+void copy(KeyPair::const_span src, KeyPair::span dst) {
+  copy(src.privateKey, dst.privateKey);
+  copy(src.publicKey, dst.publicKey);
+}
 
-  CertificateData data;
-  CertificateData::iterator dataIt = data.begin();
-  dataIt = copy(publicKey.x.begin(), publicKey.x.end(), dataIt);
-  dataIt = copy(publicKey.y.begin(), publicKey.y.end(), dataIt);
-  dataIt = copy(romId.begin(), romId.end(), dataIt);
-  copy(manId.begin(), manId.end(), dataIt);
-  return data;
+void copy(Signature::const_span src, Signature::span dst) {
+  copy(src.r, dst.r);
+  copy(src.s, dst.s);
+}
+
+PublicKey::span CertificateData::publicKey() {
+  const PublicKey::span span = {
+      make_span(result_).subspan<publicKeyIdx, Scalar::size>(),
+      make_span(result_)
+          .subspan<publicKeyIdx + Scalar::size, Scalar::size>()};
+  return span;
 }
 
 } // namespace Ecc256
--- a/Utilities/Ecc256.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/Ecc256.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -34,7 +34,7 @@
 #define MaximInterface_Ecc256
 
 #include <stdint.h>
-#include "array.hpp"
+#include "array_span.hpp"
 #include "Export.h"
 #include "ManId.hpp"
 #include "RomId.hpp"
@@ -42,41 +42,206 @@
 namespace MaximInterface {
 namespace Ecc256 {
 
-typedef array<uint_least8_t, 32> Scalar;
+typedef array_span<uint_least8_t, 32> Scalar;
+
 struct Point {
-  /// Total size of all elements in bytes.
-  static const size_t size = 2 * Scalar::csize;
+  struct const_span {
+    Scalar::const_span x;
+    Scalar::const_span y;
+  };
+
+  struct span {
+    Scalar::span x;
+    Scalar::span y;
+
+    operator const_span() const {
+      const const_span sp = {x, y};
+      return sp;
+    }
+  };
+
+  struct array {
+    Scalar::array x;
+    Scalar::array y;
+
+    operator span() {
+      const span sp = {x, y};
+      return sp;
+    }
+    
+    operator const_span() const {
+      const const_span sp = {x, y};
+      return sp;
+    }
+  };
   
-  Scalar x;
-  Scalar y;
+private:
+  Point(); // deleted
 };
 
+MaximInterface_EXPORT void copy(Point::const_span src, Point::span dst);
+
 typedef Scalar PrivateKey;
 typedef Point PublicKey;
+
 struct KeyPair {
-  /// Total size of all elements in bytes.
-  static const size_t size = PrivateKey::csize + PublicKey::size;
+  struct const_span {
+    PrivateKey::const_span privateKey;
+    PublicKey::const_span publicKey;
+  };
+
+  struct span {
+    PrivateKey::span privateKey;
+    PublicKey::span publicKey;
+
+    operator const_span() const {
+      const const_span sp = {privateKey, publicKey};
+      return sp;
+    }
+  };
+
+  struct array {
+    PrivateKey::array privateKey;
+    PublicKey::array publicKey;
+
+    operator span() {
+      const span sp = {privateKey, publicKey};
+      return sp;
+    }
+    
+    operator const_span() const {
+      const const_span sp = {privateKey, publicKey};
+      return sp;
+    }
+  };
   
-  PrivateKey privateKey;
-  PublicKey publicKey;
+private:
+  KeyPair(); // deleted
 };
 
+MaximInterface_EXPORT void copy(KeyPair::const_span src, KeyPair::span dst);
+
 struct Signature {
-  /// Total size of all elements in bytes.
-  static const size_t size = 2 * Scalar::csize;
+  struct const_span {
+    Scalar::const_span r;
+    Scalar::const_span s;
+  };
+
+  struct span {
+    Scalar::span r;
+    Scalar::span s;
+
+    operator const_span() const {
+      const const_span sp = {r, s};
+      return sp;
+    }
+  };
+
+  struct array {
+    Scalar::array r;
+    Scalar::array s;
+
+    operator span() {
+      const span sp = {r, s};
+      return sp;
+    }
+    
+    operator const_span() const {
+      const const_span sp = {r, s};
+      return sp;
+    }
+  };
   
-  Scalar r;
-  Scalar s;
+private:
+  Signature(); // deleted
 };
 
+MaximInterface_EXPORT void copy(Signature::const_span src, Signature::span dst);
+
 /// Data used to create a device key certificate for ECC-256 authenticators.
-typedef array<uint_least8_t, 2 * Scalar::csize + RomId::csize + ManId::csize>
-    CertificateData;
+class CertificateData {
+public:
+  typedef array_span<uint_least8_t, 2 * Scalar::size + RomId::size + ManId::size>
+      Result;
+
+  CertificateData() : result_() {}
+
+  /// Formatted data result.
+  Result::const_span result() const { return result_; }
+
+  /// @name Public Key
+  /// @brief Public key of the device.
+  /// @{
+  
+  /// Get mutable Public Key.
+  MaximInterface_EXPORT PublicKey::span publicKey();
+  
+  /// Get immutable Public Key.
+  PublicKey::const_span publicKey() const {
+    return const_cast<CertificateData &>(*this).publicKey();
+  }
+  
+  /// Set Public Key.
+  CertificateData & setPublicKey(PublicKey::const_span publicKey) {
+    copy(publicKey, this->publicKey());
+    return *this;
+  }
+  
+  /// @}
 
-/// Formats data for creating a device key certificate from the public key,
-/// ROM ID, and MAN ID.
-MaximInterface_EXPORT CertificateData createCertificateData(
-    const PublicKey & publicKey, const RomId & romId, const ManId & manId);
+  /// @name ROM ID
+  /// @brief 1-Wire ROM ID of the device.
+  /// @{
+  
+  /// Get mutable ROM ID.
+  RomId::span romId() {
+    return make_span(result_).subspan<romIdIdx, RomId::size>();
+  }
+  
+  /// Get immutable ROM ID.
+  RomId::const_span romId() const {
+    return const_cast<CertificateData &>(*this).romId();
+  }
+  
+  /// Set ROM ID.
+  CertificateData & setRomId(RomId::const_span romId) {
+    copy(romId, this->romId());
+    return *this;
+  }
+  
+  /// @}
+
+  /// @name MAN ID
+  /// @brief Manufacturer ID of the device.
+  /// @{
+  
+  /// Get mutable MAN ID.
+  ManId::span manId() {
+    return make_span(result_).subspan<manIdIdx, ManId::size>();
+  }
+  
+  /// Get immutable MAN ID.
+  ManId::const_span manId() const {
+    return const_cast<CertificateData &>(*this).manId();
+  }
+  
+  /// Set MAN ID.
+  CertificateData & setManId(ManId::const_span manId) {
+    copy(manId, this->manId());
+    return *this;
+  }
+  
+  /// @}
+
+private:
+  typedef Result::span::index_type index;
+
+  static const index publicKeyIdx = 0;
+  static const index romIdIdx = publicKeyIdx + 2 * Scalar::size;
+  static const index manIdIdx = romIdIdx + RomId::size;
+
+  Result::array result_;
+};
 
 } // namespace Ecc256
 } // namespace MaximInterface
--- a/Utilities/Error.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/Error.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -38,4 +38,4 @@
   return (condition == 0) ? "Success" : "Unknown Error";
 }
 
-} // namespace MaximInterface
\ No newline at end of file
+} // namespace MaximInterface
--- a/Utilities/Error.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/Error.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -37,10 +37,10 @@
 
 namespace MaximInterface {
 
-/// Get the default error message associated with a condition. Typically used
-/// by an error_category when the condition is unknown.
+/// @brief Get the default error message associated with a condition.
+/// @details Typically used by an error_category when the condition is unknown.
 MaximInterface_EXPORT const char * defaultErrorMessage(int condition);
 
 }
 
-#endif
\ No newline at end of file
+#endif
--- a/Utilities/Export.h	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/Export.h	Wed Apr 03 12:33:10 2019 +0000
@@ -31,13 +31,9 @@
 *******************************************************************************/
 
 #ifndef MaximInterface_EXPORT
-    #ifdef _MSC_VER
-        #ifdef _DLL
-            #define MaximInterface_EXPORT __declspec(dllexport)
-        #else
-            #define MaximInterface_EXPORT __declspec(dllimport)
-        #endif /* _DLL */
-    #else
-        #define MaximInterface_EXPORT
-    #endif /* _MSC_VER */
-#endif /* MaximInterface_EXPORT */
\ No newline at end of file
+  #if defined(_MSC_VER) && defined(MaximInterface_EXPORTING)
+    #define MaximInterface_EXPORT __declspec(dllexport)
+  #else
+    #define MaximInterface_EXPORT
+  #endif
+#endif
--- a/Utilities/FlagSet.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/FlagSet.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -38,6 +38,7 @@
 
 namespace MaximInterface {
 
+/// @brief
 /// Provides functionality similar to std::bitset except using a bit flag,
 /// typically of an enum type, as the indexer.
 template <typename Flag, size_t flagBits> class FlagSet {
@@ -45,15 +46,20 @@
   class reference {
   public:
     reference(FlagSet & flagSet, Flag flag) : flagSet(&flagSet), flag(flag) {}
+    
     reference & operator=(bool x) {
       flagSet->set(flag, x);
       return *this;
     }
+    
     reference & operator=(const reference & x) {
       return operator=(static_cast<bool>(x));
     }
+    
     operator bool() const { return flagSet->test(flag); }
+    
     bool operator~() const { return reference(*this).flip(); }
+    
     reference & flip() {
       *this = !*this;
       return *this;
@@ -65,6 +71,7 @@
   };
 
   FlagSet() : bits() {}
+  
   FlagSet(unsigned long val) : bits(val) {}
 
   template <typename CharT, typename Traits, typename Alloc>
@@ -76,38 +83,58 @@
       : bits(str, pos, n) {}
 
   bool operator==(const FlagSet & rhs) const { return bits == rhs.bits; }
+  
   bool operator!=(const FlagSet & rhs) const { return !operator==(rhs); }
 
-  // Element access
+  /// @name Element access
+  /// @{
+  
   bool operator[](Flag flag) const { return test(flag); }
+  
   reference operator[](Flag flag) { return reference(*this, flag); }
+  
   bool test(Flag flag) const { return (bits.to_ulong() & flag) == flag; }
+  
   bool any() const { return bits.any(); }
+  
   bool none() const { return bits.none(); }
+  
   size_t count() const { return bits.count(); }
+  
+  /// @}
 
-  // Capacity
+  /// @name Capacity
+  /// @{
+  
   size_t size() const { return bits.size(); }
+  
+  /// @}
 
-  // Modifiers
+  /// @name Modifiers
+  /// @{
+  
   FlagSet & operator&=(const FlagSet & other) {
     bits &= other.bits;
     return *this;
   }
+  
   FlagSet & operator|=(const FlagSet & other) {
     bits |= other.bits;
     return *this;
   }
+  
   FlagSet & operator^=(const FlagSet & other) {
     bits ^= other.bits;
     return *this;
   }
+  
   FlagSet operator~() const { return ~bits; }
 
   FlagSet & set() {
     bits.set();
     return *this;
   }
+  
   FlagSet & set(Flag flag, bool value = true) {
     if (value) {
       bits |= flag;
@@ -116,26 +143,37 @@
     }
     return *this;
   }
+  
   FlagSet & reset() {
     bits.reset();
     return *this;
   }
+  
   FlagSet & reset(Flag flag) { return set(flag, false); }
+  
   FlagSet & flip() {
     bits.flip();
     return *this;
   }
+  
   FlagSet & flip(Flag flag) {
     bits ^= flag;
     return *this;
   }
+  
+  /// @}
 
-  // Conversions
+  /// @name Conversions
+  /// @{
+  
   template <typename CharT, typename Traits, typename Allocator>
   std::basic_string<CharT, Traits, Allocator> to_string() const {
     return bits.template to_string<CharT, Traits, Allocator>();
   }
+  
   unsigned long to_ulong() const { return bits.to_ulong(); }
+  
+  /// @}
 
 private:
   std::bitset<flagBits> bits;
@@ -185,4 +223,4 @@
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Utilities/Function.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/Function.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -34,6 +34,7 @@
 #define MaximInterface_Function
 
 #include <stddef.h>
+#include "SafeBool.hpp"
 #include "type_traits.hpp"
 
 // Include for std::swap.
@@ -70,7 +71,9 @@
 
 private:
   char data[TypeSize];
-  long double aligner;
+  long double aligner1;
+  long int aligner2;
+  void * aligner3;
 };
 
 // Computes the internal target size for TypeStorage based on a desired total
@@ -80,7 +83,9 @@
 template <typename Target, size_t totalSize> class TypeWrapperTotalSize {
 private:
   typedef TypeStorage<Target, 1> MinSizeStorage;
+  
   static const size_t otherDataSize = sizeof(Target *);
+  
   // Round down to be a multiple of alignment_of<MinSizeTargetStorage>::value.
   static const size_t internalTargetRawSize =
       (totalSize - otherDataSize) / alignment_of<MinSizeStorage>::value *
@@ -235,7 +240,7 @@
 
 } // namespace detail
 
-// Function wrapper similar to std::function for 0-2 argument functions.
+// Function wrapper similar to std::function for 0-3 argument functions.
 template <typename> class Function;
 
 // Function implementation for zero argument functions.
@@ -267,10 +272,12 @@
 
   void swap(Function & other) { callableWrapper.swap(other.callableWrapper); }
 
-  operator bool() const { return callableWrapper.target() != NULL; }
+  operator SafeBool() const {
+    return makeSafeBool(callableWrapper.target() != NULL);
+  }
 
   ResultType operator()() const {
-    return callableWrapper.target() ? (*callableWrapper.target())()
+    return callableWrapper.target() ? callableWrapper.target()->invoke()
                                     : ResultType();
   }
 
@@ -278,7 +285,7 @@
   class Callable {
   public:
     virtual ~Callable() {}
-    virtual ResultType operator()() const = 0;
+    virtual ResultType invoke() const = 0;
     virtual Callable * clone() const = 0;
     virtual void clone(void * buffer) const = 0;
   };
@@ -287,7 +294,7 @@
   public:
     CallableAdapter(F func) : func(func) {}
 
-    virtual ResultType operator()() const { return func(); }
+    virtual ResultType invoke() const { return func(); }
 
     virtual Callable * clone() const { return new CallableAdapter(*this); }
 
@@ -338,10 +345,12 @@
 
   void swap(Function & other) { callableWrapper.swap(other.callableWrapper); }
 
-  operator bool() const { return callableWrapper.target() != NULL; }
+  operator SafeBool() const {
+    return makeSafeBool(callableWrapper.target() != NULL);
+  }
 
   ResultType operator()(ArgumentType arg) const {
-    return callableWrapper.target() ? (*callableWrapper.target())(arg)
+    return callableWrapper.target() ? callableWrapper.target()->invoke(arg)
                                     : ResultType();
   }
 
@@ -349,7 +358,7 @@
   class Callable {
   public:
     virtual ~Callable() {}
-    virtual ResultType operator()(ArgumentType) const = 0;
+    virtual ResultType invoke(ArgumentType) const = 0;
     virtual Callable * clone() const = 0;
     virtual void clone(void * buffer) const = 0;
   };
@@ -358,7 +367,7 @@
   public:
     CallableAdapter(F func) : func(func) {}
 
-    virtual ResultType operator()(ArgumentType arg) const { return func(arg); }
+    virtual ResultType invoke(ArgumentType arg) const { return func(arg); }
 
     virtual Callable * clone() const { return new CallableAdapter(*this); }
 
@@ -414,19 +423,21 @@
 
   void swap(Function & other) { callableWrapper.swap(other.callableWrapper); }
 
-  operator bool() const { return callableWrapper.target() != NULL; }
+  operator SafeBool() const {
+    return makeSafeBool(callableWrapper.target() != NULL);
+  }
 
   ResultType operator()(FirstArgumentType arg1, SecondArgumentType arg2) const {
-    return callableWrapper.target() ? (*callableWrapper.target())(arg1, arg2)
-                                    : ResultType();
+    return callableWrapper.target()
+               ? callableWrapper.target()->invoke(arg1, arg2)
+               : ResultType();
   }
 
 private:
   class Callable {
   public:
     virtual ~Callable() {}
-    virtual ResultType operator()(FirstArgumentType,
-                                  SecondArgumentType) const = 0;
+    virtual ResultType invoke(FirstArgumentType, SecondArgumentType) const = 0;
     virtual Callable * clone() const = 0;
     virtual void clone(void * buffer) const = 0;
   };
@@ -435,8 +446,8 @@
   public:
     CallableAdapter(F func) : func(func) {}
 
-    virtual ResultType operator()(FirstArgumentType arg1,
-                                  SecondArgumentType arg2) const {
+    virtual ResultType invoke(FirstArgumentType arg1,
+                              SecondArgumentType arg2) const {
       return func(arg1, arg2);
     }
 
@@ -461,6 +472,94 @@
   lhs.swap(rhs);
 }
 
+// Function implementation for three argument functions.
+template <typename FirstArgumentType, typename SecondArgumentType,
+          typename ThirdArgumentType, typename ResultType>
+class Function<ResultType(FirstArgumentType, SecondArgumentType,
+                          ThirdArgumentType)> {
+public:
+  typedef ResultType result_type;
+
+  Function(ResultType (*func)(FirstArgumentType, SecondArgumentType,
+                              ThirdArgumentType) = NULL)
+      : callableWrapper() {
+    if (func) {
+      callableWrapper = func;
+    }
+  }
+
+  template <typename F> Function(F func) : callableWrapper(func) {}
+
+  const Function & operator=(ResultType (*func)(FirstArgumentType,
+                                                SecondArgumentType,
+                                                ThirdArgumentType)) {
+    if (func) {
+      callableWrapper = func;
+    } else {
+      callableWrapper.clear();
+    }
+    return *this;
+  }
+
+  template <typename F> const Function & operator=(F func) {
+    callableWrapper = func;
+    return *this;
+  }
+
+  void swap(Function & other) { callableWrapper.swap(other.callableWrapper); }
+
+  operator SafeBool() const {
+    return makeSafeBool(callableWrapper.target() != NULL);
+  }
+
+  ResultType operator()(FirstArgumentType arg1, SecondArgumentType arg2,
+                        ThirdArgumentType arg3) const {
+    return callableWrapper.target()
+               ? callableWrapper.target()->invoke(arg1, arg2, arg3)
+               : ResultType();
+  }
+
+private:
+  class Callable {
+  public:
+    virtual ~Callable() {}
+    virtual ResultType invoke(FirstArgumentType, SecondArgumentType,
+                              ThirdArgumentType) const = 0;
+    virtual Callable * clone() const = 0;
+    virtual void clone(void * buffer) const = 0;
+  };
+
+  template <typename F> class CallableAdapter : public Callable {
+  public:
+    CallableAdapter(F func) : func(func) {}
+
+    virtual ResultType invoke(FirstArgumentType arg1, SecondArgumentType arg2,
+                              ThirdArgumentType arg3) const {
+      return func(arg1, arg2, arg3);
+    }
+
+    virtual Callable * clone() const { return new CallableAdapter(*this); }
+
+    virtual void clone(void * buffer) const {
+      new (buffer) CallableAdapter(*this);
+    }
+
+  private:
+    F func;
+  };
+
+  detail::TypeWrapper<Callable, CallableAdapter> callableWrapper;
+};
+
+template <typename FirstArgumentType, typename SecondArgumentType,
+          typename ThirdArgumentType, typename ResultType>
+inline void swap(Function<ResultType(FirstArgumentType, SecondArgumentType,
+                                     ThirdArgumentType)> & lhs,
+                 Function<ResultType(FirstArgumentType, SecondArgumentType,
+                                     ThirdArgumentType)> & rhs) {
+  lhs.swap(rhs);
+}
+
 } // namespace MaximInterface
 
 #endif
--- a/Utilities/HexConversions.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/HexConversions.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -30,31 +30,55 @@
 * ownership rights.
 *******************************************************************************/
 
+#include <cctype>
 #include <cstdio>
+#include <cstdlib>
 #include "HexConversions.hpp"
 
+using std::string;
+using std::vector;
+
 namespace MaximInterface {
 
-static const unsigned int charsPerByte = 2;
+static const int charsPerByte = 2;
 
-std::string byteArrayToHexString(const uint_least8_t * byteArray,
-                                 size_t byteArraySize) {
-  std::string hexString;
-  char hexBuf[charsPerByte + 1];
-  for (size_t i = 0; i < byteArraySize; i++) {
+string byteArrayToHexString(span<const uint_least8_t> byteArray) {
+  string hexString;
+  hexString.reserve(byteArray.size() * charsPerByte);
+  for (span<const uint_least8_t>::index_type i = 0; i < byteArray.size(); ++i) {
+    char hexBuf[charsPerByte + 1];
     std::sprintf(hexBuf, "%2.2X", byteArray[i] & 0xFF);
     hexString.append(hexBuf, charsPerByte);
   }
   return hexString;
 }
 
-std::vector<uint_least8_t> hexStringToByteArray(const std::string & hexString) {
-  std::vector<uint_least8_t> byteArray;
-  byteArray.reserve(hexString.size() / charsPerByte + 1);
-  for (std::string::size_type i = 0; i < hexString.size(); i += charsPerByte) {
-    unsigned int byte;
-    std::sscanf(hexString.substr(i, charsPerByte).c_str(), "%2x", &byte);
-    byteArray.push_back(byte);
+optional<vector<uint_least8_t> >
+hexStringToByteArray(const string & hexString) {
+  optional<vector<uint_least8_t> > byteArray = vector<uint_least8_t>();
+  byteArray->reserve(hexString.size() / charsPerByte);
+  char hexBuf[charsPerByte + 1];
+  char * const hexBufEnd = hexBuf + charsPerByte;
+  *hexBufEnd = '\0';
+  char * hexBufIt = hexBuf;
+  for (string::const_iterator hexStringIt = hexString.begin(),
+                              hexStringEnd = hexString.end();
+       hexStringIt != hexStringEnd; ++hexStringIt) {
+    if (!std::isspace(*hexStringIt)) {
+      *hexBufIt = *hexStringIt;
+      if (++hexBufIt == hexBufEnd) {
+        char * hexBufParseEnd;
+        byteArray->push_back(static_cast<uint_least8_t>(
+            std::strtoul(hexBuf, &hexBufParseEnd, 16)));
+        if (hexBufParseEnd != hexBufEnd) {
+          break;
+        }
+        hexBufIt = hexBuf;
+      }
+    }
+  }
+  if (hexBufIt != hexBuf) {
+    byteArray.reset();
   }
   return byteArray;
 }
--- a/Utilities/HexConversions.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/HexConversions.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -37,16 +37,18 @@
 #include <stdint.h>
 #include <string>
 #include <vector>
-#include <MaximInterface/Utilities/Export.h>
+#include "Export.h"
+#include "optional.hpp"
+#include "span.hpp"
 
 namespace MaximInterface {
 
 /// Convert a byte array to a hex string.
 MaximInterface_EXPORT std::string
-byteArrayToHexString(const uint_least8_t * byteArray, size_t byteArraySize);
+byteArrayToHexString(span<const uint_least8_t> byteArray);
 
 /// Convert a hex string to a byte array.
-MaximInterface_EXPORT std::vector<uint_least8_t>
+MaximInterface_EXPORT optional<std::vector<uint_least8_t> >
 hexStringToByteArray(const std::string & hexString);
 
 } // namespace MaximInterface
--- a/Utilities/ManId.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/ManId.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -33,12 +33,12 @@
 #ifndef MaximInterface_ManId
 #define MaximInterface_ManId
 
-#include "array.hpp"
+#include "array_span.hpp"
 
 namespace MaximInterface {
 
 /// Standard container for a manufacturer ID.
-typedef array<uint_least8_t, 2> ManId;
+typedef array_span<uint_least8_t, 2> ManId;
 
 } // namespace MaximInterface
 
--- a/Utilities/RomId.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/RomId.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -33,36 +33,48 @@
 #ifndef MaximInterface_RomId
 #define MaximInterface_RomId
 
-#include "array.hpp"
+#include "array_span.hpp"
 #include "crc.hpp"
 
 namespace MaximInterface {
 
 /// Standard container for a 1-Wire ROM ID.
-typedef array<uint_least8_t, 8> RomId;
+typedef array_span<uint_least8_t, 8> RomId;
 
+/// @name Family Code
 /// @{
-/// Access the Family Code byte.
-inline RomId::value_type familyCode(const RomId & romId) {
-  return romId.front();
+
+/// Get the Family Code byte.
+inline RomId::element familyCode(RomId::const_span romId) {
+  return romId[0];
 }
-inline void setFamilyCode(RomId & romId, RomId::value_type familyCode) {
-  romId.front() = familyCode;
+
+/// Set the Family Code byte.
+inline void setFamilyCode(RomId::span romId, RomId::element familyCode) {
+  romId[0] = familyCode;
 }
+
 /// @}
 
+/// @name CRC8
 /// @{
-/// Access the CRC8 byte.
-inline RomId::value_type crc8(const RomId & romId) { return romId.back(); }
-inline void setCrc8(RomId & romId, RomId::value_type crc8) {
-  romId.back() = crc8;
+
+/// Get the CRC8 byte.
+inline RomId::element crc8(RomId::const_span romId) { 
+  return *romId.last<1>().data();
 }
+
+/// Set the CRC8 byte.
+inline void setCrc8(RomId::span romId, RomId::element crc8) {
+  *romId.last<1>().data() = crc8;
+}
+
 /// @}
 
-/// Check if the ROM ID is valid (Family Code and CRC8 are both valid).
+/// @brief Check if the ROM ID is valid (Family Code and CRC8 are both valid).
 /// @returns True if the ROM ID is valid.
-inline bool valid(const RomId & romId) {
-  return calculateCrc8(romId.data(), romId.size() - 1) == crc8(romId);
+inline bool valid(RomId::const_span romId) {
+  return calculateCrc8(romId.first(romId.size() - 1)) == crc8(romId);
 }
 
 } // namespace MaximInterface
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utilities/SafeBool.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -0,0 +1,67 @@
+/*******************************************************************************
+* Copyright (C) 2018 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.
+*******************************************************************************/
+
+#ifndef MaximInterface_SafeBool
+#define MaximInterface_SafeBool
+
+#include <stddef.h>
+
+namespace MaximInterface {
+namespace detail {
+
+// Implement SafeBool as a member function pointer since some compilers allow
+// function pointer to void pointer conversion.
+struct SafeBoolHelper {
+  void trueValue() const {}
+  
+private:
+  SafeBoolHelper(); // deleted
+};
+
+} // namespace detail
+
+/// @brief Type definition for SafeBool.
+/// @details
+/// SafeBool is a boolean type that eliminates many error-prone implicit
+/// conversions allowed by the fundamental bool type.
+/// @note
+/// SafeBool can be used to add an explicit bool conversion operator to a type.
+typedef void (detail::SafeBoolHelper::*SafeBool)() const;
+
+/// Constructor for SafeBool.
+inline SafeBool makeSafeBool(bool value) {
+  return value ? &detail::SafeBoolHelper::trueValue : NULL;
+}
+
+} // namespace MaximInterface
+
+#endif
--- a/Utilities/Segment.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/Segment.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -39,8 +39,9 @@
 
 namespace MaximInterface {
 
+/// @brief
 /// Advances a given iterator by a given number of elements with bounds checking.
-/// InputIt must meet the requirements of InputIterator.
+/// @tparam InputIt Must meet the requirements of InputIterator.
 /// @param[in,out] it Iterator to advance. 
 /// @param bound
 /// Past-the-end boundary iterator. If distance is positive, bound must be
@@ -97,16 +98,19 @@
   return distance;
 }
 
-/// Locates an iterator sub-range using segment number addressing. Useful for
-/// devices that divide the memory space into uniform chunks such as pages and
-/// segments. ForwardIt must meet the requirements of ForwardIterator.
+/// @brief Locates an iterator sub-range using segment number addressing.
+/// @details
+/// Useful for devices that divide the memory space into uniform chunks such as
+/// pages and segments.
+/// @tparam ForwardIt Must meet the requirements of ForwardIterator.
 /// @param begin Beginning of the input data range.
 /// @param end End of the input data range.
 /// @param segmentSize Number of elements contained in a segment.
 /// @param segmentNum Zero-indexed number of the desired segment.
-/// @returns Pair of iterators representing the sub-range of the segment within
+/// @returns
+/// Pair of iterators representing the sub-range of the segment within
 /// the input range. If the segment does not exist within the input range, both
-/// iterators in the pair are set to the end interator of the input range.
+/// iterators in the pair are set to the end iterator of the input range.
 template <typename ForwardIt, typename Index>
 std::pair<ForwardIt, ForwardIt> createSegment(
     ForwardIt begin, const ForwardIt end,
--- a/Utilities/Sha256.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/Sha256.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -34,26 +34,24 @@
 #define MaximInterface_Sha256
 
 #include <stdint.h>
-#include "array.hpp"
+#include "array_span.hpp"
 
 namespace MaximInterface {
 namespace Sha256 {
 
 /// Container for a SHA-256 hash.
-typedef array<uint_least8_t, 32> Hash;
-
-// Data used by SHA-256 MAC authenticators including DS28E15/22/25 and DS2465.
+typedef array_span<uint_least8_t, 32> Hash;
 
-/// Data for Compute Write MAC operation.
-typedef array<uint_least8_t, 20> WriteMacData;
+/// @brief Data for Compute Write MAC operation.
+/// @details
+/// Used by SHA-256 MAC authenticators including DS28E15/22/25 and DS2465.
+typedef array_span<uint_least8_t, 20> WriteMacData;
 
-/// Data for the Compute Auth. MAC operation.
-typedef array<uint_least8_t, 76>AuthMacData;
-
-/// Data for the Compute Slave Secret operation.
-typedef array<uint_least8_t, 76> SlaveSecretData;
+/// @brief Data for the Compute Auth. MAC and Compute Slave Secret operations.
+/// @copydetails WriteMacData
+typedef array_span<uint_least8_t, 76> AuthenticationData;
 
 } // namespace Sha256
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Utilities/Uncopyable.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/Uncopyable.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -47,4 +47,4 @@
 
 } // namespace MaximInterface
 
-#endif
\ No newline at end of file
+#endif
--- a/Utilities/WriteMessage.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/WriteMessage.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -43,4 +43,4 @@
 
 }
 
-#endif
\ No newline at end of file
+#endif
--- a/Utilities/array.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/array.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -55,58 +55,98 @@
   typedef std::reverse_iterator<iterator> reverse_iterator;
   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
 
-  // Element access
+  /// @name Element access
+  /// @{
+  
   reference operator[](size_type pos) {
     return const_cast<reference>(
         static_cast<const array &>(*this).operator[](pos));
   }
-  const_reference operator[](size_type pos) const { return _buffer[pos]; }
+  
+  const_reference operator[](size_type pos) const { return data()[pos]; }
+  
   reference front() {
     return const_cast<reference>(static_cast<const array &>(*this).front());
   }
-  const_reference front() const { return _buffer[0]; }
+  
+  const_reference front() const { return operator[](0); }
+  
   reference back() {
     return const_cast<reference>(static_cast<const array &>(*this).back());
   }
-  const_reference back() const { return _buffer[size() - 1]; }
+  
+  const_reference back() const { return operator[](size() - 1); }
+  
   pointer data() {
     return const_cast<pointer>(static_cast<const array &>(*this).data());
   }
+  
   const_pointer data() const { return _buffer; }
+  
+  /// @}
 
-  // Iterators
+  /// @name Iterators
+  /// @{
+  
   iterator begin() {
     return const_cast<iterator>(static_cast<const array &>(*this).cbegin());
   }
+  
   const_iterator begin() const { return cbegin(); }
-  const_iterator cbegin() const { return _buffer; }
+  
+  const_iterator cbegin() const { return data(); }
+  
   iterator end() {
     return const_cast<iterator>(static_cast<const array &>(*this).cend());
   }
+  
   const_iterator end() const { return cend(); }
-  const_iterator cend() const { return _buffer + size(); }
+  
+  const_iterator cend() const { return cbegin() + size(); }
+  
   reverse_iterator rbegin() { return reverse_iterator(end()); }
+  
   const_reverse_iterator rbegin() const {
     return const_reverse_iterator(end());
   }
+  
   const_reverse_iterator crbegin() const { return rbegin(); }
+  
   reverse_iterator rend() { return reverse_iterator(begin()); }
+  
   const_reverse_iterator rend() const {
     return const_reverse_iterator(begin());
   }
+  
   const_reverse_iterator crend() const { return rend(); }
+  
+  /// @}
 
-  // Capacity
+  /// @name Capacity
+  /// @{
+  
   static bool empty() { return size() == 0; }
+  
   static size_type size() { return N; }
+  
   static size_type max_size() { return size(); }
-  static const size_type csize =
-      N; ///< Alternative to size() when a constant expression is required.
+  
+  /// Alternative to size() when a constant expression is required.
+  static const size_type csize = N;
+  
+  /// @}
 
-  // Operations
+  /// @name Operations
+  /// @{
+  
   void fill(const_reference value) { std::fill(begin(), end(), value); }
+  
   void swap(array & other) { std::swap_ranges(begin(), end(), other.begin()); }
+  
+  /// @}
 
+  /// @private
+  /// @note Implementation detail set public to allow aggregate initialization.
   T _buffer[N];
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utilities/array_span.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -0,0 +1,63 @@
+/*******************************************************************************
+* Copyright (C) 2018 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.
+*******************************************************************************/
+
+#ifndef MaximInterface_array_span
+#define MaximInterface_array_span
+
+#include "array.hpp"
+#include "span.hpp"
+#include "type_traits.hpp"
+
+namespace MaximInterface {
+
+/// @brief
+/// Defines a standard set of types for data fields that are represented as a
+/// fixed-size array of elements.
+/// @tparam T A const qualifier is not allowed.
+template <typename T, size_t N> struct array_span {
+  typedef typename remove_volatile<T>::type element;
+  static const size_t size = N;
+  
+  typedef MaximInterface::array<element, N> array;
+  typedef MaximInterface::span<const T, N> const_span;
+  typedef MaximInterface::span<T, N> span;
+  
+private:
+  array_span(); // deleted
+};
+
+// Specialization for "const T" is not defined.
+template <typename T, size_t N> struct array_span<const T, N>;
+
+}
+
+#endif
--- a/Utilities/crc.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/crc.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -48,9 +48,8 @@
   return crc;
 }
 
-uint_fast8_t calculateCrc8(const uint_least8_t * data, size_t dataLen,
-                           uint_fast8_t crc) {
-  for (size_t i = 0; i < dataLen; i++) {
+uint_fast8_t calculateCrc8(span<const uint_least8_t> data, uint_fast8_t crc) {
+  for (span<const uint_least8_t>::index_type i = 0; i < data.size(); ++i) {
     crc = calculateCrc8(data[i], crc);
   }
   return crc;
@@ -75,9 +74,9 @@
   return crc;
 }
 
-uint_fast16_t calculateCrc16(const uint_least8_t * data, size_t dataLen,
+uint_fast16_t calculateCrc16(span<const uint_least8_t> data,
                              uint_fast16_t crc) {
-  for (size_t i = 0; i < dataLen; i++) {
+  for (span<const uint_least8_t>::index_type i = 0; i < data.size(); ++i) {
     crc = calculateCrc16(data[i], crc);
   }
   return crc;
--- a/Utilities/crc.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/crc.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -36,41 +36,37 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <MaximInterface/Utilities/Export.h>
+#include "span.hpp"
 
 namespace MaximInterface {
 
-/// Perform a CRC8 calculation.
+/// @brief Perform a CRC8 calculation.
 /// @param data Data to pass though the CRC generator.
 /// @param crc Beginning state of the CRC generator.
 /// @returns The calculated CRC8.
 MaximInterface_EXPORT uint_fast8_t calculateCrc8(uint_fast8_t data,
                                                  uint_fast8_t crc = 0);
 
-/// Perform a CRC8 calculation with variable length data.
+/// @brief Perform a CRC8 calculation with variable length data.
 /// @param[in] data Data array to pass through the CRC generator.
-/// @param dataLen Length of the data array to process.
 /// @param crc Beginning state of the CRC generator.
 /// @returns The calculated CRC8.
-MaximInterface_EXPORT uint_fast8_t calculateCrc8(const uint_least8_t * data,
-                                                 size_t dataLen,
+MaximInterface_EXPORT uint_fast8_t calculateCrc8(span<const uint_least8_t> data,
                                                  uint_fast8_t crc = 0);
 
-/// Perform a CRC16 calculation.
+/// @brief Perform a CRC16 calculation.
 /// @param data Data to pass though the CRC generator.
 /// @param crc Beginning state of the CRC generator.
 /// @returns The calculated CRC16.
 MaximInterface_EXPORT uint_fast16_t calculateCrc16(uint_fast8_t data,
                                                    uint_fast16_t crc = 0);
 
-/// Perform a CRC16 calculation with variable length data.
+/// @brief Perform a CRC16 calculation with variable length data.
 /// @param[in] data Data array to pass through the CRC generator.
-/// @param data_offset Offset of the data array to begin processing.
-/// @param data_len Length of the data array to process.
 /// @param crc Beginning state of the CRC generator.
 /// @returns The calculated CRC16.
-MaximInterface_EXPORT uint_fast16_t calculateCrc16(const uint_least8_t * data,
-                                                   size_t dataLen,
-                                                   uint_fast16_t crc = 0);
+MaximInterface_EXPORT uint_fast16_t
+calculateCrc16(span<const uint_least8_t> data, uint_fast16_t crc = 0);
 
 } // namespace MaximInterface
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utilities/optional.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -0,0 +1,318 @@
+/*******************************************************************************
+* Copyright (C) 2018 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.
+*******************************************************************************/
+
+#ifndef MaximInterface_optional
+#define MaximInterface_optional
+
+#include "SafeBool.hpp"
+
+// Include for std::swap.
+#include <algorithm>
+#include <utility>
+
+namespace MaximInterface {
+
+struct nullopt_t {
+  explicit nullopt_t(int) {}
+};
+
+static const nullopt_t nullopt(0);
+
+/// @brief Optional value container similar to std::optional.
+/// @details
+/// To prevent the need for aligned storage, this implementation imposes that
+/// types must be DefaultConstructible, CopyConstructible, and CopyAssignable.
+/// No exceptions are thrown when accessing a valueless optional.
+template <typename T> class optional {
+public:
+  typedef T value_type;
+
+  optional() : value_(), has_value_(false) {}
+  
+  optional(nullopt_t) : value_(), has_value_(false) {}
+
+  optional(const T & value) : value_(value), has_value_(true) {}
+
+  template <typename U>
+  explicit optional(const optional<U> & other)
+      : value_(other.value_), has_value_(other.has_value_) {}
+
+  optional & operator=(nullopt_t) {
+    reset();
+    return *this;
+  }
+
+  optional & operator=(const T & value) {
+    value_ = value;
+    has_value_ = true;
+    return *this;
+  }
+
+  template <typename U> optional & operator=(const optional<U> & other) {
+    if (has_value_ || other.has_value_) {
+      value_ = other.value_;
+      has_value_ = other.has_value_;
+    }
+    return *this;
+  }
+
+  bool has_value() const { return has_value_; }
+  
+  operator SafeBool() const { return makeSafeBool(has_value()); }
+
+  const T & value() const { return value_; }
+  
+  T & value() {
+    return const_cast<T &>(static_cast<const optional &>(*this).value());
+  }
+  
+  const T & operator*() const { return value(); }
+  
+  T & operator*() {
+    return const_cast<T &>(static_cast<const optional &>(*this).operator*());
+  }
+  
+  const T * operator->() const { return &value(); }
+  
+  T * operator->() {
+    return const_cast<T *>(static_cast<const optional &>(*this).operator->());
+  }
+
+  const T & value_or(const T & default_value) const {
+    return has_value() ? value() : default_value;
+  }
+
+  void swap(optional & other) {
+    if (has_value_ || other.has_value_) {
+      using std::swap;
+      swap(value_, other.value_);
+      swap(has_value_, other.has_value_);
+    }
+  }
+
+  void reset() {
+    if (has_value_) {
+      has_value_ = false;
+      value_ = T();
+    }
+  }
+
+private:
+  T value_;
+  bool has_value_;
+};
+
+template <typename T> optional<T> make_optional(const T & value) {
+  return value;
+}
+
+template <typename T> void swap(optional<T> & lhs, optional<T> & rhs) {
+  lhs.swap(rhs);
+}
+
+template <typename T, typename U>
+bool operator==(const optional<T> & lhs, const optional<U> & rhs) {
+  if (lhs.has_value() != rhs.has_value()) {
+    return false;
+  }
+  if (!lhs.has_value()) {
+    return true;
+  }
+  return lhs.value() == rhs.value();
+}
+
+template <typename T, typename U>
+bool operator!=(const optional<T> & lhs, const optional<U> & rhs) {
+  if (lhs.has_value() != rhs.has_value()) {
+    return true;
+  }
+  if (!lhs.has_value()) {
+    return false;
+  }
+  return lhs.value() != rhs.value();
+}
+
+template <typename T, typename U>
+bool operator<(const optional<T> & lhs, const optional<U> & rhs) {
+  if (!rhs.has_value()) {
+    return false;
+  }
+  if (!lhs.has_value()) {
+    return true;
+  }
+  return lhs.value() < rhs.value();
+}
+
+template <typename T, typename U>
+bool operator<=(const optional<T> & lhs, const optional<U> & rhs) {
+  if (!lhs.has_value()) {
+    return true;
+  }
+  if (!rhs.has_value()) {
+    return false;
+  }
+  return lhs.value() <= rhs.value();
+}
+
+template <typename T, typename U>
+bool operator>(const optional<T> & lhs, const optional<U> & rhs) {
+  if (!lhs.has_value()) {
+    return false;
+  }
+  if (!rhs.has_value()) {
+    return true;
+  }
+  return lhs.value() > rhs.value();
+}
+
+template <typename T, typename U>
+bool operator>=(const optional<T> & lhs, const optional<U> & rhs) {
+  if (!rhs.has_value()) {
+    return true;
+  }
+  if (!lhs.has_value()) {
+    return false;
+  }
+  return lhs.value() >= rhs.value();
+}
+
+template <typename T> bool operator==(const optional<T> & opt, nullopt_t) {
+  return !opt.has_value();
+}
+
+template <typename T> bool operator==(nullopt_t, const optional<T> & opt) {
+  return operator==(opt, nullopt);
+}
+
+template <typename T> bool operator!=(const optional<T> & opt, nullopt_t) {
+  return !operator==(opt, nullopt);
+}
+
+template <typename T> bool operator!=(nullopt_t, const optional<T> & opt) {
+  return operator!=(opt, nullopt);
+}
+
+template <typename T> bool operator<(const optional<T> &, nullopt_t) {
+  return false;
+}
+
+template <typename T> bool operator<(nullopt_t, const optional<T> & opt) {
+  return opt.has_value();
+}
+
+template <typename T> bool operator<=(const optional<T> & opt, nullopt_t) {
+  return !operator>(opt, nullopt);
+}
+
+template <typename T> bool operator<=(nullopt_t, const optional<T> & opt) {
+  return !operator>(nullopt, opt);
+}
+
+template <typename T> bool operator>(const optional<T> & opt, nullopt_t) {
+  return operator<(nullopt, opt);
+}
+
+template <typename T> bool operator>(nullopt_t, const optional<T> & opt) {
+  return operator<(opt, nullopt);
+}
+
+template <typename T> bool operator>=(const optional<T> & opt, nullopt_t) {
+  return !operator<(opt, nullopt);
+}
+
+template <typename T> bool operator>=(nullopt_t, const optional<T> & opt) {
+  return !operator<(nullopt, opt);
+}
+
+template <typename T, typename U>
+bool operator==(const optional<T> & opt, const U & value) {
+  return opt.has_value() ? opt.value() == value : false;
+}
+
+template <typename T, typename U>
+bool operator==(const T & value, const optional<U> & opt) {
+  return operator==(opt, value);
+}
+
+template <typename T, typename U>
+bool operator!=(const optional<T> & opt, const U & value) {
+  return opt.has_value() ? opt.value() != value : true;
+}
+
+template <typename T, typename U>
+bool operator!=(const T & value, const optional<U> & opt) {
+  return operator!=(opt, value);
+}
+
+template <typename T, typename U>
+bool operator<(const optional<T> & opt, const U & value) {
+  return opt.has_value() ? opt.value() < value : true;
+}
+
+template <typename T, typename U>
+bool operator<(const T & value, const optional<U> & opt) {
+  return opt.has_value() ? value < opt.value() : false;
+}
+
+template <typename T, typename U>
+bool operator<=(const optional<T> & opt, const U & value) {
+  return opt.has_value() ? opt.value() <= value : true;
+}
+
+template <typename T, typename U>
+bool operator<=(const T & value, const optional<U> & opt) {
+  return opt.has_value() ? value <= opt.value() : false;
+}
+
+template <typename T, typename U>
+bool operator>(const optional<T> & opt, const U & value) {
+  return opt.has_value() ? opt.value() > value : false;
+}
+
+template <typename T, typename U>
+bool operator>(const T & value, const optional<U> & opt) {
+  return opt.has_value() ? value > opt.value() : true;
+}
+
+template <typename T, typename U>
+bool operator>=(const optional<T> & opt, const U & value) {
+  return opt.has_value() ? opt.value() >= value : false;
+}
+
+template <typename T, typename U>
+bool operator>=(const T & value, const optional<U> & opt) {
+  return opt.has_value() ? value >= opt.value() : true;
+}
+
+} // namespace MaximInterface
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utilities/span.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -0,0 +1,366 @@
+/*******************************************************************************
+* Copyright (C) 2018 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.
+*******************************************************************************/
+
+#ifndef MaximInterface_span
+#define MaximInterface_span
+
+#include <stddef.h>
+#include <algorithm>
+#include <iterator>
+#include <vector>
+#include "array.hpp"
+#include "type_traits.hpp"
+
+namespace MaximInterface {
+
+static const ptrdiff_t dynamic_extent = -1;
+
+struct with_container_t {
+  explicit with_container_t(int) {}
+};
+
+static const with_container_t with_container(0);
+
+namespace detail {
+
+template <template <typename, ptrdiff_t = MaximInterface::dynamic_extent>
+          class span,
+          typename T, ptrdiff_t Extent>
+class span_base {
+public:
+  typedef T element_type;
+  typedef typename remove_cv<element_type>::type value_type;
+  typedef ptrdiff_t index_type;
+  typedef ptrdiff_t difference_type;
+  typedef element_type * pointer;
+  typedef element_type & reference;
+  typedef element_type * iterator;
+  typedef const element_type * const_iterator;
+  typedef std::reverse_iterator<iterator> reverse_iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+  static const index_type extent = Extent;
+
+protected:
+  span_base(pointer data) : data_(data) {}
+  ~span_base() {}
+
+public:
+  /// @name Iterators
+  /// @{
+  
+  iterator begin() const {
+    return const_cast<iterator>(static_cast<const span_base &>(*this).cbegin());
+  }
+  
+  const_iterator cbegin() const { return data(); }
+  
+  iterator end() const {
+    return const_cast<iterator>(static_cast<const span_base &>(*this).cend());
+  }
+  
+  const_iterator cend() const { return cbegin() + size(); }
+  
+  reverse_iterator rbegin() const { return reverse_iterator(end()); }
+  
+  const_reverse_iterator crbegin() const {
+    return const_reverse_iterator(cend());
+  }
+  
+  reverse_iterator rend() const { return reverse_iterator(begin()); }
+  
+  const_reverse_iterator crend() const {
+    return const_reverse_iterator(cbegin());
+  }
+  
+  /// @}
+
+  /// @name Element access
+  /// @{
+  
+  reference operator[](index_type idx) const { return data()[idx]; }
+  
+  reference operator()(index_type idx) const { return operator[](idx); }
+  
+  pointer data() const { return data_; }
+  
+  /// @}
+
+  /// @name Subviews
+  /// @{
+  
+  template <index_type Count> span<element_type, Count> first() const {
+    return subspan<0, Count>();
+  }
+  
+  span<element_type> first(index_type Count) const { return subspan(0, Count); }
+  
+  span<element_type> last(index_type Count) const {
+    return subspan(size() - Count, Count);
+  }
+  
+  template <index_type Offset, index_type Count>
+  span<element_type, Count> subspan() const {
+    return span<element_type, Count>(data() + Offset, Count);
+  }
+  
+  span<element_type> subspan(index_type Offset,
+                             index_type Count = dynamic_extent) const {
+    return span<element_type>(
+        data() + Offset, Count == dynamic_extent ? size() - Offset : Count);
+  }
+  
+  /// @}
+
+private:
+  index_type size() const {
+    return static_cast<const span<T, Extent> &>(*this).size();
+  }
+
+  pointer data_;
+};
+
+} // namespace detail
+
+/// Generic memory span class similar to gsl::span or the proposed std::span.
+template <typename T, ptrdiff_t Extent = dynamic_extent>
+class span : public detail::span_base<MaximInterface::span, T, Extent> {
+  typedef detail::span_base<MaximInterface::span, T, Extent> span_base;
+
+public:
+  using span_base::extent;
+  using typename span_base::element_type;
+  using typename span_base::index_type;
+  using typename span_base::pointer;
+  using typename span_base::value_type;
+
+  span(pointer data, index_type) : span_base(data) {}
+  
+  span(pointer begin, pointer) : span_base(begin) {}
+  
+  span(element_type (&arr)[extent]) : span_base(arr) {}
+  
+  span(array<value_type, extent> & arr) : span_base(arr.data()) {}
+  
+  span(const array<value_type, extent> & arr) : span_base(arr.data()) {}
+  
+  template <typename U> span(const span<U, extent> & s) : span_base(s.data()) {}
+  
+  template <typename Allocator>
+  explicit span(std::vector<value_type, Allocator> & vec)
+      : span_base(&vec.front()) {}
+      
+  template <typename Allocator>
+  explicit span(const std::vector<value_type, Allocator> & vec)
+      : span_base(&vec.front()) {}
+      
+  template <typename Container>
+  span(with_container_t, Container & cont) : span_base(cont.data()) {}
+  
+  template <typename Container>
+  span(with_container_t, const Container & cont) : span_base(cont.data()) {}
+
+  /// @name Observers
+  /// @{
+  
+  static index_type size() { return extent; }
+  
+  static index_type size_bytes() { return size() * sizeof(element_type); }
+  
+  static bool empty() { return size() == 0; }
+  
+  /// @}
+
+  /// @name Subviews
+  /// @{
+  
+  template <index_type Count> span<element_type, Count> last() const {
+    return this->template subspan<extent - Count, Count>();
+  }
+  
+  /// @}
+};
+
+template <typename T>
+class span<T, dynamic_extent>
+    : public detail::span_base<MaximInterface::span, T, dynamic_extent> {
+  typedef detail::span_base<MaximInterface::span, T, dynamic_extent> span_base;
+
+public:
+  using typename span_base::element_type;
+  using typename span_base::index_type;
+  using typename span_base::pointer;
+  using typename span_base::value_type;
+
+  span() : span_base(NULL), size_(0) {}
+  
+  span(pointer data, index_type size) : span_base(data), size_(size) {}
+  
+  span(pointer begin, pointer end) : span_base(begin), size_(end - begin) {}
+  
+  template <size_t N> span(element_type (&arr)[N]) : span_base(arr), size_(N) {}
+  
+  template <size_t N>
+  span(array<value_type, N> & arr) : span_base(arr.data()), size_(N) {}
+  
+  template <size_t N>
+  span(const array<value_type, N> & arr) : span_base(arr.data()), size_(N) {}
+  
+  template <typename U, ptrdiff_t N>
+  span(const span<U, N> & s) : span_base(s.data()), size_(s.size()) {}
+  
+  template <typename Allocator>
+  span(std::vector<value_type, Allocator> & vec)
+      : span_base(vec.empty() ? NULL : &vec.front()), size_(vec.size()) {}
+      
+  template <typename Allocator>
+  span(const std::vector<value_type, Allocator> & vec)
+      : span_base(vec.empty() ? NULL : &vec.front()), size_(vec.size()) {}
+      
+  template <typename Container>
+  span(with_container_t, Container & cont)
+      : span_base(cont.data()), size_(cont.size()) {}
+      
+  template <typename Container>
+  span(with_container_t, const Container & cont)
+      : span_base(cont.data()), size_(cont.size()) {}
+
+  /// @name Observers
+  /// @{
+  
+  index_type size() const { return size_; }
+  
+  index_type size_bytes() const { return size() * sizeof(element_type); }
+  
+  bool empty() const { return size() == 0; }
+  
+  /// @}
+
+  /// @name Subviews
+  /// @{
+  
+  template <index_type Count> span<element_type, Count> last() const {
+    return span<element_type, Count>(this->data() + (size() - Count), Count);
+  }
+  
+  /// @}
+
+private:
+  index_type size_;
+};
+
+template <typename T, ptrdiff_t Extent, typename U>
+bool operator==(span<T, Extent> lhs, span<U, Extent> rhs) {
+  return lhs.size() == rhs.size() &&
+         std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+template <typename T, ptrdiff_t Extent, typename U>
+bool operator!=(span<T, Extent> lhs, span<U, Extent> rhs) {
+  return !operator==(lhs, rhs);
+}
+
+template <typename T, ptrdiff_t Extent, typename U>
+bool operator<(span<T, Extent> lhs, span<U, Extent> rhs) {
+  return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
+                                      rhs.end());
+}
+
+template <typename T, ptrdiff_t Extent, typename U>
+bool operator>(span<T, Extent> lhs, span<U, Extent> rhs) {
+  return operator<(rhs, lhs);
+}
+
+template <typename T, ptrdiff_t Extent, typename U>
+bool operator<=(span<T, Extent> lhs, span<U, Extent> rhs) {
+  return !operator>(lhs, rhs);
+}
+
+template <typename T, ptrdiff_t Extent, typename U>
+bool operator>=(span<T, Extent> lhs, span<U, Extent> rhs) {
+  return !operator<(lhs, rhs);
+}
+
+template <typename T>
+span<T> make_span(T * data, typename span<T>::index_type size) {
+  return span<T>(data, size);
+}
+
+template <typename T> span<T> make_span(T * begin, T * end) {
+  return span<T>(begin, end);
+}
+
+template <typename T, size_t N> span<T, N> make_span(T (&arr)[N]) {
+  return span<T, N>(arr);
+}
+
+template <typename T, size_t N> span<T, N> make_span(array<T, N> & arr) {
+  return arr;
+}
+
+template <typename T, size_t N>
+span<const T, N> make_span(const array<T, N> & arr) {
+  return arr;
+}
+
+template <typename T, typename Allocator>
+span<T> make_span(std::vector<T, Allocator> & vec) {
+  return vec;
+}
+
+template <typename T, typename Allocator>
+span<const T> make_span(const std::vector<T, Allocator> & vec) {
+  return vec;
+}
+
+template <typename Container>
+span<typename Container::value_type> make_span(with_container_t,
+                                               Container & cont) {
+  return span<typename Container::value_type>(with_container, cont);
+}
+
+template <typename Container>
+span<const typename Container::value_type> make_span(with_container_t,
+                                                     const Container & cont) {
+  return span<const typename Container::value_type>(with_container, cont);
+}
+
+/// Deep copy between static spans of the same size.
+template <typename T, ptrdiff_t Extent, typename U>
+typename enable_if<Extent != dynamic_extent>::type copy(span<T, Extent> src,
+                                                        span<U, Extent> dst) {
+  std::copy(src.begin(), src.end(), dst.begin());
+}
+
+} // namespace MaximInterface
+
+#endif
--- a/Utilities/system_error.cpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/system_error.cpp	Wed Apr 03 12:33:10 2019 +0000
@@ -35,6 +35,8 @@
 
 namespace MaximInterface {
 
+using std::string;
+
 error_condition error_category::default_error_condition(int code) const {
   return error_condition(code, *this);
 }
@@ -53,11 +55,42 @@
   public:
     virtual const char * name() const { return "system"; }
 
-    virtual std::string message(int condition) const {
+    virtual string message(int condition) const {
       return defaultErrorMessage(condition);
     }
   } instance;
   return instance;
 }
 
-} // namespace MaximInterface
\ No newline at end of file
+static string formatWhat(const error_code & ec) {
+  return string(ec.category().name()) + ' ' + ec.message();
+}
+
+template <typename T>
+static string formatWhat(const error_code & ec, const T & what_arg) {
+  return string(what_arg) + ": " + formatWhat(ec);
+}
+
+system_error::system_error(const error_code & ec)
+    : runtime_error(formatWhat(ec)), code_(ec) {}
+
+system_error::system_error(const error_code & ec, const string & what_arg)
+    : runtime_error(formatWhat(ec, what_arg)), code_(ec) {}
+    
+system_error::system_error(const error_code & ec, const char * what_arg)
+    : runtime_error(formatWhat(ec, what_arg)), code_(ec) {}
+
+system_error::system_error(int ev, const error_category & ecat)
+    : runtime_error(formatWhat(error_code(ev, ecat))), code_(ev, ecat) {}
+
+system_error::system_error(int ev, const error_category & ecat,
+                           const string & what_arg)
+    : runtime_error(formatWhat(error_code(ev, ecat), what_arg)),
+      code_(ev, ecat) {}
+      
+system_error::system_error(int ev, const error_category & ecat,
+                           const char * what_arg)
+    : runtime_error(formatWhat(error_code(ev, ecat), what_arg)),
+      code_(ev, ecat) {}
+
+} // namespace MaximInterface
--- a/Utilities/system_error.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/system_error.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -31,14 +31,17 @@
 *******************************************************************************/
 
 /// @file
-/// Error handling constructs similar std::error_code, std::error_condition, and
-/// std::error_category.
+/// @brief
+/// Error handling constructs similar to std::error_code, std::error_condition,
+/// and std::error_category.
 
 #ifndef MaximInterface_system_error
 #define MaximInterface_system_error
 
+#include <stdexcept>
 #include <string>
-#include <MaximInterface/Utilities/Export.h>
+#include "Export.h"
+#include "SafeBool.hpp"
 #include "Uncopyable.hpp"
 
 namespace MaximInterface {
@@ -51,20 +54,27 @@
   virtual ~error_category() {}
 
   virtual const char * name() const = 0;
+  
   MaximInterface_EXPORT virtual error_condition
   default_error_condition(int code) const;
+  
   MaximInterface_EXPORT virtual bool
   equivalent(int code, const error_condition & condition) const;
+  
   MaximInterface_EXPORT virtual bool equivalent(const error_code & code,
                                                 int condition) const;
+  
   virtual std::string message(int condition) const = 0;
 };
+
 inline bool operator==(const error_category & lhs, const error_category & rhs) {
   return &lhs == &rhs;
 }
+
 inline bool operator!=(const error_category & lhs, const error_category & rhs) {
   return !operator==(lhs, rhs);
 }
+
 inline bool operator<(const error_category & lhs, const error_category & rhs) {
   return &lhs < &rhs;
 }
@@ -74,6 +84,7 @@
 class error_condition {
 public:
   error_condition() : value_(0), category_(&system_category()) {}
+  
   error_condition(int value, const error_category & category)
       : value_(value), category_(&category) {}
 
@@ -81,27 +92,35 @@
     value_ = value;
     category_ = &category;
   }
+  
   void clear() {
     value_ = 0;
     category_ = &system_category();
   }
+  
   int value() const { return value_; }
+  
   const error_category & category() const { return *category_; }
+  
   std::string message() const { return category().message(value()); }
-  operator bool() const { return value() != 0; }
+  
+  operator SafeBool() const { return makeSafeBool(value() != 0); }
 
 private:
   int value_;
   const error_category * category_;
 };
+
 inline bool operator==(const error_condition & lhs,
                        const error_condition & rhs) {
   return (lhs.value() == rhs.value()) && (lhs.category() == rhs.category());
 }
+
 inline bool operator!=(const error_condition & lhs,
                        const error_condition & rhs) {
   return !operator==(lhs, rhs);
 }
+
 inline bool operator<(const error_condition & lhs,
                       const error_condition & rhs) {
   return (lhs.category() < rhs.category()) ||
@@ -111,6 +130,7 @@
 class error_code {
 public:
   error_code() : value_(0), category_(&system_category()) {}
+  
   error_code(int value, const error_category & category)
       : value_(value), category_(&category) {}
 
@@ -118,28 +138,37 @@
     value_ = value;
     category_ = &category;
   }
+  
   void clear() {
     value_ = 0;
     category_ = &system_category();
   }
+  
   int value() const { return value_; }
+  
   const error_category & category() const { return *category_; }
+  
   error_condition default_error_condition() const {
     return category().default_error_condition(value());
   }
+  
   std::string message() const { return category().message(value()); }
-  operator bool() const { return value() != 0; }
+  
+  operator SafeBool() const { return makeSafeBool(value() != 0); }
 
 private:
   int value_;
   const error_category * category_;
 };
+
 inline bool operator==(const error_code & lhs, const error_code & rhs) {
   return (lhs.value() == rhs.value()) && (lhs.category() == rhs.category());
 }
+
 inline bool operator!=(const error_code & lhs, const error_code & rhs) {
   return !operator==(lhs, rhs);
 }
+
 inline bool operator<(const error_code & lhs, const error_code & rhs) {
   return (lhs.category() < rhs.category()) ||
          ((lhs.category() == rhs.category()) && (lhs.value() < rhs.value()));
@@ -156,16 +185,43 @@
   return lhs.category().equivalent(lhs.value(), rhs) ||
          rhs.category().equivalent(lhs, rhs.value());
 }
+
 inline bool operator!=(const error_code & lhs, const error_condition & rhs) {
   return !operator==(lhs, rhs);
 }
+
 inline bool operator==(const error_condition & lhs, const error_code & rhs) {
   return operator==(rhs, lhs);
 }
+
 inline bool operator!=(const error_condition & lhs, const error_code & rhs) {
   return !operator==(lhs, rhs);
 }
 
+class system_error : public std::runtime_error {
+public:
+  MaximInterface_EXPORT system_error(const error_code & ec);
+  
+  MaximInterface_EXPORT system_error(const error_code & ec,
+                                     const std::string & what_arg);
+                                     
+  MaximInterface_EXPORT system_error(const error_code & ec,
+                                     const char * what_arg);
+                                     
+  MaximInterface_EXPORT system_error(int ev, const error_category & ecat);
+  
+  MaximInterface_EXPORT system_error(int ev, const error_category & ecat,
+                                     const std::string & what_arg);
+                                     
+  MaximInterface_EXPORT system_error(int ev, const error_category & ecat,
+                                     const char * what_arg);
+
+  const error_code & code() const { return code_; }
+
+private:
+  error_code code_;
+};
+
 } // namespace MaximInterface
 
 #endif
--- a/Utilities/type_traits.hpp	Tue Jul 24 08:33:31 2018 +0000
+++ b/Utilities/type_traits.hpp	Wed Apr 03 12:33:10 2019 +0000
@@ -39,7 +39,8 @@
   static const T value = v;
   typedef T value_type;
   typedef integral_constant<T, v> type;
-  operator T() { return v; }
+  operator value_type() const { return value; }
+  value_type operator()() const { return value; }
 };
 
 typedef integral_constant<bool, true> true_type;
@@ -71,6 +72,16 @@
 struct alignment_of
     : integral_constant<size_t,
                         sizeof(detail::alignment_of_helper<T>) - sizeof(T)> {};
+                        
+template <typename T> struct remove_const { typedef T type; };
+template <typename T> struct remove_const<const T> { typedef T type; };
+
+template <typename T> struct remove_volatile { typedef T type; };
+template <typename T> struct remove_volatile<volatile T> { typedef T type; };
+
+template <typename T> struct remove_cv {
+  typedef typename remove_volatile<typename remove_const<T>::type>::type type;
+};
 
 } // namespace MaximInterface
 
--- a/clr.cmake	Tue Jul 24 08:33:31 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-#[[*****************************************************************************
-* 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_guard()
-
-macro(initializeClr)
-	if(NOT MSVC)
-		message(SEND_ERROR "MSVC must be used for CLR compilation.")
-	endif()
-	string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
-	string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
-	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHa /DNOMINMAX")
-endmacro(initializeClr)
-
-function(enableClr target dotnetFrameworkVersion)
-	set(dotnetFrameworkDir
-		"C:/Program Files (x86)/Reference Assemblies/Microsoft/Framework/.NETFramework/${dotnetFrameworkVersion}")
-	set(ARGN "mscorlib.dll" ${ARGN})
-	unset(dotnetReferences)
-	foreach(reference ${ARGN})
-		if(NOT IS_ABSOLUTE ${reference})
-			set(reference "${dotnetFrameworkDir}/${reference}")
-		endif()
-		list(APPEND dotnetReferences ${reference})
-	endforeach()
-
-	if(CMAKE_GENERATOR MATCHES "Visual Studio")
-		if(CMAKE_GENERATOR MATCHES "2005" OR CMAKE_GENERATOR MATCHES "2008")
-			message(SEND_ERROR "Visual Studio 2010 or later is required to build CLR target \"${target}\".")
-		endif()
-		
-		set_property(TARGET ${target} PROPERTY VS_GLOBAL_CLRSupport "true")
-		set_property(TARGET ${target} PROPERTY
-			VS_DOTNET_TARGET_FRAMEWORK_VERSION "${dotnetFrameworkVersion}")
-		set_property(TARGET ${target} PROPERTY VS_DOTNET_REFERENCES ${dotnetReferences})
-	else()
-		unset(dotnetReferenceArgs)
-		foreach(reference ${dotnetReferences})
-			list(APPEND dotnetReferenceArgs "/FU${reference}")
-		endforeach()
-		set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS
-			"/AI${dotnetFrameworkDir}"
-			"/clr"
-			${dotnetReferenceArgs}
-			"/clr:nostdlib")
-	endif()
-endfunction(enableClr)
\ No newline at end of file