Device interface library for multiple platforms including Mbed.

Dependents:   DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#

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

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

Files at this revision

API Documentation at this revision

Comitter:
IanBenzMaxim
Date:
Thu Jan 11 13:50:39 2018 -0600
Parent:
2:dbc089c57059
Child:
4:caf56f265a13
Commit message:
Updated to version 1.1.

Changed in this revision

CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
Devices/DS2480B.cpp Show annotated file Show diff for this revision Revisions of this file
Devices/DS2480B.hpp Show annotated file Show diff for this revision Revisions of this file
Devices/DS28C36_DS2476.cpp Show annotated file Show diff for this revision Revisions of this file
Devices/DS28C36_DS2476.hpp Show annotated file Show diff for this revision Revisions of this file
Devices/DS9400.cpp Show annotated file Show diff for this revision Revisions of this file
Devices/DS9400.hpp Show annotated file Show diff for this revision Revisions of this file
Devices/DS9481P_300.cpp Show annotated file Show diff for this revision Revisions of this file
Devices/DS9481P_300.hpp Show annotated file Show diff for this revision Revisions of this file
Links/I2CMaster.cpp Show annotated file Show diff for this revision Revisions of this file
Links/I2CMaster.hpp Show annotated file Show diff for this revision Revisions of this file
Links/I2CMasterDecorator.cpp Show annotated file Show diff for this revision Revisions of this file
Links/I2CMasterDecorator.hpp Show annotated file Show diff for this revision Revisions of this file
Links/LoggingI2CMaster.cpp Show annotated file Show diff for this revision Revisions of this file
Links/LoggingI2CMaster.hpp Show annotated file Show diff for this revision Revisions of this file
Links/OneWireMaster.hpp Show annotated file Show diff for this revision Revisions of this file
Links/SerialPort.hpp Show annotated file Show diff for this revision Revisions of this file
Links/Uart.hpp Show annotated file Show diff for this revision Revisions of this file
MaximInterface.vcxproj Show diff for this revision Revisions of this file
MaximInterface.vcxproj.filters Show diff for this revision Revisions of this file
Platforms/Qt/.mbedignore Show annotated file Show diff for this revision Revisions of this file
Platforms/Qt/SerialPort.cpp Show annotated file Show diff for this revision Revisions of this file
Platforms/Qt/SerialPort.hpp Show annotated file Show diff for this revision Revisions of this file
Platforms/Qt/Sleep.cpp Show annotated file Show diff for this revision Revisions of this file
Platforms/Qt/Sleep.hpp Show annotated file Show diff for this revision Revisions of this file
Platforms/dotnet/SerialPort.cpp Show annotated file Show diff for this revision Revisions of this file
Platforms/dotnet/SerialPort.hpp Show annotated file Show diff for this revision Revisions of this file
Platforms/mbed/I2CMaster.cpp Show annotated file Show diff for this revision Revisions of this file
Platforms/mbed/I2CMaster.hpp Show annotated file Show diff for this revision Revisions of this file
Platforms/mbed/Uart.cpp Show annotated file Show diff for this revision Revisions of this file
Platforms/mbed/Uart.hpp Show annotated file Show diff for this revision Revisions of this file
Utilities/Ecc256.hpp Show annotated file Show diff for this revision Revisions of this file
Utilities/system_error.hpp Show annotated file Show diff for this revision Revisions of this file
clr.cmake Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CMakeLists.txt	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,148 @@
+#[[*****************************************************************************
+* 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/DS2480B.cpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Devices/DS2480B.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -562,6 +562,23 @@
   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;
 
