Extended MaximInterface
Dependents: mbed_DS28EC20_GPIO
Revision 8:211d1b8f730c, committed 2019-04-03
- Comitter:
- reARMnimator
- Date:
- Wed Apr 03 12:33:10 2019 +0000
- Parent:
- 5:3523abdda8ed
- Parent:
- 7:471901a04573
- Child:
- 9:aeda90624ad0
- Commit message:
- Merge with version 1.7;
Changed in this revision
--- a/CMakeLists.txt Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -#[[***************************************************************************** -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -******************************************************************************]] - -cmake_minimum_required(VERSION 3.10) - -include("clr.cmake") - -project("MaximInterface" VERSION 1.1) -option(BUILD_SHARED_LIBS "Build ${CMAKE_PROJECT_NAME} as a shared library." ON) -set(MaximInterface_Platforms "" CACHE STRING - "List of platforms to build. Available platforms are dotnet and Qt.") - -if("dotnet" IN_LIST MaximInterface_Platforms) - # Require shared library for the dotnet platform. - if(NOT BUILD_SHARED_LIBS) - message(SEND_ERROR "BUILD_SHARED_LIBS must be enabled to build the dotnet platform.") - endif() - - # Initialize CLR compilation flags that all targets should use. - initializeClr() -endif() - -# Search in parent directory for includes. -get_filename_component(baseIncludeDir ${CMAKE_SOURCE_DIR} DIRECTORY) -include_directories(${baseIncludeDir}) - -# Prepend a path to all items in a list. -macro(prependPath var path) - unset(${var}) - foreach(arg ${ARGN}) - list(APPEND ${var} "${path}/${arg}") - endforeach() -endmacro(prependPath) - -# Add base components. -set(resourceDirs "Devices" "Links" "Utilities") -prependPath(DevicesSources "Devices" - "DS18B20.cpp" - "DS28C36_DS2476.cpp" - "DS28E15_22_25.cpp" - "DS28E17.cpp" - "DS28E38.cpp" - "DS1920.cpp" - "DS2413.cpp" - "DS2431.cpp" - "DS2465.cpp" - "DS2480B.cpp" - "DS2482_DS2484.cpp" - "DS9400.cpp" - "DS9481P_300.cpp") -prependPath(LinksSources "Links" - "I2CMaster.cpp" - "I2CMasterDecorator.cpp" - "LoggingI2CMaster.cpp" - "LoggingOneWireMaster.cpp" - "LoggingSleep.cpp" - "OneWireMaster.cpp" - "OneWireMasterDecorator.cpp" - "RomCommands.cpp" - "SelectRom.cpp" - "SleepDecorator.cpp" - "Uart.cpp") -prependPath(UtilitiesSources "Utilities" - "crc.cpp" - "Ecc256.cpp" - "Error.cpp" - "HexConversions.cpp" - "system_error.cpp") -add_library(${CMAKE_PROJECT_NAME} ${DevicesSources} ${LinksSources} ${UtilitiesSources}) - -# Add selected platforms. -foreach(platform ${MaximInterface_Platforms}) - if(platform STREQUAL "dotnet") - # Add CLR support to target. - enableClr(${CMAKE_PROJECT_NAME} "v4.5" - "System.dll" - "${CMAKE_SOURCE_DIR}/Platforms/dotnet/OneWireLinkLayer/OneWireLinkLayer.dll") - - # Add files to top-level target since CLR objects do not support static linking. - list(APPEND resourceDirs "Platforms/dotnet") - prependPath(dotnetSources "Platforms/dotnet" - "OneWireLinkLayerMaster.cpp" - "SerialPort.cpp" - "Sleep.cpp") - target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${dotnetSources}) - elseif(platform STREQUAL "Qt") - find_package(Qt5 COMPONENTS Core SerialPort) - list(APPEND resourceDirs "Platforms/Qt") - prependPath(QtSources "Platforms/Qt" - "SerialPort.cpp" - "Sleep.cpp") - add_library(Qt OBJECT ${QtSources}) - target_include_directories(Qt PRIVATE ${Qt5Core_INCLUDE_DIRS} ${Qt5SerialPort_INCLUDE_DIRS}) - target_sources(${CMAKE_PROJECT_NAME} PRIVATE $<TARGET_OBJECTS:Qt>) - target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC Qt5::Core Qt5::SerialPort) - else() - message(SEND_ERROR "\"${platform}\" is not a supported platform.") - endif() -endforeach() - -# Set up build and install exports. -target_include_directories(${CMAKE_PROJECT_NAME} INTERFACE - $<BUILD_INTERFACE:${baseIncludeDir}> - $<INSTALL_INTERFACE:.>) -foreach(resourceDir ${resourceDirs}) - get_filename_component(resourceInstallDir "${CMAKE_PROJECT_NAME}/${resourceDir}" DIRECTORY) - install(DIRECTORY ${resourceDir} DESTINATION ${resourceInstallDir} - FILES_MATCHING PATTERN "*.h*" PATTERN "*.dll") -endforeach() -install(TARGETS ${CMAKE_PROJECT_NAME} EXPORT "${CMAKE_PROJECT_NAME}Config" - ARCHIVE DESTINATION $<CONFIG> - LIBRARY DESTINATION $<CONFIG> - RUNTIME DESTINATION $<CONFIG>) -install(EXPORT "${CMAKE_PROJECT_NAME}Config" DESTINATION "cmake") -export(TARGETS ${CMAKE_PROJECT_NAME} FILE "${CMAKE_PROJECT_NAME}Config.cmake") - -# Set up source groups. -get_property(${CMAKE_PROJECT_NAME}Sources TARGET ${CMAKE_PROJECT_NAME} PROPERTY SOURCES) -source_group(TREE ${CMAKE_SOURCE_DIR} FILES ${${CMAKE_PROJECT_NAME}Sources}) \ No newline at end of file
--- a/Devices/DS18B20.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS18B20.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -36,27 +36,22 @@ namespace MaximInterface { -enum DS18B20_CMDS { - WRITE_SCRATCHPAD = 0x4E, - READ_SCRATCHPAD = 0xBE, - COPY_SCRATCHPAD = 0x48, - CONV_TEMPERATURE = 0x44, - READ_POWER_SUPPY = 0xB4, - RECALL = 0xB8 -}; +const uint_least8_t DS18B20::nineBitResolution; +const uint_least8_t DS18B20::tenBitResolution; +const uint_least8_t DS18B20::elevenBitResolution; +const uint_least8_t DS18B20::twelveBitResolution; error_code DS18B20::initialize() { - Scratchpad scratchpad; + Scratchpad::array scratchpad; return readScratchpad(scratchpad); } error_code DS18B20::writeScratchpad(uint_least8_t th, uint_least8_t tl, - uint_least8_t res) { + uint_least8_t res) { error_code result = selectRom(*master); if (!result) { - const uint_least8_t sendBlock[] = {WRITE_SCRATCHPAD, th, tl, res}; - result = - master->writeBlock(sendBlock, sizeof(sendBlock) / sizeof(sendBlock[0])); + const uint_least8_t sendBlock[] = {0x4E, th, tl, res}; + result = master->writeBlock(sendBlock); if (!result) { resolution = res; } @@ -64,17 +59,16 @@ return result; } -error_code DS18B20::readScratchpad(Scratchpad & scratchpad) { +error_code DS18B20::readScratchpad(Scratchpad::span scratchpad) { error_code result = selectRom(*master); if (result) { return result; } - result = - master->writeByteSetLevel(READ_SCRATCHPAD, OneWireMaster::NormalLevel); + result = master->writeByte(0xBE); if (result) { return result; } - result = master->readBlock(scratchpad.data(), scratchpad.size()); + result = master->readBlock(scratchpad); if (result) { return result; } @@ -83,7 +77,7 @@ if (result) { return result; } - if (receivedCrc == calculateCrc8(scratchpad.data(), scratchpad.size())) { + if (receivedCrc == calculateCrc8(scratchpad)) { resolution = scratchpad[4]; } else { result = make_error_code(CrcError); @@ -91,21 +85,22 @@ return result; } -error_code DS18B20::readPowerSupply(bool & localPower) { +error_code DS18B20::readPowerSupply(bool & localPower) { error_code result = selectRom(*master); if (result) { return result; } - result = - master->writeByteSetLevel(READ_POWER_SUPPY, OneWireMaster::NormalLevel); + result = master->writeByte(0xB4); if (result) { return result; } - result = master->touchBitSetLevel(localPower, OneWireMaster::NormalLevel); + result = master->touchBit(localPower); return result; } error_code DS18B20::copyScratchpad() { + const uint_least8_t copyScratchpadCmd = 0x48; + bool hasLocalPower; error_code result = readPowerSupply(hasLocalPower); if (result) { @@ -116,17 +111,16 @@ return result; } if (hasLocalPower) { - result = - master->writeByteSetLevel(COPY_SCRATCHPAD, OneWireMaster::NormalLevel); + result = master->writeByte(copyScratchpadCmd); bool recvbit = 0; while (!recvbit && !result) { - result = master->touchBitSetLevel(recvbit, OneWireMaster::NormalLevel); + result = master->touchBit(recvbit); } } else { - result = - master->writeByteSetLevel(COPY_SCRATCHPAD, OneWireMaster::StrongLevel); + result = master->writeByteSetLevel(copyScratchpadCmd, + OneWireMaster::StrongLevel); if (!result) { - (*sleep)(10); + sleep->invoke(10); result = master->setLevel(OneWireMaster::NormalLevel); } } @@ -134,6 +128,8 @@ } error_code DS18B20::convertTemperature() { + const uint_least8_t convertTemperatureCmd = 0x44; + bool hasLocalPower; error_code result = readPowerSupply(hasLocalPower); if (result) { @@ -144,15 +140,14 @@ return result; } if (hasLocalPower) { - result = - master->writeByteSetLevel(CONV_TEMPERATURE, OneWireMaster::NormalLevel); + result = master->writeByte(convertTemperatureCmd); bool recvbit = 0; while (!result && !recvbit) { - result = master->touchBitSetLevel(recvbit, OneWireMaster::NormalLevel); + result = master->touchBit(recvbit); } } else { - result = - master->writeByteSetLevel(CONV_TEMPERATURE, OneWireMaster::StrongLevel); + result = master->writeByteSetLevel(convertTemperatureCmd, + OneWireMaster::StrongLevel); if (!result) { int sleepTime; switch (resolution) { @@ -173,17 +168,17 @@ sleepTime = 750; break; } - (*sleep)(sleepTime); + sleep->invoke(sleepTime); result = master->setLevel(OneWireMaster::NormalLevel); } } return result; } -error_code DS18B20::recallEeprom() { +error_code DS18B20::recallEeprom() { error_code result = selectRom(*master); if (!result) { - result = master->writeByte(RECALL); + result = master->writeByte(0xB8); } return result; } @@ -214,13 +209,13 @@ if (result) { return result; } - DS18B20::Scratchpad scratchpad; + DS18B20::Scratchpad::array scratchpad; result = ds18b20.readScratchpad(scratchpad); if (result) { return result; } - unsigned int tempData = + const unsigned int tempData = (static_cast<unsigned int>(scratchpad[1]) << 8) | scratchpad[0]; const unsigned int signMask = 0xF800; if ((tempData & signMask) == signMask) {
--- a/Devices/DS18B20.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS18B20.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,11 +35,12 @@ #include <MaximInterface/Links/SelectRom.hpp> #include <MaximInterface/Links/Sleep.hpp> +#include <MaximInterface/Utilities/array_span.hpp> #include <MaximInterface/Utilities/Export.h> namespace MaximInterface { -/// DS18B20 Programmable Resolution 1-Wire Digital Thermometer +/// @brief DS18B20 Programmable Resolution 1-Wire Digital Thermometer /// @details The DS18B20 digital thermometer provides 9-bit to 12-bit /// Celsius temperature measurements and has an alarm function with /// nonvolatile user-programmable upper and lower trigger points. The @@ -58,14 +59,15 @@ static const uint_least8_t twelveBitResolution = 0x7F; /// Holds the contents of the device scratchpad. - typedef array<uint_least8_t, 8> Scratchpad; + typedef array_span<uint_least8_t, 8> Scratchpad; - DS18B20(const Sleep & sleep, OneWireMaster & master, - const SelectRom & selectRom) + DS18B20(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom) : selectRom(selectRom), master(&master), sleep(&sleep), resolution(0) {} - void setSleep(const Sleep & sleep) { this->sleep = &sleep; } + void setSleep(Sleep & sleep) { this->sleep = &sleep; } + void setMaster(OneWireMaster & master) { this->master = &master; } + void setSelectRom(const SelectRom & selectRom) { this->selectRom = selectRom; } @@ -88,7 +90,7 @@ /// Read Scratchpad Command /// @param[out] scratchpad Contents of scratchpad. - MaximInterface_EXPORT error_code readScratchpad(Scratchpad & scratchpad); + MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span scratchpad); /// Copy Scratchpad Command /// @details This command copies from the scratchpad into the @@ -123,7 +125,8 @@ }; /// Reads the current temperature as an integer value with decimal. -/// @param[out] temperature Temperature in degrees Celsius multiplied by 2. +/// @param ds18b20 Device to read. +/// @param[out] temperature Temperature in degrees Celsius multiplied by 16. MaximInterface_EXPORT error_code readTemperature(DS18B20 & ds18b20, int & temperature);
--- a/Devices/DS1920.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS1920.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -36,35 +36,25 @@ namespace MaximInterface { -enum DS1920_CMDS { - WRITE_SCRATCHPAD = 0x4E, - READ_SCRATCHPAD = 0xBE, - COPY_SCRATCHPAD = 0x48, - CONV_TEMPERATURE = 0x44, - RECALL = 0xB8 -}; - -error_code DS1920::writeScratchpad(uint_least8_t th, uint_least8_t tl) { +error_code DS1920::writeScratchpad(uint_least8_t th, uint_least8_t tl) { error_code result = selectRom(*master); if (!result) { - const uint_least8_t sendBlock[] = {WRITE_SCRATCHPAD, th, tl}; - result = - master->writeBlock(sendBlock, sizeof(sendBlock) / sizeof(sendBlock[0])); + const uint_least8_t sendBlock[] = {0x4E, th, tl}; + result = master->writeBlock(sendBlock); } return result; } -error_code DS1920::readScratchpad(Scratchpad & scratchpad) { +error_code DS1920::readScratchpad(Scratchpad::span scratchpad) { error_code result = selectRom(*master); if (!result) { - result = master->writeByte(READ_SCRATCHPAD); + result = master->writeByte(0xBE); if (!result) { - result = master->readBlock(scratchpad.data(), scratchpad.size()); + result = master->readBlock(scratchpad); if (!result) { uint_least8_t receivedCrc; result = master->readByte(receivedCrc); - if (!result && (receivedCrc != - calculateCrc8(scratchpad.data(), scratchpad.size()))) { + if (!result && (receivedCrc != calculateCrc8(scratchpad))) { result = make_error_code(CrcError); } } @@ -73,36 +63,34 @@ return result; } -error_code DS1920::copyScratchpad() { +error_code DS1920::copyScratchpad() { error_code result = selectRom(*master); if (!result) { - result = - master->writeByteSetLevel(COPY_SCRATCHPAD, OneWireMaster::StrongLevel); + result = master->writeByteSetLevel(0x48, OneWireMaster::StrongLevel); if (!result) { - (*sleep)(10); + sleep->invoke(10); result = master->setLevel(OneWireMaster::NormalLevel); } } return result; } -error_code DS1920::convertTemperature() { +error_code DS1920::convertTemperature() { error_code result = selectRom(*master); if (!result) { - result = - master->writeByteSetLevel(CONV_TEMPERATURE, OneWireMaster::StrongLevel); + result = master->writeByteSetLevel(0x44, OneWireMaster::StrongLevel); if (!result) { - (*sleep)(750); + sleep->invoke(750); result = master->setLevel(OneWireMaster::NormalLevel); } } return result; } -error_code DS1920::recallEeprom() { +error_code DS1920::recallEeprom() { error_code result = selectRom(*master); if (!result) { - result = master->writeByte(RECALL); + result = master->writeByte(0xB8); } return result; } @@ -133,7 +121,7 @@ if (result) { return result; } - DS1920::Scratchpad scratchpad; + DS1920::Scratchpad::array scratchpad; result = ds1920.readScratchpad(scratchpad); if (result) { return result;
--- a/Devices/DS1920.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS1920.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,11 +35,12 @@ #include <MaximInterface/Links/SelectRom.hpp> #include <MaximInterface/Links/Sleep.hpp> +#include <MaximInterface/Utilities/array_span.hpp> #include <MaximInterface/Utilities/Export.h> namespace MaximInterface { -/// DS1920 1-Wire Temperature iButton +/// @brief DS1920 1-Wire Temperature iButton /// @details The iButton® temperature logger (DS1920) provides /// direct-to-digital 9-bit temperature readings over a range of /// -55°C to +100°C in 0.5° increments. The iButton communicates with @@ -54,19 +55,20 @@ enum ErrorValue { CrcError = 1, DataError }; /// Holds the contents of the device scratchpad. - typedef array<uint_least8_t, 8> Scratchpad; + typedef array_span<uint_least8_t, 8> Scratchpad; - DS1920(const Sleep & sleep, OneWireMaster & master, - const SelectRom & selectRom) + DS1920(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom) : selectRom(selectRom), master(&master), sleep(&sleep) {} - void setSleep(const Sleep & sleep) { this->sleep = &sleep; } + void setSleep(Sleep & sleep) { this->sleep = &sleep; } + void setMaster(OneWireMaster & master) { this->master = &master; } + void setSelectRom(const SelectRom & selectRom) { this->selectRom = selectRom; } - /// Write Scratchpad Command + /// @brief Write Scratchpad Command /// @details If the result of a temperature measurement is higher /// than TH or lower than TL, an alarm flag inside the device is /// set. This flag is updated with every temperature measurement. @@ -77,21 +79,21 @@ MaximInterface_EXPORT error_code writeScratchpad(uint_least8_t th, uint_least8_t tl); - /// Read Scratchpad Command + /// @brief Read Scratchpad Command /// @param[out] scratchpad Contents of scratchpad. - MaximInterface_EXPORT error_code readScratchpad(Scratchpad & scratchpad); + MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span scratchpad); - /// Copy Scratchpad Command + /// @brief Copy Scratchpad Command /// @details This command copies from the scratchpad into the /// EEPROM of the DS1920, storing the temperature trigger bytes /// in nonvolatile memory. MaximInterface_EXPORT error_code copyScratchpad(); - /// Convert Temperature Command + /// @brief Convert Temperature Command /// @details This command begins a temperature conversion. MaximInterface_EXPORT error_code convertTemperature(); - /// Recall Command + /// @brief Recall Command /// @details This command recalls the temperature trigger values /// stored in EEPROM to the scratchpad. MaximInterface_EXPORT error_code recallEeprom(); @@ -104,8 +106,9 @@ const Sleep * sleep; }; -/// Reads the current temperature as an integer value. -/// @param[out] temperature Temperature in degrees Celsius multiplied by 16. +/// @brief Reads the current temperature as an integer value. +/// @param ds1920 Device to read. +/// @param[out] temperature Temperature in degrees Celsius multiplied by 2. MaximInterface_EXPORT error_code readTemperature(DS1920 & ds1920, int & temperature);
--- a/Devices/DS2413.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS2413.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -40,10 +40,7 @@ uint_least8_t val; const error_code result = pioAccessRead(val); if (!result) { - status.pioAInputState = (val & 0x1) == 0x1; - status.pioAOutputState = (val & 0x2) == 0x2; - status.pioBInputState = (val & 0x4) == 0x4; - status.pioBOutputState = (val & 0x8) == 0x8; + status = val; } return result; } @@ -77,7 +74,7 @@ error_code result = selectRom(*master); if (!result) { uint_least8_t block[] = {0x5A, val, static_cast<uint_least8_t>(val ^ 0xFF)}; - result = master->writeBlock(block, sizeof(block) / sizeof(block[0])); + result = master->writeBlock(block); if (!result) { result = master->readByte(block[0]); if (!result && block[0] != 0xAA) { @@ -97,10 +94,8 @@ switch (condition) { case CommunicationError: return "Communication Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance; @@ -109,8 +104,9 @@ error_code writePioAOutputState(DS2413 & ds2413, bool pioAState) { DS2413::Status status; error_code result = ds2413.readStatus(status); - if (!result && pioAState != status.pioAOutputState) { - result = ds2413.writeOutputState(pioAState, status.pioBOutputState); + if (!result && pioAState != status[DS2413::PioAOutputState]) { + result = + ds2413.writeOutputState(pioAState, status[DS2413::PioBOutputState]); } return result; } @@ -118,8 +114,9 @@ error_code writePioBOutputState(DS2413 & ds2413, bool pioBState) { DS2413::Status status; error_code result = ds2413.readStatus(status); - if (!result && pioBState != status.pioBOutputState) { - result = ds2413.writeOutputState(status.pioAOutputState, pioBState); + if (!result && pioBState != status[DS2413::PioBOutputState]) { + result = + ds2413.writeOutputState(status[DS2413::PioAOutputState], pioBState); } return result; }
--- a/Devices/DS2413.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS2413.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -36,10 +36,11 @@ #include <stdint.h> #include <MaximInterface/Links/SelectRom.hpp> #include <MaximInterface/Utilities/Export.h> +#include <MaximInterface/Utilities/FlagSet.hpp> namespace MaximInterface { -/// DS2413 1-Wire Dual Channel Addressable Switch +/// @brief DS2413 1-Wire Dual Channel Addressable Switch /// @details The DS2413 is a dual-channel programmable I/O 1-Wire® /// chip. The PIO outputs are configured as open-drain and provide up /// to 20mA continuous sink capability and off-state operating voltage @@ -53,17 +54,19 @@ public: enum ErrorValue { CommunicationError = 1 }; - struct Status { - bool pioAInputState; - bool pioAOutputState; - bool pioBInputState; - bool pioBOutputState; + enum StatusFlags { + PioAInputState = 0x1, + PioAOutputState = 0x2, + PioBInputState = 0x4, + PioBOutputState = 0x8 }; + typedef FlagSet<StatusFlags, 4> Status; DS2413(OneWireMaster & master, const SelectRom & selectRom) : selectRom(selectRom), master(&master) {} void setMaster(OneWireMaster & master) { this->master = &master; } + void setSelectRom(const SelectRom & selectRom) { this->selectRom = selectRom; } @@ -85,13 +88,13 @@ OneWireMaster * master; }; -/// @{ -/// Write the output logic state for only a single PIO pin. +/// Write the output logic state for only PIOA. MaximInterface_EXPORT error_code writePioAOutputState(DS2413 & ds2413, bool pioAState); + +/// Write the output logic state for only PIOB. MaximInterface_EXPORT error_code writePioBOutputState(DS2413 & ds2413, bool pioBState); -/// @} inline error_code make_error_code(DS2413::ErrorValue e) { return error_code(e, DS2413::errorCategory());
--- a/Devices/DS2431.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS2431.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -37,20 +37,13 @@ namespace MaximInterface { -enum Command { - WriteScratchpad = 0x0F, - ReadScratchpad = 0xAA, - CopyScratchpad = 0x55, - ReadMemory = 0xF0 -}; - error_code writeMemory(DS2431 & device, DS2431::Address targetAddress, - const DS2431::Scratchpad & data) { + DS2431::Scratchpad::const_span data) { error_code result = device.writeScratchpad(targetAddress, data); if (result) { return result; } - DS2431::Scratchpad readData; + DS2431::Scratchpad::array readData; uint_least8_t esByte; result = device.readScratchpad(readData, esByte); if (result) { @@ -60,107 +53,105 @@ return result; } -error_code DS2431::readMemory(Address beginAddress, uint_least8_t * data, - size_t dataLen) const { - error_code owmResult = selectRom(*master); - if (owmResult) { - return owmResult; +error_code DS2431::readMemory(Address beginAddress, + span<uint_least8_t> data) const { + error_code result = selectRom(*master); + if (result) { + return result; } - const uint_least8_t sendBlock[] = {ReadMemory, beginAddress, 0x00}; - owmResult = - master->writeBlock(sendBlock, sizeof(sendBlock) / sizeof(sendBlock[0])); - if (owmResult) { - return owmResult; + const uint_least8_t sendBlock[] = {0xF0, beginAddress, 0x00}; + result = master->writeBlock(sendBlock); + if (result) { + return result; } - owmResult = master->readBlock(data, dataLen); - return owmResult; + result = master->readBlock(data); + return result; } error_code DS2431::writeScratchpad(Address targetAddress, - const Scratchpad & data) { - error_code owmResult = selectRom(*master); - if (owmResult) { - return owmResult; + Scratchpad::const_span data) { + error_code result = selectRom(*master); + if (result) { + return result; } - array<uint_least8_t, 3 + Scratchpad::csize> block = {WriteScratchpad, - targetAddress, 0x00}; - std::copy(data.begin(), data.end(), block.begin() + 3); - owmResult = master->writeBlock(block.data(), block.size()); - if (owmResult) { - return owmResult; + uint_least8_t block[3 + Scratchpad::size] = {0x0F, targetAddress, 0x00}; + std::copy(data.begin(), data.end(), block + 3); + result = master->writeBlock(block); + if (result) { + return result; } - const uint_fast16_t calculatedCrc = - calculateCrc16(block.data(), block.size()) ^ 0xFFFFU; - owmResult = master->readBlock(block.data(), 2); - if (owmResult) { - return owmResult; + const uint_fast16_t calculatedCrc = calculateCrc16(block) ^ 0xFFFFU; + result = master->readBlock(make_span(block, 2)); + if (result) { + return result; } if (calculatedCrc != ((static_cast<uint_fast16_t>(block[1]) << 8) | block[0])) { - owmResult = make_error_code(CrcError); + result = make_error_code(CrcError); } - return owmResult; + return result; } -error_code DS2431::readScratchpad(Scratchpad & data, uint_least8_t & esByte) { - typedef array<uint_least8_t, 6 + Scratchpad::csize> Block; +error_code DS2431::readScratchpad(Scratchpad::span data, + uint_least8_t & esByte) { + typedef array<uint_least8_t, 6 + Scratchpad::size> Block; - error_code owmResult = selectRom(*master); - if (owmResult) { - return owmResult; + error_code result = selectRom(*master); + if (result) { + return result; } - Block block = {ReadScratchpad}; - owmResult = master->writeByte(block.front()); - if (owmResult) { - return owmResult; + Block block = {0xAA}; + result = master->writeByte(block.front()); + if (result) { + return result; } - owmResult = master->readBlock(block.data() + 1, block.size() - 1); - if (owmResult) { - return owmResult; + result = master->readBlock(make_span(block).subspan(1)); + if (result) { + return result; } Block::const_iterator blockIt = block.end(); uint_fast16_t receivedCrc = static_cast<uint_fast16_t>(*(--blockIt)) << 8; receivedCrc |= *(--blockIt); const uint_fast16_t expectedCrc = - calculateCrc16(block.data(), block.size() - 2) ^ 0xFFFFU; + calculateCrc16(make_span(block.data(), block.size() - 2)) ^ 0xFFFFU; if (expectedCrc == receivedCrc) { Block::const_iterator blockItEnd = blockIt; blockIt -= data.size(); std::copy(blockIt, blockItEnd, data.begin()); esByte = *(--blockIt); } else { - owmResult = make_error_code(CrcError); + result = make_error_code(CrcError); } - return owmResult; + return result; } -error_code DS2431::copyScratchpad(Address targetAddress, uint_least8_t esByte) { - error_code owmResult = selectRom(*master); - if (owmResult) { - return owmResult; +error_code DS2431::copyScratchpad(Address targetAddress, uint_least8_t esByte) { + error_code result = selectRom(*master); + if (result) { + return result; } - uint_least8_t block[] = {CopyScratchpad, targetAddress, 0x00}; - owmResult = master->writeBlock(block, sizeof(block) / sizeof(block[0])); - if (owmResult) { - return owmResult; + uint_least8_t block[] = {0x55, targetAddress, 0x00}; + result = master->writeBlock(block); + if (result) { + return result; } - owmResult = master->writeByteSetLevel(esByte, OneWireMaster::StrongLevel); - if (owmResult) { - return owmResult; + result = master->writeByteSetLevel(esByte, OneWireMaster::StrongLevel); + if (result) { + return result; } - (*sleep)(10); - owmResult = master->setLevel(OneWireMaster::NormalLevel); - if (owmResult) { - return owmResult; + sleep->invoke(10); + result = master->setLevel(OneWireMaster::NormalLevel); + if (result) { + return result; } - owmResult = master->readByte(block[0]); - if (owmResult) { - return owmResult; + result = master->readByte(block[0]); + if (result) { + return result; } if (block[0] != 0xAA) { - owmResult = make_error_code(OperationFailure); + result = make_error_code(OperationFailure); } - return owmResult; + return result; } const error_category & DS2431::errorCategory() { @@ -174,11 +165,9 @@ return "CRC Error"; case OperationFailure: - return "Operation Failure"; - - default: - return defaultErrorMessage(condition); + return "Operation Failure"; } + return defaultErrorMessage(condition); } } instance; return instance;
--- a/Devices/DS2431.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS2431.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,11 +35,12 @@ #include <MaximInterface/Links/SelectRom.hpp> #include <MaximInterface/Links/Sleep.hpp> +#include <MaximInterface/Utilities/array_span.hpp> #include <MaximInterface/Utilities/Export.h> namespace MaximInterface { -/// DS2431 1024-bit 1-Wire EEPROM +/// @brief DS2431 1024-bit 1-Wire EEPROM /// @details The DS2431 is a 1024-bit, 1-Wire® EEPROM chip organized /// as four memory pages of 256 bits each. Data is written to an 8-byte /// scratchpad, verified, and then copied to the EEPROM memory. As a @@ -55,41 +56,41 @@ public: enum ErrorValue { CrcError = 1, OperationFailure }; - typedef array<uint_least8_t, 8> Scratchpad; + typedef array_span<uint_least8_t, 8> Scratchpad; typedef uint_least8_t Address; - DS2431(const Sleep & sleep, OneWireMaster & master, - const SelectRom & selectRom) + DS2431(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom) : selectRom(selectRom), master(&master), sleep(&sleep) {} - void setSleep(const Sleep & sleep) { this->sleep = &sleep; } + void setSleep(Sleep & sleep) { this->sleep = &sleep; } + void setMaster(OneWireMaster & master) { this->master = &master; } + void setSelectRom(const SelectRom & selectRom) { this->selectRom = selectRom; } - /// Reads block of data from EEPROM memory. + /// @brief Reads block of data from EEPROM memory. /// @param[in] beginAddress EEPROM memory address to start reading from. /// @param[out] data EEPROM data read from the device. - /// @param[in] dataLen Length of data parameter and number of bytes to read. MaximInterface_EXPORT error_code readMemory(Address beginAddress, - uint_least8_t * data, - size_t dataLen) const; + span<uint_least8_t> data) const; - /// Writes 8 bytes to the scratchpad. - /// @param[in] targetAddress EEPROM memory address that this data. - /// will be copied to. Must be on row boundary. + /// @brief Writes 8 bytes to the scratchpad. + /// @param[in] targetAddress + /// EEPROM memory address that this data will be copied to. + /// Must be on row boundary. /// @param[in] data Data to write to scratchpad. MaximInterface_EXPORT error_code writeScratchpad(Address targetAddress, - const Scratchpad & data); + Scratchpad::const_span data); - /// Reads contents of scratchpad. + /// @brief Reads contents of scratchpad. /// @param[out] data Data read from scratchpad. /// @param[out] esByte E/S byte read before scratchpad data. - MaximInterface_EXPORT error_code readScratchpad(Scratchpad & data, + MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span data, uint_least8_t & esByte); - /// Copies contents of scratchpad to EEPROM. + /// @brief Copies contents of scratchpad to EEPROM. /// @param[in] targetAddress EEPROM memory address that scratchpad /// will be copied to. Must be on row boundary. /// @param[in] esByte E/S byte from preceding Read Scratchpad command. @@ -104,13 +105,15 @@ const Sleep * sleep; }; +/// @brief /// Writes data to EEPROM using Write Scratchpad, Read Scratchpad, /// and Copy Scratchpad commands. +/// @param device Device to write. /// @param[in] targetAddress EEPROM memory address to start writing at. /// @param[in] data Data to write to EEPROM. MaximInterface_EXPORT error_code writeMemory(DS2431 & device, DS2431::Address targetAddress, - const DS2431::Scratchpad & data); + DS2431::Scratchpad::const_span data); inline error_code make_error_code(DS2431::ErrorValue e) { return error_code(e, DS2431::errorCategory());
--- a/Devices/DS2465.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS2465.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -37,24 +37,6 @@ using namespace Sha256; -enum MemoryAddress { - Scratchpad = 0x00, - CommandReg = 0x60, - StatusReg = 0x61, - ReadDataReg = 0x62, - MacReadoutReg = 0x63, - MemoryProtectionReg = 0x64, - ConfigReg = 0x67, - tRSTL_Reg = 0x68, - tMSP_Reg = 0x69, - tW0L_Reg = 0x6A, - tREC0_Reg = 0x6B, - RWPU_Reg = 0x6C, - tW1L_Reg = 0x6D, - UserMemoryPage0 = 0x80, - UserMemoryPage1 = 0xA0 -}; - /// Delay required after writing an EEPROM segment. static const int eepromSegmentWriteDelayMs = 10; /// Delay required after writing an EEPROM page such as the secret memory. @@ -62,26 +44,12 @@ /// Delay required for a SHA computation to complete. static const int shaComputationDelayMs = 2; -/// DS2465 Commands -enum Command { - DeviceResetCmd = 0xF0, - WriteDeviceConfigCmd = 0xD2, - OwResetCmd = 0xB4, - OwWriteByteCmd = 0xA5, - OwReadByteCmd = 0x96, - OwSingleBitCmd = 0x87, - OwTripletCmd = 0x78, - OwTransmitBlockCmd = 0x69, - OwReceiveBlockCmd = 0xE1, - CopyScratchpadCmd = 0x5A, - ComputeSlaveSecretCmd = 0x4B, - ComputeSlaveAuthMacCmd = 0x3C, - ComputeSlaveWriteMacCmd = 0x2D, - ComputeNextMasterSecretCmd = 0x1E, - SetProtectionCmd = 0x0F -}; +static const uint_least8_t scratchpad = 0x00; +static const uint_least8_t commandReg = 0x60; -/// DS2465 Status Bits +static const uint_least8_t owTransmitBlockCmd = 0x69; + +/// DS2465 Status bits. enum StatusBit { Status_1WB = 0x01, Status_PPD = 0x02, @@ -93,7 +61,10 @@ Status_DIR = 0x80 }; -static const size_t maxBlockSize = 63; +static const int maxBlockSize = 63; + +const int DS2465::memoryPages; +const int DS2465::segmentsPerPage; error_code DS2465::initialize(Config config) { // reset DS2465 @@ -109,12 +80,10 @@ PageRegion region) { error_code result = make_error_code(ArgumentOutOfRangeError); if (pageNum >= 0) { - uint_least8_t command[] = { - ComputeNextMasterSecretCmd, - static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region) - : 0xBF)}; - result = - writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0])); + const uint_least8_t command[] = { + 0x1E, static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region) + : 0xBF)}; + result = writeMemory(commandReg, command); } return result; } @@ -123,14 +92,12 @@ int segmentNum) const { error_code result = make_error_code(ArgumentOutOfRangeError); if (pageNum >= 0 && segmentNum >= 0) { - uint_least8_t command[] = { - ComputeSlaveWriteMacCmd, - static_cast<uint_least8_t>((regwrite << 7) | (swap << 6) | - (pageNum << 4) | segmentNum)}; - result = - writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0])); + const uint_least8_t command[] = { + 0x2D, static_cast<uint_least8_t>((regwrite << 7) | (swap << 6) | + (pageNum << 4) | segmentNum)}; + result = writeMemory(commandReg, command); if (!result) { - (*sleep)(shaComputationDelayMs); + sleep->invoke(shaComputationDelayMs); } } return result; @@ -140,14 +107,12 @@ PageRegion region) const { error_code result = make_error_code(ArgumentOutOfRangeError); if (pageNum >= 0) { - uint_least8_t command[] = { - ComputeSlaveAuthMacCmd, - static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region) - : 0xBF)}; - result = - writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0])); + const uint_least8_t command[] = { + 0x3C, static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region) + : 0xBF)}; + result = writeMemory(commandReg, command); if (!result) { - (*sleep)(shaComputationDelayMs * 2); + sleep->invoke(shaComputationDelayMs * 2); } } return result; @@ -157,65 +122,62 @@ PageRegion region) { error_code result = make_error_code(ArgumentOutOfRangeError); if (pageNum >= 0) { - uint_least8_t command[] = { - ComputeSlaveSecretCmd, - static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region) - : 0xBF)}; - result = - writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0])); + const uint_least8_t command[] = { + 0x4B, static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region) + : 0xBF)}; + result = writeMemory(commandReg, command); if (!result) { - (*sleep)(shaComputationDelayMs * 2); + sleep->invoke(shaComputationDelayMs * 2); } } return result; } -error_code DS2465::readPage(int pageNum, Page & data) const { +error_code DS2465::readPage(int pageNum, Page::span data) const { uint_least8_t addr; switch (pageNum) { case 0: - addr = UserMemoryPage0; + addr = 0x80; break; case 1: - addr = UserMemoryPage1; + addr = 0xA0; break; default: return make_error_code(ArgumentOutOfRangeError); } - return readMemory(addr, data.data(), data.size()); + return readMemory(addr, data); } -error_code DS2465::writePage(int pageNum, const Page & data) { - error_code result = writeMemory(Scratchpad, data.data(), data.size()); +error_code DS2465::writePage(int pageNum, Page::const_span data) { + error_code result = writeMemory(scratchpad, data); if (!result) { result = copyScratchpad(false, pageNum, false, 0); } if (!result) { - (*sleep)(eepromPageWriteDelayMs); + sleep->invoke(eepromPageWriteDelayMs); } return result; } error_code DS2465::writeSegment(int pageNum, int segmentNum, - const Segment & data) { - error_code result = writeMemory(Scratchpad, data.data(), data.size()); + Segment::const_span data) { + error_code result = writeMemory(scratchpad, data); if (!result) { result = copyScratchpad(false, pageNum, true, segmentNum); } if (!result) { - (*sleep)(eepromSegmentWriteDelayMs); + sleep->invoke(eepromSegmentWriteDelayMs); } return result; } -error_code DS2465::writeMasterSecret(const Hash & masterSecret) { - error_code result = - writeMemory(Scratchpad, masterSecret.data(), masterSecret.size()); +error_code DS2465::writeMasterSecret(Hash::const_span masterSecret) { + error_code result = writeMemory(scratchpad, masterSecret); if (!result) { result = copyScratchpad(true, 0, false, 0); } if (!result) { - (*sleep)(eepromPageWriteDelayMs); + sleep->invoke(eepromPageWriteDelayMs); } return result; } @@ -224,13 +186,12 @@ int segmentNum) { error_code result = make_error_code(ArgumentOutOfRangeError); if (pageNum >= 0 && segmentNum >= 0) { - uint_least8_t command[] = { - CopyScratchpadCmd, + const uint_least8_t command[] = { + 0x5A, static_cast<uint_least8_t>(destSecret ? 0 : (0x80 | (pageNum << 4) | (notFull << 3) | segmentNum))}; - result = - writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0])); + result = writeMemory(commandReg, command); } return result; } @@ -245,9 +206,7 @@ return error_code(); } // Set the level - Config newConfig = curConfig; - newConfig.setSPU(level == StrongLevel); - return writeConfig(newConfig); + return writeConfig(Config(curConfig).setSPU(level == StrongLevel)); } error_code DS2465::setLevel(Level newLevel) { @@ -268,9 +227,7 @@ return error_code(); } // Set the speed - Config newConfig = curConfig; - newConfig.set1WS(newSpeed == OverdriveSpeed); - return writeConfig(newConfig); + return writeConfig(Config(curConfig).set1WS(newSpeed == OverdriveSpeed)); } error_code DS2465::triplet(TripletData & data) { @@ -282,9 +239,8 @@ // SS indicates byte containing search direction bit value in msbit const uint_least8_t command[] = { - OwTripletCmd, static_cast<uint_least8_t>(data.writeBit ? 0x80 : 0x00)}; - error_code result = - writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0])); + 0x78, static_cast<uint_least8_t>(data.writeBit ? 0x80 : 0x00)}; + error_code result = writeMemory(commandReg, command); if (!result) { uint_least8_t status; result = pollBusy(&status); @@ -298,54 +254,54 @@ return result; } -error_code DS2465::readBlock(uint_least8_t * recvBuf, size_t recvLen) { +error_code DS2465::readBlock(span<uint_least8_t> recvBuf) { // 1-Wire Receive Block (Case A) // S AD,0 [A] CommandReg [A] 1WRF [A] PR [A] P // [] indicates from slave // PR indicates byte containing parameter error_code result; - while ((recvLen > 0) && !result) { + span<uint_least8_t>::index_type recvIdx = 0; + while (recvIdx < recvBuf.size() && !result) { const uint_least8_t command[] = { - OwReceiveBlockCmd, - static_cast<uint_least8_t>(std::min(recvLen, maxBlockSize))}; - result = - writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0])); + 0xE1, + static_cast<uint_least8_t>(std::min<span<uint_least8_t>::index_type>( + recvBuf.size() - recvIdx, maxBlockSize))}; + result = writeMemory(commandReg, command); if (!result) { result = pollBusy(); } if (!result) { - result = readMemory(Scratchpad, recvBuf, command[1]); + result = readMemory(scratchpad, recvBuf.subspan(recvIdx, command[1])); } - recvBuf += command[1]; - recvLen -= command[1]; + recvIdx += command[1]; } return result; } -error_code DS2465::writeBlock(const uint_least8_t * sendBuf, size_t sendLen) { +error_code DS2465::writeBlock(span<const uint_least8_t> sendBuf) { error_code result; - while ((sendLen > 0) && !result) { + span<const uint_least8_t>::index_type sendIdx = 0; + while (sendIdx < sendBuf.size() && !result) { const uint_least8_t command[] = { - OwTransmitBlockCmd, - static_cast<uint_least8_t>(std::min(sendLen, maxBlockSize))}; + owTransmitBlockCmd, static_cast<uint_least8_t>( + std::min<span<const uint_least8_t>::index_type>( + sendBuf.size() - sendIdx, maxBlockSize))}; // prefill scratchpad with required data - result = writeMemory(Scratchpad, sendBuf, command[1]); + result = writeMemory(scratchpad, sendBuf.subspan(sendIdx, command[1])); // 1-Wire Transmit Block (Case A) // S AD,0 [A] CommandReg [A] 1WTB [A] PR [A] P // [] indicates from slave // PR indicates byte containing parameter if (!result) { - result = writeMemory(CommandReg, command, - sizeof(command) / sizeof(command[0])); + result = writeMemory(commandReg, command); } if (!result) { result = pollBusy(); } - sendBuf += command[1]; - sendLen -= command[1]; + sendIdx += command[1]; } return result; } @@ -356,9 +312,8 @@ // [] indicates from slave // PR indicates byte containing parameter - const uint_least8_t command[] = {OwTransmitBlockCmd, 0xFF}; - error_code result = - writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0])); + const uint_least8_t command[] = {owTransmitBlockCmd, 0xFF}; + error_code result = writeMemory(commandReg, command); if (!result) { result = pollBusy(); } @@ -381,21 +336,18 @@ return result; } - uint_least8_t buf = OwReadByteCmd; - result = writeMemory(CommandReg, &buf, 1); - - if (!result) { - result = pollBusy(); + const uint_least8_t command = 0x96; + result = writeMemory(commandReg, make_span(&command, 1)); + if (result) { + return result; } - if (!result) { - result = readMemory(ReadDataReg, &buf, 1); + result = pollBusy(); + if (result) { + return result; } - if (!result) { - recvByte = buf; - } - + result = readMemory(0x62, make_span(&recvByte, 1)); return result; } @@ -413,14 +365,13 @@ return result; } - const uint_least8_t command[] = {OwWriteByteCmd, sendByte}; - - result = - writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0])); - if (!result) { - result = pollBusy(); + const uint_least8_t command[] = {0xA5, sendByte}; + result = writeMemory(commandReg, command); + if (result) { + return result; } + result = pollBusy(); return result; } @@ -439,25 +390,22 @@ } const uint_least8_t command[] = { - OwSingleBitCmd, static_cast<uint_least8_t>(sendRecvBit ? 0x80 : 0x00)}; - uint_least8_t status; - - result = - writeMemory(CommandReg, command, sizeof(command) / sizeof(command[0])); - - if (!result) { - result = pollBusy(&status); + 0x87, static_cast<uint_least8_t>(sendRecvBit ? 0x80 : 0x00)}; + result = writeMemory(commandReg, command); + if (result) { + return result; } + uint_least8_t status; + result = pollBusy(&status); if (!result) { sendRecvBit = ((status & Status_SBR) == Status_SBR); } - return result; } -error_code DS2465::writeMemory(uint_least8_t addr, const uint_least8_t * buf, - size_t bufLen) const { +error_code DS2465::writeMemory(uint_least8_t addr, + span<const uint_least8_t> buf) const { // Write SRAM (Case A) // S AD,0 [A] VSA [A] DD [A] P // \-----/ @@ -466,27 +414,27 @@ // VSA valid SRAM memory address // DD memory data to write - error_code result = i2cMaster->start(i2cAddress_); + error_code result = master->start(address_); if (result) { - i2cMaster->stop(); + master->stop(); return result; } - result = i2cMaster->writeByte(addr); + result = master->writeByte(addr); if (result) { - i2cMaster->stop(); + master->stop(); return result; } - result = i2cMaster->writeBlock(buf, bufLen); + result = master->writeBlock(buf); if (result) { - i2cMaster->stop(); + master->stop(); return result; } - result = i2cMaster->stop(); + result = master->stop(); return result; } -error_code DS2465::readMemory(uint_least8_t addr, uint_least8_t * buf, - size_t bufLen) const { +error_code DS2465::readMemory(uint_least8_t addr, + span<uint_least8_t> buf) const { // Read (Case A) // S AD,0 [A] MA [A] Sr AD,1 [A] [DD] A [DD] A\ P // \-----/ @@ -495,40 +443,42 @@ // MA memory address // DD memory data read - error_code result = i2cMaster->start(i2cAddress_); + error_code result = master->start(address_); if (result) { - i2cMaster->stop(); + master->stop(); return result; } - result = i2cMaster->writeByte(addr); + result = master->writeByte(addr); if (result) { - i2cMaster->stop(); + master->stop(); return result; } - result = readMemory(buf, bufLen); + result = readMemory(buf); return result; } -error_code DS2465::readMemory(uint_least8_t * buf, size_t bufLen) const { - error_code result = i2cMaster->start(i2cAddress_ | 1); +error_code DS2465::readMemory(span<uint_least8_t> buf) const { + error_code result = master->start(address_ | 1); if (result) { - i2cMaster->stop(); + master->stop(); return result; } - result = i2cMaster->readBlock(I2CMaster::Nack, buf, bufLen); + result = master->readBlock(I2CMaster::Nack, buf); if (result) { - i2cMaster->stop(); + master->stop(); return result; } - result = i2cMaster->stop(); + result = master->stop(); return result; } error_code DS2465::writeConfig(Config config) { - uint_least8_t configBuf = ((config.readByte() ^ 0xF) << 4) | config.readByte(); - error_code result = writeMemory(ConfigReg, &configBuf, 1); + const uint_least8_t configReg = 0x67; + uint_least8_t configBuf = + ((config.readByte() ^ 0xF) << 4) | config.readByte(); + error_code result = writeMemory(configReg, make_span(&configBuf, 1)); if (!result) { - result = readMemory(ConfigReg, &configBuf, 1); + result = readMemory(configReg, make_span(&configBuf, 1)); } if (!result) { if (configBuf != config.readByte()) @@ -549,29 +499,29 @@ switch (param) { case tRSTL_STD: case tRSTL_OD: - addr = tRSTL_Reg; + addr = 0x68; break; case tMSP_STD: case tMSP_OD: - addr = tMSP_Reg; + addr = 0x69; break; case tW0L_STD: case tW0L_OD: - addr = tW0L_Reg; + addr = 0x6A; break; case tREC0: - addr = tREC0_Reg; + addr = 0x6B; break; case RWPU: - addr = RWPU_Reg; + addr = 0x6C; break; case tW1L_OD: - addr = tW1L_Reg; + addr = 0x6D; break; } uint_least8_t data; - error_code result = readMemory(addr, &data, 1); + error_code result = readMemory(addr, make_span(&data, 1)); if (result) { return result; } @@ -584,7 +534,7 @@ } if (newData != data) { - result = writeMemory(addr, &newData, 1); + result = writeMemory(addr, make_span(&newData, 1)); } return result; } @@ -595,7 +545,7 @@ int pollCount = 0; uint_least8_t status; do { - error_code result = readMemory(&status, 1); + error_code result = readMemory(make_span(&status, 1)); if (result) { return result; } @@ -617,8 +567,8 @@ // Repeat until 1WB bit has changed to 0 // [] indicates from slave - uint_least8_t buf = OwResetCmd; - error_code result = writeMemory(CommandReg, &buf, 1); + uint_least8_t buf = 0xB4; + error_code result = writeMemory(commandReg, make_span(&buf, 1)); if (!result) { result = pollBusy(&buf); @@ -627,8 +577,7 @@ if (!result) { if ((buf & Status_SD) == Status_SD) { result = make_error_code(ShortDetectedError); - } - else if ((buf & Status_PPD) != Status_PPD) { + } else if ((buf & Status_PPD) != Status_PPD) { result = make_error_code(NoSlaveError); } } @@ -642,11 +591,11 @@ // [] indicates from slave // SS status byte to read to verify state - uint_least8_t buf = DeviceResetCmd; - error_code result = writeMemory(CommandReg, &buf, 1); + uint_least8_t buf = 0xF0; + error_code result = writeMemory(commandReg, make_span(&buf, 1)); if (!result) { - result = readMemory(&buf, 1); + result = readMemory(make_span(&buf, 1)); } if (!result) { @@ -662,42 +611,44 @@ return result; } -error_code DS2465::computeNextMasterSecret(const SlaveSecretData & data) { - error_code result = writeMemory(Scratchpad, data.data(), data.size()); +error_code +DS2465::computeNextMasterSecret(AuthenticationData::const_span data) { + error_code result = writeMemory(scratchpad, data); if (!result) { result = computeNextMasterSecret(false, 0, FullPage); } return result; } -error_code DS2465::computeNextMasterSecretWithSwap(const SlaveSecretData & data, - int pageNum, - PageRegion region) { - error_code result = writeMemory(Scratchpad, data.data(), data.size()); +error_code +DS2465::computeNextMasterSecretWithSwap(AuthenticationData::const_span data, + int pageNum, PageRegion region) { + error_code result = writeMemory(scratchpad, data); if (!result) { result = computeNextMasterSecret(true, pageNum, region); } return result; } -error_code DS2465::computeWriteMac(const WriteMacData & data) const { - error_code result = writeMemory(Scratchpad, data.data(), data.size()); +error_code DS2465::computeWriteMac(WriteMacData::const_span data) const { + error_code result = writeMemory(scratchpad, data); if (!result) { result = computeWriteMac(false, false, 0, 0); } return result; } -error_code DS2465::computeWriteMac(const WriteMacData & data, - Hash & mac) const { +error_code DS2465::computeWriteMac(WriteMacData::const_span data, + Hash::span mac) const { error_code result = computeWriteMac(data); if (!result) { - result = readMemory(mac.data(), mac.size()); + result = readMemory(mac); } return result; } -error_code DS2465::computeAndTransmitWriteMac(const WriteMacData & data) const { +error_code +DS2465::computeAndTransmitWriteMac(WriteMacData::const_span data) const { error_code result = computeWriteMac(data); if (!result) { result = writeMacBlock(); @@ -705,28 +656,28 @@ return result; } -error_code DS2465::computeWriteMacWithSwap(const WriteMacData & data, +error_code DS2465::computeWriteMacWithSwap(WriteMacData::const_span data, int pageNum, int segmentNum) const { - error_code result = writeMemory(Scratchpad, data.data(), data.size()); + error_code result = writeMemory(scratchpad, data); if (!result) { result = computeWriteMac(false, true, pageNum, segmentNum); } return result; } -error_code DS2465::computeWriteMacWithSwap(const WriteMacData & data, +error_code DS2465::computeWriteMacWithSwap(WriteMacData::const_span data, int pageNum, int segmentNum, - Hash & mac) const { + Hash::span mac) const { error_code result = computeWriteMacWithSwap(data, pageNum, segmentNum); if (!result) { - result = readMemory(mac.data(), mac.size()); + result = readMemory(mac); } return result; } -error_code DS2465::computeAndTransmitWriteMacWithSwap(const WriteMacData & data, - int pageNum, - int segmentNum) const { +error_code +DS2465::computeAndTransmitWriteMacWithSwap(WriteMacData::const_span data, + int pageNum, int segmentNum) const { error_code result = computeWriteMacWithSwap(data, pageNum, segmentNum); if (!result) { result = writeMacBlock(); @@ -734,40 +685,43 @@ return result; } -error_code DS2465::computeSlaveSecret(const SlaveSecretData & data) { - error_code result = writeMemory(Scratchpad, data.data(), data.size()); +error_code DS2465::computeSlaveSecret(AuthenticationData::const_span data) { + error_code result = writeMemory(scratchpad, data); if (!result) { result = computeSlaveSecret(false, 0, FullPage); } return result; } -error_code DS2465::computeSlaveSecretWithSwap(const SlaveSecretData & data, - int pageNum, PageRegion region) { - error_code result = writeMemory(Scratchpad, data.data(), data.size()); +error_code +DS2465::computeSlaveSecretWithSwap(AuthenticationData::const_span data, + int pageNum, PageRegion region) { + error_code result = writeMemory(scratchpad, data); if (!result) { result = computeSlaveSecret(true, pageNum, region); } return result; } -error_code DS2465::computeAuthMac(const AuthMacData & data) const { - error_code result = writeMemory(Scratchpad, data.data(), data.size()); +error_code DS2465::computeAuthMac(AuthenticationData::const_span data) const { + error_code result = writeMemory(scratchpad, data); if (!result) { result = computeAuthMac(false, 0, FullPage); } return result; } -error_code DS2465::computeAuthMac(const AuthMacData & data, Hash & mac) const { +error_code DS2465::computeAuthMac(AuthenticationData::const_span data, + Hash::span mac) const { error_code result = computeAuthMac(data); if (!result) { - result = readMemory(mac.data(), mac.size()); + result = readMemory(mac); } return result; } -error_code DS2465::computeAndTransmitAuthMac(const AuthMacData & data) const { +error_code +DS2465::computeAndTransmitAuthMac(AuthenticationData::const_span data) const { error_code result = computeAuthMac(data); if (!result) { result = writeMacBlock(); @@ -775,27 +729,28 @@ return result; } -error_code DS2465::computeAuthMacWithSwap(const AuthMacData & data, int pageNum, +error_code DS2465::computeAuthMacWithSwap(AuthenticationData::const_span data, + int pageNum, PageRegion region) const { - error_code result = writeMemory(Scratchpad, data.data(), data.size()); + error_code result = writeMemory(scratchpad, data); if (!result) { result = computeAuthMac(true, pageNum, region); } return result; } -error_code DS2465::computeAuthMacWithSwap(const AuthMacData & data, int pageNum, - PageRegion region, Hash & mac) const { +error_code DS2465::computeAuthMacWithSwap(AuthenticationData::const_span data, + int pageNum, PageRegion region, + Hash::span mac) const { error_code result = computeAuthMacWithSwap(data, pageNum, region); if (!result) { - result = readMemory(mac.data(), mac.size()); + result = readMemory(mac); } return result; } -error_code DS2465::computeAndTransmitAuthMacWithSwap(const AuthMacData & data, - int pageNum, - PageRegion region) const { +error_code DS2465::computeAndTransmitAuthMacWithSwap( + AuthenticationData::const_span data, int pageNum, PageRegion region) const { error_code result = computeAuthMacWithSwap(data, pageNum, region); if (!result) { result = writeMacBlock();
--- a/Devices/DS2465.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS2465.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -36,6 +36,7 @@ #include <MaximInterface/Links/I2CMaster.hpp> #include <MaximInterface/Links/OneWireMaster.hpp> #include <MaximInterface/Links/Sleep.hpp> +#include <MaximInterface/Utilities/array_span.hpp> #include <MaximInterface/Utilities/Export.h> #include <MaximInterface/Utilities/Sha256.hpp> @@ -46,7 +47,7 @@ public: enum ErrorValue { HardwareError = 1, ArgumentOutOfRangeError }; - /// 1-Wire port adjustment parameters. + /// @brief 1-Wire port adjustment parameters. /// @note See datasheet page 13. enum PortParameter { tRSTL_STD, @@ -64,13 +65,13 @@ enum PageRegion { FullPage = 0x03, FirstHalf = 0x01, SecondHalf = 0x02 }; /// Holds the contents of a device memory segment. - typedef array<uint_least8_t, 4> Segment; + typedef array_span<uint_least8_t, 4> Segment; /// Holds the contents of a device memory page. - typedef array<uint_least8_t, 32> Page; + typedef array_span<uint_least8_t, 32> Page; static const int memoryPages = 2; - static const int segmentsPerPage = Page::csize / Segment::csize; + static const int segmentsPerPage = Page::size / Segment::size; /// Represents a DS2465 configuration. class Config { @@ -79,52 +80,80 @@ explicit Config(uint_least8_t readByte = optionAPU) : readByte_(readByte & 0xF) {} + /// @name 1WS + /// @brief 1-Wire Speed /// @{ - /// 1-Wire Speed + + /// Get 1WS bit. bool get1WS() const { return (readByte_ & option1WS) == option1WS; } - void set1WS(bool new1WS) { + + /// Set 1WS bit. + Config & set1WS(bool new1WS) { if (new1WS) { readByte_ |= option1WS; } else { readByte_ &= ~option1WS; } + return *this; } + /// @} + /// @name SPU + /// @brief Strong Pullup /// @{ - /// Strong Pullup + + /// Get SPU bit. bool getSPU() const { return (readByte_ & optionSPU) == optionSPU; } - void setSPU(bool newSPU) { + + /// Set SPU bit. + Config & setSPU(bool newSPU) { if (newSPU) { readByte_ |= optionSPU; } else { readByte_ &= ~optionSPU; } + return *this; } + /// @} + /// @name PDN + /// @brief 1-Wire Power Down /// @{ - /// 1-Wire Power Down + + /// Get PDN bit. bool getPDN() const { return (readByte_ & optionPDN) == optionPDN; } - void setPDN(bool newPDN) { + + /// Set PDN bit. + Config & setPDN(bool newPDN) { if (newPDN) { readByte_ |= optionPDN; } else { readByte_ &= ~optionPDN; } + return *this; } + /// @} + /// @name APU + /// @brief Active Pullup /// @{ - /// Active Pullup + + /// Get APU bit. bool getAPU() const { return (readByte_ & optionAPU) == optionAPU; } - void setAPU(bool newAPU) { + + /// Set APU bit. + Config & setAPU(bool newAPU) { if (newAPU) { readByte_ |= optionAPU; } else { readByte_ &= ~optionAPU; } + return *this; } + /// @} /// Byte representation that is read from the DS2465. @@ -143,196 +172,213 @@ // affect the state of the 1-Wire bus. Read pointer, scratchpad, MAC output // register, and command register on the DS2465 are considered mutable. - DS2465(const Sleep & sleep, I2CMaster & i2cMaster, - uint_least8_t i2cAddress = 0x30) - : sleep(&sleep), i2cMaster(&i2cMaster), i2cAddress_(i2cAddress & 0xFE) {} + DS2465(Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x30) + : sleep(&sleep), master(&master), address_(address & 0xFE) {} - void setSleep(const Sleep & sleep) { this->sleep = &sleep; } - void setI2CMaster(I2CMaster & i2cMaster) { this->i2cMaster = &i2cMaster; } - uint_least8_t i2cAddress() const { return i2cAddress_; } - void setI2CAddress(uint_least8_t i2cAddress) { - this->i2cAddress_ = (i2cAddress & 0xFE); - } + void setSleep(Sleep & sleep) { this->sleep = &sleep; } + + void setMaster(I2CMaster & master) { this->master = &master; } + + uint_least8_t address() const { return address_; } + + void setAddress(uint_least8_t address) { address_ = address & 0xFE; } /// Initialize hardware for use. MaximInterface_EXPORT error_code initialize(Config config = Config()); - /// Write a new configuration to the DS2465. + /// @brief Write a new configuration to the DS2465. /// @param[in] config New configuration to write. MaximInterface_EXPORT error_code writeConfig(Config config); - /// Write a new port configuration parameter to the DS2465. + /// @brief Write a new port configuration parameter to the DS2465. /// @param[in] param Parameter to adjust. - /// @param[in] val New parameter value to set. Consult datasheet for value - /// mappings. + /// @param[in] val + /// New parameter value to set. Consult datasheet for value mappings. MaximInterface_EXPORT error_code writePortParameter(PortParameter param, int val); // 1-Wire Master Commands MaximInterface_EXPORT virtual error_code reset(); + MaximInterface_EXPORT virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel); + MaximInterface_EXPORT virtual error_code readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterface_EXPORT virtual error_code writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); - MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * recvBuf, - size_t recvLen); + + MaximInterface_EXPORT virtual error_code + readBlock(span<uint_least8_t> recvBuf); + MaximInterface_EXPORT virtual error_code - writeBlock(const uint_least8_t * sendBuf, size_t sendLen); + writeBlock(span<const uint_least8_t> sendBuf); + MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed); - /// @note The DS2465 only supports enabling strong pullup following a 1-Wire - /// read or write operation. + + /// @copydoc OneWireMaster::setLevel + /// @note + /// The DS2465 only supports enabling strong pullup following a 1-Wire read or + /// write operation. MaximInterface_EXPORT virtual error_code setLevel(Level newLevel); + MaximInterface_EXPORT virtual error_code triplet(TripletData & data); // DS2465 Coprocessor Commands - - /// Read data from an EEPROM memory page. + + /// @brief Read data from an EEPROM memory page. /// @param pageNum Page number to read from. - MaximInterface_EXPORT error_code readPage(int pageNum, Page & data) const; + /// @param[out] data Data that was read. + MaximInterface_EXPORT error_code readPage(int pageNum, Page::span data) const; - /// Write data to an EEPROM memory page. + /// @brief Write data to an EEPROM memory page. /// @param pageNum Page number to copy to. - MaximInterface_EXPORT error_code writePage(int pageNum, const Page & data); + /// @param data Data to write. + MaximInterface_EXPORT error_code writePage(int pageNum, + Page::const_span data); - /// Write data to an EEPROM memory segment. + /// @brief Write data to an EEPROM memory segment. /// @param pageNum Page number to copy to. /// @param segmentNum Segment number to copy to. + /// @param data Data to write. MaximInterface_EXPORT error_code writeSegment(int pageNum, int segmentNum, - const Segment & data); + Segment::const_span data); /// Write data to the secret EEPROM memory page. MaximInterface_EXPORT error_code - writeMasterSecret(const Sha256::Hash & masterSecret); + writeMasterSecret(Sha256::Hash::const_span masterSecret); - /// Compute Next Master Secret. + /// @brief Compute Next Master Secret. /// @param data Combined data fields for computation. MaximInterface_EXPORT error_code - computeNextMasterSecret(const Sha256::SlaveSecretData & data); + computeNextMasterSecret(Sha256::AuthenticationData::const_span data); - /// Compute Next Master Secret with page swapping. + /// @brief Compute Next Master Secret with page swapping. /// @param data Combined data fields for computation. /// @param pageNum Page number to swap in. /// @param region Region of the page to swap in. - MaximInterface_EXPORT error_code computeNextMasterSecretWithSwap( - const Sha256::SlaveSecretData & data, int pageNum, PageRegion region); + MaximInterface_EXPORT error_code + computeNextMasterSecretWithSwap(Sha256::AuthenticationData::const_span data, + int pageNum, PageRegion region); - /// Compute Write MAC. + /// @brief Compute Write MAC. /// @param data Combined data fields for computation. /// @param[out] mac Computed Write MAC. - MaximInterface_EXPORT error_code - computeWriteMac(const Sha256::WriteMacData & data, Sha256::Hash & mac) const; + MaximInterface_EXPORT error_code computeWriteMac( + Sha256::WriteMacData::const_span data, Sha256::Hash::span mac) const; - /// Compute Write MAC. + /// @brief Compute Write MAC. /// @param data Combined data fields for computation. MaximInterface_EXPORT error_code - computeAndTransmitWriteMac(const Sha256::WriteMacData & data) const; + computeAndTransmitWriteMac(Sha256::WriteMacData::const_span data) const; - /// Compute Write MAC with page swapping. + /// @brief Compute Write MAC with page swapping. /// @param data Combined data fields for computation. /// @param pageNum Page number to swap in. /// @param segmentNum Segment number to swap in. /// @param[out] mac Computed Write MAC. MaximInterface_EXPORT error_code - computeWriteMacWithSwap(const Sha256::WriteMacData & data, int pageNum, - int segmentNum, Sha256::Hash & mac) const; + computeWriteMacWithSwap(Sha256::WriteMacData::const_span data, int pageNum, + int segmentNum, Sha256::Hash::span mac) const; - /// Compute Write MAC with page swapping. + /// @brief Compute Write MAC with page swapping. /// @param data Combined data fields for computation. /// @param pageNum Page number to swap in. /// @param segmentNum Segment number to swap in. MaximInterface_EXPORT error_code computeAndTransmitWriteMacWithSwap( - const Sha256::WriteMacData & data, int pageNum, int segmentNum) const; + Sha256::WriteMacData::const_span data, int pageNum, int segmentNum) const; - /// Compute Slave Secret (S-Secret). + /// @brief Compute Slave Secret (S-Secret). /// @param data Combined data fields for computation. MaximInterface_EXPORT error_code - computeSlaveSecret(const Sha256::SlaveSecretData & data); + computeSlaveSecret(Sha256::AuthenticationData::const_span data); - /// Compute Slave Secret (S-Secret) with page swapping. + /// @brief Compute Slave Secret (S-Secret) with page swapping. /// @param data Combined data fields for computation. /// @param pageNum Page number to swap in. /// @param region Region of the page to swap in. - MaximInterface_EXPORT error_code computeSlaveSecretWithSwap( - const Sha256::SlaveSecretData & data, int pageNum, PageRegion region); + MaximInterface_EXPORT error_code + computeSlaveSecretWithSwap(Sha256::AuthenticationData::const_span data, + int pageNum, PageRegion region); - /// Compute Authentication MAC. + /// @brief Compute Authentication MAC. /// @param data Combined data fields for computation. /// @param[out] mac Computed Auth MAC. MaximInterface_EXPORT error_code - computeAuthMac(const Sha256::AuthMacData & data, Sha256::Hash & mac) const; + computeAuthMac(Sha256::AuthenticationData::const_span data, + Sha256::Hash::span mac) const; - /// Compute Authentication MAC. + /// @brief Compute Authentication MAC. /// @param data Combined data fields for computation. MaximInterface_EXPORT error_code - computeAndTransmitAuthMac(const Sha256::AuthMacData & data) const; + computeAndTransmitAuthMac(Sha256::AuthenticationData::const_span data) const; - /// Compute Authentication MAC with page swapping. + /// @brief Compute Authentication MAC with page swapping. /// @param data Combined data fields for computation. /// @param pageNum Page number to swap in. /// @param region Region of the page to swap in. /// @param[out] mac Computed Auth MAC. - MaximInterface_EXPORT error_code - computeAuthMacWithSwap(const Sha256::AuthMacData & data, int pageNum, - PageRegion region, Sha256::Hash & mac) const; + MaximInterface_EXPORT error_code computeAuthMacWithSwap( + Sha256::AuthenticationData::const_span data, int pageNum, + PageRegion region, Sha256::Hash::span mac) const; - /// Compute Authentication MAC with page swapping. + /// @brief Compute Authentication MAC with page swapping. /// @param data Combined data fields for computation. /// @param pageNum Page number to swap in. /// @param region Region of the page to swap in. - MaximInterface_EXPORT error_code computeAndTransmitAuthMacWithSwap( - const Sha256::AuthMacData & data, int pageNum, PageRegion region) const; + MaximInterface_EXPORT error_code + computeAndTransmitAuthMacWithSwap(Sha256::AuthenticationData::const_span data, + int pageNum, PageRegion region) const; MaximInterface_EXPORT static const error_category & errorCategory(); private: const Sleep * sleep; - I2CMaster * i2cMaster; - uint_least8_t i2cAddress_; + I2CMaster * master; + uint_least8_t address_; Config curConfig; - /// Performs a soft reset on the DS2465. + /// @brief Performs a soft reset on the DS2465. /// @note This is not a 1-Wire Reset. error_code resetDevice(); - /// Polls the DS2465 status waiting for the 1-Wire Busy bit (1WB) to be cleared. + /// @brief + /// Polls the DS2465 status waiting for the 1-Wire Busy bit (1WB) to be + /// cleared. /// @param[out] pStatus Optionally retrive the status byte when 1WB cleared. /// @returns Success or TimeoutError if poll limit reached. error_code pollBusy(uint_least8_t * pStatus = NULL) const; - /// Ensure that the desired 1-Wire level is set in the configuration. + /// @brief Ensure that the desired 1-Wire level is set in the configuration. /// @param level Desired 1-Wire level. error_code configureLevel(Level level); - /// Const since only for internal use. - error_code writeMemory(uint_least8_t addr, const uint_least8_t * buf, - size_t bufLen) const; + /// @note Const since only for internal use. + error_code writeMemory(uint_least8_t addr, + span<const uint_least8_t> buf) const; - /// Read memory from the DS2465. + /// @brief Read memory from the DS2465. /// @param addr Address to begin reading from. /// @param[out] buf Buffer to hold read data. - /// @param bufLen Length of buffer, buf, and number of bytes to read. - error_code readMemory(uint_least8_t addr, uint_least8_t * buf, - size_t bufLen) const; + error_code readMemory(uint_least8_t addr, span<uint_least8_t> buf) const; - /// Read memory from the DS2465 at the current pointer. + /// @brief Read memory from the DS2465 at the current pointer. /// @param[out] buf Buffer to hold read data. - /// @param bufLen Length of buffer, buf, and number of bytes to read. - error_code readMemory(uint_least8_t * buf, size_t bufLen) const; + error_code readMemory(span<uint_least8_t> buf) const; /// Write the last computed MAC to the 1-Wire bus. error_code writeMacBlock() const; - error_code computeWriteMac(const Sha256::WriteMacData & data) const; + error_code computeWriteMac(Sha256::WriteMacData::const_span data) const; - error_code computeWriteMacWithSwap(const Sha256::WriteMacData & data, + error_code computeWriteMacWithSwap(Sha256::WriteMacData::const_span data, int pageNum, int segmentNum) const; - error_code computeAuthMac(const Sha256::AuthMacData & data) const; + error_code computeAuthMac(Sha256::AuthenticationData::const_span data) const; - error_code computeAuthMacWithSwap(const Sha256::AuthMacData & data, + error_code computeAuthMacWithSwap(Sha256::AuthenticationData::const_span data, int pageNum, PageRegion region) const; // Legacy implementations
--- a/Devices/DS2480B.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS2480B.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -160,516 +160,23 @@ #define PARMSET_PullUp3p0us 0x0C #define PARMSET_PullUp3p5us 0x0E +// Baud rate bits +#define PARMSET_9600 0x00 +#define PARMSET_19200 0x02 +#define PARMSET_57600 0x04 +#define PARMSET_115200 0x06 + // DS2480B program voltage available #define DS2480BPROG_MASK 0x20 namespace MaximInterface { error_code DS2480B::initialize() { - // reset modes level = NormalLevel; - baud = Baud9600bps; mode = MODSEL_COMMAND; - speed = SPEEDSEL_FLEX; - - // set the baud rate to 9600 - error_code result = setComBaud(baud); - if (result) { - return result; - } - - // send a break to reset the DS2480B - result = breakCom(); - if (result) { - return result; - } - - // delay to let line settle - (*sleep)(2); - - // flush the buffers - result = uart->clearReadBuffer(); - if (result) { - return result; - } - - // send the timing byte - uint_least8_t packet[5]; - packet[0] = 0xC1; - result = uart->writeBlock(packet, 1); - if (result) { - return result; - } - - // delay to let line settle - (*sleep)(2); - - // set the FLEX configuration parameters - // default PDSRC = 1.37Vus - int packetLen = 0; - packet[packetLen++] = CMD_CONFIG | PARMSEL_SLEW | PARMSET_Slew1p37Vus; - // default W1LT = 10us - packet[packetLen++] = CMD_CONFIG | PARMSEL_WRITE1LOW | PARMSET_Write10us; - // default DSO/WORT = 8us - packet[packetLen++] = CMD_CONFIG | PARMSEL_SAMPLEOFFSET | PARMSET_SampOff8us; - - // construct the command to read the baud rate (to test command block) - packet[packetLen++] = CMD_CONFIG | PARMSEL_PARMREAD | (PARMSEL_BAUDRATE >> 3); - - // also do 1 bit operation (to test 1-Wire block) - packet[packetLen++] = CMD_COMM | FUNCTSEL_BIT | baud | BITPOL_ONE; - - // flush the buffers - result = uart->clearReadBuffer(); - if (result) { - return result; - } - - // send the packet - result = uart->writeBlock(packet, packetLen); - if (result) { - return result; - } - - // read back the response - result = uart->readBlock(packet, sizeof(packet) / sizeof(packet[0])); - if (result) { - return result; - } - - // look at the baud rate and bit operation - // to see if the response makes sense - if (!(((packet[3] & 0xF1) == 0x00) && ((packet[3] & 0x0E) == baud) && - ((packet[4] & 0xF0) == 0x90) && ((packet[4] & 0x0C) == baud))) { - result = make_error_code(HardwareError); - } - - return result; -} - -error_code DS2480B::reset() { - uint_least8_t packet[2]; - int packetLen = 0; - - // check for correct mode - if (mode != MODSEL_COMMAND) { - mode = MODSEL_COMMAND; - packet[packetLen++] = MODE_COMMAND; - } - - // construct the command - packet[packetLen++] = (CMD_COMM | FUNCTSEL_RESET | speed); - - // flush the buffers - error_code result = uart->clearReadBuffer(); - if (result) { - return result; - } - - // send the packet - result = uart->writeBlock(packet, packetLen); - if (result) { - return result; - } - - // read back the 1 byte response - result = uart->readBlock(packet, 1); - if (result) { - return result; - } - - // make sure this byte looks like a reset byte - if ((packet[0] & RB_RESET_MASK) == RB_1WIRESHORT) { - result = make_error_code(ShortDetectedError); - } - else if ((packet[0] & RB_RESET_MASK) == RB_NOPRESENCE) { - result = make_error_code(NoSlaveError); - } - - return result; -} - -error_code DS2480B::touchBitSetLevel(bool & sendRecvBit, Level afterLevel) { - uint_least8_t packet[2]; - int packetLen = 0; - - // check for correct mode - if (mode != MODSEL_COMMAND) { - mode = MODSEL_COMMAND; - packet[packetLen++] = MODE_COMMAND; - } - - // construct the command - packet[packetLen++] = (sendRecvBit ? BITPOL_ONE : BITPOL_ZERO) | CMD_COMM | - FUNCTSEL_BIT | speed; - - // flush the buffers - error_code result = uart->clearReadBuffer(); - if (result) { - return result; - } - - // send the packet - result = uart->writeBlock(packet, packetLen); - if (result) { - return result; - } - - // read back the response - result = uart->readBlock(packet, 1); - if (result) { - return result; - } - - // interpret the response - if ((packet[0] & 0xE0) == 0x80) { - sendRecvBit = ((packet[0] & RB_BIT_MASK) == RB_BIT_ONE); - result = setLevel(afterLevel); - } else { - result = make_error_code(HardwareError); - } - - return result; -} - -error_code DS2480B::writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel) { - uint_least8_t packet[3]; - int packetLen = 0; - - // check for correct mode - if (mode != MODSEL_DATA) { - mode = MODSEL_DATA; - packet[packetLen++] = MODE_DATA; - } - - // add the byte to send - packet[packetLen++] = sendByte; - - // check for duplication of data that looks like COMMAND mode - if (sendByte == MODE_COMMAND) { - packet[packetLen++] = sendByte; - } - - // flush the buffers - error_code result = uart->clearReadBuffer(); - if (result) { - return result; - } - - // send the packet - result = uart->writeBlock(packet, packetLen); - if (result) { - return result; - } - - // read back the 1 byte response - result = uart->readBlock(packet, 1); - if (result) { - return result; - } - - if (packet[0] == sendByte) { - result = setLevel(afterLevel); - } else { - result = make_error_code(HardwareError); - } - - return result; -} - -error_code DS2480B::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { - uint_least8_t packet[2]; - int packetLen = 0; - - // check for correct mode - if (mode != MODSEL_DATA) { - mode = MODSEL_DATA; - packet[packetLen++] = MODE_DATA; - } - - // add the byte to send - packet[packetLen++] = 0xFF; - - // flush the buffers - error_code result = uart->clearReadBuffer(); - if (result) { - return result; - } - - // send the packet - result = uart->writeBlock(packet, packetLen); - if (result) { - return result; - } - - // read back the 1 byte response - result = uart->readBlock(packet, 1); - if (result) { - return result; - } - - recvByte = packet[0]; - result = setLevel(afterLevel); - - return result; -} + speed = SPEEDSEL_STD; -error_code DS2480B::setSpeed(Speed newSpeed) { - error_code result; - bool setSpeed = false; - - // check if supported speed - switch (newSpeed) { - case OverdriveSpeed: - // check if change from current mode - if (speed != SPEEDSEL_OD) { - result = changeBaud(Baud115200bps); - if (!result) { - speed = SPEEDSEL_OD; - setSpeed = true; - } - } - break; - - case StandardSpeed: - // check if change from current mode - if (speed != SPEEDSEL_STD) { - result = changeBaud(Baud9600bps); - if (!result) { - speed = SPEEDSEL_STD; - setSpeed = true; - } - } - break; - - default: - result = make_error_code(InvalidSpeedError); - break; - } - - // if baud rate is set correctly then change DS2480 speed - if (setSpeed) { - uint_least8_t packet[2]; - int packetLen = 0; - - // check if correct mode - if (mode != MODSEL_COMMAND) { - mode = MODSEL_COMMAND; - packet[packetLen++] = MODE_COMMAND; - } - - // proceed to set the DS2480 communication speed - packet[packetLen++] = CMD_COMM | FUNCTSEL_SEARCHOFF | speed; - - // send the packet - result = uart->writeBlock(packet, packetLen); - } - - return result; -} - -error_code DS2480B::setLevel(Level newLevel) { - error_code result; - // check if need to change level - if (newLevel != level) { - uint_least8_t packet[4]; - int packetLen = 0; - - // check for correct mode - if (mode != MODSEL_COMMAND) { - mode = MODSEL_COMMAND; - packet[packetLen++] = MODE_COMMAND; - } - - switch (newLevel) { - case NormalLevel: - // stop pulse command - packet[packetLen++] = MODE_STOP_PULSE; - - // add the command to begin the pulse WITHOUT prime - packet[packetLen++] = CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | - BITPOL_5V | PRIME5V_FALSE; - - // stop pulse command - packet[packetLen++] = MODE_STOP_PULSE; - - // flush the buffers - result = uart->clearReadBuffer(); - if (result) { - return result; - } - - // send the packet - result = uart->writeBlock(packet, packetLen); - if (result) { - return result; - } - - // read back the 1 byte response - result = uart->readBlock(packet, 2); - if (result) { - return result; - } - - // check response byte - if (((packet[0] & 0xE0) == 0xE0) && ((packet[1] & 0xE0) == 0xE0)) { - level = NormalLevel; - } else { - result = make_error_code(HardwareError); - } - break; - - case StrongLevel: - // set the SPUD time value - packet[packetLen++] = CMD_CONFIG | PARMSEL_5VPULSE | PARMSET_infinite; - // add the command to begin the pulse - packet[packetLen++] = - CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V; - - // flush the buffers - result = uart->clearReadBuffer(); - if (result) { - return result; - } - - // send the packet - result = uart->writeBlock(packet, packetLen); - if (result) { - return result; - } - - // read back the 1 byte response from setting time limit - result = uart->readBlock(packet, 1); - if (result) { - return result; - } - - // check response byte - if ((packet[0] & 0x81) == 0) { - level = newLevel; - } else { - result = make_error_code(HardwareError); - } - break; - - default: - result = make_error_code(InvalidLevelError); - break; - } - } - return result; -} - -error_code DS2480B::sendCommand(uint_least8_t command) { - uint_least8_t packet[2]; - int packetLen = 0; - - // check for correct mode - if (mode != MODSEL_COMMAND) { - mode = MODSEL_COMMAND; - packet[packetLen++] = MODE_COMMAND; - } - - // add command - packet[packetLen++] = command; - - // send the packet - return uart->writeBlock(packet, packetLen); -} - -error_code DS2480B::changeBaud(BaudRate newBaud) { - error_code result; - - //see if different then current baud rate - if (baud != newBaud) { - uint_least8_t packet[2]; - int packetLen = 0; - - // build the command packet - // check for correct mode - if (mode != MODSEL_COMMAND) { - mode = MODSEL_COMMAND; - packet[packetLen++] = MODE_COMMAND; - } - // build the command - const uint_least8_t baudByte = CMD_CONFIG | PARMSEL_BAUDRATE | newBaud; - packet[packetLen++] = baudByte; - - // flush the buffers - result = uart->clearReadBuffer(); - if (result) { - return result; - } - - // send the packet - result = uart->writeBlock(packet, packetLen); - if (result) { - return result; - } - - // make sure buffer is flushed - (*sleep)(5); - - // change our baud rate - result = setComBaud(newBaud); - if (result) { - return result; - } - baud = newBaud; - - // wait for things to settle - (*sleep)(5); - - // build a command packet to read back baud rate - packet[0] = CMD_CONFIG | PARMSEL_PARMREAD | (PARMSEL_BAUDRATE >> 3); - - // flush the buffers - result = uart->clearReadBuffer(); - if (result) { - return result; - } - - // send the packet - result = uart->writeBlock(packet, 1); - if (result) { - return result; - } - - // read back the 1 byte response - result = uart->readBlock(packet, 1); - if (result) { - return result; - } - - // verify correct baud - if (!((packet[0] & 0x0E) == (baudByte & 0x0E))) { - result = make_error_code(HardwareError); - } - } - - return result; -} - -error_code DS2480B::setComBaud(BaudRate newBaud) { - switch (newBaud) { - case Baud115200bps: - return uart->setBaudRate(115200); - - case Baud57600bps: - return uart->setBaudRate(57600); - - case Baud19200bps: - return uart->setBaudRate(19200); - - case Baud9600bps: - default: - return uart->setBaudRate(9600); - } -} - -error_code DS2480B::breakCom() { + // Send a break to reset the DS2480B. // Switch to lower baud rate to ensure break is longer than 2 ms. error_code result = uart->setBaudRate(4800); if (result) { @@ -679,10 +186,358 @@ if (result) { return result; } - result = setComBaud(baud); + result = uart->setBaudRate(9600); + if (result) { + return result; + } + + // Wait for master reset. + sleep->invoke(1); + + // Flush the read buffer. + result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // Send the timing byte. + result = uart->writeByte(CMD_COMM | FUNCTSEL_RESET | SPEEDSEL_STD); + if (result) { + return result; + } + + // Change the DS2480 baud rate. + result = uart->writeByte(CMD_CONFIG | PARMSEL_BAUDRATE | PARMSET_115200); + if (result) { + return result; + } + + // Change our baud rate. + result = uart->setBaudRate(115200); + if (result) { + return result; + } + + uint_least8_t response; + + // Verify response. + result = uart->readByte(response); + if (result) { + return result; + } + if ((response & (PARMSEL_MASK | PARMSET_MASK)) != + (PARMSEL_BAUDRATE | PARMSET_115200)) { + return make_error_code(HardwareError); + } + + // Set the SPUD time value. + result = uart->writeByte(CMD_CONFIG | PARMSEL_5VPULSE | PARMSET_infinite); + if (result) { + return result; + } + + // Verify response. + result = uart->readByte(response); + if (result) { + return result; + } + if ((response & (PARMSEL_MASK | PARMSET_MASK)) != + (PARMSEL_5VPULSE | PARMSET_infinite)) { + return make_error_code(HardwareError); + } + + return result; +} + +error_code DS2480B::reset() { + if (level != NormalLevel) { + return make_error_code(InvalidLevelError); + } + + uint_least8_t packet[2]; + int packetLen = 0; + + // Check for correct mode. + if (mode != MODSEL_COMMAND) { + mode = MODSEL_COMMAND; + packet[packetLen++] = MODE_COMMAND; + } + + // Construct the command. + packet[packetLen++] = CMD_COMM | FUNCTSEL_RESET | speed; + + // Send the packet. + error_code result = uart->writeBlock(make_span(packet, packetLen)); + if (result) { + return result; + } + + // Read back the response. + result = uart->readByte(packet[0]); + if (result) { + return result; + } + + // Make sure this byte looks like a reset byte. + if ((packet[0] & RB_RESET_MASK) == RB_1WIRESHORT) { + result = make_error_code(ShortDetectedError); + } else if ((packet[0] & RB_RESET_MASK) == RB_NOPRESENCE) { + result = make_error_code(NoSlaveError); + } + return result; +} + +error_code DS2480B::touchBitSetLevel(bool & sendRecvBit, Level afterLevel) { + if (level != NormalLevel) { + return make_error_code(InvalidLevelError); + } + + uint_least8_t packet[3]; + int packetLen = 0; + + // Check for correct mode. + if (mode != MODSEL_COMMAND) { + mode = MODSEL_COMMAND; + packet[packetLen++] = MODE_COMMAND; + } + + // Construct the command. + packet[packetLen++] = CMD_COMM | FUNCTSEL_BIT | + (sendRecvBit ? BITPOL_ONE : BITPOL_ZERO) | speed; + switch (afterLevel) { + case NormalLevel: + break; + + case StrongLevel: + // Add the command to begin the pulse. + packet[packetLen++] = + CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V | PRIME5V_FALSE; + break; + + default: + return make_error_code(InvalidLevelError); + } + + // Send the packet. + error_code result = uart->writeBlock(make_span(packet, packetLen)); + if (result) { + return result; + } + + // Read back the response. + result = uart->readByte(packet[0]); + if (result) { + return result; + } + + // Interpret the response. + if ((packet[0] & 0xE0) == 0x80) { + sendRecvBit = ((packet[0] & RB_BIT_MASK) == RB_BIT_ONE); + level = afterLevel; + } else { + result = make_error_code(HardwareError); + } return result; } +error_code DS2480B::writeByteSetLevel(uint_least8_t sendByte, + Level afterLevel) { + if (level != NormalLevel) { + return make_error_code(InvalidLevelError); + } + + switch (afterLevel) { + case NormalLevel: + break; + + case StrongLevel: + return OneWireMaster::writeByteSetLevel(sendByte, afterLevel); + + default: + return make_error_code(InvalidLevelError); + } + + uint_least8_t packet[3]; + int packetLen = 0; + + // Check for correct mode. + if (mode != MODSEL_DATA) { + mode = MODSEL_DATA; + packet[packetLen++] = MODE_DATA; + } + + // Add the byte to send. + packet[packetLen++] = sendByte; + + // Check for duplication of data that looks like COMMAND mode. + if (sendByte == MODE_COMMAND) { + packet[packetLen++] = sendByte; + } + + // Send the packet. + error_code result = uart->writeBlock(make_span(packet, packetLen)); + if (result) { + return result; + } + + // Read back the response. + result = uart->readByte(packet[0]); + if (result) { + return result; + } + + // Interpret the response. + if (packet[0] != sendByte) { + result = make_error_code(HardwareError); + } + return result; +} + +error_code DS2480B::readByteSetLevel(uint_least8_t & recvByte, + Level afterLevel) { + if (level != NormalLevel) { + return make_error_code(InvalidLevelError); + } + + switch (afterLevel) { + case NormalLevel: + break; + + case StrongLevel: + return OneWireMaster::readByteSetLevel(recvByte, afterLevel); + + default: + return make_error_code(InvalidLevelError); + } + + uint_least8_t packet[2]; + int packetLen = 0; + + // Check for correct mode. + if (mode != MODSEL_DATA) { + mode = MODSEL_DATA; + packet[packetLen++] = MODE_DATA; + } + + // Add the byte to send. + packet[packetLen++] = 0xFF; + + // Send the packet. + error_code result = uart->writeBlock(make_span(packet, packetLen)); + if (result) { + return result; + } + + // Read back the response. + result = uart->readByte(recvByte); + return result; +} + +error_code DS2480B::setSpeed(Speed newSpeed) { + uint_least8_t newSpeedByte; + switch (newSpeed) { + case OverdriveSpeed: + newSpeedByte = SPEEDSEL_OD; + break; + + case StandardSpeed: + newSpeedByte = SPEEDSEL_STD; + break; + + default: + return make_error_code(InvalidSpeedError); + } + if (speed == newSpeedByte) { + return error_code(); + } + speed = newSpeedByte; + + uint_least8_t packet[2]; + int packetLen = 0; + + // Check for correct mode. + if (mode != MODSEL_COMMAND) { + mode = MODSEL_COMMAND; + packet[packetLen++] = MODE_COMMAND; + } + + // Change DS2480 speed. + packet[packetLen++] = CMD_COMM | FUNCTSEL_SEARCHOFF | speed; + + // Send the packet. + return uart->writeBlock(make_span(packet, packetLen)); +} + +error_code DS2480B::setLevel(Level newLevel) { + if (level == newLevel) { + return error_code(); + } + + uint_least8_t packet[2]; + int packetLen = 0; + + switch (newLevel) { + case NormalLevel: + // Stop pulse command. + packet[packetLen++] = MODE_STOP_PULSE; + break; + + case StrongLevel: + // Check for correct mode. + if (mode != MODSEL_COMMAND) { + mode = MODSEL_COMMAND; + packet[packetLen++] = MODE_COMMAND; + } + + // Add the command to begin the pulse. + packet[packetLen++] = + CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V | PRIME5V_FALSE; + break; + + default: + return make_error_code(InvalidLevelError); + } + + // Send the packet. + error_code result = uart->writeBlock(make_span(packet, packetLen)); + if (result) { + return result; + } + + if (newLevel == NormalLevel) { + // Read back the response. + result = uart->readByte(packet[0]); + if (result) { + return result; + } + + // Interpret the response. + if ((packet[0] & 0xE0) != 0xE0) { + return make_error_code(HardwareError); + } + } + + level = newLevel; + return result; +} + +error_code DS2480B::sendCommand(uint_least8_t command) { + uint_least8_t packet[2]; + int packetLen = 0; + + // Check for correct mode. + if (mode != MODSEL_COMMAND) { + mode = MODSEL_COMMAND; + packet[packetLen++] = MODE_COMMAND; + } + + // Add command. + packet[packetLen++] = command; + + // Send the packet. + return uart->writeBlock(make_span(packet, packetLen)); +} + const error_category & DS2480B::errorCategory() { static class : public error_category { public:
--- a/Devices/DS2480B.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS2480B.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -43,25 +43,28 @@ /// Serial to 1-Wire Line Driver class DS2480B : public OneWireMaster { public: - enum ErrorValue { - HardwareError = 1 - }; + enum ErrorValue { HardwareError = 1 }; - DS2480B(const Sleep & sleep, Uart & uart) : sleep(&sleep), uart(&uart) {} + DS2480B(Sleep & sleep, Uart & uart) : sleep(&sleep), uart(&uart) {} - void setSleep(const Sleep & sleep) { this->sleep = &sleep; } + void setSleep(Sleep & sleep) { this->sleep = &sleep; } void setUart(Uart & uart) { this->uart = &uart; } MaximInterface_EXPORT error_code initialize(); MaximInterface_EXPORT virtual error_code reset(); + MaximInterface_EXPORT virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel); + MaximInterface_EXPORT virtual error_code writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); + MaximInterface_EXPORT virtual error_code readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed); + MaximInterface_EXPORT virtual error_code setLevel(Level newLevel); MaximInterface_EXPORT static const error_category & errorCategory(); @@ -70,23 +73,10 @@ MaximInterface_EXPORT error_code sendCommand(uint_least8_t command); private: - /// Baud rates for DS2480B - enum BaudRate { - Baud9600bps = 0, ///< 9600 bps - Baud19200bps = 2, ///< 19200 bps - Baud57600bps = 4, ///< 57600 bps - Baud115200bps = 6 ///< 115200 bps - }; - - error_code changeBaud(BaudRate newBaud); - error_code setComBaud(BaudRate newBaud); - error_code breakCom(); - const Sleep * sleep; Uart * uart; Level level; - BaudRate baud; uint_least8_t mode; uint_least8_t speed; };
--- a/Devices/DS2482_DS2484.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS2482_DS2484.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,26 +35,6 @@ namespace MaximInterface { -enum Command { - DeviceResetCmd = 0xF0, - WriteDeviceConfigCmd = 0xD2, - AdjustOwPortCmd = 0xC3, // DS2484 only - ChannelSelectCmd = 0xC3, // DS2482-800 only - SetReadPointerCmd = 0xE1, - OwResetCmd = 0xB4, - OwWriteByteCmd = 0xA5, - OwReadByteCmd = 0x96, - OwSingleBitCmd = 0x87, - OwTripletCmd = 0x78 -}; - -// Device register pointers. -enum Register { - ConfigReg = 0xC3, - StatusReg = 0xF0, - ReadDataReg = 0xE1 -}; - // Device Status bits enum StatusBit { Status_1WB = 0x01, @@ -68,13 +48,11 @@ }; error_code DS2482_DS2484::initialize(Config config) { - // reset device error_code result = resetDevice(); if (result) { return result; } - - // write the default configuration setup + // Write the default configuration setup. result = writeConfig(config); return result; } @@ -85,23 +63,24 @@ // [] indicates from slave // SS status byte to read to verify state - uint_least8_t buf; - error_code result = sendCommand(DeviceResetCmd); - - if (!result) { - result = readRegister(buf); + error_code result = sendCommand(0xF0); + if (result) { + return result; } - if (!result) { - if ((buf & 0xF7) != 0x10) { - result = make_error_code(HardwareError); - } + uint_least8_t buf; + result = readRegister(buf); + if (result) { + return result; } - if (!result) { - reset(); // do a command to get 1-Wire master reset out of holding state + if ((buf & 0xF7) != 0x10) { + return make_error_code(HardwareError); } + // Do a command to get 1-Wire master reset out of holding state. + reset(); + return result; } @@ -113,12 +92,11 @@ // [] indicates from slave // SS indicates byte containing search direction bit value in msbit - error_code result = sendCommand(OwTripletCmd, data.writeBit ? 0x80 : 0x00); + error_code result = sendCommand(0x78, data.writeBit ? 0x80 : 0x00); if (!result) { uint_least8_t status; result = pollBusy(&status); if (!result) { - // check bit results in status byte data.readBit = ((status & Status_SBR) == Status_SBR); data.readBitComplement = ((status & Status_TSB) == Status_TSB); data.writeBit = ((status & Status_DIR) == Status_DIR); @@ -134,26 +112,28 @@ // Repeat until 1WB bit has changed to 0 // [] indicates from slave - error_code result = sendCommand(OwResetCmd); - uint_least8_t buf; - - if (!result) { - result = pollBusy(&buf); + error_code result = sendCommand(0xB4); + if (result) { + return result; } - if (!result) { - if ((buf & Status_SD) == Status_SD) { - result = make_error_code(ShortDetectedError); - } - else if ((buf & Status_PPD) != Status_PPD) { - result = make_error_code(NoSlaveError); - } + uint_least8_t buf; + result = pollBusy(&buf); + if (result) { + return result; + } + + if ((buf & Status_SD) == Status_SD) { + result = make_error_code(ShortDetectedError); + } else if ((buf & Status_PPD) != Status_PPD) { + result = make_error_code(NoSlaveError); } return result; } -error_code DS2482_DS2484::touchBitSetLevel(bool & sendRecvBit, Level afterLevel) { +error_code DS2482_DS2484::touchBitSetLevel(bool & sendRecvBit, + Level afterLevel) { // 1-Wire bit (Case B) // S AD,0 [A] 1WSB [A] BB [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ @@ -162,25 +142,25 @@ // BB indicates byte containing bit value in msbit error_code result = configureLevel(afterLevel); + if (result) { + return result; + } - if (!result) { - result = sendCommand(OwSingleBitCmd, sendRecvBit ? 0x80 : 0x00); + result = sendCommand(0x87, sendRecvBit ? 0x80 : 0x00); + if (result) { + return result; } uint_least8_t status; - - if (!result) { - result = pollBusy(&status); - } - + result = pollBusy(&status); if (!result) { sendRecvBit = ((status & Status_SBR) == Status_SBR); } - return result; } -error_code DS2482_DS2484::writeByteSetLevel(uint_least8_t sendByte, Level afterLevel) { +error_code DS2482_DS2484::writeByteSetLevel(uint_least8_t sendByte, + Level afterLevel) { // 1-Wire Write Byte (Case B) // S AD,0 [A] 1WWB [A] DD [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ @@ -193,16 +173,17 @@ return result; } - result = sendCommand(OwWriteByteCmd, sendByte); - if (!result) { - result = pollBusy(); + result = sendCommand(0xA5, sendByte); + if (result) { + return result; } + result = pollBusy(); return result; } error_code DS2482_DS2484::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { + Level afterLevel) { // 1-Wire Read Bytes (Case C) // S AD,0 [A] 1WRB [A] Sr AD,1 [A] [Status] A [Status] A // \--------/ @@ -217,22 +198,17 @@ return result; } - result = sendCommand(OwReadByteCmd); - - if (!result) { - result = pollBusy(); + result = sendCommand(0x96); + if (result) { + return result; } - uint_least8_t buf; - - if (!result) { - result = readRegister(ReadDataReg, buf); + result = pollBusy(); + if (result) { + return result; } - if (!result) { - recvByte = buf; - } - + result = readRegister(0xE1, recvByte); return result; } @@ -246,9 +222,7 @@ return error_code(); } // Set the speed - Config newConfig = curConfig; - newConfig.set1WS(newSpeed == OverdriveSpeed); - return writeConfig(newConfig); + return writeConfig(Config(curConfig).set1WS(newSpeed == OverdriveSpeed)); } error_code DS2482_DS2484::setLevel(Level newLevel) { @@ -260,10 +234,11 @@ } error_code DS2482_DS2484::writeConfig(Config config) { - uint_least8_t configBuf = ((config.readByte() ^ 0xF) << 4) | config.readByte(); - error_code result = sendCommand(WriteDeviceConfigCmd, configBuf); + uint_least8_t configBuf = + ((config.readByte() ^ 0xF) << 4) | config.readByte(); + error_code result = sendCommand(0xD2, configBuf); if (!result) { - result = readRegister(ConfigReg, configBuf); + result = readRegister(0xC3, configBuf); } if (!result) { if (configBuf != config.readByte()) { @@ -276,8 +251,9 @@ return result; } -error_code DS2482_DS2484::readRegister(uint_least8_t reg, uint_least8_t & buf) const { - error_code result = sendCommand(SetReadPointerCmd, reg); +error_code DS2482_DS2484::readRegister(uint_least8_t reg, + uint_least8_t & buf) const { + error_code result = sendCommand(0xE1, reg); if (!result) { result = readRegister(buf); } @@ -285,7 +261,7 @@ } error_code DS2482_DS2484::readRegister(uint_least8_t & buf) const { - return i2cMaster->readPacket(i2cAddress_, &buf, 1); + return master->readPacket(address_, make_span(&buf, 1)); } error_code DS2482_DS2484::pollBusy(uint_least8_t * pStatus) { @@ -319,18 +295,17 @@ return error_code(); } // Set the level - Config newConfig = curConfig; - newConfig.setSPU(level == StrongLevel); - return writeConfig(newConfig); + return writeConfig(Config(curConfig).setSPU(level == StrongLevel)); } error_code DS2482_DS2484::sendCommand(uint_least8_t cmd) const { - return i2cMaster->writePacket(i2cAddress_, &cmd, 1); + return master->writePacket(address_, make_span(&cmd, 1)); } -error_code DS2482_DS2484::sendCommand(uint_least8_t cmd, uint_least8_t param) const { +error_code DS2482_DS2484::sendCommand(uint_least8_t cmd, + uint_least8_t param) const { uint_least8_t buf[] = {cmd, param}; - return i2cMaster->writePacket(i2cAddress_, buf, sizeof(buf) / sizeof(buf[0])); + return master->writePacket(address_, buf); } const error_category & DS2482_DS2484::errorCategory() { @@ -408,7 +383,7 @@ return make_error_code(ArgumentOutOfRangeError); }; - error_code result = sendCommand(ChannelSelectCmd, ch); + error_code result = sendCommand(0xC3, ch); if (!result) { result = readRegister(ch); if (!result) { @@ -427,13 +402,13 @@ return make_error_code(ArgumentOutOfRangeError); } - error_code result = sendCommand(AdjustOwPortCmd, (param << 4) | val); + error_code result = sendCommand(0xC3, (param << 4) | val); if (result) { return result; } - uint_least8_t portConfig; - for (int paramNum = param + 1; paramNum > 0; paramNum--) { + uint_least8_t portConfig = val + 1; + for (int reads = -1; reads < param; ++reads) { result = readRegister(portConfig); if (result) { return result;
--- a/Devices/DS2482_DS2484.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS2482_DS2484.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -51,52 +51,80 @@ explicit Config(uint_least8_t readByte = optionAPU) : readByte_(readByte & 0xF) {} + /// @name 1WS + /// @brief 1-Wire Speed /// @{ - /// 1-Wire Speed + + /// Get 1WS bit. bool get1WS() const { return (readByte_ & option1WS) == option1WS; } - void set1WS(bool new1WS) { + + /// Set 1WS bit. + Config & set1WS(bool new1WS) { if (new1WS) { readByte_ |= option1WS; } else { readByte_ &= ~option1WS; } + return *this; } + /// @} + /// @name SPU + /// @brief Strong Pullup /// @{ - /// Strong Pullup + + /// Get SPU bit. bool getSPU() const { return (readByte_ & optionSPU) == optionSPU; } - void setSPU(bool newSPU) { + + /// Set SPU bit. + Config & setSPU(bool newSPU) { if (newSPU) { readByte_ |= optionSPU; } else { readByte_ &= ~optionSPU; } + return *this; } + /// @} + /// @name PDN + /// @brief 1-Wire Power Down /// @{ - /// 1-Wire Power Down + + /// Get PDN bit. bool getPDN() const { return (readByte_ & optionPDN) == optionPDN; } - void setPDN(bool newPDN) { + + /// Set PDN bit. + Config & setPDN(bool newPDN) { if (newPDN) { readByte_ |= optionPDN; } else { readByte_ &= ~optionPDN; } + return *this; } + /// @} + /// @name APU + /// @brief Active Pullup /// @{ - /// Active Pullup + + /// Get APU bit. bool getAPU() const { return (readByte_ & optionAPU) == optionAPU; } - void setAPU(bool newAPU) { + + /// Set APU bit. + Config & setAPU(bool newAPU) { if (newAPU) { readByte_ |= optionAPU; } else { readByte_ &= ~optionAPU; } + return *this; } + /// @} /// Byte representation that is read from the device. @@ -111,37 +139,41 @@ uint_least8_t readByte_; }; - void setI2CMaster(I2CMaster & i2cMaster) { this->i2cMaster = &i2cMaster; } - uint_least8_t i2cAddress() const { return i2cAddress_; } - void setI2CAddress(uint_least8_t i2cAddress) { - this->i2cAddress_ = i2cAddress; - } + void setMaster(I2CMaster & master) { this->master = &master; } + + uint_least8_t address() const { return address_; } + + void setAddress(uint_least8_t address) { address_ = address; } /// Initialize hardware for use. MaximInterface_EXPORT error_code initialize(Config config = Config()); - /// Write a new configuration to the device. + /// @brief Write a new configuration to the device. /// @param[in] config New configuration to write. MaximInterface_EXPORT error_code writeConfig(Config config); - /// @note Perform a 1-Wire triplet using the device command. MaximInterface_EXPORT virtual error_code triplet(TripletData & data); MaximInterface_EXPORT virtual error_code reset(); + MaximInterface_EXPORT virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel); + MaximInterface_EXPORT virtual error_code readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterface_EXPORT virtual error_code writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); + MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed); + MaximInterface_EXPORT virtual error_code setLevel(Level newLevel); MaximInterface_EXPORT static const error_category & errorCategory(); protected: - DS2482_DS2484(I2CMaster & i2cMaster, uint_least8_t i2cAddress) - : i2cMaster(&i2cMaster), i2cAddress_(i2cAddress) {} + DS2482_DS2484(I2CMaster & master, uint_least8_t address) + : master(&master), address_(address) {} /// @note Allow marking const since not public. error_code sendCommand(uint_least8_t cmd) const; @@ -149,31 +181,32 @@ /// @note Allow marking const since not public. error_code sendCommand(uint_least8_t cmd, uint_least8_t param) const; - /// Reads a register from the device. + /// @brief Reads a register from the device. /// @param reg Register to read from. /// @param[out] buf Buffer to hold read data. error_code readRegister(uint_least8_t reg, uint_least8_t & buf) const; - /// Reads the current register from the device. + /// @brief Reads the current register from the device. /// @param[out] buf Buffer to hold read data. error_code readRegister(uint_least8_t & buf) const; private: - /// Performs a soft reset on the device. + /// @brief Performs a soft reset on the device. /// @note This is not a 1-Wire Reset. error_code resetDevice(); + /// @brief /// Polls the device status waiting for the 1-Wire Busy bit (1WB) to be cleared. /// @param[out] pStatus Optionally retrieve the status byte when 1WB cleared. /// @returns Success or TimeoutError if poll limit reached. error_code pollBusy(uint_least8_t * pStatus = NULL); - /// Ensure that the desired 1-Wire level is set in the configuration. + /// @brief Ensure that the desired 1-Wire level is set in the configuration. /// @param level Desired 1-Wire level. error_code configureLevel(Level level); - I2CMaster * i2cMaster; - uint_least8_t i2cAddress_; + I2CMaster * master; + uint_least8_t address_; Config curConfig; }; @@ -193,7 +226,7 @@ DS2482_800(I2CMaster & i2c_bus, uint_least8_t adrs) : DS2482_DS2484(i2c_bus, adrs) {} - /// Select the active 1-Wire channel. + /// @brief Select the active 1-Wire channel. /// @param channel Channel number to select from 0 to 7. MaximInterface_EXPORT error_code selectChannel(int channel); }; @@ -201,7 +234,7 @@ /// DS2484 I2C to 1-Wire Master class DS2484 : public DS2482_DS2484 { public: - /// 1-Wire port adjustment parameters. + /// @brief 1-Wire port adjustment parameters. /// @note See datasheet page 13. enum PortParameter { tRSTL = 0, @@ -217,7 +250,7 @@ explicit DS2484(I2CMaster & i2c_bus, uint_least8_t adrs = 0x30) : DS2482_DS2484(i2c_bus, adrs) {} - /// Adjust 1-Wire port parameters. + /// @brief Adjust 1-Wire port parameters. /// @param param Parameter to adjust. /// @param val New parameter value to set. Consult datasheet for value mappings. MaximInterface_EXPORT error_code adjustPort(PortParameter param, int val);
--- a/Devices/DS28C36_DS2476.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS28C36_DS2476.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -1,731 +1,724 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include <MaximInterface/Links/I2CMaster.hpp> -#include <MaximInterface/Utilities/Error.hpp> -#include <MaximInterface/Utilities/RomId.hpp> -#include "DS28C36_DS2476.hpp" - -using std::copy; - -namespace MaximInterface { -using namespace Ecc256; - -// DS28C36 commands. -enum Command { - WriteMemory = 0x96, - ReadMemory = 0x69, - WriteBuffer = 0x87, - ReadBuffer = 0x5A, - ReadPageProtection = 0xAA, - SetPageProtection = 0xC3, - DecrementCounter = 0xC9, - ReadRng = 0xD2, - EncryptedReadMemory = 0x4B, - ComputeAndReadPathAuthentication = 0xA5, - AuthenticatedSha2WriteMemory = 0x99, - ComputeAndLockSha2Secret = 0x3C, - GenerateEcc256KeyPair = 0xCB, - ComputeMultiblockHash = 0x33, - VerifyEcdsaSignature = 0x59, - AuthenticateEcdsaPublicKey = 0xA8, - AuthenticatedEcdsaWriteMemory = 0x89 -}; - -static error_code convertResultByte(uint_least8_t resultByte) { - error_code errorCode; - if (resultByte != 0xAA) { - errorCode.assign((resultByte == 0x00) - ? static_cast<int>(DS28C36::AuthenticationError) - : resultByte, - DS28C36::errorCategory()); - } - return errorCode; -} - -error_code DS28C36::writeMemory(int pageNum, const Page & page) { - if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); - } - - array<uint_least8_t, 1 + Page::csize> buffer; - buffer[0] = pageNum; - copy(page.begin(), page.end(), buffer.begin() + 1); - error_code result = writeCommand(WriteMemory, buffer.data(), buffer.size()); - if (!result) { - sleep(writeMemoryTimeMs); - result = readFixedLengthResponse(buffer.data(), 1); - if (!result) { - result = convertResultByte(buffer[0]); - } - } - return result; -} - -error_code DS28C36::readMemory(int pageNum, Page & page) { - if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); - } - - const uint_least8_t parameter = pageNum; - error_code result = writeCommand(ReadMemory, ¶meter, 1); - if (!result) { - sleep(readMemoryTimeMs); - array<uint_least8_t, 1 + Page::csize> response; - result = readFixedLengthResponse(response.data(), response.size()); - if (!result) { - result = convertResultByte(response[0]); - copy(response.begin() + 1, response.end(), page.begin()); - } - } - return result; -} - -error_code DS28C36::writeBuffer(const uint_least8_t * data, size_t dataSize) { - return writeCommand(WriteBuffer, data, dataSize); -} - -error_code DS28C36::readBuffer(std::vector<uint_least8_t> & data) { - error_code result = writeCommand(ReadBuffer); - if (!result) { - data.resize(80); - size_t dataSize = data.size(); - result = readVariableLengthResponse(&data[0], dataSize); - if (result) { - data.clear(); - } else { - data.resize(dataSize); - } - } - return result; -} - -error_code DS28C36::readPageProtection(int pageNum, - PageProtection & protection) { - if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); - } - - uint_least8_t buffer = pageNum; - error_code result = writeCommand(ReadPageProtection, &buffer, 1); - if (!result) { - sleep(readMemoryTimeMs); - result = readFixedLengthResponse(&buffer, 1); - if (!result) { - protection = buffer; - } - } - return result; -} - -error_code DS28C36::setPageProtection(int pageNum, - const PageProtection & protection) { - if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); - } - - array<uint_least8_t, 2> buffer = { - static_cast<uint_least8_t>(pageNum), - static_cast<uint_least8_t>(protection.to_ulong())}; - error_code result = - writeCommand(SetPageProtection, buffer.data(), buffer.size()); - if (!result) { - sleep(writeMemoryTimeMs); - result = readFixedLengthResponse(buffer.data(), 1); - if (!result) { - result = convertResultByte(buffer[0]); - } - } - return result; -} - -error_code DS28C36::decrementCounter() { - error_code result = writeCommand(DecrementCounter); - if (!result) { - sleep(writeMemoryTimeMs); - uint_least8_t response; - result = readFixedLengthResponse(&response, 1); - if (!result) { - result = convertResultByte(response); - } - } - return result; -} - -error_code DS28C36::readRng(uint_least8_t * data, size_t dataSize) { - if ((dataSize < 1) || (dataSize > 64)) { - return make_error_code(InvalidParameterError); - } - - data[0] = static_cast<uint_least8_t>(dataSize - 1); - error_code result = writeCommand(ReadRng, data, 1); - if (!result) { - sleep(sha256ComputationTimeMs); - result = readFixedLengthResponse(data, dataSize); - } - return result; -} - -error_code DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum, - EncryptedPage & page) { - if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); - } - - const uint_least8_t parameter = (secretNum << 6) | pageNum; - error_code result = writeCommand(EncryptedReadMemory, ¶meter, 1); - if (!result) { - sleep(readMemoryTimeMs + sha256ComputationTimeMs); - typedef array<uint_least8_t, 1 + EncryptedPage::size> Response; - Response response; - result = readFixedLengthResponse(response.data(), response.size()); - if (!result) { - result = convertResultByte(response[0]); - Response::const_iterator begin = response.begin() + 1; - Response::const_iterator end = begin + page.challenge.size(); - copy(begin, end, page.challenge.begin()); - begin = end; - end = begin + page.data.size(); - copy(begin, end, page.data.begin()); - } - } - return result; -} - -error_code DS28C36::computeAndReadPageAuthentication(int pageNum, - AuthType authType) { - if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); - } - - const uint_least8_t parameter = (authType << 5) | pageNum; - return writeCommand(ComputeAndReadPathAuthentication, ¶meter, 1); -} - -error_code -DS28C36::computeAndReadEcdsaPageAuthentication(int pageNum, KeyNum keyNum, - Signature & signature) { - AuthType authType; - switch (keyNum) { - case KeyNumA: - authType = EcdsaWithKeyA; - break; - case KeyNumB: - authType = EcdsaWithKeyB; - break; - case KeyNumC: - authType = EcdsaWithKeyC; - break; - default: - return make_error_code(InvalidParameterError); - } - error_code result = computeAndReadPageAuthentication(pageNum, authType); - if (!result) { - sleep(sha256ComputationTimeMs); - typedef array<uint_least8_t, 1 + Signature::size> Response; - Response response; - result = readFixedLengthResponse(response.data(), response.size()); - if (!result) { - result = convertResultByte(response[0]); - Response::const_iterator begin = response.begin() + 1; - Response::const_iterator end = begin + signature.s.size(); - copy(begin, end, signature.s.begin()); - begin = end; - end = begin + signature.r.size(); - copy(begin, end, signature.r.begin()); - } - } - return result; -} - -error_code DS28C36::computeAndReadHmacPageAuthentication(int pageNum, - SecretNum secretNum, - Sha256::Hash & hmac) { - AuthType authType; - switch (secretNum) { - case SecretNumA: - authType = HmacWithSecretA; - break; - case SecretNumB: - authType = HmacWithSecretB; - break; - case SecretNumS: - authType = HmacWithSecretS; - break; - default: - return make_error_code(InvalidParameterError); - } - error_code result = computeAndReadPageAuthentication(pageNum, authType); - if (!result) { - sleep(generateEcdsaSignatureTimeMs); - array<uint_least8_t, 1 + Sha256::Hash::csize> response; - result = readFixedLengthResponse(response.data(), response.size()); - if (!result) { - result = convertResultByte(response[0]); - copy(response.begin() + 1, response.end(), hmac.begin()); - } - } - return result; -} - -error_code DS28C36::authenticatedSha2WriteMemory(int pageNum, - SecretNum secretNum, - const Page & page) { - if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); - } - - array<uint_least8_t, 1 + Page::csize> buffer; - buffer[0] = (secretNum << 6) | pageNum; - copy(page.begin(), page.end(), buffer.begin() + 1); - error_code result = - writeCommand(AuthenticatedSha2WriteMemory, buffer.data(), buffer.size()); - if (!result) { - sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs)); - result = readFixedLengthResponse(buffer.data(), 1); - if (!result) { - result = convertResultByte(buffer[0]); - } - } - return result; -} - -error_code DS28C36::computeAndLockSha2Secret(int pageNum, SecretNum msecretNum, - SecretNum dsecretNum, - bool writeProtectEnable) { - // User pages only - if (pageNum < UserData0 || pageNum > UserData15) { - return make_error_code(InvalidParameterError); - } - - array<uint_least8_t, 2> buffer = { - static_cast<uint_least8_t>((dsecretNum << 6) | (msecretNum << 4) | - pageNum), - static_cast<uint_least8_t>(writeProtectEnable ? 0x80 : 0x00)}; - error_code result = - writeCommand(ComputeAndLockSha2Secret, buffer.data(), buffer.size()); - if (!result) { - sleep(sha256ComputationTimeMs + - ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs)); - result = readFixedLengthResponse(buffer.data(), 1); - if (!result) { - result = convertResultByte(buffer[0]); - } - } - return result; -} - -error_code DS28C36::generateEcc256KeyPair(KeyNum keyNum, - bool writeProtectEnable) { - if (keyNum == KeyNumS) { - return make_error_code(InvalidParameterError); - } - - uint_least8_t buffer = keyNum; - if (writeProtectEnable) { - buffer |= 0x80; - } - error_code result = writeCommand(GenerateEcc256KeyPair, &buffer, 1); - if (!result) { - sleep(generateEccKeyPairTimeMs); - result = readFixedLengthResponse(&buffer, 1); - if (!result) { - result = convertResultByte(buffer); - } - } - return result; -} - -error_code DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock, - const uint_least8_t * data, - size_t dataSize) { - const size_t maxDataSize = 64; - - if (dataSize < 1 || dataSize > maxDataSize) { - return make_error_code(InvalidParameterError); - } - - array<uint_least8_t, 1 + maxDataSize> buffer; - buffer[0] = 0; - if (firstBlock) { - buffer[0] |= 0x40; - } - if (lastBlock) { - buffer[0] |= 0x80; - } - copy(data, data + dataSize, buffer.begin() + 1); - error_code result = - writeCommand(ComputeMultiblockHash, buffer.data(), dataSize + 1); - if (!result) { - sleep(sha256ComputationTimeMs); - result = readFixedLengthResponse(buffer.data(), 1); - if (!result) { - result = convertResultByte(buffer[0]); - } - } - return result; -} - -error_code DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType, - const Signature & signature, - PioState pioa, PioState piob) { - typedef array<uint_least8_t, 1 + Signature::size> Buffer; - Buffer buffer; - buffer[0] = keyNum | (hashType << 2); - if (pioa != Unchanged) { - buffer[0] |= 0x20; - } - if (pioa == Conducting) { - buffer[0] |= 0x10; - } - if (piob != Unchanged) { - buffer[0] |= 0x80; - } - if (piob == Conducting) { - buffer[0] |= 0x40; - } - Buffer::iterator bufferIt = - copy(signature.r.begin(), signature.r.end(), buffer.begin() + 1); - copy(signature.s.begin(), signature.s.end(), bufferIt); - error_code result = - writeCommand(VerifyEcdsaSignature, buffer.data(), buffer.size()); - if (!result) { - sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + - ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0)); - result = readFixedLengthResponse(buffer.data(), 1); - if (!result) { - result = convertResultByte(buffer[0]); - } - } - return result; -} - -error_code DS28C36::authenticateEcdsaPublicKey(bool authWrites, bool ecdh, - KeyNum keyNum, int csOffset, - const Signature & signature) { - if (((keyNum != KeyNumA) && (keyNum != KeyNumB)) || (csOffset < 0) || - (csOffset > 31)) { - return make_error_code(InvalidParameterError); - } - - typedef array<uint_least8_t, 1 + Signature::size> Buffer; - Buffer buffer; - buffer[0] = (csOffset << 3) | (keyNum << 2); - if (ecdh) { - buffer[0] |= 0x02; - } - if (authWrites) { - buffer[0] |= 0x01; - } - Buffer::iterator bufferIt = - copy(signature.r.begin(), signature.r.end(), buffer.begin() + 1); - copy(signature.s.begin(), signature.s.end(), bufferIt); - error_code result = - writeCommand(AuthenticateEcdsaPublicKey, buffer.data(), buffer.size()); - if (!result) { - sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs); - result = readFixedLengthResponse(buffer.data(), 1); - if (!result) { - result = convertResultByte(buffer[0]); - } - } - return result; -} - -error_code DS28C36::authenticatedEcdsaWriteMemory(int pageNum, - const Page & page) { - if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); - } - - array<uint_least8_t, 1 + Page::csize> buffer; - buffer[0] = pageNum; - copy(page.begin(), page.end(), buffer.begin() + 1); - error_code result = - writeCommand(AuthenticatedEcdsaWriteMemory, buffer.data(), buffer.size()); - if (!result) { - sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs + - sha256ComputationTimeMs); - result = readFixedLengthResponse(buffer.data(), 1); - if (!result) { - result = convertResultByte(buffer[0]); - } - } - return result; -} - -error_code DS28C36::writeCommand(uint_least8_t command, - const uint_least8_t * parameters, - size_t parametersSize) { - error_code result = master->start(address_); - if (result) { - master->stop(); - return result; - } - result = master->writeByte(command); - if (result) { - master->stop(); - return result; - } - if (parameters) { - result = master->writeByte(static_cast<uint_least8_t>(parametersSize)); - if (result) { - master->stop(); - return result; - } - result = master->writeBlock(parameters, parametersSize); - if (result) { - master->stop(); - return result; - } - } - result = master->stop(); - return result; -} - -error_code DS28C36::readVariableLengthResponse(uint_least8_t * response, - size_t & responseSize) { - error_code result = master->start(address_ | 1); - if (result) { - master->stop(); - return result; - } - uint_least8_t length; - result = master->readByte(I2CMaster::Ack, length); - if (result) { - master->stop(); - return result; - } - if (length > responseSize) { - master->stop(); - return make_error_code(InvalidResponseError); - } - if (length > 0) { - result = master->readBlock(I2CMaster::Nack, response, length); - if (result) { - master->stop(); - return result; - } - } - responseSize = length; - result = master->stop(); - return result; -} - -error_code DS28C36::readFixedLengthResponse(uint_least8_t * response, - size_t responseSize) { - const size_t requestedResponseSize = responseSize; - error_code result = readVariableLengthResponse(response, responseSize); - if (!result && responseSize != requestedResponseSize) { - result = make_error_code(InvalidResponseError); - } - return result; -} - -DS28C36::PageAuthenticationData -DS28C36::createPageAuthenticationData(const RomId & romId, const Page & page, - const Page & challenge, int pageNum, - const ManId & manId) { - PageAuthenticationData data; - PageAuthenticationData::iterator dataIt = data.begin(); - dataIt = copy(romId.begin(), romId.end(), dataIt); - dataIt = copy(page.begin(), page.end(), dataIt); - dataIt = copy(challenge.begin(), challenge.end(), dataIt); - *dataIt = static_cast<uint_least8_t>(pageNum); - ++dataIt; - copy(manId.begin(), manId.end(), dataIt); - return data; -} - -const error_category & DS28C36::errorCategory() { - static class : public error_category { - public: - virtual const char * name() const { return "DS28C36"; } - - virtual std::string message(int condition) const { - switch (condition) { - case ProtectionError: - return "Protection Error"; - - case InvalidParameterError: - return "Invalid Parameter Error"; - - case InvalidSequenceError: - return "Invalid Sequence Error"; - - case InvalidEcdsaInputOrResultError: - return "Invalid ECDSA Input or Result Error"; - - case AuthenticationError: - return "Authentication Error"; - - case InvalidResponseError: - return "Invalid Response Error"; - - default: - return defaultErrorMessage(condition); - } - } - } instance; - return instance; -} - -error_code readRomIdAndManId(DS28C36 & ds28c36, RomId * romId, ManId * manId) { - DS28C36::Page page; - const error_code result = ds28c36.readMemory(DS28C36::RomOptions, page); - if (!result) { - DS28C36::Page::const_iterator pageIt = page.begin() + 22; - if (manId) { - copy(pageIt, pageIt + ManId::size(), manId->begin()); - } - pageIt += ManId::size(); - if (romId) { - copy(pageIt, pageIt + RomId::size(), romId->begin()); - } - } - return result; -} - -error_code computeMultiblockHash(DS28C36 & ds28c36, const uint_least8_t * data, - const size_t dataSize) { - error_code result; - size_t remainingSize = dataSize; - while ((remainingSize > 0) && !result) { - const size_t chunkSize = std::min<size_t>(remainingSize, 64); - result = ds28c36.computeMultiblockHash( - remainingSize == dataSize, remainingSize == chunkSize, data, chunkSize); - data += chunkSize; - remainingSize -= chunkSize; - } - return result; -} - -error_code verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey, - const uint_least8_t * data, size_t dataSize, - const Signature & signature, - DS28C36::PioState pioa, - DS28C36::PioState piob) { - error_code result = computeMultiblockHash(ds28c36, data, dataSize); - if (!result) { - result = ds28c36.verifyEcdsaSignature(publicKey, DS28C36::THASH, signature, - pioa, piob); - } - return result; -} - -error_code verifyEcdsaSignature(DS28C36 & ds28c36, const PublicKey & publicKey, - const uint_least8_t * data, size_t dataSize, - const Signature & signature, - DS28C36::PioState pioa, - DS28C36::PioState piob) { - error_code result = ds28c36.writeMemory(DS28C36::PublicKeySX, publicKey.x); - if (!result) { - result = ds28c36.writeMemory(DS28C36::PublicKeySY, publicKey.y); - } - if (!result) { - result = verifyEcdsaSignature(ds28c36, DS28C36::KeyNumS, data, dataSize, - signature, pioa, piob); - } - return result; -} - -// DS2476 additional commands. -enum DS2476_Command { - GenerateEcdsaSignature = 0x1E, - ComputeSha2UniqueSecret = 0x55, - ComputeSha2Hmac = 0x2D -}; - -error_code DS2476::generateEcdsaSignature(KeyNum keyNum, - Signature & signature) { - if (keyNum == KeyNumS) { - return make_error_code(InvalidParameterError); - } - - const uint_least8_t parameter = keyNum; - error_code result = writeCommand(GenerateEcdsaSignature, ¶meter, 1); - if (!result) { - sleep(generateEcdsaSignatureTimeMs); - typedef array<uint_least8_t, 1 + Signature::size> Response; - Response response; - result = readFixedLengthResponse(response.data(), response.size()); - if (!result) { - result = convertResultByte(response[0]); - Response::const_iterator begin = response.begin() + 1; - Response::const_iterator end = begin + signature.s.size(); - copy(begin, end, signature.s.begin()); - begin = end; - end = begin + signature.r.size(); - copy(begin, end, signature.r.begin()); - } - } - return result; -} - -error_code DS2476::computeSha2UniqueSecret(SecretNum msecretNum) { - uint_least8_t buffer = msecretNum << 4; - error_code result = writeCommand(ComputeSha2UniqueSecret, &buffer, 1); - if (!result) { - sleep(sha256ComputationTimeMs); - result = readFixedLengthResponse(&buffer, 1); - if (!result) { - convertResultByte(buffer); - } - } - return result; -} - -error_code DS2476::computeSha2Hmac(Sha256::Hash & hmac) { - error_code result = writeCommand(ComputeSha2Hmac); - if (!result) { - sleep(sha256ComputationTimeMs); - array<uint_least8_t, 1 + Sha256::Hash::csize> response; - result = readFixedLengthResponse(response.data(), response.size()); - if (!result) { - result = convertResultByte(response[0]); - copy(response.begin() + 1, response.end(), hmac.begin()); - } - } - return result; -} - -error_code enableCoprocessor(DS2476 & ds2476) { - DS2476::Page gpioControl; - error_code result = ds2476.readMemory(DS2476::GpioControl, gpioControl); - if (!result && gpioControl[0] != 0xAA) { - gpioControl[0] = 0xAA; - result = ds2476.writeMemory(DS2476::GpioControl, gpioControl); - } - return result; -} - -} // namespace MaximInterface +/******************************************************************************* +* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#include <algorithm> +#include <MaximInterface/Links/I2CMaster.hpp> +#include <MaximInterface/Utilities/Error.hpp> +#include <MaximInterface/Utilities/RomId.hpp> +#include "DS28C36_DS2476.hpp" + +namespace MaximInterface { + +using namespace Ecc256; +using std::copy; + +static error_code convertResultByte(uint_least8_t resultByte) { + error_code errorCode; + if (resultByte != 0xAA) { + errorCode.assign((resultByte == 0x00) + ? static_cast<int>(DS28C36::AuthenticationError) + : resultByte, + DS28C36::errorCategory()); + } + return errorCode; +} + +const int DS28C36::publicKeyAxPage; +const int DS28C36::publicKeyAyPage; +const int DS28C36::publicKeyBxPage; +const int DS28C36::publicKeyByPage; +const int DS28C36::publicKeyCxPage; +const int DS28C36::publicKeyCyPage; +const int DS28C36::privateKeyAPage; +const int DS28C36::privateKeyBPage; +const int DS28C36::privateKeyCPage; +const int DS28C36::secretAPage; +const int DS28C36::secretBPage; +const int DS28C36::decrementCounterPage; +const int DS28C36::romOptionsPage; +const int DS28C36::gpioControlPage; +const int DS28C36::publicKeySxPage; +const int DS28C36::publicKeySyPage; +const int DS28C36::memoryPages; + +error_code DS28C36::writeMemory(int pageNum, Page::const_span page) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer[1 + Page::size]; + buffer[0] = pageNum; + copy(page.begin(), page.end(), buffer + 1); + error_code result = writeCommand(0x96, buffer); + if (!result) { + sleep(writeMemoryTimeMs); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + result = convertResultByte(buffer[0]); + } + } + return result; +} + +error_code DS28C36::readMemory(int pageNum, Page::span page) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + const uint_least8_t parameter = pageNum; + error_code result = writeCommand(0x69, make_span(¶meter, 1)); + if (!result) { + sleep(readMemoryTimeMs); + array<uint_least8_t, 1 + Page::size> response; + result = readFixedLengthResponse(response); + if (!result) { + result = convertResultByte(response[0]); + copy(response.begin() + 1, response.end(), page.begin()); + } + } + return result; +} + +error_code DS28C36::writeBuffer(span<const uint_least8_t> data) { + return writeCommand(0x87, data); +} + +error_code DS28C36::readBuffer(std::vector<uint_least8_t> & data) { + error_code result = writeCommand(0x5A); + if (!result) { + data.resize(80); + span<uint_least8_t> dataSpan(data); + result = readVariableLengthResponse(dataSpan); + if (result) { + data.clear(); + } else { + data.resize(dataSpan.size()); + } + } + return result; +} + +error_code DS28C36::readPageProtection(int pageNum, + PageProtection & protection) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer = pageNum; + error_code result = writeCommand(0xAA, make_span(&buffer, 1)); + if (!result) { + sleep(readMemoryTimeMs); + result = readFixedLengthResponse(make_span(&buffer, 1)); + if (!result) { + protection = buffer; + } + } + return result; +} + +error_code DS28C36::setPageProtection(int pageNum, + const PageProtection & protection) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer[] = {static_cast<uint_least8_t>(pageNum), + static_cast<uint_least8_t>(protection.to_ulong())}; + error_code result = writeCommand(0xC3, buffer); + if (!result) { + sleep(writeMemoryTimeMs); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + result = convertResultByte(buffer[0]); + } + } + return result; +} + +error_code DS28C36::decrementCounter() { + error_code result = writeCommand(0xC9); + if (!result) { + sleep(writeMemoryTimeMs); + uint_least8_t response; + result = readFixedLengthResponse(make_span(&response, 1)); + if (!result) { + result = convertResultByte(response); + } + } + return result; +} + +error_code DS28C36::readRng(span<uint_least8_t> data) { + if ((data.size() < 1) || (data.size() > 64)) { + return make_error_code(InvalidParameterError); + } + + data[0] = static_cast<uint_least8_t>(data.size() - 1); + error_code result = writeCommand(0xD2, data.first(1)); + if (!result) { + sleep(sha256ComputationTimeMs); + result = readFixedLengthResponse(data); + } + return result; +} + +error_code DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum, + EncryptionChallenge::span challenge, + Page::span data) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + const uint_least8_t parameter = (secretNum << 6) | pageNum; + error_code result = writeCommand(0x4B, make_span(¶meter, 1)); + if (!result) { + sleep(readMemoryTimeMs + sha256ComputationTimeMs); + uint_least8_t response[1 + EncryptionChallenge::size + Page::size]; + result = readFixedLengthResponse(response); + if (!result) { + result = convertResultByte(response[0]); + const uint_least8_t * begin = response + 1; + const uint_least8_t * end = begin + challenge.size(); + copy(begin, end, challenge.begin()); + begin = end; + end = begin + data.size(); + copy(begin, end, data.begin()); + } + } + return result; +} + +error_code DS28C36::computeAndReadPageAuthentication(int pageNum, + AuthType authType) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + const uint_least8_t parameter = (authType << 5) | pageNum; + return writeCommand(0xA5, make_span(¶meter, 1)); +} + +error_code +DS28C36::computeAndReadPageAuthentication(int pageNum, KeyNum keyNum, + Signature::span signature) { + AuthType authType; + switch (keyNum) { + case KeyNumA: + authType = EcdsaWithKeyA; + break; + case KeyNumB: + authType = EcdsaWithKeyB; + break; + case KeyNumC: + authType = EcdsaWithKeyC; + break; + default: + return make_error_code(InvalidParameterError); + } + error_code result = computeAndReadPageAuthentication(pageNum, authType); + if (!result) { + sleep(readMemoryTimeMs + generateEcdsaSignatureTimeMs); + uint_least8_t response[1 + 2 * Scalar::size]; + result = readFixedLengthResponse(response); + if (!result) { + result = convertResultByte(response[0]); + const uint_least8_t * begin = response + 1; + const uint_least8_t * end = begin + signature.s.size(); + copy(begin, end, signature.s.begin()); + begin = end; + end = begin + signature.r.size(); + copy(begin, end, signature.r.begin()); + } + } + return result; +} + +error_code DS28C36::computeAndReadPageAuthentication(int pageNum, + SecretNum secretNum, + Sha256::Hash::span hmac) { + AuthType authType; + switch (secretNum) { + case SecretNumA: + authType = HmacWithSecretA; + break; + case SecretNumB: + authType = HmacWithSecretB; + break; + case SecretNumS: + authType = HmacWithSecretS; + break; + default: + return make_error_code(InvalidParameterError); + } + error_code result = computeAndReadPageAuthentication(pageNum, authType); + if (!result) { + sleep(readMemoryTimeMs + sha256ComputationTimeMs); + array<uint_least8_t, 1 + Sha256::Hash::size> response; + result = readFixedLengthResponse(response); + if (!result) { + result = convertResultByte(response[0]); + copy(response.begin() + 1, response.end(), hmac.begin()); + } + } + return result; +} + +error_code DS28C36::authenticatedSha2WriteMemory(int pageNum, + SecretNum secretNum, + Page::const_span page) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer[1 + Page::size]; + buffer[0] = (secretNum << 6) | pageNum; + copy(page.begin(), page.end(), buffer + 1); + error_code result = writeCommand(0x99, buffer); + if (!result) { + sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs)); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + result = convertResultByte(buffer[0]); + } + } + return result; +} + +error_code DS28C36::computeAndLockSha2Secret(int pageNum, SecretNum msecretNum, + SecretNum dsecretNum, + bool writeProtectEnable) { + // User pages only + if (pageNum < 0 || pageNum > 15) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer[] = { + static_cast<uint_least8_t>((dsecretNum << 6) | (msecretNum << 4) | + pageNum), + static_cast<uint_least8_t>(writeProtectEnable ? 0x80 : 0x00)}; + error_code result = writeCommand(0x3C, buffer); + if (!result) { + sleep(sha256ComputationTimeMs + + ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs)); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + result = convertResultByte(buffer[0]); + } + } + return result; +} + +error_code DS28C36::generateEcc256KeyPair(KeyNum keyNum, + bool writeProtectEnable) { + if (keyNum == KeyNumS) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer = keyNum; + if (writeProtectEnable) { + buffer |= 0x80; + } + error_code result = writeCommand(0xCB, make_span(&buffer, 1)); + if (!result) { + sleep(generateEccKeyPairTimeMs); + result = readFixedLengthResponse(make_span(&buffer, 1)); + if (!result) { + result = convertResultByte(buffer); + } + } + return result; +} + +error_code DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock, + span<const uint_least8_t> data) { + const span<const uint_least8_t>::index_type maxDataSize = 64; + + if (data.size() < 1 || data.size() > maxDataSize) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer[1 + maxDataSize]; + buffer[0] = 0; + if (firstBlock) { + buffer[0] |= 0x40; + } + if (lastBlock) { + buffer[0] |= 0x80; + } + copy(data.begin(), data.end(), buffer + 1); + error_code result = writeCommand(0x33, make_span(buffer, data.size() + 1)); + if (!result) { + sleep(sha256ComputationTimeMs); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + result = convertResultByte(buffer[0]); + } + } + return result; +} + +error_code DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType, + Signature::const_span signature, + PioState pioa, PioState piob) { + uint_least8_t buffer[1 + 2 * Scalar::size]; + buffer[0] = keyNum | (hashType << 2); + if (pioa != Unchanged) { + buffer[0] |= 0x20; + } + if (pioa == Conducting) { + buffer[0] |= 0x10; + } + if (piob != Unchanged) { + buffer[0] |= 0x80; + } + if (piob == Conducting) { + buffer[0] |= 0x40; + } + uint_least8_t * bufferIt = + copy(signature.r.begin(), signature.r.end(), buffer + 1); + copy(signature.s.begin(), signature.s.end(), bufferIt); + error_code result = writeCommand(0x59, buffer); + if (!result) { + sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + + ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0)); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + result = convertResultByte(buffer[0]); + } + } + return result; +} + +error_code +DS28C36::authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum, + int csOffset, + Signature::const_span signature) { + if (((keyNum != KeyNumA) && (keyNum != KeyNumB)) || (csOffset < 0) || + (csOffset > 31)) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer[1 + 2 * Scalar::size]; + buffer[0] = (csOffset << 3) | (keyNum << 2); + if (ecdh) { + buffer[0] |= 0x02; + } + if (authWrites) { + buffer[0] |= 0x01; + } + uint_least8_t * bufferIt = + copy(signature.r.begin(), signature.r.end(), buffer + 1); + copy(signature.s.begin(), signature.s.end(), bufferIt); + error_code result = writeCommand(0xA8, buffer); + if (!result) { + sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + result = convertResultByte(buffer[0]); + } + } + return result; +} + +error_code DS28C36::authenticatedEcdsaWriteMemory(int pageNum, + Page::const_span page) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer[1 + Page::size]; + buffer[0] = pageNum; + copy(page.begin(), page.end(), buffer + 1); + error_code result = writeCommand(0x89, buffer); + if (!result) { + sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs + + sha256ComputationTimeMs); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + result = convertResultByte(buffer[0]); + } + } + return result; +} + +error_code DS28C36::writeCommand(uint_least8_t command, + span<const uint_least8_t> parameters) { + error_code result = master->start(address_); + if (result) { + master->stop(); + return result; + } + result = master->writeByte(command); + if (result) { + master->stop(); + return result; + } + if (!parameters.empty()) { + result = master->writeByte(static_cast<uint_least8_t>(parameters.size())); + if (result) { + master->stop(); + return result; + } + result = master->writeBlock(parameters); + if (result) { + master->stop(); + return result; + } + } + result = master->stop(); + return result; +} + +error_code DS28C36::readVariableLengthResponse(span<uint_least8_t> & response) { + error_code result = master->start(address_ | 1); + if (result) { + master->stop(); + return result; + } + uint_least8_t length; + result = master->readByte(I2CMaster::Ack, length); + if (result) { + master->stop(); + return result; + } + if (length > response.size()) { + master->stop(); + return make_error_code(InvalidResponseError); + } + response = response.first(length); + if (!response.empty()) { + result = master->readBlock(I2CMaster::Nack, response); + if (result) { + master->stop(); + return result; + } + } + result = master->stop(); + return result; +} + +error_code DS28C36::readFixedLengthResponse(span<uint_least8_t> response) { + const span<uint_least8_t>::index_type requestedResponseSize = response.size(); + error_code result = readVariableLengthResponse(response); + if (!result && response.size() != requestedResponseSize) { + result = make_error_code(InvalidResponseError); + } + return result; +} + +const error_category & DS28C36::errorCategory() { + static class : public error_category { + public: + virtual const char * name() const { return "DS28C36"; } + + virtual std::string message(int condition) const { + switch (condition) { + case ProtectionError: + return "Protection Error"; + + case InvalidParameterError: + return "Invalid Parameter Error"; + + case InvalidSequenceError: + return "Invalid Sequence Error"; + + case InvalidEcdsaInputOrResultError: + return "Invalid ECDSA Input or Result Error"; + + case AuthenticationError: + return "Authentication Error"; + + case InvalidResponseError: + return "Invalid Response Error"; + + default: + return defaultErrorMessage(condition); + } + } + } instance; + return instance; +} + +error_code DS2476::generateEcdsaSignature(KeyNum keyNum, + Signature::span signature) { + if (keyNum == KeyNumS) { + return make_error_code(InvalidParameterError); + } + + const uint_least8_t parameter = keyNum; + error_code result = writeCommand(0x1E, make_span(¶meter, 1)); + if (!result) { + sleep(generateEcdsaSignatureTimeMs); + uint_least8_t response[1 + 2 * Scalar::size]; + result = readFixedLengthResponse(response); + if (!result) { + result = convertResultByte(response[0]); + const uint_least8_t * begin = response + 1; + const uint_least8_t * end = begin + signature.s.size(); + copy(begin, end, signature.s.begin()); + begin = end; + end = begin + signature.r.size(); + copy(begin, end, signature.r.begin()); + } + } + return result; +} + +error_code DS2476::computeSha2UniqueSecret(SecretNum msecretNum) { + uint_least8_t buffer = msecretNum << 4; + error_code result = writeCommand(0x55, make_span(&buffer, 1)); + if (!result) { + sleep(sha256ComputationTimeMs); + result = readFixedLengthResponse(make_span(&buffer, 1)); + if (!result) { + convertResultByte(buffer); + } + } + return result; +} + +error_code DS2476::computeSha2Hmac(Sha256::Hash::span hmac) { + error_code result = writeCommand(0x2D); + if (!result) { + sleep(sha256ComputationTimeMs); + array<uint_least8_t, 1 + Sha256::Hash::size> response; + result = readFixedLengthResponse(response); + if (!result) { + result = convertResultByte(response[0]); + copy(response.begin() + 1, response.end(), hmac.begin()); + } + } + return result; +} + +error_code computeMultiblockHash(DS28C36 & ds28c36, + span<const uint_least8_t> data) { + error_code result; + span<const uint_least8_t>::index_type dataIdx = 0; + while (dataIdx < data.size() && !result) { + const span<const uint_least8_t>::index_type remainingSize = + data.size() - dataIdx; + const span<const uint_least8_t>::index_type chunkSize = + std::min<span<const uint_least8_t>::index_type>(remainingSize, 64); + result = + ds28c36.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize, + data.subspan(dataIdx, chunkSize)); + dataIdx += chunkSize; + } + return result; +} + +error_code verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey, + span<const uint_least8_t> data, + Signature::const_span signature, + DS28C36::PioState pioa, + DS28C36::PioState piob) { + error_code result = computeMultiblockHash(ds28c36, data); + if (!result) { + result = ds28c36.verifyEcdsaSignature(publicKey, DS28C36::THASH, signature, + pioa, piob); + } + return result; +} + +error_code verifyEcdsaSignature(DS28C36 & ds28c36, + PublicKey::const_span publicKey, + span<const uint_least8_t> data, + Signature::const_span signature, + DS28C36::PioState pioa, + DS28C36::PioState piob) { + error_code result = + ds28c36.writeMemory(DS28C36::publicKeySxPage, publicKey.x); + if (!result) { + result = ds28c36.writeMemory(DS28C36::publicKeySyPage, publicKey.y); + } + if (!result) { + result = verifyEcdsaSignature(ds28c36, DS28C36::KeyNumS, data, signature, + pioa, piob); + } + return result; +} + +error_code readRomIdAndManId(DS28C36 & ds28c36, RomId::span romId, + ManId::span manId) { + DS28C36::Page::array page; + error_code result = ds28c36.readMemory(DS28C36::romOptionsPage, page); + if (!result) { + const DS28C36::RomOptions romOptions(page); + copy(romOptions.romId(), romId); + copy(romOptions.manId(), manId); + } + return result; +} + +error_code enableCoprocessor(DS2476 & ds2476) { + DS2476::Page::array page; + error_code result = ds2476.readMemory(DS2476::gpioControlPage, page); + if (!result) { + DS2476::GpioControl gpioControl(page); + if (!gpioControl.pioaConducting()) { + gpioControl.setPioaConducting(true); + result = ds2476.writeMemory(DS2476::gpioControlPage, page); + } + } + return result; +} + +error_code enableRomId(DS2476 & ds2476) { + DS2476::Page::array page; + error_code result = ds2476.readMemory(DS2476::romOptionsPage, page); + if (!result) { + DS2476::RomOptions romOptions(page); + if (!romOptions.romBlockDisable()) { + romOptions.setRomBlockDisable(true); + result = ds2476.writeMemory(DS2476::romOptionsPage, page); + } + } + return result; +} + +static void setAnonymous(RomId::span romId) { + std::fill(romId.begin(), romId.end(), 0xFF); +} + +DS28C36::PageAuthenticationData & +DS28C36::PageAuthenticationData::setAnonymousRomId() { + setAnonymous(romId()); + return *this; +} + +DS28C36::EncryptionHmacData & DS28C36::EncryptionHmacData::setAnonymousRomId() { + setAnonymous(romId()); + return *this; +} + +} // namespace MaximInterface
--- a/Devices/DS28C36_DS2476.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS28C36_DS2476.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -1,411 +1,923 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#ifndef MaximInterface_DS28C36_DS2476 -#define MaximInterface_DS28C36_DS2476 - -#include <stddef.h> -#include <stdint.h> -#include <vector> -#include <MaximInterface/Links/I2CMaster.hpp> -#include <MaximInterface/Links/Sleep.hpp> -#include <MaximInterface/Utilities/array.hpp> -#include <MaximInterface/Utilities/Ecc256.hpp> -#include <MaximInterface/Utilities/Export.h> -#include <MaximInterface/Utilities/RomId.hpp> -#include <MaximInterface/Utilities/ManId.hpp> -#include <MaximInterface/Utilities/Sha256.hpp> -#include <MaximInterface/Utilities/system_error.hpp> -#include <MaximInterface/Utilities/FlagSet.hpp> - -namespace MaximInterface { - -/// Interface to the DS28C36 authenticator. -class DS28C36 { -public: - /// Device command results. - enum ErrorValue { - ProtectionError = 0x55, - InvalidParameterError = 0x77, - InvalidSequenceError = 0x33, - InvalidEcdsaInputOrResultError = 0x22, - AuthenticationError = 0x100, - InvalidResponseError = 0x101 ///< Response does not match expected format. - }; - - /// Device memory pages. - enum PageNum { - UserData0 = 0, - UserData1, - UserData2, - UserData3, - UserData4, - UserData5, - UserData6, - UserData7, - UserData8, - UserData9, - UserData10, - UserData11, - UserData12, - UserData13, - UserData14, - UserData15, - PublicKeyAX, - PublicKeyAY, - PublicKeyBX, - PublicKeyBY, - PublicKeyCX, - PublicKeyCY, - PrivateKeyA, - PrivateKeyB, - PrivateKeyC, - SecretA, - SecretB, - DecrementCounter, - RomOptions, - GpioControl, - PublicKeySX, - PublicKeySY - }; - - /// Available keys for ECDSA operations. - enum KeyNum { KeyNumA = 0, KeyNumB = 1, KeyNumC = 2, KeyNumS = 3 }; - - /// Available secrets for HMAC operations. - enum SecretNum { SecretNumA = 0, SecretNumB = 1, SecretNumS = 2 }; - - /// Data hash type when verifying an ECDSA signature. - enum HashType { - HashInBuffer = 0, ///< Hash is loaded in the buffer. - DataInBuffer = 1, ///< Compute hash from data loaded in the buffer. - THASH = 2 ///< Use THASH from Compute Multiblock Hash command. - }; - - /// Available PIO states when verifying an ECDSA signature. - enum PioState { Unchanged, Conducting, HighImpedance }; - - /// Holds a device memory page. - typedef array<uint_least8_t, 32> Page; - - /// Holds page authentication input data. - typedef array<uint_least8_t, 75> PageAuthenticationData; - - /// Page protection types. - enum PageProtectionType { - RP = 0x01, ///< Read protection. - WP = 0x02, ///< Write protection. - EM = 0x04, ///< EPROM emulation mode. - APH = 0x08, ///< Authentication write protection HMAC. - EPH = 0x10, ///< Encryption and authenticated write protection HMAC. - AUTH = 0x20, ///< Public Key C is set to authority public key. - ECH = 0x40, ///< Encrypted read and write using shared key from ECDH. - ECW = 0x80 ///< Authentication write protection ECDSA. - }; - typedef FlagSet<PageProtectionType, 8> PageProtection; - - /// Holds an encrypted device memory page. - struct EncryptedPage { - typedef array<uint_least8_t, 8> Challenge; - - /// Total size of all elements in bytes. - static const size_t size = Challenge::csize + Page::csize; - - Challenge challenge; - Page data; - }; - - /// Number of memory pages on the device. - static const int memoryPages = 32; - - DS28C36(const Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x36) - : sleep_(&sleep), master(&master), address_(address & 0xFE) {} - - void setSleep(const Sleep & sleep) { this->sleep_ = &sleep; } - void setMaster(I2CMaster & master) { this->master = &master; } - uint_least8_t address() const { return address_; } - void setAddress(uint_least8_t address) { this->address_ = (address & 0xFE); } - - /// Write memory with no protection. - /// @param pageNum Number of page to write. - /// @param page Data to write. - MaximInterface_EXPORT error_code writeMemory(int pageNum, const Page & page); - - /// Read memory with no protection. - /// @param pageNum Number of page to read. - /// @param[out] page Data that was read. - MaximInterface_EXPORT error_code readMemory(int pageNum, Page & page); - - /// Write the temporary buffer. - /// @param data Data to write. - /// @param dataSize Size of data to write. - MaximInterface_EXPORT error_code writeBuffer(const uint_least8_t * data, - size_t dataSize); - - /// Read the temporary buffer. - /// @param[out] data Data that was read. - MaximInterface_EXPORT error_code - readBuffer(std::vector<uint_least8_t> & data); - - /// Read the protection settings of a page. - /// @param pageNum Number of page to read. - /// @param[out] protection Protection that was read. - MaximInterface_EXPORT error_code - readPageProtection(int pageNum, PageProtection & protection); - - /// Set the protection settings of a page. - /// @param pageNum Number of page to write. - /// @param protection Protection to write. - MaximInterface_EXPORT error_code - setPageProtection(int pageNum, const PageProtection & protection); - - /// Decrement the decrement-only counter. - MaximInterface_EXPORT error_code decrementCounter(); - - /// Read a block of random data from the RNG. - /// @param[out] data Buffer to hold random data from RNG. - /// @param dataSize Number of bytes to read from 1 to 64 and length of data. - MaximInterface_EXPORT error_code readRng(uint_least8_t * data, - size_t dataSize); - - /// Read memory with encryption. - /// @param pageNum Number of page to read from. - /// @param secretNum Secret to use for encryption. - /// @param[out] page Data that was read. - MaximInterface_EXPORT error_code encryptedReadMemory(int pageNum, - SecretNum secretNum, - EncryptedPage & page); - - /// Compute and read page authentication with ECDSA. - /// @param pageNum Number of page to authenticate. - /// @param keyNum Private key to use for authentication. - /// Key S cannot be used with this command. - /// @param[out] signature Computed page signature. - MaximInterface_EXPORT error_code computeAndReadEcdsaPageAuthentication( - int pageNum, KeyNum keyNum, Ecc256::Signature & signature); - - /// Compute and read page authentication with HMAC. - /// @param pageNum Number of page to authenticate. - /// @param secretNum Secret to use for authentication. - /// @param[out] hmac Computed page HMAC. - MaximInterface_EXPORT error_code computeAndReadHmacPageAuthentication( - int pageNum, SecretNum secretNum, Sha256::Hash & hmac); - - /// Write with SHA2 authentication. - /// @param pageNum Number of page to write. - /// @param secretNum Secret to use for authentication. - /// @param page Data to write. - MaximInterface_EXPORT error_code authenticatedSha2WriteMemory( - int pageNum, SecretNum secretNum, const Page & page); - - /// Compute SHA2 secret and optionally lock. - /// @param pageNum Number of page to use in computation. - /// @param msecretNum Master secret to use in computation. - /// @param dsecretNum Destination secret to receive the computation result. - /// @param writeProtectEnable - /// True to lock the destination secret against further writes. - MaximInterface_EXPORT error_code - computeAndLockSha2Secret(int pageNum, SecretNum msecretNum, - SecretNum dsecretNum, bool writeProtectEnable); - - /// Generate a new ECDSA key pair. - /// @param keyNum Key to generate. Key S cannot be used with this command. - /// @param writeProtectEnable True to lock the key against further writes. - MaximInterface_EXPORT error_code - generateEcc256KeyPair(KeyNum keyNum, bool writeProtectEnable); - - /// Compute a hash over multiple blocks. - /// @param firstBlock True if this is the first block being hashed. - /// @param lastBlock True if this is the last block being hashed. - /// @param data Data block to hash. - /// @param dataSize Size of data to hash. - /// Should be 64 bytes unless this is the last block. - MaximInterface_EXPORT error_code - computeMultiblockHash(bool firstBlock, bool lastBlock, - const uint_least8_t * data, size_t dataSize); - - /// Verify ECDSA signature. - /// @param keyNum Public key to use for verification. - /// @param hashType Source of the data hash input. - /// @param signature Signature to verify. - /// @param pioa New state of PIOA if verification successful. - /// @param piob New state of PIOB if verification successful. - MaximInterface_EXPORT error_code verifyEcdsaSignature( - KeyNum keyNum, HashType hashType, const Ecc256::Signature & signature, - PioState pioa = Unchanged, PioState piob = Unchanged); - - /// Authenticate a public key for authenticated writes or encrypted reads with ECDH. - /// @param authWrites True to select authentication for writes. - /// @param ecdh True to select ECDH key exchange. - /// @param keyNum Private key to use for ECDH key exchange. - /// Key A or B can be selected. - /// @param csOffset Certificate customization field ending offset in buffer. - /// @param signature Signature to use for authentication of public key S. - MaximInterface_EXPORT error_code - authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum, - int csOffset, const Ecc256::Signature & signature); - - /// Write with ECDSA authentication. - /// @param pageNum Number of page to write. - /// @param page Data to write. - MaximInterface_EXPORT error_code - authenticatedEcdsaWriteMemory(int pageNum, const Page & page); - - /// Create data used by the Compute and Read Page Authentication command to - /// generate a signature. - MaximInterface_EXPORT static PageAuthenticationData - createPageAuthenticationData(const RomId & romId, const Page & page, - const Page & challenge, int pageNum, - const ManId & manId); - - MaximInterface_EXPORT static const error_category & errorCategory(); - -protected: - // Timing constants. - static const int generateEcdsaSignatureTimeMs = 50; - static const int generateEccKeyPairTimeMs = 100; - static const int verifyEsdsaSignatureOrComputeEcdhTimeMs = 150; - static const int sha256ComputationTimeMs = 3; - static const int readMemoryTimeMs = /*1*/ 2; - static const int writeMemoryTimeMs = 15; - - error_code writeCommand(uint_least8_t command, - const uint_least8_t * parameters, - size_t parametersSize); - - error_code writeCommand(uint_least8_t command) { - return writeCommand(command, NULL, 0); - } - - error_code readVariableLengthResponse(uint_least8_t * response, - size_t & responseSize); - - error_code readFixedLengthResponse(uint_least8_t * response, - size_t responseSize); - - void sleep(int ms) const { (*sleep_)(ms); } - -private: - enum AuthType { - HmacWithSecretA = 0, - HmacWithSecretB = 1, - HmacWithSecretS = 2, - EcdsaWithKeyA = 3, - EcdsaWithKeyB = 4, - EcdsaWithKeyC = 5 - }; - - const Sleep * sleep_; - I2CMaster * master; - uint_least8_t address_; - - error_code computeAndReadPageAuthentication(int pageNum, AuthType authType); -}; - -/// Read the device ROM ID and MAN ID using the Read Memory command on the -/// ROM Options page. -/// @param[out] romId -/// Read ROM ID valid when operation is successful. May be set to NULL. -/// @param[out] manId -/// Read MAN ID valid when operation is successful. May be set to NULL. -MaximInterface_EXPORT error_code readRomIdAndManId(DS28C36 & ds28c36, - RomId * romId, - ManId * manId); - -/// Hash arbitrary length data with successive Compute Multiblock Hash commands. -/// @param data Data to hash. -/// @param dataSize Size of data to hash. -MaximInterface_EXPORT error_code computeMultiblockHash( - DS28C36 & ds28c36, const uint_least8_t * data, const size_t dataSize); - -/// Verify ECDSA signature. -/// @param publicKey Public key to use for verification. -/// @param data Data to verify. -/// @param dataSize Size of data to verify. -/// @param signature Signature to verify. -/// @param pioa New state of PIOA if verification successful. -/// @param piob New state of PIOB if verification successful. -MaximInterface_EXPORT error_code verifyEcdsaSignature( - DS28C36 & ds28c36, DS28C36::KeyNum publicKey, const uint_least8_t * data, - size_t dataSize, const Ecc256::Signature & signature, - DS28C36::PioState pioa = DS28C36::Unchanged, - DS28C36::PioState piob = DS28C36::Unchanged); - -/// Verify ECDSA signature. -/// @param publicKey -/// Public key to use for verification which is loaded into Public Key S. -/// @param data Data to verify. -/// @param dataSize Size of data to verify. -/// @param signature Signature to verify. -/// @param pioa New state of PIOA if verification successful. -/// @param piob New state of PIOB if verification successful. -MaximInterface_EXPORT error_code -verifyEcdsaSignature(DS28C36 & ds28c36, const Ecc256::PublicKey & publicKey, - const uint_least8_t * data, size_t dataSize, - const Ecc256::Signature & signature, - DS28C36::PioState pioa = DS28C36::Unchanged, - DS28C36::PioState piob = DS28C36::Unchanged); - -inline error_code make_error_code(DS28C36::ErrorValue e) { - return error_code(e, DS28C36::errorCategory()); -} - -/// Interface to the DS2476 coprocessor. -class DS2476 : public DS28C36 { -public: - DS2476(const Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x76) - : DS28C36(sleep, master, address) {} - - /// Generate ECDSA signature. - /// @param keyNum Private key to use to create signature. - /// Key S cannot be used with this command. - /// @param[out] signature Computed signature. - MaximInterface_EXPORT error_code - generateEcdsaSignature(KeyNum keyNum, Ecc256::Signature & signature); - - /// Compute unique SHA2 secret. - /// @param msecretNum Master secret to use in computation. - MaximInterface_EXPORT error_code - computeSha2UniqueSecret(SecretNum msecretNum); - - /// Compute SHA2 HMAC. - /// @param[out] hmac Computed HMAC. - MaximInterface_EXPORT error_code computeSha2Hmac(Sha256::Hash & hmac); -}; - -/// Enable coprocessor functionality on the DS2476 by writing to the -/// ROM Options page. -MaximInterface_EXPORT error_code enableCoprocessor(DS2476 & ds2476); - -} // namespace MaximInterface - -#endif +/******************************************************************************* +* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#ifndef MaximInterface_DS28C36_DS2476 +#define MaximInterface_DS28C36_DS2476 + +#include <stdint.h> +#include <vector> +#include <MaximInterface/Links/I2CMaster.hpp> +#include <MaximInterface/Links/Sleep.hpp> +#include <MaximInterface/Utilities/array_span.hpp> +#include <MaximInterface/Utilities/Ecc256.hpp> +#include <MaximInterface/Utilities/Export.h> +#include <MaximInterface/Utilities/RomId.hpp> +#include <MaximInterface/Utilities/ManId.hpp> +#include <MaximInterface/Utilities/Sha256.hpp> +#include <MaximInterface/Utilities/system_error.hpp> +#include <MaximInterface/Utilities/FlagSet.hpp> + +namespace MaximInterface { + +/// Interface to the DS28C36 authenticator. +class DS28C36 { +public: + /// Device command results. + enum ErrorValue { + ProtectionError = 0x55, + InvalidParameterError = 0x77, + InvalidSequenceError = 0x33, + InvalidEcdsaInputOrResultError = 0x22, + AuthenticationError = 0x100, + InvalidResponseError = 0x101 ///< Response does not match expected format. + }; + + /// @name Device memory pages + /// @{ + + static const int publicKeyAxPage = 16; + static const int publicKeyAyPage = 17; + static const int publicKeyBxPage = 18; + static const int publicKeyByPage = 19; + static const int publicKeyCxPage = 20; + static const int publicKeyCyPage = 21; + static const int privateKeyAPage = 22; + static const int privateKeyBPage = 23; + static const int privateKeyCPage = 24; + static const int secretAPage = 25; + static const int secretBPage = 26; + static const int decrementCounterPage = 27; + static const int romOptionsPage = 28; + static const int gpioControlPage = 29; + static const int publicKeySxPage = 30; + static const int publicKeySyPage = 31; + + /// @} + + /// Number of memory pages on the device. + static const int memoryPages = 32; + + /// Available keys for ECDSA operations. + enum KeyNum { KeyNumA = 0, KeyNumB = 1, KeyNumC = 2, KeyNumS = 3 }; + + /// Available secrets for HMAC operations. + enum SecretNum { SecretNumA = 0, SecretNumB = 1, SecretNumS = 2 }; + + /// Data hash type when verifying an ECDSA signature. + enum HashType { + HashInBuffer = 0, ///< Hash is loaded in the buffer. + DataInBuffer = 1, ///< Compute hash from data loaded in the buffer. + THASH = 2 ///< Use THASH from Compute Multiblock Hash command. + }; + + /// Available PIO states when verifying an ECDSA signature. + enum PioState { Unchanged, Conducting, HighImpedance }; + + /// Holds a device memory page. + typedef array_span<uint_least8_t, 32> Page; + + // Format page authentication input data. + class PageAuthenticationData; + + // Format authenticated write input data. + class WriteAuthenticationData; + + // Format compute secret input data. + class ComputeSecretData; + + // Format encryption or decryption HMAC input data. + class EncryptionHmacData; + + // Access fields in the ROM Options page. + class RomOptions; + + // Access fields in the GPIO Control page. + class GpioControl; + + /// Page protection types. + enum PageProtectionType { + RP = 0x01, ///< Read protection. + WP = 0x02, ///< Write protection. + EM = 0x04, ///< EPROM emulation mode. + APH = 0x08, ///< Authentication write protection HMAC. + EPH = 0x10, ///< Encryption and authenticated write protection HMAC. + AUTH = 0x20, ///< Public Key C is set to authority public key. + ECH = 0x40, ///< Encrypted read and write using shared key from ECDH. + ECW = 0x80 ///< Authentication write protection ECDSA. + }; + typedef FlagSet<PageProtectionType, 8> PageProtection; + + /// Challenge for an encrypted device memory page. + typedef array_span<uint_least8_t, 8> EncryptionChallenge; + + DS28C36(Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x36) + : sleep_(&sleep), master(&master), address_(address & 0xFE) {} + + void setSleep(Sleep & sleep) { sleep_ = &sleep; } + + void setMaster(I2CMaster & master) { this->master = &master; } + + uint_least8_t address() const { return address_; } + + void setAddress(uint_least8_t address) { address_ = address & 0xFE; } + + /// @brief Write memory with no protection. + /// @param pageNum Number of page to write. + /// @param page Data to write. + MaximInterface_EXPORT error_code writeMemory(int pageNum, + Page::const_span page); + + /// @brief Read memory with no protection. + /// @param pageNum Number of page to read. + /// @param[out] page Data that was read. + MaximInterface_EXPORT error_code readMemory(int pageNum, Page::span page); + + /// @brief Write the temporary buffer. + /// @param data Data to write. + MaximInterface_EXPORT error_code writeBuffer(span<const uint_least8_t> data); + + /// @brief Read the temporary buffer. + /// @param[out] data Data that was read. + MaximInterface_EXPORT error_code + readBuffer(std::vector<uint_least8_t> & data); + + /// @brief Read the protection settings of a page. + /// @param pageNum Number of page to read. + /// @param[out] protection Protection that was read. + MaximInterface_EXPORT error_code + readPageProtection(int pageNum, PageProtection & protection); + + /// @brief Set the protection settings of a page. + /// @param pageNum Number of page to write. + /// @param protection Protection to write. + MaximInterface_EXPORT error_code + setPageProtection(int pageNum, const PageProtection & protection); + + /// Decrement the decrement-only counter. + MaximInterface_EXPORT error_code decrementCounter(); + + /// @brief Read a block of random data from the RNG. + /// @param[out] data Random data from RNG with length from 1 to 64. + MaximInterface_EXPORT error_code readRng(span<uint_least8_t> data); + + /// @brief Read memory with encryption. + /// @param pageNum Number of page to read from. + /// @param secretNum Secret to use for encryption. + /// @param[out] challenge Encryption challenge that was read. + /// @param[out] data Encrypted page data that was read. + MaximInterface_EXPORT error_code + encryptedReadMemory(int pageNum, SecretNum secretNum, + EncryptionChallenge::span challenge, Page::span data); + + /// @brief Compute and read page authentication with ECDSA. + /// @param pageNum Number of page to authenticate. + /// @param keyNum + /// Private key to use for authentication. + /// Key S cannot be used with this command. + /// @param[out] signature Computed page signature. + MaximInterface_EXPORT error_code computeAndReadPageAuthentication( + int pageNum, KeyNum keyNum, Ecc256::Signature::span signature); + + /// @brief Compute and read page authentication with HMAC. + /// @param pageNum Number of page to authenticate. + /// @param secretNum Secret to use for authentication. + /// @param[out] hmac Computed page HMAC. + MaximInterface_EXPORT error_code computeAndReadPageAuthentication( + int pageNum, SecretNum secretNum, Sha256::Hash::span hmac); + + /// @brief Write with SHA2 authentication. + /// @param pageNum Number of page to write. + /// @param secretNum Secret to use for authentication. + /// @param page Data to write. + MaximInterface_EXPORT error_code authenticatedSha2WriteMemory( + int pageNum, SecretNum secretNum, Page::const_span page); + + /// @brief Compute SHA2 secret and optionally lock. + /// @param pageNum Number of page to use in computation. + /// @param msecretNum Master secret to use in computation. + /// @param dsecretNum Destination secret to receive the computation result. + /// @param writeProtectEnable + /// True to lock the destination secret against further writes. + MaximInterface_EXPORT error_code + computeAndLockSha2Secret(int pageNum, SecretNum msecretNum, + SecretNum dsecretNum, bool writeProtectEnable); + + /// @brief Generate a new ECDSA key pair. + /// @param keyNum Key to generate. Key S cannot be used with this command. + /// @param writeProtectEnable True to lock the key against further writes. + MaximInterface_EXPORT error_code + generateEcc256KeyPair(KeyNum keyNum, bool writeProtectEnable); + + /// @brief Compute a hash over multiple blocks. + /// @param firstBlock True if this is the first block being hashed. + /// @param lastBlock True if this is the last block being hashed. + /// @param data + /// Data block to hash. Should be 64 bytes unless this is the last block. + MaximInterface_EXPORT error_code computeMultiblockHash( + bool firstBlock, bool lastBlock, span<const uint_least8_t> data); + + /// @brief Verify ECDSA signature. + /// @param keyNum Public key to use for verification. + /// @param hashType Source of the data hash input. + /// @param signature Signature to verify. + /// @param pioa New state of PIOA if verification successful. + /// @param piob New state of PIOB if verification successful. + MaximInterface_EXPORT error_code verifyEcdsaSignature( + KeyNum keyNum, HashType hashType, Ecc256::Signature::const_span signature, + PioState pioa = Unchanged, PioState piob = Unchanged); + + /// @brief + /// Authenticate a public key for authenticated writes or encrypted reads + /// with ECDH. + /// @param authWrites True to select authentication for writes. + /// @param ecdh True to select ECDH key exchange. + /// @param keyNum + /// Private key to use for ECDH key exchange. Key A or B can be selected. + /// @param csOffset Certificate customization field ending offset in buffer. + /// @param signature Signature to use for authentication of public key S. + MaximInterface_EXPORT error_code authenticateEcdsaPublicKey( + bool authWrites, bool ecdh, KeyNum keyNum, int csOffset, + Ecc256::Signature::const_span signature); + + /// @brief Write with ECDSA authentication. + /// @param pageNum Number of page to write. + /// @param page Data to write. + MaximInterface_EXPORT error_code + authenticatedEcdsaWriteMemory(int pageNum, Page::const_span page); + + MaximInterface_EXPORT static const error_category & errorCategory(); + +protected: + // Timing constants. + static const int generateEcdsaSignatureTimeMs = 50; + static const int generateEccKeyPairTimeMs = 100; + static const int verifyEsdsaSignatureOrComputeEcdhTimeMs = 150; + static const int sha256ComputationTimeMs = 3; + static const int readMemoryTimeMs = /*1*/ 2; + static const int writeMemoryTimeMs = 15; + + error_code writeCommand(uint_least8_t command, + span<const uint_least8_t> parameters); + + error_code writeCommand(uint_least8_t command) { + return writeCommand(command, span<const uint_least8_t>()); + } + + error_code readVariableLengthResponse(span<uint_least8_t> & response); + + error_code readFixedLengthResponse(span<uint_least8_t> response); + + void sleep(int ms) const { sleep_->invoke(ms); } + +private: + enum AuthType { + HmacWithSecretA = 0, + HmacWithSecretB = 1, + HmacWithSecretS = 2, + EcdsaWithKeyA = 3, + EcdsaWithKeyB = 4, + EcdsaWithKeyC = 5 + }; + + const Sleep * sleep_; + I2CMaster * master; + uint_least8_t address_; + + error_code computeAndReadPageAuthentication(int pageNum, AuthType authType); +}; + +/// Interface to the DS2476 coprocessor. +class DS2476 : public DS28C36 { +public: + DS2476(Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x76) + : DS28C36(sleep, master, address) {} + + /// @brief Generate ECDSA signature. + /// @param keyNum + /// Private key to use to create signature. + /// Key S cannot be used with this command. + /// @param[out] signature Computed signature. + MaximInterface_EXPORT error_code + generateEcdsaSignature(KeyNum keyNum, Ecc256::Signature::span signature); + + /// @brief Compute unique SHA2 secret. + /// @param msecretNum Master secret to use in computation. + MaximInterface_EXPORT error_code + computeSha2UniqueSecret(SecretNum msecretNum); + + /// @brief Compute SHA2 HMAC. + /// @param[out] hmac Computed HMAC. + MaximInterface_EXPORT error_code computeSha2Hmac(Sha256::Hash::span hmac); +}; + +inline error_code make_error_code(DS28C36::ErrorValue e) { + return error_code(e, DS28C36::errorCategory()); +} + +/// @brief +/// Hash arbitrary length data with successive Compute Multiblock Hash commands. +/// @param ds28c36 Device for computation. +/// @param data Data to hash. +MaximInterface_EXPORT error_code +computeMultiblockHash(DS28C36 & ds28c36, span<const uint_least8_t> data); + +/// @brief Verify ECDSA signature. +/// @param ds28c36 Device for computation. +/// @param publicKey Public key to use for verification. +/// @param data Data to verify. +/// @param signature Signature to verify. +/// @param pioa New state of PIOA if verification successful. +/// @param piob New state of PIOB if verification successful. +MaximInterface_EXPORT error_code verifyEcdsaSignature( + DS28C36 & ds28c36, DS28C36::KeyNum publicKey, + span<const uint_least8_t> data, Ecc256::Signature::const_span signature, + DS28C36::PioState pioa = DS28C36::Unchanged, + DS28C36::PioState piob = DS28C36::Unchanged); + +/// @brief Verify ECDSA signature. +/// @param ds28c36 Device for computation. +/// @param publicKey +/// Public key to use for verification which is loaded into Public Key S. +/// @param data Data to verify. +/// @param signature Signature to verify. +/// @param pioa New state of PIOA if verification successful. +/// @param piob New state of PIOB if verification successful. +MaximInterface_EXPORT error_code verifyEcdsaSignature( + DS28C36 & ds28c36, Ecc256::PublicKey::const_span publicKey, + span<const uint_least8_t> data, Ecc256::Signature::const_span signature, + DS28C36::PioState pioa = DS28C36::Unchanged, + DS28C36::PioState piob = DS28C36::Unchanged); + +/// @brief +/// Read the device ROM ID and MAN ID using the Read Memory command on the +/// ROM Options page. +/// @param ds28c36 Device to read. +/// @param[out] romId Read ROM ID valid when operation is successful. +/// @param[out] manId Read MAN ID valid when operation is successful. +MaximInterface_EXPORT error_code readRomIdAndManId(DS28C36 & ds28c36, + RomId::span romId, + ManId::span manId); + +/// @brief +/// Enable coprocessor functionality on the DS2476 by writing to the +/// GPIO Control page. +MaximInterface_EXPORT error_code enableCoprocessor(DS2476 & ds2476); + +/// @brief +/// Disable blocking of the ROM ID on the DS2476 by writing to the +/// ROM Options page. +MaximInterface_EXPORT error_code enableRomId(DS2476 & ds2476); + +/// Format page authentication input data. +class DS28C36::PageAuthenticationData { +public: + typedef array_span<uint_least8_t, + RomId::size + 2 * Page::size + 1 + ManId::size> + Result; + + PageAuthenticationData() : result_() {} + + /// Formatted data result. + Result::const_span result() const { return result_; } + + /// @name ROM ID + /// @brief 1-Wire ROM ID of the device. + /// @{ + + /// Get mutable ROM ID. + RomId::span romId() { + return make_span(result_).subspan<romIdIdx, RomId::size>(); + } + + /// Get immutable ROM ID. + RomId::const_span romId() const { + return const_cast<PageAuthenticationData &>(*this).romId(); + } + + /// Set ROM ID. + PageAuthenticationData & setRomId(RomId::const_span romId) { + copy(romId, this->romId()); + return *this; + } + + /// Set ROM ID for use in anonymous mode. + MaximInterface_EXPORT PageAuthenticationData & setAnonymousRomId(); + + /// @} + + /// @name Page + /// @brief Data from a device memory page. + /// @{ + + /// Get mutable page. + Page::span page() { + return make_span(result_).subspan<pageIdx, Page::size>(); + } + + /// Get immutable page. + Page::const_span page() const { + return const_cast<PageAuthenticationData &>(*this).page(); + } + + /// Set page. + PageAuthenticationData & setPage(Page::const_span page) { + copy(page, this->page()); + return *this; + } + + /// @} + + /// @name Challenge + /// @brief Random challenge used to prevent replay attacks. + /// @{ + + /// Get mutable Challenge. + Page::span challenge() { + return make_span(result_).subspan<challengeIdx, Page::size>(); + } + + /// Get immutable Challenge. + Page::const_span challenge() const { + return const_cast<PageAuthenticationData &>(*this).challenge(); + } + + /// Set Challenge. + PageAuthenticationData & setChallenge(Page::const_span challenge) { + copy(challenge, this->challenge()); + return *this; + } + + /// @} + + /// @name Page number + /// @brief Number of the page to use data from. + /// @{ + + /// Get page number. + int pageNum() const { return result_[pageNumIdx]; } + + /// Set page number. + PageAuthenticationData & setPageNum(int pageNum) { + result_[pageNumIdx] = pageNum; + return *this; + } + + /// @} + + /// @name MAN ID + /// @brief Manufacturer ID of the device. + /// @{ + + /// Get mutable MAN ID. + ManId::span manId() { + return make_span(result_).subspan<manIdIdx, ManId::size>(); + } + + /// Get immutable MAN ID. + ManId::const_span manId() const { + return const_cast<PageAuthenticationData &>(*this).manId(); + } + + /// Set MAN ID. + PageAuthenticationData & setManId(ManId::const_span manId) { + copy(manId, this->manId()); + return *this; + } + + /// @} + +private: + typedef Result::span::index_type index; + + static const index romIdIdx = 0; + static const index pageIdx = romIdIdx + RomId::size; + static const index challengeIdx = pageIdx + Page::size; + static const index pageNumIdx = challengeIdx + Page::size; + static const index manIdIdx = pageNumIdx + 1; + + Result::array result_; +}; + +/// Format authenticated write input data. +class DS28C36::WriteAuthenticationData { +public: + typedef PageAuthenticationData::Result Result; + + WriteAuthenticationData() : data() {} + + /// Formatted data result. + Result::const_span result() const { return data.result(); } + + /// @name ROM ID + /// @brief 1-Wire ROM ID of the device. + /// @{ + + /// Get mutable ROM ID. + RomId::span romId() { return data.romId(); } + + /// Get immutable ROM ID. + RomId::const_span romId() const { return data.romId(); } + + /// Set ROM ID. + WriteAuthenticationData & setRomId(RomId::const_span romId) { + data.setRomId(romId); + return *this; + } + + /// Set ROM ID for use in anonymous mode. + WriteAuthenticationData & setAnonymousRomId() { + data.setAnonymousRomId(); + return *this; + } + + /// @} + + /// @name Old page + /// @brief Existing data contained in the page. + /// @{ + + /// Get mutable old page. + Page::span oldPage() { return data.page(); } + + /// Get immutable old page. + Page::const_span oldPage() const { return data.page(); } + + /// Set old page. + WriteAuthenticationData & setOldPage(Page::const_span oldPage) { + data.setPage(oldPage); + return *this; + } + + /// @} + + /// @name New page + /// @brief New data to write to the page. + /// @{ + + /// Get mutable new page. + Page::span newPage() { return data.challenge(); } + + /// Get immutable new page. + Page::const_span newPage() const { return data.challenge(); } + + /// Set new page. + WriteAuthenticationData & setNewPage(Page::const_span newPage) { + data.setChallenge(newPage); + return *this; + } + + /// @} + + /// @name Page number + /// @brief Page number for write operation. + /// @{ + + /// Get page number. + int pageNum() const { return data.pageNum(); } + + /// Set page number. + WriteAuthenticationData & setPageNum(int pageNum) { + data.setPageNum(pageNum); + return *this; + } + + /// @} + + /// @name MAN ID + /// @brief Manufacturer ID of the device. + /// @{ + + /// Get mutable MAN ID. + ManId::span manId() { return data.manId(); } + + /// Get immutable MAN ID. + ManId::const_span manId() const { return data.manId(); } + + /// Set MAN ID. + WriteAuthenticationData & setManId(ManId::const_span manId) { + data.setManId(manId); + return *this; + } + + /// @} + +private: + PageAuthenticationData data; +}; + +/// Format compute secret input data. +class DS28C36::ComputeSecretData { +public: + typedef PageAuthenticationData::Result Result; + + ComputeSecretData() : data() {} + + /// Formatted data result. + Result::const_span result() const { return data.result(); } + + /// @name ROM ID + /// @brief 1-Wire ROM ID of the device. + /// @{ + + /// Get mutable ROM ID. + RomId::span romId() { return data.romId(); } + + /// Get immutable ROM ID. + RomId::const_span romId() const { return data.romId(); } + + /// Set ROM ID. + ComputeSecretData & setRomId(RomId::const_span romId) { + data.setRomId(romId); + return *this; + } + + /// @} + + /// @name Binding Data + /// @brief Binding Data contained in the selected page. + /// @{ + + /// Get mutable Binding Data. + Page::span bindingData() { return data.page(); } + + /// Get immutable Binding Data. + Page::const_span bindingData() const { return data.page(); } + + /// Set Binding Data. + ComputeSecretData & setBindingData(Page::const_span bindingData) { + data.setPage(bindingData); + return *this; + } + + /// @} + + /// @name Partial Secret + /// @brief Partial Secret used for customization. + /// @{ + + /// Get mutable Partial Secret. + Page::span partialSecret() { return data.challenge(); } + + /// Get immutable Partial Secret. + Page::const_span partialSecret() const { return data.challenge(); } + + /// Set Partial Secret. + ComputeSecretData & setPartialSecret(Page::const_span partialSecret) { + data.setChallenge(partialSecret); + return *this; + } + + /// @} + + /// @name Page number + /// @brief Page number for Binding Data. + /// @{ + + /// Get page number. + int pageNum() const { return data.pageNum(); } + + /// Set page number. + ComputeSecretData & setPageNum(int pageNum) { + data.setPageNum(pageNum); + return *this; + } + + /// @} + + /// @name MAN ID + /// @brief Manufacturer ID of the device. + /// @{ + + /// Get mutable MAN ID. + ManId::span manId() { return data.manId(); } + + /// Get immutable MAN ID. + ManId::const_span manId() const { return data.manId(); } + + /// Set MAN ID. + ComputeSecretData & setManId(ManId::const_span manId) { + data.setManId(manId); + return *this; + } + + /// @} + +private: + PageAuthenticationData data; +}; + +/// Format encryption or decryption HMAC input data. +class DS28C36::EncryptionHmacData { +public: + typedef array_span<uint_least8_t, + EncryptionChallenge::size + RomId::size + 1 + ManId::size> + Result; + + EncryptionHmacData() : result_() {} + + /// Formatted data result. + Result::const_span result() const { return result_; } + + /// @name Encryption Challenge + /// @brief Random challenge used to prevent replay attacks. + /// @{ + + /// Get mutable Encryption Challenge. + EncryptionChallenge::span encryptionChallenge() { + return make_span(result_) + .subspan<encryptionChallengeIdx, EncryptionChallenge::size>(); + } + + /// Get immutable Encryption Challenge. + EncryptionChallenge::const_span encryptionChallenge() const { + return const_cast<EncryptionHmacData &>(*this).encryptionChallenge(); + } + + /// Set Encryption Challenge. + EncryptionHmacData & + setEncryptionChallenge(EncryptionChallenge::const_span encryptionChallenge) { + copy(encryptionChallenge, this->encryptionChallenge()); + return *this; + } + + /// @} + + /// @name ROM ID + /// @brief 1-Wire ROM ID of the device. + /// @{ + + /// Get mutable ROM ID. + RomId::span romId() { + return make_span(result_).subspan<romIdIdx, RomId::size>(); + } + + /// Get immutable ROM ID. + RomId::const_span romId() const { + return const_cast<EncryptionHmacData &>(*this).romId(); + } + + /// Set ROM ID. + EncryptionHmacData & setRomId(RomId::const_span romId) { + copy(romId, this->romId()); + return *this; + } + + /// Set ROM ID for use in anonymous mode. + MaximInterface_EXPORT EncryptionHmacData & setAnonymousRomId(); + + /// @} + + /// @name Page number + /// @brief Number of the page to use data from. + /// @{ + + /// Get page number. + int pageNum() const { return result_[pageNumIdx]; } + + /// Set page number. + EncryptionHmacData & setPageNum(int pageNum) { + result_[pageNumIdx] = pageNum; + return *this; + } + + /// @} + + /// @name MAN ID + /// @brief Manufacturer ID of the device. + /// @{ + + /// Get mutable MAN ID. + ManId::span manId() { + return make_span(result_).subspan<manIdIdx, ManId::size>(); + } + + /// Get immutable MAN ID. + ManId::const_span manId() const { + return const_cast<EncryptionHmacData &>(*this).manId(); + } + + /// Set MAN ID. + EncryptionHmacData & setManId(ManId::const_span manId) { + copy(manId, this->manId()); + return *this; + } + + /// @} + +private: + typedef Result::span::index_type index; + + static const index encryptionChallengeIdx = 0; + static const index romIdIdx = + encryptionChallengeIdx + EncryptionChallenge::size; + static const index pageNumIdx = romIdIdx + RomId::size; + static const index manIdIdx = pageNumIdx + 1; + + Result::array result_; +}; + +/// Access fields in the ROM Options page. +class DS28C36::RomOptions { +public: + explicit RomOptions(Page::span page) : page(page) {} + + bool romBlockDisable() const { + return page[romBlockDisableIdx] == enabledValue; + } + + RomOptions & setRomBlockDisable(bool romBlockDisable) { + page[romBlockDisableIdx] = (romBlockDisable ? enabledValue : 0); + return *this; + } + + bool anonymous() const { return page[anonymousIdx] == enabledValue; } + + RomOptions & setAnonymous(bool anonymous) { + page[anonymousIdx] = (anonymous ? enabledValue : 0); + return *this; + } + + ManId::const_span manId() const { + return page.subspan<22, ManId::size>(); + } + + RomId::const_span romId() const { + return page.subspan<24, RomId::size>(); + } + +private: + static const Page::span::index_type romBlockDisableIdx = 0; + static const Page::span::index_type anonymousIdx = 1; + static const Page::span::value_type enabledValue = 0xAA; + + Page::span page; +}; + +/// Access fields in the GPIO Control page. +class DS28C36::GpioControl { +public: + explicit GpioControl(Page::span page) : page(page) {} + + bool pioaConducting() const { + return page[pioaConductingIdx] == pioConductingValue; + } + + GpioControl & setPioaConducting(bool pioaConducting) { + page[pioaConductingIdx] = (pioaConducting ? pioConductingValue : 0x55); + return *this; + } + + bool piobConducting() const { + return page[piobConductingIdx] == pioConductingValue; + } + + GpioControl & setPiobConducting(bool piobConducting) { + page[piobConductingIdx] = (piobConducting ? pioConductingValue : 0x55); + return *this; + } + + bool pioaLevel() const { return page[2] == pioLevelValue; } + + bool piobLevel() const { return page[3] == pioLevelValue; } + +private: + static const Page::span::index_type pioaConductingIdx = 0; + static const Page::span::index_type piobConductingIdx = 1; + static const Page::span::value_type pioConductingValue = 0xAA; + static const Page::span::value_type pioLevelValue = 0x55; + + Page::span page; +}; + +} // namespace MaximInterface + +#endif
--- a/Devices/DS28E15_22_25.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS28E15_22_25.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -31,29 +31,28 @@ *******************************************************************************/ #include <algorithm> -#include "DS28E15_22_25.hpp" #include <MaximInterface/Utilities/crc.hpp> #include <MaximInterface/Utilities/Error.hpp> - -using std::copy; +#include "DS28E15_22_25.hpp" namespace MaximInterface { using namespace Sha256; +using std::copy; static const int shaComputationDelayMs = 3; static const int eepromWriteDelayMs = 10; static inline int secretEepromWriteDelayMs(bool lowPower) { return lowPower ? 200 : 100; } + static const int ds28e22_25_pagesPerBlock = 2; static error_code -writeDataWithCrc(OneWireMaster & master, const uint_least8_t * data, - size_t dataLen, +writeDataWithCrc(OneWireMaster & master, span<const uint_least8_t> data, OneWireMaster::Level level = OneWireMaster::NormalLevel, uint_fast16_t crcStart = 0) { - error_code result = master.writeBlock(data, dataLen); + error_code result = master.writeBlock(data); if (result) { return result; } @@ -66,13 +65,20 @@ if (result) { return result; } - if (calculateCrc16(response, sizeof(response) / sizeof(response[0]), - calculateCrc16(data, dataLen, crcStart)) != 0xB001) { + if (calculateCrc16(response, calculateCrc16(data, crcStart)) != 0xB001) { result = make_error_code(DS28E15_22_25::CrcError); } return result; } +const int DS28E15_22_25::segmentsPerPage; + +DS28E15_22_25::AuthenticationData & +DS28E15_22_25::AuthenticationData::setAnonymousRomId() { + std::fill(romId().begin(), romId().end(), 0xFF); + return *this; +} + error_code DS28E15_22_25::writeCommandWithCrc(Command command, uint_least8_t parameter, OneWireMaster::Level level) const { @@ -80,26 +86,23 @@ if (!result) { const uint_least8_t data[] = {static_cast<uint_least8_t>(command), parameter}; - result = - writeDataWithCrc(*master, data, sizeof(data) / sizeof(data[0]), level); + result = writeDataWithCrc(*master, data); } return result; } -static error_code readDataWithCrc(OneWireMaster & master, uint_least8_t * data, - size_t dataLen) { - error_code result = master.readBlock(data, dataLen); +static error_code readDataWithCrc(OneWireMaster & master, + span<uint_least8_t> data) { + error_code result = master.readBlock(data); if (result) { return result; } uint_least8_t response[2]; - const size_t responseLen = sizeof(response) / sizeof(response[0]); - result = master.readBlock(response, responseLen); + result = master.readBlock(response); if (result) { return result; } - if (calculateCrc16(response, responseLen, calculateCrc16(data, dataLen)) != - 0xB001) { + if (calculateCrc16(response, calculateCrc16(data)) != 0xB001) { result = make_error_code(DS28E15_22_25::CrcError); } return result; @@ -117,7 +120,7 @@ return result; } -static error_code releaseSequence(OneWireMaster & master, const Sleep & sleep, +static error_code releaseSequence(OneWireMaster & master, Sleep & sleep, int delayTimeMs) { error_code result = master.writeBytePower(0xAA); if (result) { @@ -131,21 +134,11 @@ return readCsByte(master); } -DS28E15_22_25::BlockProtection::BlockProtection(bool readProtection, - bool writeProtection, - bool eepromEmulation, - bool authProtection, - int blockNum) { - setReadProtection(readProtection); - setWriteProtection(writeProtection); - setEepromEmulation(eepromEmulation); - setAuthProtection(authProtection); - setBlockNum(blockNum); -} - -void DS28E15_22_25::BlockProtection::setBlockNum(int blockNum) { +DS28E15_22_25::BlockProtection & +DS28E15_22_25::BlockProtection::setBlockNum(int blockNum) { status &= ~blockNumMask; status |= (blockNum & blockNumMask); + return *this; } bool DS28E15_22_25::BlockProtection::noProtection() const { @@ -153,41 +146,78 @@ !authProtection(); } -void DS28E15_22_25::BlockProtection::setReadProtection(bool readProtection) { +DS28E15_22_25::BlockProtection & +DS28E15_22_25::BlockProtection::setReadProtection(bool readProtection) { if (readProtection) { status |= readProtectionMask; } else { status &= ~readProtectionMask; } + return *this; } -void DS28E15_22_25::BlockProtection::setWriteProtection(bool writeProtection) { +DS28E15_22_25::BlockProtection & +DS28E15_22_25::BlockProtection::setWriteProtection(bool writeProtection) { if (writeProtection) { status |= writeProtectionMask; } else { status &= ~writeProtectionMask; } + return *this; } -void DS28E15_22_25::BlockProtection::setEepromEmulation(bool eepromEmulation) { +DS28E15_22_25::BlockProtection & +DS28E15_22_25::BlockProtection::setEepromEmulation(bool eepromEmulation) { if (eepromEmulation) { status |= eepromEmulationMask; } else { status &= ~eepromEmulationMask; } + return *this; } -void DS28E15_22_25::BlockProtection::setAuthProtection(bool authProtection) { +DS28E15_22_25::BlockProtection & +DS28E15_22_25::BlockProtection::setAuthProtection(bool authProtection) { if (authProtection) { status |= authProtectionMask; } else { status &= ~authProtectionMask; } + return *this; +} + +DS28E15_22_25::ProtectionWriteMacData::ProtectionWriteMacData() + : result_(), oldProtection_(), newProtection_() { + setOldProtection(oldProtection_); + setNewProtection(newProtection_); +} + +DS28E15_22_25::ProtectionWriteMacData & +DS28E15_22_25::ProtectionWriteMacData::setOldProtection( + BlockProtection oldProtection) { + result_[oldProtectionIdx] = oldProtection.authProtection() ? 1 : 0; + result_[oldProtectionIdx + 1] = oldProtection.eepromEmulation() ? 1 : 0; + result_[oldProtectionIdx + 2] = oldProtection.writeProtection() ? 1 : 0; + result_[oldProtectionIdx + 3] = oldProtection.readProtection() ? 1 : 0; + oldProtection_ = oldProtection; + return *this; +} + +DS28E15_22_25::ProtectionWriteMacData & +DS28E15_22_25::ProtectionWriteMacData::setNewProtection( + BlockProtection newProtection) { + result_[blockNumIdx] = newProtection.blockNum(); + result_[newProtectionIdx] = newProtection.authProtection() ? 1 : 0; + result_[newProtectionIdx + 1] = newProtection.eepromEmulation() ? 1 : 0; + result_[newProtectionIdx + 2] = newProtection.writeProtection() ? 1 : 0; + result_[newProtectionIdx + 3] = newProtection.readProtection() ? 1 : 0; + newProtection_ = newProtection; + return *this; } error_code -DS28E15_22_25::writeAuthBlockProtection(const BlockProtection & newProtection, - const Hash & mac) { +DS28E15_22_25::writeAuthBlockProtection(BlockProtection newProtection, + Hash::const_span mac) { error_code result = writeCommandWithCrc(AuthWriteBlockProtection, newProtection.statusByte(), OneWireMaster::StrongLevel); @@ -195,13 +225,13 @@ return result; } - (*sleep)(shaComputationDelayMs); + sleep->invoke(shaComputationDelayMs); result = master->setLevel(OneWireMaster::NormalLevel); if (result) { return result; } - result = writeDataWithCrc(*master, mac.data(), mac.size()); + result = writeDataWithCrc(*master, mac); if (result) { return result; } @@ -215,8 +245,7 @@ return result; } -error_code -DS28E15_22_25::writeBlockProtection(const BlockProtection & protection) { +error_code DS28E15_22_25::writeBlockProtection(BlockProtection protection) { error_code result = writeCommandWithCrc(WriteBlockProtection, protection.statusByte()); if (result) { @@ -244,33 +273,8 @@ return result; } -AuthMacData DS28E15_22_25::createAuthMacData(const Page & pageData, int pageNum, - const Scratchpad & challenge, - const RomId & romId, - const ManId & manId) { - AuthMacData authMacData; - AuthMacData::iterator authMacDataIt = authMacData.begin(); - authMacDataIt = copy(pageData.begin(), pageData.end(), authMacDataIt); - authMacDataIt = copy(challenge.begin(), challenge.end(), authMacDataIt); - authMacDataIt = copy(romId.begin(), romId.end(), authMacDataIt); - *authMacDataIt = manId[1]; - *(++authMacDataIt) = manId[0]; - *(++authMacDataIt) = pageNum; - *(++authMacDataIt) = 0x00; - return authMacData; -} - -AuthMacData DS28E15_22_25::createAnonAuthMacData(const Page & pageData, - int pageNum, - const Scratchpad & challenge, - const ManId & manId) { - RomId romId; - romId.fill(0xFF); - return createAuthMacData(pageData, pageNum, challenge, romId, manId); -} - error_code DS28E15_22_25::computeReadPageMac(int page_num, bool anon, - Hash & mac) const { + Hash::span mac) const { error_code result = writeCommandWithCrc(ComputePageMac, (anon ? 0xE0 : 0x00) | page_num, OneWireMaster::StrongLevel); @@ -278,7 +282,7 @@ return result; } - (*sleep)(shaComputationDelayMs * 2); + sleep->invoke(shaComputationDelayMs * 2); result = master->setLevel(OneWireMaster::NormalLevel); if (result) { return result; @@ -289,7 +293,7 @@ return result; } - result = readDataWithCrc(*master, mac.data(), mac.size()); + result = readDataWithCrc(*master, mac); return result; } @@ -307,7 +311,7 @@ return result; } -error_code DS28E15_22_25::doWriteScratchpad(const Scratchpad & data, +error_code DS28E15_22_25::doWriteScratchpad(Scratchpad::const_span data, Variant variant) { const uint_least8_t parameter = (variant == DS28E22 || variant == DS28E25) ? 0x20 : 0x00; @@ -316,11 +320,11 @@ return result; } - result = writeDataWithCrc(*master, data.data(), data.size()); + result = writeDataWithCrc(*master, data); return result; } -error_code DS28E15_22_25::doReadScratchpad(Scratchpad & data, +error_code DS28E15_22_25::doReadScratchpad(Scratchpad::span data, Variant variant) const { const uint_least8_t parameter = (variant == DS28E22 || variant == DS28E25) ? 0x2F : 0x0F; @@ -329,7 +333,7 @@ return result; } - result = readDataWithCrc(*master, data.data(), data.size()); + result = readDataWithCrc(*master, data); return result; } @@ -344,7 +348,7 @@ return result; } -error_code DS28E15_22_25::readPage(int page, Page & rdbuf) const { +error_code DS28E15_22_25::readPage(int page, Page::span rdbuf) const { error_code result = writeCommandWithCrc(ReadMemory, page); if (result) { return result; @@ -354,31 +358,31 @@ return result; } -error_code DS28E15_22_25::continueReadPage(Page & rdbuf) const { - return readDataWithCrc(*master, rdbuf.data(), rdbuf.size()); +error_code DS28E15_22_25::continueReadPage(Page::span rdbuf) const { + return readDataWithCrc(*master, rdbuf); } -error_code DS28E15_22_25::doWriteAuthSegment(const Segment & newData, - const Hash & mac, Variant variant, - bool continuing) { +error_code DS28E15_22_25::doWriteAuthSegment(Segment::const_span newData, + Hash::const_span mac, + Variant variant, bool continuing) { // CRC gets calculated with CS byte when continuing on DS28E22 and DS28E25. const uint_fast16_t crcStart = ((variant == DS28E22 || variant == DS28E25) && continuing) ? calculateCrc16(0xAA) : 0; - error_code result = writeDataWithCrc(*master, newData.data(), newData.size(), - OneWireMaster::StrongLevel, crcStart); + error_code result = + writeDataWithCrc(*master, newData, OneWireMaster::StrongLevel, crcStart); if (result) { return result; } - (*sleep)(shaComputationDelayMs); + sleep->invoke(shaComputationDelayMs); result = master->setLevel(OneWireMaster::NormalLevel); if (result) { return result; } - result = writeDataWithCrc(*master, mac.data(), mac.size()); + result = writeDataWithCrc(*master, mac); if (result) { return result; } @@ -393,8 +397,8 @@ } error_code DS28E15_22_25::doWriteAuthSegment(int pageNum, int segmentNum, - const Segment & newData, - const Hash & mac, + Segment::const_span newData, + Hash::const_span mac, Variant variant) { error_code result = writeCommandWithCrc(AuthWriteMemory, (segmentNum << 5) | pageNum); @@ -406,67 +410,13 @@ return result; } -error_code DS28E15_22_25::doContinueWriteAuthSegment(const Segment & newData, - const Hash & mac, - Variant variant) { +error_code DS28E15_22_25::doContinueWriteAuthSegment( + Segment::const_span newData, Hash::const_span mac, Variant variant) { return doWriteAuthSegment(newData, mac, variant, true); } -WriteMacData DS28E15_22_25::createSegmentWriteMacData( - int pageNum, int segmentNum, const Segment & newData, - const Segment & oldData, const RomId & romId, const ManId & manId) { - WriteMacData MT; - - // insert ROM number - copy(romId.begin(), romId.end(), MT.begin()); - - MT[11] = segmentNum; - MT[10] = pageNum; - MT[9] = manId[0]; - MT[8] = manId[1]; - - // insert old data - copy(oldData.begin(), oldData.end(), MT.begin() + 12); - - // insert new data - copy(newData.begin(), newData.end(), MT.begin() + 16); - - return MT; -} - -WriteMacData DS28E15_22_25::createProtectionWriteMacData( - const BlockProtection & newProtection, - const BlockProtection & oldProtection, const RomId & romId, - const ManId & manId) { - WriteMacData MT; - - // insert ROM number - copy(romId.begin(), romId.end(), MT.begin()); - - // instert block and page - MT[11] = 0; - MT[10] = newProtection.blockNum(); - - MT[9] = manId[0]; - MT[8] = manId[1]; - - // old data - MT[12] = oldProtection.authProtection() ? 0x01 : 0x00; - MT[13] = oldProtection.eepromEmulation() ? 0x01 : 0x00; - MT[14] = oldProtection.writeProtection() ? 0x01 : 0x00; - MT[15] = oldProtection.readProtection() ? 0x01 : 0x00; - // new data - MT[16] = newProtection.authProtection() ? 0x01 : 0x00; - MT[17] = newProtection.eepromEmulation() ? 0x01 : 0x00; - MT[18] = newProtection.writeProtection() ? 0x01 : 0x00; - MT[19] = newProtection.readProtection() ? 0x01 : 0x00; - - // compute the mac - return MT; -} - error_code DS28E15_22_25::readSegment(int page, int segment, - Segment & data) const { + Segment::span data) const { error_code result = writeCommandWithCrc(ReadMemory, (segment << 5) | page); if (result) { return result; @@ -476,12 +426,12 @@ return result; } -error_code DS28E15_22_25::continueReadSegment(Segment & data) const { - return master->readBlock(data.data(), data.size()); +error_code DS28E15_22_25::continueReadSegment(Segment::span data) const { + return master->readBlock(data); } error_code DS28E15_22_25::writeSegment(int page, int block, - const Segment & data) { + Segment::const_span data) { error_code result = writeCommandWithCrc(WriteMemory, (block << 5) | page); if (result) { return result; @@ -491,8 +441,8 @@ return result; } -error_code DS28E15_22_25::continueWriteSegment(const Segment & data) { - error_code result = writeDataWithCrc(*master, data.data(), data.size()); +error_code DS28E15_22_25::continueWriteSegment(Segment::const_span data) { + error_code result = writeDataWithCrc(*master, data); if (result) { return result; } @@ -501,55 +451,37 @@ return result; } -SlaveSecretData -DS28E15_22_25::createSlaveSecretData(const Page & bindingPage, - int bindingPageNum, - const Scratchpad & partialSecret, - const RomId & romId, const ManId & manId) { - SlaveSecretData slaveSecretData; - SlaveSecretData::iterator slaveSecretDataIt = slaveSecretData.begin(); - slaveSecretDataIt = - copy(bindingPage.begin(), bindingPage.end(), slaveSecretDataIt); - slaveSecretDataIt = - copy(partialSecret.begin(), partialSecret.end(), slaveSecretDataIt); - slaveSecretDataIt = copy(romId.begin(), romId.end(), slaveSecretDataIt); - *slaveSecretDataIt = manId[1]; - *(++slaveSecretDataIt) = manId[0]; - *(++slaveSecretDataIt) = bindingPageNum; - *(++slaveSecretDataIt) = 0x00; - return slaveSecretData; -} - -error_code DS28E15_22_25::doReadAllBlockProtection(BlockProtection * protection, - const size_t protectionLen, - Variant variant) const { +error_code +DS28E15_22_25::doReadAllBlockProtection(span<BlockProtection> protection, + Variant variant) const { error_code result = writeCommandWithCrc(ReadStatus, 0); if (!result) { if (variant == DS28E22 || variant == DS28E25) { // Need to read extra data on DS28E22 to get CRC16. uint_least8_t buf[DS28E25::memoryPages]; - result = readDataWithCrc(*master, buf, DS28E25::memoryPages); + result = readDataWithCrc(*master, buf); if (!result) { const int blocks = ((variant == DS28E22) ? DS28E22::memoryPages : DS28E25::memoryPages) / ds28e22_25_pagesPerBlock; - for (size_t i = 0; - i < std::min(protectionLen, static_cast<size_t>(blocks)); i++) { + for (span<BlockProtection>::index_type i = 0; + i < std::min<span<BlockProtection>::index_type>(protection.size(), + blocks); + ++i) { protection[i].setStatusByte( (buf[i * ds28e22_25_pagesPerBlock] & 0xF0) | // Upper nibble ((buf[i * ds28e22_25_pagesPerBlock] & 0x0F) / ds28e22_25_pagesPerBlock)); // Lower nibble } } - } else // DS28E15 - { + } else { // DS28E15 uint_least8_t buf[DS28E15::protectionBlocks]; - result = readDataWithCrc(*master, buf, DS28E15::protectionBlocks); + result = readDataWithCrc(*master, buf); if (!result) { - for (size_t i = 0; - i < std::min(protectionLen, - static_cast<size_t>(DS28E15::protectionBlocks)); - i++) { + for (span<BlockProtection>::index_type i = 0; + i < std::min<span<BlockProtection>::index_type>( + protection.size(), DS28E15::protectionBlocks); + ++i) { protection[i].setStatusByte(buf[i]); } } @@ -592,8 +524,8 @@ error_code DS28E15_22_25::readPersonality(Personality & personality) const { error_code result = writeCommandWithCrc(ReadStatus, 0xE0); if (!result) { - array<uint_least8_t, 4> data; - result = readDataWithCrc(*master, data.data(), data.size()); + uint_least8_t data[4]; + result = readDataWithCrc(*master, data); if (!result) { personality.PB1 = data[0]; personality.PB2 = data[1]; @@ -604,11 +536,14 @@ return result; } -error_code DS28EL15::writeScratchpad(const Scratchpad & data) { +const int DS28EL15::memoryPages; +const int DS28EL15::protectionBlocks; + +error_code DS28EL15::writeScratchpad(Scratchpad::const_span data) { return doWriteScratchpad(data, DS28E15); } -error_code DS28EL15::readScratchpad(Scratchpad & data) const { +error_code DS28EL15::readScratchpad(Scratchpad::span data) const { return doReadScratchpad(data, DS28E15); } @@ -618,20 +553,19 @@ } error_code DS28EL15::writeAuthSegment(int pageNum, int segmentNum, - const Segment & newData, - const Hash & mac) { + Segment::const_span newData, + Hash::const_span mac) { return doWriteAuthSegment(pageNum, segmentNum, newData, mac, DS28E15); } -error_code DS28EL15::continueWriteAuthSegment(const Segment & newData, - const Hash & mac) { +error_code DS28EL15::continueWriteAuthSegment(Segment::const_span newData, + Hash::const_span mac) { return doContinueWriteAuthSegment(newData, mac, DS28E15); } error_code DS28EL15::readAllBlockProtection( - array<BlockProtection, protectionBlocks> & protection) const { - return doReadAllBlockProtection(protection.data(), protection.size(), - DS28E15); + span<BlockProtection, protectionBlocks> protection) const { + return doReadAllBlockProtection(protection, DS28E15); } error_code DS28E15::loadSecret(bool lock) { return doLoadSecret(lock, false); } @@ -640,11 +574,14 @@ return doComputeSecret(pageNum, lock, false); } -error_code DS28EL22::writeScratchpad(const Scratchpad & data) { +const int DS28EL22::memoryPages; +const int DS28EL22::protectionBlocks; + +error_code DS28EL22::writeScratchpad(Scratchpad::const_span data) { return doWriteScratchpad(data, DS28E22); } -error_code DS28EL22::readScratchpad(Scratchpad & data) const { +error_code DS28EL22::readScratchpad(Scratchpad::span data) const { return doReadScratchpad(data, DS28E22); } @@ -654,20 +591,19 @@ } error_code DS28EL22::writeAuthSegment(int pageNum, int segmentNum, - const Segment & newData, - const Hash & mac) { + Segment::const_span newData, + Hash::const_span mac) { return doWriteAuthSegment(pageNum, segmentNum, newData, mac, DS28E22); } -error_code DS28EL22::continueWriteAuthSegment(const Segment & newData, - const Hash & mac) { +error_code DS28EL22::continueWriteAuthSegment(Segment::const_span newData, + Hash::const_span mac) { return doContinueWriteAuthSegment(newData, mac, DS28E22); } error_code DS28EL22::readAllBlockProtection( - array<BlockProtection, protectionBlocks> & protection) const { - return doReadAllBlockProtection(protection.data(), protection.size(), - DS28E22); + span<BlockProtection, protectionBlocks> protection) const { + return doReadAllBlockProtection(protection, DS28E22); } error_code DS28E22::loadSecret(bool lock) { return doLoadSecret(lock, false); } @@ -676,11 +612,14 @@ return doComputeSecret(pageNum, lock, false); } -error_code DS28EL25::writeScratchpad(const Scratchpad & data) { +const int DS28EL25::memoryPages; +const int DS28EL25::protectionBlocks; + +error_code DS28EL25::writeScratchpad(Scratchpad::const_span data) { return doWriteScratchpad(data, DS28E25); } -error_code DS28EL25::readScratchpad(Scratchpad & data) const { +error_code DS28EL25::readScratchpad(Scratchpad::span data) const { return doReadScratchpad(data, DS28E25); } @@ -690,20 +629,19 @@ } error_code DS28EL25::writeAuthSegment(int pageNum, int segmentNum, - const Segment & newData, - const Hash & mac) { + Segment::const_span newData, + Hash::const_span mac) { return doWriteAuthSegment(pageNum, segmentNum, newData, mac, DS28E25); } -error_code DS28EL25::continueWriteAuthSegment(const Segment & newData, - const Hash & mac) { +error_code DS28EL25::continueWriteAuthSegment(Segment::const_span newData, + Hash::const_span mac) { return doContinueWriteAuthSegment(newData, mac, DS28E25); } error_code DS28EL25::readAllBlockProtection( - array<BlockProtection, protectionBlocks> & protection) const { - return doReadAllBlockProtection(protection.data(), protection.size(), - DS28E25); + span<BlockProtection, protectionBlocks> protection) const { + return doReadAllBlockProtection(protection, DS28E25); } error_code DS28E25::loadSecret(bool lock) { return doLoadSecret(lock, false); }
--- a/Devices/DS28E15_22_25.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS28E15_22_25.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -33,16 +33,18 @@ #ifndef MaximInterface_DS28E15_22_25 #define MaximInterface_DS28E15_22_25 +#include <stdint.h> #include <MaximInterface/Links/OneWireMaster.hpp> #include <MaximInterface/Links/SelectRom.hpp> #include <MaximInterface/Links/Sleep.hpp> -#include <MaximInterface/Utilities/array.hpp> +#include <MaximInterface/Utilities/array_span.hpp> #include <MaximInterface/Utilities/Export.h> #include <MaximInterface/Utilities/ManId.hpp> #include <MaximInterface/Utilities/Sha256.hpp> namespace MaximInterface { +/// @brief /// Interface to the DS28E15/22/25 series of authenticators /// including low power variants. class DS28E15_22_25 { @@ -50,146 +52,43 @@ enum ErrorValue { CrcError = 1, OperationFailure }; /// Holds the contents of a device memory segment. - typedef array<uint_least8_t, 4> Segment; + typedef array_span<uint_least8_t, 4> Segment; /// Holds the contents of a device memory page. - typedef array<uint_least8_t, 32> Page; + typedef array_span<uint_least8_t, 32> Page; /// Number of segments per page. - static const int segmentsPerPage = Page::csize / Segment::csize; + static const int segmentsPerPage = Page::size / Segment::size; /// Holds the contents of the device scratchpad. - typedef array<uint_least8_t, 32> Scratchpad; + typedef array_span<uint_least8_t, 32> Scratchpad; - /// Container for the device personality. + /// Container for the device personality. struct Personality { uint_least8_t PB1; uint_least8_t PB2; - ManId manId; - + ManId::array manId; + bool secretLocked() const { return PB2 & 0x01; } }; - /// Represents the status of a memory protection block. - class BlockProtection { - private: - static const unsigned int readProtectionMask = 0x80, - writeProtectionMask = 0x40, - eepromEmulationMask = 0x20, - authProtectionMask = 0x10, - blockNumMask = 0x0F; - uint_least8_t status; - - public: - explicit BlockProtection(uint_least8_t status = 0x00) : status(status) {} - MaximInterface_EXPORT BlockProtection(bool readProtection, - bool writeProtection, - bool eepromEmulation, - bool authProtection, - int blockNum); - - /// Get the byte representation used by the device. - uint_least8_t statusByte() const { return status; } - /// Set the byte representation used by the device. - void setStatusByte(uint_least8_t status) { this->status = status; } - - /// Get the Block Number which is indexed from zero. - int blockNum() const { return (status & blockNumMask); } - /// Set the Block Number which is indexed from zero. - MaximInterface_EXPORT void setBlockNum(int blockNum); + // Represents the status of a memory protection block. + class BlockProtection; - /// Get the Read Protection status. - /// @returns True if Read Protection is enabled. - bool readProtection() const { - return ((status & readProtectionMask) == readProtectionMask); - } - /// Set the Read Protection status. - MaximInterface_EXPORT void setReadProtection(bool readProtection); - - /// Get the Write Protection status. - /// @returns True if Write Protection is enabled. - bool writeProtection() const { - return ((status & writeProtectionMask) == writeProtectionMask); - } - /// Set the Write Protection status. - MaximInterface_EXPORT void setWriteProtection(bool writeProtection); + // Format data to hash for an Authenticated Write to a memory segment. + class SegmentWriteMacData; - /// Get the EEPROM Emulation Mode status. - /// @returns True if EEPROM Emulation Mode is enabled. - bool eepromEmulation() const { - return ((status & eepromEmulationMask) == eepromEmulationMask); - } - /// Set the EEPROM Emulation Mode status. - MaximInterface_EXPORT void setEepromEmulation(bool eepromEmulation); - - /// Get the Authentication Protection status. - /// @returns True if Authentication Protection is enabled. - bool authProtection() const { - return ((status & authProtectionMask) == authProtectionMask); - } - /// Set the Authentication Protection status. - MaximInterface_EXPORT void setAuthProtection(bool authProtection); + // Format data to hash for an Authenticated Write to a memory protection block. + class ProtectionWriteMacData; - /// Check if no protection options are enabled. - /// @returns True if no protection options are enabled. - MaximInterface_EXPORT bool noProtection() const; - }; - - /// Format data to hash for an Authenticated Write to a memory segment. - /// @param pageNum Page number for write operation. - /// @param segmentNum Segment number within page for write operation. - /// @param[in] newData New data to write to the segment. - /// @param[in] oldData Existing data contained in the segment. - /// @param[in] romId 1-Wire ROM ID of the device. - /// @param[in] manId Manufacturer ID of the device. - MaximInterface_EXPORT static Sha256::WriteMacData - createSegmentWriteMacData(int pageNum, int segmentNum, - const Segment & newData, const Segment & oldData, - const RomId & romId, const ManId & manId); - - /// Format data to hash for an Authenticated Write to a memory protection block. - /// @param[in] newProtection New protection status to write. - /// @param[in] oldProtection Existing protection status in device. - /// @param[in] romId 1-Wire ROM ID of the device. - /// @param[in] manId Manufacturer ID of the device. - MaximInterface_EXPORT static Sha256::WriteMacData - createProtectionWriteMacData(const BlockProtection & newProtection, - const BlockProtection & oldProtection, - const RomId & romId, const ManId & manId); + // Format data to hash for device authentication or computing the next secret + // from the existing secret. + class AuthenticationData; - /// Format data to hash to compute the next secret from the existing secret. - /// @param[in] bindingPage Binding data from a device memory page. - /// @param bindingPageNum Number of the page where the binding data is from. - /// @param[in] partialSecret Partial secret data from the device scratchpad. - /// @param[in] romId 1-Wire ROM ID of the device. - /// @param[in] manId Manufacturer ID of the device. - MaximInterface_EXPORT static Sha256::SlaveSecretData - createSlaveSecretData(const Page & bindingPage, int bindingPageNum, - const Scratchpad & partialSecret, const RomId & romId, - const ManId & manId); - - /// Format data to hash for device authentication. - /// @param[in] pageData Data from a device memory page. - /// @param pageNum Number of the page to use data from. - /// @param[in] challenge Random challenge to prevent replay attacks. - /// @param[in] romId 1-Wire ROM ID of the device. - /// @param[in] manId Manufacturer ID of the device. - MaximInterface_EXPORT static Sha256::AuthMacData - createAuthMacData(const Page & pageData, int pageNum, - const Scratchpad & challenge, const RomId & romId, - const ManId & manId); - - /// Format datat to hash for device authentication using anonymous mode. - /// @param[in] pageData Data from a device memory page. - /// @param pageNum Number of the page to use data from. - /// @param[in] challenge Random challenge to prevent replay attacks. - /// @param[in] manId Manufacturer ID of the device. - MaximInterface_EXPORT static Sha256::AuthMacData - createAnonAuthMacData(const Page & pageData, int pageNum, - const Scratchpad & challenge, const ManId & manId); - - void setSleep(const Sleep & sleep) { this->sleep = &sleep; } + void setSleep(Sleep & sleep) { this->sleep = &sleep; } + void setMaster(OneWireMaster & master) { this->master = &master; } + void setSelectRom(const SelectRom & selectRom) { this->selectRom = selectRom; } @@ -197,74 +96,81 @@ // Const member functions should not affect the state of the memory, // block protection, or secret on the device. - /// Read memory segment using the Read Memory command on the device. + /// @brief Read memory segment using the Read Memory command on the device. /// @param pageNum Page number for read operation. /// @param segmentNum Segment number within page for read operation. /// @param[out] data Buffer to read data from the segment into. MaximInterface_EXPORT error_code readSegment(int pageNum, int segmentNum, - Segment & data) const; + Segment::span data) const; - /// Continue an in-progress readSegment operation. + /// @brief Continue an in-progress readSegment operation. /// @note A CRC16 will encountered after reading the last segment of a page. /// @param[out] data Buffer to read data from the segment into. - MaximInterface_EXPORT error_code continueReadSegment(Segment & data) const; + MaximInterface_EXPORT error_code + continueReadSegment(Segment::span data) const; - /// Write memory segment using the Write Memory command. + /// @brief Write memory segment using the Write Memory command. /// @note 1-Wire ROM selection should have already occurred. /// @param pageNum Page number for write operation. /// @param segmentNum Segment number within page for write operation. /// @param[in] data Data to write to the memory segment. MaximInterface_EXPORT error_code writeSegment(int pageNum, int segmentNum, - const Segment & data); + Segment::const_span data); - /// Continue an in-progress Write Memory command. + /// @brief Continue an in-progress Write Memory command. /// @param[in] data Data to write to the memory segment. - MaximInterface_EXPORT error_code continueWriteSegment(const Segment & data); + MaximInterface_EXPORT error_code + continueWriteSegment(Segment::const_span data); - /// Read memory page using the Read Memory command on the device. + /// @brief Read memory page using the Read Memory command on the device. /// @param pageNum Page number for write operation. /// @param[out] rdbuf Buffer to read data from the page into. - MaximInterface_EXPORT error_code readPage(int pageNum, Page & rdbuf) const; + MaximInterface_EXPORT error_code readPage(int pageNum, + Page::span rdbuf) const; - /// Continue an in-progress readPageOperation. + /// @brief Continue an in-progress readPageOperation. /// @param[out] rdbuf Buffer to read data from the page into. - MaximInterface_EXPORT error_code continueReadPage(Page & rdbuf) const; + MaximInterface_EXPORT error_code continueReadPage(Page::span rdbuf) const; + /// @brief /// Perform a Compute Page MAC command on the device. /// Read back the MAC and verify the CRC16. /// @param pageNum Page number to use for the computation. /// @param anon True to compute in anonymous mode where ROM ID is not used. /// @param[out] mac The device computed MAC. - MaximInterface_EXPORT error_code computeReadPageMac(int pageNum, bool anon, - Sha256::Hash & mac) const; + MaximInterface_EXPORT error_code + computeReadPageMac(int pageNum, bool anon, Sha256::Hash::span mac) const; + /// @brief /// Update the status of a memory protection block using the /// Write Page Protection command. - /// @param[in] Desired protection status for the block. - /// It is not possible to disable existing protections. - /// @param continuing True to continue a previous Write Page Protection command. - /// False to begin a new command. + /// @param protection + /// Desired protection status for the block. + /// It is not possible to disable existing protections. MaximInterface_EXPORT error_code - writeBlockProtection(const BlockProtection & protection); + writeBlockProtection(BlockProtection protection); + /// @brief /// Update the status of a memory protection block using the /// Authenticated Write Page Protection command. - /// @param[in] newProtection New protection status to write. + /// @param newProtection New protection status to write. /// @param[in] mac Write MAC computed for this operation. MaximInterface_EXPORT error_code writeAuthBlockProtection( - const BlockProtection & newProtection, const Sha256::Hash & mac); + BlockProtection newProtection, Sha256::Hash::const_span mac); - /// Perform Load and Lock Secret command on the device. + /// @brief Perform Load and Lock Secret command on the device. /// @note The secret should already be stored in the scratchpad on the device. - /// @param lock Prevent further changes to the secret on the device after loading. + /// @param lock + /// Prevent further changes to the secret on the device after loading. MaximInterface_EXPORT error_code loadSecret(bool lock); - /// Perform a Compute and Lock Secret command on the device. + /// @brief Perform a Compute and Lock Secret command on the device. /// @param pageNum Page number to use as the binding data. - /// @param lock Prevent further changes to the secret on the device after computing. + /// @param lock + /// Prevent further changes to the secret on the device after computing. MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock); - /// Read the personality bytes using the Read Status command. + /// @brief Read the personality bytes using the Read Status command. /// @param[out] personality Receives personality read from device. MaximInterface_EXPORT error_code readPersonality(Personality & personality) const; @@ -274,27 +180,28 @@ protected: enum Variant { DS28E15, DS28E22, DS28E25 }; - DS28E15_22_25(const Sleep & sleep, OneWireMaster & master, + DS28E15_22_25(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom) : selectRom(selectRom), master(&master), sleep(&sleep) {} + + ~DS28E15_22_25() {} - error_code doWriteScratchpad(const Scratchpad & data, Variant variant); + error_code doWriteScratchpad(Scratchpad::const_span data, Variant variant); - error_code doReadScratchpad(Scratchpad & data, Variant variant) const; + error_code doReadScratchpad(Scratchpad::span data, Variant variant) const; error_code doReadBlockProtection(int blockNum, BlockProtection & protection, Variant variant) const; error_code doWriteAuthSegment(int pageNum, int segmentNum, - const Segment & newData, - const Sha256::Hash & mac, Variant variant); + Segment::const_span newData, + Sha256::Hash::const_span mac, Variant variant); - error_code doContinueWriteAuthSegment(const Segment & newData, - const Sha256::Hash & mac, + error_code doContinueWriteAuthSegment(Segment::const_span newData, + Sha256::Hash::const_span mac, Variant variant); - error_code doReadAllBlockProtection(BlockProtection * protection, - size_t protectionLen, + error_code doReadAllBlockProtection(span<BlockProtection> protection, Variant variant) const; error_code doLoadSecret(bool lock, bool lowPower); @@ -315,8 +222,8 @@ AuthWriteBlockProtection = 0xCC, }; - error_code doWriteAuthSegment(const Segment & newData, - const Sha256::Hash & mac, Variant variant, + error_code doWriteAuthSegment(Segment::const_span newData, + Sha256::Hash::const_span mac, Variant variant, bool continuing); error_code writeCommandWithCrc( @@ -325,23 +232,13 @@ SelectRom selectRom; OneWireMaster * master; - const Sleep * sleep; + Sleep * sleep; }; inline error_code make_error_code(DS28E15_22_25::ErrorValue e) { return error_code(e, DS28E15_22_25::errorCategory()); } -inline bool operator==(DS28E15_22_25::BlockProtection lhs, - DS28E15_22_25::BlockProtection rhs) { - return lhs.statusByte() == rhs.statusByte(); -} - -inline bool operator!=(DS28E15_22_25::BlockProtection lhs, - DS28E15_22_25::BlockProtection rhs) { - return !operator==(lhs, rhs); -} - /// Interface to the DS28EL15 (low power) authenticator. class DS28EL15 : public DS28E15_22_25 { public: @@ -349,18 +246,150 @@ static const int memoryPages = 2; static const int protectionBlocks = 4; - DS28EL15(const Sleep & sleep, OneWireMaster & master, - const SelectRom & selectRom) + DS28EL15(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom) + : DS28E15_22_25(sleep, master, selectRom) {} + + /// @brief Perform Write Scratchpad operation on the device. + /// @param[in] data Data to write to the scratchpad. + MaximInterface_EXPORT error_code writeScratchpad(Scratchpad::const_span data); + + /// @brief Perform a Read Scratchpad operation on the device. + /// @param[out] data Buffer to read data from the scratchpad into. + MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span data) const; + + /// @brief + /// Read the status of a memory protection block using the Read Status command. + /// @param blockNum Block number to to read status of. + /// @param[out] protection Receives protection status read from device. + MaximInterface_EXPORT error_code + readBlockProtection(int blockNum, BlockProtection & protection) const; + + /// @brief Write memory segment using the Authenticated Write Memory command. + /// @param pageNum Page number for write operation. + /// @param segmentNum Segment number within page for write operation. + /// @param[in] newData New data to write to the segment. + /// @param[in] mac Write MAC computed for this operation. + MaximInterface_EXPORT error_code + writeAuthSegment(int pageNum, int segmentNum, Segment::const_span newData, + Sha256::Hash::const_span mac); + + /// @brief Continue an in-progress Authenticated Write Memory command. + /// @param[in] newData New data to write to the segment. + /// @param[in] mac Write MAC computed for this operation. + MaximInterface_EXPORT error_code continueWriteAuthSegment( + Segment::const_span newData, Sha256::Hash::const_span mac); + + /// @brief + /// Read the status of all memory protection blocks using the Read Status command. + /// @param[out] protection Receives protection statuses read from device. + MaximInterface_EXPORT error_code readAllBlockProtection( + span<BlockProtection, protectionBlocks> protection) const; +}; + +/// Interface to the DS28E15 authenticator. +class DS28E15 : public DS28EL15 { +public: + DS28E15(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom) + : DS28EL15(sleep, master, selectRom) {} + + /// @brief Perform Load and Lock Secret command on the device. + /// @note The secret should already be stored in the scratchpad on the device. + /// @param lock + /// Prevent further changes to the secret on the device after loading. + MaximInterface_EXPORT error_code loadSecret(bool lock); + + /// @brief Perform a Compute and Lock Secret command on the device. + /// @param pageNum Page number to use as the binding data. + /// @param lock + /// Prevent further changes to the secret on the device after computing. + MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock); +}; + +/// Interface to the DS28EL22 (low power) authenticator. +class DS28EL22 : public DS28E15_22_25 { +public: + // DS28E15_22_25 traits + static const int memoryPages = 8; + static const int protectionBlocks = 4; + + DS28EL22(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom) : DS28E15_22_25(sleep, master, selectRom) {} - /// Perform Write Scratchpad operation on the device. + /// @brief Perform Write Scratchpad operation on the device. /// @param[in] data Data to write to the scratchpad. - MaximInterface_EXPORT error_code writeScratchpad(const Scratchpad & data); + MaximInterface_EXPORT error_code writeScratchpad(Scratchpad::const_span data); + + /// @brief Perform a Read Scratchpad operation on the device. + /// @param[out] data Buffer to read data from the scratchpad into. + MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span data) const; + + /// @brief + /// Read the status of a memory protection block using the Read Status command. + /// @param blockNum Block number to to read status of. + /// @param[out] protection Receives protection status read from device. + MaximInterface_EXPORT error_code + readBlockProtection(int blockNum, BlockProtection & protection) const; + + /// @brief Write memory segment using the Authenticated Write Memory command. + /// @param pageNum Page number for write operation. + /// @param segmentNum Segment number within page for write operation. + /// @param[in] newData New data to write to the segment. + /// @param[in] mac Write MAC computed for this operation. + MaximInterface_EXPORT error_code + writeAuthSegment(int pageNum, int segmentNum, Segment::const_span newData, + Sha256::Hash::const_span mac); + + /// @brief Continue an in-progress Authenticated Write Memory command. + /// @param[in] newData New data to write to the segment. + /// @param[in] mac Write MAC computed for this operation. + MaximInterface_EXPORT error_code continueWriteAuthSegment( + Segment::const_span newData, Sha256::Hash::const_span mac); + + /// @brief + /// Read the status of all memory protection blocks using the Read Status command. + /// @param[out] protection Receives protection statuses read from device. + MaximInterface_EXPORT error_code readAllBlockProtection( + span<BlockProtection, protectionBlocks> protection) const; +}; - /// Perform a Read Scratchpad operation on the device. +/// Interface to the DS28E22 authenticator. +class DS28E22 : public DS28EL22 { +public: + DS28E22(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom) + : DS28EL22(sleep, master, selectRom) {} + + /// @brief Perform Load and Lock Secret command on the device. + /// @note The secret should already be stored in the scratchpad on the device. + /// @param lock + /// Prevent further changes to the secret on the device after loading. + MaximInterface_EXPORT error_code loadSecret(bool lock); + + /// @brief Perform a Compute and Lock Secret command on the device. + /// @param pageNum Page number to use as the binding data. + /// @param lock + /// Prevent further changes to the secret on the device after computing. + MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock); +}; + +/// Interface to the DS28EL25 (low power) authenticator. +class DS28EL25 : public DS28E15_22_25 { +public: + // DS28E15_22_25 traits + static const int memoryPages = 16; + static const int protectionBlocks = 8; + + DS28EL25(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom) + : DS28E15_22_25(sleep, master, selectRom) {} + + /// @brief Perform Write Scratchpad operation on the device. + /// @param[in] data Data to write to the scratchpad. + MaximInterface_EXPORT error_code writeScratchpad(Scratchpad::const_span data); + + /// @brief Perform a Read Scratchpad operation on the device. /// @param[out] data Buffer to read data from the scratchpad into. - MaximInterface_EXPORT error_code readScratchpad(Scratchpad & data) const; + MaximInterface_EXPORT error_code readScratchpad(Scratchpad::span data) const; + /// @brief /// Read the status of a memory protection block using the Read Status command. /// @param blockNum Block number to to read status of. /// @param[out] protection Receives protection status read from device. @@ -372,168 +401,485 @@ /// @param segmentNum Segment number within page for write operation. /// @param[in] newData New data to write to the segment. /// @param[in] mac Write MAC computed for this operation. - MaximInterface_EXPORT error_code writeAuthSegment(int pageNum, int segmentNum, - const Segment & newData, - const Sha256::Hash & mac); + MaximInterface_EXPORT error_code + writeAuthSegment(int pageNum, int segmentNum, Segment::const_span newData, + Sha256::Hash::const_span mac); - /// Continue an in-progress Authenticated Write Memory command. + /// @brief Continue an in-progress Authenticated Write Memory command. /// @param[in] newData New data to write to the segment. /// @param[in] mac Write MAC computed for this operation. - MaximInterface_EXPORT error_code - continueWriteAuthSegment(const Segment & newData, const Sha256::Hash & mac); + MaximInterface_EXPORT error_code continueWriteAuthSegment( + Segment::const_span newData, Sha256::Hash::const_span mac); + /// @brief /// Read the status of all memory protection blocks using the Read Status command. /// @param[out] protection Receives protection statuses read from device. MaximInterface_EXPORT error_code readAllBlockProtection( - array<BlockProtection, protectionBlocks> & protection) const; -}; - -/// Interface to the DS28E15 authenticator. -class DS28E15 : public DS28EL15 { -public: - DS28E15(const Sleep & sleep, OneWireMaster & master, - const SelectRom & selectRom) - : DS28EL15(sleep, master, selectRom) {} - - /// Perform Load and Lock Secret command on the device. - /// @note The secret should already be stored in the scratchpad on the device. - /// @param lock Prevent further changes to the secret on the device after loading. - MaximInterface_EXPORT error_code loadSecret(bool lock); - - /// Perform a Compute and Lock Secret command on the device. - /// @param pageNum Page number to use as the binding data. - /// @param lock Prevent further changes to the secret on the device after computing. - MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock); -}; - -/// Interface to the DS28EL22 (low power) authenticator. -class DS28EL22 : public DS28E15_22_25 { -public: - // DS28E15_22_25 traits - static const int memoryPages = 8; - static const int protectionBlocks = 4; - - DS28EL22(const Sleep & sleep, OneWireMaster & master, - const SelectRom & selectRom) - : DS28E15_22_25(sleep, master, selectRom) {} - - /// Perform Write Scratchpad operation on the device. - /// @param[in] data Data to write to the scratchpad. - MaximInterface_EXPORT error_code writeScratchpad(const Scratchpad & data); - - /// Perform a Read Scratchpad operation on the device. - /// @param[out] data Buffer to read data from the scratchpad into. - MaximInterface_EXPORT error_code readScratchpad(Scratchpad & data) const; - - /// Read the status of a memory protection block using the Read Status command. - /// @param blockNum Block number to to read status of. - /// @param[out] protection Receives protection status read from device. - MaximInterface_EXPORT error_code - readBlockProtection(int blockNum, BlockProtection & protection) const; - - /// Write memory segment using the Authenticated Write Memory command. - /// @param pageNum Page number for write operation. - /// @param segmentNum Segment number within page for write operation. - /// @param[in] newData New data to write to the segment. - /// @param[in] mac Write MAC computed for this operation. - MaximInterface_EXPORT error_code writeAuthSegment(int pageNum, int segmentNum, - const Segment & newData, - const Sha256::Hash & mac); - - /// Continue an in-progress Authenticated Write Memory command. - /// @param[in] newData New data to write to the segment. - /// @param[in] mac Write MAC computed for this operation. - MaximInterface_EXPORT error_code - continueWriteAuthSegment(const Segment & newData, const Sha256::Hash & mac); - - /// Read the status of all memory protection blocks using the Read Status command. - /// @param[out] protection Receives protection statuses read from device. - MaximInterface_EXPORT error_code readAllBlockProtection( - array<BlockProtection, protectionBlocks> & protection) const; -}; - -/// Interface to the DS28E22 authenticator. -class DS28E22 : public DS28EL22 { -public: - DS28E22(const Sleep & sleep, OneWireMaster & master, - const SelectRom & selectRom) - : DS28EL22(sleep, master, selectRom) {} - - /// Perform Load and Lock Secret command on the device. - /// @note The secret should already be stored in the scratchpad on the device. - /// @param lock Prevent further changes to the secret on the device after loading. - MaximInterface_EXPORT error_code loadSecret(bool lock); - - /// Perform a Compute and Lock Secret command on the device. - /// @param pageNum Page number to use as the binding data. - /// @param lock Prevent further changes to the secret on the device after computing. - MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock); -}; - -/// Interface to the DS28EL25 (low power) authenticator. -class DS28EL25 : public DS28E15_22_25 { -public: - // DS28E15_22_25 traits - static const int memoryPages = 16; - static const int protectionBlocks = 8; - - DS28EL25(const Sleep & sleep, OneWireMaster & master, - const SelectRom & selectRom) - : DS28E15_22_25(sleep, master, selectRom) {} - - /// Perform Write Scratchpad operation on the device. - /// @param[in] data Data to write to the scratchpad. - MaximInterface_EXPORT error_code writeScratchpad(const Scratchpad & data); - - /// Perform a Read Scratchpad operation on the device. - /// @param[out] data Buffer to read data from the scratchpad into. - MaximInterface_EXPORT error_code readScratchpad(Scratchpad & data) const; - - /// Read the status of a memory protection block using the Read Status command. - /// @param blockNum Block number to to read status of. - /// @param[out] protection Receives protection status read from device. - MaximInterface_EXPORT error_code - readBlockProtection(int blockNum, BlockProtection & protection) const; - - /// Write memory segment using the Authenticated Write Memory command. - /// @param pageNum Page number for write operation. - /// @param segmentNum Segment number within page for write operation. - /// @param[in] newData New data to write to the segment. - /// @param[in] mac Write MAC computed for this operation. - MaximInterface_EXPORT error_code writeAuthSegment(int pageNum, int segmentNum, - const Segment & newData, - const Sha256::Hash & mac); - - /// Continue an in-progress Authenticated Write Memory command. - /// @param[in] newData New data to write to the segment. - /// @param[in] mac Write MAC computed for this operation. - MaximInterface_EXPORT error_code - continueWriteAuthSegment(const Segment & newData, const Sha256::Hash & mac); - - /// Read the status of all memory protection blocks using the Read Status command. - /// @param[out] protection Receives protection statuses read from device. - MaximInterface_EXPORT error_code readAllBlockProtection( - array<BlockProtection, protectionBlocks> & protection) const; + span<BlockProtection, protectionBlocks> protection) const; }; /// Interface to the DS28E25 authenticator. class DS28E25 : public DS28EL25 { public: - DS28E25(const Sleep & sleep, OneWireMaster & master, - const SelectRom & selectRom) + DS28E25(Sleep & sleep, OneWireMaster & master, const SelectRom & selectRom) : DS28EL25(sleep, master, selectRom) {} - /// Perform Load and Lock Secret command on the device. + /// @brief Perform Load and Lock Secret command on the device. /// @note The secret should already be stored in the scratchpad on the device. /// @param lock Prevent further changes to the secret on the device after loading. MaximInterface_EXPORT error_code loadSecret(bool lock); - /// Perform a Compute and Lock Secret command on the device. + /// @brief Perform a Compute and Lock Secret command on the device. /// @param pageNum Page number to use as the binding data. - /// @param lock Prevent further changes to the secret on the device after computing. + /// @param lock + /// Prevent further changes to the secret on the device after computing. MaximInterface_EXPORT error_code computeSecret(int pageNum, bool lock); }; +/// Represents the status of a memory protection block. +class DS28E15_22_25::BlockProtection { +public: + explicit BlockProtection(uint_least8_t status = 0x00) : status(status) {} + + /// Get the byte representation used by the device. + uint_least8_t statusByte() const { return status; } + + /// Set the byte representation used by the device. + BlockProtection & setStatusByte(uint_least8_t status) { + this->status = status; + return *this; + } + + /// Get the Block Number which is indexed from zero. + int blockNum() const { return (status & blockNumMask); } + + /// Set the Block Number which is indexed from zero. + MaximInterface_EXPORT BlockProtection & setBlockNum(int blockNum); + + /// @brief Get the Read Protection status. + /// @returns True if Read Protection is enabled. + bool readProtection() const { + return ((status & readProtectionMask) == readProtectionMask); + } + + /// Set the Read Protection status. + MaximInterface_EXPORT BlockProtection & + setReadProtection(bool readProtection); + + /// @brief Get the Write Protection status. + /// @returns True if Write Protection is enabled. + bool writeProtection() const { + return ((status & writeProtectionMask) == writeProtectionMask); + } + + /// Set the Write Protection status. + MaximInterface_EXPORT BlockProtection & + setWriteProtection(bool writeProtection); + + /// @brief Get the EEPROM Emulation Mode status. + /// @returns True if EEPROM Emulation Mode is enabled. + bool eepromEmulation() const { + return ((status & eepromEmulationMask) == eepromEmulationMask); + } + + /// Set the EEPROM Emulation Mode status. + MaximInterface_EXPORT BlockProtection & + setEepromEmulation(bool eepromEmulation); + + /// @brief Get the Authentication Protection status. + /// @returns True if Authentication Protection is enabled. + bool authProtection() const { + return ((status & authProtectionMask) == authProtectionMask); + } + + /// Set the Authentication Protection status. + MaximInterface_EXPORT BlockProtection & + setAuthProtection(bool authProtection); + + /// @brief Check if no protection options are enabled. + /// @returns True if no protection options are enabled. + MaximInterface_EXPORT bool noProtection() const; + +private: + static const unsigned int readProtectionMask = 0x80, + writeProtectionMask = 0x40, + eepromEmulationMask = 0x20, + authProtectionMask = 0x10, + blockNumMask = 0x0F; + uint_least8_t status; +}; + +inline bool operator==(DS28E15_22_25::BlockProtection lhs, + DS28E15_22_25::BlockProtection rhs) { + return lhs.statusByte() == rhs.statusByte(); +} + +inline bool operator!=(DS28E15_22_25::BlockProtection lhs, + DS28E15_22_25::BlockProtection rhs) { + return !operator==(lhs, rhs); +} + +/// Format data to hash for an Authenticated Write to a memory segment. +class DS28E15_22_25::SegmentWriteMacData { +public: + SegmentWriteMacData() : result_() {} + + /// Formatted data result. + Sha256::WriteMacData::const_span result() const { return result_; } + + /// @name ROM ID + /// @brief 1-Wire ROM ID of the device. + /// @{ + + /// Get mutable ROM ID. + RomId::span romId() { + return make_span(result_).subspan<romIdIdx, RomId::size>(); + } + + /// Get immutable ROM ID. + RomId::const_span romId() const { + return const_cast<SegmentWriteMacData &>(*this).romId(); + } + + /// Set ROM ID. + SegmentWriteMacData & setRomId(RomId::const_span romId) { + copy(romId, this->romId()); + return *this; + } + + /// @} + + /// @name MAN ID + /// @brief Manufacturer ID of the device. + /// @{ + + /// Get mutable MAN ID. + ManId::span manId() { + return make_span(result_).subspan<manIdIdx, ManId::size>(); + } + + /// Get immutable MAN ID. + ManId::const_span manId() const { + return const_cast<SegmentWriteMacData &>(*this).manId(); + } + + /// Set MAN ID. + SegmentWriteMacData & setManId(ManId::const_span manId) { + copy(manId, this->manId()); + return *this; + } + + /// @} + + /// @name Page number + /// @brief Page number for write operation. + /// @{ + + /// Get page number. + int pageNum() const { return result_[pageNumIdx]; } + + /// Set page number. + SegmentWriteMacData & setPageNum(int pageNum) { + result_[pageNumIdx] = pageNum; + return *this; + } + + /// @} + + /// @name Segment number + /// @brief Segment number within page for write operation. + /// @{ + + /// Get segment number. + int segmentNum() const { return result_[segmentNumIdx]; } + + /// Set segment number. + SegmentWriteMacData & setSegmentNum(int segmentNum) { + result_[segmentNumIdx] = segmentNum; + return *this; + } + + /// @} + + /// @name Old data + /// @brief Existing data contained in the segment. + /// @{ + + /// Get mutable old data. + Segment::span oldData() { + return make_span(result_).subspan<oldDataIdx, Segment::size>(); + } + + /// Get immutable old data. + Segment::const_span oldData() const { + return const_cast<SegmentWriteMacData &>(*this).oldData(); + } + + /// Set old data. + SegmentWriteMacData & setOldData(Segment::const_span oldData) { + copy(oldData, this->oldData()); + return *this; + } + + /// @} + + /// @name New data + /// @brief New data to write to the segment. + /// @{ + + /// Get mutable new data. + Segment::span newData() { + return make_span(result_).subspan<newDataIdx, Segment::size>(); + } + + /// Get immutable new data. + Segment::const_span newData() const { + return const_cast<SegmentWriteMacData &>(*this).newData(); + } + + /// Set new data. + SegmentWriteMacData & setNewData(Segment::const_span newData) { + copy(newData, this->newData()); + return *this; + } + + /// @} + +private: + typedef Sha256::WriteMacData::span::index_type index; + + static const index romIdIdx = 0; + static const index manIdIdx = romIdIdx + RomId::size; + static const index pageNumIdx = manIdIdx + ManId::size; + static const index segmentNumIdx = pageNumIdx + 1; + static const index oldDataIdx = segmentNumIdx + 1; + static const index newDataIdx = oldDataIdx + Segment::size; + + Sha256::WriteMacData::array result_; +}; + +/// Format data to hash for an Authenticated Write to a memory protection block. +class DS28E15_22_25::ProtectionWriteMacData { +public: + MaximInterface_EXPORT ProtectionWriteMacData(); + + /// Formatted data result. + Sha256::WriteMacData::const_span result() const { return result_; } + + /// @name ROM ID + /// @brief 1-Wire ROM ID of the device. + /// @{ + + /// Get mutable ROM ID. + RomId::span romId() { + return make_span(result_).subspan<romIdIdx, RomId::size>(); + } + + /// Get immutable ROM ID. + RomId::const_span romId() const { + return const_cast<ProtectionWriteMacData &>(*this).romId(); + } + + /// Set ROM ID. + ProtectionWriteMacData & setRomId(RomId::const_span romId) { + copy(romId, this->romId()); + return *this; + } + + /// @} + + /// @name MAN ID + /// @brief Manufacturer ID of the device. + /// @{ + + /// Get mutable MAN ID. + ManId::span manId() { + return make_span(result_).subspan<manIdIdx, ManId::size>(); + } + + /// Get immutable MAN ID. + ManId::const_span manId() const { + return const_cast<ProtectionWriteMacData &>(*this).manId(); + } + + /// Set MAN ID. + ProtectionWriteMacData & setManId(ManId::const_span manId) { + copy(manId, this->manId()); + return *this; + } + + /// @} + + /// @name Old protection + /// @brief Existing protection status in device. + /// @{ + + /// Get old protection. + BlockProtection oldProtection() const { return oldProtection_; } + + /// Set old protection. + MaximInterface_EXPORT ProtectionWriteMacData & + setOldProtection(BlockProtection oldProtection); + + /// @} + + /// @name New protection + /// @brief New protection status to write. + /// @{ + + /// Get new protection. + BlockProtection newProtection() const { return newProtection_; } + + /// Set new protection. + MaximInterface_EXPORT ProtectionWriteMacData & + setNewProtection(BlockProtection newProtection); + + /// @} + +private: + typedef Sha256::WriteMacData::span::index_type index; + + static const index romIdIdx = 0; + static const index manIdIdx = romIdIdx + RomId::size; + static const index blockNumIdx = manIdIdx + ManId::size; + static const index oldProtectionIdx = blockNumIdx + 2; + static const index newProtectionIdx = oldProtectionIdx + 4; + + Sha256::WriteMacData::array result_; + BlockProtection oldProtection_; + BlockProtection newProtection_; +}; + +/// @brief +/// Format data to hash for device authentication or computing the next secret +/// from the existing secret. +class DS28E15_22_25::AuthenticationData { +public: + AuthenticationData() : result_() {} + + /// Formatted data result. + Sha256::AuthenticationData::const_span result() const { return result_; } + + /// @name Page + /// @brief Data from a device memory page. + /// @{ + + /// Get mutable page. + Page::span page() { + return make_span(result_).subspan<pageIdx, Page::size>(); + } + + /// Get immutable page. + Page::const_span page() const { + return const_cast<AuthenticationData &>(*this).page(); + } + + /// Set page. + AuthenticationData & setPage(Page::const_span page) { + copy(page, this->page()); + return *this; + } + + /// @} + + /// @name Scratchpad + /// @brief + /// Data from device scratchpad used as a random challenge in device + /// authentication and a partial secret in secret computation. + /// @{ + + /// Get mutable scratchpad. + Scratchpad::span scratchpad() { + return make_span(result_).subspan<scratchpadIdx, Scratchpad::size>(); + } + + /// Get immutable scratchpad. + Scratchpad::const_span scratchpad() const { + return const_cast<AuthenticationData &>(*this).scratchpad(); + } + + /// Set scratchpad. + AuthenticationData & setScratchpad(Scratchpad::const_span scratchpad) { + copy(scratchpad, this->scratchpad()); + return *this; + } + + /// @} + + /// @name ROM ID + /// @brief 1-Wire ROM ID of the device. + /// @{ + + /// Get mutable ROM ID. + RomId::span romId() { + return make_span(result_).subspan<romIdIdx, RomId::size>(); + } + + /// Get immutable ROM ID. + RomId::const_span romId() const { + return const_cast<AuthenticationData &>(*this).romId(); + } + + /// Set ROM ID. + AuthenticationData & setRomId(RomId::const_span romId) { + copy(romId, this->romId()); + return *this; + } + + /// Set ROM ID for use in anonymous mode. + MaximInterface_EXPORT AuthenticationData & setAnonymousRomId(); + + /// @} + + /// @name MAN ID + /// @brief Manufacturer ID of the device. + /// @{ + + /// Get mutable MAN ID. + ManId::span manId() { + return make_span(result_).subspan<manIdIdx, ManId::size>(); + } + + /// Get immutable MAN ID. + ManId::const_span manId() const { + return const_cast<AuthenticationData &>(*this).manId(); + } + + /// Set MAN ID. + AuthenticationData & setManId(ManId::const_span manId) { + copy(manId, this->manId()); + return *this; + } + + /// @} + + /// @name Page number + /// @brief Number of the page to use data from. + /// @{ + + /// Get page number. + int pageNum() const { return result_[pageNumIdx]; } + + /// Set page number. + AuthenticationData & setPageNum(int pageNum) { + result_[pageNumIdx] = pageNum; + return *this; + } + + /// @} + +private: + typedef Sha256::AuthenticationData::span::index_type index; + + static const index pageIdx = 0; + static const index scratchpadIdx = pageIdx + Page::size; + static const index romIdIdx = scratchpadIdx + Scratchpad::size; + static const index manIdIdx = romIdIdx + RomId::size; + static const index pageNumIdx = manIdIdx + ManId::size; + + Sha256::AuthenticationData::array result_; +}; + } // namespace MaximInterface #endif
--- a/Devices/DS28E17.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS28E17.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -39,46 +39,43 @@ namespace MaximInterface { error_code DS28E17::writeDataWithStop(uint_least8_t I2C_addr, - const uint_least8_t * data, - size_t data_len, + span<const uint_least8_t> data, uint_least8_t * wr_status) { - return sendPacket(WriteDataWithStopCmd, &I2C_addr, data, data_len, NULL, 0, - wr_status); + return sendPacket(WriteDataWithStopCmd, &I2C_addr, data, + span<uint_least8_t>(), wr_status); } error_code DS28E17::writeDataNoStop(uint_least8_t I2C_addr, - const uint_least8_t * data, size_t data_len, + span<const uint_least8_t> data, uint_least8_t * wr_status) { - return sendPacket(WriteDataNoStopCmd, &I2C_addr, data, data_len, NULL, 0, + return sendPacket(WriteDataNoStopCmd, &I2C_addr, data, span<uint_least8_t>(), wr_status); } -error_code DS28E17::writeDataOnly(const uint_least8_t * data, size_t data_len, +error_code DS28E17::writeDataOnly(span<const uint_least8_t> data, uint_least8_t * wr_status) { - return sendPacket(WriteDataOnlyCmd, NULL, data, data_len, NULL, 0, wr_status); + return sendPacket(WriteDataOnlyCmd, NULL, data, span<uint_least8_t>(), + wr_status); } -error_code DS28E17::writeDataOnlyWithStop(const uint_least8_t * data, - size_t data_len, +error_code DS28E17::writeDataOnlyWithStop(span<const uint_least8_t> data, uint_least8_t * wr_status) { - return sendPacket(WriteDataOnlyWithStopCmd, NULL, data, data_len, NULL, 0, + return sendPacket(WriteDataOnlyWithStopCmd, NULL, data, span<uint_least8_t>(), wr_status); } error_code DS28E17::writeReadDataWithStop(uint_least8_t I2C_addr, - const uint_least8_t * write_data, - size_t write_data_len, - uint_least8_t * read_data, - size_t read_data_len, + span<const uint_least8_t> write_data, + span<uint_least8_t> read_data, uint_least8_t * wr_status) { - return sendPacket(WriteReadDataWithStopCmd, &I2C_addr, write_data, - write_data_len, read_data, read_data_len, wr_status); + return sendPacket(WriteReadDataWithStopCmd, &I2C_addr, write_data, read_data, + wr_status); } error_code DS28E17::readDataWithStop(uint_least8_t I2C_addr, - uint_least8_t * data, size_t data_len) { - return sendPacket(ReadDataWithStopCmd, &I2C_addr, NULL, 0, data, data_len, - NULL); + span<uint_least8_t> data) { + return sendPacket(ReadDataWithStopCmd, &I2C_addr, span<const uint_least8_t>(), + data, NULL); } error_code DS28E17::writeConfigReg(I2CSpeed speed) { @@ -87,8 +84,7 @@ // Send CMD and Data const uint_least8_t send_block[] = {WriteConfigurationCmd, static_cast<uint_least8_t>(speed)}; - result = master->writeBlock(send_block, - sizeof(send_block) / sizeof(send_block[0])); + result = master->writeBlock(send_block); } return result; } @@ -141,18 +137,14 @@ } error_code DS28E17::sendPacket(Command command, const uint_least8_t * I2C_addr, - const uint_least8_t * write_data, - size_t write_data_len, uint_least8_t * read_data, - size_t read_data_len, + span<const uint_least8_t> write_data, + span<uint_least8_t> read_data, uint_least8_t * wr_status) { const int pollLimit = 10000; - const size_t minDataLen = 1; - const size_t maxDataLen = 255; + const span<const uint_least8_t>::index_type maxDataLen = 255; - if ((write_data && - (write_data_len < minDataLen || write_data_len > maxDataLen)) || - (read_data && - (read_data_len < minDataLen || read_data_len > maxDataLen))) { + if ((!write_data.empty() && write_data.size() > maxDataLen) || + (!read_data.empty() && read_data.size() > maxDataLen)) { return make_error_code(OutOfRangeError); } @@ -172,21 +164,21 @@ return result; } } - if (write_data) { - crc16 = calculateCrc16(static_cast<uint_fast8_t>(write_data_len), crc16); - result = master->writeByte(static_cast<uint_least8_t>(write_data_len)); + if (!write_data.empty()) { + crc16 = calculateCrc16(static_cast<uint_fast8_t>(write_data.size()), crc16); + result = master->writeByte(static_cast<uint_least8_t>(write_data.size())); if (result) { return result; } - crc16 = calculateCrc16(write_data, write_data_len, crc16); - result = master->writeBlock(write_data, write_data_len); + crc16 = calculateCrc16(write_data, crc16); + result = master->writeBlock(write_data); if (result) { return result; } } - if (read_data) { - crc16 = calculateCrc16(static_cast<uint_fast8_t>(read_data_len), crc16); - result = master->writeByte(static_cast<uint_least8_t>(read_data_len)); + if (!read_data.empty()) { + crc16 = calculateCrc16(static_cast<uint_fast8_t>(read_data.size()), crc16); + result = master->writeByte(static_cast<uint_least8_t>(read_data.size())); if (result) { return result; } @@ -194,8 +186,7 @@ crc16 ^= 0xFFFFU; const uint_least8_t crc16Bytes[] = {static_cast<uint_least8_t>(crc16), static_cast<uint_least8_t>(crc16 >> 8)}; - result = master->writeBlock(crc16Bytes, - sizeof(crc16Bytes) / sizeof(crc16Bytes[0])); + result = master->writeBlock(crc16Bytes); if (result) { return result; } @@ -225,7 +216,7 @@ if ((status & 0x8) == 0x8) { return make_error_code(InvalidStartError); } - if (write_data) { + if (!write_data.empty()) { result = master->readByte(status); if (result) { return result; @@ -237,8 +228,8 @@ return make_error_code(WriteNackError); } } - if (read_data) { - result = master->readBlock(read_data, read_data_len); + if (!read_data.empty()) { + result = master->readBlock(read_data); } return result; }
--- a/Devices/DS28E17.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS28E17.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -36,10 +36,11 @@ #include <stdint.h> #include <MaximInterface/Links/SelectRom.hpp> #include <MaximInterface/Utilities/Export.h> +#include <MaximInterface/Utilities/span.hpp> namespace MaximInterface { -/// DS28E17 1-Wire®-to-I2C Master Bridge +/// @brief DS28E17 1-Wire®-to-I2C Master Bridge /// @details The DS28E17 is a 1-Wire slave to I2C master bridge /// device that interfaces directly to I2C slaves at standard /// (100kHz max) or fast (400kHz max). Data transfers serially by @@ -69,110 +70,102 @@ : selectRom(selectRom), master(&master) {} void setMaster(OneWireMaster & master) { this->master = &master; } + void setSelectRom(const SelectRom & selectRom) { this->selectRom = selectRom; } - /// Write Data With Stop command. + /// @brief Write Data With Stop command. /// @details Output on I2C: S, Address + Write, Write Data [1-255], P /// @param[in] I2C_addr /// I2C slave address. The least significant bit of the I2C /// address is automatically cleared by the command. - /// @param[in] data I2C data to write. - /// @param[in] data_len Length of data. Valid from 1-255. + /// @param[in] data I2C data to write with length 1-255. /// @param[out] wr_status /// Indicates which write byte NACK’d. A value of 00h indicates all bytes /// were acknowledged by the slave. A non-zero value indicates the byte number /// that NACK’d. May be set to NULL. MaximInterface_EXPORT error_code - writeDataWithStop(uint_least8_t I2C_addr, const uint_least8_t * data, - size_t data_len, uint_least8_t * wr_status = NULL); + writeDataWithStop(uint_least8_t I2C_addr, span<const uint_least8_t> data, + uint_least8_t * wr_status = NULL); - /// Write Data No Stop command. + /// @brief Write Data No Stop command. /// @details Output on I2C: S, Address + Write, Write Data [1-255] /// @param[in] I2C_addr /// I2C slave address. The least significant bit of the I2C address /// is automatically cleared by the command. - /// @param[in] data I2C data to write. - /// @param[in] data_len Length of data. Valid from 1-255. + /// @param[in] data I2C data to write with length 1-255. /// @param[out] wr_status /// Indicates which write byte NACK’d. A value of 00h indicates all bytes /// were acknowledged by the slave. A non-zero value indicates the byte number /// that NACK’d. May be set to NULL. MaximInterface_EXPORT error_code - writeDataNoStop(uint_least8_t I2C_addr, const uint_least8_t * data, - size_t data_len, uint_least8_t * wr_status = NULL); + writeDataNoStop(uint_least8_t I2C_addr, span<const uint_least8_t> data, + uint_least8_t * wr_status = NULL); - /// Write Data Only command. + /// @brief Write Data Only command. /// @details Output on I2C: Write Data [1-255] - /// @param[in] data I2C data to write. - /// @param[in] data_len Length of data. Valid from 1-255. + /// @param[in] data I2C data to write with length 1-255. /// @param[out] wr_status /// Indicates which write byte NACK’d. A value of 00h indicates all bytes /// were acknowledged by the slave. A non-zero value indicates the byte number /// that NACK’d. May be set to NULL. MaximInterface_EXPORT error_code - writeDataOnly(const uint_least8_t * data, size_t data_len, + writeDataOnly(span<const uint_least8_t> data, uint_least8_t * wr_status = NULL); - /// Write Data Only With Stop command. + /// @brief Write Data Only With Stop command. /// @details Output on I2C: Write Data [1-255], P - /// @param[in] data I2C data to write. - /// @param[in] data_len Length of data. Valid from 1-255. + /// @param[in] data I2C data to write with length 1-255. /// @param[out] wr_status /// Indicates which write byte NACK’d. A value of 00h indicates all bytes /// were acknowledged by the slave. A non-zero value indicates the byte number /// that NACK’d. May be set to NULL. MaximInterface_EXPORT error_code - writeDataOnlyWithStop(const uint_least8_t * data, size_t data_len, + writeDataOnlyWithStop(span<const uint_least8_t> data, uint_least8_t * wr_status = NULL); - /// Write, Read Data With Stop command. + /// @brief Write, Read Data With Stop command. /// @details Output on I2C: /// S, Slave Address + Write, Write Data [1-255], /// Sr, Address + Read, Read Data [1-255], P (NACK last read byte) /// @param[in] I2C_addr /// I2C slave address. The least significant bit of the I2C address /// is automatically cleared and set by the command. - /// @param[in] write_data I2C data to write. - /// @param[in] write_data_len Length of write_data. Valid from 1-255. - /// @param[out] read_data I2C data that was read. - /// @param[in] read_data_len Length of read_data. Valid from 1-255. + /// @param[in] write_data I2C data to write with length 1-255. + /// @param[out] read_data I2C data that was read with length 1-255. /// @param[out] wr_status /// Indicates which write byte NACK’d. A value of 00h indicates all bytes /// were acknowledged by the slave. A non-zero value indicates the byte number /// that NACK’d. May be set to NULL. MaximInterface_EXPORT error_code writeReadDataWithStop( - uint_least8_t I2C_addr, const uint_least8_t * write_data, - size_t write_data_len, uint_least8_t * read_data, size_t read_data_len, - uint_least8_t * wr_status = NULL); + uint_least8_t I2C_addr, span<const uint_least8_t> write_data, + span<uint_least8_t> read_data, uint_least8_t * wr_status = NULL); - /// Read Data With Stop command. + /// @brief Read Data With Stop command. /// @details Output on I2C: /// S, Slave Address + Read, Read Data [1-255], P (NACK last read byte) /// @param[in] I2C_addr /// I2C slave address. The least significant bit of the I2C address /// is automatically set by the command. - /// @param[out] data I2C data that was read. - /// @param[in] data_len Length of data. Valid from 1-255. + /// @param[out] data I2C data that was read with length 1-255. MaximInterface_EXPORT error_code readDataWithStop(uint_least8_t I2C_addr, - uint_least8_t * data, - size_t data_len); + span<uint_least8_t> data); /// Write to Configuration Register of DS28E17. MaximInterface_EXPORT error_code writeConfigReg(I2CSpeed speed); - /// Read the Configuration Register of DS28E17. + /// @brief Read the Configuration Register of DS28E17. /// @param[out] speed Speed read from configuration register. MaximInterface_EXPORT error_code readConfigReg(I2CSpeed & speed); - /// The Enable Sleep Mode command puts the device into a low current mode. + /// @brief Put the device into a low current mode. /// @details All 1-Wire communication is ignored until woken up. Immediately /// after the command, the device monitors the WAKEUP input pin and exits /// sleep mode on a rising edge. MaximInterface_EXPORT error_code enableSleepMode(); - /// Read the Device Revision of DS28E17. + /// @brief Read the Device Revision of DS28E17. /// @details The upper nibble is the major revision, /// and the lower nibble is the minor revision. /// @param[out] rev Device Revision. @@ -195,8 +188,8 @@ }; error_code sendPacket(Command command, const uint_least8_t * I2C_addr, - const uint_least8_t * write_data, size_t write_data_len, - uint_least8_t * read_data, size_t read_data_len, + span<const uint_least8_t> write_data, + span<uint_least8_t> read_data, uint_least8_t * wr_status); SelectRom selectRom;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Devices/DS28E38.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -0,0 +1,302 @@ +/******************************************************************************* +* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#include <stddef.h> +#include <algorithm> +#include <MaximInterface/Utilities/Algorithm.hpp> +#include <MaximInterface/Utilities/Error.hpp> +#include "DS28E38.hpp" + +namespace MaximInterface { + +using std::copy; + +static const int readMemoryTimeMs = 30; +static const int writeMemoryTimeMs = 65; +static const int writeStateTimeMs = 15; +static const int generateEccKeyPairTimeMs = 200; +static const int generateEcdsaSignatureTimeMs = 130; +static const int trngOnDemandCheckTimeMs = 20; +static const int trngGenerationTimeMs = 10; + +const int DS28E38::decrementCounterPage; +const int DS28E38::publicKeyXPage; +const int DS28E38::publicKeyYPage; +const int DS28E38::privateKeyPage; +const int DS28E38::memoryPages; + +error_code DS28E38::writeMemory(int pageNum, Page::const_span page) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t command[2 + Page::size]; + command[0] = 0x96; + command[1] = pageNum; + copy(page.begin(), page.end(), command + 2); + return runCommand(command, writeMemoryTimeMs); +} + +error_code DS28E38::readMemory(int pageNum, Page::span page) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer[1 + Page::size]; + buffer[0] = 0x44; + buffer[1] = pageNum; + span<uint_least8_t> response(buffer); + const error_code result = + runCommand(make_span(buffer, 2), readMemoryTimeMs, response); + if (!result) { + copy(response.begin(), response.end(), page.begin()); + } + return result; +} + +error_code DS28E38::readStatus(bool entropyHealthTest, Status & status) { + int delay = readMemoryTimeMs; + if (entropyHealthTest) { + delay += trngOnDemandCheckTimeMs; + } + uint_least8_t buffer[Status::PageProtectionList::csize + ManId::size + + Status::RomVersion::csize + 2]; + buffer[0] = 0xAA; + buffer[1] = entropyHealthTest ? 0x01 : 0x00; + span<uint_least8_t> response(buffer); + error_code result = runCommand(make_span(buffer, 2), delay, response); + if (!result) { + span<uint_least8_t>::const_iterator responseIt = response.begin(); + for (Status::PageProtectionList::iterator it = + status.pageProtection.begin(); + it != status.pageProtection.end(); ++it) { + *it = *responseIt; + ++responseIt; + } + span<uint_least8_t>::const_iterator responseItEnd = + responseIt + status.manId.size(); + copy(responseIt, responseItEnd, status.manId.begin()); + responseIt = responseItEnd; + responseItEnd = responseIt + status.romVersion.size(); + copy(responseIt, responseItEnd, status.romVersion.begin()); + responseIt = responseItEnd; + switch (*responseIt) { + case Status::TestNotPerformed: + case Status::EntropyHealthy: + case Status::EntropyNotHealthy: + status.entropyHealthTestStatus = + static_cast<Status::EntropyHealthTestStatus>(*responseIt); + break; + + default: + result = make_error_code(InvalidResponseError); + break; + } + } + return result; +} + +error_code DS28E38::setPageProtection(int pageNum, + const PageProtection & protection) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + int delay = writeStateTimeMs; + if (pageNum == decrementCounterPage) { + delay += writeMemoryTimeMs; + } + const uint_least8_t command[] = { + 0xC3, static_cast<uint_least8_t>(pageNum), + static_cast<uint_least8_t>(protection.to_ulong())}; + return runCommand(command, delay); +} + +error_code +DS28E38::computeAndReadPageAuthentication(int pageNum, bool anonymous, + Page::const_span challenge, + Ecc256::Signature::span signature) { + if (pageNum < 0 || pageNum >= memoryPages) { + return make_error_code(InvalidParameterError); + } + + const size_t commandSize = 2 + Page::size; + const size_t responseSize = 1 + 2 * Ecc256::Scalar::size; + uint_least8_t buffer[MaximInterface_MAX(commandSize, responseSize)]; + buffer[0] = 0xA5; + buffer[1] = pageNum | (anonymous ? 0xE0 : 0x00); + copy(challenge.begin(), challenge.end(), buffer + 2); + span<uint_least8_t> response(buffer, responseSize); + const error_code result = runCommand(make_span(buffer, commandSize), + generateEcdsaSignatureTimeMs, response); + if (!result) { + span<uint_least8_t>::const_iterator begin = response.begin(); + span<uint_least8_t>::const_iterator end = begin + signature.s.size(); + copy(begin, end, signature.s.begin()); + begin = end; + end = begin + signature.r.size(); + copy(begin, end, signature.r.begin()); + } + return result; +} + +error_code DS28E38::decrementCounter() { + const uint_least8_t command = 0xC9; + return runCommand(make_span(&command, 1), writeMemoryTimeMs); +} + +error_code DS28E38::disableDevice() { + const uint_least8_t command[] = {0x33, 0x9E, 0xA7, 0x49, 0xFB, + 0x10, 0x62, 0x0A, 0x26}; + return runCommand(command, writeStateTimeMs); +} + +error_code DS28E38::generateEcc256KeyPair(bool privateKeyPuf, + bool writeProtectEnable) { + int delay = generateEccKeyPairTimeMs; + if (writeProtectEnable) { + delay += writeStateTimeMs; + } + uint_least8_t command[] = {0xCB, 0x00}; + if (privateKeyPuf) { + command[1] |= 0x01; + } + if (writeProtectEnable) { + command[1] |= 0x80; + } + return runCommand(command, delay); +} + +error_code DS28E38::readRng(span<uint_least8_t> data) { + const span<uint_least8_t>::index_type maxDataSize = 64; + if ((data.size() < 1) || (data.size() > maxDataSize)) { + return make_error_code(InvalidParameterError); + } + + uint_least8_t buffer[1 + maxDataSize]; + buffer[0] = 0xD2; + buffer[1] = data.size() - 1; + span<uint_least8_t> response(buffer, 1 + data.size()); + const error_code result = + runCommand(make_span(buffer, 2), trngGenerationTimeMs, response); + if (!result) { + copy(response.begin(), response.end(), data.begin()); + } + return result; +} + +error_code DS28E38::runCommand(span<const uint_least8_t> command, int delayTime, + span<uint_least8_t> & response) { + const span<const uint_least8_t>::index_type responseInputSize = + response.size(); + error_code result = doRunCommand(command, delayTime, response); + if (result) { + return result; + } + if (response.empty()) { + return make_error_code(InvalidResponseError); + } + // Parse command result byte. + switch (response[0]) { + case 0xAA: + // Success response. + if (response.size() != responseInputSize) { + result = make_error_code(InvalidResponseError); + } + break; + + case 0x00: + result = make_error_code(InvalidResponseError); + break; + + default: + result.assign(response[0], errorCategory()); + break; + } + response = response.subspan(1); + return result; +} + +error_code DS28E38::runCommand(span<const uint_least8_t> command, + int delayTime) { + uint_least8_t buffer; + span<uint_least8_t> response(&buffer, 1); + return runCommand(command, delayTime, response); +} + +const error_category & DS28E38::errorCategory() { + static class : public error_category { + public: + virtual const char * name() const { return "DS28E38"; } + + virtual std::string message(int condition) const { + switch (condition) { + case InvalidOperationError: + return "Invalid Operation Error"; + + case InvalidParameterError: + return "Invalid Parameter Error"; + + case InvalidSequenceError: + return "Invalid Sequence Error"; + + case InternalError: + return "Internal Error"; + + case DeviceDisabledError: + return "Device Disabled Error"; + + case InvalidResponseError: + return "Invalid Response Error"; + } + return defaultErrorMessage(condition); + } + } instance; + return instance; +} + +error_code readManId(DS28E38 & ds28e38, ManId::span manId) { + DS28E38::Status status; + const error_code result = ds28e38.readStatus(false, status); + if (!result) { + copy(make_span(status.manId), manId); + } + return result; +} + +DS28E38::PageAuthenticationData & +DS28E38::PageAuthenticationData::setAnonymousRomId() { + std::fill(romId().begin(), romId().end(), 0xFF); + return *this; +} + +} // namespace MaximInterface
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Devices/DS28E38.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -0,0 +1,316 @@ +/******************************************************************************* +* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#ifndef MaximInterface_DS28E38 +#define MaximInterface_DS28E38 + +#include <stdint.h> +#include <MaximInterface/Links/RunCommand.hpp> +#include <MaximInterface/Utilities/array_span.hpp> +#include <MaximInterface/Utilities/Ecc256.hpp> +#include <MaximInterface/Utilities/Export.h> +#include <MaximInterface/Utilities/FlagSet.hpp> +#include <MaximInterface/Utilities/ManId.hpp> +#include <MaximInterface/Utilities/system_error.hpp> + +namespace MaximInterface { + +class DS28E38 { +public: + /// Device command results. + enum ErrorValue { + InvalidOperationError = 0x55, + InvalidParameterError = 0x77, + InvalidSequenceError = 0x33, + InternalError = 0x22, + DeviceDisabledError = 0x88, + InvalidResponseError = + 0x100 ///< Command response does not match expected format. + }; + + /// @name Device memory pages + /// @{ + + static const int decrementCounterPage = 3; + static const int publicKeyXPage = 4; + static const int publicKeyYPage = 5; + static const int privateKeyPage = 6; + + /// @} + + static const int memoryPages = 7; + + /// Holds a device memory page. + typedef array_span<uint_least8_t, 32> Page; + + // Format page authentication input data. + class PageAuthenticationData; + + /// Page protection types. + enum PageProtectionType { + RP = 0x01, ///< Read protection. + WP = 0x02, ///< Write protection. + EM = 0x04, ///< EPROM emulation mode. + DC = 0x08, ///< Decrement counter. + PF = 0x10 ///< PUF used as private key. + }; + typedef FlagSet<PageProtectionType, 5> PageProtection; + + struct Status { + enum EntropyHealthTestStatus { + TestNotPerformed = 0xFF, + EntropyHealthy = 0xAA, + EntropyNotHealthy = 0xDD + }; + + typedef array<PageProtection, memoryPages> PageProtectionList; + typedef array<uint_least8_t, 2> RomVersion; + + PageProtectionList pageProtection; + ManId::array manId; + RomVersion romVersion; + EntropyHealthTestStatus entropyHealthTestStatus; + }; + + explicit DS28E38(const RunCommand & runCommand) : doRunCommand(runCommand) {} + + void setRunCommand(const RunCommand & runCommand) { + doRunCommand = runCommand; + } + + /// @brief Write memory with no protection. + /// @param pageNum Number of page to write. + /// @param page Data to write. + MaximInterface_EXPORT error_code writeMemory(int pageNum, + Page::const_span page); + + /// @brief Read memory with no protection. + /// @param pageNum Number of page to read. + /// @param[out] page Data that was read. + MaximInterface_EXPORT error_code readMemory(int pageNum, Page::span page); + + /// @brief + /// Reads the current status of the device and optionally performs an + /// entropy health test. + /// @param entropyHealthTest True to perform an entropy health test. + /// @param[out] status Status that was read. + MaximInterface_EXPORT error_code readStatus(bool entropyHealthTest, + Status & status); + + /// @brief Set the protection settings of a page. + /// @param pageNum Number of page to write. + /// @param protection Protection to write. + MaximInterface_EXPORT error_code + setPageProtection(int pageNum, const PageProtection & protection); + + /// @brief Compute and read page authentication with ECDSA. + /// @param pageNum Number of page to authenticate. + /// @param anonymous True to disable use of ROM ID in computation. + /// @param challenge Random challenge used to prevent replay attacks. + /// @param[out] signature Computed page signature. + MaximInterface_EXPORT error_code computeAndReadPageAuthentication( + int pageNum, bool anonymous, Page::const_span challenge, + Ecc256::Signature::span signature); + + /// Decrement the decrement-only counter. + MaximInterface_EXPORT error_code decrementCounter(); + + /// Permanently disable the device. + MaximInterface_EXPORT error_code disableDevice(); + + /// @brief Generate a new ECDSA public key from an existing private key. + /// @param privateKeyPuf True if PUF is used as the private key. + /// @param writeProtectEnable True to lock the key against further writes. + MaximInterface_EXPORT error_code + generateEcc256KeyPair(bool privateKeyPuf, bool writeProtectEnable); + + /// @brief Read a block of random data from the RNG. + /// @param[out] data Random data from RNG with length from 1 to 64. + MaximInterface_EXPORT error_code readRng(span<uint_least8_t> data); + + MaximInterface_EXPORT static const error_category & errorCategory(); + +protected: + MaximInterface_EXPORT error_code runCommand(span<const uint_least8_t> command, + int delayTime, + span<uint_least8_t> & response); + + MaximInterface_EXPORT error_code runCommand(span<const uint_least8_t> command, + int delayTime); + +private: + RunCommand doRunCommand; +}; + +inline error_code make_error_code(DS28E38::ErrorValue e) { + return error_code(e, DS28E38::errorCategory()); +} + +/// @brief Read the device MAN ID using the Read Status command. +/// @param ds28e38 Device to read. +/// @param[out] manId Read MAN ID valid when operation is successful. +MaximInterface_EXPORT error_code readManId(DS28E38 & ds28e38, + ManId::span manId); + +/// Format page authentication input data. +class DS28E38::PageAuthenticationData { +public: + typedef array_span<uint_least8_t, + RomId::size + 2 * Page::size + 1 + ManId::size> + Result; + + PageAuthenticationData() : result_() {} + + /// Formatted data result. + Result::const_span result() const { return result_; } + + /// @name ROM ID + /// @brief 1-Wire ROM ID of the device. + /// @{ + + /// Get mutable ROM ID. + RomId::span romId() { + return make_span(result_).subspan<romIdIdx, RomId::size>(); + } + + /// Get immutable ROM ID. + RomId::const_span romId() const { + return const_cast<PageAuthenticationData &>(*this).romId(); + } + + /// Set ROM ID. + PageAuthenticationData & setRomId(RomId::const_span romId) { + copy(romId, this->romId()); + return *this; + } + + /// Set ROM ID for use in anonymous mode. + MaximInterface_EXPORT PageAuthenticationData & setAnonymousRomId(); + + /// @} + + /// @name Page + /// @brief Data from a device memory page. + /// @{ + + /// Get mutable page. + Page::span page() { + return make_span(result_).subspan<pageIdx, Page::size>(); + } + + /// Get immutable page. + Page::const_span page() const { + return const_cast<PageAuthenticationData &>(*this).page(); + } + + /// Set page. + PageAuthenticationData & setPage(Page::const_span page) { + copy(page, this->page()); + return *this; + } + + /// @} + + /// @name Challenge + /// @brief Random challenge used to prevent replay attacks. + /// @{ + + /// Get mutable Challenge. + Page::span challenge() { + return make_span(result_).subspan<challengeIdx, Page::size>(); + } + + /// Get immutable Challenge. + Page::const_span challenge() const { + return const_cast<PageAuthenticationData &>(*this).challenge(); + } + + /// Set Challenge. + PageAuthenticationData & setChallenge(Page::const_span challenge) { + copy(challenge, this->challenge()); + return *this; + } + + /// @} + + /// @name Page number + /// @brief Number of the page to use data from. + /// @{ + + /// Get page number. + int pageNum() const { return result_[pageNumIdx]; } + + /// Set page number. + PageAuthenticationData & setPageNum(int pageNum) { + result_[pageNumIdx] = pageNum; + return *this; + } + + /// @} + + /// @name MAN ID + /// @brief Manufacturer ID of the device. + /// @{ + + /// Get mutable MAN ID. + ManId::span manId() { + return make_span(result_).subspan<manIdIdx, ManId::size>(); + } + + /// Get immutable MAN ID. + ManId::const_span manId() const { + return const_cast<PageAuthenticationData &>(*this).manId(); + } + + /// Set MAN ID. + PageAuthenticationData & setManId(ManId::const_span manId) { + copy(manId, this->manId()); + return *this; + } + + /// @} + +private: + typedef Result::span::index_type index; + + static const index romIdIdx = 0; + static const index pageIdx = romIdIdx + RomId::size; + static const index challengeIdx = pageIdx + Page::size; + static const index pageNumIdx = challengeIdx + Page::size; + static const index manIdIdx = pageNumIdx + 1; + + Result::array result_; +}; + +} // namespace MaximInterface + +#endif
--- a/Devices/DS9400.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS9400.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -59,7 +59,7 @@ const uint_least8_t packet[] = {'Q', data}; error_code result = uart->clearReadBuffer(); if (!result) { - result = uart->writeBlock(packet, sizeof(packet) / sizeof(packet[0])); + result = uart->writeBlock(packet); if (!result) { result = uart->readByte(data); if (!result && data != 0) { @@ -83,7 +83,7 @@ error_code DS9400::configure(uint_least8_t config) { const uint_least8_t packet[] = {'C', config}; - return uart->writeBlock(packet, sizeof(packet) / sizeof(packet[0])); + return uart->writeBlock(packet); } -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Devices/DS9400.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS9400.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -48,9 +48,13 @@ MaximInterface_EXPORT error_code waitAwake(); MaximInterface_EXPORT error_code start(); + MaximInterface_EXPORT virtual error_code start(uint_least8_t address); + MaximInterface_EXPORT virtual error_code stop(); + MaximInterface_EXPORT virtual error_code writeByte(uint_least8_t data); + MaximInterface_EXPORT virtual error_code readByte(AckStatus status, uint_least8_t & data); @@ -63,4 +67,4 @@ } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Devices/DS9481P_300.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS9481P_300.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,7 +35,7 @@ namespace MaximInterface { -DS9481P_300::DS9481P_300(const Sleep & sleep, SerialPort & serialPort) +DS9481P_300::DS9481P_300(Sleep & sleep, SerialPort & serialPort) : serialPort(&serialPort), currentBus(OneWire), ds2480b(sleep, serialPort), oneWireMaster_(*this), ds9400(serialPort), i2cMaster_(*this) {} @@ -135,20 +135,19 @@ } error_code -DS9481P_300::OneWireMasterImpl::writeBlock(const uint_least8_t * sendBuf, - size_t sendLen) { +DS9481P_300::OneWireMasterImpl::writeBlock(span<const uint_least8_t> sendBuf) { error_code result = parent->selectBus(OneWire); if (!result) { - result = OneWireMasterDecorator::writeBlock(sendBuf, sendLen); + result = OneWireMasterDecorator::writeBlock(sendBuf); } return result; } -error_code DS9481P_300::OneWireMasterImpl::readBlock(uint_least8_t * recvBuf, - size_t recvLen) { +error_code +DS9481P_300::OneWireMasterImpl::readBlock(span<uint_least8_t> recvBuf) { error_code result = parent->selectBus(OneWire); if (!result) { - result = OneWireMasterDecorator::readBlock(recvBuf, recvLen); + result = OneWireMasterDecorator::readBlock(recvBuf); } return result; } @@ -201,22 +200,20 @@ return result; } -error_code DS9481P_300::I2CMasterImpl::writeBlock(const uint_least8_t * data, - size_t dataLen) { +error_code +DS9481P_300::I2CMasterImpl::writeBlock(span<const uint_least8_t> data) { error_code result = parent->selectBus(I2C); if (!result) { - result = I2CMasterDecorator::writeBlock(data, dataLen); + result = I2CMasterDecorator::writeBlock(data); } return result; } error_code DS9481P_300::I2CMasterImpl::writePacketImpl( - uint_least8_t address, const uint_least8_t * data, size_t dataLen, - bool sendStop) { + uint_least8_t address, span<const uint_least8_t> data, bool sendStop) { error_code result = parent->selectBus(I2C); if (!result) { - result = I2CMasterDecorator::writePacketImpl(address, data, dataLen, - sendStop); + result = I2CMasterDecorator::writePacketImpl(address, data, sendStop); } return result; } @@ -231,23 +228,20 @@ } error_code DS9481P_300::I2CMasterImpl::readBlock(AckStatus status, - uint_least8_t * data, - size_t dataLen) { + span<uint_least8_t> data) { error_code result = parent->selectBus(I2C); if (!result) { - result = I2CMasterDecorator::readBlock(status, data, dataLen); + result = I2CMasterDecorator::readBlock(status, data); } return result; } error_code DS9481P_300::I2CMasterImpl::readPacketImpl(uint_least8_t address, - uint_least8_t * data, - size_t dataLen, + span<uint_least8_t> data, bool sendStop) { error_code result = parent->selectBus(I2C); if (!result) { - result = I2CMasterDecorator::readPacketImpl(address, data, dataLen, - sendStop); + result = I2CMasterDecorator::readPacketImpl(address, data, sendStop); } return result; } @@ -260,4 +254,4 @@ return configure('O'); } -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Devices/DS9481P_300.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Devices/DS9481P_300.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -46,10 +46,10 @@ /// DS9481P-300 USB to 1-Wire and I2C adapter. class DS9481P_300 { public: - MaximInterface_EXPORT DS9481P_300(const Sleep & sleep, - SerialPort & serialPort); + MaximInterface_EXPORT DS9481P_300(Sleep & sleep, SerialPort & serialPort); - void setSleep(const Sleep & sleep) { ds2480b.setSleep(sleep); } + void setSleep(Sleep & sleep) { ds2480b.setSleep(sleep); } + void setSerialPort(SerialPort & serialPort) { this->serialPort = &serialPort; ds2480b.setUart(serialPort); @@ -57,13 +57,16 @@ } MaximInterface_EXPORT error_code connect(const std::string & portName); + MaximInterface_EXPORT error_code disconnect(); + MaximInterface_EXPORT bool connected() const; + MaximInterface_EXPORT std::string portName() const; /// Access the 1-Wire master when connected to an adapter. OneWireMaster & oneWireMaster() { return oneWireMaster_; } - + /// Access the I2C master when connected to an adapter. I2CMaster & i2cMaster() { return i2cMaster_; } @@ -73,18 +76,28 @@ explicit OneWireMasterImpl(DS9481P_300 & parent) : OneWireMasterDecorator(parent.ds2480b), parent(&parent) {} - virtual error_code reset(); - virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel); - virtual error_code writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel); - virtual error_code readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel); - virtual error_code writeBlock(const uint_least8_t * sendBuf, - size_t sendLen); - virtual error_code readBlock(uint_least8_t * recvBuf, size_t recvLen); - virtual error_code setSpeed(Speed newSpeed); - virtual error_code setLevel(Level newLevel); - virtual error_code triplet(TripletData & data); + MaximInterface_EXPORT virtual error_code reset(); + + MaximInterface_EXPORT virtual error_code + touchBitSetLevel(bool & sendRecvBit, Level afterLevel); + + MaximInterface_EXPORT virtual error_code + writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); + + MaximInterface_EXPORT virtual error_code + readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + + MaximInterface_EXPORT virtual error_code + writeBlock(span<const uint_least8_t> sendBuf); + + MaximInterface_EXPORT virtual error_code + readBlock(span<uint_least8_t> recvBuf); + + MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed); + + MaximInterface_EXPORT virtual error_code setLevel(Level newLevel); + + MaximInterface_EXPORT virtual error_code triplet(TripletData & data); private: DS9481P_300 * parent; @@ -95,21 +108,28 @@ explicit I2CMasterImpl(DS9481P_300 & parent) : I2CMasterDecorator(parent.ds9400), parent(&parent) {} - virtual error_code start(uint_least8_t address); - virtual error_code stop(); - virtual error_code writeByte(uint_least8_t data); - virtual error_code writeBlock(const uint_least8_t * data, size_t dataLen); - virtual error_code readByte(AckStatus status, uint_least8_t & data); - virtual error_code readBlock(AckStatus status, uint_least8_t * data, - size_t dataLen); + MaximInterface_EXPORT virtual error_code start(uint_least8_t address); + + MaximInterface_EXPORT virtual error_code stop(); + + MaximInterface_EXPORT virtual error_code writeByte(uint_least8_t data); + + MaximInterface_EXPORT virtual error_code + writeBlock(span<const uint_least8_t> data); + + MaximInterface_EXPORT virtual error_code readByte(AckStatus status, + uint_least8_t & data); + MaximInterface_EXPORT virtual error_code + readBlock(AckStatus status, span<uint_least8_t> data); protected: - virtual error_code writePacketImpl(uint_least8_t address, - const uint_least8_t * data, - size_t dataLen, bool sendStop); - virtual error_code readPacketImpl(uint_least8_t address, - uint_least8_t * data, size_t dataLen, - bool sendStop); + MaximInterface_EXPORT virtual error_code + writePacketImpl(uint_least8_t address, span<const uint_least8_t> data, + bool sendStop); + + MaximInterface_EXPORT virtual error_code + readPacketImpl(uint_least8_t address, span<uint_least8_t> data, + bool sendStop); private: DS9481P_300 * parent; @@ -117,8 +137,7 @@ class DS2480BWithEscape : public DS2480B { public: - DS2480BWithEscape(const Sleep & sleep, Uart & uart) - : DS2480B(sleep, uart) {} + DS2480BWithEscape(Sleep & sleep, Uart & uart) : DS2480B(sleep, uart) {} error_code escape(); }; @@ -148,4 +167,4 @@ } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Links/I2CMaster.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/I2CMaster.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,20 +35,21 @@ namespace MaximInterface { -error_code I2CMaster::writeBlock(const uint_least8_t * data, size_t dataLen) { +error_code I2CMaster::writeBlock(span<const uint_least8_t> data) { error_code result; - for (size_t i = 0; (i < dataLen) && !result; i++) { + for (span<const uint_least8_t>::index_type i = 0; + i < data.size() && !result; ++i) { result = writeByte(data[i]); } return result; } error_code I2CMaster::writePacketImpl(uint_least8_t address, - const uint_least8_t * data, - size_t dataLen, bool sendStop) { + span<const uint_least8_t> data, + bool sendStop) { error_code result = start(address & 0xFE); if (!result) { - result = writeBlock(data, dataLen); + result = writeBlock(data); } if (sendStop) { error_code stopResult = stop(); @@ -59,21 +60,19 @@ return result; } -error_code I2CMaster::readBlock(AckStatus status, uint_least8_t * data, - size_t dataLen) { +error_code I2CMaster::readBlock(AckStatus status, span<uint_least8_t> data) { error_code result; - for (size_t i = 0; (i < dataLen) && !result; i++) { - result = readByte(i == (dataLen - 1) ? status : Ack, data[i]); + for (span<uint_least8_t>::index_type i = 0; i < data.size() && !result; ++i) { + result = readByte(i == (data.size() - 1) ? status : Ack, data[i]); } return result; } error_code I2CMaster::readPacketImpl(uint_least8_t address, - uint_least8_t * data, size_t dataLen, - bool sendStop) { + span<uint_least8_t> data, bool sendStop) { error_code result = start(address | 0x01); if (!result) { - result = readBlock(Nack, data, dataLen); + result = readBlock(Nack, data); } if (sendStop) { error_code stopResult = stop(); @@ -102,4 +101,4 @@ return instance; } -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Links/I2CMaster.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/I2CMaster.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -33,9 +33,9 @@ #ifndef MaximInterface_I2CMaster #define MaximInterface_I2CMaster -#include <stddef.h> #include <stdint.h> #include <MaximInterface/Utilities/Export.h> +#include <MaximInterface/Utilities/span.hpp> #include <MaximInterface/Utilities/system_error.hpp> namespace MaximInterface { @@ -51,7 +51,7 @@ virtual ~I2CMaster() {} - /// Send start condition and address on the bus. + /// @brief Send start condition and address on the bus. /// @param address Address with R/W bit. virtual error_code start(uint_least8_t address) = 0; @@ -63,60 +63,63 @@ /// Write data block to the bus. MaximInterface_EXPORT virtual error_code - writeBlock(const uint_least8_t * data, size_t dataLen); + writeBlock(span<const uint_least8_t> data); + /// @brief /// Perform a complete write transaction on the bus with optional stop /// condition. /// @param address Address in 8-bit format. + /// @param data Data to write to the bus. /// @param sendStop /// True to send a stop condition or false to set up a repeated start. - error_code writePacket(uint_least8_t address, const uint_least8_t * data, - size_t dataLen, bool sendStop = true) { - return writePacketImpl(address, data, dataLen, sendStop); + error_code writePacket(uint_least8_t address, span<const uint_least8_t> data, + bool sendStop = true) { + return writePacketImpl(address, data, sendStop); } - /// Read data byte from the bus. + /// @brief Read data byte from the bus. /// @param status Determines whether an ACK or NACK is sent after reading. /// @param[out] data Data read from the bus if successful. virtual error_code readByte(AckStatus status, uint_least8_t & data) = 0; - /// Read data block from the bus. + /// @brief Read data block from the bus. /// @param status Determines whether an ACK or NACK is sent after reading. /// @param[out] data Data read from the bus if successful. - /// @param dataLen Number of bytes to read and length of data. MaximInterface_EXPORT virtual error_code - readBlock(AckStatus status, uint_least8_t * data, size_t dataLen); + readBlock(AckStatus status, span<uint_least8_t> data); + /// @brief /// Perform a complete read transaction on the bus with optional stop /// condition. /// @param address Address in 8-bit format. + /// @param[out] data Data read from the bus if successful. /// @param sendStop /// True to send a stop condition or false to set up a repeated start. - error_code readPacket(uint_least8_t address, uint_least8_t * data, - size_t dataLen, bool sendStop = true) { - return readPacketImpl(address, data, dataLen, sendStop); + error_code readPacket(uint_least8_t address, span<uint_least8_t> data, + bool sendStop = true) { + return readPacketImpl(address, data, sendStop); } MaximInterface_EXPORT static const error_category & errorCategory(); protected: MaximInterface_EXPORT virtual error_code - writePacketImpl(uint_least8_t address, const uint_least8_t * data, - size_t dataLen, bool sendStop); + writePacketImpl(uint_least8_t address, span<const uint_least8_t> data, + bool sendStop); - MaximInterface_EXPORT virtual error_code readPacketImpl(uint_least8_t address, - uint_least8_t * data, - size_t dataLen, - bool sendStop); + MaximInterface_EXPORT virtual error_code + readPacketImpl(uint_least8_t address, span<uint_least8_t> data, + bool sendStop); }; inline error_code make_error_code(I2CMaster::ErrorValue e) { return error_code(e, I2CMaster::errorCategory()); } + inline error_condition make_error_condition(I2CMaster::ErrorValue e) { return error_condition(e, I2CMaster::errorCategory()); } } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Links/I2CMasterDecorator.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/I2CMasterDecorator.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,40 +35,39 @@ namespace MaximInterface { error_code I2CMasterDecorator::start(uint_least8_t address) { - return i2c->start(address); + return master->start(address); } -error_code I2CMasterDecorator::stop() { return i2c->stop(); } +error_code I2CMasterDecorator::stop() { return master->stop(); } error_code I2CMasterDecorator::writeByte(uint_least8_t data) { - return i2c->writeByte(data); + return master->writeByte(data); } -error_code I2CMasterDecorator::writeBlock(const uint_least8_t * data, - size_t dataLen) { - return i2c->writeBlock(data, dataLen); +error_code I2CMasterDecorator::writeBlock(span<const uint_least8_t> data) { + return master->writeBlock(data); } error_code I2CMasterDecorator::writePacketImpl(uint_least8_t address, - const uint_least8_t * data, - size_t dataLen, bool sendStop) { - return i2c->writePacket(address, data, dataLen, sendStop); + span<const uint_least8_t> data, + bool sendStop) { + return master->writePacket(address, data, sendStop); } error_code I2CMasterDecorator::readByte(AckStatus status, uint_least8_t & data) { - return i2c->readByte(status, data); + return master->readByte(status, data); } -error_code I2CMasterDecorator::readBlock(AckStatus status, uint_least8_t * data, - size_t dataLen) { - return i2c->readBlock(status, data, dataLen); +error_code I2CMasterDecorator::readBlock(AckStatus status, + span<uint_least8_t> data) { + return master->readBlock(status, data); } error_code I2CMasterDecorator::readPacketImpl(uint_least8_t address, - uint_least8_t * data, - size_t dataLen, bool sendStop) { - return i2c->readPacket(address, data, dataLen, sendStop); + span<uint_least8_t> data, + bool sendStop) { + return master->readPacket(address, data, sendStop); } -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Links/I2CMasterDecorator.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/I2CMasterDecorator.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -40,34 +40,39 @@ class I2CMasterDecorator : public I2CMaster { protected: - explicit I2CMasterDecorator(I2CMaster & i2c) : i2c(&i2c) {} + explicit I2CMasterDecorator(I2CMaster & master) : master(&master) {} public: - void setI2CMaster(I2CMaster & i2c) { this->i2c = &i2c; } + void setMaster(I2CMaster & master) { this->master = &master; } MaximInterface_EXPORT virtual error_code start(uint_least8_t address); + MaximInterface_EXPORT virtual error_code stop(); + MaximInterface_EXPORT virtual error_code writeByte(uint_least8_t data); + MaximInterface_EXPORT virtual error_code - writeBlock(const uint_least8_t * data, size_t dataLen); + writeBlock(span<const uint_least8_t> data); + MaximInterface_EXPORT virtual error_code readByte(AckStatus status, uint_least8_t & data); + MaximInterface_EXPORT virtual error_code - readBlock(AckStatus status, uint_least8_t * data, size_t dataLen); + readBlock(AckStatus status, span<uint_least8_t> data); protected: MaximInterface_EXPORT virtual error_code - writePacketImpl(uint_least8_t address, const uint_least8_t * data, - size_t dataLen, bool sendStop); - MaximInterface_EXPORT virtual error_code readPacketImpl(uint_least8_t address, - uint_least8_t * data, - size_t dataLen, - bool sendStop); + writePacketImpl(uint_least8_t address, span<const uint_least8_t> data, + bool sendStop); + + MaximInterface_EXPORT virtual error_code + readPacketImpl(uint_least8_t address, span<uint_least8_t> data, + bool sendStop); private: - I2CMaster * i2c; + I2CMaster * master; }; } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Links/LoggingI2CMaster.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/LoggingI2CMaster.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -41,14 +41,13 @@ static const char startString[] = "S "; static const char stopString[] = "P"; -static string formatDataString(const uint_least8_t * data, size_t dataSize, - bool read) { +static string formatDataString(span<const uint_least8_t> data, bool read) { string dataBuilder; - for (size_t i = 0; i < dataSize; i++) { + for (span<const uint_least8_t>::index_type i = 0; i < data.size(); ++i) { if (read) { dataBuilder.append(1, '['); } - dataBuilder.append(byteArrayToHexString(data + i, 1)); + dataBuilder.append(byteArrayToHexString(data.subspan(i, 1))); if (read) { dataBuilder.append(1, ']'); } @@ -66,7 +65,7 @@ error_code LoggingI2CMaster::start(uint_least8_t address) { messageBuilder.append(startString); - messageBuilder.append(formatDataString(&address, 1, false)); + messageBuilder.append(formatDataString(make_span(&address, 1), false)); return I2CMasterDecorator::start(address); } @@ -77,25 +76,24 @@ } error_code LoggingI2CMaster::writeByte(uint_least8_t data) { - messageBuilder.append(formatDataString(&data, 1, false)); + messageBuilder.append(formatDataString(make_span(&data, 1), false)); return I2CMasterDecorator::writeByte(data); } -error_code LoggingI2CMaster::writeBlock(const uint_least8_t * data, - size_t dataLen) { - messageBuilder.append(formatDataString(data, dataLen, false)); - return I2CMasterDecorator::writeBlock(data, dataLen); +error_code LoggingI2CMaster::writeBlock(span<const uint_least8_t> data) { + messageBuilder.append(formatDataString(data, false)); + return I2CMasterDecorator::writeBlock(data); } error_code LoggingI2CMaster::writePacketImpl(uint_least8_t address, - const uint_least8_t * data, - size_t dataLen, bool sendStop) { + span<const uint_least8_t> data, + bool sendStop) { messageBuilder.append(startString); - messageBuilder.append(formatDataString(&address, 1, false)); + messageBuilder.append(formatDataString(make_span(&address, 1), false)); error_code result = - I2CMasterDecorator::writePacketImpl(address, data, dataLen, sendStop); + I2CMasterDecorator::writePacketImpl(address, data, sendStop); if (!result) { - messageBuilder.append(formatDataString(data, dataLen, false)); + messageBuilder.append(formatDataString(data, false)); } if (sendStop || result) { messageBuilder.append(stopString); @@ -107,29 +105,29 @@ error_code LoggingI2CMaster::readByte(AckStatus status, uint_least8_t & data) { error_code result = I2CMasterDecorator::readByte(status, data); if (!result) { - messageBuilder.append(formatDataString(&data, 1, true)); + messageBuilder.append(formatDataString(make_span(&data, 1), true)); } return result; } -error_code LoggingI2CMaster::readBlock(AckStatus status, uint_least8_t * data, - size_t dataLen) { - error_code result = I2CMasterDecorator::readBlock(status, data, dataLen); +error_code LoggingI2CMaster::readBlock(AckStatus status, + span<uint_least8_t> data) { + error_code result = I2CMasterDecorator::readBlock(status, data); if (!result) { - messageBuilder.append(formatDataString(data, dataLen, true)); + messageBuilder.append(formatDataString(data, true)); } return result; } error_code LoggingI2CMaster::readPacketImpl(uint_least8_t address, - uint_least8_t * data, - size_t dataLen, bool sendStop) { + span<uint_least8_t> data, + bool sendStop) { messageBuilder.append(startString); - messageBuilder.append(formatDataString(&address, 1, false)); + messageBuilder.append(formatDataString(make_span(&address, 1), false)); error_code result = - I2CMasterDecorator::readPacketImpl(address, data, dataLen, sendStop); + I2CMasterDecorator::readPacketImpl(address, data, sendStop); if (!result) { - messageBuilder.append(formatDataString(data, dataLen, true)); + messageBuilder.append(formatDataString(data, true)); } if (sendStop || result) { messageBuilder.append(stopString); @@ -138,4 +136,4 @@ return result; } -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Links/LoggingI2CMaster.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/LoggingI2CMaster.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -51,23 +51,27 @@ } MaximInterface_EXPORT virtual error_code start(uint_least8_t address); + MaximInterface_EXPORT virtual error_code stop(); + MaximInterface_EXPORT virtual error_code writeByte(uint_least8_t data); + MaximInterface_EXPORT virtual error_code - writeBlock(const uint_least8_t * data, size_t dataLen); + writeBlock(span<const uint_least8_t> data); + MaximInterface_EXPORT virtual error_code readByte(AckStatus status, uint_least8_t & data); MaximInterface_EXPORT virtual error_code - readBlock(AckStatus status, uint_least8_t * data, size_t dataLen); + readBlock(AckStatus status, span<uint_least8_t> data); protected: MaximInterface_EXPORT virtual error_code - writePacketImpl(uint_least8_t address, const uint_least8_t * data, - size_t dataLen, bool sendStop); - MaximInterface_EXPORT virtual error_code readPacketImpl(uint_least8_t address, - uint_least8_t * data, - size_t dataLen, - bool sendStop); + writePacketImpl(uint_least8_t address, span<const uint_least8_t> data, + bool sendStop); + + MaximInterface_EXPORT virtual error_code + readPacketImpl(uint_least8_t address, span<uint_least8_t> data, + bool sendStop); private: void tryWriteMessage(); @@ -78,4 +82,4 @@ } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Links/LoggingOneWireMaster.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/LoggingOneWireMaster.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -39,14 +39,13 @@ static const char strongLevelString[] = "<SP_ON>"; -static string formatDataString(const uint_least8_t * data, size_t dataSize, - bool read) { +static string formatDataString(span<const uint_least8_t> data, bool read) { string dataBuilder; - for (size_t i = 0; i < dataSize; i++) { + for (span<const uint_least8_t>::index_type i = 0; i < data.size(); ++i) { if (read) { dataBuilder.append(1, '['); } - dataBuilder.append(byteArrayToHexString(data + i, 1)); + dataBuilder.append(byteArrayToHexString(data.subspan(i, 1))); if (read) { dataBuilder.append(1, ']'); } @@ -69,7 +68,7 @@ error_code LoggingOneWireMaster::writeByteSetLevel(uint_least8_t sendByte, Level afterLevel) { - tryWriteMessage(formatDataString(&sendByte, 1, false)); + tryWriteMessage(formatDataString(make_span(&sendByte, 1), false)); if (afterLevel == StrongLevel) { tryWriteMessage(strongLevelString); } @@ -81,7 +80,7 @@ error_code result = OneWireMasterDecorator::readByteSetLevel(recvByte, afterLevel); if (!result) { - tryWriteMessage(formatDataString(&recvByte, 1, true)); + tryWriteMessage(formatDataString(make_span(&recvByte, 1), true)); if (afterLevel == StrongLevel) { tryWriteMessage(strongLevelString); } @@ -89,17 +88,15 @@ return result; } -error_code LoggingOneWireMaster::writeBlock(const uint_least8_t * sendBuf, - size_t sendLen) { - tryWriteMessage(formatDataString(sendBuf, sendLen, false)); - return OneWireMasterDecorator::writeBlock(sendBuf, sendLen); +error_code LoggingOneWireMaster::writeBlock(span<const uint_least8_t> sendBuf) { + tryWriteMessage(formatDataString(sendBuf, false)); + return OneWireMasterDecorator::writeBlock(sendBuf); } -error_code LoggingOneWireMaster::readBlock(uint_least8_t * recvBuf, - size_t recvLen) { - error_code result = OneWireMasterDecorator::readBlock(recvBuf, recvLen); +error_code LoggingOneWireMaster::readBlock(span<uint_least8_t> recvBuf) { + error_code result = OneWireMasterDecorator::readBlock(recvBuf); if (!result) { - tryWriteMessage(formatDataString(recvBuf, recvLen, true)); + tryWriteMessage(formatDataString(recvBuf, true)); } return result; } @@ -144,4 +141,4 @@ return result; } -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Links/LoggingOneWireMaster.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/LoggingOneWireMaster.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -52,15 +52,21 @@ } MaximInterface_EXPORT virtual error_code reset(); + MaximInterface_EXPORT virtual error_code writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); + MaximInterface_EXPORT virtual error_code readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterface_EXPORT virtual error_code - writeBlock(const uint_least8_t * sendBuf, size_t sendLen); - MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * recvBuf, - size_t recvLen); + writeBlock(span<const uint_least8_t> sendBuf); + + MaximInterface_EXPORT virtual error_code + readBlock(span<uint_least8_t> recvBuf); + MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed); + MaximInterface_EXPORT virtual error_code setLevel(Level newLevel); private: @@ -71,4 +77,4 @@ } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Links/LoggingSleep.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/LoggingSleep.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,13 +35,13 @@ namespace MaximInterface { -void LoggingSleep::operator()(int ms) const { +void LoggingSleep::invoke(int ms) const { if (writeMessage) { std::ostringstream message; message << "<DELAY" << ms << '>'; writeMessage(message.str()); } - SleepDecorator::operator()(ms); + SleepDecorator::invoke(ms); } } // namespace MaximInterface
--- a/Links/LoggingSleep.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/LoggingSleep.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -41,7 +41,7 @@ class LoggingSleep : public SleepDecorator { public: - LoggingSleep(const Sleep & sleep, + LoggingSleep(Sleep & sleep, const WriteMessage & writeMessage = WriteMessage()) : SleepDecorator(sleep), writeMessage(writeMessage) {} @@ -49,7 +49,7 @@ this->writeMessage = writeMessage; } - MaximInterface_EXPORT virtual void operator()(int ms) const; + MaximInterface_EXPORT virtual void invoke(int ms) const; private: WriteMessage writeMessage; @@ -57,4 +57,4 @@ } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Links/OneWireMaster.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/OneWireMaster.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,14 +35,14 @@ namespace MaximInterface { +static const int maxBitNum = 7; + error_code OneWireMaster::writeByteSetLevel(uint_least8_t sendByte, Level afterLevel) { error_code result; - for (int idx = 0; (idx < 8) && !result; idx++) { - result = writeBit(((sendByte >> idx) & 1) == 1); - } - if (!result) { - result = setLevel(afterLevel); + for (int bitNum = 0; (bitNum <= maxBitNum) && !result; ++bitNum) { + result = writeBitSetLevel(((sendByte >> bitNum) & 1) == 1, + (bitNum == maxBitNum) ? afterLevel : NormalLevel); } return result; } @@ -51,35 +51,34 @@ Level afterLevel) { recvByte = 0; error_code result; - for (int idx = 0; idx < 8; idx++) { + for (int bitNum = 0; bitNum <= maxBitNum; ++bitNum) { bool recvBit; - result = readBit(recvBit); + result = readBitSetLevel(recvBit, + (bitNum == maxBitNum) ? afterLevel : NormalLevel); if (result) { break; } if (recvBit) { - recvByte |= (1 << idx); + recvByte |= (1 << bitNum); } } - if (!result) { - result = setLevel(afterLevel); - } return result; } -error_code OneWireMaster::writeBlock(const uint_least8_t * sendBuf, - size_t sendLen) { +error_code OneWireMaster::writeBlock(span<const uint_least8_t> sendBuf) { error_code result; - for (size_t idx = 0; (idx < sendLen) && !result; idx++) { - result = writeByte(sendBuf[idx]); + for (span<const uint_least8_t>::index_type i = 0; + i < sendBuf.size() && !result; ++i) { + result = writeByte(sendBuf[i]); } return result; } -error_code OneWireMaster::readBlock(uint_least8_t * recvBuf, size_t recvLen) { +error_code OneWireMaster::readBlock(span<uint_least8_t> recvBuf) { error_code result; - for (size_t idx = 0; (idx < recvLen) && !result; idx++) { - result = readByte(recvBuf[idx]); + for (span<uint_least8_t>::index_type i = 0; i < recvBuf.size() && !result; + ++i) { + result = readByte(recvBuf[i]); } return result; }
--- a/Links/OneWireMaster.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/OneWireMaster.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -33,9 +33,9 @@ #ifndef MaximInterface_OneWireMaster #define MaximInterface_OneWireMaster -#include <stddef.h> #include <stdint.h> #include <MaximInterface/Utilities/Export.h> +#include <MaximInterface/Utilities/span.hpp> #include <MaximInterface/Utilities/system_error.hpp> namespace MaximInterface { @@ -65,10 +65,13 @@ virtual ~OneWireMaster() {} + /// @brief /// Reset all of the devices on the 1-Wire bus and check for a presence pulse. - /// @returns NoSlaveError if reset was performed but no presence pulse was detected. + /// @returns + /// NoSlaveError if reset was performed but no presence pulse was detected. virtual error_code reset() = 0; + /// @brief /// Send and receive one bit of communication and set a new level on the /// 1-Wire bus. /// @param[in,out] sendRecvBit @@ -76,29 +79,29 @@ /// @param afterLevel Level to set the 1-Wire bus to after communication. virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel) = 0; + /// @brief /// Send one byte of communication and set a new level on the 1-Wire bus. /// @param sendByte Byte to send on the 1-Wire bus. /// @param afterLevel Level to set the 1-Wire bus to after communication. MaximInterface_EXPORT virtual error_code writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); + /// @brief /// Receive one byte of communication and set a new level on the 1-Wire bus. /// @param recvByte Buffer to receive the data from the 1-Wire bus. /// @param afterLevel Level to set the 1-Wire bus to after communication. MaximInterface_EXPORT virtual error_code readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); - /// Send a block of communication on the 1-Wire bus. + /// @brief Send a block of communication on the 1-Wire bus. /// @param[in] sendBuf Buffer to send on the 1-Wire bus. - /// @param sendLen Length of the buffer to send. MaximInterface_EXPORT virtual error_code - writeBlock(const uint_least8_t * sendBuf, size_t sendLen); + writeBlock(span<const uint_least8_t> sendBuf); - /// Receive a block of communication on the 1-Wire bus. + /// @brief Receive a block of communication on the 1-Wire bus. /// @param[out] recvBuf Buffer to receive the data from the 1-Wire bus. - /// @param recvLen Length of the buffer to receive. - MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * recvBuf, - size_t recvLen); + MaximInterface_EXPORT virtual error_code + readBlock(span<uint_least8_t> recvBuf); /// Set the 1-Wire bus communication speed. virtual error_code setSpeed(Speed newSpeed) = 0; @@ -106,16 +109,17 @@ /// Set the 1-Wire bus level. virtual error_code setLevel(Level newLevel) = 0; - /// 1-Wire Triplet operation. + /// @brief 1-Wire Triplet operation. /// @details Perform one bit of a 1-Wire search. This command /// does two read bits and one write bit. The write bit is either /// the default direction (all devices have same bit) or in case /// of a discrepancy, the data.writeBit parameter is used. - ///@param[in,out] data + /// @param[in,out] data /// Input with desired writeBit in case both read bits are zero. /// Output with all data fields set. MaximInterface_EXPORT virtual error_code triplet(TripletData & data); + /// @brief /// Send one bit of communication and set a new level on the 1-Wire bus. /// @param sendBit Bit to send on the 1-Wire bus. /// @param afterLevel Level to set the 1-Wire bus to after communication. @@ -123,6 +127,7 @@ return touchBitSetLevel(sendBit, afterLevel); } + /// @brief /// Receive one bit of communication and set a new level on the 1-Wire bus. /// @param[out] recvBit Received data from the 1-Wire bus. /// @param afterLevel Level to set the 1-Wire bus to after communication. @@ -132,27 +137,39 @@ } // Alternate forms of the read and write functions. + + error_code touchBit(bool & sendRecvBit) { + return touchBitSetLevel(sendRecvBit, NormalLevel); + } + error_code writeBit(bool sendBit) { return writeBitSetLevel(sendBit, NormalLevel); } + error_code readBit(bool & recvBit) { return readBitSetLevel(recvBit, NormalLevel); } + error_code writeBitPower(bool sendBit) { return writeBitSetLevel(sendBit, StrongLevel); } + error_code readBitPower(bool & recvBit) { return readBitSetLevel(recvBit, StrongLevel); } + error_code writeByte(uint_least8_t sendByte) { return writeByteSetLevel(sendByte, NormalLevel); } + error_code readByte(uint_least8_t & recvByte) { return readByteSetLevel(recvByte, NormalLevel); } + error_code writeBytePower(uint_least8_t sendByte) { return writeByteSetLevel(sendByte, StrongLevel); } + error_code readBytePower(uint_least8_t & recvByte) { return readByteSetLevel(recvByte, StrongLevel); } @@ -163,6 +180,7 @@ inline error_code make_error_code(OneWireMaster::ErrorValue e) { return error_code(e, OneWireMaster::errorCategory()); } + inline error_condition make_error_condition(OneWireMaster::ErrorValue e) { return error_condition(e, OneWireMaster::errorCategory()); }
--- a/Links/OneWireMasterDecorator.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/OneWireMasterDecorator.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -51,14 +51,13 @@ return master->readByteSetLevel(recvByte, afterLevel); } -error_code OneWireMasterDecorator::writeBlock(const uint_least8_t * sendBuf, - size_t sendLen) { - return master->writeBlock(sendBuf, sendLen); +error_code +OneWireMasterDecorator::writeBlock(span<const uint_least8_t> sendBuf) { + return master->writeBlock(sendBuf); } -error_code OneWireMasterDecorator::readBlock(uint_least8_t * recvBuf, - size_t recvLen) { - return master->readBlock(recvBuf, recvLen); +error_code OneWireMasterDecorator::readBlock(span<uint_least8_t> recvBuf) { + return master->readBlock(recvBuf); } error_code OneWireMasterDecorator::setSpeed(Speed newSpeed) { @@ -73,4 +72,4 @@ return master->triplet(data); } -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Links/OneWireMasterDecorator.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/OneWireMasterDecorator.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -43,21 +43,29 @@ explicit OneWireMasterDecorator(OneWireMaster & master) : master(&master) {} public: - void setOneWireMaster(OneWireMaster & master) { this->master = &master; } + void setMaster(OneWireMaster & master) { this->master = &master; } MaximInterface_EXPORT virtual error_code reset(); + MaximInterface_EXPORT virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel); + MaximInterface_EXPORT virtual error_code writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); + MaximInterface_EXPORT virtual error_code readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterface_EXPORT virtual error_code - writeBlock(const uint_least8_t * sendBuf, size_t sendLen); - MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * recvBuf, - size_t recvLen); + writeBlock(span<const uint_least8_t> sendBuf); + + MaximInterface_EXPORT virtual error_code + readBlock(span<uint_least8_t> recvBuf); + MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed); + MaximInterface_EXPORT virtual error_code setLevel(Level newLevel); + MaximInterface_EXPORT virtual error_code triplet(TripletData & data); private: @@ -66,4 +74,4 @@ } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Links/RomCommands.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/RomCommands.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -30,7 +30,6 @@ * ownership rights. *******************************************************************************/ -#include <algorithm> #include "RomCommands.hpp" namespace MaximInterface { @@ -46,114 +45,106 @@ }; void skipCurrentFamily(SearchRomState & searchState) { - // set the Last discrepancy to last family discrepancy + // Set the last discrepancy to last family discrepancy. searchState.lastDiscrepancy = searchState.lastFamilyDiscrepancy; - - // clear the last family discrepancy + // Clear the last family discrepancy. searchState.lastFamilyDiscrepancy = 0; - - // check for end of list + // Check for end of list. if (searchState.lastDiscrepancy == 0) { searchState.lastDevice = true; } } -error_code verifyRom(OneWireMaster & master, const RomId & romId) { +error_code verifyRom(OneWireMaster & master, RomId::const_span romId) { SearchRomState searchState(romId); error_code result = searchRom(master, searchState); - if (!result) { - // check if same device found - if (romId != searchState.romId) { - result = make_error_code(OneWireMaster::NoSlaveError); - } + if (result) { + return result; + } + // Check if same device found. + if (romId != make_span(searchState.romId)) { + result = make_error_code(OneWireMaster::NoSlaveError); } return result; } -error_code readRom(OneWireMaster & master, RomId & romId) { +error_code readRom(OneWireMaster & master, RomId::span romId) { error_code result = master.reset(); - if (!result) { - result = master.writeByte(ReadRomCmd); - } - - // read the ROM - RomId readId; - if (!result) { - result = master.readBlock(readId.data(), readId.size()); + if (result) { + return result; } - - // verify CRC8 - if (!result) { - if (valid(readId)) { - romId = readId; - } else { - result = make_error_code(OneWireMaster::NoSlaveError); - } + result = master.writeByte(ReadRomCmd); + if (result) { + return result; } - + result = master.readBlock(romId); + if (result) { + return result; + } + if (!valid(romId)) { + result = make_error_code(OneWireMaster::NoSlaveError); + } return result; } error_code skipRom(OneWireMaster & master) { error_code result = master.reset(); - if (!result) { - result = master.writeByte(SkipRomCmd); + if (result) { + return result; } + result = master.writeByte(SkipRomCmd); return result; } -error_code matchRom(OneWireMaster & master, const RomId & romId) { - // use MatchROM +error_code matchRom(OneWireMaster & master, RomId::const_span romId) { error_code result = master.reset(); - if (!result) { - uint_least8_t buf[1 + RomId::csize]; - buf[0] = MatchRomCmd; - std::copy(romId.begin(), romId.end(), buf + 1); - // send command and rom - result = master.writeBlock(buf, sizeof(buf) / sizeof(buf[0])); + if (result) { + return result; } + result = master.writeByte(MatchRomCmd); + if (result) { + return result; + } + result = master.writeBlock(romId); return result; } error_code overdriveSkipRom(OneWireMaster & master) { - error_code result = master.setSpeed(OneWireMaster::StandardSpeed); - - if (!result) { - result = master.reset(); + error_code result = master.reset(); + if (result) { + return result; } - - if (!result) { - result = master.writeByte(OverdriveSkipRomCmd); + result = master.writeByte(OverdriveSkipRomCmd); + if (result) { + return result; } - - if (!result) { - result = master.setSpeed(OneWireMaster::OverdriveSpeed); - } - + result = master.setSpeed(OneWireMaster::OverdriveSpeed); return result; } -error_code overdriveMatchRom(OneWireMaster & master, const RomId & romId) { - // use overdrive MatchROM - master.setSpeed(OneWireMaster::StandardSpeed); - +error_code overdriveMatchRom(OneWireMaster & master, RomId::const_span romId) { error_code result = master.reset(); - if (!result) { - result = master.writeByte(OverdriveMatchRomCmd); - if (!result) { - master.setSpeed(OneWireMaster::OverdriveSpeed); - // send ROM - result = master.writeBlock(romId.data(), romId.size()); - } + if (result) { + return result; } + result = master.writeByte(OverdriveMatchRomCmd); + if (result) { + return result; + } + result = master.setSpeed(OneWireMaster::OverdriveSpeed); + if (result) { + return result; + } + result = master.writeBlock(romId); return result; } error_code resumeRom(OneWireMaster & master) { error_code result = master.reset(); - if (!result) { - result = master.writeByte(ResumeRomCmd); + if (result) { + return result; } + result = master.writeByte(ResumeRomCmd); return result; } @@ -171,20 +162,20 @@ return result; } - SearchRomState newSearchState = searchState; - for (int idBitNumber = 1; idBitNumber <= 64; idBitNumber++) { + SearchRomState newSearchState; + newSearchState.lastFamilyDiscrepancy = searchState.lastFamilyDiscrepancy; + for (int idBitNumber = 1; idBitNumber <= 64; ++idBitNumber) { const int idByteNumber = (idBitNumber - 1) / 8; const unsigned int idBitMask = 1 << ((idBitNumber - 1) % 8); OneWireMaster::TripletData tripletData; - if (idBitNumber == newSearchState.lastDiscrepancy) { + if (idBitNumber == searchState.lastDiscrepancy) { tripletData.writeBit = 1; - } else if (idBitNumber > newSearchState.lastDiscrepancy) { + } else if (idBitNumber > searchState.lastDiscrepancy) { tripletData.writeBit = 0; - } else // idBitNumber < searchState.lastDiscrepancy - { + } else { // idBitNumber < searchState.lastDiscrepancy tripletData.writeBit = - (newSearchState.romId[idByteNumber] & idBitMask) == idBitMask; + (searchState.romId[idByteNumber] & idBitMask) == idBitMask; } result = master.triplet(tripletData); @@ -197,19 +188,16 @@ if (tripletData.writeBit) { newSearchState.romId[idByteNumber] |= idBitMask; - } else { - newSearchState.romId[idByteNumber] &= ~idBitMask; - if (!tripletData.readBit && !tripletData.readBitComplement) { - newSearchState.lastDiscrepancy = idBitNumber; - if (idBitNumber <= 8) { - newSearchState.lastFamilyDiscrepancy = idBitNumber; - } + } else if (!tripletData.readBit && !tripletData.readBitComplement) { + newSearchState.lastDiscrepancy = idBitNumber; + if (idBitNumber <= 8) { + newSearchState.lastFamilyDiscrepancy = idBitNumber; } } } if (valid(newSearchState.romId)) { - if (newSearchState.lastDiscrepancy == searchState.lastDiscrepancy) { + if (newSearchState.lastDiscrepancy == 0) { newSearchState.lastDevice = true; } searchState = newSearchState;
--- a/Links/RomCommands.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/RomCommands.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -30,7 +30,8 @@ * ownership rights. *******************************************************************************/ -/// @file ROM Commands for enumerating and selecting 1-Wire devices. +/// @file +/// @brief ROM Commands for enumerating and selecting 1-Wire devices. #ifndef MaximInterface_RomCommands #define MaximInterface_RomCommands @@ -44,7 +45,7 @@ /// State used by Search ROM command. struct SearchRomState { - RomId romId; + RomId::array romId; int_least8_t lastDiscrepancy; int_least8_t lastFamilyDiscrepancy; bool lastDevice; @@ -53,61 +54,74 @@ : romId(), lastDiscrepancy(0), lastFamilyDiscrepancy(0), lastDevice(false) {} - explicit SearchRomState(const RomId & romId) - : romId(romId), lastDiscrepancy(64), lastFamilyDiscrepancy(0), - lastDevice(false) {} + explicit SearchRomState(RomId::const_span romId) + : lastDiscrepancy(64), lastFamilyDiscrepancy(0), lastDevice(false) { + copy(romId, make_span(this->romId)); + } - explicit SearchRomState(RomId::value_type familyCode) + explicit SearchRomState(RomId::element familyCode) : romId(), lastDiscrepancy(64), lastFamilyDiscrepancy(0), lastDevice(false) { setFamilyCode(romId, familyCode); } }; +/// @brief /// Set the search state to skip the current device family on the next /// Search ROM command. MaximInterface_EXPORT void skipCurrentFamily(SearchRomState & searchState); /// Verify that the device with the specified ROM ID is present. MaximInterface_EXPORT error_code verifyRom(OneWireMaster & master, - const RomId & romId); + RomId::const_span romId); -/// Use Read ROM command to read ROM ID from device on bus. -/// @note Only use this command with a single drop bus, data -/// collisions will occur if more than 1 device on bus. +/// @brief Use Read ROM command to read ROM ID from device on bus. +/// @note +/// Only use this command with a single-drop bus. +/// Data collisions will occur if there is more than one device on the bus. +/// @param master 1-Wire master for operation. /// @param[out] romId ROM ID read from device. -MaximInterface_EXPORT error_code readRom(OneWireMaster & master, RomId & romId); +MaximInterface_EXPORT error_code readRom(OneWireMaster & master, + RomId::span romId); -/// Issue Skip ROM command on bus. -/// @note Only use this command with a single drop bus, data -/// collisions will occur if more than 1 device on bus. +/// @brief Issue Skip ROM command on bus. +/// @note +/// Only use this command with a single-drop bus. +/// Data collisions will occur if there is more than one device on the bus. MaximInterface_EXPORT error_code skipRom(OneWireMaster & master); -/// Use the Match ROM command to select the device by its known ID. -/// @note This command causes all devices supporting Overdrive -/// mode to switch to Overdrive timing. +/// @brief Use the Match ROM command to select the device by its known ID. +/// @note +/// This command causes all devices supporting Overdrive mode to switch to +/// Overdrive timing. +/// @param master 1-Wire master for operation. /// @param[in] romId ROM ID of device to select. MaximInterface_EXPORT error_code matchRom(OneWireMaster & master, - const RomId & romId); + RomId::const_span romId); -/// Issue Overdrive Skip ROM command on bus. -/// @note This command causes all devices supporting Overdrive -/// mode to switch to Overdrive timing. -/// @note Only use this command with a single drop bus, data -/// collisions will occur if more than 1 device on bus. +/// @brief Issue Overdrive Skip ROM command on bus. +/// @note +/// This command causes all devices supporting Overdrive mode to switch to +/// Overdrive timing. +/// @note +/// Only use this command with a single-drop bus. +/// Data collisions will occur if there is more than one device on the bus. MaximInterface_EXPORT error_code overdriveSkipRom(OneWireMaster & master); +/// @brief /// Use the Overdrive Match ROM command to select the device by its known ID. +/// @param master 1-Wire master for operation. /// @param[in] romId ROM ID of device to select. MaximInterface_EXPORT error_code overdriveMatchRom(OneWireMaster & master, - const RomId & romId); + RomId::const_span romId); -/// Perform a Resume ROM command on bus. -/// @details Resumes communication with the last device selected -/// though a Match ROM or Search ROM operation. +/// @brief Perform a Resume ROM command on bus. +/// @details +/// Resumes communication with the last device selected through a Match ROM or +/// Search ROM operation. MaximInterface_EXPORT error_code resumeRom(OneWireMaster & master); -/// Find device on the 1-Wire bus. +/// @brief Find device on the 1-Wire bus. /// @details /// This command uses the Search ROM command to enumerate all 1-Wire devices in /// sequence. Begin with a new search state and continue using the same search
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Links/RunCommand.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -0,0 +1,210 @@ +/******************************************************************************* +* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#include <MaximInterface/Utilities/crc.hpp> +#include <MaximInterface/Utilities/Error.hpp> +#include "I2CMaster.hpp" +#include "OneWireMaster.hpp" +#include "Sleep.hpp" +#include "RunCommand.hpp" + +namespace MaximInterface { + +const error_category & RunCommandWithOneWireMaster::errorCategory() { + static class : public error_category { + public: + virtual const char * name() const { return "RunCommandWithOneWireMaster"; } + + virtual std::string message(int condition) const { + switch (condition) { + case CrcError: + return "CRC Error"; + + case InvalidResponseError: + return "Invalid Response Error"; + } + return defaultErrorMessage(condition); + } + } instance; + return instance; +} + +error_code RunCommandWithOneWireMaster:: +operator()(span<const uint_least8_t> command, int delayTime, + span<uint_least8_t> & response) const { + // Write command. + error_code result = selectRom(*master); + if (result) { + return result; + } + uint_least8_t xpcBuffer[2] = {0x66, + static_cast<uint_least8_t>(command.size())}; + result = master->writeBlock(xpcBuffer); + if (result) { + return result; + } + result = master->writeBlock(command); + if (result) { + return result; + } + uint_fast16_t expectedCrc = + calculateCrc16(command, calculateCrc16(xpcBuffer)) ^ 0xFFFFU; + result = master->readBlock(xpcBuffer); + if (result) { + return result; + } + if (expectedCrc != + ((static_cast<uint_fast16_t>(xpcBuffer[1]) << 8) | xpcBuffer[0])) { + return make_error_code(CrcError); + } + result = master->writeBytePower(0xAA); + if (result) { + return result; + } + + // Wait for device to process. + sleep->invoke(delayTime); + + // Read response. + result = master->setLevel(OneWireMaster::NormalLevel); + if (result) { + return result; + } + result = master->readBlock(xpcBuffer); + if (result) { + return result; + } + if (xpcBuffer[1] > response.size()) { + return make_error_code(InvalidResponseError); + } + response = response.first(xpcBuffer[1]); + result = master->readBlock(response); + if (result) { + return result; + } + expectedCrc = + calculateCrc16(response, calculateCrc16(make_span(xpcBuffer + 1, 1))) ^ + 0xFFFFU; + result = master->readBlock(xpcBuffer); + if (result) { + return result; + } + if (expectedCrc != + ((static_cast<uint_fast16_t>(xpcBuffer[1]) << 8) | xpcBuffer[0])) { + return make_error_code(CrcError); + } + return result; +} + +const error_category & RunCommandWithI2CMaster::errorCategory() { + static class : public error_category { + public: + virtual const char * name() const { return "RunCommandWithI2CMaster"; } + + virtual std::string message(int condition) const { + switch (condition) { + case InvalidResponseError: + return "Invalid Response Error"; + } + return defaultErrorMessage(condition); + } + } instance; + return instance; +} + +error_code RunCommandWithI2CMaster:: +operator()(span<const uint_least8_t> command, int delayTime, + span<uint_least8_t> & response) const { + // Write command. + error_code result = master->start(address_); + if (result == make_error_condition(I2CMaster::NackError) && address_ != 0) { + result = master->start(0); + } + if (result) { + master->stop(); + return result; + } + if (!command.empty()) { + result = master->writeByte(command[0]); + if (result) { + master->stop(); + return result; + } + command = command.subspan(1); + if (!command.empty()) { + result = master->writeByte(command.size()); + if (result) { + master->stop(); + return result; + } + result = master->writeBlock(command); + if (result) { + master->stop(); + return result; + } + } + } + result = master->stop(); + if (result) { + return result; + } + + // Wait for device to process. + sleep->invoke(delayTime); + + // Read response. + result = master->start(address_ | 1); + if (result) { + master->stop(); + return result; + } + uint_least8_t length; + result = master->readByte(I2CMaster::Ack, length); + if (result) { + master->stop(); + return result; + } + if (length > response.size()) { + master->stop(); + return make_error_code(InvalidResponseError); + } + response = response.first(length); + result = master->readBlock(I2CMaster::Nack, response); + if (result) { + master->stop(); + return result; + } + result = master->stop(); + return result; +} + +} // namespace MaximInterface
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Links/RunCommand.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -0,0 +1,120 @@ +/******************************************************************************* +* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#ifndef MaximInterface_RunCommand +#define MaximInterface_RunCommand + +#include <MaximInterface/Utilities/Export.h> +#include <MaximInterface/Utilities/Function.hpp> +#include <MaximInterface/Utilities/span.hpp> +#include <MaximInterface/Utilities/system_error.hpp> +#include "SelectRom.hpp" + +namespace MaximInterface { + +class I2CMaster; +class OneWireMaster; +class Sleep; + +typedef Function<error_code(span<const uint_least8_t>, int, + span<uint_least8_t> &)> + RunCommand; + +class RunCommandWithOneWireMaster { +public: + typedef RunCommand::result_type result_type; + + enum ErrorValue { CrcError = 1, InvalidResponseError }; + MaximInterface_EXPORT static const error_category & errorCategory(); + + RunCommandWithOneWireMaster(Sleep & sleep, OneWireMaster & master, + const SelectRom & selectRom) + : selectRom(selectRom), master(&master), sleep(&sleep) {} + + void setSleep(Sleep & sleep) { this->sleep = &sleep; } + + void setMaster(OneWireMaster & master) { this->master = &master; } + + void setSelectRom(const SelectRom & selectRom) { + this->selectRom = selectRom; + } + + MaximInterface_EXPORT error_code + operator()(span<const uint_least8_t> command, int delayTime, + span<uint_least8_t> & response) const; + +private: + SelectRom selectRom; + OneWireMaster * master; + const Sleep * sleep; +}; + +inline error_code make_error_code(RunCommandWithOneWireMaster::ErrorValue e) { + return error_code(e, RunCommandWithOneWireMaster::errorCategory()); +} + +class RunCommandWithI2CMaster { +public: + typedef RunCommand::result_type result_type; + + enum ErrorValue { InvalidResponseError = 1 }; + MaximInterface_EXPORT static const error_category & errorCategory(); + + RunCommandWithI2CMaster(Sleep & sleep, I2CMaster & master, + uint_least8_t address) + : sleep(&sleep), master(&master), address_(address & 0xFE) {} + + void setSleep(Sleep & sleep) { this->sleep = &sleep; } + + void setMaster(I2CMaster & master) { this->master = &master; } + + uint_least8_t address() const { return address_; } + + void setAddress(uint_least8_t address) { address_ = address & 0xFE; } + + MaximInterface_EXPORT error_code + operator()(span<const uint_least8_t> command, int delayTime, + span<uint_least8_t> & response) const; + +private: + const Sleep * sleep; + I2CMaster * master; + uint_least8_t address_; +}; + +inline error_code make_error_code(RunCommandWithI2CMaster::ErrorValue e) { + return error_code(e, RunCommandWithI2CMaster::errorCategory()); +} + +} // namespace MaximInterface + +#endif
--- a/Links/SelectRom.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/SelectRom.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -40,11 +40,11 @@ error_code SelectMatchRomWithResume::operator()(OneWireMaster & master) const { error_code result; - if (romId_ == data->lastRom) { + if (romId_ == data->lastRomId) { result = resumeRom(master); } else { result = matchRom(master, romId_); - data->lastRom = romId_; + data->lastRomId = romId_; } return result; }
--- a/Links/SelectRom.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/SelectRom.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -43,6 +43,7 @@ class OneWireMaster; +/// Selects a 1-Wire device on the bus for communication. typedef Function<error_code(OneWireMaster &)> SelectRom; typedef Function<error_code(OneWireMaster &, const RomId & romId)> SelectRomExt; @@ -52,41 +53,47 @@ typedef SelectRom::argument_type argument_type; typedef SelectRom::result_type result_type; - explicit SelectMatchRom(const RomId & romId = RomId()) : romId_(romId) {} + explicit SelectMatchRom(RomId::const_span romId) { setRomId(romId); } - const RomId & romId() const { return romId_; } - void setRomId(const RomId & romId) { romId_ = romId; } + RomId::const_span romId() const { return romId_; } + + void setRomId(RomId::const_span romId) { copy(romId, make_span(romId_)); } MaximInterface_EXPORT error_code operator()(OneWireMaster & master) const; private: - RomId romId_; + RomId::array romId_; }; -/// Selector for a multidrop 1-Wire bus where slaves support the Resume ROM command. +/// @brief +/// Selector for a multidrop 1-Wire bus where slaves support the Resume ROM +/// command. class SelectMatchRomWithResume { public: typedef SelectRom::argument_type argument_type; typedef SelectRom::result_type result_type; struct SharedData { - RomId lastRom; - - SharedData() : lastRom() {} + SharedData() : lastRomId() {} + RomId::array lastRomId; }; - explicit SelectMatchRomWithResume(SharedData & data, - const RomId & romId = RomId()) - : romId_(romId), data(&data) {} + SelectMatchRomWithResume(SharedData & data, RomId::const_span romId) + : data(&data) { + setRomId(romId); + } - const RomId & romId() const { return romId_; } - void setRomId(const RomId & romId) { romId_ = romId; } + void setSharedData(SharedData & data) { this->data = &data; } + + RomId::const_span romId() const { return romId_; } + + void setRomId(RomId::const_span romId) { copy(romId, make_span(romId_)); } MaximInterface_EXPORT error_code operator()(OneWireMaster & master) const; private: - RomId romId_; SharedData * data; + RomId::array romId_; }; } // namespace MaximInterface
--- a/Links/SerialPort.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/SerialPort.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -46,7 +46,7 @@ /// Disconnect from the current port. virtual error_code disconnect() = 0; - /// Check if currently connected to a port. + /// @brief Check if currently connected to a port. /// @returns True if connected. virtual bool connected() const = 0; @@ -56,4 +56,4 @@ } -#endif \ No newline at end of file +#endif
--- a/Links/Sleep.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/Sleep.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -38,10 +38,10 @@ class Sleep { public: virtual ~Sleep() {} - - virtual void operator()(int ms) const = 0; + virtual void invoke(int ms) const = 0; + void operator()(int ms) const { invoke(ms); } }; } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Links/SleepDecorator.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/SleepDecorator.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -34,6 +34,6 @@ namespace MaximInterface { -void SleepDecorator::operator()(int ms) const { (*sleep)(ms); } +void SleepDecorator::invoke(int ms) const { sleep->invoke(ms); } -} \ No newline at end of file +}
--- a/Links/SleepDecorator.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/SleepDecorator.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -40,11 +40,11 @@ class SleepDecorator : public Sleep { protected: - explicit SleepDecorator(const Sleep & sleep) : sleep(&sleep) {} + explicit SleepDecorator(Sleep & sleep) : sleep(&sleep) {} public: - void setSleep(const Sleep & sleep) { this->sleep = &sleep; } - MaximInterface_EXPORT virtual void operator()(int ms) const; + void setSleep(Sleep & sleep) { this->sleep = &sleep; } + MaximInterface_EXPORT virtual void invoke(int ms) const; private: const Sleep * sleep; @@ -52,4 +52,4 @@ } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Links/Uart.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/Uart.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,17 +35,18 @@ namespace MaximInterface { -error_code Uart::writeBlock(const uint_least8_t * data, size_t dataLen) { +error_code Uart::writeBlock(span<const uint_least8_t> data) { error_code result; - for (size_t i = 0; i < dataLen && !result; i++) { + for (span<const uint_least8_t>::index_type i = 0; + i < data.size() && !result; ++i) { result = writeByte(data[i]); } return result; } -error_code Uart::readBlock(uint_least8_t * data, size_t dataLen) { +error_code Uart::readBlock(span<uint_least8_t> data) { error_code result; - for (size_t i = 0; i < dataLen && !result; i++) { + for (span<uint_least8_t>::index_type i = 0; i < data.size() && !result; ++i) { result = readByte(data[i]); } return result; @@ -72,4 +73,4 @@ return instance; } -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Links/Uart.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Links/Uart.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -34,9 +34,8 @@ #define MaximInterface_Uart #include <stdint.h> -#include <stddef.h> - #include <MaximInterface/Utilities/Export.h> +#include <MaximInterface/Utilities/span.hpp> #include <MaximInterface/Utilities/system_error.hpp> namespace MaximInterface { @@ -65,19 +64,19 @@ /// Writes a block of data to the port. MaximInterface_EXPORT virtual error_code - writeBlock(const uint_least8_t * data, size_t dataLen); + writeBlock(span<const uint_least8_t> data); + /// @brief /// Reads a byte of data from the port. Block until data is received or a /// timeout is reached. /// @param[out] data Data read from the port if successful. virtual error_code readByte(uint_least8_t & data) = 0; + /// @brief /// Read a block of data from the port. Block until data is received or a /// timeout is reached. /// @param[out] data Data read from the port if successful. - /// @para dataLen Number of bytes to read and length of data. - MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * data, - size_t dataLen); + MaximInterface_EXPORT virtual error_code readBlock(span<uint_least8_t> data); MaximInterface_EXPORT static const error_category & errorCategory(); }; @@ -85,10 +84,11 @@ inline error_code make_error_code(Uart::ErrorValue e) { return error_code(e, Uart::errorCategory()); } + inline error_condition make_error_condition(Uart::ErrorValue e) { return error_condition(e, Uart::errorCategory()); } } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Platforms/Qt/.mbedignore Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -* \ No newline at end of file
--- a/Platforms/Qt/SerialPort.cpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include <QSerialPortInfo> -#include <MaximInterface/Utilities/Error.hpp> -#include "SerialPort.hpp" -#include "Sleep.hpp" - -using std::string; - -namespace MaximInterface { -namespace Qt { - -static_assert(QSerialPort::NoError == 0, "Remapping required for error_code."); - -error_code SerialPort::connect(const string & portName) { - port.setPort(QSerialPortInfo(QString::fromStdString(portName))); - auto result = port.open(QSerialPort::ReadWrite) - ? error_code() - : make_error_code(port.error()); - if (result) { - return result; - } - result = port.setDataTerminalReady(true) ? error_code() - : make_error_code(port.error()); - if (result) { - port.close(); - } - return result; -} - -error_code SerialPort::disconnect() { - port.close(); - return error_code(); -} - -bool SerialPort::connected() const { return port.isOpen(); } - -string SerialPort::portName() const { return port.portName().toStdString(); } - -error_code SerialPort::setBaudRate(int_least32_t baudRate) { - return port.setBaudRate(baudRate) ? error_code() - : make_error_code(port.error()); -} - -error_code SerialPort::sendBreak() { - auto result = - port.setBreakEnabled(true) ? error_code() : make_error_code(port.error()); - if (!result) { - sleep(1); - result = port.setBreakEnabled(false) ? error_code() - : make_error_code(port.error()); - } - return result; -} - -error_code SerialPort::clearReadBuffer() { - port.readAll(); - return error_code(); -} - -error_code SerialPort::writeByte(uint_least8_t data) { - auto result = - port.putChar(data) ? error_code() : make_error_code(port.error()); - if (!result) { - result = port.waitForBytesWritten(1000) ? error_code() - : make_error_code(port.error()); - } - return result; -} - -error_code SerialPort::readByte(uint_least8_t & data) { - if (port.atEnd()) { - const auto result = port.waitForReadyRead(1000) - ? error_code() - : make_error_code(port.error()); - if (result) { - return result; - } - } - return port.getChar(reinterpret_cast<char *>(&data)) - ? error_code() - : make_error_code(port.error()); -} - -const error_category & SerialPort::errorCategory() { - static class : public error_category { - public: - virtual const char * name() const override { return "Qt SerialPort"; } - - virtual string message(int condition) const override { - switch (condition) { - case QSerialPort::DeviceNotFoundError: - return "Device Not Found"; - - case QSerialPort::PermissionError: - return "Permission Error"; - - case QSerialPort::OpenError: - return "Open Error"; - - case QSerialPort::NotOpenError: - return "Not Open Error"; - - case QSerialPort::WriteError: - return "Write Error"; - - case QSerialPort::ReadError: - return "Read Error"; - - case QSerialPort::ResourceError: - return "Resource Error"; - - case QSerialPort::UnsupportedOperationError: - return "Unsupported Operation Error"; - - case QSerialPort::TimeoutError: - return "Timeout Error"; - - default: - return defaultErrorMessage(condition); - } - } - - // Make QSerialPort::TimeoutError equivalent to Uart::TimeoutError. - virtual bool equivalent(int code, - const error_condition & condition) const override { - return (code == QSerialPort::TimeoutError) - ? (condition == make_error_condition(Uart::TimeoutError)) - : error_category::equivalent(code, condition); - } - } instance; - return instance; -} - -} // namespace Qt -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/Qt/SerialPort.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include <QSerialPort> -#include <MaximInterface/Links/SerialPort.hpp> -#include <MaximInterface/Utilities/Export.h> - -namespace MaximInterface { -namespace Qt { - -class SerialPort : public MaximInterface::SerialPort { -public: - MaximInterface_EXPORT virtual error_code - connect(const std::string & portName) override; - MaximInterface_EXPORT virtual error_code disconnect() override; - MaximInterface_EXPORT virtual bool connected() const override; - MaximInterface_EXPORT virtual std::string portName() const override; - - MaximInterface_EXPORT virtual error_code - setBaudRate(int_least32_t baudRate) override; - MaximInterface_EXPORT virtual error_code sendBreak() override; - MaximInterface_EXPORT virtual error_code clearReadBuffer() override; - MaximInterface_EXPORT virtual error_code - writeByte(uint_least8_t data) override; - MaximInterface_EXPORT virtual error_code - readByte(uint_least8_t & data) override; - - MaximInterface_EXPORT static const error_category & errorCategory(); - -private: - QSerialPort port; -}; - -inline error_code make_error_code(QSerialPort::SerialPortError e) { - return error_code(e, SerialPort::errorCategory()); -} - -} // namespace Qt -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/Qt/Sleep.cpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include <QThread> -#include "SerialPort.hpp" -#include "Sleep.hpp" - -namespace MaximInterface { -namespace Qt { - -void sleep(const int ms) { - QThread::msleep(ms); -} - -Sleep & Sleep::instance() { - static Sleep instance; - return instance; -} - -void Sleep::operator()(int ms) const { sleep(ms); } - -} // namespace Qt -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/Qt/Sleep.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#ifndef MaximInterface_Qt_SerialPort -#define MaximInterface_Qt_SerialPort - -#include <MaximInterface/Links/Sleep.hpp> -#include <MaximInterface/Utilities/Export.h> -#include <MaximInterface/Utilities/Uncopyable.hpp> - -namespace MaximInterface { -namespace Qt { - -MaximInterface_EXPORT void sleep(int ms); - -class Sleep : public MaximInterface::Sleep, private Uncopyable { -public: - MaximInterface_EXPORT static Sleep & instance(); - - MaximInterface_EXPORT virtual void operator()(int ms) const override; - -private: - Sleep() = default; -}; - -} // namespace Qt -} // namespace MaximInterface - -#endif \ No newline at end of file
--- a/Platforms/dotnet/.mbedignore Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -* \ No newline at end of file
--- a/Platforms/dotnet/ChangeSizeType.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#pragma once - -#include <algorithm> -#include <limits> -#include <type_traits> - -namespace MaximInterface { - -/// Adapts functions taking a data pointer and data size where the size type is -/// not size_t. The function will be called multiple times if necessary to -/// process all data. -template <typename NewSize, typename Func, typename Data> -void changeSizeType(Func func, Data data, size_t dataSize) { - using namespace std; - - // Check if NewSize can represent the maximum value of dataSize. - if (numeric_limits<decltype(dataSize)>::max() > - static_cast<make_unsigned_t<NewSize>>(numeric_limits<NewSize>::max())) { - do { - const auto chunkSize = - min<decltype(dataSize)>(dataSize, numeric_limits<NewSize>::max()); - func(data, static_cast<NewSize>(chunkSize)); - data += chunkSize; - dataSize -= chunkSize; - } while (dataSize > 0); - } else { - func(data, static_cast<NewSize>(dataSize)); - } -} - -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/dotnet/DelegateWrapper.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#pragma once - -#include <msclr/marshal_cppstd.h> -#include <vcclr.h> - -namespace MaximInterface { -namespace detail { - -template <typename DelegateT> class DelegateWrapperBase { -public: - using Delegate = DelegateT; - -protected: - DelegateWrapperBase(Delegate ^ target) : target_(target) {} - ~DelegateWrapperBase() = default; - -public: - Delegate ^ target() const { return static_cast<Delegate ^>(target_); } - void setTarget(Delegate ^ target) { target_ = target; } - void swap(DelegateWrapperBase & other) { target_.swap(other.target_); } - explicit operator bool() const { return target() != nullptr; } - -private: - gcroot<Delegate ^> target_; -}; - -template <typename DelegateT> -inline void swap(DelegateWrapperBase<DelegateT> & lhs, - DelegateWrapperBase<DelegateT> & rhs) { - lhs.swap(rhs); -} - -template <typename R, typename... Args> -class DelegateWrapperImpl - : public DelegateWrapperBase<System::Func<Args..., R> > { -protected: - DelegateWrapperImpl(Delegate ^ target) : DelegateWrapperBase(target) {} - -public: - R operator()(Args... args) { return target()(args...); } -}; - -template <typename... Args> -class DelegateWrapperImpl<void, Args...> - : public DelegateWrapperBase<System::Action<Args...> > { -protected: - DelegateWrapperImpl(Delegate ^ target) : DelegateWrapperBase(target) {} - -public: - void operator()(Args... args) const { target()(args...); } -}; - -} // namespace detail - -/// @{ -/// Functor wrapper for .NET delegates. -template <typename> class DelegateWrapper; - -template <typename R, typename... Args> -class DelegateWrapper<R(Args...)> - : public detail::DelegateWrapperImpl<R, Args...> { -public: - DelegateWrapper(Delegate ^ target = nullptr) : DelegateWrapperImpl(target) {} -}; - -template <typename R, typename... Args> -class DelegateWrapper<R __clrcall(Args...)> - : public detail::DelegateWrapperImpl<R, Args...> { -public: - DelegateWrapper(Delegate ^ target = nullptr) : DelegateWrapperImpl(target) {} -}; -/// @} - -/// Wrapper for using a .NET delegate as a MaximInterface::WriteMessage. -class WriteMessageDelegateWrapper - : public DelegateWrapper<void(System::String ^)> { -public: - WriteMessageDelegateWrapper(Delegate ^ target = nullptr) - : DelegateWrapper(target) {} - - void operator()(const std::string & arg) const { - target()(msclr::interop::marshal_as<System::String ^>(arg)); - } -}; - -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/dotnet/MoveOnly.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#ifndef MaximInterface_MoveOnly -#define MaximInterface_MoveOnly - -namespace MaximInterface { - -class MoveOnly { -protected: - MoveOnly() = default; - ~MoveOnly() = default; - - MoveOnly(const MoveOnly &) = delete; - MoveOnly(MoveOnly &&) = default; - const MoveOnly & operator=(const MoveOnly &) = delete; - MoveOnly & operator=(MoveOnly &&) = default; -}; - -} // namespace MaximInterface - -#endif \ No newline at end of file
--- a/Platforms/dotnet/OneWireLinkLayerMaster.cpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,337 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include <stdexcept> -#include <msclr/auto_gcroot.h> -#include <msclr/marshal_cppstd.h> -#include <MaximInterface/Utilities/Error.hpp> -#include "ChangeSizeType.hpp" -#include "OneWireLinkLayerMaster.hpp" - -using DalSemi::OneWire::Adapter::AdapterException; -using System::IntPtr; -using System::Runtime::InteropServices::Marshal; -using System::String; -using msclr::interop::marshal_as; -using std::string; - -namespace MaximInterface { - -struct OneWireLinkLayerMaster::Data { - msclr::auto_gcroot<DalSemi::OneWire::Adapter::PortAdapter ^> adapter; - bool connected = false; -}; - -OneWireLinkLayerMaster::OneWireLinkLayerMaster(const string & adapterName) - : data(std::make_unique<Data>()) { - try { - data->adapter = DalSemi::OneWire::AccessProvider::GetAdapter( - marshal_as<String ^>(adapterName)); - } catch (AdapterException ^ e) { - throw std::invalid_argument(marshal_as<string>(e->Message)); - } -} - -OneWireLinkLayerMaster::~OneWireLinkLayerMaster() = default; - -OneWireLinkLayerMaster::OneWireLinkLayerMaster( - OneWireLinkLayerMaster && rhs) noexcept = default; - -OneWireLinkLayerMaster & OneWireLinkLayerMaster:: -operator=(OneWireLinkLayerMaster && rhs) noexcept = default; - -error_code OneWireLinkLayerMaster::connect(const string & portName) { - if (connected()) { - return make_error_code(AlreadyConnectedError); - } - - error_code result; - try { - auto adapterResult = - data->adapter->OpenPort(marshal_as<String ^>(portName)); - if (adapterResult) { - adapterResult = data->adapter->BeginExclusive(true); - if (adapterResult) { - data->connected = true; - } else { - data->adapter->FreePort(); - result = make_error_code(OpenPortError); - } - } else { - result = make_error_code(OpenPortError); - } - } catch (AdapterException ^) { - result = make_error_code(CommunicationError); - } - return result; -} - -void OneWireLinkLayerMaster::disconnect() { - data->adapter->EndExclusive(); - data->adapter->FreePort(); - data->connected = false; -} - -bool OneWireLinkLayerMaster::connected() const { return data->connected; } - -string OneWireLinkLayerMaster::adapterName() const { - return marshal_as<string>(data->adapter->AdapterName); -} - -string OneWireLinkLayerMaster::portName() const { - return connected() ? marshal_as<string>(data->adapter->PortName) : ""; -} - -error_code OneWireLinkLayerMaster::reset() { - using DalSemi::OneWire::Adapter::OWResetResult; - - error_code result; - try { - switch (data->adapter->Reset()) { - case OWResetResult::RESET_SHORT: - result = make_error_code(ShortDetectedError); - break; - - case OWResetResult::RESET_NOPRESENCE: - result = make_error_code(NoSlaveError); - break; - } - } catch (AdapterException ^) { - result = make_error_code(CommunicationError); - } - return result; -} - -error_code OneWireLinkLayerMaster::touchBitSetLevel(bool & sendRecvBit, - Level afterLevel) { - error_code result; - try { - switch (afterLevel) { - case StrongLevel: { - auto adapterResult = data->adapter->StartPowerDelivery( - DalSemi::OneWire::Adapter::OWPowerStart::CONDITION_AFTER_BIT); - if (!adapterResult) { - result = make_error_code(PowerDeliveryError); - } - } break; - - case NormalLevel: - break; - - default: - result = make_error_code(InvalidLevelError); - break; - } - if (!result) { - if (sendRecvBit) { - sendRecvBit = data->adapter->GetBit(); - } else { - data->adapter->PutBit(0); - } - } - } catch (AdapterException ^) { - result = make_error_code(CommunicationError); - } - return result; -} - -error_code OneWireLinkLayerMaster::writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel) { - error_code result; - try { - switch (afterLevel) { - case StrongLevel: { - auto adapterResult = data->adapter->StartPowerDelivery( - DalSemi::OneWire::Adapter::OWPowerStart::CONDITION_AFTER_BYTE); - if (!adapterResult) { - result = make_error_code(PowerDeliveryError); - } - } break; - - case NormalLevel: - break; - - default: - result = make_error_code(InvalidLevelError); - break; - } - if (!result) { - data->adapter->PutByte(sendByte); - } - } catch (AdapterException ^) { - result = make_error_code(CommunicationError); - } - return result; -} - -error_code OneWireLinkLayerMaster::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { - error_code result; - try { - switch (afterLevel) { - case StrongLevel: { - auto adapterResult = data->adapter->StartPowerDelivery( - DalSemi::OneWire::Adapter::OWPowerStart::CONDITION_AFTER_BYTE); - if (!adapterResult) { - result = make_error_code(PowerDeliveryError); - } - } break; - - case NormalLevel: - break; - - default: - result = make_error_code(InvalidLevelError); - break; - } - if (!result) { - recvByte = data->adapter->GetByte(); - } - } catch (AdapterException ^) { - result = make_error_code(CommunicationError); - } - return result; -} - -error_code OneWireLinkLayerMaster::writeBlock(const uint_least8_t * sendBuf, - size_t sendLen) { - error_code result; - try { - changeSizeType<int>( - [this](const uint_least8_t * data, int dataSize) { - auto dataManaged = gcnew array<uint_least8_t>(dataSize); - Marshal::Copy(static_cast<IntPtr>(const_cast<uint_least8_t *>(data)), - dataManaged, 0, dataSize); - this->data->adapter->DataBlock(dataManaged, 0, dataSize); - }, - sendBuf, sendLen); - } catch (AdapterException ^) { - result = make_error_code(CommunicationError); - } - return result; -} - -error_code OneWireLinkLayerMaster::readBlock(uint_least8_t * recvBuf, - size_t recvLen) { - error_code result; - try { - changeSizeType<int>( - [this](uint_least8_t * data, int dataSize) { - auto dataManaged = gcnew array<uint_least8_t>(dataSize); - this->data->adapter->GetBlock(dataManaged, dataSize); - Marshal::Copy(dataManaged, 0, static_cast<IntPtr>(data), dataSize); - }, - recvBuf, recvLen); - } catch (AdapterException ^) { - result = make_error_code(CommunicationError); - } - return result; -} - -error_code OneWireLinkLayerMaster::setSpeed(Speed newSpeed) { - using DalSemi::OneWire::Adapter::OWSpeed; - - error_code result; - try { - switch (newSpeed) { - case OverdriveSpeed: - data->adapter->Speed = OWSpeed::SPEED_OVERDRIVE; - break; - - case StandardSpeed: - data->adapter->Speed = OWSpeed::SPEED_REGULAR; - break; - - default: - result = make_error_code(InvalidSpeedError); - break; - } - } catch (AdapterException ^) { - result = make_error_code(CommunicationError); - } - return result; -} - -error_code OneWireLinkLayerMaster::setLevel(Level newLevel) { - error_code result; - try { - switch (newLevel) { - case StrongLevel: { - auto setResult = data->adapter->StartPowerDelivery( - DalSemi::OneWire::Adapter::OWPowerStart::CONDITION_NOW); - if (!setResult) { - result = make_error_code(PowerDeliveryError); - } - } break; - - case NormalLevel: - data->adapter->SetPowerNormal(); - break; - - default: - result = make_error_code(InvalidLevelError); - break; - } - } catch (AdapterException ^) { - result = make_error_code(CommunicationError); - } - return result; -} - -const error_category & OneWireLinkLayerMaster::errorCategory() { - static class : public error_category { - public: - virtual const char * name() const { return "OneWireLinkLayerMaster"; } - - virtual string message(int condition) const { - switch (condition) { - case CommunicationError: - return "Communication Error"; - - case OpenPortError: - return "Open Port Error"; - - case PowerDeliveryError: - return "Power Delivery Error"; - - case AlreadyConnectedError: - return "Already Connected Error"; - - default: - return defaultErrorMessage(condition); - } - } - } instance; - return instance; -} - -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/dotnet/OneWireLinkLayerMaster.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#pragma once - -#include <memory> -#include <string> -#include <MaximInterface/Links/OneWireMaster.hpp> -#include <MaximInterface/Utilities/Export.h> -#include "MoveOnly.hpp" - -namespace MaximInterface { - -/// 1-Wire interface using the OneWireLinkLayer DLL from the Compact.NET API. -class OneWireLinkLayerMaster : public OneWireMaster, private MoveOnly { -public: - enum ErrorValue { - CommunicationError = 1, - OpenPortError, - PowerDeliveryError, - AlreadyConnectedError - }; - - /// @param adapterName Adapter type name recogized by OneWireLinkLayer. - MaximInterface_EXPORT OneWireLinkLayerMaster(const std::string & adapterName); - MaximInterface_EXPORT ~OneWireLinkLayerMaster(); - - MaximInterface_EXPORT - OneWireLinkLayerMaster(OneWireLinkLayerMaster &&) noexcept; - MaximInterface_EXPORT OneWireLinkLayerMaster & - operator=(OneWireLinkLayerMaster &&) noexcept; - - /// Connect to an adapter on the specified COM port. - MaximInterface_EXPORT error_code connect(const std::string & portName); - - /// Disconnect from the adapter on the current COM port. - MaximInterface_EXPORT void disconnect(); - - /// Check if currently connected to an adapter. - /// @returns True if connected. - MaximInterface_EXPORT bool connected() const; - - /// Get the adapter type name. - MaximInterface_EXPORT std::string adapterName() const; - - /// Get the currently connected COM port name. - MaximInterface_EXPORT std::string portName() const; - - MaximInterface_EXPORT virtual error_code reset() override; - MaximInterface_EXPORT virtual error_code - touchBitSetLevel(bool & sendRecvBit, Level afterLevel) override; - MaximInterface_EXPORT virtual error_code - writeByteSetLevel(uint_least8_t sendByte, Level afterLevel) override; - MaximInterface_EXPORT virtual error_code - readByteSetLevel(uint_least8_t & recvByte, Level afterLevel) override; - MaximInterface_EXPORT virtual error_code - writeBlock(const uint_least8_t * sendBuf, size_t sendLen) override; - MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * recvBuf, - size_t recvLen) override; - MaximInterface_EXPORT virtual error_code setSpeed(Speed newSpeed) override; - MaximInterface_EXPORT virtual error_code setLevel(Level newLevel) override; - - MaximInterface_EXPORT static const error_category & errorCategory(); - -private: - struct Data; - std::unique_ptr<Data> data; -}; - -inline error_code make_error_code(OneWireLinkLayerMaster::ErrorValue e) { - return error_code(e, OneWireLinkLayerMaster::errorCategory()); -} - -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/dotnet/SerialPort.cpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,225 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include <msclr/auto_gcroot.h> -#include <msclr/marshal_cppstd.h> -#include <MaximInterface/Utilities/Error.hpp> -#include "ChangeSizeType.hpp" -#include "Sleep.hpp" -#include "SerialPort.hpp" - -using msclr::interop::marshal_as; -using std::string; -using namespace System; -using System::Runtime::InteropServices::Marshal; - -namespace MaximInterface { -namespace dotnet { - -template <typename Type, typename Input> static bool isType(Input in) { - return dynamic_cast<Type>(in) != nullptr; -} - -template <typename Func> -static error_code executeTryCatchOperation(Func tryOperation) { - return executeTryCatchOperation(tryOperation, [] {}); -} - -template <typename TryFunc, typename CatchFunc> -static error_code executeTryCatchOperation(TryFunc tryOperation, - CatchFunc catchOperation) { - error_code result; - try { - tryOperation(); - } catch (Exception ^ e) { - catchOperation(); - if (isType<ArgumentException ^>(e)) { - result = make_error_code(SerialPort::ArgumentError); - } else if (isType<InvalidOperationException ^>(e)) { - result = make_error_code(SerialPort::InvalidOperationError); - } else if (isType<System::IO::IOException ^>(e)) { - result = make_error_code(SerialPort::IOError); - } else if (isType<UnauthorizedAccessException ^>(e)) { - result = make_error_code(SerialPort::UnauthorizedAccessError); - } else if (isType<TimeoutException ^>(e)) { - result = make_error_code(SerialPort::TimeoutError); - } else { - throw; - } - } - return result; -} - -template <typename Func> -static error_code executeIfConnected(const SerialPort & serial, - Func operation) { - return serial.connected() ? operation() - : make_error_code(SerialPort::NotConnectedError); -} - -struct SerialPort::Data { - msclr::auto_gcroot<System::IO::Ports::SerialPort ^> port; -}; - -SerialPort::SerialPort() : data(std::make_unique<Data>()) {} - -SerialPort::~SerialPort() = default; - -SerialPort::SerialPort(SerialPort &&) noexcept = default; - -SerialPort & SerialPort::operator=(SerialPort &&) noexcept = default; - -error_code SerialPort::connect(const string & portName) { - data->port = gcnew System::IO::Ports::SerialPort; - return executeTryCatchOperation( - [this, &portName] { - data->port->PortName = marshal_as<String ^>(portName); - data->port->DtrEnable = true; - data->port->ReadTimeout = 1000; - data->port->WriteTimeout = 1000; - data->port->Open(); - }, - [this] { data->port.reset(); }); -} - -error_code SerialPort::disconnect() { - data->port.reset(); - return error_code(); -} - -bool SerialPort::connected() const { return data->port.get() != nullptr; } - -string SerialPort::portName() const { - return connected() ? marshal_as<string>(data->port->PortName) : ""; -} - -error_code SerialPort::setBaudRate(int_least32_t baudRate) { - return executeIfConnected(*this, [this, baudRate] { - return executeTryCatchOperation( - [this, baudRate] { data->port->BaudRate = baudRate; }); - }); -} - -error_code SerialPort::sendBreak() { - return executeIfConnected(*this, [this] { - return executeTryCatchOperation([this] { - data->port->BreakState = true; - sleep(1); - data->port->BreakState = false; - }); - }); -} - -error_code SerialPort::clearReadBuffer() { - return executeIfConnected(*this, [this] { - return executeTryCatchOperation([this] { data->port->ReadExisting(); }); - }); -} - -error_code SerialPort::writeByte(uint_least8_t data) { - return writeBlock(&data, 1); -} - -error_code SerialPort::writeBlock(const uint_least8_t * data, size_t dataLen) { - return executeIfConnected(*this, [this, data, dataLen] { - return executeTryCatchOperation([this, data, dataLen] { - changeSizeType<int>( - [this](const uint_least8_t * dataChunk, int dataChunkSize) { - auto dataManaged = gcnew array<uint_least8_t>(dataChunkSize); - Marshal::Copy( - static_cast<IntPtr>(const_cast<uint_least8_t *>(dataChunk)), - dataManaged, 0, dataChunkSize); - this->data->port->Write(dataManaged, 0, dataChunkSize); - }, - data, dataLen); - }); - }); -} - -error_code SerialPort::readByte(uint_least8_t & data) { - return executeIfConnected(*this, [this, &data] { - return executeTryCatchOperation( - [this, &data] { data = this->data->port->ReadByte(); }); - }); -} - -error_code SerialPort::readBlock(uint_least8_t * data, size_t dataLen) { - return executeIfConnected(*this, [this, data, dataLen] { - return executeTryCatchOperation([this, data, dataLen] { - changeSizeType<int>( - [this](uint_least8_t * dataChunk, int dataChunkSize) { - auto dataManaged = gcnew array<uint_least8_t>(dataChunkSize); - int bytesRead = 0; - do { - bytesRead += this->data->port->Read(dataManaged, bytesRead, - dataChunkSize - bytesRead); - } while (bytesRead < dataChunkSize); - Marshal::Copy(dataManaged, 0, static_cast<IntPtr>(dataChunk), - dataChunkSize); - }, - data, dataLen); - }); - }); -} - -const error_category & SerialPort::errorCategory() { - static class : public error_category { - public: - virtual const char * name() const override { return "dotnet SerialPort"; } - - virtual string message(int condition) const override { - switch (condition) { - case NotConnectedError: - return "Not Connected Error"; - - case ArgumentError: - return "Argument Error"; - - case InvalidOperationError: - return "Invalid Operation Error"; - - case IOError: - return "IO Error"; - - case UnauthorizedAccessError: - return "Unauthorized Access Error"; - - default: - return defaultErrorMessage(condition); - } - } - } instance; - return instance; -} - -} // namespace dotnet -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/dotnet/SerialPort.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#pragma once - -#include <memory> -#include <string> -#include <MaximInterface/Links/SerialPort.hpp> -#include <MaximInterface/Utilities/Export.h> -#include "MoveOnly.hpp" - -namespace MaximInterface { -namespace dotnet { - -/// Serial port interface using .NET type System::IO::Ports::SerialPort. -class SerialPort : public MaximInterface::SerialPort, private MoveOnly { -public: - enum ErrorValue { - NotConnectedError = 1, - ArgumentError, - InvalidOperationError, - IOError, - UnauthorizedAccessError - }; - - MaximInterface_EXPORT SerialPort(); - MaximInterface_EXPORT ~SerialPort(); - - MaximInterface_EXPORT SerialPort(SerialPort &&) noexcept; - MaximInterface_EXPORT SerialPort & operator=(SerialPort &&) noexcept; - - MaximInterface_EXPORT virtual error_code - connect(const std::string & portName) override; - MaximInterface_EXPORT virtual error_code disconnect() override; - MaximInterface_EXPORT virtual bool connected() const override; - MaximInterface_EXPORT virtual std::string portName() const override; - - MaximInterface_EXPORT virtual error_code - setBaudRate(int_least32_t baudRate) override; - MaximInterface_EXPORT virtual error_code sendBreak() override; - MaximInterface_EXPORT virtual error_code clearReadBuffer() override; - MaximInterface_EXPORT virtual error_code - writeByte(uint_least8_t data) override; - MaximInterface_EXPORT virtual error_code - writeBlock(const uint_least8_t * data, size_t dataLen) override; - MaximInterface_EXPORT virtual error_code - readByte(uint_least8_t & data) override; - MaximInterface_EXPORT virtual error_code readBlock(uint_least8_t * data, - size_t dataLen) override; - - MaximInterface_EXPORT static const error_category & errorCategory(); - -private: - struct Data; - std::unique_ptr<Data> data; -}; - -inline error_code make_error_code(SerialPort::ErrorValue e) { - return error_code(e, SerialPort::errorCategory()); -} - -} // namespace dotnet -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/dotnet/Sleep.cpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include "Sleep.hpp" - -namespace MaximInterface { -namespace dotnet { - -void sleep(const int ms) { - constexpr int timeSlice_ms = 20; - if (ms > timeSlice_ms / 2) { - System::Threading::Thread::Sleep(ms); - } else { - auto watch = System::Diagnostics::Stopwatch::StartNew(); - while (watch->ElapsedMilliseconds < ms); - watch->Stop(); - } -} - -Sleep & Sleep::instance() { - static Sleep instance; - return instance; -} - -void Sleep::operator()(int ms) const { sleep(ms); } - -} // namespace dotnet -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/dotnet/Sleep.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#pragma once - -#include <MaximInterface/Links/Sleep.hpp> -#include <MaximInterface/Utilities/Export.h> -#include <MaximInterface/Utilities/Uncopyable.hpp> - -namespace MaximInterface { -namespace dotnet { - -MaximInterface_EXPORT void sleep(int ms); - -class Sleep : public MaximInterface::Sleep, private Uncopyable { -public: - MaximInterface_EXPORT static Sleep & instance(); - - MaximInterface_EXPORT virtual void operator()(int ms) const override; - -private: - Sleep() = default; -}; - -} // namespace dotnet -} // namespace MaximInterface \ No newline at end of file
--- a/Platforms/mbed/I2CMaster.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Platforms/mbed/I2CMaster.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -50,10 +50,10 @@ } error_code I2CMaster::writePacketImpl(uint_least8_t address, - const uint_least8_t * data, - size_t dataLen, bool sendStop) { - return (i2c->write(address, reinterpret_cast<const char *>(data), dataLen, - !sendStop) == 0) + span<const uint_least8_t> data, + bool sendStop) { + return (i2c->write(address, reinterpret_cast<const char *>(data.data()), + data.size(), !sendStop) == 0) ? error_code() : make_error_code(NackError); } @@ -64,13 +64,12 @@ } error_code I2CMaster::readPacketImpl(uint_least8_t address, - uint_least8_t * data, size_t dataLen, - bool sendStop) { - return (i2c->read(address, reinterpret_cast<char *>(data), dataLen, + span<uint_least8_t> data, bool sendStop) { + return (i2c->read(address, reinterpret_cast<char *>(data.data()), data.size(), !sendStop) == 0) ? error_code() : make_error_code(NackError); } } // namespace mbed -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Platforms/mbed/I2CMaster.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Platforms/mbed/I2CMaster.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -50,12 +50,13 @@ virtual error_code stop(); virtual error_code writeByte(uint_least8_t data); virtual error_code readByte(AckStatus status, uint_least8_t & data); - + protected: - virtual error_code readPacketImpl(uint_least8_t address, uint_least8_t * data, - size_t dataLen, bool sendStop); + virtual error_code readPacketImpl(uint_least8_t address, + span<uint_least8_t> data, bool sendStop); + virtual error_code writePacketImpl(uint_least8_t address, - const uint_least8_t * data, size_t dataLen, + span<const uint_least8_t> data, bool sendStop); private:
--- a/Platforms/mbed/Sleep.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Platforms/mbed/Sleep.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -43,7 +43,7 @@ return instance; } -void Sleep::operator()(int ms) const { sleep(ms); } +void Sleep::invoke(int ms) const { sleep(ms); } } // namespace mbed -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Platforms/mbed/Sleep.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Platforms/mbed/Sleep.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -44,8 +44,7 @@ class Sleep : public MaximInterface::Sleep, private Uncopyable { public: static Sleep & instance(); - - virtual void operator()(int ms) const; + virtual void invoke(int ms) const; private: Sleep() {}
--- a/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_ARM_STD/owlink.s Tue Jul 24 08:33:31 2018 +0000 +++ b/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_ARM_STD/owlink.s Wed Apr 03 12:33:10 2019 +0000 @@ -31,17 +31,25 @@ **********************************************************************/ // ow_usdelay configuration -#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000) // Processor clock in MHz -#define OVERHEAD_TUNING 18 // Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ -// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP for best results +// +// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP +// for best results +// +// Processor clock in MHz +#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000) +// +// Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ +#define OVERHEAD_TUNING 18 +// +// ARM specifies 1-3 cycles for pipeline refill following a branch +#define PIPELINE_REFILL_PROC_CYCLES 1 // ow_usdelay constants -#define PIPELINE_REFILL_PROC_CYCLES 1 // ARM specifies 1-3 cycles for pipeline refill following a branch #define PROC_CYCLES_PER_LOOP (2 + PIPELINE_REFILL_PROC_CYCLES) -#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP) // Number of loop passes for a 1 us delay +#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP) #define LOOPS_REMOVED_TUNING (OVERHEAD_TUNING / PROC_CYCLES_PER_LOOP) -// OwTiming offsets +// OneWireTiming offsets #define tRSTL_OFFSET 0 #define tMSP_OFFSET 2 #define tW0L_OFFSET 4 @@ -65,7 +73,7 @@ ow_usdelay_return bx R14 -// static void write_ow_gpio_low(unsigned int * portReg, unsigned int pinMask) +// void write_ow_gpio_low(volatile uint32_t * portReg, unsigned int pinMask) MACRO $label write_ow_gpio_low ldr R2, [R0] @@ -73,7 +81,7 @@ str R2, [R0] MEND -// static void write_ow_gpio_high(unsigned int * portReg, unsigned int pinMask) +// void write_ow_gpio_high(volatile uint32_t * portReg, unsigned int pinMask) MACRO $label write_ow_gpio_high ldr R2, [R0] @@ -81,7 +89,9 @@ str R2, [R0] MEND -// void ow_bit(uint8_t * sendrecvbit, volatile uint32_t * inPortReg, volatile uint32_t * outPortReg, unsigned int pinMask, const OwTiming * timing) +// void ow_bit(uint8_t * sendRecvBit, const volatile uint32_t * inReg, +// volatile uint32_t * outReg, unsigned int pinMask, +// const OneWireTiming * timing) EXPORT ow_bit ow_bit push {R4-R8, R14} @@ -90,9 +100,9 @@ ldr R6, [R6] // Load timing struct ldrh R4, [R6, #tSLOT_OFFSET] ldrh R5, [R6, #tMSR_OFFSET] - // R0: sendrecvbit - // R1: inPortReg - // R2: outPortReg + // R0: sendRecvBit + // R1: inReg + // R2: outReg // R3: pinMask // R4: tSLOT // R5: tMSR @@ -102,22 +112,22 @@ // R14: Scratch // Reorganize registers for upcoming function calls - mov R8, R1 // inPortReg to R8 - mov R7, R2 // outPortReg to R7 + mov R8, R1 // inReg to R8 + mov R7, R2 // outReg to R7 mov R1, R3 // pinMask to R1 - mov R3, R0 // sendrecvbit to R3 + mov R3, R0 // sendRecvBit to R3 // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tSLOT // R5: tMSR // R6: timing - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch - // if (*sendrecvbit & 1) + // if (*sendRecvBit & 1) ldrb R14, [R3] tst R14, #1 beq write_zero @@ -127,22 +137,22 @@ // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tREC // R5: delay2 // R6: tW1L - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_low // Pull low mov R0, R6 // tLOW bl ow_usdelay // Delay for tLOW - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_high // Release pin mov R0, R5 // delay2 bl ow_usdelay // Delay for sample time - ldr R5, [R8] // Read *inPortReg + ldr R5, [R8] // Read *inReg b recovery_delay // else write_zero @@ -152,32 +162,32 @@ // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tREC // R5: tMSR // R6: delay2 - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_low // Pull low mov R0, R5 // tMSR bl ow_usdelay // Delay for tMSR - ldr R5, [R8] // Read *inPortReg + ldr R5, [R8] // Read *inReg mov R0, R6 // delay2 bl ow_usdelay // Delay for release - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_high // Release pin - // endif (*sendrecvbit & 1) + // endif (*sendRecvBit & 1) // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tREC - // R5: *inPortReg + // R5: *inReg // R6: Scratch - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch recovery_delay @@ -185,7 +195,7 @@ bl ow_usdelay // Delay for tREC // Parse received bit - // *sendrecvbit = ((*inPortReg & pinMask) == pinMask) + // *sendRecvBit = ((*inReg & pinMask) == pinMask) and R5, R5, R1 cmp R5, R1 ite eq
--- a/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_GCC_ARM/owlink.S Tue Jul 24 08:33:31 2018 +0000 +++ b/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_GCC_ARM/owlink.S Wed Apr 03 12:33:10 2019 +0000 @@ -31,17 +31,25 @@ **********************************************************************/ // ow_usdelay configuration -#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000) // Processor clock in MHz -#define OVERHEAD_TUNING 18 // Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ -// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP for best results +// +// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP +// for best results +// +// Processor clock in MHz +#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000) +// +// Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ +#define OVERHEAD_TUNING 18 +// +// ARM specifies 1-3 cycles for pipeline refill following a branch +#define PIPELINE_REFILL_PROC_CYCLES 1 // ow_usdelay constants -#define PIPELINE_REFILL_PROC_CYCLES 1 // ARM specifies 1-3 cycles for pipeline refill following a branch #define PROC_CYCLES_PER_LOOP (2 + PIPELINE_REFILL_PROC_CYCLES) -#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP) // Number of loop passes for a 1 us delay +#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP) #define LOOPS_REMOVED_TUNING (OVERHEAD_TUNING / PROC_CYCLES_PER_LOOP) -// OwTiming offsets +// OneWireTiming offsets #define tRSTL_OFFSET 0 #define tMSP_OFFSET 2 #define tW0L_OFFSET 4 @@ -67,21 +75,23 @@ ow_usdelay_return: bx R14 -// static void write_ow_gpio_low(unsigned int * portReg, unsigned int pinMask) +// void write_ow_gpio_low(volatile uint32_t * portReg, unsigned int pinMask) .macro write_ow_gpio_low ldr R2, [R0] bic R2, R2, R1 str R2, [R0] .endm -// static void write_ow_gpio_high(unsigned int * portReg, unsigned int pinMask) +// void write_ow_gpio_high(volatile uint32_t * portReg, unsigned int pinMask) .macro write_ow_gpio_high ldr R2, [R0] orr R2, R2, R1 str R2, [R0] .endm -// void ow_bit(uint8_t * sendrecvbit, volatile uint32_t * inPortReg, volatile uint32_t * outPortReg, unsigned int pinMask, const OwTiming * timing) +// void ow_bit(uint8_t * sendRecvBit, const volatile uint32_t * inReg, +// volatile uint32_t * outReg, unsigned int pinMask, +// const OneWireTiming * timing) .thumb_func .global ow_bit ow_bit: @@ -91,9 +101,9 @@ ldr R6, [R6] // Load timing struct ldrh R4, [R6, #tSLOT_OFFSET] ldrh R5, [R6, #tMSR_OFFSET] - // R0: sendrecvbit - // R1: inPortReg - // R2: outPortReg + // R0: sendRecvBit + // R1: inReg + // R2: outReg // R3: pinMask // R4: tSLOT // R5: tMSR @@ -103,22 +113,22 @@ // R14: Scratch // Reorganize registers for upcoming function calls - mov R8, R1 // inPortReg to R8 - mov R7, R2 // outPortReg to R7 + mov R8, R1 // inReg to R8 + mov R7, R2 // outReg to R7 mov R1, R3 // pinMask to R1 - mov R3, R0 // sendrecvbit to R3 + mov R3, R0 // sendRecvBit to R3 // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tSLOT // R5: tMSR // R6: timing - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch - // if (*sendrecvbit & 1) + // if (*sendRecvBit & 1) ldrb R14, [R3] tst R14, #1 beq write_zero @@ -128,22 +138,22 @@ // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tREC // R5: delay2 // R6: tW1L - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_low // Pull low mov R0, R6 // tLOW bl ow_usdelay // Delay for tLOW - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_high // Release pin mov R0, R5 // delay2 bl ow_usdelay // Delay for sample time - ldr R5, [R8] // Read *inPortReg + ldr R5, [R8] // Read *inReg b recovery_delay // else write_zero: @@ -153,32 +163,32 @@ // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tREC // R5: tMSR // R6: delay2 - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_low // Pull low mov R0, R5 // tMSR bl ow_usdelay // Delay for tMSR - ldr R5, [R8] // Read *inPortReg + ldr R5, [R8] // Read *inReg mov R0, R6 // delay2 bl ow_usdelay // Delay for release - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_high // Release pin - // endif (*sendrecvbit & 1) + // endif (*sendRecvBit & 1) // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tREC - // R5: *inPortReg + // R5: *inReg // R6: Scratch - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch recovery_delay: @@ -186,7 +196,7 @@ bl ow_usdelay // Delay for tREC // Parse received bit - // *sendrecvbit = ((*inPortReg & pinMask) == pinMask) + // *sendRecvBit = ((*inReg & pinMask) == pinMask) and R5, R5, R1 cmp R5, R1 ite eq
--- a/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_IAR/owlink.s Tue Jul 24 08:33:31 2018 +0000 +++ b/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/TOOLCHAIN_IAR/owlink.s Wed Apr 03 12:33:10 2019 +0000 @@ -31,17 +31,25 @@ **********************************************************************/ // ow_usdelay configuration -#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000) // Processor clock in MHz -#define OVERHEAD_TUNING 18 // Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ -// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP for best results +// +// Make PROC_CLOCK_MHZ and OVERHEAD_TUNING divisible by PROC_CYCLES_PER_LOOP +// for best results +// +// Processor clock in MHz +#define PROC_CLOCK_MHZ (__SYSTEM_HFX / 1000000) +// +// Fraction where OverheadTime(us) = OVERHEAD_TUNING / PROC_CLOCK_MHZ +#define OVERHEAD_TUNING 18 +// +// ARM specifies 1-3 cycles for pipeline refill following a branch +#define PIPELINE_REFILL_PROC_CYCLES 1 // ow_usdelay constants -#define PIPELINE_REFILL_PROC_CYCLES 1 // ARM specifies 1-3 cycles for pipeline refill following a branch #define PROC_CYCLES_PER_LOOP (2 + PIPELINE_REFILL_PROC_CYCLES) -#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP) // Number of loop passes for a 1 us delay +#define LOOPS_PER_US (PROC_CLOCK_MHZ / PROC_CYCLES_PER_LOOP) #define LOOPS_REMOVED_TUNING (OVERHEAD_TUNING / PROC_CYCLES_PER_LOOP) -// OwTiming offsets +// OneWireTiming offsets #define tRSTL_OFFSET 0 #define tMSP_OFFSET 2 #define tW0L_OFFSET 4 @@ -66,21 +74,23 @@ ow_usdelay_return bx R14 -// static void write_ow_gpio_low(unsigned int * portReg, unsigned int pinMask) +// void write_ow_gpio_low(volatile uint32_t * portReg, unsigned int pinMask) write_ow_gpio_low MACRO ldr R2, [R0] bic R2, R2, R1 str R2, [R0] ENDM -// static void write_ow_gpio_high(unsigned int * portReg, unsigned int pinMask) +// void write_ow_gpio_high(volatile uint32_t * portReg, unsigned int pinMask) write_ow_gpio_high MACRO ldr R2, [R0] orr R2, R2, R1 str R2, [R0] ENDM -// void ow_bit(uint8_t * sendrecvbit, volatile uint32_t * inPortReg, volatile uint32_t * outPortReg, unsigned int pinMask, const OwTiming * timing) +// void ow_bit(uint8_t * sendRecvBit, const volatile uint32_t * inReg, +// volatile uint32_t * outReg, unsigned int pinMask, +// const OneWireTiming * timing) EXPORT ow_bit ow_bit push {R4-R8, R14} @@ -89,9 +99,9 @@ ldr R6, [R6] // Load timing struct ldrh R4, [R6, #tSLOT_OFFSET] ldrh R5, [R6, #tMSR_OFFSET] - // R0: sendrecvbit - // R1: inPortReg - // R2: outPortReg + // R0: sendRecvBit + // R1: inReg + // R2: outReg // R3: pinMask // R4: tSLOT // R5: tMSR @@ -101,22 +111,22 @@ // R14: Scratch // Reorganize registers for upcoming function calls - mov R8, R1 // inPortReg to R8 - mov R7, R2 // outPortReg to R7 + mov R8, R1 // inReg to R8 + mov R7, R2 // outReg to R7 mov R1, R3 // pinMask to R1 - mov R3, R0 // sendrecvbit to R3 + mov R3, R0 // sendRecvBit to R3 // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tSLOT // R5: tMSR // R6: timing - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch - // if (*sendrecvbit & 1) + // if (*sendRecvBit & 1) ldrb R14, [R3] tst R14, #1 beq write_zero @@ -126,22 +136,22 @@ // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tREC // R5: delay2 // R6: tW1L - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_low // Pull low mov R0, R6 // tLOW bl ow_usdelay // Delay for tLOW - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_high // Release pin mov R0, R5 // delay2 bl ow_usdelay // Delay for sample time - ldr R5, [R8] // Read *inPortReg + ldr R5, [R8] // Read *inReg b recovery_delay // else write_zero @@ -151,32 +161,32 @@ // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tREC // R5: tMSR // R6: delay2 - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_low // Pull low mov R0, R5 // tMSR bl ow_usdelay // Delay for tMSR - ldr R5, [R8] // Read *inPortReg + ldr R5, [R8] // Read *inReg mov R0, R6 // delay2 bl ow_usdelay // Delay for release - mov R0, R7 // outPortReg + mov R0, R7 // outReg write_ow_gpio_high // Release pin - // endif (*sendrecvbit & 1) + // endif (*sendRecvBit & 1) // R0: Scratch // R1: pinMask // R2: Scratch - // R3: sendrecvbit + // R3: sendRecvBit // R4: tREC - // R5: *inPortReg + // R5: *inReg // R6: Scratch - // R7: outPortReg - // R8: inPortReg + // R7: outReg + // R8: inReg // R14: Scratch recovery_delay @@ -184,7 +194,7 @@ bl ow_usdelay // Delay for tREC // Parse received bit - // *sendrecvbit = ((*inPortReg & pinMask) == pinMask) + // *sendRecvBit = ((*inReg & pinMask) == pinMask) and R5, R5, R1 cmp R5, R1 ite eq
--- a/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/owlink.h Tue Jul 24 08:33:31 2018 +0000 +++ b/Platforms/mbed/TARGET_Maxim/TARGET_MAX32600/owlink.h Wed Apr 03 12:33:10 2019 +0000 @@ -39,8 +39,7 @@ extern "C" { #endif -/// Timing parameters for the 1-Wire bus. -/// @note All times are in terms of microseconds. +/// Timing parameters for the 1-Wire bus in microseconds. struct OneWireTiming { uint16_t tRSTL; ///< Reset Low Time uint16_t tMSP; ///< Presence-Detect Sample Time @@ -53,16 +52,17 @@ /// Delay for the specified number of microseconds. void ow_usdelay(unsigned int time_us); -/// Send and receive one bit of communication and set a new level on the 1-Wire bus. +/// @brief Send and receive one bit, and set a new level on the 1-Wire bus. /// @note GPIO pin must be configured for open drain operation. -/// @param[in,out] sendRecvBit Buffer containing the bit to send on 1-Wire bus in lsb. -/// Read data from 1-Wire bus will be returned in lsb. -/// @param inReg Input register for GPIO pin. -/// @param outReg Output register for GPIO pin. +/// @param[in,out] sendRecvBit +/// Buffer containing the bit to send on 1-Wire bus in lsb. +/// Read data from 1-Wire bus will be returned in lsb. +/// @param[in] inReg Input register for GPIO pin. +/// @param[in,out] outReg Output register for GPIO pin. /// @param pinMask Pin mask for input and output registers. /// @param[in] timing 1-Wire timing parameters to use. -void ow_bit(uint8_t * sendRecvBit, volatile uint32_t * inReg, - volatile uint32_t * outPortReg, unsigned int pinMask, +void ow_bit(uint8_t * sendRecvBit, const volatile uint32_t * inReg, + volatile uint32_t * outReg, unsigned int pinMask, const OneWireTiming * timing); #ifdef __cplusplus
--- a/Platforms/mbed/Uart.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Platforms/mbed/Uart.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -103,4 +103,4 @@ } } // namespace mbed -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Platforms/mxc/.mbedignore Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -* \ No newline at end of file
--- a/Platforms/mxc/Error.cpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include <MaximInterface/Links/I2CMaster.hpp> -#include <MaximInterface/Utilities/Error.hpp> -#include <mxc_errors.h> -#include "Error.hpp" - -namespace MaximInterface { -namespace mxc { - -const error_category & errorCategory() { - static class : public error_category { - public: - virtual const char * name() const { return "mxc"; } - - virtual std::string message(int condition) const { - return defaultErrorMessage(condition); - } - - // Make E_COMM_ERR equivalent to I2CMaster::NackError. - virtual bool equivalent(int code, const error_condition & condition) const { - return (code == E_COMM_ERR) - ? (condition == make_error_condition(I2CMaster::NackError)) - : error_category::equivalent(code, condition); - } - } instance; - return instance; -} - -} // namespace mxc -} // namespace MaximInterface
--- a/Platforms/mxc/Error.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -/// @file Common functionality for mapping mxc return codes to -/// MaximInterface::error_code. - -#ifndef MaximInterface_mxc_Error -#define MaximInterface_mxc_Error - -#include <MaximInterface/Utilities/system_error.hpp> - -namespace MaximInterface { -namespace mxc { - -const error_category & errorCategory(); - -inline error_code makeErrorCode(int mxcResult) { - return error_code(mxcResult, errorCategory()); -} - -} // namespace mxc -} // namespace MaximInterface - -#endif
--- a/Platforms/mxc/I2CMaster.cpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include <mxc_device.h> -#include "Error.hpp" -#include "I2CMaster.hpp" - -namespace MaximInterface { -namespace mxc { - -static void verifyTransactionStarted(mxc_i2cm_regs_t & i2cm) { - if (!(i2cm.trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) { - i2cm.trans |= MXC_F_I2CM_TRANS_TX_START; - } -} - -error_code I2CMaster::initialize(const sys_cfg_i2cm_t & sysCfg, - i2cm_speed_t speed) { - return makeErrorCode(I2CM_Init(i2cm, &sysCfg, speed)); -} - -error_code I2CMaster::shutdown() { return makeErrorCode(I2CM_Shutdown(i2cm)); } - -error_code I2CMaster::writeByte(uint_least8_t data, bool start) { - const uint16_t fifoData = - static_cast<uint16_t>(data & 0xFF) | - (start ? MXC_S_I2CM_TRANS_TAG_START : MXC_S_I2CM_TRANS_TAG_TXDATA_ACK); - const error_code result = - makeErrorCode(I2CM_WriteTxFifo(i2cm, i2cmFifo, fifoData)); - if (result) { - I2CM_Recover(i2cm); - } else { - verifyTransactionStarted(*i2cm); - } - return result; -} - -error_code I2CMaster::start(uint_least8_t address) { - return writeByte(address, true); -} - -error_code I2CMaster::stop() { - error_code result = makeErrorCode( - I2CM_WriteTxFifo(i2cm, i2cmFifo, MXC_S_I2CM_TRANS_TAG_STOP)); - if (!result) { - result = makeErrorCode(I2CM_TxInProgress(i2cm)); - } - return result; -} - -error_code I2CMaster::writeByte(uint_least8_t data) { - return writeByte(data, false); -} - -error_code I2CMaster::readByte(AckStatus status, uint_least8_t & data) { - uint16_t fifoData = (status == Nack) ? MXC_S_I2CM_TRANS_TAG_RXDATA_NACK - : MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT; - error_code result = makeErrorCode(I2CM_WriteTxFifo(i2cm, i2cmFifo, fifoData)); - if (!result) { - verifyTransactionStarted(*i2cm); - do { - int timeout = 0x5000; - while ((i2cm->bb & MXC_F_I2CM_BB_RX_FIFO_CNT) == 0) { - if ((--timeout <= 0) || (i2cm->trans & MXC_F_I2CM_TRANS_TX_TIMEOUT)) { - result = makeErrorCode(E_TIME_OUT); - goto exit; - } - if (i2cm->trans & - (MXC_F_I2CM_TRANS_TX_LOST_ARBITR | MXC_F_I2CM_TRANS_TX_NACKED)) { - result = make_error_code(NackError); - goto exit; - } - } - fifoData = i2cmFifo->rx; - } while (fifoData & MXC_S_I2CM_RSTLS_TAG_EMPTY); - data = fifoData & 0xFF; - } - -exit: - if (result) { - I2CM_Recover(i2cm); - } - return result; -} - -} // namespace mxc -} // namespace MaximInterface
--- a/Platforms/mxc/I2CMaster.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#ifndef MaximInterface_mxc_I2CMaster -#define MaximInterface_mxc_I2CMaster - -#include <MaximInterface/Links/I2CMaster.hpp> -#include <i2cm.h> - -namespace MaximInterface { -namespace mxc { - -class I2CMaster : public MaximInterface::I2CMaster { -public: - I2CMaster(mxc_i2cm_regs_t & i2cm, mxc_i2cm_fifo_regs_t & i2cmFifo) - : i2cm(&i2cm), i2cmFifo(&i2cmFifo) {} - - void set_mxc_i2cm(mxc_i2cm_regs_t & i2cm, mxc_i2cm_fifo_regs_t & i2cmFifo) { - this->i2cm = &i2cm; - this->i2cmFifo = &i2cmFifo; - } - - /// Initialize the hardware interface for use. - error_code initialize(const sys_cfg_i2cm_t & sysCfg, i2cm_speed_t speed); - - /// Shutdown the hardware interface after use. - error_code shutdown(); - - virtual error_code start(uint_least8_t address); - virtual error_code stop(); - virtual error_code writeByte(uint_least8_t data); - virtual error_code readByte(AckStatus status, uint_least8_t & data); - -private: - error_code writeByte(uint_least8_t data, bool start); - - mxc_i2cm_regs_t * i2cm; - mxc_i2cm_fifo_regs_t * i2cmFifo; -}; - -} // namespace mxc -} // namespace MaximInterface - -#endif
--- a/Platforms/mxc/OneWireMaster.cpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include "Error.hpp" -#include "OneWireMaster.hpp" - -namespace MaximInterface { -namespace mxc { - -error_code OneWireMaster::initialize(const owm_cfg_t & owmCfg, - const sys_cfg_owm_t & sysCfgOwm) { - extStrongPup = (owmCfg.ext_pu_mode != OWM_EXT_PU_UNUSED); - return makeErrorCode(OWM_Init(owm, &owmCfg, &sysCfgOwm)); -} - -error_code OneWireMaster::shutdown() { - return makeErrorCode(OWM_Shutdown(owm)); -} - -error_code OneWireMaster::reset() { - return OWM_Reset(owm) ? error_code() : make_error_code(NoSlaveError); -} - -error_code OneWireMaster::touchBitSetLevel(bool & sendRecvBit, - Level afterLevel) { - sendRecvBit = OWM_TouchBit(owm, sendRecvBit); - return setLevel(afterLevel); -} - -error_code OneWireMaster::writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel) { - error_code result = makeErrorCode(OWM_WriteByte(owm, sendByte)); - if (!result) { - result = setLevel(afterLevel); - } - return result; -} - -error_code OneWireMaster::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { - recvByte = OWM_ReadByte(owm); - return setLevel(afterLevel); -} - -error_code OneWireMaster::setSpeed(Speed newSpeed) { - error_code result; - if (newSpeed == OverdriveSpeed) { - OWM_SetOverdrive(owm, 1); - } else if (newSpeed == StandardSpeed) { - OWM_SetOverdrive(owm, 0); - } else { - result = make_error_code(InvalidSpeedError); - } - return result; -} - -error_code OneWireMaster::setLevel(Level newLevel) { - error_code result; - if (extStrongPup) { - if (newLevel == StrongLevel) { - OWM_SetExtPullup(owm, 1); - } else if (newLevel == NormalLevel) { - OWM_SetExtPullup(owm, 0); - } else { - result = make_error_code(InvalidLevelError); - } - } else if (newLevel != NormalLevel) { - result = make_error_code(InvalidLevelError); - } - return result; -} - -} // namespace mxc -} // namespace MaximInterface
--- a/Platforms/mxc/OneWireMaster.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#ifndef MaximInterface_mxc_OneWireMaster -#define MaximInterface_mxc_OneWireMaster - -#include <MaximInterface/Links/OneWireMaster.hpp> -#include <owm.h> - -namespace MaximInterface { -namespace mxc { - -/// MCU peripheral 1-Wire master (OWM) -class OneWireMaster : public MaximInterface::OneWireMaster { -public: - explicit OneWireMaster(mxc_owm_regs_t & owm) - : owm(&owm), extStrongPup(false) {} - - void set_mxc_owm(mxc_owm_regs_t & owm) { this->owm = &owm; } - - /// Initialize the hardware interface for use. - error_code initialize(const owm_cfg_t & owmCfg, - const sys_cfg_owm_t & sysCfgOwm); - - /// Shutdown the hardware interface after use. - error_code shutdown(); - - virtual error_code reset(); - virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel); - virtual error_code writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel); - virtual error_code readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel); - virtual error_code setSpeed(Speed newSpeed); - virtual error_code setLevel(Level newLevel); - -private: - mxc_owm_regs_t * owm; - bool extStrongPup; -}; - -} // namespace mxc -} // namespace MaximInterface - -#endif /* MaximInterface_mxc_OneWireMaster */
--- a/Platforms/mxc/Sleep.cpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#include "Sleep.hpp" - -namespace MaximInterface { -namespace mxc { - -void Sleep::operator()(int ms) const { - if (ms > 0) { - TMR_Delay(tmr, MSEC(static_cast<unsigned long>(ms))); - } -} - -} // namespace mxc -} // namespace MaximInterface
--- a/Platforms/mxc/Sleep.hpp Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -*******************************************************************************/ - -#ifndef MaximInterface_mxc_Sleep -#define MaximInterface_mxc_Sleep - -#include <MaximInterface/Links/Sleep.hpp> -#include <tmr_utils.h> - -namespace MaximInterface { -namespace mxc { - -class Sleep : public MaximInterface::Sleep { -public: - explicit Sleep(mxc_tmr_regs_t & tmr) : tmr(&tmr) {} - - void set_mxc_tmr(mxc_tmr_regs_t & tmr) { this->tmr = &tmr; } - - virtual void operator()(int ms) const; - -private: - mxc_tmr_regs_t * tmr; -}; - -} // namespace mxc -} // namespace MaximInterface - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utilities/Algorithm.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -0,0 +1,42 @@ +/******************************************************************************* +* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#ifndef MaximInterface_Algorithm +#define MaximInterface_Algorithm + +/// Alternative to std::max when a constant expression is required. +#define MaximInterface_MAX(a, b) ((a) < (b) ? (b) : (a)) + +/// Alternative to std::min when a constant expression is required. +#define MaximInterface_MIN(a, b) ((b) < (a) ? (b) : (a)) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utilities/ChangeSizeType.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -0,0 +1,77 @@ +/******************************************************************************* +* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#ifndef MaximInterface_ChangeSizeType +#define MaximInterface_ChangeSizeType + +#include <stdint.h> +#include <algorithm> +#include <limits> +#include "span.hpp" +#include "system_error.hpp" + +namespace MaximInterface { + +/// @brief +/// Adapts functions taking an array pointer and size where the size type is +/// nonstandard. +/// @tparam NewSize Nonstandard size type. +/// @tparam Func Must be callable as func(Data *, NewSize). +/// @tparam Data Array element type. +/// @param func Callback for processing chunks of data. +/// @param data Data to process with callback. +template <typename NewSize, typename Func, typename Data> +error_code changeSizeType(Func func, span<Data> data) { + using namespace std; + typedef typename span<Data>::index_type DataSize; + + error_code result; + // Check if NewSize can represent the maximum value of DataSize. + if (static_cast<uintmax_t>(numeric_limits<DataSize>::max()) > + static_cast<uintmax_t>(numeric_limits<NewSize>::max())) { + DataSize dataIdx = 0; + do { + const span<Data> chunk = + data.subspan(dataIdx, min<DataSize>(data.size() - dataIdx, + numeric_limits<NewSize>::max())); + result = func(chunk.data(), static_cast<NewSize>(chunk.size())); + dataIdx += chunk.size(); + } while (dataIdx < data.size() && !result); + } else { + result = func(data.data(), static_cast<NewSize>(data.size())); + } + return result; +} + +} // namespace MaximInterface + +#endif \ No newline at end of file
--- a/Utilities/Ecc256.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/Ecc256.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -30,24 +30,32 @@ * ownership rights. *******************************************************************************/ -#include <algorithm> #include "Ecc256.hpp" namespace MaximInterface { namespace Ecc256 { -CertificateData createCertificateData(const PublicKey & publicKey, - const RomId & romId, - const ManId & manId) { - using std::copy; +void copy(Point::const_span src, Point::span dst) { + copy(src.x, dst.x); + copy(src.y, dst.y); +} + +void copy(KeyPair::const_span src, KeyPair::span dst) { + copy(src.privateKey, dst.privateKey); + copy(src.publicKey, dst.publicKey); +} - CertificateData data; - CertificateData::iterator dataIt = data.begin(); - dataIt = copy(publicKey.x.begin(), publicKey.x.end(), dataIt); - dataIt = copy(publicKey.y.begin(), publicKey.y.end(), dataIt); - dataIt = copy(romId.begin(), romId.end(), dataIt); - copy(manId.begin(), manId.end(), dataIt); - return data; +void copy(Signature::const_span src, Signature::span dst) { + copy(src.r, dst.r); + copy(src.s, dst.s); +} + +PublicKey::span CertificateData::publicKey() { + const PublicKey::span span = { + make_span(result_).subspan<publicKeyIdx, Scalar::size>(), + make_span(result_) + .subspan<publicKeyIdx + Scalar::size, Scalar::size>()}; + return span; } } // namespace Ecc256
--- a/Utilities/Ecc256.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/Ecc256.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -34,7 +34,7 @@ #define MaximInterface_Ecc256 #include <stdint.h> -#include "array.hpp" +#include "array_span.hpp" #include "Export.h" #include "ManId.hpp" #include "RomId.hpp" @@ -42,41 +42,206 @@ namespace MaximInterface { namespace Ecc256 { -typedef array<uint_least8_t, 32> Scalar; +typedef array_span<uint_least8_t, 32> Scalar; + struct Point { - /// Total size of all elements in bytes. - static const size_t size = 2 * Scalar::csize; + struct const_span { + Scalar::const_span x; + Scalar::const_span y; + }; + + struct span { + Scalar::span x; + Scalar::span y; + + operator const_span() const { + const const_span sp = {x, y}; + return sp; + } + }; + + struct array { + Scalar::array x; + Scalar::array y; + + operator span() { + const span sp = {x, y}; + return sp; + } + + operator const_span() const { + const const_span sp = {x, y}; + return sp; + } + }; - Scalar x; - Scalar y; +private: + Point(); // deleted }; +MaximInterface_EXPORT void copy(Point::const_span src, Point::span dst); + typedef Scalar PrivateKey; typedef Point PublicKey; + struct KeyPair { - /// Total size of all elements in bytes. - static const size_t size = PrivateKey::csize + PublicKey::size; + struct const_span { + PrivateKey::const_span privateKey; + PublicKey::const_span publicKey; + }; + + struct span { + PrivateKey::span privateKey; + PublicKey::span publicKey; + + operator const_span() const { + const const_span sp = {privateKey, publicKey}; + return sp; + } + }; + + struct array { + PrivateKey::array privateKey; + PublicKey::array publicKey; + + operator span() { + const span sp = {privateKey, publicKey}; + return sp; + } + + operator const_span() const { + const const_span sp = {privateKey, publicKey}; + return sp; + } + }; - PrivateKey privateKey; - PublicKey publicKey; +private: + KeyPair(); // deleted }; +MaximInterface_EXPORT void copy(KeyPair::const_span src, KeyPair::span dst); + struct Signature { - /// Total size of all elements in bytes. - static const size_t size = 2 * Scalar::csize; + struct const_span { + Scalar::const_span r; + Scalar::const_span s; + }; + + struct span { + Scalar::span r; + Scalar::span s; + + operator const_span() const { + const const_span sp = {r, s}; + return sp; + } + }; + + struct array { + Scalar::array r; + Scalar::array s; + + operator span() { + const span sp = {r, s}; + return sp; + } + + operator const_span() const { + const const_span sp = {r, s}; + return sp; + } + }; - Scalar r; - Scalar s; +private: + Signature(); // deleted }; +MaximInterface_EXPORT void copy(Signature::const_span src, Signature::span dst); + /// Data used to create a device key certificate for ECC-256 authenticators. -typedef array<uint_least8_t, 2 * Scalar::csize + RomId::csize + ManId::csize> - CertificateData; +class CertificateData { +public: + typedef array_span<uint_least8_t, 2 * Scalar::size + RomId::size + ManId::size> + Result; + + CertificateData() : result_() {} + + /// Formatted data result. + Result::const_span result() const { return result_; } + + /// @name Public Key + /// @brief Public key of the device. + /// @{ + + /// Get mutable Public Key. + MaximInterface_EXPORT PublicKey::span publicKey(); + + /// Get immutable Public Key. + PublicKey::const_span publicKey() const { + return const_cast<CertificateData &>(*this).publicKey(); + } + + /// Set Public Key. + CertificateData & setPublicKey(PublicKey::const_span publicKey) { + copy(publicKey, this->publicKey()); + return *this; + } + + /// @} -/// Formats data for creating a device key certificate from the public key, -/// ROM ID, and MAN ID. -MaximInterface_EXPORT CertificateData createCertificateData( - const PublicKey & publicKey, const RomId & romId, const ManId & manId); + /// @name ROM ID + /// @brief 1-Wire ROM ID of the device. + /// @{ + + /// Get mutable ROM ID. + RomId::span romId() { + return make_span(result_).subspan<romIdIdx, RomId::size>(); + } + + /// Get immutable ROM ID. + RomId::const_span romId() const { + return const_cast<CertificateData &>(*this).romId(); + } + + /// Set ROM ID. + CertificateData & setRomId(RomId::const_span romId) { + copy(romId, this->romId()); + return *this; + } + + /// @} + + /// @name MAN ID + /// @brief Manufacturer ID of the device. + /// @{ + + /// Get mutable MAN ID. + ManId::span manId() { + return make_span(result_).subspan<manIdIdx, ManId::size>(); + } + + /// Get immutable MAN ID. + ManId::const_span manId() const { + return const_cast<CertificateData &>(*this).manId(); + } + + /// Set MAN ID. + CertificateData & setManId(ManId::const_span manId) { + copy(manId, this->manId()); + return *this; + } + + /// @} + +private: + typedef Result::span::index_type index; + + static const index publicKeyIdx = 0; + static const index romIdIdx = publicKeyIdx + 2 * Scalar::size; + static const index manIdIdx = romIdIdx + RomId::size; + + Result::array result_; +}; } // namespace Ecc256 } // namespace MaximInterface
--- a/Utilities/Error.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/Error.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -38,4 +38,4 @@ return (condition == 0) ? "Success" : "Unknown Error"; } -} // namespace MaximInterface \ No newline at end of file +} // namespace MaximInterface
--- a/Utilities/Error.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/Error.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -37,10 +37,10 @@ namespace MaximInterface { -/// Get the default error message associated with a condition. Typically used -/// by an error_category when the condition is unknown. +/// @brief Get the default error message associated with a condition. +/// @details Typically used by an error_category when the condition is unknown. MaximInterface_EXPORT const char * defaultErrorMessage(int condition); } -#endif \ No newline at end of file +#endif
--- a/Utilities/Export.h Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/Export.h Wed Apr 03 12:33:10 2019 +0000 @@ -31,13 +31,9 @@ *******************************************************************************/ #ifndef MaximInterface_EXPORT - #ifdef _MSC_VER - #ifdef _DLL - #define MaximInterface_EXPORT __declspec(dllexport) - #else - #define MaximInterface_EXPORT __declspec(dllimport) - #endif /* _DLL */ - #else - #define MaximInterface_EXPORT - #endif /* _MSC_VER */ -#endif /* MaximInterface_EXPORT */ \ No newline at end of file + #if defined(_MSC_VER) && defined(MaximInterface_EXPORTING) + #define MaximInterface_EXPORT __declspec(dllexport) + #else + #define MaximInterface_EXPORT + #endif +#endif
--- a/Utilities/FlagSet.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/FlagSet.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -38,6 +38,7 @@ namespace MaximInterface { +/// @brief /// Provides functionality similar to std::bitset except using a bit flag, /// typically of an enum type, as the indexer. template <typename Flag, size_t flagBits> class FlagSet { @@ -45,15 +46,20 @@ class reference { public: reference(FlagSet & flagSet, Flag flag) : flagSet(&flagSet), flag(flag) {} + reference & operator=(bool x) { flagSet->set(flag, x); return *this; } + reference & operator=(const reference & x) { return operator=(static_cast<bool>(x)); } + operator bool() const { return flagSet->test(flag); } + bool operator~() const { return reference(*this).flip(); } + reference & flip() { *this = !*this; return *this; @@ -65,6 +71,7 @@ }; FlagSet() : bits() {} + FlagSet(unsigned long val) : bits(val) {} template <typename CharT, typename Traits, typename Alloc> @@ -76,38 +83,58 @@ : bits(str, pos, n) {} bool operator==(const FlagSet & rhs) const { return bits == rhs.bits; } + bool operator!=(const FlagSet & rhs) const { return !operator==(rhs); } - // Element access + /// @name Element access + /// @{ + bool operator[](Flag flag) const { return test(flag); } + reference operator[](Flag flag) { return reference(*this, flag); } + bool test(Flag flag) const { return (bits.to_ulong() & flag) == flag; } + bool any() const { return bits.any(); } + bool none() const { return bits.none(); } + size_t count() const { return bits.count(); } + + /// @} - // Capacity + /// @name Capacity + /// @{ + size_t size() const { return bits.size(); } + + /// @} - // Modifiers + /// @name Modifiers + /// @{ + FlagSet & operator&=(const FlagSet & other) { bits &= other.bits; return *this; } + FlagSet & operator|=(const FlagSet & other) { bits |= other.bits; return *this; } + FlagSet & operator^=(const FlagSet & other) { bits ^= other.bits; return *this; } + FlagSet operator~() const { return ~bits; } FlagSet & set() { bits.set(); return *this; } + FlagSet & set(Flag flag, bool value = true) { if (value) { bits |= flag; @@ -116,26 +143,37 @@ } return *this; } + FlagSet & reset() { bits.reset(); return *this; } + FlagSet & reset(Flag flag) { return set(flag, false); } + FlagSet & flip() { bits.flip(); return *this; } + FlagSet & flip(Flag flag) { bits ^= flag; return *this; } + + /// @} - // Conversions + /// @name Conversions + /// @{ + template <typename CharT, typename Traits, typename Allocator> std::basic_string<CharT, Traits, Allocator> to_string() const { return bits.template to_string<CharT, Traits, Allocator>(); } + unsigned long to_ulong() const { return bits.to_ulong(); } + + /// @} private: std::bitset<flagBits> bits; @@ -185,4 +223,4 @@ } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Utilities/Function.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/Function.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -34,6 +34,7 @@ #define MaximInterface_Function #include <stddef.h> +#include "SafeBool.hpp" #include "type_traits.hpp" // Include for std::swap. @@ -70,7 +71,9 @@ private: char data[TypeSize]; - long double aligner; + long double aligner1; + long int aligner2; + void * aligner3; }; // Computes the internal target size for TypeStorage based on a desired total @@ -80,7 +83,9 @@ template <typename Target, size_t totalSize> class TypeWrapperTotalSize { private: typedef TypeStorage<Target, 1> MinSizeStorage; + static const size_t otherDataSize = sizeof(Target *); + // Round down to be a multiple of alignment_of<MinSizeTargetStorage>::value. static const size_t internalTargetRawSize = (totalSize - otherDataSize) / alignment_of<MinSizeStorage>::value * @@ -235,7 +240,7 @@ } // namespace detail -// Function wrapper similar to std::function for 0-2 argument functions. +// Function wrapper similar to std::function for 0-3 argument functions. template <typename> class Function; // Function implementation for zero argument functions. @@ -267,10 +272,12 @@ void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } - operator bool() const { return callableWrapper.target() != NULL; } + operator SafeBool() const { + return makeSafeBool(callableWrapper.target() != NULL); + } ResultType operator()() const { - return callableWrapper.target() ? (*callableWrapper.target())() + return callableWrapper.target() ? callableWrapper.target()->invoke() : ResultType(); } @@ -278,7 +285,7 @@ class Callable { public: virtual ~Callable() {} - virtual ResultType operator()() const = 0; + virtual ResultType invoke() const = 0; virtual Callable * clone() const = 0; virtual void clone(void * buffer) const = 0; }; @@ -287,7 +294,7 @@ public: CallableAdapter(F func) : func(func) {} - virtual ResultType operator()() const { return func(); } + virtual ResultType invoke() const { return func(); } virtual Callable * clone() const { return new CallableAdapter(*this); } @@ -338,10 +345,12 @@ void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } - operator bool() const { return callableWrapper.target() != NULL; } + operator SafeBool() const { + return makeSafeBool(callableWrapper.target() != NULL); + } ResultType operator()(ArgumentType arg) const { - return callableWrapper.target() ? (*callableWrapper.target())(arg) + return callableWrapper.target() ? callableWrapper.target()->invoke(arg) : ResultType(); } @@ -349,7 +358,7 @@ class Callable { public: virtual ~Callable() {} - virtual ResultType operator()(ArgumentType) const = 0; + virtual ResultType invoke(ArgumentType) const = 0; virtual Callable * clone() const = 0; virtual void clone(void * buffer) const = 0; }; @@ -358,7 +367,7 @@ public: CallableAdapter(F func) : func(func) {} - virtual ResultType operator()(ArgumentType arg) const { return func(arg); } + virtual ResultType invoke(ArgumentType arg) const { return func(arg); } virtual Callable * clone() const { return new CallableAdapter(*this); } @@ -414,19 +423,21 @@ void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } - operator bool() const { return callableWrapper.target() != NULL; } + operator SafeBool() const { + return makeSafeBool(callableWrapper.target() != NULL); + } ResultType operator()(FirstArgumentType arg1, SecondArgumentType arg2) const { - return callableWrapper.target() ? (*callableWrapper.target())(arg1, arg2) - : ResultType(); + return callableWrapper.target() + ? callableWrapper.target()->invoke(arg1, arg2) + : ResultType(); } private: class Callable { public: virtual ~Callable() {} - virtual ResultType operator()(FirstArgumentType, - SecondArgumentType) const = 0; + virtual ResultType invoke(FirstArgumentType, SecondArgumentType) const = 0; virtual Callable * clone() const = 0; virtual void clone(void * buffer) const = 0; }; @@ -435,8 +446,8 @@ public: CallableAdapter(F func) : func(func) {} - virtual ResultType operator()(FirstArgumentType arg1, - SecondArgumentType arg2) const { + virtual ResultType invoke(FirstArgumentType arg1, + SecondArgumentType arg2) const { return func(arg1, arg2); } @@ -461,6 +472,94 @@ lhs.swap(rhs); } +// Function implementation for three argument functions. +template <typename FirstArgumentType, typename SecondArgumentType, + typename ThirdArgumentType, typename ResultType> +class Function<ResultType(FirstArgumentType, SecondArgumentType, + ThirdArgumentType)> { +public: + typedef ResultType result_type; + + Function(ResultType (*func)(FirstArgumentType, SecondArgumentType, + ThirdArgumentType) = NULL) + : callableWrapper() { + if (func) { + callableWrapper = func; + } + } + + template <typename F> Function(F func) : callableWrapper(func) {} + + const Function & operator=(ResultType (*func)(FirstArgumentType, + SecondArgumentType, + ThirdArgumentType)) { + if (func) { + callableWrapper = func; + } else { + callableWrapper.clear(); + } + return *this; + } + + template <typename F> const Function & operator=(F func) { + callableWrapper = func; + return *this; + } + + void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } + + operator SafeBool() const { + return makeSafeBool(callableWrapper.target() != NULL); + } + + ResultType operator()(FirstArgumentType arg1, SecondArgumentType arg2, + ThirdArgumentType arg3) const { + return callableWrapper.target() + ? callableWrapper.target()->invoke(arg1, arg2, arg3) + : ResultType(); + } + +private: + class Callable { + public: + virtual ~Callable() {} + virtual ResultType invoke(FirstArgumentType, SecondArgumentType, + ThirdArgumentType) const = 0; + virtual Callable * clone() const = 0; + virtual void clone(void * buffer) const = 0; + }; + + template <typename F> class CallableAdapter : public Callable { + public: + CallableAdapter(F func) : func(func) {} + + virtual ResultType invoke(FirstArgumentType arg1, SecondArgumentType arg2, + ThirdArgumentType arg3) const { + return func(arg1, arg2, arg3); + } + + virtual Callable * clone() const { return new CallableAdapter(*this); } + + virtual void clone(void * buffer) const { + new (buffer) CallableAdapter(*this); + } + + private: + F func; + }; + + detail::TypeWrapper<Callable, CallableAdapter> callableWrapper; +}; + +template <typename FirstArgumentType, typename SecondArgumentType, + typename ThirdArgumentType, typename ResultType> +inline void swap(Function<ResultType(FirstArgumentType, SecondArgumentType, + ThirdArgumentType)> & lhs, + Function<ResultType(FirstArgumentType, SecondArgumentType, + ThirdArgumentType)> & rhs) { + lhs.swap(rhs); +} + } // namespace MaximInterface #endif
--- a/Utilities/HexConversions.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/HexConversions.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -30,31 +30,55 @@ * ownership rights. *******************************************************************************/ +#include <cctype> #include <cstdio> +#include <cstdlib> #include "HexConversions.hpp" +using std::string; +using std::vector; + namespace MaximInterface { -static const unsigned int charsPerByte = 2; +static const int charsPerByte = 2; -std::string byteArrayToHexString(const uint_least8_t * byteArray, - size_t byteArraySize) { - std::string hexString; - char hexBuf[charsPerByte + 1]; - for (size_t i = 0; i < byteArraySize; i++) { +string byteArrayToHexString(span<const uint_least8_t> byteArray) { + string hexString; + hexString.reserve(byteArray.size() * charsPerByte); + for (span<const uint_least8_t>::index_type i = 0; i < byteArray.size(); ++i) { + char hexBuf[charsPerByte + 1]; std::sprintf(hexBuf, "%2.2X", byteArray[i] & 0xFF); hexString.append(hexBuf, charsPerByte); } return hexString; } -std::vector<uint_least8_t> hexStringToByteArray(const std::string & hexString) { - std::vector<uint_least8_t> byteArray; - byteArray.reserve(hexString.size() / charsPerByte + 1); - for (std::string::size_type i = 0; i < hexString.size(); i += charsPerByte) { - unsigned int byte; - std::sscanf(hexString.substr(i, charsPerByte).c_str(), "%2x", &byte); - byteArray.push_back(byte); +optional<vector<uint_least8_t> > +hexStringToByteArray(const string & hexString) { + optional<vector<uint_least8_t> > byteArray = vector<uint_least8_t>(); + byteArray->reserve(hexString.size() / charsPerByte); + char hexBuf[charsPerByte + 1]; + char * const hexBufEnd = hexBuf + charsPerByte; + *hexBufEnd = '\0'; + char * hexBufIt = hexBuf; + for (string::const_iterator hexStringIt = hexString.begin(), + hexStringEnd = hexString.end(); + hexStringIt != hexStringEnd; ++hexStringIt) { + if (!std::isspace(*hexStringIt)) { + *hexBufIt = *hexStringIt; + if (++hexBufIt == hexBufEnd) { + char * hexBufParseEnd; + byteArray->push_back(static_cast<uint_least8_t>( + std::strtoul(hexBuf, &hexBufParseEnd, 16))); + if (hexBufParseEnd != hexBufEnd) { + break; + } + hexBufIt = hexBuf; + } + } + } + if (hexBufIt != hexBuf) { + byteArray.reset(); } return byteArray; }
--- a/Utilities/HexConversions.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/HexConversions.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -37,16 +37,18 @@ #include <stdint.h> #include <string> #include <vector> -#include <MaximInterface/Utilities/Export.h> +#include "Export.h" +#include "optional.hpp" +#include "span.hpp" namespace MaximInterface { /// Convert a byte array to a hex string. MaximInterface_EXPORT std::string -byteArrayToHexString(const uint_least8_t * byteArray, size_t byteArraySize); +byteArrayToHexString(span<const uint_least8_t> byteArray); /// Convert a hex string to a byte array. -MaximInterface_EXPORT std::vector<uint_least8_t> +MaximInterface_EXPORT optional<std::vector<uint_least8_t> > hexStringToByteArray(const std::string & hexString); } // namespace MaximInterface
--- a/Utilities/ManId.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/ManId.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -33,12 +33,12 @@ #ifndef MaximInterface_ManId #define MaximInterface_ManId -#include "array.hpp" +#include "array_span.hpp" namespace MaximInterface { /// Standard container for a manufacturer ID. -typedef array<uint_least8_t, 2> ManId; +typedef array_span<uint_least8_t, 2> ManId; } // namespace MaximInterface
--- a/Utilities/RomId.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/RomId.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -33,36 +33,48 @@ #ifndef MaximInterface_RomId #define MaximInterface_RomId -#include "array.hpp" +#include "array_span.hpp" #include "crc.hpp" namespace MaximInterface { /// Standard container for a 1-Wire ROM ID. -typedef array<uint_least8_t, 8> RomId; +typedef array_span<uint_least8_t, 8> RomId; +/// @name Family Code /// @{ -/// Access the Family Code byte. -inline RomId::value_type familyCode(const RomId & romId) { - return romId.front(); + +/// Get the Family Code byte. +inline RomId::element familyCode(RomId::const_span romId) { + return romId[0]; } -inline void setFamilyCode(RomId & romId, RomId::value_type familyCode) { - romId.front() = familyCode; + +/// Set the Family Code byte. +inline void setFamilyCode(RomId::span romId, RomId::element familyCode) { + romId[0] = familyCode; } + /// @} +/// @name CRC8 /// @{ -/// Access the CRC8 byte. -inline RomId::value_type crc8(const RomId & romId) { return romId.back(); } -inline void setCrc8(RomId & romId, RomId::value_type crc8) { - romId.back() = crc8; + +/// Get the CRC8 byte. +inline RomId::element crc8(RomId::const_span romId) { + return *romId.last<1>().data(); } + +/// Set the CRC8 byte. +inline void setCrc8(RomId::span romId, RomId::element crc8) { + *romId.last<1>().data() = crc8; +} + /// @} -/// Check if the ROM ID is valid (Family Code and CRC8 are both valid). +/// @brief Check if the ROM ID is valid (Family Code and CRC8 are both valid). /// @returns True if the ROM ID is valid. -inline bool valid(const RomId & romId) { - return calculateCrc8(romId.data(), romId.size() - 1) == crc8(romId); +inline bool valid(RomId::const_span romId) { + return calculateCrc8(romId.first(romId.size() - 1)) == crc8(romId); } } // namespace MaximInterface
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utilities/SafeBool.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -0,0 +1,67 @@ +/******************************************************************************* +* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#ifndef MaximInterface_SafeBool +#define MaximInterface_SafeBool + +#include <stddef.h> + +namespace MaximInterface { +namespace detail { + +// Implement SafeBool as a member function pointer since some compilers allow +// function pointer to void pointer conversion. +struct SafeBoolHelper { + void trueValue() const {} + +private: + SafeBoolHelper(); // deleted +}; + +} // namespace detail + +/// @brief Type definition for SafeBool. +/// @details +/// SafeBool is a boolean type that eliminates many error-prone implicit +/// conversions allowed by the fundamental bool type. +/// @note +/// SafeBool can be used to add an explicit bool conversion operator to a type. +typedef void (detail::SafeBoolHelper::*SafeBool)() const; + +/// Constructor for SafeBool. +inline SafeBool makeSafeBool(bool value) { + return value ? &detail::SafeBoolHelper::trueValue : NULL; +} + +} // namespace MaximInterface + +#endif
--- a/Utilities/Segment.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/Segment.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -39,8 +39,9 @@ namespace MaximInterface { +/// @brief /// Advances a given iterator by a given number of elements with bounds checking. -/// InputIt must meet the requirements of InputIterator. +/// @tparam InputIt Must meet the requirements of InputIterator. /// @param[in,out] it Iterator to advance. /// @param bound /// Past-the-end boundary iterator. If distance is positive, bound must be @@ -97,16 +98,19 @@ return distance; } -/// Locates an iterator sub-range using segment number addressing. Useful for -/// devices that divide the memory space into uniform chunks such as pages and -/// segments. ForwardIt must meet the requirements of ForwardIterator. +/// @brief Locates an iterator sub-range using segment number addressing. +/// @details +/// Useful for devices that divide the memory space into uniform chunks such as +/// pages and segments. +/// @tparam ForwardIt Must meet the requirements of ForwardIterator. /// @param begin Beginning of the input data range. /// @param end End of the input data range. /// @param segmentSize Number of elements contained in a segment. /// @param segmentNum Zero-indexed number of the desired segment. -/// @returns Pair of iterators representing the sub-range of the segment within +/// @returns +/// Pair of iterators representing the sub-range of the segment within /// the input range. If the segment does not exist within the input range, both -/// iterators in the pair are set to the end interator of the input range. +/// iterators in the pair are set to the end iterator of the input range. template <typename ForwardIt, typename Index> std::pair<ForwardIt, ForwardIt> createSegment( ForwardIt begin, const ForwardIt end,
--- a/Utilities/Sha256.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/Sha256.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -34,26 +34,24 @@ #define MaximInterface_Sha256 #include <stdint.h> -#include "array.hpp" +#include "array_span.hpp" namespace MaximInterface { namespace Sha256 { /// Container for a SHA-256 hash. -typedef array<uint_least8_t, 32> Hash; - -// Data used by SHA-256 MAC authenticators including DS28E15/22/25 and DS2465. +typedef array_span<uint_least8_t, 32> Hash; -/// Data for Compute Write MAC operation. -typedef array<uint_least8_t, 20> WriteMacData; +/// @brief Data for Compute Write MAC operation. +/// @details +/// Used by SHA-256 MAC authenticators including DS28E15/22/25 and DS2465. +typedef array_span<uint_least8_t, 20> WriteMacData; -/// Data for the Compute Auth. MAC operation. -typedef array<uint_least8_t, 76>AuthMacData; - -/// Data for the Compute Slave Secret operation. -typedef array<uint_least8_t, 76> SlaveSecretData; +/// @brief Data for the Compute Auth. MAC and Compute Slave Secret operations. +/// @copydetails WriteMacData +typedef array_span<uint_least8_t, 76> AuthenticationData; } // namespace Sha256 } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Utilities/Uncopyable.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/Uncopyable.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -47,4 +47,4 @@ } // namespace MaximInterface -#endif \ No newline at end of file +#endif
--- a/Utilities/WriteMessage.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/WriteMessage.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -43,4 +43,4 @@ } -#endif \ No newline at end of file +#endif
--- a/Utilities/array.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/array.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -55,58 +55,98 @@ typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - // Element access + /// @name Element access + /// @{ + reference operator[](size_type pos) { return const_cast<reference>( static_cast<const array &>(*this).operator[](pos)); } - const_reference operator[](size_type pos) const { return _buffer[pos]; } + + const_reference operator[](size_type pos) const { return data()[pos]; } + reference front() { return const_cast<reference>(static_cast<const array &>(*this).front()); } - const_reference front() const { return _buffer[0]; } + + const_reference front() const { return operator[](0); } + reference back() { return const_cast<reference>(static_cast<const array &>(*this).back()); } - const_reference back() const { return _buffer[size() - 1]; } + + const_reference back() const { return operator[](size() - 1); } + pointer data() { return const_cast<pointer>(static_cast<const array &>(*this).data()); } + const_pointer data() const { return _buffer; } + + /// @} - // Iterators + /// @name Iterators + /// @{ + iterator begin() { return const_cast<iterator>(static_cast<const array &>(*this).cbegin()); } + const_iterator begin() const { return cbegin(); } - const_iterator cbegin() const { return _buffer; } + + const_iterator cbegin() const { return data(); } + iterator end() { return const_cast<iterator>(static_cast<const array &>(*this).cend()); } + const_iterator end() const { return cend(); } - const_iterator cend() const { return _buffer + size(); } + + const_iterator cend() const { return cbegin() + size(); } + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const { return rbegin(); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const { return rend(); } + + /// @} - // Capacity + /// @name Capacity + /// @{ + static bool empty() { return size() == 0; } + static size_type size() { return N; } + static size_type max_size() { return size(); } - static const size_type csize = - N; ///< Alternative to size() when a constant expression is required. + + /// Alternative to size() when a constant expression is required. + static const size_type csize = N; + + /// @} - // Operations + /// @name Operations + /// @{ + void fill(const_reference value) { std::fill(begin(), end(), value); } + void swap(array & other) { std::swap_ranges(begin(), end(), other.begin()); } + + /// @} + /// @private + /// @note Implementation detail set public to allow aggregate initialization. T _buffer[N]; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utilities/array_span.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -0,0 +1,63 @@ +/******************************************************************************* +* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#ifndef MaximInterface_array_span +#define MaximInterface_array_span + +#include "array.hpp" +#include "span.hpp" +#include "type_traits.hpp" + +namespace MaximInterface { + +/// @brief +/// Defines a standard set of types for data fields that are represented as a +/// fixed-size array of elements. +/// @tparam T A const qualifier is not allowed. +template <typename T, size_t N> struct array_span { + typedef typename remove_volatile<T>::type element; + static const size_t size = N; + + typedef MaximInterface::array<element, N> array; + typedef MaximInterface::span<const T, N> const_span; + typedef MaximInterface::span<T, N> span; + +private: + array_span(); // deleted +}; + +// Specialization for "const T" is not defined. +template <typename T, size_t N> struct array_span<const T, N>; + +} + +#endif
--- a/Utilities/crc.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/crc.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -48,9 +48,8 @@ return crc; } -uint_fast8_t calculateCrc8(const uint_least8_t * data, size_t dataLen, - uint_fast8_t crc) { - for (size_t i = 0; i < dataLen; i++) { +uint_fast8_t calculateCrc8(span<const uint_least8_t> data, uint_fast8_t crc) { + for (span<const uint_least8_t>::index_type i = 0; i < data.size(); ++i) { crc = calculateCrc8(data[i], crc); } return crc; @@ -75,9 +74,9 @@ return crc; } -uint_fast16_t calculateCrc16(const uint_least8_t * data, size_t dataLen, +uint_fast16_t calculateCrc16(span<const uint_least8_t> data, uint_fast16_t crc) { - for (size_t i = 0; i < dataLen; i++) { + for (span<const uint_least8_t>::index_type i = 0; i < data.size(); ++i) { crc = calculateCrc16(data[i], crc); } return crc;
--- a/Utilities/crc.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/crc.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -36,41 +36,37 @@ #include <stddef.h> #include <stdint.h> #include <MaximInterface/Utilities/Export.h> +#include "span.hpp" namespace MaximInterface { -/// Perform a CRC8 calculation. +/// @brief Perform a CRC8 calculation. /// @param data Data to pass though the CRC generator. /// @param crc Beginning state of the CRC generator. /// @returns The calculated CRC8. MaximInterface_EXPORT uint_fast8_t calculateCrc8(uint_fast8_t data, uint_fast8_t crc = 0); -/// Perform a CRC8 calculation with variable length data. +/// @brief Perform a CRC8 calculation with variable length data. /// @param[in] data Data array to pass through the CRC generator. -/// @param dataLen Length of the data array to process. /// @param crc Beginning state of the CRC generator. /// @returns The calculated CRC8. -MaximInterface_EXPORT uint_fast8_t calculateCrc8(const uint_least8_t * data, - size_t dataLen, +MaximInterface_EXPORT uint_fast8_t calculateCrc8(span<const uint_least8_t> data, uint_fast8_t crc = 0); -/// Perform a CRC16 calculation. +/// @brief Perform a CRC16 calculation. /// @param data Data to pass though the CRC generator. /// @param crc Beginning state of the CRC generator. /// @returns The calculated CRC16. MaximInterface_EXPORT uint_fast16_t calculateCrc16(uint_fast8_t data, uint_fast16_t crc = 0); -/// Perform a CRC16 calculation with variable length data. +/// @brief Perform a CRC16 calculation with variable length data. /// @param[in] data Data array to pass through the CRC generator. -/// @param data_offset Offset of the data array to begin processing. -/// @param data_len Length of the data array to process. /// @param crc Beginning state of the CRC generator. /// @returns The calculated CRC16. -MaximInterface_EXPORT uint_fast16_t calculateCrc16(const uint_least8_t * data, - size_t dataLen, - uint_fast16_t crc = 0); +MaximInterface_EXPORT uint_fast16_t +calculateCrc16(span<const uint_least8_t> data, uint_fast16_t crc = 0); } // namespace MaximInterface
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utilities/optional.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -0,0 +1,318 @@ +/******************************************************************************* +* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#ifndef MaximInterface_optional +#define MaximInterface_optional + +#include "SafeBool.hpp" + +// Include for std::swap. +#include <algorithm> +#include <utility> + +namespace MaximInterface { + +struct nullopt_t { + explicit nullopt_t(int) {} +}; + +static const nullopt_t nullopt(0); + +/// @brief Optional value container similar to std::optional. +/// @details +/// To prevent the need for aligned storage, this implementation imposes that +/// types must be DefaultConstructible, CopyConstructible, and CopyAssignable. +/// No exceptions are thrown when accessing a valueless optional. +template <typename T> class optional { +public: + typedef T value_type; + + optional() : value_(), has_value_(false) {} + + optional(nullopt_t) : value_(), has_value_(false) {} + + optional(const T & value) : value_(value), has_value_(true) {} + + template <typename U> + explicit optional(const optional<U> & other) + : value_(other.value_), has_value_(other.has_value_) {} + + optional & operator=(nullopt_t) { + reset(); + return *this; + } + + optional & operator=(const T & value) { + value_ = value; + has_value_ = true; + return *this; + } + + template <typename U> optional & operator=(const optional<U> & other) { + if (has_value_ || other.has_value_) { + value_ = other.value_; + has_value_ = other.has_value_; + } + return *this; + } + + bool has_value() const { return has_value_; } + + operator SafeBool() const { return makeSafeBool(has_value()); } + + const T & value() const { return value_; } + + T & value() { + return const_cast<T &>(static_cast<const optional &>(*this).value()); + } + + const T & operator*() const { return value(); } + + T & operator*() { + return const_cast<T &>(static_cast<const optional &>(*this).operator*()); + } + + const T * operator->() const { return &value(); } + + T * operator->() { + return const_cast<T *>(static_cast<const optional &>(*this).operator->()); + } + + const T & value_or(const T & default_value) const { + return has_value() ? value() : default_value; + } + + void swap(optional & other) { + if (has_value_ || other.has_value_) { + using std::swap; + swap(value_, other.value_); + swap(has_value_, other.has_value_); + } + } + + void reset() { + if (has_value_) { + has_value_ = false; + value_ = T(); + } + } + +private: + T value_; + bool has_value_; +}; + +template <typename T> optional<T> make_optional(const T & value) { + return value; +} + +template <typename T> void swap(optional<T> & lhs, optional<T> & rhs) { + lhs.swap(rhs); +} + +template <typename T, typename U> +bool operator==(const optional<T> & lhs, const optional<U> & rhs) { + if (lhs.has_value() != rhs.has_value()) { + return false; + } + if (!lhs.has_value()) { + return true; + } + return lhs.value() == rhs.value(); +} + +template <typename T, typename U> +bool operator!=(const optional<T> & lhs, const optional<U> & rhs) { + if (lhs.has_value() != rhs.has_value()) { + return true; + } + if (!lhs.has_value()) { + return false; + } + return lhs.value() != rhs.value(); +} + +template <typename T, typename U> +bool operator<(const optional<T> & lhs, const optional<U> & rhs) { + if (!rhs.has_value()) { + return false; + } + if (!lhs.has_value()) { + return true; + } + return lhs.value() < rhs.value(); +} + +template <typename T, typename U> +bool operator<=(const optional<T> & lhs, const optional<U> & rhs) { + if (!lhs.has_value()) { + return true; + } + if (!rhs.has_value()) { + return false; + } + return lhs.value() <= rhs.value(); +} + +template <typename T, typename U> +bool operator>(const optional<T> & lhs, const optional<U> & rhs) { + if (!lhs.has_value()) { + return false; + } + if (!rhs.has_value()) { + return true; + } + return lhs.value() > rhs.value(); +} + +template <typename T, typename U> +bool operator>=(const optional<T> & lhs, const optional<U> & rhs) { + if (!rhs.has_value()) { + return true; + } + if (!lhs.has_value()) { + return false; + } + return lhs.value() >= rhs.value(); +} + +template <typename T> bool operator==(const optional<T> & opt, nullopt_t) { + return !opt.has_value(); +} + +template <typename T> bool operator==(nullopt_t, const optional<T> & opt) { + return operator==(opt, nullopt); +} + +template <typename T> bool operator!=(const optional<T> & opt, nullopt_t) { + return !operator==(opt, nullopt); +} + +template <typename T> bool operator!=(nullopt_t, const optional<T> & opt) { + return operator!=(opt, nullopt); +} + +template <typename T> bool operator<(const optional<T> &, nullopt_t) { + return false; +} + +template <typename T> bool operator<(nullopt_t, const optional<T> & opt) { + return opt.has_value(); +} + +template <typename T> bool operator<=(const optional<T> & opt, nullopt_t) { + return !operator>(opt, nullopt); +} + +template <typename T> bool operator<=(nullopt_t, const optional<T> & opt) { + return !operator>(nullopt, opt); +} + +template <typename T> bool operator>(const optional<T> & opt, nullopt_t) { + return operator<(nullopt, opt); +} + +template <typename T> bool operator>(nullopt_t, const optional<T> & opt) { + return operator<(opt, nullopt); +} + +template <typename T> bool operator>=(const optional<T> & opt, nullopt_t) { + return !operator<(opt, nullopt); +} + +template <typename T> bool operator>=(nullopt_t, const optional<T> & opt) { + return !operator<(nullopt, opt); +} + +template <typename T, typename U> +bool operator==(const optional<T> & opt, const U & value) { + return opt.has_value() ? opt.value() == value : false; +} + +template <typename T, typename U> +bool operator==(const T & value, const optional<U> & opt) { + return operator==(opt, value); +} + +template <typename T, typename U> +bool operator!=(const optional<T> & opt, const U & value) { + return opt.has_value() ? opt.value() != value : true; +} + +template <typename T, typename U> +bool operator!=(const T & value, const optional<U> & opt) { + return operator!=(opt, value); +} + +template <typename T, typename U> +bool operator<(const optional<T> & opt, const U & value) { + return opt.has_value() ? opt.value() < value : true; +} + +template <typename T, typename U> +bool operator<(const T & value, const optional<U> & opt) { + return opt.has_value() ? value < opt.value() : false; +} + +template <typename T, typename U> +bool operator<=(const optional<T> & opt, const U & value) { + return opt.has_value() ? opt.value() <= value : true; +} + +template <typename T, typename U> +bool operator<=(const T & value, const optional<U> & opt) { + return opt.has_value() ? value <= opt.value() : false; +} + +template <typename T, typename U> +bool operator>(const optional<T> & opt, const U & value) { + return opt.has_value() ? opt.value() > value : false; +} + +template <typename T, typename U> +bool operator>(const T & value, const optional<U> & opt) { + return opt.has_value() ? value > opt.value() : true; +} + +template <typename T, typename U> +bool operator>=(const optional<T> & opt, const U & value) { + return opt.has_value() ? opt.value() >= value : false; +} + +template <typename T, typename U> +bool operator>=(const T & value, const optional<U> & opt) { + return opt.has_value() ? value >= opt.value() : true; +} + +} // namespace MaximInterface + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utilities/span.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -0,0 +1,366 @@ +/******************************************************************************* +* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#ifndef MaximInterface_span +#define MaximInterface_span + +#include <stddef.h> +#include <algorithm> +#include <iterator> +#include <vector> +#include "array.hpp" +#include "type_traits.hpp" + +namespace MaximInterface { + +static const ptrdiff_t dynamic_extent = -1; + +struct with_container_t { + explicit with_container_t(int) {} +}; + +static const with_container_t with_container(0); + +namespace detail { + +template <template <typename, ptrdiff_t = MaximInterface::dynamic_extent> + class span, + typename T, ptrdiff_t Extent> +class span_base { +public: + typedef T element_type; + typedef typename remove_cv<element_type>::type value_type; + typedef ptrdiff_t index_type; + typedef ptrdiff_t difference_type; + typedef element_type * pointer; + typedef element_type & reference; + typedef element_type * iterator; + typedef const element_type * const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + static const index_type extent = Extent; + +protected: + span_base(pointer data) : data_(data) {} + ~span_base() {} + +public: + /// @name Iterators + /// @{ + + iterator begin() const { + return const_cast<iterator>(static_cast<const span_base &>(*this).cbegin()); + } + + const_iterator cbegin() const { return data(); } + + iterator end() const { + return const_cast<iterator>(static_cast<const span_base &>(*this).cend()); + } + + const_iterator cend() const { return cbegin() + size(); } + + reverse_iterator rbegin() const { return reverse_iterator(end()); } + + const_reverse_iterator crbegin() const { + return const_reverse_iterator(cend()); + } + + reverse_iterator rend() const { return reverse_iterator(begin()); } + + const_reverse_iterator crend() const { + return const_reverse_iterator(cbegin()); + } + + /// @} + + /// @name Element access + /// @{ + + reference operator[](index_type idx) const { return data()[idx]; } + + reference operator()(index_type idx) const { return operator[](idx); } + + pointer data() const { return data_; } + + /// @} + + /// @name Subviews + /// @{ + + template <index_type Count> span<element_type, Count> first() const { + return subspan<0, Count>(); + } + + span<element_type> first(index_type Count) const { return subspan(0, Count); } + + span<element_type> last(index_type Count) const { + return subspan(size() - Count, Count); + } + + template <index_type Offset, index_type Count> + span<element_type, Count> subspan() const { + return span<element_type, Count>(data() + Offset, Count); + } + + span<element_type> subspan(index_type Offset, + index_type Count = dynamic_extent) const { + return span<element_type>( + data() + Offset, Count == dynamic_extent ? size() - Offset : Count); + } + + /// @} + +private: + index_type size() const { + return static_cast<const span<T, Extent> &>(*this).size(); + } + + pointer data_; +}; + +} // namespace detail + +/// Generic memory span class similar to gsl::span or the proposed std::span. +template <typename T, ptrdiff_t Extent = dynamic_extent> +class span : public detail::span_base<MaximInterface::span, T, Extent> { + typedef detail::span_base<MaximInterface::span, T, Extent> span_base; + +public: + using span_base::extent; + using typename span_base::element_type; + using typename span_base::index_type; + using typename span_base::pointer; + using typename span_base::value_type; + + span(pointer data, index_type) : span_base(data) {} + + span(pointer begin, pointer) : span_base(begin) {} + + span(element_type (&arr)[extent]) : span_base(arr) {} + + span(array<value_type, extent> & arr) : span_base(arr.data()) {} + + span(const array<value_type, extent> & arr) : span_base(arr.data()) {} + + template <typename U> span(const span<U, extent> & s) : span_base(s.data()) {} + + template <typename Allocator> + explicit span(std::vector<value_type, Allocator> & vec) + : span_base(&vec.front()) {} + + template <typename Allocator> + explicit span(const std::vector<value_type, Allocator> & vec) + : span_base(&vec.front()) {} + + template <typename Container> + span(with_container_t, Container & cont) : span_base(cont.data()) {} + + template <typename Container> + span(with_container_t, const Container & cont) : span_base(cont.data()) {} + + /// @name Observers + /// @{ + + static index_type size() { return extent; } + + static index_type size_bytes() { return size() * sizeof(element_type); } + + static bool empty() { return size() == 0; } + + /// @} + + /// @name Subviews + /// @{ + + template <index_type Count> span<element_type, Count> last() const { + return this->template subspan<extent - Count, Count>(); + } + + /// @} +}; + +template <typename T> +class span<T, dynamic_extent> + : public detail::span_base<MaximInterface::span, T, dynamic_extent> { + typedef detail::span_base<MaximInterface::span, T, dynamic_extent> span_base; + +public: + using typename span_base::element_type; + using typename span_base::index_type; + using typename span_base::pointer; + using typename span_base::value_type; + + span() : span_base(NULL), size_(0) {} + + span(pointer data, index_type size) : span_base(data), size_(size) {} + + span(pointer begin, pointer end) : span_base(begin), size_(end - begin) {} + + template <size_t N> span(element_type (&arr)[N]) : span_base(arr), size_(N) {} + + template <size_t N> + span(array<value_type, N> & arr) : span_base(arr.data()), size_(N) {} + + template <size_t N> + span(const array<value_type, N> & arr) : span_base(arr.data()), size_(N) {} + + template <typename U, ptrdiff_t N> + span(const span<U, N> & s) : span_base(s.data()), size_(s.size()) {} + + template <typename Allocator> + span(std::vector<value_type, Allocator> & vec) + : span_base(vec.empty() ? NULL : &vec.front()), size_(vec.size()) {} + + template <typename Allocator> + span(const std::vector<value_type, Allocator> & vec) + : span_base(vec.empty() ? NULL : &vec.front()), size_(vec.size()) {} + + template <typename Container> + span(with_container_t, Container & cont) + : span_base(cont.data()), size_(cont.size()) {} + + template <typename Container> + span(with_container_t, const Container & cont) + : span_base(cont.data()), size_(cont.size()) {} + + /// @name Observers + /// @{ + + index_type size() const { return size_; } + + index_type size_bytes() const { return size() * sizeof(element_type); } + + bool empty() const { return size() == 0; } + + /// @} + + /// @name Subviews + /// @{ + + template <index_type Count> span<element_type, Count> last() const { + return span<element_type, Count>(this->data() + (size() - Count), Count); + } + + /// @} + +private: + index_type size_; +}; + +template <typename T, ptrdiff_t Extent, typename U> +bool operator==(span<T, Extent> lhs, span<U, Extent> rhs) { + return lhs.size() == rhs.size() && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template <typename T, ptrdiff_t Extent, typename U> +bool operator!=(span<T, Extent> lhs, span<U, Extent> rhs) { + return !operator==(lhs, rhs); +} + +template <typename T, ptrdiff_t Extent, typename U> +bool operator<(span<T, Extent> lhs, span<U, Extent> rhs) { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), + rhs.end()); +} + +template <typename T, ptrdiff_t Extent, typename U> +bool operator>(span<T, Extent> lhs, span<U, Extent> rhs) { + return operator<(rhs, lhs); +} + +template <typename T, ptrdiff_t Extent, typename U> +bool operator<=(span<T, Extent> lhs, span<U, Extent> rhs) { + return !operator>(lhs, rhs); +} + +template <typename T, ptrdiff_t Extent, typename U> +bool operator>=(span<T, Extent> lhs, span<U, Extent> rhs) { + return !operator<(lhs, rhs); +} + +template <typename T> +span<T> make_span(T * data, typename span<T>::index_type size) { + return span<T>(data, size); +} + +template <typename T> span<T> make_span(T * begin, T * end) { + return span<T>(begin, end); +} + +template <typename T, size_t N> span<T, N> make_span(T (&arr)[N]) { + return span<T, N>(arr); +} + +template <typename T, size_t N> span<T, N> make_span(array<T, N> & arr) { + return arr; +} + +template <typename T, size_t N> +span<const T, N> make_span(const array<T, N> & arr) { + return arr; +} + +template <typename T, typename Allocator> +span<T> make_span(std::vector<T, Allocator> & vec) { + return vec; +} + +template <typename T, typename Allocator> +span<const T> make_span(const std::vector<T, Allocator> & vec) { + return vec; +} + +template <typename Container> +span<typename Container::value_type> make_span(with_container_t, + Container & cont) { + return span<typename Container::value_type>(with_container, cont); +} + +template <typename Container> +span<const typename Container::value_type> make_span(with_container_t, + const Container & cont) { + return span<const typename Container::value_type>(with_container, cont); +} + +/// Deep copy between static spans of the same size. +template <typename T, ptrdiff_t Extent, typename U> +typename enable_if<Extent != dynamic_extent>::type copy(span<T, Extent> src, + span<U, Extent> dst) { + std::copy(src.begin(), src.end(), dst.begin()); +} + +} // namespace MaximInterface + +#endif
--- a/Utilities/system_error.cpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/system_error.cpp Wed Apr 03 12:33:10 2019 +0000 @@ -35,6 +35,8 @@ namespace MaximInterface { +using std::string; + error_condition error_category::default_error_condition(int code) const { return error_condition(code, *this); } @@ -53,11 +55,42 @@ public: virtual const char * name() const { return "system"; } - virtual std::string message(int condition) const { + virtual string message(int condition) const { return defaultErrorMessage(condition); } } instance; return instance; } -} // namespace MaximInterface \ No newline at end of file +static string formatWhat(const error_code & ec) { + return string(ec.category().name()) + ' ' + ec.message(); +} + +template <typename T> +static string formatWhat(const error_code & ec, const T & what_arg) { + return string(what_arg) + ": " + formatWhat(ec); +} + +system_error::system_error(const error_code & ec) + : runtime_error(formatWhat(ec)), code_(ec) {} + +system_error::system_error(const error_code & ec, const string & what_arg) + : runtime_error(formatWhat(ec, what_arg)), code_(ec) {} + +system_error::system_error(const error_code & ec, const char * what_arg) + : runtime_error(formatWhat(ec, what_arg)), code_(ec) {} + +system_error::system_error(int ev, const error_category & ecat) + : runtime_error(formatWhat(error_code(ev, ecat))), code_(ev, ecat) {} + +system_error::system_error(int ev, const error_category & ecat, + const string & what_arg) + : runtime_error(formatWhat(error_code(ev, ecat), what_arg)), + code_(ev, ecat) {} + +system_error::system_error(int ev, const error_category & ecat, + const char * what_arg) + : runtime_error(formatWhat(error_code(ev, ecat), what_arg)), + code_(ev, ecat) {} + +} // namespace MaximInterface
--- a/Utilities/system_error.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/system_error.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -31,14 +31,17 @@ *******************************************************************************/ /// @file -/// Error handling constructs similar std::error_code, std::error_condition, and -/// std::error_category. +/// @brief +/// Error handling constructs similar to std::error_code, std::error_condition, +/// and std::error_category. #ifndef MaximInterface_system_error #define MaximInterface_system_error +#include <stdexcept> #include <string> -#include <MaximInterface/Utilities/Export.h> +#include "Export.h" +#include "SafeBool.hpp" #include "Uncopyable.hpp" namespace MaximInterface { @@ -51,20 +54,27 @@ virtual ~error_category() {} virtual const char * name() const = 0; + MaximInterface_EXPORT virtual error_condition default_error_condition(int code) const; + MaximInterface_EXPORT virtual bool equivalent(int code, const error_condition & condition) const; + MaximInterface_EXPORT virtual bool equivalent(const error_code & code, int condition) const; + virtual std::string message(int condition) const = 0; }; + inline bool operator==(const error_category & lhs, const error_category & rhs) { return &lhs == &rhs; } + inline bool operator!=(const error_category & lhs, const error_category & rhs) { return !operator==(lhs, rhs); } + inline bool operator<(const error_category & lhs, const error_category & rhs) { return &lhs < &rhs; } @@ -74,6 +84,7 @@ class error_condition { public: error_condition() : value_(0), category_(&system_category()) {} + error_condition(int value, const error_category & category) : value_(value), category_(&category) {} @@ -81,27 +92,35 @@ value_ = value; category_ = &category; } + void clear() { value_ = 0; category_ = &system_category(); } + int value() const { return value_; } + const error_category & category() const { return *category_; } + std::string message() const { return category().message(value()); } - operator bool() const { return value() != 0; } + + operator SafeBool() const { return makeSafeBool(value() != 0); } private: int value_; const error_category * category_; }; + inline bool operator==(const error_condition & lhs, const error_condition & rhs) { return (lhs.value() == rhs.value()) && (lhs.category() == rhs.category()); } + inline bool operator!=(const error_condition & lhs, const error_condition & rhs) { return !operator==(lhs, rhs); } + inline bool operator<(const error_condition & lhs, const error_condition & rhs) { return (lhs.category() < rhs.category()) || @@ -111,6 +130,7 @@ class error_code { public: error_code() : value_(0), category_(&system_category()) {} + error_code(int value, const error_category & category) : value_(value), category_(&category) {} @@ -118,28 +138,37 @@ value_ = value; category_ = &category; } + void clear() { value_ = 0; category_ = &system_category(); } + int value() const { return value_; } + const error_category & category() const { return *category_; } + error_condition default_error_condition() const { return category().default_error_condition(value()); } + std::string message() const { return category().message(value()); } - operator bool() const { return value() != 0; } + + operator SafeBool() const { return makeSafeBool(value() != 0); } private: int value_; const error_category * category_; }; + inline bool operator==(const error_code & lhs, const error_code & rhs) { return (lhs.value() == rhs.value()) && (lhs.category() == rhs.category()); } + inline bool operator!=(const error_code & lhs, const error_code & rhs) { return !operator==(lhs, rhs); } + inline bool operator<(const error_code & lhs, const error_code & rhs) { return (lhs.category() < rhs.category()) || ((lhs.category() == rhs.category()) && (lhs.value() < rhs.value())); @@ -156,16 +185,43 @@ return lhs.category().equivalent(lhs.value(), rhs) || rhs.category().equivalent(lhs, rhs.value()); } + inline bool operator!=(const error_code & lhs, const error_condition & rhs) { return !operator==(lhs, rhs); } + inline bool operator==(const error_condition & lhs, const error_code & rhs) { return operator==(rhs, lhs); } + inline bool operator!=(const error_condition & lhs, const error_code & rhs) { return !operator==(lhs, rhs); } +class system_error : public std::runtime_error { +public: + MaximInterface_EXPORT system_error(const error_code & ec); + + MaximInterface_EXPORT system_error(const error_code & ec, + const std::string & what_arg); + + MaximInterface_EXPORT system_error(const error_code & ec, + const char * what_arg); + + MaximInterface_EXPORT system_error(int ev, const error_category & ecat); + + MaximInterface_EXPORT system_error(int ev, const error_category & ecat, + const std::string & what_arg); + + MaximInterface_EXPORT system_error(int ev, const error_category & ecat, + const char * what_arg); + + const error_code & code() const { return code_; } + +private: + error_code code_; +}; + } // namespace MaximInterface #endif
--- a/Utilities/type_traits.hpp Tue Jul 24 08:33:31 2018 +0000 +++ b/Utilities/type_traits.hpp Wed Apr 03 12:33:10 2019 +0000 @@ -39,7 +39,8 @@ static const T value = v; typedef T value_type; typedef integral_constant<T, v> type; - operator T() { return v; } + operator value_type() const { return value; } + value_type operator()() const { return value; } }; typedef integral_constant<bool, true> true_type; @@ -71,6 +72,16 @@ struct alignment_of : integral_constant<size_t, sizeof(detail::alignment_of_helper<T>) - sizeof(T)> {}; + +template <typename T> struct remove_const { typedef T type; }; +template <typename T> struct remove_const<const T> { typedef T type; }; + +template <typename T> struct remove_volatile { typedef T type; }; +template <typename T> struct remove_volatile<volatile T> { typedef T type; }; + +template <typename T> struct remove_cv { + typedef typename remove_volatile<typename remove_const<T>::type>::type type; +}; } // namespace MaximInterface
--- a/clr.cmake Tue Jul 24 08:33:31 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -#[[***************************************************************************** -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES -* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -* -* Except as contained in this notice, the name of Maxim Integrated -* Products, Inc. shall not be used except as stated in the Maxim Integrated -* Products, Inc. Branding Policy. -* -* The mere transfer of this software does not imply any licenses -* of trade secrets, proprietary technology, copyrights, patents, -* trademarks, maskwork rights, or any other form of intellectual -* property whatsoever. Maxim Integrated Products, Inc. retains all -* ownership rights. -******************************************************************************]] - -include_guard() - -macro(initializeClr) - if(NOT MSVC) - message(SEND_ERROR "MSVC must be used for CLR compilation.") - endif() - string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") - string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHa /DNOMINMAX") -endmacro(initializeClr) - -function(enableClr target dotnetFrameworkVersion) - set(dotnetFrameworkDir - "C:/Program Files (x86)/Reference Assemblies/Microsoft/Framework/.NETFramework/${dotnetFrameworkVersion}") - set(ARGN "mscorlib.dll" ${ARGN}) - unset(dotnetReferences) - foreach(reference ${ARGN}) - if(NOT IS_ABSOLUTE ${reference}) - set(reference "${dotnetFrameworkDir}/${reference}") - endif() - list(APPEND dotnetReferences ${reference}) - endforeach() - - if(CMAKE_GENERATOR MATCHES "Visual Studio") - if(CMAKE_GENERATOR MATCHES "2005" OR CMAKE_GENERATOR MATCHES "2008") - message(SEND_ERROR "Visual Studio 2010 or later is required to build CLR target \"${target}\".") - endif() - - set_property(TARGET ${target} PROPERTY VS_GLOBAL_CLRSupport "true") - set_property(TARGET ${target} PROPERTY - VS_DOTNET_TARGET_FRAMEWORK_VERSION "${dotnetFrameworkVersion}") - set_property(TARGET ${target} PROPERTY VS_DOTNET_REFERENCES ${dotnetReferences}) - else() - unset(dotnetReferenceArgs) - foreach(reference ${dotnetReferences}) - list(APPEND dotnetReferenceArgs "/FU${reference}") - endforeach() - set_property(TARGET ${target} APPEND PROPERTY COMPILE_OPTIONS - "/AI${dotnetFrameworkDir}" - "/clr" - ${dotnetReferenceArgs} - "/clr:nostdlib") - endif() -endfunction(enableClr) \ No newline at end of file