@@ -638,23 +655,23 @@
 error_code DS2480B::setComBaud(BaudRate newBaud) {
   switch (newBaud) {
   case Baud115200bps:
-    return uart->setBaud(115200);
+    return uart->setBaudRate(115200);
 
   case Baud57600bps:
-    return uart->setBaud(57600);
+    return uart->setBaudRate(57600);
 
   case Baud19200bps:
-    return uart->setBaud(19200);
+    return uart->setBaudRate(19200);
 
   case Baud9600bps:
   default:
-    return uart->setBaud(9600);
+    return uart->setBaudRate(9600);
   }
 }
 
 error_code DS2480B::breakCom() {
   // Switch to lower baud rate to ensure break is longer than 2 ms.
-  error_code result = uart->setBaud(4800);
+  error_code result = uart->setBaudRate(4800);
   if (result) {
     return result;
   }
--- a/Devices/DS2480B.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Devices/DS2480B.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -44,7 +44,7 @@
 class DS2480B : public OneWireMaster {
 public:
   enum ErrorValue {
-    HardwareError = 1,
+    HardwareError = 1
   };
 
   DS2480B(const Sleep & sleep, Uart & uart) : sleep(&sleep), uart(&uart) {}
@@ -66,6 +66,9 @@
 
   MaximInterface_EXPORT static const error_category & errorCategory();
 
+protected:
+  MaximInterface_EXPORT error_code sendCommand(uint_least8_t command);
+
 private:
   /// Baud rates for DS2480B
   enum BaudRate {
--- a/Devices/DS28C36_DS2476.cpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Devices/DS28C36_DS2476.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -36,10 +36,8 @@
 #include "DS28C36_DS2476.hpp"
 
 using std::copy;
-using std::vector;
 
 namespace MaximInterface {
-
 using namespace Ecc256;
 
 // DS28C36 commands.
@@ -79,20 +77,15 @@
     return make_error_code(InvalidParameterError);
   }
 
-  vector<uint_least8_t> buffer;
-  buffer.reserve(1 + page.size());
-  buffer.push_back(pageNum);
-  buffer.insert(buffer.end(), page.begin(), page.end());
-  error_code result = writeCommand(WriteMemory, &buffer[0], buffer.size());
+  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 = readResponse(buffer);
+    result = readFixedLengthResponse(buffer.data(), 1);
     if (!result) {
-      if (buffer.size() == 1) {
-        result = convertResultByte(buffer[0]);
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      result = convertResultByte(buffer[0]);
     }
   }
   return result;
@@ -103,19 +96,15 @@
     return make_error_code(InvalidParameterError);
   }
 
-  vector<uint_least8_t> buffer;
-  buffer.push_back(pageNum);
-  error_code result = writeCommand(ReadMemory, &buffer[0], buffer.size());
+  const uint_least8_t parameter = pageNum;
+  error_code result = writeCommand(ReadMemory, &parameter, 1);
   if (!result) {
     sleep(readMemoryTimeMs);
-    result = readResponse(buffer);
+    array<uint_least8_t, 1 + Page::csize> response;
+    result = readFixedLengthResponse(response.data(), response.size());
     if (!result) {
-      if (buffer.size() == (1 + page.size())) {
-        result = convertResultByte(buffer[0]);
-        copy(buffer.begin() + 1, buffer.end(), page.begin());
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      result = convertResultByte(response[0]);
+      copy(response.begin() + 1, response.end(), page.begin());
     }
   }
   return result;
@@ -125,10 +114,17 @@
   return writeCommand(WriteBuffer, data, dataSize);
 }
 
-error_code DS28C36::readBuffer(vector<uint_least8_t> & data) {
-  error_code result = writeCommand(ReadBuffer, NULL, 0);
+error_code DS28C36::readBuffer(std::vector<uint_least8_t> & data) {
+  error_code result = writeCommand(ReadBuffer);
   if (!result) {
-    result = readResponse(data);
+    data.resize(80);
+    size_t dataSize = data.size();
+    result = readVariableLengthResponse(&data[0], dataSize);
+    if (result) {
+      data.clear();
+    } else {
+      data.resize(dataSize);
+    }
   }
   return result;
 }
@@ -139,19 +135,13 @@
     return make_error_code(InvalidParameterError);
   }
 
-  vector<uint_least8_t> buffer;
-  buffer.push_back(pageNum);
-  error_code result =
-      writeCommand(ReadPageProtection, &buffer[0], buffer.size());
+  uint_least8_t buffer = pageNum;
+  error_code result = writeCommand(ReadPageProtection, &buffer, 1);
   if (!result) {
     sleep(readMemoryTimeMs);
-    result = readResponse(buffer);
+    result = readFixedLengthResponse(&buffer, 1);
     if (!result) {
-      if (buffer.size() == 1) {
-        protection = buffer[0];
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      protection = buffer;
     }
   }
   return result;
@@ -163,59 +153,44 @@
     return make_error_code(InvalidParameterError);
   }
 
-  vector<uint_least8_t> buffer;
-  buffer.push_back(pageNum);
-  buffer.push_back(static_cast<uint_least8_t>(protection.to_ulong()));
+  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[0], buffer.size());
+      writeCommand(SetPageProtection, buffer.data(), buffer.size());
   if (!result) {
     sleep(writeMemoryTimeMs);
-    result = readResponse(buffer);
+    result = readFixedLengthResponse(buffer.data(), 1);
     if (!result) {
-      if (buffer.size() == 1) {
-        result = convertResultByte(buffer[0]);
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      result = convertResultByte(buffer[0]);
     }
   }
   return result;
 }
 
 error_code DS28C36::decrementCounter() {
-  error_code result = writeCommand(DecrementCounter, NULL, 0);
+  error_code result = writeCommand(DecrementCounter);
   if (!result) {
     sleep(writeMemoryTimeMs);
-    vector<uint_least8_t> buffer;
-    result = readResponse(buffer);
+    uint_least8_t response;
+    result = readFixedLengthResponse(&response, 1);
     if (!result) {
-      if (buffer.size() == 1) {
-        result = convertResultByte(buffer[0]);
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      result = convertResultByte(response);
     }
   }
   return result;
 }
 
-error_code DS28C36::readRng(int numBytes, vector<uint_least8_t> & data) {
-  if ((numBytes < 1) || (numBytes > 64)) {
+error_code DS28C36::readRng(uint_least8_t * data, size_t dataSize) {
+  if ((dataSize < 1) || (dataSize > 64)) {
     return make_error_code(InvalidParameterError);
   }
 
-  data.clear();
-  data.push_back(numBytes - 1);
-  error_code result = writeCommand(ReadRng, &data[0], data.size());
+  data[0] = static_cast<uint_least8_t>(dataSize - 1);
+  error_code result = writeCommand(ReadRng, data, 1);
   if (!result) {
     sleep(sha256ComputationTimeMs);
-    result = readResponse(data);
-    if (!result) {
-      if (data.size() !=
-          static_cast<vector<uint_least8_t>::size_type>(numBytes)) {
-        result = make_error_code(InvalidResponseError);
-      }
-    }
+    result = readFixedLengthResponse(data, dataSize);
   }
   return result;
 }
@@ -226,57 +201,34 @@
     return make_error_code(InvalidParameterError);
   }
 
-  vector<uint_least8_t> buffer;
-  buffer.push_back((secretNum << 6) | pageNum);
-  error_code result =
-      writeCommand(EncryptedReadMemory, &buffer[0], buffer.size());
+  const uint_least8_t parameter = (secretNum << 6) | pageNum;
+  error_code result = writeCommand(EncryptedReadMemory, &parameter, 1);
   if (!result) {
     sleep(readMemoryTimeMs + sha256ComputationTimeMs);
-    result = readResponse(buffer);
+    typedef array<uint_least8_t, 1 + EncryptedPage::size> Response;
+    Response response;
+    result = readFixedLengthResponse(response.data(), response.size());
     if (!result) {
-      if (buffer.size() == (1 + page.challenge.size() + page.data.size())) {
-        result = convertResultByte(buffer[0]);
-        vector<uint_least8_t>::const_iterator begin = buffer.begin() + 1;
-        vector<uint_least8_t>::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());
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      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,
-                                          vector<uint_least8_t> & data) {
+error_code DS28C36::computeAndReadPageAuthentication(int pageNum,
+                                                     AuthType authType) {
   if (pageNum < 0 || pageNum >= memoryPages) {
     return make_error_code(InvalidParameterError);
   }
 
-  data.clear();
-  data.push_back((authType << 5) | pageNum);
-  error_code result =
-      writeCommand(ComputeAndReadPathAuthentication, &data[0], data.size());
-  if (!result) {
-    sleep(readMemoryTimeMs + ((authType < EcdsaWithKeyA)
-                                  ? sha256ComputationTimeMs
-                                  : generateEcdsaSignatureTimeMs));
-    result = readResponse(data);
-    if (!result) {
-      if (data.size() > 1) {
-        result = convertResultByte(data[0]);
-        data.erase(data.begin());
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
-    }
-  }
-  return result;
+  const uint_least8_t parameter = (authType << 5) | pageNum;
+  return writeCommand(ComputeAndReadPathAuthentication, &parameter, 1);
 }
 
 error_code
@@ -296,15 +248,21 @@
   default:
     return make_error_code(InvalidParameterError);
   }
-  vector<uint_least8_t> data;
-  error_code result = computeAndReadPageAuthentication(pageNum, authType, data);
+  error_code result = computeAndReadPageAuthentication(pageNum, authType);
   if (!result) {
-    vector<uint_least8_t>::const_iterator begin = data.begin();
-    vector<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());
+    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;
 }
@@ -326,10 +284,15 @@
   default:
     return make_error_code(InvalidParameterError);
   }
-  vector<uint_least8_t> data;
-  error_code result = computeAndReadPageAuthentication(pageNum, authType, data);
+  error_code result = computeAndReadPageAuthentication(pageNum, authType);
   if (!result) {
-    copy(data.begin(), data.end(), hmac.begin());
+    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;
 }
@@ -341,19 +304,16 @@
     return make_error_code(InvalidParameterError);
   }
 
-  vector<uint_least8_t> buffer;
-  buffer.reserve(1 + page.size());
-  buffer.push_back((secretNum << 6) | pageNum);
-  buffer.insert(buffer.end(), page.begin(), page.end());
+  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[0], buffer.size());
+      writeCommand(AuthenticatedSha2WriteMemory, buffer.data(), buffer.size());
   if (!result) {
     sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs));
-    result = readResponse(buffer);
-    if (buffer.size() == 1) {
+    result = readFixedLengthResponse(buffer.data(), 1);
+    if (!result) {
       result = convertResultByte(buffer[0]);
-    } else {
-      result = make_error_code(InvalidResponseError);
     }
   }
   return result;
@@ -367,19 +327,18 @@
     return make_error_code(InvalidParameterError);
   }
 
-  vector<uint_least8_t> buffer;
-  buffer.push_back((dsecretNum << 6) | (msecretNum << 4) | pageNum);
-  buffer.push_back(writeProtectEnable ? 0x80 : 0x00);
+  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[0], buffer.size());
+      writeCommand(ComputeAndLockSha2Secret, buffer.data(), buffer.size());
   if (!result) {
     sleep(sha256ComputationTimeMs +
           ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs));
-    result = readResponse(buffer);
-    if (buffer.size() == 1) {
+    result = readFixedLengthResponse(buffer.data(), 1);
+    if (!result) {
       result = convertResultByte(buffer[0]);
-    } else {
-      result = make_error_code(InvalidResponseError);
     }
   }
   return result;
@@ -391,23 +350,16 @@
     return make_error_code(InvalidParameterError);
   }
 
-  vector<uint_least8_t> buffer;
-  uint_least8_t parameter = keyNum;
+  uint_least8_t buffer = keyNum;
   if (writeProtectEnable) {
-    parameter |= 0x80;
+    buffer |= 0x80;
   }
-  buffer.push_back(parameter);
-  error_code result =
-      writeCommand(GenerateEcc256KeyPair, &buffer[0], buffer.size());
+  error_code result = writeCommand(GenerateEcc256KeyPair, &buffer, 1);
   if (!result) {
     sleep(generateEccKeyPairTimeMs);
-    result = readResponse(buffer);
+    result = readFixedLengthResponse(&buffer, 1);
     if (!result) {
-      if (buffer.size() == 1) {
-        result = convertResultByte(buffer[0]);
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      result = convertResultByte(buffer);
     }
   }
   return result;
@@ -416,28 +368,28 @@
 error_code DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock,
                                           const uint_least8_t * data,
                                           size_t dataSize) {
-  uint_least8_t parameter = 0;
+  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) {
-    parameter |= 0x40;
+    buffer[0] |= 0x40;
   }
   if (lastBlock) {
-    parameter |= 0x80;
+    buffer[0] |= 0x80;
   }
-  vector<uint_least8_t> buffer;
-  buffer.reserve(1 + dataSize);
-  buffer.push_back(parameter);
-  buffer.insert(buffer.end(), data, data + dataSize);
+  copy(data, data + dataSize, buffer.begin() + 1);
   error_code result =
-      writeCommand(ComputeMultiblockHash, &buffer[0], buffer.size());
+      writeCommand(ComputeMultiblockHash, buffer.data(), dataSize + 1);
   if (!result) {
     sleep(sha256ComputationTimeMs);
-    result = readResponse(buffer);
+    result = readFixedLengthResponse(buffer.data(), 1);
     if (!result) {
-      if (buffer.size() == 1) {
-        result = convertResultByte(buffer[0]);
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      result = convertResultByte(buffer[0]);
     }
   }
   return result;
@@ -446,36 +398,32 @@
 error_code DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType,
                                          const Signature & signature,
                                          PioState pioa, PioState piob) {
-  uint_least8_t parameter = keyNum | (hashType << 2);
+  typedef array<uint_least8_t, 1 + Signature::size> Buffer;
+  Buffer buffer;
+  buffer[0] = keyNum | (hashType << 2);
   if (pioa != Unchanged) {
-    parameter |= 0x20;
+    buffer[0] |= 0x20;
   }
   if (pioa == Conducting) {
-    parameter |= 0x10;
+    buffer[0] |= 0x10;
   }
   if (piob != Unchanged) {
-    parameter |= 0x80;
+    buffer[0] |= 0x80;
   }
   if (piob == Conducting) {
-    parameter |= 0x40;
+    buffer[0] |= 0x40;
   }
-  vector<uint_least8_t> buffer;
-  buffer.reserve(1 + signature.r.size() + signature.s.size());
-  buffer.push_back(parameter);
-  buffer.insert(buffer.end(), signature.r.begin(), signature.r.end());
-  buffer.insert(buffer.end(), signature.s.begin(), signature.s.end());
+  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[0], buffer.size());
+      writeCommand(VerifyEcdsaSignature, buffer.data(), buffer.size());
   if (!result) {
     sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs +
           ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0));
-    result = readResponse(buffer);
+    result = readFixedLengthResponse(buffer.data(), 1);
     if (!result) {
-      if (buffer.size() == 1) {
-        result = convertResultByte(buffer[0]);
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      result = convertResultByte(buffer[0]);
     }
   }
   return result;
@@ -489,29 +437,25 @@
     return make_error_code(InvalidParameterError);
   }
 
-  uint_least8_t parameter = (csOffset << 3) | (keyNum << 2);
+  typedef array<uint_least8_t, 1 + Signature::size> Buffer;
+  Buffer buffer;
+  buffer[0] = (csOffset << 3) | (keyNum << 2);
   if (ecdh) {
-    parameter |= 0x02;
+    buffer[0] |= 0x02;
   }
   if (authWrites) {
-    parameter |= 0x01;
+    buffer[0] |= 0x01;
   }
-  vector<uint_least8_t> buffer;
-  buffer.reserve(1 + signature.r.size() + signature.s.size());
-  buffer.push_back(parameter);
-  buffer.insert(buffer.end(), signature.r.begin(), signature.r.end());
-  buffer.insert(buffer.end(), signature.s.begin(), signature.s.end());
+  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[0], buffer.size());
+      writeCommand(AuthenticateEcdsaPublicKey, buffer.data(), buffer.size());
   if (!result) {
     sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs);
-    result = readResponse(buffer);
+    result = readFixedLengthResponse(buffer.data(), 1);
     if (!result) {
-      if (buffer.size() == 1) {
-        result = convertResultByte(buffer[0]);
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      result = convertResultByte(buffer[0]);
     }
   }
   return result;
@@ -523,22 +467,17 @@
     return make_error_code(InvalidParameterError);
   }
 
-  vector<uint_least8_t> buffer;
-  buffer.reserve(1 + page.size());
-  buffer.push_back(pageNum);
-  buffer.insert(buffer.end(), page.begin(), page.end());
+  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[0], buffer.size());
+      writeCommand(AuthenticatedEcdsaWriteMemory, buffer.data(), buffer.size());
   if (!result) {
     sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs +
           sha256ComputationTimeMs);
-    result = readResponse(buffer);
+    result = readFixedLengthResponse(buffer.data(), 1);
     if (!result) {
-      if (buffer.size() == 1) {
-        result = convertResultByte(buffer[0]);
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      result = convertResultByte(buffer[0]);
     }
   }
   return result;
@@ -573,7 +512,8 @@
   return result;
 }
 
-error_code DS28C36::readResponse(vector<uint_least8_t> & response) {
+error_code DS28C36::readVariableLengthResponse(uint_least8_t * response,
+                                               size_t & responseSize) {
   error_code result = master->start(address_ | 1);
   if (result) {
     master->stop();
@@ -585,16 +525,32 @@
     master->stop();
     return result;
   }
-  response.resize(length);
-  result = master->readBlock(I2CMaster::Nack, &response[0], response.size());
-  if (result) {
+  if (length > responseSize) {
     master->stop();
-    return result;
+    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,
@@ -659,22 +615,6 @@
   return result;
 }
 
-error_code readRng(DS28C36 & ds28c36, uint_least8_t * data, size_t dataSize) {
-  error_code result;
-  vector<uint_least8_t> buffer;
-  while (dataSize > 0) {
-    result = ds28c36.readRng(static_cast<int>(std::min<size_t>(dataSize, 64)),
-                             buffer);
-    if (result) {
-      break;
-    }
-    copy(buffer.begin(), buffer.end(), data);
-    data += buffer.size();
-    dataSize -= buffer.size();
-  }
-  return result;
-}
-
 error_code computeMultiblockHash(DS28C36 & ds28c36, const uint_least8_t * data,
                                  const size_t dataSize) {
   error_code result;
@@ -726,67 +666,53 @@
 };
 
 error_code DS2476::generateEcdsaSignature(KeyNum keyNum,
-                                          Ecc256::Signature & signature) {
+                                          Signature & signature) {
   if (keyNum == KeyNumS) {
     return make_error_code(InvalidParameterError);
   }
 
-  vector<uint_least8_t> buffer;
-  buffer.push_back(keyNum);
-  error_code result =
-      writeCommand(GenerateEcdsaSignature, &buffer[0], buffer.size());
+  const uint_least8_t parameter = keyNum;
+  error_code result = writeCommand(GenerateEcdsaSignature, &parameter, 1);
   if (!result) {
     sleep(generateEcdsaSignatureTimeMs);
-    result = readResponse(buffer);
+    typedef array<uint_least8_t, 1 + Signature::size> Response;
+    Response response;
+    result = readFixedLengthResponse(response.data(), response.size());
     if (!result) {
-      if (buffer.size() == (1 + signature.r.size() + signature.s.size())) {
-        result = convertResultByte(buffer[0]);
-        vector<uint_least8_t>::const_iterator begin = buffer.begin() + 1;
-        vector<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());
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      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) {
-  vector<uint_least8_t> buffer;
-  buffer.push_back(msecretNum << 4);
-  error_code result =
-      writeCommand(ComputeSha2UniqueSecret, &buffer[0], buffer.size());
+  uint_least8_t buffer = msecretNum << 4;
+  error_code result = writeCommand(ComputeSha2UniqueSecret, &buffer, 1);
   if (!result) {
     sleep(sha256ComputationTimeMs);
-    result = readResponse(buffer);
+    result = readFixedLengthResponse(&buffer, 1);
     if (!result) {
-      if (buffer.size() == 1) {
-        convertResultByte(buffer[0]);
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      convertResultByte(buffer);
     }
   }
   return result;
 }
 
 error_code DS2476::computeSha2Hmac(Sha256::Hash & hmac) {
-  error_code result = writeCommand(ComputeSha2Hmac, NULL, 0);
+  error_code result = writeCommand(ComputeSha2Hmac);
   if (!result) {
     sleep(sha256ComputationTimeMs);
-    vector<uint_least8_t> buffer;
-    result = readResponse(buffer);
+    array<uint_least8_t, 1 + Sha256::Hash::csize> response;
+    result = readFixedLengthResponse(response.data(), response.size());
     if (!result) {
-      if (buffer.size() == (1 + hmac.size())) {
-        result = convertResultByte(buffer[0]);
-        copy(buffer.begin() + 1, buffer.end(), hmac.begin());
-      } else {
-        result = make_error_code(InvalidResponseError);
-      }
+      result = convertResultByte(response[0]);
+      copy(response.begin() + 1, response.end(), hmac.begin());
     }
   }
   return result;
--- a/Devices/DS28C36_DS2476.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Devices/DS28C36_DS2476.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -33,6 +33,8 @@
 #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>
@@ -133,7 +135,12 @@
 
   /// Holds an encrypted device memory page.
   struct EncryptedPage {
-    array<uint_least8_t, 8> challenge;
+    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;
   };
 
@@ -185,10 +192,10 @@
   MaximInterface_EXPORT error_code decrementCounter();
 
   /// Read a block of random data from the RNG.
-  /// @param numBytes Number of bytes to read from 1 to 64.
-  /// @param[out] data Random data from RNG.
-  MaximInterface_EXPORT error_code readRng(int numBytes,
-                                           std::vector<uint_least8_t> & data);
+  /// @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.
@@ -294,7 +301,16 @@
   error_code writeCommand(uint_least8_t command,
                           const uint_least8_t * parameters,
                           size_t parametersSize);
-  error_code readResponse(std::vector<uint_least8_t> & response);
+
+  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); }
 
@@ -312,13 +328,7 @@
   I2CMaster * master;
   uint_least8_t address_;
 
-  /// Compute any type of authentication on page.
-  /// @param pageNum Number of page to authenticate.
-  /// @param authType Method to use to compute authentication.
-  /// @param[out] data Raw computed page authentication.
-  error_code
-  computeAndReadPageAuthentication(int pageNum, AuthType authType,
-                                   std::vector<uint_least8_t> & data);
+  error_code computeAndReadPageAuthentication(int pageNum, AuthType authType);
 };
 
 /// Read the device ROM ID and MAN ID using the Read Memory command on the
@@ -331,12 +341,6 @@
                                                    RomId * romId,
                                                    ManId * manId);
 
-/// Read arbitrary length random data with successive Read RNG commands.
-/// @param[out] data Buffer to receive random data.
-/// @param dataSize Size of data buffer.
-MaximInterface_EXPORT error_code readRng(DS28C36 & ds28c36,
-                                         uint_least8_t * data, size_t dataSize);
-
 /// Hash arbitrary length data with successive Compute Multiblock Hash commands.
 /// @param data Data to hash.
 /// @param dataSize Size of data to hash.
--- a/Devices/DS9400.cpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Devices/DS9400.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -34,6 +34,15 @@
 
 namespace MaximInterface {
 
+error_code DS9400::waitAwake() {
+  error_code result;
+  uint_least8_t data;
+  do {
+    result = uart->readByte(data);
+  } while (!result && data != 0xA5);
+  return result;
+}
+
 error_code DS9400::start() { return uart->writeByte('S'); }
 
 error_code DS9400::start(uint_least8_t address) {
@@ -72,4 +81,9 @@
   return result;
 }
 
+error_code DS9400::configure(uint_least8_t config) {
+  const uint_least8_t packet[] = {'C', config};
+  return uart->writeBlock(packet, sizeof(packet) / sizeof(packet[0]));
+}
+
 } // namespace MaximInterface
\ No newline at end of file
--- a/Devices/DS9400.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Devices/DS9400.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -45,6 +45,8 @@
 
   void setUart(Uart & uart) { this->uart = &uart; }
 
+  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();
@@ -52,6 +54,9 @@
   MaximInterface_EXPORT virtual error_code readByte(AckStatus status,
                                                     uint_least8_t & data);
 
+protected:
+  MaximInterface_EXPORT error_code configure(uint_least8_t config);
+
 private:
   Uart * uart;
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Devices/DS9481P_300.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,263 @@
+/*******************************************************************************
+* 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/Utilities/Error.hpp>
+#include "DS9481P_300.hpp"
+
+namespace MaximInterface {
+
+DS9481P_300::DS9481P_300(const Sleep & sleep, SerialPort & serialPort)
+    : serialPort(&serialPort), currentBus(OneWire), ds2480b(sleep, serialPort),
+      oneWireMaster_(*this), ds9400(serialPort), i2cMaster_(*this) {}
+
+error_code DS9481P_300::connect(const std::string & portName) {
+  error_code result = serialPort->connect(portName);
+  if (!result) {
+    result = selectOneWire();
+    if (result) {
+      serialPort->disconnect();
+    } else {
+      currentBus = OneWire;
+    }
+  }
+  return result;
+}
+
+error_code DS9481P_300::disconnect() {
+  return serialPort->disconnect();
+}
+
+bool DS9481P_300::connected() const {
+  return serialPort->connected();
+}
+
+std::string DS9481P_300::portName() const {
+  return serialPort->portName();
+}
+
+error_code DS9481P_300::selectOneWire() {
+  // Escape DS9400 mode.
+  error_code result = ds9400.escape();
+  if (!result) {
+    result = ds2480b.initialize();
+  }
+  return result;
+}
+
+error_code DS9481P_300::selectBus(Bus newBus) {
+  error_code result;
+  if (currentBus != newBus) {
+    switch (currentBus) {
+    case OneWire: // Next bus I2C.
+      // Escape DS2480 Mode.
+      result = ds2480b.escape();
+      if (!result) {
+        // Wait for awake notification.
+        result = ds9400.waitAwake();
+      }
+      break;
+
+    case I2C: // Next bus OneWire.
+      result = selectOneWire();
+      break;
+    }
+    if (!result) {
+      currentBus = newBus;
+    }
+  }
+  return result;
+}
+
+error_code DS9481P_300::OneWireMasterImpl::reset() {
+  error_code result = parent->selectBus(OneWire);
+  if (!result) {
+    result = OneWireMasterDecorator::reset();
+  }
+  return result;
+}
+
+error_code DS9481P_300::OneWireMasterImpl::touchBitSetLevel(bool & sendRecvBit,
+                                                            Level afterLevel) {
+  error_code result = parent->selectBus(OneWire);
+  if (!result) {
+    result = OneWireMasterDecorator::touchBitSetLevel(sendRecvBit, afterLevel);
+  }
+  return result;
+}
+
+error_code
+DS9481P_300::OneWireMasterImpl::writeByteSetLevel(uint_least8_t sendByte,
+                                                  Level afterLevel) {
+  error_code result = parent->selectBus(OneWire);
+  if (!result) {
+    result = OneWireMasterDecorator::writeByteSetLevel(sendByte, afterLevel);
+  }
+  return result;
+}
+
+error_code
+DS9481P_300::OneWireMasterImpl::readByteSetLevel(uint_least8_t & recvByte,
+                                                 Level afterLevel) {
+  error_code result = parent->selectBus(OneWire);
+  if (!result) {
+    result = OneWireMasterDecorator::readByteSetLevel(recvByte, afterLevel);
+  }
+  return result;
+}
+
+error_code
+DS9481P_300::OneWireMasterImpl::writeBlock(const uint_least8_t * sendBuf,
+                                           size_t sendLen) {
+  error_code result = parent->selectBus(OneWire);
+  if (!result) {
+    result = OneWireMasterDecorator::writeBlock(sendBuf, sendLen);
+  }
+  return result;
+}
+
+error_code DS9481P_300::OneWireMasterImpl::readBlock(uint_least8_t * recvBuf,
+                                                     size_t recvLen) {
+  error_code result = parent->selectBus(OneWire);
+  if (!result) {
+    result = OneWireMasterDecorator::readBlock(recvBuf, recvLen);
+  }
+  return result;
+}
+
+error_code DS9481P_300::OneWireMasterImpl::setSpeed(Speed newSpeed) {
+  error_code result = parent->selectBus(OneWire);
+  if (!result) {
+    result = OneWireMasterDecorator::setSpeed(newSpeed);
+  }
+  return result;
+}
+
+error_code DS9481P_300::OneWireMasterImpl::setLevel(Level newLevel) {
+  error_code result = parent->selectBus(OneWire);
+  if (!result) {
+    result = OneWireMasterDecorator::setLevel(newLevel);
+  }
+  return result;
+}
+
+error_code DS9481P_300::OneWireMasterImpl::triplet(TripletData & data) {
+  error_code result = parent->selectBus(OneWire);
+  if (!result) {
+    result = OneWireMasterDecorator::triplet(data);
+  }
+  return result;
+}
+
+error_code DS9481P_300::I2CMasterImpl::start(uint_least8_t address) {
+  error_code result = parent->selectBus(I2C);
+  if (!result) {
+    result = I2CMasterDecorator::start(address);
+  }
+  return result;
+}
+
+error_code DS9481P_300::I2CMasterImpl::stop() {
+  error_code result = parent->selectBus(I2C);
+  if (!result) {
+    result = I2CMasterDecorator::stop();
+  }
+  return result;
+}
+
+error_code DS9481P_300::I2CMasterImpl::writeByte(uint_least8_t data) {
+  error_code result = parent->selectBus(I2C);
+  if (!result) {
+    result = I2CMasterDecorator::writeByte(data);
+  }
+  return result;
+}
+
+error_code DS9481P_300::I2CMasterImpl::writeBlock(const uint_least8_t * data,
+                                                  size_t dataLen) {
+  error_code result = parent->selectBus(I2C);
+  if (!result) {
+    result = I2CMasterDecorator::writeBlock(data, dataLen);
+  }
+  return result;
+}
+
+error_code DS9481P_300::I2CMasterImpl::writePacketImpl(
+    uint_least8_t address, const uint_least8_t * data, size_t dataLen,
+    bool sendStop) {
+  error_code result = parent->selectBus(I2C);
+  if (!result) {
+    result = I2CMasterDecorator::writePacketImpl(address, data, dataLen,
+                                                 sendStop);
+  }
+  return result;
+}
+
+error_code DS9481P_300::I2CMasterImpl::readByte(AckStatus status,
+                                                uint_least8_t & data) {
+  error_code result = parent->selectBus(I2C);
+  if (!result) {
+    result = I2CMasterDecorator::readByte(status, data);
+  }
+  return result;
+}
+
+error_code DS9481P_300::I2CMasterImpl::readBlock(AckStatus status,
+                                                 uint_least8_t * data,
+                                                 size_t dataLen) {
+  error_code result = parent->selectBus(I2C);
+  if (!result) {
+    result = I2CMasterDecorator::readBlock(status, data, dataLen);
+  }
+  return result;
+}
+
+error_code DS9481P_300::I2CMasterImpl::readPacketImpl(uint_least8_t address,
+                                                      uint_least8_t * data,
+                                                      size_t dataLen,
+                                                      bool sendStop) {
+  error_code result = parent->selectBus(I2C);
+  if (!result) {
+    result = I2CMasterDecorator::readPacketImpl(address, data, dataLen,
+                                                sendStop);
+  }
+  return result;
+}
+
+error_code DS9481P_300::DS2480BWithEscape::escape() {
+  return sendCommand(0xE5);
+}
+
+error_code DS9481P_300::DS9400WithEscape::escape() {
+  return configure('O');
+}
+
+} // namespace MaximInterface
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Devices/DS9481P_300.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,151 @@
+/*******************************************************************************
+* 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_DS9481P_300
+#define MaximInterface_DS9481P_300
+
+#include <MaximInterface/Devices/DS2480B.hpp>
+#include <MaximInterface/Devices/DS9400.hpp>
+#include <MaximInterface/Links/I2CMasterDecorator.hpp>
+#include <MaximInterface/Links/OneWireMasterDecorator.hpp>
+#include <MaximInterface/Links/SerialPort.hpp>
+#include <MaximInterface/Links/Sleep.hpp>
+#include <MaximInterface/Utilities/Export.h>
+
+namespace MaximInterface {
+
+/// DS9481P-300 USB to 1-Wire and I2C adapter.
+class DS9481P_300 {
+public:
+  MaximInterface_EXPORT DS9481P_300(const Sleep & sleep,
+                                    SerialPort & serialPort);
+
+  void setSleep(const Sleep & sleep) { ds2480b.setSleep(sleep); }
+  void setSerialPort(SerialPort & serialPort) {
+    this->serialPort = &serialPort;
+    ds2480b.setUart(serialPort);
+    ds9400.setUart(serialPort);
+  }
+
+  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_; }
+
+private:
+  class OneWireMasterImpl : public OneWireMasterDecorator {
+  public:
+    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);
+
+  private:
+    DS9481P_300 * parent;
+  };
+
+  class I2CMasterImpl : public I2CMasterDecorator {
+  public:
+    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);
+
+  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);
+
+  private:
+    DS9481P_300 * parent;
+  };
+
+  class DS2480BWithEscape : public DS2480B {
+  public:
+    DS2480BWithEscape(const Sleep & sleep, Uart & uart)
+      : DS2480B(sleep, uart) {}
+
+    error_code escape();
+  };
+
+  class DS9400WithEscape : public DS9400 {
+  public:
+    explicit DS9400WithEscape(Uart & uart) : DS9400(uart) {}
+
+    error_code escape();
+  };
+
+  enum Bus { OneWire, I2C };
+
+  SerialPort * serialPort;
+  Bus currentBus;
+  DS2480BWithEscape ds2480b;
+  OneWireMasterImpl oneWireMaster_;
+  DS9400WithEscape ds9400;
+  I2CMasterImpl i2cMaster_;
+
+  error_code selectOneWire();
+  error_code selectBus(Bus newBus);
+
+  friend class OneWireMasterImpl;
+  friend class I2CMasterImpl;
+};
+
+} // namespace MaximInterface
+
+#endif
\ No newline at end of file
--- a/Links/I2CMaster.cpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Links/I2CMaster.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -43,9 +43,9 @@
   return result;
 }
 
-error_code I2CMaster::writePacket(uint_least8_t address,
-                                  const uint_least8_t * data, size_t dataLen,
-                                  bool sendStop) {
+error_code I2CMaster::writePacketImpl(uint_least8_t address,
+                                      const uint_least8_t * data,
+                                      size_t dataLen, bool sendStop) {
   error_code result = start(address & 0xFE);
   if (!result) {
     result = writeBlock(data, dataLen);
@@ -68,8 +68,9 @@
   return result;
 }
 
-error_code I2CMaster::readPacket(uint_least8_t address, uint_least8_t * data,
-                                 size_t dataLen, bool sendStop) {
+error_code I2CMaster::readPacketImpl(uint_least8_t address,
+                                     uint_least8_t * data, size_t dataLen,
+                                     bool sendStop) {
   error_code result = start(address | 0x01);
   if (!result) {
     result = readBlock(Nack, data, dataLen);
--- a/Links/I2CMaster.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Links/I2CMaster.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -40,41 +40,74 @@
 
 namespace MaximInterface {
 
+/// I2C master interface.
 class I2CMaster {
 public:
   enum ErrorValue {
     NackError = 1 ///< Transaction stopped due to a NACK from the slave device.
   };
 
-  enum AckStatus { Ack = 1, Nack = 0 };
+  enum AckStatus { Nack, Ack };
 
   virtual ~I2CMaster() {}
 
+  /// Send start condition and address on the bus.
+  /// @param address Address with R/W bit.
   virtual error_code start(uint_least8_t address) = 0;
+  
+  /// Send stop condition on the bus.
   virtual error_code stop() = 0;
+  
+  /// Write data byte to the bus.
   virtual error_code writeByte(uint_least8_t data) = 0;
+  
+  /// Write data block to the bus.
   MaximInterface_EXPORT virtual error_code
   writeBlock(const uint_least8_t * data, size_t dataLen);
-  MaximInterface_EXPORT virtual error_code
-  writePacket(uint_least8_t address, const uint_least8_t * data, size_t dataLen,
-              bool sendStop);
+  
+  /// Perform a complete write transaction on the bus with optional stop
+  /// condition.
+  /// @param address Address in 8-bit format.
+  /// @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) {
-    return writePacket(address, data, dataLen, true);
+                         size_t dataLen, bool sendStop = true) {
+    return writePacketImpl(address, data, dataLen, sendStop);
   }
+  
+  /// 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.
+  /// @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);
-  MaximInterface_EXPORT virtual error_code readPacket(uint_least8_t address,
-                                                      uint_least8_t * data,
-                                                      size_t dataLen,
-                                                      bool sendStop);
+  
+  /// Perform a complete read transaction on the bus with optional stop
+  /// condition.
+  /// @param address Address in 8-bit format.
+  /// @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) {
-    return readPacket(address, data, dataLen, true);
+                        size_t dataLen, bool sendStop = true) {
+    return readPacketImpl(address, data, dataLen, 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);
+ 
+  MaximInterface_EXPORT virtual error_code readPacketImpl(uint_least8_t address,
+                                                          uint_least8_t * data,
+                                                          size_t dataLen,
+                                                          bool sendStop);
 };
 
 inline error_code make_error_code(I2CMaster::ErrorValue e) {
--- a/Links/I2CMasterDecorator.cpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Links/I2CMasterDecorator.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -49,9 +49,9 @@
   return i2c->writeBlock(data, dataLen);
 }
 
-error_code I2CMasterDecorator::writePacket(uint_least8_t address,
-                                           const uint_least8_t * data,
-                                           size_t dataLen, bool sendStop) {
+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);
 }
 
@@ -65,9 +65,9 @@
   return i2c->readBlock(status, data, dataLen);
 }
 
-error_code I2CMasterDecorator::readPacket(uint_least8_t address,
-                                          uint_least8_t * data, size_t dataLen,
-                                          bool sendStop) {
+error_code I2CMasterDecorator::readPacketImpl(uint_least8_t address,
+                                              uint_least8_t * data,
+                                              size_t dataLen, bool sendStop) {
   return i2c->readPacket(address, data, dataLen, sendStop);
 }
 
--- a/Links/I2CMasterDecorator.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Links/I2CMasterDecorator.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -50,17 +50,19 @@
   MaximInterface_EXPORT virtual error_code writeByte(uint_least8_t data);
   MaximInterface_EXPORT virtual error_code
   writeBlock(const uint_least8_t * data, size_t dataLen);
-  MaximInterface_EXPORT virtual error_code
-  writePacket(uint_least8_t address, const uint_least8_t * data, size_t dataLen,
-              bool sendStop);
   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);
-  MaximInterface_EXPORT virtual error_code readPacket(uint_least8_t address,
-                                                      uint_least8_t * data,
-                                                      size_t dataLen,
-                                                      bool sendStop);
+
+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);
 
 private:
   I2CMaster * i2c;
--- a/Links/LoggingI2CMaster.cpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Links/LoggingI2CMaster.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -87,13 +87,13 @@
   return I2CMasterDecorator::writeBlock(data, dataLen);
 }
 
-error_code LoggingI2CMaster::writePacket(uint_least8_t address,
-                                         const uint_least8_t * data,
-                                         size_t dataLen, bool sendStop) {
+error_code LoggingI2CMaster::writePacketImpl(uint_least8_t address,
+                                             const uint_least8_t * data,
+                                             size_t dataLen, bool sendStop) {
   messageBuilder.append(startString);
   messageBuilder.append(formatDataString(&address, 1, false));
   error_code result =
-      I2CMasterDecorator::writePacket(address, data, dataLen, sendStop);
+      I2CMasterDecorator::writePacketImpl(address, data, dataLen, sendStop);
   if (!result) {
     messageBuilder.append(formatDataString(data, dataLen, false));
   }
@@ -121,13 +121,13 @@
   return result;
 }
 
-error_code LoggingI2CMaster::readPacket(uint_least8_t address,
-                                        uint_least8_t * data, size_t dataLen,
-                                        bool sendStop) {
+error_code LoggingI2CMaster::readPacketImpl(uint_least8_t address,
+                                            uint_least8_t * data,
+                                            size_t dataLen, bool sendStop) {
   messageBuilder.append(startString);
   messageBuilder.append(formatDataString(&address, 1, false));
   error_code result =
-      I2CMasterDecorator::readPacket(address, data, dataLen, sendStop);
+      I2CMasterDecorator::readPacketImpl(address, data, dataLen, sendStop);
   if (!result) {
     messageBuilder.append(formatDataString(data, dataLen, true));
   }
--- a/Links/LoggingI2CMaster.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Links/LoggingI2CMaster.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -55,17 +55,19 @@
   MaximInterface_EXPORT virtual error_code writeByte(uint_least8_t data);
   MaximInterface_EXPORT virtual error_code
   writeBlock(const uint_least8_t * data, size_t dataLen);
-  MaximInterface_EXPORT virtual error_code
-  writePacket(uint_least8_t address, const uint_least8_t * data, size_t dataLen,
-              bool sendStop);
   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);
-  MaximInterface_EXPORT virtual error_code readPacket(uint_least8_t address,
-                                                      uint_least8_t * data,
-                                                      size_t dataLen,
-                                                      bool sendStop);
+
+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);
 
 private:
   void tryWriteMessage();
--- a/Links/OneWireMaster.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Links/OneWireMaster.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -40,7 +40,7 @@
 
 namespace MaximInterface {
 
-/// Base class for all 1-Wire Masters.
+/// 1-Wire master interface.
 class OneWireMaster {
 public:
   /// Speed of the 1-Wire bus.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Links/SerialPort.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,59 @@
+/*******************************************************************************
+* 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_SerialPort
+#define MaximInterface_SerialPort
+
+#include <string>
+#include "Uart.hpp"
+
+namespace MaximInterface {
+
+class SerialPort : public Uart {
+public:
+  /// Connect a specified COM port.
+  virtual error_code connect(const std::string & portName) = 0;
+  
+  /// Disconnect from the current port.
+  virtual error_code disconnect() = 0;
+  
+  /// Check if currently connected to a port.
+  /// @returns True if connected.
+  virtual bool connected() const = 0;
+
+  /// Get the currently connected port name.
+  virtual std::string portName() const = 0;
+};
+
+}
+
+#endif
\ No newline at end of file
--- a/Links/Uart.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Links/Uart.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -41,6 +41,7 @@
 
 namespace MaximInterface {
 
+/// Universal asynchronous receiver-transmitter interface.
 class Uart {
 public:
   enum ErrorValue {
@@ -50,13 +51,31 @@
 
   virtual ~Uart() {}
 
-  virtual error_code setBaud(int_least32_t baud) = 0;
+  /// Set the baud rate of the port in Hz.
+  virtual error_code setBaudRate(int_least32_t baudRate) = 0;
+  
+  /// Generate a break condition on the port for a small amount of time.
   virtual error_code sendBreak() = 0;
+  
+  /// Clear all received data that was buffered.
   virtual error_code clearReadBuffer() = 0;
+  
+  /// Writes a byte of data to the port.
   virtual error_code writeByte(uint_least8_t data) = 0;
+  
+  /// Writes a block of data to the port.
   MaximInterface_EXPORT virtual error_code
   writeBlock(const uint_least8_t * data, size_t dataLen);
+  
+  /// 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;
+  
+  /// 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);
 
--- a/MaximInterface.vcxproj	Mon Nov 06 17:46:41 2017 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,254 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{7E1C5898-64B8-422F-8030-F8D2EFB5B0CB}</ProjectGuid>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <Keyword>ManagedCProj</Keyword>
-    <RootNamespace>MaximInterface</RootNamespace>
-    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v140</PlatformToolset>
-    <CLRSupport>true</CLRSupport>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v140</PlatformToolset>
-    <CLRSupport>true</CLRSupport>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v140</PlatformToolset>
-    <CLRSupport>true</CLRSupport>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v140</PlatformToolset>
-    <CLRSupport>true</CLRSupport>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="Shared">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <LinkIncremental>true</LinkIncremental>
-    <IncludePath>$(ProjectDir)\..;$(IncludePath)</IncludePath>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <LinkIncremental>true</LinkIncremental>
-    <IncludePath>$(ProjectDir)\..;$(IncludePath)</IncludePath>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <LinkIncremental>false</LinkIncremental>
-    <IncludePath>$(ProjectDir)\..;$(IncludePath)</IncludePath>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <LinkIncremental>false</LinkIncremental>
-    <IncludePath>$(ProjectDir)\..;$(IncludePath)</IncludePath>
-  </PropertyGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>NOMINMAX;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-    </ClCompile>
-    <Link>
-      <AdditionalDependencies />
-    </Link>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>NOMINMAX;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-    </ClCompile>
-    <Link>
-      <AdditionalDependencies />
-    </Link>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <ClCompile>
-      <WarningLevel>Level3</WarningLevel>
-      <PreprocessorDefinitions>NOMINMAX;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-    </ClCompile>
-    <Link>
-      <AdditionalDependencies />
-    </Link>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <WarningLevel>Level3</WarningLevel>
-      <PreprocessorDefinitions>NOMINMAX;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-    </ClCompile>
-    <Link>
-      <AdditionalDependencies />
-    </Link>
-  </ItemDefinitionGroup>
-  <ItemGroup>
-    <Reference Include="OneWireLinkLayer">
-      <HintPath>Platforms\dotnet\OneWireLinkLayer\OneWireLinkLayer.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="Devices\DS18B20.cpp" />
-    <ClCompile Include="Devices\DS1920.cpp" />
-    <ClCompile Include="Devices\DS2413.cpp" />
-    <ClCompile Include="Devices\DS2431.cpp" />
-    <ClCompile Include="Devices\DS2465.cpp" />
-    <ClCompile Include="Devices\DS2480B.cpp" />
-    <ClCompile Include="Devices\DS2482_DS2484.cpp" />
-    <ClCompile Include="Devices\DS28C36_DS2476.cpp" />
-    <ClCompile Include="Devices\DS28E15_22_25.cpp" />
-    <ClCompile Include="Devices\DS28E17.cpp" />
-    <ClCompile Include="Devices\DS28E38.cpp" />
-    <ClCompile Include="Devices\DS9400.cpp" />
-    <ClCompile Include="Links\I2CMaster.cpp" />
-    <ClCompile Include="Links\I2CMasterDecorator.cpp" />
-    <ClCompile Include="Links\LoggingI2CMaster.cpp" />
-    <ClCompile Include="Links\LoggingOneWireMaster.cpp" />
-    <ClCompile Include="Links\OneWireMaster.cpp" />
-    <ClCompile Include="Links\OneWireMasterDecorator.cpp" />
-    <ClCompile Include="Links\RomCommands.cpp" />
-    <ClCompile Include="Links\SelectRom.cpp" />
-    <ClCompile Include="Links\LoggingSleep.cpp" />
-    <ClCompile Include="Links\SleepDecorator.cpp" />
-    <ClCompile Include="Links\Uart.cpp" />
-    <ClCompile Include="Platforms\dotnet\DS9481P_300.cpp">
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)dotnet\</ObjectFileName>
-    </ClCompile>
-    <ClCompile Include="Platforms\dotnet\OneWireLinkLayerMaster.cpp">
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)dotnet\</ObjectFileName>
-    </ClCompile>
-    <ClCompile Include="Platforms\dotnet\Sleep.cpp">
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)\dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)\dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)\dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)\dotnet\</ObjectFileName>
-    </ClCompile>
-    <ClCompile Include="Platforms\dotnet\Uart.cpp">
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)\dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)\dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)\dotnet\</ObjectFileName>
-      <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)\dotnet\</ObjectFileName>
-    </ClCompile>
-    <ClCompile Include="Utilities\crc.cpp" />
-    <ClCompile Include="Utilities\Ecc256.cpp" />
-    <ClCompile Include="Utilities\Error.cpp" />
-    <ClCompile Include="Utilities\HexConversions.cpp" />
-    <ClCompile Include="Utilities\system_error.cpp" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="Devices\DS18B20.hpp" />
-    <ClInclude Include="Devices\DS1920.hpp" />
-    <ClInclude Include="Devices\DS2413.hpp" />
-    <ClInclude Include="Devices\DS2431.hpp" />
-    <ClInclude Include="Devices\DS2465.hpp" />
-    <ClInclude Include="Devices\DS2480B.hpp" />
-    <ClInclude Include="Devices\DS2482_DS2484.hpp" />
-    <ClInclude Include="Devices\DS28C36_DS2476.hpp" />
-    <ClInclude Include="Devices\DS28E15_22_25.hpp" />
-    <ClInclude Include="Devices\DS28E17.hpp" />
-    <ClInclude Include="Devices\DS28E38.hpp" />
-    <ClInclude Include="Devices\DS9400.hpp" />
-    <ClInclude Include="Links\I2CMaster.hpp" />
-    <ClInclude Include="Links\I2CMasterDecorator.hpp" />
-    <ClInclude Include="Links\LoggingI2CMaster.hpp" />
-    <ClInclude Include="Links\LoggingOneWireMaster.hpp" />
-    <ClInclude Include="Links\OneWireMaster.hpp" />
-    <ClInclude Include="Links\OneWireMasterDecorator.hpp" />
-    <ClInclude Include="Links\RomCommands.hpp" />
-    <ClInclude Include="Links\SelectRom.hpp" />
-    <ClInclude Include="Links\LoggingSleep.hpp" />
-    <ClInclude Include="Links\Sleep.hpp" />
-    <ClInclude Include="Links\SleepDecorator.hpp" />
-    <ClInclude Include="Links\Uart.hpp" />
-    <ClInclude Include="Platforms\dotnet\ChangeSizeType.hpp" />
-    <ClInclude Include="Platforms\dotnet\DelegateWrapper.hpp" />
-    <ClInclude Include="Platforms\dotnet\DS9481P_300.hpp" />
-    <ClInclude Include="Platforms\dotnet\MoveOnly.hpp" />
-    <ClInclude Include="Platforms\dotnet\OneWireLinkLayerMaster.hpp" />
-    <ClInclude Include="Platforms\dotnet\Sleep.hpp" />
-    <ClInclude Include="Platforms\dotnet\Uart.hpp" />
-    <ClInclude Include="Utilities\array.hpp" />
-    <ClInclude Include="Utilities\crc.hpp" />
-    <ClInclude Include="Utilities\Ecc256.hpp" />
-    <ClInclude Include="Utilities\Error.hpp" />
-    <ClInclude Include="Utilities\Export.h" />
-    <ClInclude Include="Utilities\FlagSet.hpp" />
-    <ClInclude Include="Utilities\Function.hpp" />
-    <ClInclude Include="Utilities\HexConversions.hpp" />
-    <ClInclude Include="Utilities\ManId.hpp" />
-    <ClInclude Include="Utilities\RomId.hpp" />
-    <ClInclude Include="Utilities\Segment.hpp" />
-    <ClInclude Include="Utilities\Sha256.hpp" />
-    <ClInclude Include="Utilities\system_error.hpp" />
-    <ClInclude Include="Utilities\type_traits.hpp" />
-    <ClInclude Include="Utilities\Uncopyable.hpp" />
-    <ClInclude Include="Utilities\WriteMessage.hpp" />
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
-  <Target Name="CopyOneWireLinkLayerDependenciesToOutDir" AfterTargets="Link">
-    <ItemGroup Condition="'$(Platform)'=='Win32'">
-      <Files Include="Platforms\dotnet\OneWireLinkLayer\IB*32.dll" />
-    </ItemGroup>
-    <ItemGroup Condition="'$(Platform)'=='x64'">
-      <Files Include="Platforms\dotnet\OneWireLinkLayer\IB*64.dll" />
-    </ItemGroup>
-    <Copy SourceFiles="@(Files)" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true" />
-  </Target>
-</Project>
\ No newline at end of file
--- a/MaximInterface.vcxproj.filters	Mon Nov 06 17:46:41 2017 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,282 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <Filter Include="Source Files">
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
-    </Filter>
-    <Filter Include="Header Files">
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
-      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
-    </Filter>
-    <Filter Include="Resource Files">
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
-    </Filter>
-    <Filter Include="Header Files\Platforms/dotnet">
-      <UniqueIdentifier>{20e2adae-b837-416c-9711-27583e3c230b}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Source Files\Platforms/dotnet">
-      <UniqueIdentifier>{63d67a30-8ace-4b0d-8f09-ca770ba4211e}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Header Files\Devices">
-      <UniqueIdentifier>{e279ae2d-8636-4b89-8c6c-69db07e90944}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Source Files\Devices">
-      <UniqueIdentifier>{1441f2db-880a-41e6-9db3-3fcf2e082fc1}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Header Files\Links">
-      <UniqueIdentifier>{63236a03-f900-4307-9ae0-db9f5ad41a32}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Header Files\Utilities">
-      <UniqueIdentifier>{92539371-ab18-4bd0-b3d6-2449d18a6620}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Source Files\Links">
-      <UniqueIdentifier>{bd04ab64-fd11-4c55-bada-233093987852}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Source Files\Utilities">
-      <UniqueIdentifier>{017fb907-ad1f-4072-a2f1-7cd23bb1c735}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="Platforms\dotnet\DS9481P_300.cpp">
-      <Filter>Source Files\Platforms/dotnet</Filter>
-    </ClCompile>
-    <ClCompile Include="Platforms\dotnet\OneWireLinkLayerMaster.cpp">
-      <Filter>Source Files\Platforms/dotnet</Filter>
-    </ClCompile>
-    <ClCompile Include="Platforms\dotnet\Sleep.cpp">
-      <Filter>Source Files\Platforms/dotnet</Filter>
-    </ClCompile>
-    <ClCompile Include="Platforms\dotnet\Uart.cpp">
-      <Filter>Source Files\Platforms/dotnet</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS18B20.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS28E15_22_25.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS28E17.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS28E38.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS1920.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS2413.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS2431.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS2465.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS2480B.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS9400.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Utilities\crc.cpp">
-      <Filter>Source Files\Utilities</Filter>
-    </ClCompile>
-    <ClCompile Include="Utilities\Ecc256.cpp">
-      <Filter>Source Files\Utilities</Filter>
-    </ClCompile>
-    <ClCompile Include="Utilities\HexConversions.cpp">
-      <Filter>Source Files\Utilities</Filter>
-    </ClCompile>
-    <ClCompile Include="Utilities\system_error.cpp">
-      <Filter>Source Files\Utilities</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\I2CMaster.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\I2CMasterDecorator.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\LoggingI2CMaster.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\LoggingOneWireMaster.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\LoggingSleep.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\OneWireMaster.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\OneWireMasterDecorator.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\RomCommands.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\SelectRom.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\SleepDecorator.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Links\Uart.cpp">
-      <Filter>Source Files\Links</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS28C36_DS2476.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Devices\DS2482_DS2484.cpp">
-      <Filter>Source Files\Devices</Filter>
-    </ClCompile>
-    <ClCompile Include="Utilities\Error.cpp">
-      <Filter>Source Files\Utilities</Filter>
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="Platforms\dotnet\ChangeSizeType.hpp">
-      <Filter>Header Files\Platforms/dotnet</Filter>
-    </ClInclude>
-    <ClInclude Include="Platforms\dotnet\DelegateWrapper.hpp">
-      <Filter>Header Files\Platforms/dotnet</Filter>
-    </ClInclude>
-    <ClInclude Include="Platforms\dotnet\DS9481P_300.hpp">
-      <Filter>Header Files\Platforms/dotnet</Filter>
-    </ClInclude>
-    <ClInclude Include="Platforms\dotnet\MoveOnly.hpp">
-      <Filter>Header Files\Platforms/dotnet</Filter>
-    </ClInclude>
-    <ClInclude Include="Platforms\dotnet\OneWireLinkLayerMaster.hpp">
-      <Filter>Header Files\Platforms/dotnet</Filter>
-    </ClInclude>
-    <ClInclude Include="Platforms\dotnet\Sleep.hpp">
-      <Filter>Header Files\Platforms/dotnet</Filter>
-    </ClInclude>
-    <ClInclude Include="Platforms\dotnet\Uart.hpp">
-      <Filter>Header Files\Platforms/dotnet</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS18B20.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS28E15_22_25.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS28E17.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS28E38.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS1920.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS2413.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS2431.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS2465.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS2480B.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS9400.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\array.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\crc.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\Ecc256.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\Function.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\HexConversions.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\ManId.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\RomId.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\Sha256.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\system_error.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\type_traits.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\Uncopyable.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\WriteMessage.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\I2CMaster.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\I2CMasterDecorator.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\LoggingI2CMaster.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\LoggingOneWireMaster.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\LoggingSleep.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\OneWireMaster.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\OneWireMasterDecorator.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\RomCommands.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\SelectRom.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\Sleep.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\SleepDecorator.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Links\Uart.hpp">
-      <Filter>Header Files\Links</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS28C36_DS2476.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Devices\DS2482_DS2484.hpp">
-      <Filter>Header Files\Devices</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\FlagSet.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\Error.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\Export.h">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-    <ClInclude Include="Utilities\Segment.hpp">
-      <Filter>Header Files\Utilities</Filter>
-    </ClInclude>
-  </ItemGroup>
-</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Platforms/Qt/.mbedignore	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,1 @@
+*
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Platforms/Qt/SerialPort.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,166 @@
+/*******************************************************************************
+* 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Platforms/Qt/SerialPort.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,68 @@
+/*******************************************************************************
+* 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Platforms/Qt/Sleep.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,52 @@
+/*******************************************************************************
+* 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Platforms/Qt/Sleep.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,58 @@
+/*******************************************************************************
+* 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Platforms/dotnet/SerialPort.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,225 @@
+/*******************************************************************************
+* 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Platforms/dotnet/SerialPort.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,92 @@
+/*******************************************************************************
+* 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/mbed/I2CMaster.cpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Platforms/mbed/I2CMaster.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -49,9 +49,9 @@
   return (i2c->write(data) == 1) ? error_code() : make_error_code(NackError);
 }
 
-error_code I2CMaster::writePacket(uint_least8_t address,
-                                  const uint_least8_t * data, size_t dataLen,
-                                  bool sendStop) {
+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)
              ? error_code()
@@ -63,8 +63,9 @@
   return error_code();
 }
 
-error_code I2CMaster::readPacket(uint_least8_t address, uint_least8_t * data,
-                                 size_t dataLen, bool sendStop) {
+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,
                     !sendStop) == 0)
              ? error_code()
--- a/Platforms/mbed/I2CMaster.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Platforms/mbed/I2CMaster.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -49,12 +49,14 @@
   virtual error_code start(uint_least8_t address);
   virtual error_code stop();
   virtual error_code writeByte(uint_least8_t data);
-  virtual error_code writePacket(uint_least8_t address,
-                                 const uint_least8_t * data, size_t dataLen,
-                                 bool sendStop);
   virtual error_code readByte(AckStatus status, uint_least8_t & data);
-  virtual error_code readPacket(uint_least8_t address, uint_least8_t * data,
-                                size_t dataLen, bool sendStop);
+  
+protected:
+  virtual error_code readPacketImpl(uint_least8_t address, uint_least8_t * data,
+                                    size_t dataLen, bool sendStop); 
+  virtual error_code writePacketImpl(uint_least8_t address,
+                                     const uint_least8_t * data, size_t dataLen,
+                                     bool sendStop);
 
 private:
   ::mbed::I2C * i2c;
--- a/Platforms/mbed/Uart.cpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Platforms/mbed/Uart.cpp	Thu Jan 11 13:50:39 2018 -0600
@@ -39,8 +39,8 @@
 namespace MaximInterface {
 namespace mbed {
 
-error_code Uart::setBaud(int_least32_t baud) {
-  serial->baud(baud);
+error_code Uart::setBaudRate(int_least32_t baudRate) {
+  serial->baud(baudRate);
   return error_code();
 }
 
--- a/Platforms/mbed/Uart.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Platforms/mbed/Uart.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -50,7 +50,7 @@
 
   void setSerial(::mbed::Serial & serial) { this->serial = &serial; }
 
-  virtual error_code setBaud(int_least32_t baud);
+  virtual error_code setBaudRate(int_least32_t baudRate);
   virtual error_code sendBreak();
   virtual error_code clearReadBuffer();
   virtual error_code writeByte(uint_least8_t data);
--- a/Utilities/Ecc256.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Utilities/Ecc256.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -44,6 +44,9 @@
 
 typedef array<uint_least8_t, 32> Scalar;
 struct Point {
+  /// Total size of all elements in bytes.
+  static const size_t size = 2 * Scalar::csize;
+  
   Scalar x;
   Scalar y;
 };
@@ -51,11 +54,17 @@
 typedef Scalar PrivateKey;
 typedef Point PublicKey;
 struct KeyPair {
+  /// Total size of all elements in bytes.
+  static const size_t size = PrivateKey::csize + PublicKey::size;
+  
   PrivateKey privateKey;
   PublicKey publicKey;
 };
 
 struct Signature {
+  /// Total size of all elements in bytes.
+  static const size_t size = 2 * Scalar::csize;
+  
   Scalar r;
   Scalar s;
 };
--- a/Utilities/system_error.hpp	Mon Nov 06 17:46:41 2017 -0600
+++ b/Utilities/system_error.hpp	Thu Jan 11 13:50:39 2018 -0600
@@ -30,6 +30,10 @@
 * ownership rights.
 *******************************************************************************/
 
+/// @file
+/// Error handling constructs similar std::error_code, std::error_condition, and
+/// std::error_category.
+
 #ifndef MaximInterface_system_error
 #define MaximInterface_system_error
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clr.cmake	Thu Jan 11 13:50:39 2018 -0600
@@ -0,0 +1,76 @@
+#[[*****************************************************************************
+* 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