Device interface library for multiple platforms including Mbed.
Dependents: DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#
Maxim Interface is a library framework focused on providing flexible and expressive hardware interfaces. Both communication interfaces such as I2C and 1-Wire and device interfaces such as DS18B20 are supported. Modern C++ concepts are used extensively while keeping compatibility with C++98/C++03 and requiring no external dependencies. The embedded-friendly design does not depend on exceptions or RTTI.
The full version of the project is hosted on GitLab: https://gitlab.com/iabenz/MaximInterface
Revision 8:5ea891c7d1a1, committed 2019-09-16
- Comitter:
- IanBenzMaxim
- Date:
- Mon Sep 16 11:13:37 2019 -0500
- Parent:
- 7:9cd16581b578
- Child:
- 9:fa054cc51fdb
- Commit message:
- Updated to version 2.0.
Changed in this revision
--- a/MaximInterfaceCore/Algorithm.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Algorithm.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_Algorithm -#define MaximInterfaceCore_Algorithm +#ifndef MaximInterfaceCore_Algorithm_hpp +#define MaximInterfaceCore_Algorithm_hpp #include <algorithm> #include "span.hpp"
--- a/MaximInterfaceCore/ChangeSizeType.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/ChangeSizeType.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,14 +30,14 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_ChangeSizeType -#define MaximInterfaceCore_ChangeSizeType +#ifndef MaximInterfaceCore_ChangeSizeType_hpp +#define MaximInterfaceCore_ChangeSizeType_hpp #include <stdint.h> #include <algorithm> #include <limits> +#include "Result.hpp" #include "span.hpp" -#include "system_error.hpp" namespace MaximInterfaceCore { @@ -50,10 +50,9 @@ /// @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) { +Result<void> changeSizeType(Func func, span<Data> data) { 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>(std::numeric_limits<DataSize>::max()) > static_cast<uintmax_t>(std::numeric_limits<NewSize>::max())) { @@ -62,15 +61,17 @@ const span<Data> chunk = data.subspan( dataIdx, std::min<DataSize>(data.size() - dataIdx, std::numeric_limits<NewSize>::max())); - result = func(chunk.data(), static_cast<NewSize>(chunk.size())); + MaximInterfaceCore_TRY( + func(chunk.data(), static_cast<NewSize>(chunk.size()))); dataIdx += chunk.size(); - } while (dataIdx < data.size() && !result); + } while (dataIdx < data.size()); } else { - result = func(data.data(), static_cast<NewSize>(data.size())); + MaximInterfaceCore_TRY( + func(data.data(), static_cast<NewSize>(data.size()))); } - return result; + return none; } } // namespace MaximInterfaceCore -#endif \ No newline at end of file +#endif
--- a/MaximInterfaceCore/Config.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Config.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"),
--- a/MaximInterfaceCore/Ecc256.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Ecc256.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -40,16 +40,29 @@ copy(src.y, dst.y); } +bool equal(Point::const_span lhs, Point::const_span rhs) { + return equal(lhs.x, rhs.x) && equal(lhs.y, rhs.y); +} + void copy(KeyPair::const_span src, KeyPair::span dst) { copy(src.privateKey, dst.privateKey); copy(src.publicKey, dst.publicKey); } +bool equal(KeyPair::const_span lhs, KeyPair::const_span rhs) { + return equal(lhs.privateKey, rhs.privateKey) && + equal(lhs.publicKey, rhs.publicKey); +} + void copy(Signature::const_span src, Signature::span dst) { copy(src.r, dst.r); copy(src.s, dst.s); } +bool equal(Signature::const_span lhs, Signature::const_span rhs) { + return equal(lhs.r, rhs.r) && equal(lhs.s, rhs.s); +} + PublicKey::span CertificateData::publicKey() { const PublicKey::span span = { make_span(result_).subspan<publicKeyIdx, Scalar::size>(),
--- a/MaximInterfaceCore/Ecc256.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Ecc256.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_Ecc256 -#define MaximInterfaceCore_Ecc256 +#ifndef MaximInterfaceCore_Ecc256_hpp +#define MaximInterfaceCore_Ecc256_hpp #include <stdint.h> #include "Algorithm.hpp" @@ -80,6 +80,9 @@ MaximInterfaceCore_EXPORT void copy(Point::const_span src, Point::span dst); +MaximInterfaceCore_EXPORT bool equal(Point::const_span lhs, + Point::const_span rhs); + typedef Scalar PrivateKey; typedef Point PublicKey; @@ -117,6 +120,9 @@ MaximInterfaceCore_EXPORT void copy(KeyPair::const_span src, KeyPair::span dst); +MaximInterfaceCore_EXPORT bool equal(KeyPair::const_span lhs, + KeyPair::const_span rhs); + struct Signature : Unconstructible { struct const_span { Scalar::const_span r; @@ -152,6 +158,9 @@ MaximInterfaceCore_EXPORT void copy(Signature::const_span src, Signature::span dst); +MaximInterfaceCore_EXPORT bool equal(Signature::const_span lhs, + Signature::const_span rhs); + /// Data used to create a device key certificate for ECC-256 authenticators. class CertificateData { public: @@ -229,11 +238,9 @@ /// @} 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; + static const size_t publicKeyIdx = 0; + static const size_t romIdIdx = publicKeyIdx + 2 * Scalar::size; + static const size_t manIdIdx = romIdIdx + RomId::size; Result::array result_; };
--- a/MaximInterfaceCore/Error.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Error.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"),
--- a/MaximInterfaceCore/Error.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Error.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_Error -#define MaximInterfaceCore_Error +#ifndef MaximInterfaceCore_Error_hpp +#define MaximInterfaceCore_Error_hpp #include "Config.hpp"
--- a/MaximInterfaceCore/FlagSet.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/FlagSet.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_FlagSet -#define MaximInterfaceCore_FlagSet +#ifndef MaximInterfaceCore_FlagSet_hpp +#define MaximInterfaceCore_FlagSet_hpp #include <stddef.h> #include <bitset> @@ -58,7 +58,7 @@ operator bool() const { return flagSet->test(flag); } - bool operator~() const { return reference(*this).flip(); } + bool operator~() const { return !*this; } reference & flip() { *this = !*this; @@ -93,7 +93,10 @@ reference operator[](Flag flag) { return reference(*this, flag); } - bool test(Flag flag) const { return (bits.to_ulong() & flag) == flag; } + bool test(Flag flag) const { + const unsigned long rawFlag = static_cast<unsigned long>(flag); + return (bits.to_ulong() & rawFlag) == rawFlag; + } bool any() const { return bits.any(); } @@ -136,10 +139,11 @@ } FlagSet & set(Flag flag, bool value = true) { + const unsigned long rawFlag = static_cast<unsigned long>(flag); if (value) { - bits |= flag; + bits |= rawFlag; } else { - bits &= ~std::bitset<flagBits>(flag); + bits &= ~rawFlag; } return *this; } @@ -157,7 +161,7 @@ } FlagSet & flip(Flag flag) { - bits ^= flag; + bits ^= static_cast<unsigned long>(flag); return *this; }
--- a/MaximInterfaceCore/Function.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Function.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,10 +30,11 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_Function -#define MaximInterfaceCore_Function +#ifndef MaximInterfaceCore_Function_hpp +#define MaximInterfaceCore_Function_hpp #include <stddef.h> +#include "None.hpp" #include "SafeBool.hpp" #include "type_traits.hpp" @@ -112,6 +113,8 @@ public: TypeWrapper() : currentTarget(NULL) {} + TypeWrapper(None) : currentTarget(NULL) {} + TypeWrapper(const TypeWrapper & other) { if (other.currentTarget == other.internalTarget) { other.currentTarget->clone(internalTarget); @@ -142,6 +145,11 @@ } } + const TypeWrapper & operator=(None) { + TypeWrapper().swap(*this); + return *this; + } + const TypeWrapper & operator=(const TypeWrapper & rhs) { TypeWrapper(rhs).swap(*this); return *this; @@ -152,8 +160,6 @@ return *this; } - void clear() { TypeWrapper().swap(*this); } - void swap(TypeWrapper & other) { if (this == &other) { return; @@ -201,6 +207,8 @@ public: TypeWrapper() : currentTarget(NULL) {} + TypeWrapper(None) : currentTarget(NULL) {} + TypeWrapper(const TypeWrapper & other) { if (other.currentTarget) { currentTarget = other.currentTarget->clone(); @@ -215,6 +223,11 @@ ~TypeWrapper() { delete currentTarget; } + const TypeWrapper & operator=(None) { + TypeWrapper().swap(*this); + return *this; + } + const TypeWrapper & operator=(const TypeWrapper & rhs) { TypeWrapper(rhs).swap(*this); return *this; @@ -225,8 +238,6 @@ return *this; } - void clear() { TypeWrapper().swap(*this); } - void swap(TypeWrapper & other) { using std::swap; swap(currentTarget, other.currentTarget); @@ -240,15 +251,19 @@ } // namespace detail -// Function wrapper similar to std::function for 0-3 argument functions. +/// %Function wrapper similar to std::function for 0-3 argument functions. template <typename> class Function; -// Function implementation for zero argument functions. +/// Function implementation for zero argument functions. template <typename ResultType> class Function<ResultType()> { public: typedef ResultType result_type; - Function(ResultType (*func)() = NULL) : callableWrapper() { + Function() : callableWrapper() {} + + Function(None) : callableWrapper() {} + + Function(ResultType (*func)()) : callableWrapper() { if (func) { callableWrapper = func; } @@ -256,11 +271,16 @@ template <typename F> Function(F func) : callableWrapper(func) {} + const Function & operator=(None) { + callableWrapper = none; + return *this; + } + const Function & operator=(ResultType (*func)()) { if (func) { callableWrapper = func; } else { - callableWrapper.clear(); + callableWrapper = none; } return *this; } @@ -314,14 +334,18 @@ lhs.swap(rhs); } -// Function implementation for one argument functions. +/// Function implementation for one argument functions. template <typename ArgumentType, typename ResultType> class Function<ResultType(ArgumentType)> { public: typedef ArgumentType argument_type; typedef ResultType result_type; - Function(ResultType (*func)(ArgumentType) = NULL) : callableWrapper() { + Function() : callableWrapper() {} + + Function(None) : callableWrapper() {} + + Function(ResultType (*func)(ArgumentType)) : callableWrapper() { if (func) { callableWrapper = func; } @@ -329,11 +353,16 @@ template <typename F> Function(F func) : callableWrapper(func) {} + const Function & operator=(None) { + callableWrapper = none; + return *this; + } + const Function & operator=(ResultType (*func)(ArgumentType)) { if (func) { callableWrapper = func; } else { - callableWrapper.clear(); + callableWrapper = none; } return *this; } @@ -388,7 +417,7 @@ lhs.swap(rhs); } -// Function implementation for two argument functions. +/// Function implementation for two argument functions. template <typename FirstArgumentType, typename SecondArgumentType, typename ResultType> class Function<ResultType(FirstArgumentType, SecondArgumentType)> { @@ -397,7 +426,11 @@ typedef SecondArgumentType second_argument_type; typedef ResultType result_type; - Function(ResultType (*func)(FirstArgumentType, SecondArgumentType) = NULL) + Function() : callableWrapper() {} + + Function(None) : callableWrapper() {} + + Function(ResultType (*func)(FirstArgumentType, SecondArgumentType)) : callableWrapper() { if (func) { callableWrapper = func; @@ -406,12 +439,17 @@ template <typename F> Function(F func) : callableWrapper(func) {} + const Function & operator=(None) { + callableWrapper = none; + return *this; + } + const Function & operator=(ResultType (*func)(FirstArgumentType, SecondArgumentType)) { if (func) { callableWrapper = func; } else { - callableWrapper.clear(); + callableWrapper = none; } return *this; } @@ -472,7 +510,7 @@ lhs.swap(rhs); } -// Function implementation for three argument functions. +/// Function implementation for three argument functions. template <typename FirstArgumentType, typename SecondArgumentType, typename ThirdArgumentType, typename ResultType> class Function<ResultType(FirstArgumentType, SecondArgumentType, @@ -480,8 +518,12 @@ public: typedef ResultType result_type; + Function() : callableWrapper() {} + + Function(None) : callableWrapper() {} + Function(ResultType (*func)(FirstArgumentType, SecondArgumentType, - ThirdArgumentType) = NULL) + ThirdArgumentType)) : callableWrapper() { if (func) { callableWrapper = func; @@ -490,13 +532,18 @@ template <typename F> Function(F func) : callableWrapper(func) {} + const Function & operator=(None) { + callableWrapper = none; + return *this; + } + const Function & operator=(ResultType (*func)(FirstArgumentType, SecondArgumentType, ThirdArgumentType)) { if (func) { callableWrapper = func; } else { - callableWrapper.clear(); + callableWrapper = none; } return *this; }
--- a/MaximInterfaceCore/HexConversions.cpp Mon Jul 22 11:44:07 2019 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +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 <cctype> -#include <cstdio> -#include <cstdlib> -#include "HexConversions.hpp" - -using std::string; -using std::vector; - -namespace MaximInterfaceCore { - -static const int charsPerByte = 2; - -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; -} - -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; -} - -} // namespace MaximInterfaceCore
--- a/MaximInterfaceCore/HexConversions.hpp Mon Jul 22 11:44:07 2019 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +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 MaximInterfaceCore_HexConversions -#define MaximInterfaceCore_HexConversions - -#include <stddef.h> -#include <stdint.h> -#include <string> -#include <vector> -#include "Config.hpp" -#include "Optional.hpp" -#include "span.hpp" - -namespace MaximInterfaceCore { - -/// Convert a byte array to a hex string. -MaximInterfaceCore_EXPORT std::string -byteArrayToHexString(span<const uint_least8_t> byteArray); - -/// Convert a hex string to a byte array. -MaximInterfaceCore_EXPORT Optional<std::vector<uint_least8_t> > -hexStringToByteArray(const std::string & hexString); - -} // namespace MaximInterfaceCore - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MaximInterfaceCore/HexString.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -0,0 +1,86 @@ +/******************************************************************************* +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* 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 <cctype> +#include <cstdio> +#include <cstdlib> +#include "HexString.hpp" + +namespace MaximInterfaceCore { + +using std::string; +using std::vector; + +static const int charsPerByte = 2; + +string toHexString(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; +} + +Optional<vector<uint_least8_t> > +fromHexString(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; +} + +} // namespace MaximInterfaceCore
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MaximInterfaceCore/HexString.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -0,0 +1,55 @@ +/******************************************************************************* +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* 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 MaximInterfaceCore_HexString_hpp +#define MaximInterfaceCore_HexString_hpp + +#include <stdint.h> +#include <string> +#include <vector> +#include "Config.hpp" +#include "Optional.hpp" +#include "span.hpp" + +namespace MaximInterfaceCore { + +/// Convert a byte array to a hex string. +MaximInterfaceCore_EXPORT std::string +toHexString(span<const uint_least8_t> byteArray); + +/// Convert a hex string to a byte array. +MaximInterfaceCore_EXPORT Optional<std::vector<uint_least8_t> > +fromHexString(const std::string & hexString); + +} // namespace MaximInterfaceCore + +#endif
--- a/MaximInterfaceCore/I2CMaster.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/I2CMaster.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -35,48 +35,46 @@ namespace MaximInterfaceCore { -error_code I2CMaster::writeBlock(span<const uint_least8_t> data) { - error_code result; - for (span<const uint_least8_t>::index_type i = 0; - i < data.size() && !result; ++i) { - result = writeByte(data[i]); +Result<void> I2CMaster::writeBlock(span<const uint_least8_t> data) { + for (span<const uint_least8_t>::index_type i = 0; i < data.size(); ++i) { + MaximInterfaceCore_TRY(writeByte(data[i])); } - return result; + return none; } -error_code I2CMaster::doWritePacket(uint_least8_t address, +Result<void> I2CMaster::writePacket(uint_least8_t address, span<const uint_least8_t> data, - bool sendStop) { - error_code result = start(address & 0xFE); - if (!result) { + DoStop doStop) { + Result<void> result = start(address & 0xFE); + if (result) { result = writeBlock(data); } - if (sendStop) { - error_code stopResult = stop(); - if (!result) { + if (doStop == Stop || (doStop == StopOnError && !result)) { + const Result<void> stopResult = stop(); + if (result) { result = stopResult; } } return result; } -error_code I2CMaster::readBlock(AckStatus status, span<uint_least8_t> data) { - error_code result; - for (span<uint_least8_t>::index_type i = 0; i < data.size() && !result; ++i) { - result = readByte(i == (data.size() - 1) ? status : Ack, data[i]); +Result<void> I2CMaster::readBlock(span<uint_least8_t> data, DoAck doAck) { + for (span<uint_least8_t>::index_type i = 0; i < data.size(); ++i) { + MaximInterfaceCore_TRY_VALUE( + data[i], readByte(i == (data.size() - 1) ? doAck : Ack)); } - return result; + return none; } -error_code I2CMaster::doReadPacket(uint_least8_t address, - span<uint_least8_t> data, bool sendStop) { - error_code result = start(address | 0x01); - if (!result) { - result = readBlock(Nack, data); +Result<void> I2CMaster::readPacket(uint_least8_t address, + span<uint_least8_t> data, DoStop doStop) { + Result<void> result = start(address | 0x01); + if (result) { + result = readBlock(data, Nack); } - if (sendStop) { - error_code stopResult = stop(); - if (!result) { + if (doStop == Stop || (doStop == StopOnError && !result)) { + const Result<void> stopResult = stop(); + if (result) { result = stopResult; } } @@ -92,10 +90,8 @@ switch (condition) { case NackError: return "Nack Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance;
--- a/MaximInterfaceCore/I2CMaster.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/I2CMaster.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,11 +30,12 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_I2CMaster -#define MaximInterfaceCore_I2CMaster +#ifndef MaximInterfaceCore_I2CMaster_hpp +#define MaximInterfaceCore_I2CMaster_hpp #include <stdint.h> #include "Config.hpp" +#include "Result.hpp" #include "span.hpp" #include "system_error.hpp" @@ -47,69 +48,58 @@ NackError = 1 ///< Transaction stopped due to a NACK from the slave device. }; - enum AckStatus { Nack, Ack }; + enum DoAck { Ack, Nack }; + + enum DoStop { Stop, StopOnError, NoStop }; virtual ~I2CMaster() {} /// @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; + virtual Result<void> start(uint_least8_t address) = 0; /// Send stop condition on the bus. - virtual error_code stop() = 0; + virtual Result<void> stop() = 0; /// Write data byte to the bus. - virtual error_code writeByte(uint_least8_t data) = 0; + virtual Result<void> writeByte(uint_least8_t data) = 0; /// Write data block to the bus. - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> writeBlock(span<const uint_least8_t> data); - /// @brief - /// Perform a complete write transaction on the bus with optional stop - /// condition. + /// @brief Perform a complete write transaction on the bus. /// @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, span<const uint_least8_t> data, - bool sendStop = true) { - return doWritePacket(address, data, sendStop); - } + /// @param doStop + /// Determines whether to do a stop condition or set up a repeated start. + MaximInterfaceCore_EXPORT virtual Result<void> + writePacket(uint_least8_t address, span<const uint_least8_t> data, + DoStop doStop); /// @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; + /// @param doAck Determines whether an ACK or NACK is done after reading. + /// @returns data Data read from the bus if successful. + virtual Result<uint_least8_t> readByte(DoAck doAck) = 0; /// @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. - MaximInterfaceCore_EXPORT virtual error_code - readBlock(AckStatus status, span<uint_least8_t> data); + /// @param doAck Determines whether an ACK or NACK is done after reading. + MaximInterfaceCore_EXPORT virtual Result<void> + readBlock(span<uint_least8_t> data, DoAck doAck); - /// @brief - /// Perform a complete read transaction on the bus with optional stop - /// condition. + /// @brief Perform a complete read transaction on the bus. /// @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, span<uint_least8_t> data, - bool sendStop = true) { - return doReadPacket(address, data, sendStop); - } + /// @param doStop + /// Determines whether to do a stop condition or set up a repeated start. + MaximInterfaceCore_EXPORT virtual Result<void> + readPacket(uint_least8_t address, span<uint_least8_t> data, DoStop doStop); MaximInterfaceCore_EXPORT static const error_category & errorCategory(); +}; -protected: - MaximInterfaceCore_EXPORT virtual error_code - doWritePacket(uint_least8_t address, span<const uint_least8_t> data, - bool sendStop); - - MaximInterfaceCore_EXPORT virtual error_code - doReadPacket(uint_least8_t address, span<uint_least8_t> data, bool sendStop); -}; +template <> struct is_error_code_enum<I2CMaster::ErrorValue> : true_type {}; inline error_code make_error_code(I2CMaster::ErrorValue e) { return error_code(e, I2CMaster::errorCategory());
--- a/MaximInterfaceCore/I2CMasterDecorator.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/I2CMasterDecorator.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -34,40 +34,39 @@ namespace MaximInterfaceCore { -error_code I2CMasterDecorator::start(uint_least8_t address) { +Result<void> I2CMasterDecorator::start(uint_least8_t address) { return master->start(address); } -error_code I2CMasterDecorator::stop() { return master->stop(); } +Result<void> I2CMasterDecorator::stop() { return master->stop(); } -error_code I2CMasterDecorator::writeByte(uint_least8_t data) { +Result<void> I2CMasterDecorator::writeByte(uint_least8_t data) { return master->writeByte(data); } -error_code I2CMasterDecorator::writeBlock(span<const uint_least8_t> data) { +Result<void> I2CMasterDecorator::writeBlock(span<const uint_least8_t> data) { return master->writeBlock(data); } -error_code I2CMasterDecorator::doWritePacket(uint_least8_t address, +Result<void> I2CMasterDecorator::writePacket(uint_least8_t address, span<const uint_least8_t> data, - bool sendStop) { - return master->writePacket(address, data, sendStop); + DoStop doStop) { + return master->writePacket(address, data, doStop); +} + +Result<uint_least8_t> I2CMasterDecorator::readByte(DoAck doAck) { + return master->readByte(doAck); } -error_code I2CMasterDecorator::readByte(AckStatus status, - uint_least8_t & data) { - return master->readByte(status, data); +Result<void> I2CMasterDecorator::readBlock(span<uint_least8_t> data, + DoAck doAck) { + return master->readBlock(data, doAck); } -error_code I2CMasterDecorator::readBlock(AckStatus status, - span<uint_least8_t> data) { - return master->readBlock(status, data); -} - -error_code I2CMasterDecorator::doReadPacket(uint_least8_t address, +Result<void> I2CMasterDecorator::readPacket(uint_least8_t address, span<uint_least8_t> data, - bool sendStop) { - return master->readPacket(address, data, sendStop); + DoStop doStop) { + return master->readPacket(address, data, doStop); } } // namespace MaximInterfaceCore
--- a/MaximInterfaceCore/I2CMasterDecorator.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/I2CMasterDecorator.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_I2CMasterDecorator -#define MaximInterfaceCore_I2CMasterDecorator +#ifndef MaximInterfaceCore_I2CMasterDecorator_hpp +#define MaximInterfaceCore_I2CMasterDecorator_hpp #include "Config.hpp" #include "I2CMaster.hpp" @@ -45,28 +45,26 @@ public: void setMaster(I2CMaster & master) { this->master = &master; } - MaximInterfaceCore_EXPORT virtual error_code start(uint_least8_t address); + MaximInterfaceCore_EXPORT virtual Result<void> start(uint_least8_t address); - MaximInterfaceCore_EXPORT virtual error_code stop(); + MaximInterfaceCore_EXPORT virtual Result<void> stop(); - MaximInterfaceCore_EXPORT virtual error_code writeByte(uint_least8_t data); + MaximInterfaceCore_EXPORT virtual Result<void> writeByte(uint_least8_t data); - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> writeBlock(span<const uint_least8_t> data); - MaximInterfaceCore_EXPORT virtual error_code readByte(AckStatus status, - uint_least8_t & data); + MaximInterfaceCore_EXPORT virtual Result<void> + writePacket(uint_least8_t address, span<const uint_least8_t> data, + DoStop doStop); - MaximInterfaceCore_EXPORT virtual error_code - readBlock(AckStatus status, span<uint_least8_t> data); + MaximInterfaceCore_EXPORT virtual Result<uint_least8_t> readByte(DoAck doAck); -protected: - MaximInterfaceCore_EXPORT virtual error_code - doWritePacket(uint_least8_t address, span<const uint_least8_t> data, - bool sendStop); + MaximInterfaceCore_EXPORT virtual Result<void> + readBlock(span<uint_least8_t> data, DoAck doAck); - MaximInterfaceCore_EXPORT virtual error_code - doReadPacket(uint_least8_t address, span<uint_least8_t> data, bool sendStop); + MaximInterfaceCore_EXPORT virtual Result<void> + readPacket(uint_least8_t address, span<uint_least8_t> data, DoStop doStop); private: I2CMaster * master;
--- a/MaximInterfaceCore/LoggingI2CMaster.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/LoggingI2CMaster.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -31,7 +31,7 @@ *******************************************************************************/ #include <utility> -#include "HexConversions.hpp" +#include "HexString.hpp" #include "LoggingI2CMaster.hpp" using std::string; @@ -47,7 +47,7 @@ if (read) { dataBuilder.append(1, '['); } - dataBuilder.append(byteArrayToHexString(data.subspan(i, 1))); + dataBuilder.append(toHexString(data.subspan(i, 1))); if (read) { dataBuilder.append(1, ']'); } @@ -63,72 +63,73 @@ messageBuilder.clear(); } -error_code LoggingI2CMaster::start(uint_least8_t address) { +Result<void> LoggingI2CMaster::start(uint_least8_t address) { messageBuilder.append(startString); messageBuilder.append(formatDataString(make_span(&address, 1), false)); return I2CMasterDecorator::start(address); } -error_code LoggingI2CMaster::stop() { +Result<void> LoggingI2CMaster::stop() { messageBuilder.append(stopString); tryWriteMessage(); return I2CMasterDecorator::stop(); } -error_code LoggingI2CMaster::writeByte(uint_least8_t data) { +Result<void> LoggingI2CMaster::writeByte(uint_least8_t data) { messageBuilder.append(formatDataString(make_span(&data, 1), false)); return I2CMasterDecorator::writeByte(data); } -error_code LoggingI2CMaster::writeBlock(span<const uint_least8_t> data) { +Result<void> LoggingI2CMaster::writeBlock(span<const uint_least8_t> data) { messageBuilder.append(formatDataString(data, false)); return I2CMasterDecorator::writeBlock(data); } -error_code LoggingI2CMaster::doWritePacket(uint_least8_t address, +Result<void> LoggingI2CMaster::writePacket(uint_least8_t address, span<const uint_least8_t> data, - bool sendStop) { + DoStop doStop) { messageBuilder.append(startString); messageBuilder.append(formatDataString(make_span(&address, 1), false)); - error_code result = - I2CMasterDecorator::doWritePacket(address, data, sendStop); - if (!result) { + const Result<void> result = + I2CMasterDecorator::writePacket(address, data, doStop); + if (result) { messageBuilder.append(formatDataString(data, false)); } - if (sendStop || result) { + if (doStop == Stop || (doStop == StopOnError && !result)) { messageBuilder.append(stopString); tryWriteMessage(); } return result; } -error_code LoggingI2CMaster::readByte(AckStatus status, uint_least8_t & data) { - error_code result = I2CMasterDecorator::readByte(status, data); - if (!result) { - messageBuilder.append(formatDataString(make_span(&data, 1), true)); +Result<uint_least8_t> LoggingI2CMaster::readByte(DoAck doAck) { + const Result<uint_least8_t> data = I2CMasterDecorator::readByte(doAck); + if (data) { + messageBuilder.append(formatDataString(make_span(&data.value(), 1), true)); } - return result; + return data; } -error_code LoggingI2CMaster::readBlock(AckStatus status, - span<uint_least8_t> data) { - error_code result = I2CMasterDecorator::readBlock(status, data); - if (!result) { +Result<void> LoggingI2CMaster::readBlock(span<uint_least8_t> data, + DoAck doAck) { + const Result<void> result = I2CMasterDecorator::readBlock(data, doAck); + if (result) { messageBuilder.append(formatDataString(data, true)); } return result; } -error_code LoggingI2CMaster::doReadPacket(uint_least8_t address, +Result<void> LoggingI2CMaster::readPacket(uint_least8_t address, span<uint_least8_t> data, - bool sendStop) { + DoStop doStop) { messageBuilder.append(startString); messageBuilder.append(formatDataString(make_span(&address, 1), false)); - error_code result = I2CMasterDecorator::doReadPacket(address, data, sendStop); - if (!result) { + const Result<void> result = + I2CMasterDecorator::readPacket(address, data, doStop); + if (result) { messageBuilder.append(formatDataString(data, true)); } - if (sendStop || result) { + if (doStop == Stop || (doStop == StopOnError && !result)) { messageBuilder.append(stopString); tryWriteMessage(); }
--- a/MaximInterfaceCore/LoggingI2CMaster.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/LoggingI2CMaster.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_LoggingI2CMaster -#define MaximInterfaceCore_LoggingI2CMaster +#ifndef MaximInterfaceCore_LoggingI2CMaster_hpp +#define MaximInterfaceCore_LoggingI2CMaster_hpp #include <string> #include "Config.hpp" @@ -50,27 +50,26 @@ this->writeMessage = writeMessage; } - MaximInterfaceCore_EXPORT virtual error_code start(uint_least8_t address); + MaximInterfaceCore_EXPORT virtual Result<void> start(uint_least8_t address); - MaximInterfaceCore_EXPORT virtual error_code stop(); + MaximInterfaceCore_EXPORT virtual Result<void> stop(); - MaximInterfaceCore_EXPORT virtual error_code writeByte(uint_least8_t data); + MaximInterfaceCore_EXPORT virtual Result<void> writeByte(uint_least8_t data); - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> writeBlock(span<const uint_least8_t> data); - MaximInterfaceCore_EXPORT virtual error_code readByte(AckStatus status, - uint_least8_t & data); - MaximInterfaceCore_EXPORT virtual error_code - readBlock(AckStatus status, span<uint_least8_t> data); + MaximInterfaceCore_EXPORT virtual Result<void> + writePacket(uint_least8_t address, span<const uint_least8_t> data, + DoStop doStop); + + MaximInterfaceCore_EXPORT virtual Result<uint_least8_t> readByte(DoAck doAck); -protected: - MaximInterfaceCore_EXPORT virtual error_code - doWritePacket(uint_least8_t address, span<const uint_least8_t> data, - bool sendStop); + MaximInterfaceCore_EXPORT virtual Result<void> + readBlock(span<uint_least8_t> data, DoAck doAck); - MaximInterfaceCore_EXPORT virtual error_code - doReadPacket(uint_least8_t address, span<uint_least8_t> data, bool sendStop); + MaximInterfaceCore_EXPORT virtual Result<void> + readPacket(uint_least8_t address, span<uint_least8_t> data, DoStop doStop); private: void tryWriteMessage();
--- a/MaximInterfaceCore/LoggingOneWireMaster.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/LoggingOneWireMaster.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,7 +30,7 @@ * ownership rights. *******************************************************************************/ -#include "HexConversions.hpp" +#include "HexString.hpp" #include "LoggingOneWireMaster.hpp" using std::string; @@ -45,7 +45,7 @@ if (read) { dataBuilder.append(1, '['); } - dataBuilder.append(byteArrayToHexString(data.subspan(i, 1))); + dataBuilder.append(toHexString(data.subspan(i, 1))); if (read) { dataBuilder.append(1, ']'); } @@ -60,14 +60,14 @@ } } -error_code LoggingOneWireMaster::reset() { - error_code result = OneWireMasterDecorator::reset(); - tryWriteMessage(!result ? "RP" : "RN"); +Result<void> LoggingOneWireMaster::reset() { + Result<void> result = OneWireMasterDecorator::reset(); + tryWriteMessage(result ? "RP" : "RN"); return result; } -error_code LoggingOneWireMaster::writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel) { +Result<void> LoggingOneWireMaster::writeByteSetLevel(uint_least8_t sendByte, + Level afterLevel) { tryWriteMessage(formatDataString(make_span(&sendByte, 1), false)); if (afterLevel == StrongLevel) { tryWriteMessage(strongLevelString); @@ -75,35 +75,35 @@ return OneWireMasterDecorator::writeByteSetLevel(sendByte, afterLevel); } -error_code LoggingOneWireMaster::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { - error_code result = - OneWireMasterDecorator::readByteSetLevel(recvByte, afterLevel); - if (!result) { - tryWriteMessage(formatDataString(make_span(&recvByte, 1), true)); +Result<uint_least8_t> LoggingOneWireMaster::readByteSetLevel(Level afterLevel) { + const Result<uint_least8_t> recvByte = + OneWireMasterDecorator::readByteSetLevel(afterLevel); + if (recvByte) { + tryWriteMessage(formatDataString(make_span(&recvByte.value(), 1), true)); if (afterLevel == StrongLevel) { tryWriteMessage(strongLevelString); } } - return result; + return recvByte; } -error_code LoggingOneWireMaster::writeBlock(span<const uint_least8_t> sendBuf) { +Result<void> +LoggingOneWireMaster::writeBlock(span<const uint_least8_t> sendBuf) { tryWriteMessage(formatDataString(sendBuf, false)); return OneWireMasterDecorator::writeBlock(sendBuf); } -error_code LoggingOneWireMaster::readBlock(span<uint_least8_t> recvBuf) { - error_code result = OneWireMasterDecorator::readBlock(recvBuf); - if (!result) { +Result<void> LoggingOneWireMaster::readBlock(span<uint_least8_t> recvBuf) { + Result<void> result = OneWireMasterDecorator::readBlock(recvBuf); + if (result) { tryWriteMessage(formatDataString(recvBuf, true)); } return result; } -error_code LoggingOneWireMaster::setSpeed(Speed newSpeed) { - error_code result = OneWireMasterDecorator::setSpeed(newSpeed); - if (!result) { +Result<void> LoggingOneWireMaster::setSpeed(Speed newSpeed) { + Result<void> result = OneWireMasterDecorator::setSpeed(newSpeed); + if (result) { string newSpeedString; switch (newSpeed) { case StandardSpeed: @@ -121,9 +121,9 @@ return result; } -error_code LoggingOneWireMaster::setLevel(Level newLevel) { - error_code result = OneWireMasterDecorator::setLevel(newLevel); - if (!result) { +Result<void> LoggingOneWireMaster::setLevel(Level newLevel) { + Result<void> result = OneWireMasterDecorator::setLevel(newLevel); + if (result) { string newLevelString; switch (newLevel) { case NormalLevel:
--- a/MaximInterfaceCore/LoggingOneWireMaster.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/LoggingOneWireMaster.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_LoggingOneWireMaster -#define MaximInterfaceCore_LoggingOneWireMaster +#ifndef MaximInterfaceCore_LoggingOneWireMaster_hpp +#define MaximInterfaceCore_LoggingOneWireMaster_hpp #include <string> #include "Config.hpp" @@ -51,23 +51,23 @@ this->writeMessage = writeMessage; } - MaximInterfaceCore_EXPORT virtual error_code reset(); + MaximInterfaceCore_EXPORT virtual Result<void> reset(); - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); - MaximInterfaceCore_EXPORT virtual error_code - readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterfaceCore_EXPORT virtual Result<uint_least8_t> + readByteSetLevel(Level afterLevel); - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> writeBlock(span<const uint_least8_t> sendBuf); - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> readBlock(span<uint_least8_t> recvBuf); - MaximInterfaceCore_EXPORT virtual error_code setSpeed(Speed newSpeed); + MaximInterfaceCore_EXPORT virtual Result<void> setSpeed(Speed newSpeed); - MaximInterfaceCore_EXPORT virtual error_code setLevel(Level newLevel); + MaximInterfaceCore_EXPORT virtual Result<void> setLevel(Level newLevel); private: void tryWriteMessage(const std::string & message);
--- a/MaximInterfaceCore/LoggingSleep.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/LoggingSleep.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"),
--- a/MaximInterfaceCore/LoggingSleep.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/LoggingSleep.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_LoggingSleep -#define MaximInterfaceCore_LoggingSleep +#ifndef MaximInterfaceCore_LoggingSleep_hpp +#define MaximInterfaceCore_LoggingSleep_hpp #include "Config.hpp" #include "SleepDecorator.hpp"
--- a/MaximInterfaceCore/ManId.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/ManId.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_ManId -#define MaximInterfaceCore_ManId +#ifndef MaximInterfaceCore_ManId_hpp +#define MaximInterfaceCore_ManId_hpp #include "array_span.hpp"
--- a/MaximInterfaceCore/None.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/None.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2019 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,17 +30,22 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_None -#define MaximInterfaceCore_None +#ifndef MaximInterfaceCore_None_hpp +#define MaximInterfaceCore_None_hpp namespace MaximInterfaceCore { +/// @brief Empty tag for use with Function, Optional, Result, and similar types. +/// @details A predefined instance called "none" is provided. +/// @see none struct None { - // Disable default constructor. + /// @private + /// @brief Disables default constructor. explicit None(int) {} }; -/// Empty tag for use with Optional and similar types. +/// @copybrief None +/// @details This is the predefined instance of the None type. static const None none(0); } // namespace MaximInterfaceCore
--- a/MaximInterfaceCore/OneWireMaster.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/OneWireMaster.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -33,71 +33,62 @@ #include "Error.hpp" #include "OneWireMaster.hpp" +#define TRY MaximInterfaceCore_TRY +#define TRY_VALUE MaximInterfaceCore_TRY_VALUE + namespace MaximInterfaceCore { static const int maxBitNum = 7; -error_code OneWireMaster::writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel) { - error_code result; - for (int bitNum = 0; (bitNum <= maxBitNum) && !result; ++bitNum) { - result = writeBitSetLevel(((sendByte >> bitNum) & 1) == 1, - (bitNum == maxBitNum) ? afterLevel : NormalLevel); +Result<void> OneWireMaster::writeByteSetLevel(uint_least8_t sendByte, + Level afterLevel) { + for (int bitNum = 0; bitNum <= maxBitNum; ++bitNum) { + TRY(writeBitSetLevel(((sendByte >> bitNum) & 1) == 1, + (bitNum == maxBitNum) ? afterLevel : NormalLevel)); } - return result; + return none; } -error_code OneWireMaster::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { - recvByte = 0; - error_code result; +Result<uint_least8_t> OneWireMaster::readByteSetLevel(Level afterLevel) { + uint_least8_t recvByte = 0; for (int bitNum = 0; bitNum <= maxBitNum; ++bitNum) { bool recvBit; - result = readBitSetLevel(recvBit, - (bitNum == maxBitNum) ? afterLevel : NormalLevel); - if (result) { - break; - } + TRY_VALUE(recvBit, readBitSetLevel((bitNum == maxBitNum) ? afterLevel + : NormalLevel)); if (recvBit) { recvByte |= (1 << bitNum); } } - return result; + return recvByte; } -error_code OneWireMaster::writeBlock(span<const uint_least8_t> sendBuf) { - error_code result; - for (span<const uint_least8_t>::index_type i = 0; - i < sendBuf.size() && !result; ++i) { - result = writeByte(sendBuf[i]); +Result<void> OneWireMaster::writeBlock(span<const uint_least8_t> sendBuf) { + for (span<const uint_least8_t>::index_type i = 0; i < sendBuf.size(); ++i) { + TRY(writeByte(sendBuf[i])); } - return result; + return none; } -error_code OneWireMaster::readBlock(span<uint_least8_t> recvBuf) { - error_code result; - for (span<uint_least8_t>::index_type i = 0; i < recvBuf.size() && !result; - ++i) { - result = readByte(recvBuf[i]); +Result<void> OneWireMaster::readBlock(span<uint_least8_t> recvBuf) { + for (span<uint_least8_t>::index_type i = 0; i < recvBuf.size(); ++i) { + TRY_VALUE(recvBuf[i], readByte()); } - return result; + return none; } -error_code OneWireMaster::triplet(TripletData & data) { - error_code result = readBit(data.readBit); - if (!result) { - result = readBit(data.readBitComplement); +Result<OneWireMaster::TripletData> OneWireMaster::triplet(bool sendBit) { + TripletData data; + TRY_VALUE(data.readBit, readBit()); + TRY_VALUE(data.readBitComplement, readBit()); + if (data.readBit) { + data.writeBit = 1; + } else if (data.readBitComplement) { + data.writeBit = 0; + } else { + data.writeBit = sendBit; } - if (!result) { - if (data.readBit) { - data.writeBit = 1; - } else if (data.readBitComplement) { - data.writeBit = 0; - } - // else: use data.writeBit parameter - result = writeBit(data.writeBit); - } - return result; + TRY(writeBit(data.writeBit)); + return data; } const error_category & OneWireMaster::errorCategory() { @@ -118,10 +109,8 @@ case InvalidLevelError: return "Invalid Level Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance;
--- a/MaximInterfaceCore/OneWireMaster.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/OneWireMaster.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,11 +30,12 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_OneWireMaster -#define MaximInterfaceCore_OneWireMaster +#ifndef MaximInterfaceCore_OneWireMaster_hpp +#define MaximInterfaceCore_OneWireMaster_hpp #include <stdint.h> #include "Config.hpp" +#include "Result.hpp" #include "span.hpp" #include "system_error.hpp" @@ -57,10 +58,11 @@ InvalidLevelError }; + /// Result of the 1-Wire triplet command. struct TripletData { - bool writeBit; bool readBit; bool readBitComplement; + bool writeBit; }; virtual ~OneWireMaster() {} @@ -69,114 +71,108 @@ /// 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. - virtual error_code reset() = 0; + virtual Result<void> reset() = 0; /// @brief /// Send and receive one bit of communication and set a new level on the /// 1-Wire bus. - /// @param[in,out] sendRecvBit - /// Input containing the bit to send and output containing the received bit. + /// @param sendBit Bit to send on the 1-Wire bus. /// @param afterLevel Level to set the 1-Wire bus to after communication. - virtual error_code touchBitSetLevel(bool & sendRecvBit, Level afterLevel) = 0; + /// @returns Bit received from the 1-Wire bus. + virtual Result<bool> touchBitSetLevel(bool sendBit, 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. - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> 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. - MaximInterfaceCore_EXPORT virtual error_code - readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + /// @returns Data received from the 1-Wire bus. + MaximInterfaceCore_EXPORT virtual Result<uint_least8_t> + readByteSetLevel(Level afterLevel); /// @brief Send a block of communication on the 1-Wire bus. /// @param[in] sendBuf Buffer to send on the 1-Wire bus. - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> writeBlock(span<const uint_least8_t> sendBuf); /// @brief Receive a block of communication on the 1-Wire bus. /// @param[out] recvBuf Buffer to receive the data from the 1-Wire bus. - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> readBlock(span<uint_least8_t> recvBuf); /// Set the 1-Wire bus communication speed. - virtual error_code setSpeed(Speed newSpeed) = 0; + virtual Result<void> setSpeed(Speed newSpeed) = 0; /// Set the 1-Wire bus level. - virtual error_code setLevel(Level newLevel) = 0; + virtual Result<void> setLevel(Level newLevel) = 0; /// @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 - /// Input with desired writeBit in case both read bits are zero. - /// Output with all data fields set. - MaximInterfaceCore_EXPORT virtual error_code triplet(TripletData & data); + /// @param sendBit Bit to send in case both read bits are zero. + MaximInterfaceCore_EXPORT virtual Result<TripletData> triplet(bool sendBit); /// @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. - error_code writeBitSetLevel(bool sendBit, Level afterLevel) { - return touchBitSetLevel(sendBit, afterLevel); + Result<void> writeBitSetLevel(bool sendBit, Level afterLevel) { + MaximInterfaceCore_TRY(touchBitSetLevel(sendBit, afterLevel)); + return none; } /// @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. - error_code readBitSetLevel(bool & recvBit, Level afterLevel) { - recvBit = 1; - return touchBitSetLevel(recvBit, afterLevel); + /// @returns Received data from the 1-Wire bus. + Result<bool> readBitSetLevel(Level afterLevel) { + return touchBitSetLevel(1, afterLevel); } // Alternate forms of the read and write functions. - error_code touchBit(bool & sendRecvBit) { - return touchBitSetLevel(sendRecvBit, NormalLevel); + Result<bool> touchBit(bool sendBit) { + return touchBitSetLevel(sendBit, NormalLevel); } - error_code writeBit(bool sendBit) { + Result<void> writeBit(bool sendBit) { return writeBitSetLevel(sendBit, NormalLevel); } - error_code readBit(bool & recvBit) { - return readBitSetLevel(recvBit, NormalLevel); - } + Result<bool> readBit() { return readBitSetLevel(NormalLevel); } - error_code writeBitPower(bool sendBit) { + Result<void> writeBitPower(bool sendBit) { return writeBitSetLevel(sendBit, StrongLevel); } - error_code readBitPower(bool & recvBit) { - return readBitSetLevel(recvBit, StrongLevel); - } + Result<bool> readBitPower() { return readBitSetLevel(StrongLevel); } - error_code writeByte(uint_least8_t sendByte) { + Result<void> writeByte(uint_least8_t sendByte) { return writeByteSetLevel(sendByte, NormalLevel); } - error_code readByte(uint_least8_t & recvByte) { - return readByteSetLevel(recvByte, NormalLevel); - } + Result<uint_least8_t> readByte() { return readByteSetLevel(NormalLevel); } - error_code writeBytePower(uint_least8_t sendByte) { + Result<void> writeBytePower(uint_least8_t sendByte) { return writeByteSetLevel(sendByte, StrongLevel); } - error_code readBytePower(uint_least8_t & recvByte) { - return readByteSetLevel(recvByte, StrongLevel); + Result<uint_least8_t> readBytePower() { + return readByteSetLevel(StrongLevel); } MaximInterfaceCore_EXPORT static const error_category & errorCategory(); }; +template <> struct is_error_code_enum<OneWireMaster::ErrorValue> : true_type {}; + inline error_code make_error_code(OneWireMaster::ErrorValue e) { return error_code(e, OneWireMaster::errorCategory()); }
--- a/MaximInterfaceCore/OneWireMasterDecorator.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/OneWireMasterDecorator.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -34,42 +34,43 @@ namespace MaximInterfaceCore { -error_code OneWireMasterDecorator::reset() { return master->reset(); } +Result<void> OneWireMasterDecorator::reset() { return master->reset(); } -error_code OneWireMasterDecorator::touchBitSetLevel(bool & sendRecvBit, - Level afterLevel) { - return master->touchBitSetLevel(sendRecvBit, afterLevel); +Result<bool> OneWireMasterDecorator::touchBitSetLevel(bool sendBit, + Level afterLevel) { + return master->touchBitSetLevel(sendBit, afterLevel); } -error_code OneWireMasterDecorator::writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel) { +Result<void> OneWireMasterDecorator::writeByteSetLevel(uint_least8_t sendByte, + Level afterLevel) { return master->writeByteSetLevel(sendByte, afterLevel); } -error_code OneWireMasterDecorator::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { - return master->readByteSetLevel(recvByte, afterLevel); +Result<uint_least8_t> +OneWireMasterDecorator::readByteSetLevel(Level afterLevel) { + return master->readByteSetLevel(afterLevel); } -error_code +Result<void> OneWireMasterDecorator::writeBlock(span<const uint_least8_t> sendBuf) { return master->writeBlock(sendBuf); } -error_code OneWireMasterDecorator::readBlock(span<uint_least8_t> recvBuf) { +Result<void> OneWireMasterDecorator::readBlock(span<uint_least8_t> recvBuf) { return master->readBlock(recvBuf); } -error_code OneWireMasterDecorator::setSpeed(Speed newSpeed) { +Result<void> OneWireMasterDecorator::setSpeed(Speed newSpeed) { return master->setSpeed(newSpeed); } -error_code OneWireMasterDecorator::setLevel(Level newLevel) { +Result<void> OneWireMasterDecorator::setLevel(Level newLevel) { return master->setLevel(newLevel); } -error_code OneWireMasterDecorator::triplet(TripletData & data) { - return master->triplet(data); +Result<OneWireMaster::TripletData> +OneWireMasterDecorator::triplet(bool sendBit) { + return master->triplet(sendBit); } } // namespace MaximInterfaceCore
--- a/MaximInterfaceCore/OneWireMasterDecorator.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/OneWireMasterDecorator.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_OneWireMasterDecorator -#define MaximInterfaceCore_OneWireMasterDecorator +#ifndef MaximInterfaceCore_OneWireMasterDecorator_hpp +#define MaximInterfaceCore_OneWireMasterDecorator_hpp #include "Config.hpp" #include "OneWireMaster.hpp" @@ -45,28 +45,28 @@ public: void setMaster(OneWireMaster & master) { this->master = &master; } - MaximInterfaceCore_EXPORT virtual error_code reset(); + MaximInterfaceCore_EXPORT virtual Result<void> reset(); - MaximInterfaceCore_EXPORT virtual error_code - touchBitSetLevel(bool & sendRecvBit, Level afterLevel); + MaximInterfaceCore_EXPORT virtual Result<bool> + touchBitSetLevel(bool sendBit, Level afterLevel); - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); - MaximInterfaceCore_EXPORT virtual error_code - readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterfaceCore_EXPORT virtual Result<uint_least8_t> + readByteSetLevel(Level afterLevel); - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> writeBlock(span<const uint_least8_t> sendBuf); - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> readBlock(span<uint_least8_t> recvBuf); - MaximInterfaceCore_EXPORT virtual error_code setSpeed(Speed newSpeed); + MaximInterfaceCore_EXPORT virtual Result<void> setSpeed(Speed newSpeed); - MaximInterfaceCore_EXPORT virtual error_code setLevel(Level newLevel); + MaximInterfaceCore_EXPORT virtual Result<void> setLevel(Level newLevel); - MaximInterfaceCore_EXPORT virtual error_code triplet(TripletData & data); + MaximInterfaceCore_EXPORT virtual Result<TripletData> triplet(bool sendBit); private: OneWireMaster * master;
--- a/MaximInterfaceCore/Optional.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Optional.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_Optional -#define MaximInterfaceCore_Optional +#ifndef MaximInterfaceCore_Optional_hpp +#define MaximInterfaceCore_Optional_hpp #include "None.hpp" #include "SafeBool.hpp" @@ -42,7 +42,7 @@ namespace MaximInterfaceCore { -/// @brief Optional value container similar to std::optional. +/// @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. @@ -66,11 +66,19 @@ return *this; } + Optional & operator=(const T & value) { + value_ = value; + hasValue_ = true; + return *this; + } + template <typename U> Optional & operator=(const Optional<U> & other) { - if (hasValue_ || other.hasValue()) { - value_ = other.value(); - hasValue_ = other.hasValue(); - } + assign(other); + return *this; + } + + Optional & operator=(const Optional & other) { + assign(other); return *this; } @@ -116,6 +124,13 @@ } private: + template <typename U> void assign(const Optional<U> & other) { + if (hasValue_ || other.hasValue()) { + value_ = other.value(); + hasValue_ = other.hasValue(); + } + } + T value_; bool hasValue_; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MaximInterfaceCore/Result.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -0,0 +1,350 @@ +/******************************************************************************* +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* 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 MaximInterfaceCore_Result_hpp +#define MaximInterfaceCore_Result_hpp + +#include "None.hpp" +#include "Optional.hpp" +#include "SafeBool.hpp" +#include "system_error.hpp" + +// Include for std::swap. +#include <algorithm> +#include <utility> + +namespace MaximInterfaceCore { + +/// @brief Expected value container that holds either a value or an error. +/// @details +/// Result can be used to multiplex errors and values returned from functions +/// that may fail as an alternative to exceptions. +/// @tparam T +/// Must be void or meet the requirements for DefaultConstructible, +/// CopyConstructible, and CopyAssignable. +template <typename T> class Result { +public: + typedef T value_type; + + Result() : value_(), error_(), hasValue_(false) {} + + Result(const T & value) : value_(value), error_(), hasValue_(true) {} + + Result(const error_code & error) + : value_(), error_(error), hasValue_(false) {} + + template <typename ErrorCodeEnum> + Result(ErrorCodeEnum error, + typename enable_if<is_error_code_enum<ErrorCodeEnum>::value>::type * = + NULL) + : value_(), error_(error), hasValue_(false) {} + + template <typename U> + explicit Result(const Result<U> & other) + : value_(other.value()), error_(other.error()), + hasValue_(other.hasValue()) {} + + Result & operator=(const T & value) { + value_ = value; + error_.clear(); + hasValue_ = true; + return *this; + } + + Result & operator=(const error_code & error) { + error_ = error; + clearValue(); + return *this; + } + + template <typename ErrorCodeEnum> + typename enable_if<is_error_code_enum<ErrorCodeEnum>::value, Result &>::type + operator=(ErrorCodeEnum error) { + error_ = error; + clearValue(); + return *this; + } + + template <typename U> Result & operator=(const Result<U> & other) { + assign(other); + return *this; + } + + Result & operator=(const Result & other) { + assign(other); + return *this; + } + + bool hasValue() const { return hasValue_; } + + operator SafeBool() const { return makeSafeBool(hasValue()); } + + const T & value() const { return value_; } + + T & value() { + return const_cast<T &>(static_cast<const Result &>(*this).value()); + } + + const error_code & error() const { return error_; } + + error_code & error() { + return const_cast<error_code &>(static_cast<const Result &>(*this).error()); + } + + void swap(Result & other) { + using std::swap; + if (hasValue_ || other.hasValue_) { + swap(value_, other.value_); + swap(hasValue_, other.hasValue_); + } + swap(error_, other.error_); + } + +private: + void clearValue() { + if (hasValue_) { + hasValue_ = false; + value_ = T(); + } + } + + template <typename U> void assign(const Result<U> & other) { + if (hasValue_ || other.hasValue()) { + value_ = other.value(); + hasValue_ = other.hasValue(); + } + error_ = other.error(); + } + + T value_; + error_code error_; + bool hasValue_; +}; + +template <typename T> Result<T> makeResult(const T & value) { return value; } + +template <typename T> void swap(Result<T> & lhs, Result<T> & rhs) { + lhs.swap(rhs); +} + +template <typename T, typename U> +bool operator==(const Result<T> & lhs, const Result<U> & rhs) { + if (lhs.hasValue() != rhs.hasValue()) { + return false; + } + if (!lhs.hasValue()) { + return lhs.error() == rhs.error(); + } + return lhs.value() == rhs.value(); +} + +template <typename T, typename U> +bool operator!=(const Result<T> & lhs, const Result<U> & rhs) { + if (lhs.hasValue() != rhs.hasValue()) { + return true; + } + if (!lhs.hasValue()) { + return lhs.error() != rhs.error(); + } + return lhs.value() != rhs.value(); +} + +template <typename T, typename U> +typename enable_if<!is_error_code_enum<U>::value, bool>::type +operator==(const Result<T> & exp, const U & value) { + return exp.hasValue() ? exp.value() == value : false; +} + +template <typename T, typename U> +typename enable_if<!is_error_code_enum<T>::value, bool>::type +operator==(const T & value, const Result<U> & exp) { + return operator==(exp, value); +} + +template <typename T, typename U> +typename enable_if<!is_error_code_enum<U>::value, bool>::type +operator!=(const Result<T> & exp, const U & value) { + return exp.hasValue() ? exp.value() != value : true; +} + +template <typename T, typename U> +typename enable_if<!is_error_code_enum<T>::value, bool>::type +operator!=(const T & value, const Result<U> & exp) { + return operator!=(exp, value); +} + +template <typename T> +bool operator==(const Result<T> & exp, const error_code & error) { + return exp.hasValue() ? false : exp.error() == error; +} + +template <typename T> +bool operator==(const error_code & error, const Result<T> & exp) { + return operator==(exp, error); +} + +template <typename T> +bool operator!=(const Result<T> & exp, const error_code & error) { + return exp.hasValue() ? true : exp.error() != error; +} + +template <typename T> +bool operator!=(const error_code & error, const Result<T> & exp) { + return operator!=(exp, error); +} + +// Specialization for void. +template <> class Result<void> { +public: + typedef void value_type; + + Result() : error_(), hasValue_(false) {} + + Result(None) : error_(), hasValue_(true) {} + + Result(const error_code & error) : error_(error), hasValue_(false) {} + + template <typename ErrorCodeEnum> + Result(ErrorCodeEnum error, + typename enable_if<is_error_code_enum<ErrorCodeEnum>::value>::type * = + NULL) + : error_(error), hasValue_(false) {} + + bool hasValue() const { return hasValue_; } + + operator SafeBool() const { return makeSafeBool(hasValue()); } + + void value() const {} + + const error_code & error() const { return error_; } + + error_code & error() { + return const_cast<error_code &>(static_cast<const Result &>(*this).error()); + } + + void swap(Result & other) { + using std::swap; + swap(hasValue_, other.hasValue_); + swap(error_, other.error_); + } + +private: + error_code error_; + bool hasValue_; +}; + +inline Result<void> makeResult(None) { return none; } + +template <> +inline bool operator==(const Result<void> & lhs, const Result<void> & rhs) { + if (lhs.hasValue() != rhs.hasValue()) { + return false; + } + if (!lhs.hasValue()) { + return lhs.error() == rhs.error(); + } + return true; +} + +template <> +inline bool operator!=(const Result<void> & lhs, const Result<void> & rhs) { + if (lhs.hasValue() != rhs.hasValue()) { + return true; + } + if (!lhs.hasValue()) { + return lhs.error() != rhs.error(); + } + return false; +} + +template <> inline bool operator==(const Result<void> & exp, const None &) { + return exp.hasValue(); +} + +template <> inline bool operator==(const None &, const Result<void> & exp) { + return operator==(exp, none); +} + +template <> inline bool operator!=(const Result<void> & exp, const None &) { + return !operator==(exp, none); +} + +template <> inline bool operator!=(const None &, const Result<void> & exp) { + return operator!=(exp, none); +} + +namespace detail { + +template <typename T> Optional<error_code> TRY_helper(const Result<T> & expr) { + Optional<error_code> error; + if (!expr) { + error = expr.error(); + } + return error; +} + +template <typename T, typename U> +Optional<error_code> TRY_VALUE_helper(T & var, const Result<U> & expr) { + Optional<error_code> error; + if (expr) { + var = expr.value(); + } else { + error = expr.error(); + } + return error; +} + +} // namespace detail +} // namespace MaximInterfaceCore + +// clang-format off + +/// @brief +/// Evaluates an expression returning a Result type by continuing execution if +/// successful or returning the error to the calling function if unsuccessful. +#define MaximInterfaceCore_TRY(expr) \ + if (const ::MaximInterfaceCore::Optional< ::MaximInterfaceCore::error_code> \ + MaximInterfaceCore_TRY_error = \ + ::MaximInterfaceCore::detail::TRY_helper(expr)) \ + return MaximInterfaceCore_TRY_error.value() + +/// @brief +/// Evaluates an expression returning a non-void Result type by assigning the +/// value to the specified variable if successful or returning the error to the +/// calling function if unsuccessful. +#define MaximInterfaceCore_TRY_VALUE(var, expr) \ + if (const ::MaximInterfaceCore::Optional< ::MaximInterfaceCore::error_code> \ + MaximInterfaceCore_TRY_VALUE_error = \ + ::MaximInterfaceCore::detail::TRY_VALUE_helper(var, expr)) \ + return MaximInterfaceCore_TRY_VALUE_error.value() + +#endif
--- a/MaximInterfaceCore/RomCommands.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/RomCommands.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -34,16 +34,6 @@ namespace MaximInterfaceCore { -enum RomCmd { - ReadRomCmd = 0x33, - MatchRomCmd = 0x55, - SearchRomCmd = 0xF0, - SkipRomCmd = 0xCC, - ResumeRomCmd = 0xA5, - OverdriveSkipRomCmd = 0x3C, - OverdriveMatchRomCmd = 0x69 -}; - void skipCurrentFamily(SearchRomState & searchState) { // Set the last discrepancy to last family discrepancy. searchState.lastDiscrepancy = searchState.lastFamilyDiscrepancy; @@ -55,110 +45,112 @@ } } -error_code verifyRom(OneWireMaster & master, RomId::const_span romId) { +Result<void> verifyRom(OneWireMaster & master, RomId::const_span romId) { SearchRomState searchState(romId); - error_code result = searchRom(master, searchState); - if (result) { + Result<void> result = searchRom(master, searchState); + if (!result) { return result; } // Check if same device found. if (!equal(romId, make_span(searchState.romId))) { - result = make_error_code(OneWireMaster::NoSlaveError); + result = OneWireMaster::NoSlaveError; } return result; } -error_code readRom(OneWireMaster & master, RomId::span romId) { - error_code result = master.reset(); - if (result) { +Result<RomId::array> readRom(OneWireMaster & master) { + Result<void> result = master.reset(); + if (!result) { + return result.error(); + } + result = master.writeByte(0x33); + if (!result) { + return result.error(); + } + RomId::array romId; + result = master.readBlock(romId); + if (!result) { + return result.error(); + } + if (!valid(romId)) { + return OneWireMaster::NoSlaveError; + } + return romId; +} + +Result<void> skipRom(OneWireMaster & master) { + Result<void> result = master.reset(); + if (!result) { return result; } - 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); - } + result = master.writeByte(0xCC); return result; } -error_code skipRom(OneWireMaster & master) { - error_code result = master.reset(); - if (result) { +Result<void> matchRom(OneWireMaster & master, RomId::const_span romId) { + Result<void> result = master.reset(); + if (!result) { return result; } - result = master.writeByte(SkipRomCmd); - return result; -} - -error_code matchRom(OneWireMaster & master, RomId::const_span romId) { - error_code result = master.reset(); - if (result) { - return result; - } - result = master.writeByte(MatchRomCmd); - if (result) { + result = master.writeByte(0x55); + if (!result) { return result; } result = master.writeBlock(romId); return result; } -error_code overdriveSkipRom(OneWireMaster & master) { - error_code result = master.reset(); - if (result) { +Result<void> overdriveSkipRom(OneWireMaster & master) { + Result<void> result = master.reset(); + if (!result) { return result; } - result = master.writeByte(OverdriveSkipRomCmd); - if (result) { + result = master.writeByte(0x3C); + if (!result) { return result; } result = master.setSpeed(OneWireMaster::OverdriveSpeed); return result; } -error_code overdriveMatchRom(OneWireMaster & master, RomId::const_span romId) { - error_code result = master.reset(); - if (result) { +Result<void> overdriveMatchRom(OneWireMaster & master, + RomId::const_span romId) { + Result<void> result = master.reset(); + if (!result) { return result; } - result = master.writeByte(OverdriveMatchRomCmd); - if (result) { + result = master.writeByte(0x69); + if (!result) { return result; } result = master.setSpeed(OneWireMaster::OverdriveSpeed); - if (result) { + if (!result) { return result; } result = master.writeBlock(romId); return result; } -error_code resumeRom(OneWireMaster & master) { - error_code result = master.reset(); - if (result) { +Result<void> resumeRom(OneWireMaster & master) { + Result<void> result = master.reset(); + if (!result) { return result; } - result = master.writeByte(ResumeRomCmd); + result = master.writeByte(0xA5); return result; } -error_code searchRom(OneWireMaster & master, SearchRomState & searchState) { +Result<void> searchRom(OneWireMaster & master, SearchRomState & searchState) { if (searchState.lastDevice) { searchState = SearchRomState(); } - error_code result = master.reset(); - if (result) { + Result<void> result = master.reset(); + if (!result) { return result; } - result = master.writeByte(SearchRomCmd); - if (result) { + result = master.writeByte(0xF0); + if (!result) { return result; } @@ -178,12 +170,10 @@ (searchState.romId[idByteNumber] & idBitMask) == idBitMask; } - result = master.triplet(tripletData); - if (result) { - return result; - } + MaximInterfaceCore_TRY_VALUE(tripletData, + master.triplet(tripletData.writeBit)); if (tripletData.readBit && tripletData.readBitComplement) { - return make_error_code(OneWireMaster::NoSlaveError); + return OneWireMaster::NoSlaveError; } if (tripletData.writeBit) { @@ -202,7 +192,7 @@ } searchState = newSearchState; } else { - result = make_error_code(OneWireMaster::NoSlaveError); + result = OneWireMaster::NoSlaveError; } return result; }
--- a/MaximInterfaceCore/RomCommands.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/RomCommands.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -33,8 +33,8 @@ /// @file /// @brief ROM Commands for enumerating and selecting 1-Wire devices. -#ifndef MaximInterfaceCore_RomCommands -#define MaximInterfaceCore_RomCommands +#ifndef MaximInterfaceCore_RomCommands_hpp +#define MaximInterfaceCore_RomCommands_hpp #include <stdint.h> #include "Algorithm.hpp" @@ -63,7 +63,7 @@ explicit SearchRomState(RomId::element familyCode) : romId(), lastDiscrepancy(64), lastFamilyDiscrepancy(0), lastDevice(false) { - setFamilyCode(romId, familyCode); + romId.front() = familyCode; } }; @@ -73,23 +73,22 @@ MaximInterfaceCore_EXPORT void skipCurrentFamily(SearchRomState & searchState); /// Verify that the device with the specified ROM ID is present. -MaximInterfaceCore_EXPORT error_code verifyRom(OneWireMaster & master, - RomId::const_span romId); +MaximInterfaceCore_EXPORT Result<void> verifyRom(OneWireMaster & master, + RomId::const_span romId); /// @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. -MaximInterfaceCore_EXPORT error_code readRom(OneWireMaster & master, - RomId::span romId); +/// @returns ROM ID read from device. +MaximInterfaceCore_EXPORT Result<RomId::array> readRom(OneWireMaster & master); /// @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. -MaximInterfaceCore_EXPORT error_code skipRom(OneWireMaster & master); +MaximInterfaceCore_EXPORT Result<void> skipRom(OneWireMaster & master); /// @brief Use the Match ROM command to select the device by its known ID. /// @note @@ -97,8 +96,8 @@ /// Overdrive timing. /// @param master 1-Wire master for operation. /// @param[in] romId ROM ID of device to select. -MaximInterfaceCore_EXPORT error_code matchRom(OneWireMaster & master, - RomId::const_span romId); +MaximInterfaceCore_EXPORT Result<void> matchRom(OneWireMaster & master, + RomId::const_span romId); /// @brief Issue Overdrive Skip ROM command on bus. /// @note @@ -107,20 +106,20 @@ /// @note /// Only use this command with a single-drop bus. /// Data collisions will occur if there is more than one device on the bus. -MaximInterfaceCore_EXPORT error_code overdriveSkipRom(OneWireMaster & master); +MaximInterfaceCore_EXPORT Result<void> 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. -MaximInterfaceCore_EXPORT error_code overdriveMatchRom(OneWireMaster & master, - RomId::const_span romId); +MaximInterfaceCore_EXPORT Result<void> +overdriveMatchRom(OneWireMaster & master, RomId::const_span romId); /// @brief Perform a Resume ROM command on bus. /// @details /// Resumes communication with the last device selected through a Match ROM or /// Search ROM operation. -MaximInterfaceCore_EXPORT error_code resumeRom(OneWireMaster & master); +MaximInterfaceCore_EXPORT Result<void> resumeRom(OneWireMaster & master); /// @brief Find device on the 1-Wire bus. /// @details @@ -128,8 +127,8 @@ /// sequence. Begin with a new search state and continue using the same search /// state until the last device flag is set which indicates that all devices /// have been discovered. -MaximInterfaceCore_EXPORT error_code searchRom(OneWireMaster & master, - SearchRomState & searchState); +MaximInterfaceCore_EXPORT Result<void> searchRom(OneWireMaster & master, + SearchRomState & searchState); } // namespace MaximInterfaceCore
--- a/MaximInterfaceCore/RomId.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/RomId.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,49 +30,21 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_RomId -#define MaximInterfaceCore_RomId +#ifndef MaximInterfaceCore_RomId_hpp +#define MaximInterfaceCore_RomId_hpp #include "array_span.hpp" -#include "crc.hpp" +#include "Crc.hpp" namespace MaximInterfaceCore { /// Standard container for a 1-Wire ROM ID. typedef array_span<uint_least8_t, 8> RomId; -/// @name Family Code -/// @{ - -/// Get the Family Code byte. -inline RomId::element familyCode(RomId::const_span romId) { return romId[0]; } - -/// Set the Family Code byte. -inline void setFamilyCode(RomId::span romId, RomId::element familyCode) { - romId[0] = familyCode; -} - -/// @} - -/// @name 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; -} - -/// @} - /// @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(RomId::const_span romId) { - return calculateCrc8(romId.first(romId.size() - 1)) == crc8(romId); + return calculateCrc8(romId.first(romId.size() - 1)) == romId.back(); } } // namespace MaximInterfaceCore
--- a/MaximInterfaceCore/RunCommand.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/RunCommand.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,7 +30,7 @@ * ownership rights. *******************************************************************************/ -#include "crc.hpp" +#include "Crc.hpp" #include "Error.hpp" #include "I2CMaster.hpp" #include "OneWireMaster.hpp" @@ -58,37 +58,37 @@ return instance; } -error_code RunCommandWithOneWireMaster:: +Result<span<uint_least8_t> > RunCommandWithOneWireMaster:: operator()(span<const uint_least8_t> request, int delayTime, - span<uint_least8_t> & response) const { + span<uint_least8_t> response) const { // Write request. - error_code result = selectRom(*master); - if (result) { - return result; + Result<void> result = selectRom(*master); + if (!result) { + return result.error(); } uint_least8_t xpcBuffer[2] = {0x66, static_cast<uint_least8_t>(request.size())}; result = master->writeBlock(xpcBuffer); - if (result) { - return result; + if (!result) { + return result.error(); } result = master->writeBlock(request); - if (result) { - return result; + if (!result) { + return result.error(); } uint_fast16_t expectedCrc = calculateCrc16(calculateCrc16(xpcBuffer), request) ^ 0xFFFFu; result = master->readBlock(xpcBuffer); - if (result) { - return result; + if (!result) { + return result.error(); } if (expectedCrc != ((static_cast<uint_fast16_t>(xpcBuffer[1]) << 8) | xpcBuffer[0])) { - return make_error_code(CrcError); + return CrcError; } result = master->writeBytePower(0xAA); - if (result) { - return result; + if (!result) { + return result.error(); } // Wait for device to process. @@ -96,33 +96,33 @@ // Read response. result = master->setLevel(OneWireMaster::NormalLevel); - if (result) { - return result; + if (!result) { + return result.error(); } result = master->readBlock(xpcBuffer); - if (result) { - return result; + if (!result) { + return result.error(); } if (xpcBuffer[1] > response.size()) { - return make_error_code(InvalidResponseError); + return InvalidResponseError; } response = response.first(xpcBuffer[1]); result = master->readBlock(response); - if (result) { - return result; + if (!result) { + return result.error(); } expectedCrc = calculateCrc16(calculateCrc16(make_span(xpcBuffer + 1, 1)), response) ^ 0xFFFFu; result = master->readBlock(xpcBuffer); - if (result) { - return result; + if (!result) { + return result.error(); } if (expectedCrc != ((static_cast<uint_fast16_t>(xpcBuffer[1]) << 8) | xpcBuffer[0])) { - return make_error_code(CrcError); + return CrcError; } - return result; + return response; } const error_category & RunCommandWithI2CMaster::errorCategory() { @@ -141,41 +141,42 @@ return instance; } -error_code RunCommandWithI2CMaster:: +Result<span<uint_least8_t> > RunCommandWithI2CMaster:: operator()(span<const uint_least8_t> request, int delayTime, - span<uint_least8_t> & response) const { + span<uint_least8_t> response) const { // Write request. - error_code result = master->start(address_); - if (result == make_error_condition(I2CMaster::NackError) && address_ != 0) { + Result<void> result = master->start(address_); + if (!result && result.error() == make_error_condition(I2CMaster::NackError) && + address_ != 0) { result = master->start(0); } - if (result) { + if (!result) { master->stop(); - return result; + return result.error(); } if (!request.empty()) { result = master->writeByte(request[0]); - if (result) { + if (!result) { master->stop(); - return result; + return result.error(); } request = request.subspan(1); if (!request.empty()) { result = master->writeByte(static_cast<uint_least8_t>(request.size())); - if (result) { + if (!result) { master->stop(); - return result; + return result.error(); } result = master->writeBlock(request); - if (result) { + if (!result) { master->stop(); - return result; + return result.error(); } } } result = master->stop(); - if (result) { - return result; + if (!result) { + return result.error(); } // Wait for device to process. @@ -183,28 +184,32 @@ // Read response. result = master->start(address_ | 1); - if (result) { + if (!result) { master->stop(); - return result; + return result.error(); } uint_least8_t length; - result = master->readByte(I2CMaster::Ack, length); - if (result) { + if (const Result<uint_least8_t> result = master->readByte(I2CMaster::Ack)) { + length = result.value(); + } else { master->stop(); - return result; + return result.error(); } if (length > response.size()) { master->stop(); - return make_error_code(InvalidResponseError); + return InvalidResponseError; } response = response.first(length); - result = master->readBlock(I2CMaster::Nack, response); - if (result) { + result = master->readBlock(response, I2CMaster::Nack); + if (!result) { master->stop(); - return result; + return result.error(); } result = master->stop(); - return result; + if (!result) { + return result.error(); + } + return response; } } // namespace MaximInterfaceCore
--- a/MaximInterfaceCore/RunCommand.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/RunCommand.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_RunCommand -#define MaximInterfaceCore_RunCommand +#ifndef MaximInterfaceCore_RunCommand_hpp +#define MaximInterfaceCore_RunCommand_hpp #include "Config.hpp" #include "Function.hpp" @@ -45,8 +45,15 @@ class OneWireMaster; class Sleep; -typedef Function<error_code(span<const uint_least8_t>, int, - span<uint_least8_t> &)> +/// @brief +/// Runs a command sequence by writing the command request, waiting the +/// specified amount of time, and reading back the command response. +/// @details +/// The parameters for this function are the command request, the delay time in +/// milliseconds, and a mutable buffer for the command response. The actual +/// buffer used for the command response is returned. +typedef Function<Result<span<uint_least8_t> >(span<const uint_least8_t>, int, + span<uint_least8_t>)> RunCommand; class RunCommandWithOneWireMaster { @@ -68,9 +75,9 @@ this->selectRom = selectRom; } - MaximInterfaceCore_EXPORT error_code + MaximInterfaceCore_EXPORT Result<span<uint_least8_t> > operator()(span<const uint_least8_t> request, int delayTime, - span<uint_least8_t> & response) const; + span<uint_least8_t> response) const; private: SelectRom selectRom; @@ -78,6 +85,10 @@ const Sleep * sleep; }; +template <> +struct is_error_code_enum<RunCommandWithOneWireMaster::ErrorValue> + : true_type {}; + inline error_code make_error_code(RunCommandWithOneWireMaster::ErrorValue e) { return error_code(e, RunCommandWithOneWireMaster::errorCategory()); } @@ -101,9 +112,9 @@ void setAddress(uint_least8_t address) { address_ = address & 0xFE; } - MaximInterfaceCore_EXPORT error_code + MaximInterfaceCore_EXPORT Result<span<uint_least8_t> > operator()(span<const uint_least8_t> request, int delayTime, - span<uint_least8_t> & response) const; + span<uint_least8_t> response) const; private: const Sleep * sleep; @@ -111,6 +122,9 @@ uint_least8_t address_; }; +template <> +struct is_error_code_enum<RunCommandWithI2CMaster::ErrorValue> : true_type {}; + inline error_code make_error_code(RunCommandWithI2CMaster::ErrorValue e) { return error_code(e, RunCommandWithI2CMaster::errorCategory()); }
--- a/MaximInterfaceCore/SafeBool.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/SafeBool.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_SafeBool -#define MaximInterfaceCore_SafeBool +#ifndef MaximInterfaceCore_SafeBool_hpp +#define MaximInterfaceCore_SafeBool_hpp #include <stddef.h> #include "Unconstructible.hpp"
--- a/MaximInterfaceCore/Segment.hpp Mon Jul 22 11:44:07 2019 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +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 MaximInterfaceCore_Segment -#define MaximInterfaceCore_Segment - -#include <iterator> -#include <utility> -#include "type_traits.hpp" - -namespace MaximInterfaceCore { - -/// @brief -/// Advances a given iterator by a given number of elements with bounds checking. -/// @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 -/// reachable by incrementing the given iterator. If distance is negative, bound -/// must be reachable by decrementing the given iterator. -/// @param distance -/// Number of elements to advance the given iterator. If distance is positive, -/// the given iterator is incremented. If distance is negative, the given -/// iterator is decremented, and InputIt must meet the requirements of -/// BidirectionalIterator. -/// @returns The number of elements that the given iterator was advanced. -template <typename InputIt> -typename std::iterator_traits<InputIt>::difference_type checkedAdvance( - InputIt & it, const InputIt bound, - typename std::iterator_traits<InputIt>::difference_type distance) { - typedef - typename std::iterator_traits<InputIt>::difference_type difference_type; - - // Use constant-time operations if InputIt is a random access iterator. - if (is_same<typename std::iterator_traits<InputIt>::iterator_category, - std::random_access_iterator_tag>::value) { - const difference_type boundDistance = std::distance(it, bound); - if (boundDistance >= 0) { - if (distance > boundDistance) { - distance = boundDistance; - } else if (distance < 0) { - distance = 0; - } - } else { - if (distance < boundDistance) { - distance = boundDistance; - } else if (distance > 0) { - distance = 0; - } - } - std::advance(it, distance); - } else { - const difference_type startingDistance = distance; - while (distance != 0 && it != bound) { - if (distance > 0) { - ++it; - --distance; - } else { - --it; - ++distance; - } - } - if (startingDistance > 0) { - distance = startingDistance - distance; - } else { - distance = startingDistance + distance; - } - } - return distance; -} - -/// @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 -/// the input range. If the segment does not exist within the input range, both -/// 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, - const typename std::iterator_traits<ForwardIt>::difference_type segmentSize, - Index segmentNum) { - ForwardIt segmentEnd = begin; - typename std::iterator_traits<ForwardIt>::difference_type lastSegmentSize = - checkedAdvance(segmentEnd, end, segmentSize); - while (segmentNum > 0 && segmentEnd != end) { - begin = segmentEnd; - lastSegmentSize = checkedAdvance(segmentEnd, end, segmentSize); - --segmentNum; - } - if (segmentNum > 0 || lastSegmentSize != segmentSize) { - begin = segmentEnd; - } - return std::make_pair(begin, segmentEnd); -} - -} // namespace MaximInterfaceCore - -#endif \ No newline at end of file
--- a/MaximInterfaceCore/SelectRom.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/SelectRom.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -34,19 +34,12 @@ namespace MaximInterfaceCore { -error_code SelectMatchRom::operator()(OneWireMaster & master) const { +SelectMatchRom::SelectMatchRom(RomId::const_span romId) { + copy(romId, make_span(romId_)); +} + +Result<void> SelectMatchRom::operator()(OneWireMaster & master) const { return matchRom(master, romId_); } -error_code SelectMatchRomWithResume::operator()(OneWireMaster & master) const { - error_code result; - if (romId_ == data->lastRomId) { - result = resumeRom(master); - } else { - result = matchRom(master, romId_); - data->lastRomId = romId_; - } - return result; -} - } // namespace MaximInterfaceCore
--- a/MaximInterfaceCore/SelectRom.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/SelectRom.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,21 +30,20 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_SelectRom -#define MaximInterfaceCore_SelectRom +#ifndef MaximInterfaceCore_SelectRom_hpp +#define MaximInterfaceCore_SelectRom_hpp #include "Config.hpp" #include "Function.hpp" #include "RomCommands.hpp" #include "RomId.hpp" -#include "system_error.hpp" namespace MaximInterfaceCore { class OneWireMaster; /// Selects a 1-Wire device on the bus for communication. -typedef Function<error_code(OneWireMaster &)> SelectRom; +typedef Function<Result<void>(OneWireMaster &)> SelectRom; /// Selector for a multidrop 1-Wire bus. class SelectMatchRom { @@ -52,49 +51,15 @@ typedef SelectRom::argument_type argument_type; typedef SelectRom::result_type result_type; - explicit SelectMatchRom(RomId::const_span romId) { setRomId(romId); } - - RomId::const_span romId() const { return romId_; } + explicit SelectMatchRom(RomId::const_span romId); - void setRomId(RomId::const_span romId) { copy(romId, make_span(romId_)); } - - MaximInterfaceCore_EXPORT error_code operator()(OneWireMaster & master) const; + MaximInterfaceCore_EXPORT Result<void> + operator()(OneWireMaster & master) const; private: RomId::array romId_; }; -/// @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 { - SharedData() : lastRomId() {} - RomId::array lastRomId; - }; - - SelectMatchRomWithResume(SharedData & data, RomId::const_span romId) - : data(&data) { - setRomId(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_)); } - - MaximInterfaceCore_EXPORT error_code operator()(OneWireMaster & master) const; - -private: - SharedData * data; - RomId::array romId_; -}; - } // namespace MaximInterfaceCore #endif
--- a/MaximInterfaceCore/SerialPort.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/SerialPort.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_SerialPort -#define MaximInterfaceCore_SerialPort +#ifndef MaximInterfaceCore_SerialPort_hpp +#define MaximInterfaceCore_SerialPort_hpp #include <string> #include "Uart.hpp" @@ -41,17 +41,10 @@ class SerialPort : public Uart { public: /// Connect a specified COM port. - virtual error_code connect(const std::string & portName) = 0; + virtual Result<void> connect(const std::string & portName) = 0; /// Disconnect from the current port. - virtual error_code disconnect() = 0; - - /// @brief Check if currently connected to a port. - /// @returns True if connected. - virtual bool connected() const = 0; - - /// Get the currently connected port name. - virtual std::string portName() const = 0; + virtual Result<void> disconnect() = 0; }; } // namespace MaximInterfaceCore
--- a/MaximInterfaceCore/Sleep.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Sleep.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_Sleep -#define MaximInterfaceCore_Sleep +#ifndef MaximInterfaceCore_Sleep_hpp +#define MaximInterfaceCore_Sleep_hpp namespace MaximInterfaceCore {
--- a/MaximInterfaceCore/SleepDecorator.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/SleepDecorator.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"),
--- a/MaximInterfaceCore/SleepDecorator.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/SleepDecorator.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_SleepDecorator -#define MaximInterfaceCore_SleepDecorator +#ifndef MaximInterfaceCore_SleepDecorator_hpp +#define MaximInterfaceCore_SleepDecorator_hpp #include "Config.hpp" #include "Sleep.hpp"
--- a/MaximInterfaceCore/Uart.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Uart.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -35,21 +35,18 @@ namespace MaximInterfaceCore { -error_code Uart::writeBlock(span<const uint_least8_t> data) { - error_code result; - for (span<const uint_least8_t>::index_type i = 0; - i < data.size() && !result; ++i) { - result = writeByte(data[i]); +Result<void> Uart::writeBlock(span<const uint_least8_t> data) { + for (span<const uint_least8_t>::index_type i = 0; i < data.size(); ++i) { + MaximInterfaceCore_TRY(writeByte(data[i])); } - return result; + return none; } -error_code Uart::readBlock(span<uint_least8_t> data) { - error_code result; - for (span<uint_least8_t>::index_type i = 0; i < data.size() && !result; ++i) { - result = readByte(data[i]); +Result<void> Uart::readBlock(span<uint_least8_t> data) { + for (span<uint_least8_t>::index_type i = 0; i < data.size(); ++i) { + MaximInterfaceCore_TRY_VALUE(data[i], readByte()); } - return result; + return none; } const error_category & Uart::errorCategory() { @@ -64,10 +61,8 @@ case OverrunError: return "Overrun Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance;
--- a/MaximInterfaceCore/Uart.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Uart.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,11 +30,12 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_Uart -#define MaximInterfaceCore_Uart +#ifndef MaximInterfaceCore_Uart_hpp +#define MaximInterfaceCore_Uart_hpp #include <stdint.h> #include "Config.hpp" +#include "Result.hpp" #include "span.hpp" #include "system_error.hpp" @@ -51,37 +52,39 @@ virtual ~Uart() {} /// Set the baud rate of the port in Hz. - virtual error_code setBaudRate(int_least32_t baudRate) = 0; + virtual Result<void> setBaudRate(int_least32_t baudRate) = 0; /// Generate a break condition on the port for a small amount of time. - virtual error_code sendBreak() = 0; + virtual Result<void> sendBreak() = 0; /// Clear all received data that was buffered. - virtual error_code clearReadBuffer() = 0; + virtual Result<void> clearReadBuffer() = 0; /// Writes a byte of data to the port. - virtual error_code writeByte(uint_least8_t data) = 0; + virtual Result<void> writeByte(uint_least8_t data) = 0; /// Writes a block of data to the port. - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> 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; + /// @returns Data read from the port if successful. + virtual Result<uint_least8_t> readByte() = 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. - MaximInterfaceCore_EXPORT virtual error_code + MaximInterfaceCore_EXPORT virtual Result<void> readBlock(span<uint_least8_t> data); MaximInterfaceCore_EXPORT static const error_category & errorCategory(); }; +template <> struct is_error_code_enum<Uart::ErrorValue> : true_type {}; + inline error_code make_error_code(Uart::ErrorValue e) { return error_code(e, Uart::errorCategory()); }
--- a/MaximInterfaceCore/Unconstructible.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Unconstructible.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2019 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_Unconstructible -#define MaximInterfaceCore_Unconstructible +#ifndef MaximInterfaceCore_Unconstructible_hpp +#define MaximInterfaceCore_Unconstructible_hpp namespace MaximInterfaceCore {
--- a/MaximInterfaceCore/Uncopyable.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/Uncopyable.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_Uncopyable -#define MaximInterfaceCore_Uncopyable +#ifndef MaximInterfaceCore_Uncopyable_hpp +#define MaximInterfaceCore_Uncopyable_hpp namespace MaximInterfaceCore {
--- a/MaximInterfaceCore/WriteMessage.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/WriteMessage.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_WriteMessage -#define MaximInterfaceCore_WriteMessage +#ifndef MaximInterfaceCore_WriteMessage_hpp +#define MaximInterfaceCore_WriteMessage_hpp #include <string> #include "Function.hpp"
--- a/MaximInterfaceCore/array.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/array.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_array -#define MaximInterfaceCore_array +#ifndef MaximInterfaceCore_array_hpp +#define MaximInterfaceCore_array_hpp #include <stddef.h> #include <stdint.h> @@ -131,9 +131,6 @@ static size_type max_size() { return size(); } - /// Alternative to size() when a constant expression is required. - static const size_type csize = N; - /// @} /// @name Operations
--- a/MaximInterfaceCore/array_span.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/array_span.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_array_span -#define MaximInterfaceCore_array_span +#ifndef MaximInterfaceCore_array_span_hpp +#define MaximInterfaceCore_array_span_hpp #include "array.hpp" #include "span.hpp" @@ -53,6 +53,8 @@ typedef MaximInterfaceCore::span<T, N> span; }; +template <typename T, size_t N> const size_t array_span<T, N>::size; + // Specialization for "const T" is not defined. template <typename T, size_t N> struct array_span<const T, N>;
--- a/MaximInterfaceCore/crc.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/crc.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,7 +30,7 @@ * ownership rights. *******************************************************************************/ -#include "crc.hpp" +#include "Crc.hpp" namespace MaximInterfaceCore {
--- a/MaximInterfaceCore/crc.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/crc.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_crc -#define MaximInterfaceCore_crc +#ifndef MaximInterfaceCore_Crc_hpp +#define MaximInterfaceCore_Crc_hpp #include <stddef.h> #include <stdint.h>
--- a/MaximInterfaceCore/span.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/span.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,11 +30,10 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_span -#define MaximInterfaceCore_span +#ifndef MaximInterfaceCore_span_hpp +#define MaximInterfaceCore_span_hpp #include <stddef.h> -#include <stdint.h> #include <iterator> #include <vector> #include "array.hpp" @@ -43,7 +42,7 @@ namespace MaximInterfaceCore { /// Differentiates spans of static and dynamic extent. -static const size_t dynamic_extent = SIZE_MAX; +static const size_t dynamic_extent = static_cast<size_t>(-1); // SIZE_MAX /// @brief /// Generic memory span class similar to gsl::span and the proposed std::span. @@ -155,11 +154,60 @@ pointer data_; }; -template <typename T> struct is_array : false_type {}; +template <template <typename, size_t> class span, typename T, size_t Extent> +const typename span_base<span, T, Extent>::index_type + span_base<span, T, Extent>::extent; + +template <typename T> class has_data { + typedef char true_type[1]; + typedef char false_type[2]; + + template <typename U, U> struct check; + + template <typename U> + static true_type & test(check<typename U::pointer (U::*)(), &U::data> *); + + template <typename> static false_type & test(...); + +public: + static const bool value = (sizeof(test<T>(NULL)) == sizeof(true_type)); +}; + +template <typename T> class has_data<const T> { + typedef char true_type[1]; + typedef char false_type[2]; + + template <typename U, U> struct check; -template <typename T> struct is_array<T[]> : true_type {}; + template <typename U> + static true_type & + test(check<typename U::const_pointer (U::*)() const, &U::data> *); + + template <typename> static false_type & test(...); + +public: + static const bool value = (sizeof(test<T>(NULL)) == sizeof(true_type)); +}; + +template <typename T> class has_size { + typedef char true_type[1]; + typedef char false_type[2]; -template <typename T, size_t N> struct is_array<T[N]> : true_type {}; + template <typename U, U> struct check; + + template <typename U> + static true_type & + test(check<typename U::size_type (U::*)() const, &U::size> *); + + // Additionally support a static member function. + template <typename U> + static true_type & test(check<typename U::size_type (*)(), &U::size> *); + + template <typename> static false_type & test(...); + +public: + static const bool value = (sizeof(test<T>(NULL)) == sizeof(true_type)); +}; template <typename T> struct is_array_class_helper : false_type {}; @@ -185,16 +233,11 @@ template <typename T> struct is_vector : is_vector_helper<typename remove_cv<T>::type> {}; -// Used by the static extent span to disable the container constructors. +// Used to disable the span container constructors. template <typename T> -struct enable_if_static_extent_convertible - : enable_if<!(is_array<T>::value || is_array_class<T>::value || - is_span<T>::value || is_vector<T>::value)> {}; - -// Used by the dynamic extent span to disable the container constructors. -template <typename T> -struct enable_if_dynamic_extent_convertible - : enable_if<!(is_array<T>::value || is_span<T>::value || +struct enable_if_span_convertible + : enable_if<has_data<T>::value && has_size<T>::value && + !(is_array_class<T>::value || is_span<T>::value || is_vector<T>::value)> {}; } // namespace detail @@ -232,13 +275,12 @@ template <typename Container> span(Container & cont, - typename detail::enable_if_static_extent_convertible<Container>::type * = - NULL) + typename detail::enable_if_span_convertible<Container>::type * = NULL) : span_base(cont.data()) {} template <typename Container> span(const Container & cont, - typename detail::enable_if_static_extent_convertible<Container>::type * = + typename detail::enable_if_span_convertible<const Container>::type * = NULL) : span_base(cont.data()) {} @@ -284,6 +326,12 @@ 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, size_t N> span(const span<U, N> & s) : span_base(s.data()), size_(s.size()) {} @@ -296,17 +344,14 @@ : span_base(vec.empty() ? NULL : &vec.front()), size_(vec.size()) {} template <typename Container> - span( - Container & cont, - typename detail::enable_if_dynamic_extent_convertible<Container>::type * = - NULL) + span(Container & cont, + typename detail::enable_if_span_convertible<Container>::type * = NULL) : span_base(cont.data()), size_(cont.size()) {} template <typename Container> - span( - const Container & cont, - typename detail::enable_if_dynamic_extent_convertible<Container>::type * = - NULL) + span(const Container & cont, + typename detail::enable_if_span_convertible<const Container>::type * = + NULL) : span_base(cont.data()), size_(cont.size()) {} /// @name Observers
--- a/MaximInterfaceCore/system_error.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/system_error.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"),
--- a/MaximInterfaceCore/system_error.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/system_error.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -35,13 +35,15 @@ /// Error handling constructs similar to std::error_code, std::error_condition, /// and std::error_category. -#ifndef MaximInterfaceCore_system_error -#define MaximInterfaceCore_system_error +#ifndef MaximInterfaceCore_system_error_hpp +#define MaximInterfaceCore_system_error_hpp +#include <stddef.h> #include <stdexcept> #include <string> #include "Config.hpp" #include "SafeBool.hpp" +#include "type_traits.hpp" #include "Uncopyable.hpp" namespace MaximInterfaceCore { @@ -49,6 +51,7 @@ class error_condition; class error_code; +/// Error category interface. class error_category : private Uncopyable { public: virtual ~error_category() {} @@ -79,8 +82,15 @@ return &lhs < &rhs; } +/// Default error category. MaximInterfaceCore_EXPORT const error_category & system_category(); +/// Checks if an enum type is implicitly convertible to an error_condition. +template <typename T> struct is_error_condition_enum : false_type {}; + +/// @brief +/// Used for classifying groups of error_code into higher-level error conditions +/// through the error_category::equivalent methods. class error_condition { public: error_condition() : value_(0), category_(&system_category()) {} @@ -88,6 +98,22 @@ error_condition(int value, const error_category & category) : value_(value), category_(&category) {} + template <typename ErrorConditionEnum> + error_condition( + ErrorConditionEnum e, + typename enable_if< + is_error_condition_enum<ErrorConditionEnum>::value>::type * = NULL) { + *this = make_error_condition(e); + } + + template <typename ErrorConditionEnum> + typename enable_if<is_error_condition_enum<ErrorConditionEnum>::value, + error_condition &>::type + operator=(ErrorConditionEnum e) { + *this = make_error_condition(e); + return *this; + } + void assign(int value, const error_category & category) { value_ = value; category_ = &category; @@ -127,6 +153,15 @@ ((lhs.category() == rhs.category()) && (lhs.value() < rhs.value())); } +/// Checks if an enum type is implicitly convertible to an error_code. +template <typename T> struct is_error_code_enum : false_type {}; + +/// @brief Holds a raw error code produced by a subsystem. +/// @details +/// An error_code is composed of a pair of values: a category of errors, usually +/// one per subsystem, and a number representing a specific error value within +/// that category. While not required, zero is typically used as the success +/// value so that the boolean conversion can be used as a failure test. class error_code { public: error_code() : value_(0), category_(&system_category()) {} @@ -134,6 +169,22 @@ error_code(int value, const error_category & category) : value_(value), category_(&category) {} + template <typename ErrorCodeEnum> + error_code( + ErrorCodeEnum e, + typename enable_if<is_error_code_enum<ErrorCodeEnum>::value>::type * = + NULL) { + *this = make_error_code(e); + } + + template <typename ErrorCodeEnum> + typename enable_if<is_error_code_enum<ErrorCodeEnum>::value, + error_code &>::type + operator=(ErrorCodeEnum e) { + *this = make_error_code(e); + return *this; + } + void assign(int value, const error_category & category) { value_ = value; category_ = &category; @@ -198,6 +249,7 @@ return !operator==(lhs, rhs); } +/// Wrapper for throwing error_code as an exception. class system_error : public std::runtime_error { public: MaximInterfaceCore_EXPORT system_error(const error_code & ec);
--- a/MaximInterfaceCore/type_traits.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceCore/type_traits.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceCore_type_traits -#define MaximInterfaceCore_type_traits +#ifndef MaximInterfaceCore_type_traits_hpp +#define MaximInterfaceCore_type_traits_hpp namespace MaximInterfaceCore { @@ -43,6 +43,8 @@ value_type operator()() const { return value; } }; +template <typename T, T v> const T integral_constant<T, v>::value; + typedef integral_constant<bool, true> true_type; typedef integral_constant<bool, false> false_type;
--- a/MaximInterfaceDevices/Config.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/Config.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2019 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"),
--- a/MaximInterfaceDevices/DS18B20.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS18B20.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -34,6 +34,9 @@ #include <MaximInterfaceCore/OneWireMaster.hpp> #include "DS18B20.hpp" +#define TRY MaximInterfaceCore_TRY +#define TRY_VALUE MaximInterfaceCore_TRY_VALUE + namespace MaximInterfaceDevices { using namespace Core; @@ -43,85 +46,80 @@ const uint_least8_t DS18B20::elevenBitResolution; const uint_least8_t DS18B20::twelveBitResolution; -error_code DS18B20::initialize() { - Scratchpad::array scratchpad; - return readScratchpad(scratchpad); +Result<void> DS18B20::initialize() const { + TRY(readScratchpad()); + return none; } -error_code DS18B20::writeScratchpad(uint_least8_t th, uint_least8_t tl, - uint_least8_t res) { - error_code result = selectRom(*master); - if (!result) { +Result<void> DS18B20::writeScratchpad(uint_least8_t th, uint_least8_t tl, + uint_least8_t res) { + Result<void> result = selectRom(*master); + if (result) { const uint_least8_t sendBlock[] = {0x4E, th, tl, res}; result = master->writeBlock(sendBlock); - if (!result) { + if (result) { resolution = res; } } return result; } -error_code DS18B20::readScratchpad(Scratchpad::span scratchpad) { - error_code result = selectRom(*master); - if (result) { - return result; +Result<DS18B20::Scratchpad> DS18B20::readScratchpad() const { + Result<void> result = selectRom(*master); + if (!result) { + return result.error(); } result = master->writeByte(0xBE); - if (result) { - return result; + if (!result) { + return result.error(); } + Scratchpad scratchpad; result = master->readBlock(scratchpad); - if (result) { - return result; + if (!result) { + return result.error(); } uint_least8_t receivedCrc; - result = master->readByte(receivedCrc); - if (result) { - return result; + TRY_VALUE(receivedCrc, master->readByte()); + if (receivedCrc != calculateCrc8(scratchpad)) { + return CrcError; } - if (receivedCrc == calculateCrc8(scratchpad)) { - resolution = scratchpad[4]; - } else { - result = make_error_code(CrcError); - } - return result; + resolution = scratchpad[4]; + return scratchpad; } -error_code DS18B20::readPowerSupply(bool & localPower) { - error_code result = selectRom(*master); - if (result) { - return result; +Result<bool> DS18B20::readPowerSupply() const { + Result<void> result = selectRom(*master); + if (!result) { + return result.error(); } result = master->writeByte(0xB4); - if (result) { - return result; + if (!result) { + return result.error(); } - result = master->touchBit(localPower); - return result; + return master->readBit(); } -error_code DS18B20::copyScratchpad() { +Result<void> DS18B20::copyScratchpad() { const uint_least8_t copyScratchpadCmd = 0x48; bool hasLocalPower; - error_code result = readPowerSupply(hasLocalPower); - if (result) { - return result; - } - result = selectRom(*master); - if (result) { + TRY_VALUE(hasLocalPower, readPowerSupply()); + Result<void> result = selectRom(*master); + if (!result) { return result; } if (hasLocalPower) { result = master->writeByte(copyScratchpadCmd); - bool recvbit = 0; - while (!recvbit && !result) { - result = master->touchBit(recvbit); + if (result) { + bool recvBit; + do { + TRY_VALUE(recvBit, master->readBit()); + } while (!recvBit); } } else { result = master->writeByteSetLevel(copyScratchpadCmd, OneWireMaster::StrongLevel); - if (!result) { + if (result) { sleep->invoke(10); result = master->setLevel(OneWireMaster::NormalLevel); } @@ -129,28 +127,27 @@ return result; } -error_code DS18B20::convertTemperature() { +Result<void> DS18B20::convertTemperature() { const uint_least8_t convertTemperatureCmd = 0x44; bool hasLocalPower; - error_code result = readPowerSupply(hasLocalPower); - if (result) { - return result; - } - result = selectRom(*master); - if (result) { + TRY_VALUE(hasLocalPower, readPowerSupply()); + Result<void> result = selectRom(*master); + if (!result) { return result; } if (hasLocalPower) { result = master->writeByte(convertTemperatureCmd); - bool recvbit = 0; - while (!result && !recvbit) { - result = master->touchBit(recvbit); + if (result) { + bool recvBit; + do { + TRY_VALUE(recvBit, master->readBit()); + } while (!recvBit); } } else { result = master->writeByteSetLevel(convertTemperatureCmd, OneWireMaster::StrongLevel); - if (!result) { + if (result) { int sleepTime; switch (resolution) { case nineBitResolution: @@ -177,9 +174,9 @@ return result; } -error_code DS18B20::recallEeprom() { - error_code result = selectRom(*master); - if (!result) { +Result<void> DS18B20::recallEeprom() { + Result<void> result = selectRom(*master); + if (result) { result = master->writeByte(0xB8); } return result; @@ -197,35 +194,28 @@ case DataError: return "Data Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance; } -error_code readTemperature(DS18B20 & ds18b20, int & temperature) { - error_code result = ds18b20.convertTemperature(); - if (result) { - return result; - } - DS18B20::Scratchpad::array scratchpad; - result = ds18b20.readScratchpad(scratchpad); - if (result) { - return result; - } +Result<int> readTemperature(DS18B20 & ds18b20) { + TRY(ds18b20.convertTemperature()); + DS18B20::Scratchpad scratchpad; + TRY_VALUE(scratchpad, ds18b20.readScratchpad()); const unsigned int tempData = (static_cast<unsigned int>(scratchpad[1]) << 8) | scratchpad[0]; const unsigned int signMask = 0xF800; + int temperature; if ((tempData & signMask) == signMask) { temperature = -0x800; } else if ((tempData & signMask) == 0) { temperature = 0; } else { - return make_error_code(DS18B20::DataError); + return DS18B20::DataError; } unsigned int precisionMask; switch (scratchpad[4]) { @@ -247,7 +237,7 @@ break; } temperature += static_cast<int>(tempData & ~(signMask | precisionMask)); - return error_code(); + return temperature; } } // namespace MaximInterfaceDevices
--- a/MaximInterfaceDevices/DS18B20.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS18B20.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,10 +30,10 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS18B20 -#define MaximInterfaceDevices_DS18B20 +#ifndef MaximInterfaceDevices_DS18B20_hpp +#define MaximInterfaceDevices_DS18B20_hpp -#include <MaximInterfaceCore/array_span.hpp> +#include <MaximInterfaceCore/array.hpp> #include <MaximInterfaceCore/SelectRom.hpp> #include <MaximInterfaceCore/Sleep.hpp> #include "Config.hpp" @@ -59,7 +59,7 @@ static const uint_least8_t twelveBitResolution = 0x7F; /// Holds the contents of the device scratchpad. - typedef Core::array_span<uint_least8_t, 8> Scratchpad; + typedef Core::array<uint_least8_t, 8> Scratchpad; DS18B20(Core::Sleep & sleep, Core::OneWireMaster & master, const Core::SelectRom & selectRom) @@ -74,7 +74,7 @@ } /// Initializes the device for first time use. - MaximInterfaceDevices_EXPORT Core::error_code initialize(); + MaximInterfaceDevices_EXPORT Core::Result<void> initialize() const; /// @brief Write Scratchpad Command /// @details If the result of a temperature measurement is higher @@ -85,37 +85,35 @@ /// @param[in] th 8-bit upper temperature threshold, MSB indicates sign. /// @param[in] tl 8-bit lower temperature threshold, LSB indicates sign. /// @param[in] res Resolution of the DS18B20. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeScratchpad(uint_least8_t th, uint_least8_t tl, uint_least8_t res); /// @brief Read Scratchpad Command - /// @param[out] scratchpad Contents of scratchpad. - MaximInterfaceDevices_EXPORT Core::error_code - readScratchpad(Scratchpad::span scratchpad); + /// @returns scratchpad Contents of scratchpad. + MaximInterfaceDevices_EXPORT Core::Result<Scratchpad> readScratchpad() const; /// @brief Copy Scratchpad Command /// @details This command copies from the scratchpad into the /// EEPROM of the DS18B20, storing the temperature trigger bytes /// and resolution in nonvolatile memory. - MaximInterfaceDevices_EXPORT Core::error_code copyScratchpad(); + MaximInterfaceDevices_EXPORT Core::Result<void> copyScratchpad(); /// @brief Read Power Supply command /// @details This command determines if the DS18B20 is parasite /// powered or has a local supply - /// @param[out] localPower + /// @returns /// True if the device is powered by a local power supply, or false if the /// device is parasitically powered. - MaximInterfaceDevices_EXPORT Core::error_code - readPowerSupply(bool & localPower); + MaximInterfaceDevices_EXPORT Core::Result<bool> readPowerSupply() const; /// @brief Convert Temperature Command /// @details This command begins a temperature conversion. - MaximInterfaceDevices_EXPORT Core::error_code convertTemperature(); + MaximInterfaceDevices_EXPORT Core::Result<void> convertTemperature(); /// @brief Recall Command /// @details This command recalls the temperature trigger values /// and resolution stored in EEPROM to the scratchpad. - MaximInterfaceDevices_EXPORT Core::error_code recallEeprom(); + MaximInterfaceDevices_EXPORT Core::Result<void> recallEeprom(); MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); @@ -124,14 +122,24 @@ Core::SelectRom selectRom; Core::OneWireMaster * master; const Core::Sleep * sleep; - uint_least8_t resolution; + mutable uint_least8_t resolution; }; /// @brief Reads the current temperature as an integer value with decimal. /// @param ds18b20 Device to read. -/// @param[out] temperature Temperature in degrees Celsius multiplied by 16. -MaximInterfaceDevices_EXPORT Core::error_code -readTemperature(DS18B20 & ds18b20, int & temperature); +/// @returns Temperature in degrees Celsius multiplied by 16. +MaximInterfaceDevices_EXPORT Core::Result<int> +readTemperature(DS18B20 & ds18b20); + +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS18B20::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { inline Core::error_code make_error_code(DS18B20::ErrorValue e) { return Core::error_code(e, DS18B20::errorCategory());
--- a/MaximInterfaceDevices/DS1920.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS1920.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -38,38 +38,42 @@ using namespace Core; -error_code DS1920::writeScratchpad(uint_least8_t th, uint_least8_t tl) { - error_code result = selectRom(*master); - if (!result) { +Result<void> DS1920::writeScratchpad(uint_least8_t th, uint_least8_t tl) { + Result<void> result = selectRom(*master); + if (result) { const uint_least8_t sendBlock[] = {0x4E, th, tl}; result = master->writeBlock(sendBlock); } return result; } -error_code DS1920::readScratchpad(Scratchpad::span scratchpad) { - error_code result = selectRom(*master); +Result<DS1920::Scratchpad> DS1920::readScratchpad() const { + Result<void> result = selectRom(*master); + if (!result) { + return result.error(); + } + result = master->writeByte(0xBE); if (!result) { - result = master->writeByte(0xBE); - if (!result) { - result = master->readBlock(scratchpad); - if (!result) { - uint_least8_t receivedCrc; - result = master->readByte(receivedCrc); - if (!result && (receivedCrc != calculateCrc8(scratchpad))) { - result = make_error_code(CrcError); - } - } - } + return result.error(); + } + Scratchpad scratchpad; + result = master->readBlock(scratchpad); + if (!result) { + return result.error(); } - return result; + uint_least8_t receivedCrc; + MaximInterfaceCore_TRY_VALUE(receivedCrc, master->readByte()); + if (receivedCrc != calculateCrc8(scratchpad)) { + return CrcError; + } + return scratchpad; } -error_code DS1920::copyScratchpad() { - error_code result = selectRom(*master); - if (!result) { +Result<void> DS1920::copyScratchpad() { + Result<void> result = selectRom(*master); + if (result) { result = master->writeByteSetLevel(0x48, OneWireMaster::StrongLevel); - if (!result) { + if (result) { sleep->invoke(10); result = master->setLevel(OneWireMaster::NormalLevel); } @@ -77,11 +81,11 @@ return result; } -error_code DS1920::convertTemperature() { - error_code result = selectRom(*master); - if (!result) { +Result<void> DS1920::convertTemperature() { + Result<void> result = selectRom(*master); + if (result) { result = master->writeByteSetLevel(0x44, OneWireMaster::StrongLevel); - if (!result) { + if (result) { sleep->invoke(750); result = master->setLevel(OneWireMaster::NormalLevel); } @@ -89,9 +93,9 @@ return result; } -error_code DS1920::recallEeprom() { - error_code result = selectRom(*master); - if (!result) { +Result<void> DS1920::recallEeprom() { + Result<void> result = selectRom(*master); + if (result) { result = master->writeByte(0xB8); } return result; @@ -109,39 +113,32 @@ case DataError: return "Data Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance; } -error_code readTemperature(DS1920 & ds1920, int & temperature) { - error_code result = ds1920.convertTemperature(); - if (result) { - return result; - } - DS1920::Scratchpad::array scratchpad; - result = ds1920.readScratchpad(scratchpad); - if (result) { - return result; - } +Result<int> readTemperature(DS1920 & ds1920) { + MaximInterfaceCore_TRY(ds1920.convertTemperature()); + DS1920::Scratchpad scratchpad; + MaximInterfaceCore_TRY_VALUE(scratchpad, ds1920.readScratchpad()); unsigned int tempData = (static_cast<unsigned int>(scratchpad[1]) << 8) | scratchpad[0]; const unsigned int signMask = 0xFF00; + int temperature; if ((tempData & signMask) == signMask) { temperature = -0x100; tempData &= ~signMask; } else if ((tempData & signMask) == 0) { temperature = 0; } else { - return make_error_code(DS1920::DataError); + return DS1920::DataError; } temperature += static_cast<int>(tempData); - return error_code(); + return temperature; } } // namespace MaximInterfaceDevices
--- a/MaximInterfaceDevices/DS1920.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS1920.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,10 +30,10 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS1920 -#define MaximInterfaceDevices_DS1920 +#ifndef MaximInterfaceDevices_DS1920_hpp +#define MaximInterfaceDevices_DS1920_hpp -#include <MaximInterfaceCore/array_span.hpp> +#include <MaximInterfaceCore/array.hpp> #include <MaximInterfaceCore/SelectRom.hpp> #include <MaximInterfaceCore/Sleep.hpp> #include "Config.hpp" @@ -55,7 +55,7 @@ enum ErrorValue { CrcError = 1, DataError }; /// Holds the contents of the device scratchpad. - typedef Core::array_span<uint_least8_t, 8> Scratchpad; + typedef Core::array<uint_least8_t, 8> Scratchpad; DS1920(Core::Sleep & sleep, Core::OneWireMaster & master, const Core::SelectRom & selectRom) @@ -77,28 +77,27 @@ /// the alarm search command. /// @param[in] th 8-bit upper temperature threshold, MSB indicates sign. /// @param[in] tl 8-bit lower temperature threshold, MSB indicates sign. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeScratchpad(uint_least8_t th, uint_least8_t tl); /// @brief Read Scratchpad Command - /// @param[out] scratchpad Contents of scratchpad. - MaximInterfaceDevices_EXPORT Core::error_code - readScratchpad(Scratchpad::span scratchpad); + /// @returns Contents of scratchpad. + MaximInterfaceDevices_EXPORT Core::Result<Scratchpad> readScratchpad() const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code copyScratchpad(); + MaximInterfaceDevices_EXPORT Core::Result<void> copyScratchpad(); /// @brief Convert Temperature Command /// @details This command begins a temperature conversion. - MaximInterfaceDevices_EXPORT Core::error_code convertTemperature(); + MaximInterfaceDevices_EXPORT Core::Result<void> convertTemperature(); /// @brief Recall Command /// @details This command recalls the temperature trigger values /// stored in EEPROM to the scratchpad. - MaximInterfaceDevices_EXPORT Core::error_code recallEeprom(); + MaximInterfaceDevices_EXPORT Core::Result<void> recallEeprom(); MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); @@ -111,9 +110,18 @@ /// @brief Reads the current temperature as an integer value. /// @param ds1920 Device to read. -/// @param[out] temperature Temperature in degrees Celsius multiplied by 2. -MaximInterfaceDevices_EXPORT Core::error_code -readTemperature(DS1920 & ds1920, int & temperature); +/// @returns Temperature in degrees Celsius multiplied by 2. +MaximInterfaceDevices_EXPORT Core::Result<int> readTemperature(DS1920 & ds1920); + +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS1920::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { inline Core::error_code make_error_code(DS1920::ErrorValue e) { return Core::error_code(e, DS1920::errorCategory());
--- a/MaximInterfaceDevices/DS2413.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS2413.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -34,20 +34,18 @@ #include <MaximInterfaceCore/OneWireMaster.hpp> #include "DS2413.hpp" +#define TRY MaximInterfaceCore_TRY +#define TRY_VALUE MaximInterfaceCore_TRY_VALUE + namespace MaximInterfaceDevices { using namespace Core; -error_code DS2413::readStatus(Status & status) const { - uint_least8_t val; - const error_code result = pioAccessRead(val); - if (!result) { - status = val; - } - return result; +Result<DS2413::Status> DS2413::readStatus() const { + return Result<DS2413::Status>(pioAccessRead()); } -error_code DS2413::writeOutputState(bool pioAState, bool pioBState) { +Result<void> DS2413::writeOutputState(bool pioAState, bool pioBState) { uint_least8_t val = 0xFC; if (pioAState) { val |= 0x1; @@ -58,33 +56,22 @@ return pioAccessWrite(val); } -error_code DS2413::pioAccessRead(uint_least8_t & val) const { - error_code result = selectRom(*master); - if (!result) { - result = master->writeByte(0xF5); - if (!result) { - result = master->readByte(val); - if (!result && (val != ((val ^ 0xF0) >> 4))) { - result = make_error_code(CommunicationError); - } - } - } - return result; +Result<uint_least8_t> DS2413::pioAccessRead() const { + TRY(selectRom(*master)); + TRY(master->writeByte(0xF5)); + uint_least8_t result; + TRY_VALUE(result, master->readByte()); + return (result == ((result ^ 0xF0) >> 4)) ? makeResult(result) + : CommunicationError; } -error_code DS2413::pioAccessWrite(uint_least8_t val) { - error_code result = selectRom(*master); - if (!result) { - uint_least8_t block[] = {0x5A, val, static_cast<uint_least8_t>(val ^ 0xFF)}; - result = master->writeBlock(block); - if (!result) { - result = master->readByte(block[0]); - if (!result && block[0] != 0xAA) { - result = make_error_code(CommunicationError); - } - } - } - return result; +Result<void> DS2413::pioAccessWrite(uint_least8_t val) { + TRY(selectRom(*master)); + const uint_least8_t block[] = {0x5A, val, + static_cast<uint_least8_t>(val ^ 0xFF)}; + TRY(master->writeBlock(block)); + TRY_VALUE(val, master->readByte()); + return (val == 0xAA) ? makeResult(none) : CommunicationError; } const error_category & DS2413::errorCategory() { @@ -103,24 +90,22 @@ return instance; } -error_code writePioAOutputState(DS2413 & ds2413, bool pioAState) { +Result<void> writePioAOutputState(DS2413 & ds2413, bool pioAState) { DS2413::Status status; - error_code result = ds2413.readStatus(status); - if (!result && pioAState != status[DS2413::PioAOutputState]) { - result = - ds2413.writeOutputState(pioAState, status[DS2413::PioBOutputState]); + TRY_VALUE(status, ds2413.readStatus()); + if (pioAState != status[DS2413::PioAOutputState]) { + TRY(ds2413.writeOutputState(pioAState, status[DS2413::PioBOutputState])); } - return result; + return none; } -error_code writePioBOutputState(DS2413 & ds2413, bool pioBState) { +Result<void> writePioBOutputState(DS2413 & ds2413, bool pioBState) { DS2413::Status status; - error_code result = ds2413.readStatus(status); - if (!result && pioBState != status[DS2413::PioBOutputState]) { - result = - ds2413.writeOutputState(status[DS2413::PioAOutputState], pioBState); + TRY_VALUE(status, ds2413.readStatus()); + if (pioBState != status[DS2413::PioBOutputState]) { + TRY(ds2413.writeOutputState(status[DS2413::PioAOutputState], pioBState)); } - return result; + return none; } } // namespace MaximInterfaceDevices
--- a/MaximInterfaceDevices/DS2413.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS2413.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS2413 -#define MaximInterfaceDevices_DS2413 +#ifndef MaximInterfaceDevices_DS2413_hpp +#define MaximInterfaceDevices_DS2413_hpp #include <stdint.h> #include <MaximInterfaceCore/FlagSet.hpp> @@ -72,32 +72,41 @@ } /// Read the input and output logic states for all PIO pins. - MaximInterfaceDevices_EXPORT Core::error_code - readStatus(Status & status) const; + MaximInterfaceDevices_EXPORT Core::Result<Status> readStatus() const; /// Write the output logic states for all PIO pins. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeOutputState(bool pioAState, bool pioBState); MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); private: - Core::error_code pioAccessRead(uint_least8_t & val) const; - Core::error_code pioAccessWrite(uint_least8_t val); + Core::Result<uint_least8_t> pioAccessRead() const; + Core::Result<void> pioAccessWrite(uint_least8_t val); Core::SelectRom selectRom; Core::OneWireMaster * master; }; /// Write the output logic state for only PIOA. -MaximInterfaceDevices_EXPORT Core::error_code +MaximInterfaceDevices_EXPORT Core::Result<void> writePioAOutputState(DS2413 & ds2413, bool pioAState); /// Write the output logic state for only PIOB. -MaximInterfaceDevices_EXPORT Core::error_code +MaximInterfaceDevices_EXPORT Core::Result<void> writePioBOutputState(DS2413 & ds2413, bool pioBState); +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS2413::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS2413::ErrorValue e) { return Core::error_code(e, DS2413::errorCategory()); }
--- a/MaximInterfaceDevices/DS2431.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS2431.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -39,119 +39,118 @@ using namespace Core; -error_code writeMemory(DS2431 & device, DS2431::Address targetAddress, - DS2431::Scratchpad::const_span data) { - error_code result = device.writeScratchpad(targetAddress, data); - if (result) { +Result<void> writeMemory(DS2431 & device, uint_least8_t targetAddress, + DS2431::Scratchpad::const_span data) { + Result<void> result = device.writeScratchpad(targetAddress, data); + if (!result) { return result; } - DS2431::Scratchpad::array readData; uint_least8_t esByte; - result = device.readScratchpad(readData, esByte); - if (result) { - return result; + if (const Result<std::pair<uint_least8_t, DS2431::Scratchpad::array> > + scratchpad = device.readScratchpad()) { + esByte = scratchpad.value().first; + } else { + return scratchpad.error(); } result = device.copyScratchpad(targetAddress, esByte); return result; } -error_code DS2431::readMemory(Address beginAddress, - span<uint_least8_t> data) const { - error_code result = selectRom(*master); - if (result) { +Result<void> DS2431::readMemory(uint_least8_t beginAddress, + span<uint_least8_t> data) const { + Result<void> result = selectRom(*master); + if (!result) { return result; } const uint_least8_t sendBlock[] = {0xF0, beginAddress, 0x00}; result = master->writeBlock(sendBlock); - if (result) { + if (!result) { return result; } result = master->readBlock(data); return result; } -error_code DS2431::writeScratchpad(Address targetAddress, - Scratchpad::const_span data) { - error_code result = selectRom(*master); - if (result) { +Result<void> DS2431::writeScratchpad(uint_least8_t targetAddress, + Scratchpad::const_span data) { + Result<void> result = selectRom(*master); + if (!result) { return result; } uint_least8_t block[3 + Scratchpad::size] = {0x0F, targetAddress, 0x00}; std::copy(data.begin(), data.end(), block + 3); result = master->writeBlock(block); - if (result) { + if (!result) { return result; } const uint_fast16_t calculatedCrc = calculateCrc16(block) ^ 0xFFFFu; result = master->readBlock(make_span(block, 2)); - if (result) { + if (!result) { return result; } if (calculatedCrc != ((static_cast<uint_fast16_t>(block[1]) << 8) | block[0])) { - result = make_error_code(CrcError); + result = CrcError; } return result; } -error_code DS2431::readScratchpad(Scratchpad::span data, - uint_least8_t & esByte) { +Result<std::pair<uint_least8_t, DS2431::Scratchpad::array> > +DS2431::readScratchpad() const { typedef array<uint_least8_t, 6 + Scratchpad::size> Block; - error_code result = selectRom(*master); - if (result) { - return result; + Result<void> result = selectRom(*master); + if (!result) { + return result.error(); } Block block = {0xAA}; result = master->writeByte(block.front()); - if (result) { - return result; + if (!result) { + return result.error(); } result = master->readBlock(make_span(block).subspan(1)); - if (result) { - return result; + if (!result) { + return result.error(); } 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(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 { - result = make_error_code(CrcError); + if (expectedCrc != receivedCrc) { + return CrcError; } - return result; + std::pair<uint_least8_t, Scratchpad::array> data; + Block::const_iterator blockItEnd = blockIt; + blockIt -= data.second.size(); + std::copy(blockIt, blockItEnd, data.second.begin()); + data.first = *(--blockIt); + return data; } -error_code DS2431::copyScratchpad(Address targetAddress, uint_least8_t esByte) { - error_code result = selectRom(*master); - if (result) { +Result<void> DS2431::copyScratchpad(uint_least8_t targetAddress, + uint_least8_t esByte) { + Result<void> result = selectRom(*master); + if (!result) { return result; } uint_least8_t block[] = {0x55, targetAddress, 0x00}; result = master->writeBlock(block); - if (result) { + if (!result) { return result; } result = master->writeByteSetLevel(esByte, OneWireMaster::StrongLevel); - if (result) { + if (!result) { return result; } sleep->invoke(10); result = master->setLevel(OneWireMaster::NormalLevel); - if (result) { + if (!result) { return result; } - result = master->readByte(block[0]); - if (result) { - return result; - } + MaximInterfaceCore_TRY_VALUE(block[0], master->readByte()); if (block[0] != 0xAA) { - result = make_error_code(OperationFailure); + result = OperationFailure; } return result; }
--- a/MaximInterfaceDevices/DS2431.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS2431.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,9 +30,10 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS2431 -#define MaximInterfaceDevices_DS2431 +#ifndef MaximInterfaceDevices_DS2431_hpp +#define MaximInterfaceDevices_DS2431_hpp +#include <utility> #include <MaximInterfaceCore/array_span.hpp> #include <MaximInterfaceCore/SelectRom.hpp> #include <MaximInterfaceCore/Sleep.hpp> @@ -57,7 +58,6 @@ enum ErrorValue { CrcError = 1, OperationFailure }; typedef Core::array_span<uint_least8_t, 8> Scratchpad; - typedef uint_least8_t Address; DS2431(Core::Sleep & sleep, Core::OneWireMaster & master, const Core::SelectRom & selectRom) @@ -74,29 +74,29 @@ /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - readMemory(Address beginAddress, Core::span<uint_least8_t> data) const; + MaximInterfaceDevices_EXPORT Core::Result<void> + readMemory(uint_least8_t beginAddress, Core::span<uint_least8_t> data) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - writeScratchpad(Address targetAddress, Scratchpad::const_span data); + MaximInterfaceDevices_EXPORT Core::Result<void> + writeScratchpad(uint_least8_t targetAddress, Scratchpad::const_span data); /// @brief Reads contents of scratchpad. - /// @param[out] data Data read from scratchpad. - /// @param[out] esByte E/S byte read before scratchpad data. - MaximInterfaceDevices_EXPORT Core::error_code - readScratchpad(Scratchpad::span data, uint_least8_t & esByte); + /// @returns E/S byte and scratchpad data. + MaximInterfaceDevices_EXPORT + Core::Result<std::pair<uint_least8_t, Scratchpad::array> > + readScratchpad() const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - copyScratchpad(Address targetAddress, uint_least8_t esByte); + MaximInterfaceDevices_EXPORT Core::Result<void> + copyScratchpad(uint_least8_t targetAddress, uint_least8_t esByte); MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); @@ -113,10 +113,20 @@ /// @param device Device to write. /// @param[in] targetAddress EEPROM memory address to start writing at. /// @param[in] data Data to write to EEPROM. -MaximInterfaceDevices_EXPORT Core::error_code -writeMemory(DS2431 & device, DS2431::Address targetAddress, +MaximInterfaceDevices_EXPORT Core::Result<void> +writeMemory(DS2431 & device, uint_least8_t targetAddress, DS2431::Scratchpad::const_span data); +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS2431::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS2431::ErrorValue e) { return Core::error_code(e, DS2431::errorCategory()); }
--- a/MaximInterfaceDevices/DS2465.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS2465.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -33,15 +33,20 @@ #include <MaximInterfaceCore/Error.hpp> #include "DS2465.hpp" +#define TRY MaximInterfaceCore_TRY +#define TRY_VALUE MaximInterfaceCore_TRY_VALUE + namespace MaximInterfaceDevices { using namespace Core; -/// Delay required after writing an EEPROM segment. +// Delay required after writing an EEPROM segment. static const int eepromSegmentWriteDelayMs = 10; -/// Delay required after writing an EEPROM page such as the secret memory. + +// Delay required after writing an EEPROM page such as the secret memory. static const int eepromPageWriteDelayMs = 8 * eepromSegmentWriteDelayMs; -/// Delay required for a SHA computation to complete. + +// Delay required for a SHA computation to complete. static const int shaComputationDelayMs = 2; static const uint_least8_t scratchpad = 0x00; @@ -49,36 +54,32 @@ static const uint_least8_t owTransmitBlockCmd = 0x69; -/// DS2465 Status bits. -enum StatusBit { - Status_1WB = 0x01, - Status_PPD = 0x02, - Status_SD = 0x04, - Status_LL = 0x08, - Status_RST = 0x10, - Status_SBR = 0x20, - Status_TSB = 0x40, - Status_DIR = 0x80 -}; +// DS2465 status bits. +static const uint_least8_t status_1WB = 0x01; +static const uint_least8_t status_PPD = 0x02; +static const uint_least8_t status_SD = 0x04; +static const uint_least8_t status_SBR = 0x20; +static const uint_least8_t status_TSB = 0x40; +static const uint_least8_t status_DIR = 0x80; static const int maxBlockSize = 63; const int DS2465::memoryPages; const int DS2465::segmentsPerPage; -error_code DS2465::initialize(Config config) { +Result<void> DS2465::initialize(Config config) { // reset DS2465 - error_code result = resetDevice(); - if (!result) { + Result<void> result = resetDevice(); + if (result) { // write the default configuration setup result = writeConfig(config); } return result; } -error_code DS2465::computeNextMasterSecret(bool swap, int pageNum, - PageRegion region) { - error_code result = make_error_code(ArgumentOutOfRangeError); +Result<void> DS2465::computeNextMasterSecret(bool swap, int pageNum, + PageRegion region) { + Result<void> result = ArgumentOutOfRangeError; if (pageNum >= 0) { const uint_least8_t command[] = { 0x1E, static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region) @@ -88,52 +89,52 @@ return result; } -error_code DS2465::computeWriteMac(bool regwrite, bool swap, int pageNum, - int segmentNum) const { - error_code result = make_error_code(ArgumentOutOfRangeError); +Result<void> DS2465::computeWriteMac(bool regwrite, bool swap, int pageNum, + int segmentNum) const { + Result<void> result = ArgumentOutOfRangeError; if (pageNum >= 0 && segmentNum >= 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) { + if (result) { sleep->invoke(shaComputationDelayMs); } } return result; } -error_code DS2465::computeAuthMac(bool swap, int pageNum, - PageRegion region) const { - error_code result = make_error_code(ArgumentOutOfRangeError); +Result<void> DS2465::computeAuthMac(bool swap, int pageNum, + PageRegion region) const { + Result<void> result = ArgumentOutOfRangeError; if (pageNum >= 0) { const uint_least8_t command[] = { 0x3C, static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region) : 0xBF)}; result = writeMemory(commandReg, command); - if (!result) { + if (result) { sleep->invoke(shaComputationDelayMs * 2); } } return result; } -error_code DS2465::computeSlaveSecret(bool swap, int pageNum, - PageRegion region) { - error_code result = make_error_code(ArgumentOutOfRangeError); +Result<void> DS2465::computeSlaveSecret(bool swap, int pageNum, + PageRegion region) { + Result<void> result = ArgumentOutOfRangeError; if (pageNum >= 0) { const uint_least8_t command[] = { 0x4B, static_cast<uint_least8_t>(swap ? (0xC8 | (pageNum << 4) | region) : 0xBF)}; result = writeMemory(commandReg, command); - if (!result) { + if (result) { sleep->invoke(shaComputationDelayMs * 2); } } return result; } -error_code DS2465::readPage(int pageNum, Page::span data) const { +Result<DS2465::Page::array> DS2465::readPage(int pageNum) const { uint_least8_t addr; switch (pageNum) { case 0: @@ -143,48 +144,50 @@ addr = 0xA0; break; default: - return make_error_code(ArgumentOutOfRangeError); + return ArgumentOutOfRangeError; } - return readMemory(addr, data); + Page::array data; + TRY(readMemory(addr, data)); + return data; } -error_code DS2465::writePage(int pageNum, Page::const_span data) { - error_code result = writeMemory(scratchpad, data); - if (!result) { +Result<void> DS2465::writePage(int pageNum, Page::const_span data) { + Result<void> result = writeMemory(scratchpad, data); + if (result) { result = copyScratchpad(false, pageNum, false, 0); } - if (!result) { + if (result) { sleep->invoke(eepromPageWriteDelayMs); } return result; } -error_code DS2465::writeSegment(int pageNum, int segmentNum, - Segment::const_span data) { - error_code result = writeMemory(scratchpad, data); - if (!result) { +Result<void> DS2465::writeSegment(int pageNum, int segmentNum, + Segment::const_span data) { + Result<void> result = writeMemory(scratchpad, data); + if (result) { result = copyScratchpad(false, pageNum, true, segmentNum); } - if (!result) { + if (result) { sleep->invoke(eepromSegmentWriteDelayMs); } return result; } -error_code DS2465::writeMasterSecret(Page::const_span masterSecret) { - error_code result = writeMemory(scratchpad, masterSecret); - if (!result) { +Result<void> DS2465::writeMasterSecret(Page::const_span masterSecret) { + Result<void> result = writeMemory(scratchpad, masterSecret); + if (result) { result = copyScratchpad(true, 0, false, 0); } - if (!result) { + if (result) { sleep->invoke(eepromPageWriteDelayMs); } return result; } -error_code DS2465::copyScratchpad(bool destSecret, int pageNum, bool notFull, - int segmentNum) { - error_code result = make_error_code(ArgumentOutOfRangeError); +Result<void> DS2465::copyScratchpad(bool destSecret, int pageNum, bool notFull, + int segmentNum) { + Result<void> result = ArgumentOutOfRangeError; if (pageNum >= 0 && segmentNum >= 0) { const uint_least8_t command[] = { 0x5A, @@ -196,41 +199,41 @@ return result; } -error_code DS2465::configureLevel(Level level) { +Result<void> DS2465::configureLevel(Level level) { // Check if supported level if (!((level == NormalLevel) || (level == StrongLevel))) { - return make_error_code(InvalidLevelError); + return InvalidLevelError; } // Check if requested level already set if (curConfig.getSPU() == (level == StrongLevel)) { - return error_code(); + return none; } // Set the level return writeConfig(Config(curConfig).setSPU(level == StrongLevel)); } -error_code DS2465::setLevel(Level newLevel) { +Result<void> DS2465::setLevel(Level newLevel) { if (newLevel == StrongLevel) { - return make_error_code(InvalidLevelError); + return InvalidLevelError; } return configureLevel(newLevel); } -error_code DS2465::setSpeed(Speed newSpeed) { +Result<void> DS2465::setSpeed(Speed newSpeed) { // Check if supported speed if (!((newSpeed == OverdriveSpeed) || (newSpeed == StandardSpeed))) { - return make_error_code(InvalidSpeedError); + return InvalidSpeedError; } // Check if requested speed is already set if (curConfig.get1WS() == (newSpeed == OverdriveSpeed)) { - return error_code(); + return none; } // Set the speed return writeConfig(Config(curConfig).set1WS(newSpeed == OverdriveSpeed)); } -error_code DS2465::triplet(TripletData & data) { +Result<OneWireMaster::TripletData> DS2465::triplet(bool sendBit) { // 1-Wire Triplet (Case B) // S AD,0 [A] 1WT [A] SS [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ @@ -239,89 +242,74 @@ // SS indicates byte containing search direction bit value in msbit const uint_least8_t command[] = { - 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); - 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); - } - } - return result; + 0x78, static_cast<uint_least8_t>(sendBit ? 0x80 : 0x00)}; + TRY(writeMemory(commandReg, command)); + + uint_least8_t status; + TRY_VALUE(status, pollBusy()); + + TripletData data; + data.readBit = ((status & status_SBR) == status_SBR); + data.readBitComplement = ((status & status_TSB) == status_TSB); + data.writeBit = ((status & status_DIR) == status_DIR); + return data; } -error_code DS2465::readBlock(span<uint_least8_t> recvBuf) { +Result<void> 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; span<uint_least8_t>::index_type recvIdx = 0; - while (recvIdx < recvBuf.size() && !result) { + while (recvIdx < recvBuf.size()) { const uint_least8_t command[] = { 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.subspan(recvIdx, command[1])); - } + TRY(writeMemory(commandReg, command)); + TRY(pollBusy()); + TRY(readMemory(scratchpad, recvBuf.subspan(recvIdx, command[1]))); recvIdx += command[1]; } - return result; + return none; } -error_code DS2465::writeBlock(span<const uint_least8_t> sendBuf) { - error_code result; +Result<void> DS2465::writeBlock(span<const uint_least8_t> sendBuf) { span<const uint_least8_t>::index_type sendIdx = 0; - while (sendIdx < sendBuf.size() && !result) { + while (sendIdx < sendBuf.size()) { const uint_least8_t command[] = { 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.subspan(sendIdx, command[1])); + TRY(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); - } - if (!result) { - result = pollBusy(); - } + TRY(writeMemory(commandReg, command)); + TRY(pollBusy()); sendIdx += command[1]; } - return result; + return none; } -error_code DS2465::writeMacBlock() const { +Result<void> DS2465::writeMacBlock() { // 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 const uint_least8_t command[] = {owTransmitBlockCmd, 0xFF}; - error_code result = writeMemory(commandReg, command); - if (!result) { - result = pollBusy(); - } - return result; + TRY(writeMemory(commandReg, command)); + TRY(pollBusy()); + return none; } -error_code DS2465::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { +Result<uint_least8_t> DS2465::readByteSetLevel(Level afterLevel) { // 1-Wire Read Bytes (Case C) // S AD,0 [A] CommandReg [A] 1WRB [A] Sr AD,1 [A] [Status] A [Status] A // \--------/ @@ -331,27 +319,17 @@ // [] indicates from slave // DD data read - error_code result = configureLevel(afterLevel); - if (result) { - return result; - } + TRY(configureLevel(afterLevel)); - const uint_least8_t command = 0x96; - result = writeMemory(commandReg, make_span(&command, 1)); - if (result) { - return result; - } - - result = pollBusy(); - if (result) { - return result; - } - - result = readMemory(0x62, make_span(&recvByte, 1)); - return result; + uint_least8_t buf = 0x96; + TRY(writeMemory(commandReg, make_span(&buf, 1))); + TRY(pollBusy()); + TRY(readMemory(0x62, make_span(&buf, 1))); + return buf; } -error_code DS2465::writeByteSetLevel(uint_least8_t sendByte, Level afterLevel) { +Result<void> DS2465::writeByteSetLevel(uint_least8_t sendByte, + Level afterLevel) { // 1-Wire Write Byte (Case B) // S AD,0 [A] CommandReg [A] 1WWB [A] DD [A] Sr AD,1 [A] [Status] A [Status] // A\ P @@ -360,22 +338,15 @@ // [] indicates from slave // DD data to write - error_code result = configureLevel(afterLevel); - if (result) { - return result; - } + TRY(configureLevel(afterLevel)); const uint_least8_t command[] = {0xA5, sendByte}; - result = writeMemory(commandReg, command); - if (result) { - return result; - } - - result = pollBusy(); - return result; + TRY(writeMemory(commandReg, command)); + TRY(pollBusy()); + return none; } -error_code DS2465::touchBitSetLevel(bool & sendRecvBit, Level afterLevel) { +Result<bool> DS2465::touchBitSetLevel(bool sendBit, Level afterLevel) { // 1-Wire bit (Case B) // S AD,0 [A] CommandReg [A] 1WSB [A] BB [A] Sr AD,1 [A] [Status] A [Status] // A\ P @@ -384,28 +355,20 @@ // [] indicates from slave // BB indicates byte containing bit value in msbit - error_code result = configureLevel(afterLevel); - if (result) { - return result; - } + TRY(configureLevel(afterLevel)); const uint_least8_t command[] = { - 0x87, static_cast<uint_least8_t>(sendRecvBit ? 0x80 : 0x00)}; - result = writeMemory(commandReg, command); - if (result) { - return result; - } + 0x87, static_cast<uint_least8_t>(sendBit ? 0x80 : 0x00)}; + TRY(writeMemory(commandReg, command)); uint_least8_t status; - result = pollBusy(&status); - if (!result) { - sendRecvBit = ((status & Status_SBR) == Status_SBR); - } - return result; + TRY_VALUE(status, pollBusy()); + + return (status & status_SBR) == status_SBR; } -error_code DS2465::writeMemory(uint_least8_t addr, - span<const uint_least8_t> buf) const { +Result<void> 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 // \-----/ @@ -414,18 +377,18 @@ // VSA valid SRAM memory address // DD memory data to write - error_code result = master->start(address_); - if (result) { + Result<void> result = master->start(address_); + if (!result) { master->stop(); return result; } result = master->writeByte(addr); - if (result) { + if (!result) { master->stop(); return result; } result = master->writeBlock(buf); - if (result) { + if (!result) { master->stop(); return result; } @@ -433,8 +396,8 @@ return result; } -error_code DS2465::readMemory(uint_least8_t addr, - span<uint_least8_t> buf) const { +Result<void> 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 // \-----/ @@ -443,13 +406,13 @@ // MA memory address // DD memory data read - error_code result = master->start(address_); - if (result) { + Result<void> result = master->start(address_); + if (!result) { master->stop(); return result; } result = master->writeByte(addr); - if (result) { + if (!result) { master->stop(); return result; } @@ -457,14 +420,14 @@ return result; } -error_code DS2465::readMemory(span<uint_least8_t> buf) const { - error_code result = master->start(address_ | 1); - if (result) { +Result<void> DS2465::readMemory(span<uint_least8_t> buf) const { + Result<void> result = master->start(address_ | 1); + if (!result) { master->stop(); return result; } - result = master->readBlock(I2CMaster::Nack, buf); - if (result) { + result = master->readBlock(buf, I2CMaster::Nack); + if (!result) { master->stop(); return result; } @@ -472,27 +435,26 @@ return result; } -error_code DS2465::writeConfig(Config config) { +Result<void> DS2465::writeConfig(Config config) { 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<void> result = writeMemory(configReg, make_span(&configBuf, 1)); + if (result) { result = readMemory(configReg, make_span(&configBuf, 1)); } - if (!result) { - if (configBuf != config.readByte()) - result = make_error_code(HardwareError); + if (result && configBuf != config.readByte()) { + result = HardwareError; } - if (!result) { + if (result) { curConfig = config; } return result; } -error_code DS2465::writePortParameter(PortParameter param, int val) { +Result<void> DS2465::writePortParameter(PortParameter param, int val) { if (val < 0 || val > 15) { - return make_error_code(ArgumentOutOfRangeError); + return ArgumentOutOfRangeError; } uint_least8_t addr = 0; @@ -521,8 +483,8 @@ } uint_least8_t data; - error_code result = readMemory(addr, make_span(&data, 1)); - if (result) { + Result<void> result = readMemory(addr, make_span(&data, 1)); + if (!result) { return result; } @@ -539,28 +501,24 @@ return result; } -error_code DS2465::pollBusy(uint_least8_t * pStatus) const { +Result<uint_least8_t> DS2465::pollBusy() const { const int pollLimit = 200; int pollCount = 0; uint_least8_t status; do { - error_code result = readMemory(make_span(&status, 1)); - if (result) { - return result; - } - if (pStatus != NULL) { - *pStatus = status; + const Result<void> result = readMemory(make_span(&status, 1)); + if (!result) { + return result.error(); } if (pollCount++ >= pollLimit) { - return make_error_code(HardwareError); + return HardwareError; } - } while (status & Status_1WB); - - return error_code(); + } while ((status & status_1WB) == status_1WB); + return status; } -error_code DS2465::reset() { +Result<void> DS2465::reset() { // 1-Wire reset (Case B) // S AD,0 [A] CommandReg [A] 1WRS [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ @@ -568,191 +526,210 @@ // [] indicates from slave uint_least8_t buf = 0xB4; - error_code result = writeMemory(commandReg, make_span(&buf, 1)); + TRY(writeMemory(commandReg, make_span(&buf, 1))); + + TRY_VALUE(buf, pollBusy()); - if (!result) { - result = pollBusy(&buf); + if ((buf & status_SD) == status_SD) { + return ShortDetectedError; + } + if ((buf & status_PPD) != status_PPD) { + return NoSlaveError; } - 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); - } - } - - return result; + return none; } -error_code DS2465::resetDevice() { +Result<void> DS2465::resetDevice() { // Device Reset // S AD,0 [A] CommandReg [A] 1WMR [A] Sr AD,1 [A] [SS] A\ P // [] indicates from slave // SS status byte to read to verify state uint_least8_t buf = 0xF0; - error_code result = writeMemory(commandReg, make_span(&buf, 1)); + Result<void> result = writeMemory(commandReg, make_span(&buf, 1)); - if (!result) { + if (result) { result = readMemory(make_span(&buf, 1)); } - if (!result) { + if (result) { if ((buf & 0xF7) != 0x10) { - result = make_error_code(HardwareError); + result = HardwareError; } } - if (!result) { + if (result) { reset(); // do a command to get 1-Wire master reset out of holding state } return result; } -error_code +Result<void> DS2465::computeNextMasterSecret(AuthenticationData::const_span data) { - error_code result = writeMemory(scratchpad, data); - if (!result) { + Result<void> result = writeMemory(scratchpad, data); + if (result) { result = computeNextMasterSecret(false, 0, FullPage); } return result; } -error_code +Result<void> DS2465::computeNextMasterSecretWithSwap(AuthenticationData::const_span data, int pageNum, PageRegion region) { - error_code result = writeMemory(scratchpad, data); - if (!result) { + Result<void> result = writeMemory(scratchpad, data); + if (result) { result = computeNextMasterSecret(true, pageNum, region); } return result; } -error_code DS2465::computeWriteMac(WriteMacData::const_span data) const { - error_code result = writeMemory(scratchpad, data); - if (!result) { +Result<void> DS2465::doComputeWriteMac(WriteMacData::const_span data) const { + Result<void> result = writeMemory(scratchpad, data); + if (result) { result = computeWriteMac(false, false, 0, 0); } return result; } -error_code DS2465::computeWriteMac(WriteMacData::const_span data, - Page::span mac) const { - error_code result = computeWriteMac(data); +Result<DS2465::Page::array> +DS2465::computeWriteMac(WriteMacData::const_span data) const { + Result<void> result = doComputeWriteMac(data); if (!result) { - result = readMemory(mac); + return result.error(); } - return result; + Page::array mac; + result = readMemory(mac); + if (!result) { + return result.error(); + } + return mac; } -error_code -DS2465::computeAndTransmitWriteMac(WriteMacData::const_span data) const { - error_code result = computeWriteMac(data); - if (!result) { +Result<void> DS2465::computeAndTransmitWriteMac(WriteMacData::const_span data) { + Result<void> result = doComputeWriteMac(data); + if (result) { result = writeMacBlock(); } return result; } -error_code DS2465::computeWriteMacWithSwap(WriteMacData::const_span data, - int pageNum, int segmentNum) const { - error_code result = writeMemory(scratchpad, data); - if (!result) { +Result<void> DS2465::doComputeWriteMacWithSwap(WriteMacData::const_span data, + int pageNum, + int segmentNum) const { + Result<void> result = writeMemory(scratchpad, data); + if (result) { result = computeWriteMac(false, true, pageNum, segmentNum); } return result; } -error_code DS2465::computeWriteMacWithSwap(WriteMacData::const_span data, - int pageNum, int segmentNum, - Page::span mac) const { - error_code result = computeWriteMacWithSwap(data, pageNum, segmentNum); +Result<DS2465::Page::array> +DS2465::computeWriteMacWithSwap(WriteMacData::const_span data, int pageNum, + int segmentNum) const { + Result<void> result = doComputeWriteMacWithSwap(data, pageNum, segmentNum); if (!result) { - result = readMemory(mac); + return result.error(); } - return result; + Page::array mac; + result = readMemory(mac); + if (!result) { + return result.error(); + } + return mac; } -error_code +Result<void> DS2465::computeAndTransmitWriteMacWithSwap(WriteMacData::const_span data, - int pageNum, int segmentNum) const { - error_code result = computeWriteMacWithSwap(data, pageNum, segmentNum); - if (!result) { + int pageNum, int segmentNum) { + Result<void> result = doComputeWriteMacWithSwap(data, pageNum, segmentNum); + if (result) { result = writeMacBlock(); } return result; } -error_code DS2465::computeSlaveSecret(AuthenticationData::const_span data) { - error_code result = writeMemory(scratchpad, data); - if (!result) { +Result<void> DS2465::computeSlaveSecret(AuthenticationData::const_span data) { + Result<void> result = writeMemory(scratchpad, data); + if (result) { result = computeSlaveSecret(false, 0, FullPage); } return result; } -error_code +Result<void> DS2465::computeSlaveSecretWithSwap(AuthenticationData::const_span data, int pageNum, PageRegion region) { - error_code result = writeMemory(scratchpad, data); - if (!result) { + Result<void> result = writeMemory(scratchpad, data); + if (result) { result = computeSlaveSecret(true, pageNum, region); } return result; } -error_code DS2465::computeAuthMac(AuthenticationData::const_span data) const { - error_code result = writeMemory(scratchpad, data); - if (!result) { +Result<void> +DS2465::doComputeAuthMac(AuthenticationData::const_span data) const { + Result<void> result = writeMemory(scratchpad, data); + if (result) { result = computeAuthMac(false, 0, FullPage); } return result; } -error_code DS2465::computeAuthMac(AuthenticationData::const_span data, - Page::span mac) const { - error_code result = computeAuthMac(data); +Result<DS2465::Page::array> +DS2465::computeAuthMac(AuthenticationData::const_span data) const { + Result<void> result = doComputeAuthMac(data); if (!result) { - result = readMemory(mac); + return result.error(); } - return result; + Page::array mac; + result = readMemory(mac); + if (!result) { + return result.error(); + } + return mac; } -error_code -DS2465::computeAndTransmitAuthMac(AuthenticationData::const_span data) const { - error_code result = computeAuthMac(data); - if (!result) { +Result<void> +DS2465::computeAndTransmitAuthMac(AuthenticationData::const_span data) { + Result<void> result = doComputeAuthMac(data); + if (result) { result = writeMacBlock(); } return result; } -error_code DS2465::computeAuthMacWithSwap(AuthenticationData::const_span data, - int pageNum, - PageRegion region) const { - error_code result = writeMemory(scratchpad, data); - if (!result) { +Result<void> +DS2465::doComputeAuthMacWithSwap(AuthenticationData::const_span data, + int pageNum, PageRegion region) const { + Result<void> result = writeMemory(scratchpad, data); + if (result) { result = computeAuthMac(true, pageNum, region); } return result; } -error_code DS2465::computeAuthMacWithSwap(AuthenticationData::const_span data, - int pageNum, PageRegion region, - Page::span mac) const { - error_code result = computeAuthMacWithSwap(data, pageNum, region); +Result<DS2465::Page::array> +DS2465::computeAuthMacWithSwap(AuthenticationData::const_span data, int pageNum, + PageRegion region) const { + Result<void> result = doComputeAuthMacWithSwap(data, pageNum, region); if (!result) { - result = readMemory(mac); + return result.error(); } - return result; + Page::array mac; + result = readMemory(mac); + if (!result) { + return result.error(); + } + return mac; } -error_code DS2465::computeAndTransmitAuthMacWithSwap( - AuthenticationData::const_span data, int pageNum, PageRegion region) const { - error_code result = computeAuthMacWithSwap(data, pageNum, region); - if (!result) { +Result<void> +DS2465::computeAndTransmitAuthMacWithSwap(AuthenticationData::const_span data, + int pageNum, PageRegion region) { + Result<void> result = doComputeAuthMacWithSwap(data, pageNum, region); + if (result) { result = writeMacBlock(); } return result; @@ -770,10 +747,8 @@ case ArgumentOutOfRangeError: return "Argument Out of Range Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance;
--- a/MaximInterfaceDevices/DS2465.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS2465.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS2465 -#define MaximInterfaceDevices_DS2465 +#ifndef MaximInterfaceDevices_DS2465_hpp +#define MaximInterfaceDevices_DS2465_hpp #include <MaximInterfaceCore/array_span.hpp> #include <MaximInterfaceCore/I2CMaster.hpp> @@ -41,7 +41,11 @@ namespace MaximInterfaceDevices { -/// Interface to the DS2465 1-Wire master and SHA-256 coprocessor. +/// @brief Interface to the DS2465 1-Wire master and SHA-256 coprocessor. +/// @details +/// Const member functions should not change the settings of the DS2465 or +/// affect the state of the 1-Wire bus. Read pointer, scratchpad, MAC output +/// register, and command register on the DS2465 are considered mutable. class DS2465 : public Core::OneWireMaster { public: enum ErrorValue { HardwareError = 1, ArgumentOutOfRangeError }; @@ -173,10 +177,6 @@ uint_least8_t readByte_; }; - // Const member functions should not change the settings of the DS2465 or - // affect the state of the 1-Wire bus. Read pointer, scratchpad, MAC output - // register, and command register on the DS2465 are considered mutable. - DS2465(Core::Sleep & sleep, Core::I2CMaster & master, uint_least8_t address = 0x30) : sleep(&sleep), master(&master), address_(address & 0xFE) {} @@ -190,158 +190,158 @@ void setAddress(uint_least8_t address) { address_ = address & 0xFE; } /// Initialize hardware for use. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> initialize(Config config = Config()); /// @brief Write a new configuration to the DS2465. /// @param[in] config New configuration to write. - MaximInterfaceDevices_EXPORT Core::error_code writeConfig(Config config); + MaximInterfaceDevices_EXPORT Core::Result<void> writeConfig(Config config); /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writePortParameter(PortParameter param, int val); // 1-Wire Master Commands - MaximInterfaceDevices_EXPORT virtual Core::error_code reset(); + MaximInterfaceDevices_EXPORT virtual Core::Result<void> reset(); - MaximInterfaceDevices_EXPORT virtual Core::error_code - touchBitSetLevel(bool & sendRecvBit, Level afterLevel); + MaximInterfaceDevices_EXPORT virtual Core::Result<bool> + touchBitSetLevel(bool sendBit, Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code - readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterfaceDevices_EXPORT virtual Core::Result<uint_least8_t> + readByteSetLevel(Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> readBlock(Core::span<uint_least8_t> recvBuf); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> writeBlock(Core::span<const uint_least8_t> sendBuf); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> setSpeed(Speed newSpeed); /// @copydoc Core::OneWireMaster::setLevel /// @note /// The DS2465 only supports enabling strong pullup following a 1-Wire read or /// write operation. - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> setLevel(Level newLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code - triplet(TripletData & data); + MaximInterfaceDevices_EXPORT virtual Core::Result<TripletData> + triplet(bool sendBit); // DS2465 Coprocessor Commands /// @brief Read data from an EEPROM memory page. /// @param pageNum Page number to read from. - /// @param[out] data Data that was read. - MaximInterfaceDevices_EXPORT Core::error_code readPage(int pageNum, - Page::span data) const; + /// @returns Data that was read. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + readPage(int pageNum) const; /// @brief Write data to an EEPROM memory page. /// @param pageNum Page number to copy to. /// @param data Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writePage(int pageNum, Page::const_span data); /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeSegment(int pageNum, int segmentNum, Segment::const_span data); /// Write data to the secret EEPROM memory page. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeMasterSecret(Page::const_span masterSecret); /// @brief Compute Next Master Secret. /// @param data Combined data fields for computation. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeNextMasterSecret(AuthenticationData::const_span data); /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeNextMasterSecretWithSwap(AuthenticationData::const_span data, int pageNum, PageRegion region); /// @brief Compute Write MAC. /// @param data Combined data fields for computation. - /// @param[out] mac Computed Write MAC. - MaximInterfaceDevices_EXPORT Core::error_code - computeWriteMac(WriteMacData::const_span data, Page::span mac) const; + /// @returns Computed Write MAC. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + computeWriteMac(WriteMacData::const_span data) const; /// @brief Compute Write MAC. /// @param data Combined data fields for computation. - MaximInterfaceDevices_EXPORT Core::error_code - computeAndTransmitWriteMac(WriteMacData::const_span data) const; + MaximInterfaceDevices_EXPORT Core::Result<void> + computeAndTransmitWriteMac(WriteMacData::const_span data); /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + /// @returns Computed Write MAC. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> computeWriteMacWithSwap(WriteMacData::const_span data, int pageNum, - int segmentNum, Page::span mac) const; + int segmentNum) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeAndTransmitWriteMacWithSwap(WriteMacData::const_span data, int pageNum, - int segmentNum) const; + int segmentNum); /// @brief Compute Slave Secret (S-Secret). /// @param data Combined data fields for computation. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeSlaveSecret(AuthenticationData::const_span data); /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeSlaveSecretWithSwap(AuthenticationData::const_span data, int pageNum, PageRegion region); /// @brief Compute Authentication MAC. /// @param data Combined data fields for computation. - /// @param[out] mac Computed Auth MAC. - MaximInterfaceDevices_EXPORT Core::error_code - computeAuthMac(AuthenticationData::const_span data, Page::span mac) const; + /// @returns Computed Auth MAC. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + computeAuthMac(AuthenticationData::const_span data) const; /// @brief Compute Authentication MAC. /// @param data Combined data fields for computation. - MaximInterfaceDevices_EXPORT Core::error_code - computeAndTransmitAuthMac(AuthenticationData::const_span data) const; + MaximInterfaceDevices_EXPORT Core::Result<void> + computeAndTransmitAuthMac(AuthenticationData::const_span data); /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + /// @returns Computed Auth MAC. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> computeAuthMacWithSwap(AuthenticationData::const_span data, int pageNum, - PageRegion region, Page::span mac) const; + PageRegion region) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeAndTransmitAuthMacWithSwap(AuthenticationData::const_span data, - int pageNum, PageRegion region) const; + int pageNum, PageRegion region); MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); @@ -354,62 +354,73 @@ /// @brief Performs a soft reset on the DS2465. /// @note This is not a 1-Wire Reset. - Core::error_code resetDevice(); + Core::Result<void> resetDevice(); /// @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. - Core::error_code pollBusy(uint_least8_t * pStatus = NULL) const; + /// Polls the DS2465 status waiting for the 1-Wire Busy bit (1WB) to be cleared. + /// @returns Status byte or TimeoutError if poll limit reached. + Core::Result<uint_least8_t> pollBusy() const; /// @brief Ensure that the desired 1-Wire level is set in the configuration. /// @param level Desired 1-Wire level. - Core::error_code configureLevel(Level level); + Core::Result<void> configureLevel(Level level); /// @note Const since only for internal use. - Core::error_code writeMemory(uint_least8_t addr, - Core::span<const uint_least8_t> buf) const; + Core::Result<void> writeMemory(uint_least8_t addr, + Core::span<const uint_least8_t> buf) const; /// @brief Read memory from the DS2465. /// @param addr Address to begin reading from. /// @param[out] buf Buffer to hold read data. - Core::error_code readMemory(uint_least8_t addr, - Core::span<uint_least8_t> buf) const; + Core::Result<void> readMemory(uint_least8_t addr, + Core::span<uint_least8_t> buf) const; /// @brief Read memory from the DS2465 at the current pointer. /// @param[out] buf Buffer to hold read data. - Core::error_code readMemory(Core::span<uint_least8_t> buf) const; + Core::Result<void> readMemory(Core::span<uint_least8_t> buf) const; /// Write the last computed MAC to the 1-Wire bus. - Core::error_code writeMacBlock() const; + Core::Result<void> writeMacBlock(); - Core::error_code computeWriteMac(WriteMacData::const_span data) const; + Core::Result<void> doComputeWriteMac(WriteMacData::const_span data) const; - Core::error_code computeWriteMacWithSwap(WriteMacData::const_span data, - int pageNum, int segmentNum) const; + Core::Result<void> doComputeWriteMacWithSwap(WriteMacData::const_span data, + int pageNum, + int segmentNum) const; - Core::error_code computeAuthMac(AuthenticationData::const_span data) const; + Core::Result<void> + doComputeAuthMac(AuthenticationData::const_span data) const; - Core::error_code computeAuthMacWithSwap(AuthenticationData::const_span data, - int pageNum, PageRegion region) const; + Core::Result<void> + doComputeAuthMacWithSwap(AuthenticationData::const_span data, int pageNum, + PageRegion region) const; // Legacy implementations - Core::error_code copyScratchpad(bool destSecret, int pageNum, bool notFull, - int segmentNum); + Core::Result<void> copyScratchpad(bool destSecret, int pageNum, bool notFull, + int segmentNum); + + Core::Result<void> computeNextMasterSecret(bool swap, int pageNum, + PageRegion region); - Core::error_code computeNextMasterSecret(bool swap, int pageNum, - PageRegion region); + Core::Result<void> computeWriteMac(bool regwrite, bool swap, int pageNum, + int segmentNum) const; + + Core::Result<void> computeSlaveSecret(bool swap, int pageNum, + PageRegion region); - Core::error_code computeWriteMac(bool regwrite, bool swap, int pageNum, - int segmentNum) const; + Core::Result<void> computeAuthMac(bool swap, int pageNum, + PageRegion region) const; +}; + +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { - Core::error_code computeSlaveSecret(bool swap, int pageNum, - PageRegion region); +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS2465::ErrorValue> + : true_type {}; - Core::error_code computeAuthMac(bool swap, int pageNum, - PageRegion region) const; -}; +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { inline Core::error_code make_error_code(DS2465::ErrorValue e) { return Core::error_code(e, DS2465::errorCategory());
--- a/MaximInterfaceDevices/DS2480B.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS2480B.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -33,6 +33,9 @@ #include <MaximInterfaceCore/Error.hpp> #include "DS2480B.hpp" +#define TRY MaximInterfaceCore_TRY +#define TRY_VALUE MaximInterfaceCore_TRY_VALUE + // Mode Commands #define MODE_DATA 0xE1 #define MODE_COMMAND 0xE3 @@ -173,23 +176,23 @@ using namespace Core; -error_code DS2480B::initialize() { +Result<void> DS2480B::initialize() { level = NormalLevel; mode = MODSEL_COMMAND; speed = SPEEDSEL_STD; // 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) { + Result<void> result = uart->setBaudRate(4800); + if (!result) { return result; } result = uart->sendBreak(); - if (result) { + if (!result) { return result; } result = uart->setBaudRate(9600); - if (result) { + if (!result) { return result; } @@ -198,62 +201,55 @@ // Flush the read buffer. result = uart->clearReadBuffer(); - if (result) { + if (!result) { return result; } // Send the timing byte. result = uart->writeByte(CMD_COMM | FUNCTSEL_RESET | SPEEDSEL_STD); - if (result) { + if (!result) { return result; } // Change the DS2480 baud rate. result = uart->writeByte(CMD_CONFIG | PARMSEL_BAUDRATE | PARMSET_115200); - if (result) { + if (!result) { return result; } // Change our baud rate. result = uart->setBaudRate(115200); - if (result) { + if (!result) { return result; } + // Verify response. uint_least8_t response; - - // Verify response. - result = uart->readByte(response); - if (result) { - return result; - } + TRY_VALUE(response, uart->readByte()); if ((response & (PARMSEL_MASK | PARMSET_MASK)) != (PARMSEL_BAUDRATE | PARMSET_115200)) { - return make_error_code(HardwareError); + return HardwareError; } // Set the SPUD time value. result = uart->writeByte(CMD_CONFIG | PARMSEL_5VPULSE | PARMSET_infinite); - if (result) { + if (!result) { return result; } // Verify response. - result = uart->readByte(response); - if (result) { - return result; - } + TRY_VALUE(response, uart->readByte()); if ((response & (PARMSEL_MASK | PARMSET_MASK)) != (PARMSEL_5VPULSE | PARMSET_infinite)) { - return make_error_code(HardwareError); + return HardwareError; } return result; } -error_code DS2480B::reset() { +Result<void> DS2480B::reset() { if (level != NormalLevel) { - return make_error_code(InvalidLevelError); + return InvalidLevelError; } uint_least8_t packet[2]; @@ -269,29 +265,25 @@ packet[packetLen++] = CMD_COMM | FUNCTSEL_RESET | speed; // Send the packet. - error_code result = uart->writeBlock(make_span(packet, packetLen)); - if (result) { - return result; - } + TRY(uart->writeBlock(make_span(packet, packetLen))); // Read back the response. - result = uart->readByte(packet[0]); - if (result) { - return result; - } + TRY_VALUE(packet[0], uart->readByte()); // 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 ShortDetectedError; } - return result; + if ((packet[0] & RB_RESET_MASK) == RB_NOPRESENCE) { + return NoSlaveError; + } + + return none; } -error_code DS2480B::touchBitSetLevel(bool & sendRecvBit, Level afterLevel) { +Result<bool> DS2480B::touchBitSetLevel(bool sendBit, Level afterLevel) { if (level != NormalLevel) { - return make_error_code(InvalidLevelError); + return InvalidLevelError; } uint_least8_t packet[3]; @@ -304,8 +296,8 @@ } // Construct the command. - packet[packetLen++] = CMD_COMM | FUNCTSEL_BIT | - (sendRecvBit ? BITPOL_ONE : BITPOL_ZERO) | speed; + packet[packetLen++] = + CMD_COMM | FUNCTSEL_BIT | (sendBit ? BITPOL_ONE : BITPOL_ZERO) | speed; switch (afterLevel) { case NormalLevel: break; @@ -317,35 +309,27 @@ break; default: - return make_error_code(InvalidLevelError); + return InvalidLevelError; } // Send the packet. - error_code result = uart->writeBlock(make_span(packet, packetLen)); - if (result) { - return result; - } + TRY(uart->writeBlock(make_span(packet, packetLen))); // Read back the response. - result = uart->readByte(packet[0]); - if (result) { - return result; - } + TRY_VALUE(packet[0], uart->readByte()); // 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); + if ((packet[0] & 0xE0) != 0x80) { + return HardwareError; } - return result; + level = afterLevel; + return (packet[0] & RB_BIT_MASK) == RB_BIT_ONE; } -error_code DS2480B::writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel) { +Result<void> DS2480B::writeByteSetLevel(uint_least8_t sendByte, + Level afterLevel) { if (level != NormalLevel) { - return make_error_code(InvalidLevelError); + return InvalidLevelError; } switch (afterLevel) { @@ -356,7 +340,7 @@ return OneWireMaster::writeByteSetLevel(sendByte, afterLevel); default: - return make_error_code(InvalidLevelError); + return InvalidLevelError; } uint_least8_t packet[3]; @@ -377,28 +361,22 @@ } // Send the packet. - error_code result = uart->writeBlock(make_span(packet, packetLen)); - if (result) { - return result; - } + TRY(uart->writeBlock(make_span(packet, packetLen))); // Read back the response. - result = uart->readByte(packet[0]); - if (result) { - return result; - } + TRY_VALUE(packet[0], uart->readByte()); // Interpret the response. if (packet[0] != sendByte) { - result = make_error_code(HardwareError); + return HardwareError; } - return result; + + return none; } -error_code DS2480B::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { +Result<uint_least8_t> DS2480B::readByteSetLevel(Level afterLevel) { if (level != NormalLevel) { - return make_error_code(InvalidLevelError); + return InvalidLevelError; } switch (afterLevel) { @@ -406,10 +384,10 @@ break; case StrongLevel: - return OneWireMaster::readByteSetLevel(recvByte, afterLevel); + return OneWireMaster::readByteSetLevel(afterLevel); default: - return make_error_code(InvalidLevelError); + return InvalidLevelError; } uint_least8_t packet[2]; @@ -425,17 +403,16 @@ packet[packetLen++] = 0xFF; // Send the packet. - error_code result = uart->writeBlock(make_span(packet, packetLen)); - if (result) { - return result; + const Result<void> result = uart->writeBlock(make_span(packet, packetLen)); + if (!result) { + return result.error(); } // Read back the response. - result = uart->readByte(recvByte); - return result; + return uart->readByte(); } -error_code DS2480B::setSpeed(Speed newSpeed) { +Result<void> DS2480B::setSpeed(Speed newSpeed) { uint_least8_t newSpeedByte; switch (newSpeed) { case OverdriveSpeed: @@ -447,10 +424,10 @@ break; default: - return make_error_code(InvalidSpeedError); + return InvalidSpeedError; } if (speed == newSpeedByte) { - return error_code(); + return none; } speed = newSpeedByte; @@ -470,9 +447,9 @@ return uart->writeBlock(make_span(packet, packetLen)); } -error_code DS2480B::setLevel(Level newLevel) { +Result<void> DS2480B::setLevel(Level newLevel) { if (level == newLevel) { - return error_code(); + return none; } uint_least8_t packet[2]; @@ -497,33 +474,27 @@ break; default: - return make_error_code(InvalidLevelError); + return InvalidLevelError; } // Send the packet. - error_code result = uart->writeBlock(make_span(packet, packetLen)); - if (result) { - return result; - } + TRY(uart->writeBlock(make_span(packet, packetLen))); if (newLevel == NormalLevel) { // Read back the response. - result = uart->readByte(packet[0]); - if (result) { - return result; - } + TRY_VALUE(packet[0], uart->readByte()); // Interpret the response. if ((packet[0] & 0xE0) != 0xE0) { - return make_error_code(HardwareError); + return HardwareError; } } level = newLevel; - return result; + return none; } -error_code DS2480B::sendCommand(uint_least8_t command) { +Result<void> DS2480B::sendCommand(uint_least8_t command) { uint_least8_t packet[2]; int packetLen = 0; @@ -549,10 +520,8 @@ switch (condition) { case HardwareError: return "Hardware Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance;
--- a/MaximInterfaceDevices/DS2480B.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS2480B.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS2480B -#define MaximInterfaceDevices_DS2480B +#ifndef MaximInterfaceDevices_DS2480B_hpp +#define MaximInterfaceDevices_DS2480B_hpp #include <MaximInterfaceCore/OneWireMaster.hpp> #include <MaximInterfaceCore/Sleep.hpp> @@ -52,30 +52,30 @@ void setUart(Core::Uart & uart) { this->uart = &uart; } - MaximInterfaceDevices_EXPORT Core::error_code initialize(); + MaximInterfaceDevices_EXPORT Core::Result<void> initialize(); - MaximInterfaceDevices_EXPORT virtual Core::error_code reset(); + MaximInterfaceDevices_EXPORT virtual Core::Result<void> reset(); - MaximInterfaceDevices_EXPORT virtual Core::error_code - touchBitSetLevel(bool & sendRecvBit, Level afterLevel); + MaximInterfaceDevices_EXPORT virtual Core::Result<bool> + touchBitSetLevel(bool sendBit, Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code - readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterfaceDevices_EXPORT virtual Core::Result<uint_least8_t> + readByteSetLevel(Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> setSpeed(Speed newSpeed); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> setLevel(Level newLevel); MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); protected: - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> sendCommand(uint_least8_t command); private: @@ -87,6 +87,16 @@ uint_least8_t speed; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS2480B::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS2480B::ErrorValue e) { return Core::error_code(e, DS2480B::errorCategory()); }
--- a/MaximInterfaceDevices/DS2482_DS2484.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS2482_DS2484.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -33,60 +33,50 @@ #include <MaximInterfaceCore/Error.hpp> #include "DS2482_DS2484.hpp" +#define TRY MaximInterfaceCore_TRY +#define TRY_VALUE MaximInterfaceCore_TRY_VALUE + namespace MaximInterfaceDevices { using namespace Core; -// Device Status bits -enum StatusBit { - Status_1WB = 0x01, - Status_PPD = 0x02, - Status_SD = 0x04, - Status_LL = 0x08, - Status_RST = 0x10, - Status_SBR = 0x20, - Status_TSB = 0x40, - Status_DIR = 0x80 -}; +// Device status bits. +static const uint_least8_t status_1WB = 0x01; +static const uint_least8_t status_PPD = 0x02; +static const uint_least8_t status_SD = 0x04; +static const uint_least8_t status_SBR = 0x20; +static const uint_least8_t status_TSB = 0x40; +static const uint_least8_t status_DIR = 0x80; -error_code DS2482_DS2484::initialize(Config config) { - error_code result = resetDevice(); - if (result) { - return result; - } +Result<void> DS2482_DS2484::initialize(Config config) { + TRY(resetDevice()); // Write the default configuration setup. - result = writeConfig(config); - return result; + TRY(writeConfig(config)); + return none; } -error_code DS2482_DS2484::resetDevice() { +Result<void> DS2482_DS2484::resetDevice() { // Device Reset // S AD,0 [A] DRST [A] Sr AD,1 [A] [SS] A\ P // [] indicates from slave // SS status byte to read to verify state - error_code result = sendCommand(0xF0); - if (result) { - return result; - } + TRY(sendCommand(0xF0)); uint_least8_t buf; - result = readRegister(buf); - if (result) { - return result; - } + TRY_VALUE(buf, readRegister()); if ((buf & 0xF7) != 0x10) { - return make_error_code(HardwareError); + return HardwareError; } // Do a command to get 1-Wire master reset out of holding state. reset(); - return result; + return none; } -error_code DS2482_DS2484::triplet(TripletData & data) { +Result<OneWireMaster::TripletData> DS2482_DS2484::triplet(bool sendBit) { // 1-Wire Triplet (Case B) // S AD,0 [A] 1WT [A] SS [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ @@ -94,48 +84,41 @@ // [] indicates from slave // SS indicates byte containing search direction bit value in msbit - error_code result = sendCommand(0x78, data.writeBit ? 0x80 : 0x00); - if (!result) { - uint_least8_t status; - result = pollBusy(&status); - if (!result) { - data.readBit = ((status & Status_SBR) == Status_SBR); - data.readBitComplement = ((status & Status_TSB) == Status_TSB); - data.writeBit = ((status & Status_DIR) == Status_DIR); - } - } - return result; + TRY(sendCommand(0x78, sendBit ? 0x80 : 0x00)); + + uint_least8_t status; + TRY_VALUE(status, pollBusy()); + + TripletData data; + data.readBit = ((status & status_SBR) == status_SBR); + data.readBitComplement = ((status & status_TSB) == status_TSB); + data.writeBit = ((status & status_DIR) == status_DIR); + return data; } -error_code DS2482_DS2484::reset() { +Result<void> DS2482_DS2484::reset() { // 1-Wire reset (Case B) // S AD,0 [A] 1WRS [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ // Repeat until 1WB bit has changed to 0 // [] indicates from slave - error_code result = sendCommand(0xB4); - if (result) { - return result; - } + TRY(sendCommand(0xB4)); + + uint_least8_t status; + TRY_VALUE(status, pollBusy()); - uint_least8_t buf; - result = pollBusy(&buf); - if (result) { - return result; + if ((status & status_SD) == status_SD) { + return ShortDetectedError; + } + if ((status & status_PPD) != status_PPD) { + return NoSlaveError; } - 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; + return none; } -error_code DS2482_DS2484::touchBitSetLevel(bool & sendRecvBit, - Level afterLevel) { +Result<bool> DS2482_DS2484::touchBitSetLevel(bool sendBit, Level afterLevel) { // 1-Wire bit (Case B) // S AD,0 [A] 1WSB [A] BB [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ @@ -143,26 +126,15 @@ // [] indicates from slave // BB indicates byte containing bit value in msbit - error_code result = configureLevel(afterLevel); - if (result) { - return result; - } - - result = sendCommand(0x87, sendRecvBit ? 0x80 : 0x00); - if (result) { - return result; - } - + TRY(configureLevel(afterLevel)); + TRY(sendCommand(0x87, sendBit ? 0x80 : 0x00)); uint_least8_t status; - result = pollBusy(&status); - if (!result) { - sendRecvBit = ((status & Status_SBR) == Status_SBR); - } - return result; + TRY_VALUE(status, pollBusy()); + return (status & status_SBR) == status_SBR; } -error_code DS2482_DS2484::writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel) { +Result<void> 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 // \--------/ @@ -170,22 +142,13 @@ // [] indicates from slave // DD data to write - error_code result = configureLevel(afterLevel); - if (result) { - return result; - } - - result = sendCommand(0xA5, sendByte); - if (result) { - return result; - } - - result = pollBusy(); - return result; + TRY(configureLevel(afterLevel)); + TRY(sendCommand(0xA5, sendByte)); + TRY(pollBusy()); + return none; } -error_code DS2482_DS2484::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { +Result<uint_least8_t> DS2482_DS2484::readByteSetLevel(Level afterLevel) { // 1-Wire Read Bytes (Case C) // S AD,0 [A] 1WRB [A] Sr AD,1 [A] [Status] A [Status] A // \--------/ @@ -195,119 +158,94 @@ // [] indicates from slave // DD data read - error_code result = configureLevel(afterLevel); - if (result) { - return result; - } - - result = sendCommand(0x96); - if (result) { - return result; - } - - result = pollBusy(); - if (result) { - return result; - } - - result = readRegister(0xE1, recvByte); - return result; + TRY(configureLevel(afterLevel)); + TRY(sendCommand(0x96)); + TRY(pollBusy()); + return readRegister(0xE1); } -error_code DS2482_DS2484::setSpeed(Speed newSpeed) { +Result<void> DS2482_DS2484::setSpeed(Speed newSpeed) { // Check if supported speed if (!((newSpeed == OverdriveSpeed) || (newSpeed == StandardSpeed))) { - return make_error_code(InvalidSpeedError); + return InvalidSpeedError; } // Check if requested speed is already set if (curConfig.get1WS() == (newSpeed == OverdriveSpeed)) { - return error_code(); + return none; } // Set the speed return writeConfig(Config(curConfig).set1WS(newSpeed == OverdriveSpeed)); } -error_code DS2482_DS2484::setLevel(Level newLevel) { +Result<void> DS2482_DS2484::setLevel(Level newLevel) { if (newLevel == StrongLevel) { - return make_error_code(InvalidLevelError); + return InvalidLevelError; } return configureLevel(newLevel); } -error_code DS2482_DS2484::writeConfig(Config config) { +Result<void> DS2482_DS2484::writeConfig(Config config) { uint_least8_t configBuf = ((config.readByte() ^ 0xF) << 4) | config.readByte(); - error_code result = sendCommand(0xD2, configBuf); - if (!result) { - result = readRegister(0xC3, configBuf); + TRY(sendCommand(0xD2, configBuf)); + + TRY_VALUE(configBuf, readRegister(0xC3)); + + if (configBuf != config.readByte()) { + return HardwareError; } - if (!result) { - if (configBuf != config.readByte()) { - result = make_error_code(HardwareError); - } - } - if (!result) { - curConfig = config; - } - return result; + + curConfig = config; + return none; } -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); - } - return result; +Result<uint_least8_t> DS2482_DS2484::readRegister(uint_least8_t reg) const { + TRY(sendCommand(0xE1, reg)); + return readRegister(); } -error_code DS2482_DS2484::readRegister(uint_least8_t & buf) const { - return master->readPacket(address_, make_span(&buf, 1)); +Result<uint_least8_t> DS2482_DS2484::readRegister() const { + uint_least8_t buf; + TRY(master->readPacket(address_, make_span(&buf, 1), I2CMaster::Stop)); + return buf; } -error_code DS2482_DS2484::pollBusy(uint_least8_t * pStatus) { +Result<uint_least8_t> DS2482_DS2484::pollBusy() { const int pollLimit = 200; int pollCount = 0; uint_least8_t status; do { - error_code result = readRegister(status); - if (result) { - return result; - } - if (pStatus != NULL) { - *pStatus = status; + TRY_VALUE(status, readRegister()); + if (pollCount++ >= pollLimit) { + return HardwareError; } - if (pollCount++ >= pollLimit) { - return make_error_code(HardwareError); - } - } while (status & Status_1WB); - - return error_code(); + } while ((status & status_1WB) == status_1WB); + return status; } -error_code DS2482_DS2484::configureLevel(Level level) { +Result<void> DS2482_DS2484::configureLevel(Level level) { // Check if supported level if (!((level == NormalLevel) || (level == StrongLevel))) { - return make_error_code(InvalidLevelError); + return InvalidLevelError; } // Check if requested level already set if (curConfig.getSPU() == (level == StrongLevel)) { - return error_code(); + return none; } // Set the level return writeConfig(Config(curConfig).setSPU(level == StrongLevel)); } -error_code DS2482_DS2484::sendCommand(uint_least8_t cmd) const { - return master->writePacket(address_, make_span(&cmd, 1)); +Result<void> DS2482_DS2484::sendCommand(uint_least8_t cmd) const { + return master->writePacket(address_, make_span(&cmd, 1), I2CMaster::Stop); } -error_code DS2482_DS2484::sendCommand(uint_least8_t cmd, - uint_least8_t param) const { - uint_least8_t buf[] = {cmd, param}; - return master->writePacket(address_, buf); +Result<void> DS2482_DS2484::sendCommand(uint_least8_t cmd, + uint_least8_t param) const { + const uint_least8_t buf[] = {cmd, param}; + return master->writePacket(address_, buf, I2CMaster::Stop); } const error_category & DS2482_DS2484::errorCategory() { @@ -322,16 +260,14 @@ case ArgumentOutOfRangeError: return "Argument Out of Range Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance; } -error_code DS2482_800::selectChannel(int channel) { +Result<void> DS2482_800::selectChannel(int channel) { // Channel Select (Case A) // S AD,0 [A] CHSL [A] CC [A] Sr AD,1 [A] [RR] A\ P // [] indicates from slave @@ -382,45 +318,35 @@ break; default: - return make_error_code(ArgumentOutOfRangeError); + return ArgumentOutOfRangeError; }; - error_code result = sendCommand(0xC3, ch); - if (!result) { - result = readRegister(ch); - if (!result) { - // check for failure due to incorrect read back of channel - if (ch != ch_read) { - result = make_error_code(HardwareError); - } - } + TRY(sendCommand(0xC3, ch)); + TRY_VALUE(ch, readRegister()); + // check for failure due to incorrect read back of channel + if (ch != ch_read) { + return HardwareError; } - return result; + return none; } -error_code DS2484::adjustPort(PortParameter param, int val) { +Result<void> DS2484::adjustPort(PortParameter param, int val) { if (val < 0 || val > 15) { - return make_error_code(ArgumentOutOfRangeError); + return ArgumentOutOfRangeError; } - error_code result = sendCommand(0xC3, (param << 4) | val); - if (result) { - return result; - } + TRY(sendCommand(0xC3, (param << 4) | val)); uint_least8_t portConfig = val + 1; for (int reads = -1; reads < param; ++reads) { - result = readRegister(portConfig); - if (result) { - return result; - } + TRY_VALUE(portConfig, readRegister()); } if (val != portConfig) { - result = make_error_code(HardwareError); + return HardwareError; } - return result; + return none; } } // namespace MaximInterfaceDevices
--- a/MaximInterfaceDevices/DS2482_DS2484.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS2482_DS2484.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS2482_DS2484 -#define MaximInterfaceDevices_DS2482_DS2484 +#ifndef MaximInterfaceDevices_DS2482_DS2484_hpp +#define MaximInterfaceDevices_DS2482_DS2484_hpp #include <MaximInterfaceCore/I2CMaster.hpp> #include <MaximInterfaceCore/OneWireMaster.hpp> @@ -146,31 +146,31 @@ void setAddress(uint_least8_t address) { address_ = address; } /// Initialize hardware for use. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> initialize(Config config = Config()); /// @brief Write a new configuration to the device. /// @param[in] config New configuration to write. - MaximInterfaceDevices_EXPORT Core::error_code writeConfig(Config config); + MaximInterfaceDevices_EXPORT Core::Result<void> writeConfig(Config config); - MaximInterfaceDevices_EXPORT virtual Core::error_code - triplet(TripletData & data); + MaximInterfaceDevices_EXPORT virtual Core::Result<TripletData> + triplet(bool sendBit); - MaximInterfaceDevices_EXPORT virtual Core::error_code reset(); + MaximInterfaceDevices_EXPORT virtual Core::Result<void> reset(); - MaximInterfaceDevices_EXPORT virtual Core::error_code - touchBitSetLevel(bool & sendRecvBit, Level afterLevel); + MaximInterfaceDevices_EXPORT virtual Core::Result<bool> + touchBitSetLevel(bool sendBit, Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code - readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterfaceDevices_EXPORT virtual Core::Result<uint_least8_t> + readByteSetLevel(Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> setSpeed(Speed newSpeed); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> setLevel(Level newLevel); MaximInterfaceDevices_EXPORT static const Core::error_category & @@ -181,40 +181,49 @@ : master(&master), address_(address) {} /// @note Allow marking const since not public. - Core::error_code sendCommand(uint_least8_t cmd) const; + Core::Result<void> sendCommand(uint_least8_t cmd) const; /// @note Allow marking const since not public. - Core::error_code sendCommand(uint_least8_t cmd, uint_least8_t param) const; + Core::Result<void> sendCommand(uint_least8_t cmd, uint_least8_t param) const; /// @brief Reads a register from the device. /// @param reg Register to read from. - /// @param[out] buf Buffer to hold read data. - Core::error_code readRegister(uint_least8_t reg, uint_least8_t & buf) const; + /// @returns Read data from register. + Core::Result<uint_least8_t> readRegister(uint_least8_t reg) const; /// @brief Reads the current register from the device. - /// @param[out] buf Buffer to hold read data. - Core::error_code readRegister(uint_least8_t & buf) const; + /// @returns Read data from register. + Core::Result<uint_least8_t> readRegister() const; private: /// @brief Performs a soft reset on the device. /// @note This is not a 1-Wire Reset. - Core::error_code resetDevice(); + Core::Result<void> 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. - Core::error_code pollBusy(uint_least8_t * pStatus = NULL); + /// @returns Status byte or TimeoutError if poll limit reached. + Core::Result<uint_least8_t> pollBusy(); /// @brief Ensure that the desired 1-Wire level is set in the configuration. /// @param level Desired 1-Wire level. - Core::error_code configureLevel(Level level); + Core::Result<void> configureLevel(Level level); Core::I2CMaster * master; uint_least8_t address_; Config curConfig; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS2482_DS2484::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS2482_DS2484::ErrorValue e) { return Core::error_code(e, DS2482_DS2484::errorCategory()); } @@ -233,7 +242,7 @@ /// @brief Select the active 1-Wire channel. /// @param channel Channel number to select from 0 to 7. - MaximInterfaceDevices_EXPORT Core::error_code selectChannel(int channel); + MaximInterfaceDevices_EXPORT Core::Result<void> selectChannel(int channel); }; /// DS2484 I2C to 1-Wire Master @@ -258,8 +267,8 @@ /// @brief Adjust 1-Wire port parameters. /// @param param Parameter to adjust. /// @param val New parameter value to set. Consult datasheet for value mappings. - MaximInterfaceDevices_EXPORT Core::error_code adjustPort(PortParameter param, - int val); + MaximInterfaceDevices_EXPORT Core::Result<void> + adjustPort(PortParameter param, int val); }; } // namespace MaximInterfaceDevices
--- a/MaximInterfaceDevices/DS28C36_DS2476.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28C36_DS2476.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -36,21 +36,22 @@ #include <MaximInterfaceCore/RomId.hpp> #include "DS28C36_DS2476.hpp" +#define TRY MaximInterfaceCore_TRY +#define TRY_VALUE MaximInterfaceCore_TRY_VALUE + namespace MaximInterfaceDevices { using namespace Core; 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; +static Result<void> convertResultByte(uint_least8_t resultByte) { + return (resultByte == 0xAA) + ? makeResult(none) + : error_code((resultByte == 0x00) + ? static_cast<int>(DS28C36::AuthenticationError) + : resultByte, + DS28C36::errorCategory()); } const int DS28C36::publicKeyAxPage; @@ -71,166 +72,178 @@ const int DS28C36::publicKeySyPage; const int DS28C36::memoryPages; -error_code DS28C36::writeMemory(int pageNum, Page::const_span page) { +Result<void> DS28C36::writeMemory(int pageNum, Page::const_span page) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + Page::size]; buffer[0] = pageNum; copy(page.begin(), page.end(), buffer + 1); - error_code result = writeCommand(0x96, buffer); + Result<void> result = writeCommand(0x96, buffer); if (!result) { - sleep(writeMemoryTimeMs); - result = readFixedLengthResponse(make_span(buffer, 1)); - if (!result) { - result = convertResultByte(buffer[0]); - } + return result; } + sleep(writeMemoryTimeMs); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + return result; + } + result = convertResultByte(buffer[0]); return result; } -error_code DS28C36::readMemory(int pageNum, Page::span page) { +Result<DS28C36::Page::array> DS28C36::readMemory(int pageNum) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t parameter = pageNum; - error_code result = writeCommand(0x69, make_span(¶meter, 1)); + Result<void> result = writeCommand(0x69, make_span(¶meter, 1)); + if (!result) { + return result.error(); + } + sleep(readMemoryTimeMs); + array<uint_least8_t, 1 + Page::size> response; + result = readFixedLengthResponse(response); 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(); } - return result; + result = convertResultByte(response[0]); + if (!result) { + return result.error(); + } + Page::array page; + copy(response.begin() + 1, response.end(), page.begin()); + return page; } -error_code DS28C36::writeBuffer(span<const uint_least8_t> data) { +Result<void> 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; +Result<std::vector<uint_least8_t> > DS28C36::readBuffer() const { + TRY(writeCommand(0x5A)); + std::vector<uint_least8_t> buffer(80); + span<uint_least8_t>::index_type bufferLength; + TRY_VALUE(bufferLength, readVariableLengthResponse(buffer)); + buffer.resize(bufferLength); + return buffer; } -error_code DS28C36::readPageProtection(int pageNum, - PageProtection & protection) { +Result<DS28C36::PageProtection> DS28C36::readPageProtection(int pageNum) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer = pageNum; - error_code result = writeCommand(0xAA, make_span(&buffer, 1)); + Result<void> result = writeCommand(0xAA, make_span(&buffer, 1)); if (!result) { - sleep(readMemoryTimeMs); - result = readFixedLengthResponse(make_span(&buffer, 1)); - if (!result) { - protection = buffer; - } + return result.error(); } - return result; + sleep(readMemoryTimeMs); + result = readFixedLengthResponse(make_span(&buffer, 1)); + if (!result) { + return result.error(); + } + return PageProtection(buffer); } -error_code DS28C36::setPageProtection(int pageNum, - const PageProtection & protection) { +Result<void> DS28C36::setPageProtection(int pageNum, + const PageProtection & protection) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return 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); + Result<void> result = writeCommand(0xC3, buffer); if (!result) { - sleep(writeMemoryTimeMs); - result = readFixedLengthResponse(make_span(buffer, 1)); - if (!result) { - result = convertResultByte(buffer[0]); - } + return result; } + sleep(writeMemoryTimeMs); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + return result; + } + result = convertResultByte(buffer[0]); return result; } -error_code DS28C36::decrementCounter() { - error_code result = writeCommand(0xC9); +Result<void> DS28C36::decrementCounter() { + Result<void> result = writeCommand(0xC9); if (!result) { - sleep(writeMemoryTimeMs); - uint_least8_t response; - result = readFixedLengthResponse(make_span(&response, 1)); - if (!result) { - result = convertResultByte(response); - } + return result; } + sleep(writeMemoryTimeMs); + uint_least8_t response; + result = readFixedLengthResponse(make_span(&response, 1)); + if (!result) { + return result; + } + result = convertResultByte(response); return result; } -error_code DS28C36::readRng(span<uint_least8_t> data) { +Result<void> DS28C36::readRng(span<uint_least8_t> data) const { if ((data.size() < 1) || (data.size() > 64)) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } data[0] = static_cast<uint_least8_t>(data.size() - 1); - error_code result = writeCommand(0xD2, data.first(1)); + Result<void> result = writeCommand(0xD2, data.first(1)); if (!result) { - sleep(sha256ComputationTimeMs); - result = readFixedLengthResponse(data); + return result; } + sleep(sha256ComputationTimeMs); + result = readFixedLengthResponse(data); return result; } -error_code DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum, - EncryptionChallenge::span challenge, - Page::span data) { +Result<std::pair<DS28C36::EncryptionChallenge::array, DS28C36::Page::array> > +DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t parameter = (secretNum << 6) | pageNum; - error_code result = writeCommand(0x4B, make_span(¶meter, 1)); + Result<void> result = writeCommand(0x4B, make_span(¶meter, 1)); + if (!result) { + return result.error(); + } + sleep(readMemoryTimeMs + sha256ComputationTimeMs); + uint_least8_t response[1 + EncryptionChallenge::size + Page::size]; + result = readFixedLengthResponse(response); 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(); + } + result = convertResultByte(response[0]); + if (!result) { + return result.error(); } - return result; + std::pair<DS28C36::EncryptionChallenge::array, DS28C36::Page::array> data; + const uint_least8_t * begin = response + 1; + const uint_least8_t * end = begin + data.first.size(); + copy(begin, end, data.first.begin()); + begin = end; + end = begin + data.second.size(); + copy(begin, end, data.second.begin()); + return data; } -error_code DS28C36::computeAndReadPageAuthentication(int pageNum, - AuthType authType) { +Result<void> +DS28C36::computeAndReadPageAuthentication(int pageNum, + AuthType authType) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return 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) { +Result<Signature::array> +DS28C36::computeAndReadPageAuthentication(int pageNum, KeyNum keyNum) const { AuthType authType; switch (keyNum) { case KeyNumA: @@ -243,29 +256,35 @@ authType = EcdsaWithKeyC; break; default: - return make_error_code(InvalidParameterError); + return InvalidParameterError; } - error_code result = computeAndReadPageAuthentication(pageNum, authType); + Result<void> result = computeAndReadPageAuthentication(pageNum, authType); + if (!result) { + return result.error(); + } + sleep(readMemoryTimeMs + generateEcdsaSignatureTimeMs); + uint_least8_t response[1 + 2 * Scalar::size]; + result = readFixedLengthResponse(response); 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(); + } + result = convertResultByte(response[0]); + if (!result) { + return result.error(); } - return result; + Signature::array signature; + 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 signature; } -error_code DS28C36::computeAndReadPageAuthentication(int pageNum, - SecretNum secretNum, - Page::span hmac) { +Result<DS28C36::Page::array> +DS28C36::computeAndReadPageAuthentication(int pageNum, + SecretNum secretNum) const { AuthType authType; switch (secretNum) { case SecretNumA: @@ -278,93 +297,106 @@ authType = HmacWithSecretS; break; default: - return make_error_code(InvalidParameterError); + return InvalidParameterError; } - error_code result = computeAndReadPageAuthentication(pageNum, authType); + Result<void> result = computeAndReadPageAuthentication(pageNum, authType); + if (!result) { + return result.error(); + } + sleep(readMemoryTimeMs + sha256ComputationTimeMs); + array<uint_least8_t, 1 + Page::size> response; + result = readFixedLengthResponse(response); if (!result) { - sleep(readMemoryTimeMs + sha256ComputationTimeMs); - array<uint_least8_t, 1 + Page::size> response; - result = readFixedLengthResponse(response); - if (!result) { - result = convertResultByte(response[0]); - copy(response.begin() + 1, response.end(), hmac.begin()); - } + return result.error(); } - return result; + result = convertResultByte(response[0]); + if (!result) { + return result.error(); + } + Page::array hmac; + copy(response.begin() + 1, response.end(), hmac.begin()); + return hmac; } -error_code DS28C36::authenticatedSha2WriteMemory(int pageNum, - SecretNum secretNum, - Page::const_span page) { +Result<void> DS28C36::authenticatedSha2WriteMemory(int pageNum, + SecretNum secretNum, + Page::const_span page) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return 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); + Result<void> result = writeCommand(0x99, buffer); if (!result) { - sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs)); - result = readFixedLengthResponse(make_span(buffer, 1)); - if (!result) { - result = convertResultByte(buffer[0]); - } + return result; } + sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs)); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + return result; + } + result = convertResultByte(buffer[0]); return result; } -error_code DS28C36::computeAndLockSha2Secret(int pageNum, SecretNum msecretNum, - SecretNum dsecretNum, - bool writeProtectEnable) { +Result<void> DS28C36::computeAndLockSha2Secret(int pageNum, + SecretNum msecretNum, + SecretNum dsecretNum, + bool writeProtectEnable) { // User pages only if (pageNum < 0 || pageNum > 15) { - return make_error_code(InvalidParameterError); + return 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); + Result<void> 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; } + sleep(sha256ComputationTimeMs + + ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs)); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + return result; + } + result = convertResultByte(buffer[0]); return result; } -error_code DS28C36::generateEcc256KeyPair(KeyNum keyNum, - bool writeProtectEnable) { +Result<void> DS28C36::generateEcc256KeyPair(KeyNum keyNum, + bool writeProtectEnable) { if (keyNum == KeyNumS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer = keyNum; if (writeProtectEnable) { buffer |= 0x80; } - error_code result = writeCommand(0xCB, make_span(&buffer, 1)); + Result<void> result = writeCommand(0xCB, make_span(&buffer, 1)); if (!result) { - sleep(generateEccKeyPairTimeMs); - result = readFixedLengthResponse(make_span(&buffer, 1)); - if (!result) { - result = convertResultByte(buffer); - } + return result; } + sleep(generateEccKeyPairTimeMs); + result = readFixedLengthResponse(make_span(&buffer, 1)); + if (!result) { + return result; + } + result = convertResultByte(buffer); return result; } -error_code DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock, - span<const uint_least8_t> data) { +Result<void> 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); + return InvalidParameterError; } uint_least8_t buffer[1 + maxDataSize]; @@ -376,20 +408,22 @@ buffer[0] |= 0x80; } copy(data.begin(), data.end(), buffer + 1); - error_code result = writeCommand(0x33, make_span(buffer, data.size() + 1)); + Result<void> 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; } + sleep(sha256ComputationTimeMs); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + return result; + } + result = convertResultByte(buffer[0]); return result; } -error_code DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType, - Signature::const_span signature, - PioState pioa, PioState piob) { +Result<void> 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) { @@ -407,25 +441,27 @@ 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); + Result<void> 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; } + sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + + ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0)); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + return result; + } + result = convertResultByte(buffer[0]); return result; } -error_code +Result<void> 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); + return InvalidParameterError; } uint_least8_t buffer[1 + 2 * Scalar::size]; @@ -439,58 +475,62 @@ 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); + Result<void> 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; } + sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + return result; + } + result = convertResultByte(buffer[0]); return result; } -error_code DS28C36::authenticatedEcdsaWriteMemory(int pageNum, - Page::const_span page) { +Result<void> DS28C36::authenticatedEcdsaWriteMemory(int pageNum, + Page::const_span page) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + Page::size]; buffer[0] = pageNum; copy(page.begin(), page.end(), buffer + 1); - error_code result = writeCommand(0x89, buffer); + Result<void> result = writeCommand(0x89, buffer); if (!result) { - sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs + - sha256ComputationTimeMs); - result = readFixedLengthResponse(make_span(buffer, 1)); - if (!result) { - result = convertResultByte(buffer[0]); - } + return result; } + sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs + + sha256ComputationTimeMs); + result = readFixedLengthResponse(make_span(buffer, 1)); + if (!result) { + return 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) { +Result<void> DS28C36::writeCommand(uint_least8_t command, + span<const uint_least8_t> parameters) const { + Result<void> result = master->start(address_); + if (!result) { master->stop(); return result; } result = master->writeByte(command); - if (result) { + if (!result) { master->stop(); return result; } if (!parameters.empty()) { result = master->writeByte(static_cast<uint_least8_t>(parameters.size())); - if (result) { + if (!result) { master->stop(); return result; } result = master->writeBlock(parameters); - if (result) { + if (!result) { master->stop(); return result; } @@ -499,41 +539,44 @@ return result; } -error_code DS28C36::readVariableLengthResponse(span<uint_least8_t> & response) { - error_code result = master->start(address_ | 1); - if (result) { +Result<span<uint_least8_t>::index_type> +DS28C36::readVariableLengthResponse(span<uint_least8_t> response) const { + Result<void> result = master->start(address_ | 1); + if (!result) { master->stop(); - return result; + return result.error(); } uint_least8_t length; - result = master->readByte(I2CMaster::Ack, length); - if (result) { + if (const Result<uint_least8_t> result = master->readByte(I2CMaster::Ack)) { + length = result.value(); + } else { master->stop(); - return result; + return result.error(); } if (length > response.size()) { master->stop(); - return make_error_code(InvalidResponseError); + return InvalidResponseError; } - response = response.first(length); - if (!response.empty()) { - result = master->readBlock(I2CMaster::Nack, response); - if (result) { + if (length > 0) { + result = master->readBlock(response.first(length), I2CMaster::Nack); + if (!result) { master->stop(); - return result; + return result.error(); } } result = master->stop(); - return result; + if (!result) { + return result.error(); + } + return length; } -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; +Result<void> +DS28C36::readFixedLengthResponse(span<uint_least8_t> response) const { + span<uint_least8_t>::index_type responseLength; + TRY_VALUE(responseLength, readVariableLengthResponse(response)); + return (responseLength == response.size()) ? makeResult(none) + : InvalidResponseError; } const error_category & DS28C36::errorCategory() { @@ -560,151 +603,146 @@ case InvalidResponseError: return "Invalid Response Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance; } -error_code DS2476::generateEcdsaSignature(KeyNum keyNum, - Signature::span signature) { +Result<Signature::array> DS2476::generateEcdsaSignature(KeyNum keyNum) const { if (keyNum == KeyNumS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t parameter = keyNum; - error_code result = writeCommand(0x1E, make_span(¶meter, 1)); + Result<void> result = writeCommand(0x1E, make_span(¶meter, 1)); + if (!result) { + return result.error(); + } + sleep(generateEcdsaSignatureTimeMs); + uint_least8_t response[1 + 2 * Scalar::size]; + result = readFixedLengthResponse(response); + if (!result) { + return result.error(); + } + result = convertResultByte(response[0]); 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(); } + Signature::array signature; + 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 signature; +} + +Result<void> DS2476::computeSha2UniqueSecret(SecretNum msecretNum) { + uint_least8_t buffer = msecretNum << 4; + Result<void> result = writeCommand(0x55, make_span(&buffer, 1)); + if (!result) { + return result; + } + sleep(sha256ComputationTimeMs); + result = readFixedLengthResponse(make_span(&buffer, 1)); + if (!result) { + return result; + } + result = convertResultByte(buffer); return result; } -error_code DS2476::computeSha2UniqueSecret(SecretNum msecretNum) { - uint_least8_t buffer = msecretNum << 4; - error_code result = writeCommand(0x55, make_span(&buffer, 1)); +Result<DS2476::Page::array> DS2476::computeSha2Hmac() const { + Result<void> result = writeCommand(0x2D); + if (!result) { + return result.error(); + } + sleep(sha256ComputationTimeMs); + array<uint_least8_t, 1 + Page::size> response; + result = readFixedLengthResponse(response); if (!result) { - sleep(sha256ComputationTimeMs); - result = readFixedLengthResponse(make_span(&buffer, 1)); - if (!result) { - convertResultByte(buffer); - } + return result.error(); } - return result; + result = convertResultByte(response[0]); + if (!result) { + return result.error(); + } + Page::array hmac; + copy(response.begin() + 1, response.end(), hmac.begin()); + return hmac; } -error_code DS2476::computeSha2Hmac(Page::span hmac) { - error_code result = writeCommand(0x2D); - if (!result) { - sleep(sha256ComputationTimeMs); - array<uint_least8_t, 1 + Page::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; +Result<void> computeMultiblockHash(DS28C36 & ds28c36, + span<const uint_least8_t> data) { span<const uint_least8_t>::index_type dataIdx = 0; - while (dataIdx < data.size() && !result) { + while (dataIdx < data.size()) { const span<const uint_least8_t>::index_type remainingSize = data.size() - dataIdx; const span<const uint_least8_t>::index_type chunkSize = std::min<span<const uint_least8_t>::index_type>(remainingSize, 64); - result = - ds28c36.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize, - data.subspan(dataIdx, chunkSize)); + TRY(ds28c36.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize, + data.subspan(dataIdx, chunkSize))); dataIdx += chunkSize; } - return result; + return none; } -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<void> verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey, + span<const uint_least8_t> data, + Signature::const_span signature, + DS28C36::PioState pioa, + DS28C36::PioState piob) { + Result<void> 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 = +Result<void> verifyEcdsaSignature(DS28C36 & ds28c36, + PublicKey::const_span publicKey, + span<const uint_least8_t> data, + Signature::const_span signature, + DS28C36::PioState pioa, + DS28C36::PioState piob) { + Result<void> result = ds28c36.writeMemory(DS28C36::publicKeySxPage, publicKey.x); if (!result) { - result = ds28c36.writeMemory(DS28C36::publicKeySyPage, publicKey.y); + return result; } + result = ds28c36.writeMemory(DS28C36::publicKeySyPage, publicKey.y); if (!result) { - result = verifyEcdsaSignature(ds28c36, DS28C36::KeyNumS, data, signature, - pioa, piob); + return 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); +Result<void> enableCoprocessor(DS2476 & ds2476) { + DS2476::Page::array page; + TRY_VALUE(page, ds2476.readMemory(DS2476::gpioControlPage)); + DS2476::GpioControl gpioControl(page); + if (!gpioControl.pioaConducting()) { + gpioControl.setPioaConducting(true); + TRY(ds2476.writeMemory(DS2476::gpioControlPage, page)); } - return result; + return none; } -error_code enableCoprocessor(DS2476 & ds2476) { +Result<void> enableRomId(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); - } + TRY_VALUE(page, ds2476.readMemory(DS2476::romOptionsPage)); + DS2476::RomOptions romOptions(page); + if (!romOptions.romBlockDisable()) { + romOptions.setRomBlockDisable(true); + TRY(ds2476.writeMemory(DS2476::romOptionsPage, 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; + return none; } static void setAnonymous(RomId::span romId) {
--- a/MaximInterfaceDevices/DS28C36_DS2476.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28C36_DS2476.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,10 +30,11 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS28C36_DS2476 -#define MaximInterfaceDevices_DS28C36_DS2476 +#ifndef MaximInterfaceDevices_DS28C36_DS2476_hpp +#define MaximInterfaceDevices_DS28C36_DS2476_hpp #include <stdint.h> +#include <utility> #include <vector> #include <MaximInterfaceCore/Algorithm.hpp> #include <MaximInterfaceCore/array_span.hpp> @@ -154,77 +155,74 @@ /// @brief Write memory with no protection. /// @param pageNum Number of page to write. /// @param page Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code readMemory(int pageNum, - Page::span page); + /// @returns Data that was read. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + readMemory(int pageNum) const; /// @brief Write the temporary buffer. /// @param data Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeBuffer(Core::span<const uint_least8_t> data); /// @brief Read the temporary buffer. - /// @param[out] data Data that was read. - MaximInterfaceDevices_EXPORT Core::error_code - readBuffer(std::vector<uint_least8_t> & data); + /// @returns Data that was read. + MaximInterfaceDevices_EXPORT Core::Result<std::vector<uint_least8_t> > + readBuffer() const; /// @brief Read the protection settings of a page. /// @param pageNum Number of page to read. - /// @param[out] protection Protection that was read. - MaximInterfaceDevices_EXPORT Core::error_code - readPageProtection(int pageNum, PageProtection & protection); + /// @returns Protection that was read. + MaximInterfaceDevices_EXPORT Core::Result<PageProtection> + readPageProtection(int pageNum) const; /// @brief Set the protection settings of a page. /// @param pageNum Number of page to write. /// @param protection Protection to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> setPageProtection(int pageNum, const PageProtection & protection); /// Decrement the decrement-only counter. - MaximInterfaceDevices_EXPORT Core::error_code decrementCounter(); + MaximInterfaceDevices_EXPORT Core::Result<void> decrementCounter(); /// @brief Read a block of random data from the RNG. /// @param[out] data Random data from RNG with length from 1 to 64. - MaximInterfaceDevices_EXPORT Core::error_code - readRng(Core::span<uint_least8_t> data); + MaximInterfaceDevices_EXPORT Core::Result<void> + readRng(Core::span<uint_least8_t> data) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - encryptedReadMemory(int pageNum, SecretNum secretNum, - EncryptionChallenge::span challenge, Page::span data); + /// @returns Encryption challenge and encrypted page data that was read. + MaximInterfaceDevices_EXPORT + Core::Result<std::pair<EncryptionChallenge::array, Page::array> > + encryptedReadMemory(int pageNum, SecretNum secretNum) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - computeAndReadPageAuthentication(int pageNum, KeyNum keyNum, - Core::Ecc256::Signature::span signature); + /// @returns Computed page signature. + MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::Signature::array> + computeAndReadPageAuthentication(int pageNum, KeyNum keyNum) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - computeAndReadPageAuthentication(int pageNum, SecretNum secretNum, - Page::span hmac); + /// @returns Computed page HMAC. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + computeAndReadPageAuthentication(int pageNum, SecretNum secretNum) const; /// @brief Write with SHA2 authentication. /// @param pageNum Number of page to write. /// @param secretNum Secret to use for authentication. /// @param page Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatedSha2WriteMemory(int pageNum, SecretNum secretNum, Page::const_span page); @@ -234,14 +232,14 @@ /// @param dsecretNum Destination secret to receive the computation result. /// @param writeProtectEnable /// True to lock the destination secret against further writes. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> generateEcc256KeyPair(KeyNum keyNum, bool writeProtectEnable); /// @brief Compute a hash over multiple blocks. @@ -249,7 +247,7 @@ /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeMultiblockHash(bool firstBlock, bool lastBlock, Core::span<const uint_least8_t> data); @@ -259,7 +257,7 @@ /// @param signature Signature to verify. /// @param pioa New state of PIOA if verification successful. /// @param piob New state of PIOB if verification successful. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> verifyEcdsaSignature(KeyNum keyNum, HashType hashType, Core::Ecc256::Signature::const_span signature, PioState pioa = Unchanged, PioState piob = Unchanged); @@ -273,7 +271,7 @@ /// 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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum, int csOffset, Core::Ecc256::Signature::const_span signature); @@ -281,7 +279,7 @@ /// @brief Write with ECDSA authentication. /// @param pageNum Number of page to write. /// @param page Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatedEcdsaWriteMemory(int pageNum, Page::const_span page); MaximInterfaceDevices_EXPORT static const Core::error_category & @@ -296,17 +294,19 @@ static const int readMemoryTimeMs = /*1*/ 2; static const int writeMemoryTimeMs = 15; - Core::error_code writeCommand(uint_least8_t command, - Core::span<const uint_least8_t> parameters); + Core::Result<void> + writeCommand(uint_least8_t command, + Core::span<const uint_least8_t> parameters) const; - Core::error_code writeCommand(uint_least8_t command) { + Core::Result<void> writeCommand(uint_least8_t command) const { return writeCommand(command, Core::span<const uint_least8_t>()); } - Core::error_code - readVariableLengthResponse(Core::span<uint_least8_t> & response); + Core::Result<Core::span<uint_least8_t>::index_type> + readVariableLengthResponse(Core::span<uint_least8_t> response) const; - Core::error_code readFixedLengthResponse(Core::span<uint_least8_t> response); + Core::Result<void> + readFixedLengthResponse(Core::span<uint_least8_t> response) const; void sleep(int ms) const { sleep_->invoke(ms); } @@ -320,12 +320,12 @@ EcdsaWithKeyC = 5 }; + Core::Result<void> computeAndReadPageAuthentication(int pageNum, + AuthType authType) const; + const Core::Sleep * sleep_; Core::I2CMaster * master; uint_least8_t address_; - - Core::error_code computeAndReadPageAuthentication(int pageNum, - AuthType authType); }; /// Interface to the DS2476 coprocessor. @@ -339,22 +339,31 @@ /// @param keyNum /// Private key to use to create signature. /// Key S cannot be used with this command. - /// @param[out] signature Computed signature. - MaximInterfaceDevices_EXPORT Core::error_code - generateEcdsaSignature(KeyNum keyNum, - Core::Ecc256::Signature::span signature); + /// @returns Computed signature. + MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::Signature::array> + generateEcdsaSignature(KeyNum keyNum) const; /// @brief Compute unique SHA2 secret. /// @param msecretNum Master secret to use in computation. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeSha2UniqueSecret(SecretNum msecretNum); /// @brief Compute SHA2 HMAC. - /// @param[out] hmac Computed HMAC. - MaximInterfaceDevices_EXPORT Core::error_code - computeSha2Hmac(Page::span hmac); + /// @returns Computed HMAC. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + computeSha2Hmac() const; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS28C36::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS28C36::ErrorValue e) { return Core::error_code(e, DS28C36::errorCategory()); } @@ -363,7 +372,7 @@ /// Hash arbitrary length data with successive Compute Multiblock Hash commands. /// @param ds28c36 Device for computation. /// @param data Data to hash. -MaximInterfaceDevices_EXPORT Core::error_code +MaximInterfaceDevices_EXPORT Core::Result<void> computeMultiblockHash(DS28C36 & ds28c36, Core::span<const uint_least8_t> data); /// @brief Verify ECDSA signature. @@ -373,7 +382,7 @@ /// @param signature Signature to verify. /// @param pioa New state of PIOA if verification successful. /// @param piob New state of PIOB if verification successful. -MaximInterfaceDevices_EXPORT Core::error_code +MaximInterfaceDevices_EXPORT Core::Result<void> verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey, Core::span<const uint_least8_t> data, Core::Ecc256::Signature::const_span signature, @@ -388,7 +397,7 @@ /// @param signature Signature to verify. /// @param pioa New state of PIOA if verification successful. /// @param piob New state of PIOB if verification successful. -MaximInterfaceDevices_EXPORT Core::error_code +MaximInterfaceDevices_EXPORT Core::Result<void> verifyEcdsaSignature(DS28C36 & ds28c36, Core::Ecc256::PublicKey::const_span publicKey, Core::span<const uint_least8_t> data, @@ -397,25 +406,15 @@ 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. -MaximInterfaceDevices_EXPORT Core::error_code -readRomIdAndManId(DS28C36 & ds28c36, Core::RomId::span romId, - Core::ManId::span manId); - -/// @brief /// Enable coprocessor functionality on the DS2476 by writing to the /// GPIO Control page. -MaximInterfaceDevices_EXPORT Core::error_code +MaximInterfaceDevices_EXPORT Core::Result<void> enableCoprocessor(DS2476 & ds2476); /// @brief /// Disable blocking of the ROM ID on the DS2476 by writing to the /// ROM Options page. -MaximInterfaceDevices_EXPORT Core::error_code enableRomId(DS2476 & ds2476); +MaximInterfaceDevices_EXPORT Core::Result<void> enableRomId(DS2476 & ds2476); /// Format page authentication input data. class DS28C36::PageAuthenticationData { @@ -536,13 +535,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index romIdIdx = 0; - static const index pageIdx = romIdIdx + Core::RomId::size; - static const index challengeIdx = pageIdx + Page::size; - static const index pageNumIdx = challengeIdx + Page::size; - static const index manIdIdx = pageNumIdx + 1; + static const size_t romIdIdx = 0; + static const size_t pageIdx = romIdIdx + Core::RomId::size; + static const size_t challengeIdx = pageIdx + Page::size; + static const size_t pageNumIdx = challengeIdx + Page::size; + static const size_t manIdIdx = pageNumIdx + 1; Result::array result_; }; @@ -855,13 +852,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index encryptionChallengeIdx = 0; - static const index romIdIdx = + static const size_t encryptionChallengeIdx = 0; + static const size_t romIdIdx = encryptionChallengeIdx + EncryptionChallenge::size; - static const index pageNumIdx = romIdIdx + Core::RomId::size; - static const index manIdIdx = pageNumIdx + 1; + static const size_t pageNumIdx = romIdIdx + Core::RomId::size; + static const size_t manIdIdx = pageNumIdx + 1; Result::array result_; };
--- a/MaximInterfaceDevices/DS28C39.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28C39.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -55,9 +55,9 @@ const int DS28C39::writePublicKeyYPage; const int DS28C39::memoryPages; -error_code DS28C39::writeMemory(int pageNum, Page::const_span page) { +Result<void> DS28C39::writeMemory(int pageNum, Page::const_span page) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size]; @@ -67,72 +67,74 @@ return runCommand(request, writeMemoryTimeMs); } -error_code DS28C39::readMemory(int pageNum, Page::span page) { +Result<DS28C39::Page::array> DS28C39::readMemory(int pageNum) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + Page::size]; buffer[0] = 0x44; buffer[1] = pageNum; - span<uint_least8_t> response(buffer); - const error_code result = - runCommand(make_span(buffer, 2), readMemoryTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), page.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer); + if (!response) { + return response.error(); } - return result; + Page::array page; + copy(response.value().begin(), response.value().end(), page.begin()); + return page; } -error_code DS28C39::readStatus(bool entropyHealthTest, Status & status) { +Result<DS28C39::Status> DS28C39::readStatus(bool entropyHealthTest) const { int delay = readMemoryTimeMs; if (entropyHealthTest) { delay += trngOnDemandCheckTimeMs; } - uint_least8_t buffer[Status::PageProtectionList::csize + RomId::size + - ManId::size + Status::RomVersion::csize + 2]; + uint_least8_t buffer[Status::PageProtectionList::size + RomId::size + + ManId::size + Status::RomVersion::size + 2]; buffer[0] = 0xAA; buffer[1] = entropyHealthTest ? 0x01 : 0x00; - span<uint_least8_t> response(buffer); - error_code result = runCommand(make_span(buffer, 2), delay, response); - if (!result) { - span<uint_least8_t>::const_iterator responseIt = response.begin(); - for (Status::PageProtectionList::iterator it = - status.pageProtection.begin(); - it != status.pageProtection.end(); ++it) { - *it = *responseIt; - ++responseIt; - } - span<uint_least8_t>::const_iterator responseItEnd = - responseIt + status.romId.size(); - copy(responseIt, responseItEnd, status.romId.begin()); - responseIt = responseItEnd; - responseItEnd = responseIt + status.manId.size(); - copy(responseIt, responseItEnd, status.manId.begin()); - responseIt = responseItEnd; - responseItEnd = responseIt + status.romVersion.size(); - copy(responseIt, responseItEnd, status.romVersion.begin()); - responseIt = responseItEnd; - switch (*responseIt) { - case Status::TestNotPerformed: - case Status::EntropyHealthy: - case Status::EntropyNotHealthy: - status.entropyHealthTestStatus = - static_cast<Status::EntropyHealthTestStatus>(*responseIt); - break; + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), delay, buffer); + if (!response) { + return response.error(); + } + Status status; + span<uint_least8_t>::const_iterator responseIt = response.value().begin(); + for (Status::PageProtectionList::array::iterator it = + status.pageProtection.begin(); + it != status.pageProtection.end(); ++it) { + *it = *responseIt; + ++responseIt; + } + span<uint_least8_t>::const_iterator responseItEnd = + responseIt + status.romId.size(); + copy(responseIt, responseItEnd, status.romId.begin()); + responseIt = responseItEnd; + responseItEnd = responseIt + status.manId.size(); + copy(responseIt, responseItEnd, status.manId.begin()); + responseIt = responseItEnd; + responseItEnd = responseIt + status.romVersion.size(); + copy(responseIt, responseItEnd, status.romVersion.begin()); + responseIt = responseItEnd; + switch (*responseIt) { + case Status::TestNotPerformed: + case Status::EntropyHealthy: + case Status::EntropyNotHealthy: + status.entropyHealthTestStatus = + static_cast<Status::EntropyHealthTestStatus>(*responseIt); + break; - default: - result = make_error_code(InvalidResponseError); - break; - } + default: + return InvalidResponseError; } - return result; + return status; } -error_code DS28C39::setPageProtection(int pageNum, - const PageProtection & protection) { +Result<void> DS28C39::setPageProtection(int pageNum, + const PageProtection & protection) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t request[] = { @@ -141,12 +143,11 @@ return runCommand(request, writeStateTimeMs); } -error_code +Result<Ecc256::Signature::array> DS28C39::computeAndReadPageAuthentication(int pageNum, bool anonymous, - Page::const_span challenge, - Ecc256::Signature::span signature) { + Page::const_span challenge) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 2 + Page::size; @@ -155,63 +156,66 @@ buffer[0] = 0xA5; buffer[1] = pageNum | (anonymous ? 0xE0 : 0x00); copy(challenge.begin(), challenge.end(), buffer + 2); - span<uint_least8_t> response(buffer, responseSize); - const error_code result = runCommand(make_span(buffer, requestSize), - generateEcdsaSignatureTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = begin + signature.s.size(); - copy(begin, end, signature.s.begin()); - begin = end; - end = begin + signature.r.size(); - copy(begin, end, signature.r.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + Ecc256::Signature::array signature; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + signature.s.size(); + copy(begin, end, signature.s.begin()); + begin = end; + end = begin + signature.r.size(); + copy(begin, end, signature.r.begin()); + return signature; } -error_code DS28C39::disableDevice() { +Result<void> DS28C39::disableDevice() { const uint_least8_t request[] = {0x33, 0x9E, 0xA7, 0x49, 0xFB, 0x10, 0x62, 0x0A, 0x26}; return runCommand(request, writeStateTimeMs); } -error_code -DS28C39::readDevicePublicKey(Ecc256::PublicKey::span devicePublicKey) { +Result<Ecc256::PublicKey::array> DS28C39::readDevicePublicKey() const { uint_least8_t buffer[1 + 2 * Ecc256::Scalar::size]; buffer[0] = 0xCB; - span<uint_least8_t> response(buffer); - const error_code result = - runCommand(make_span(buffer, 1), generateEccKeyPairTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = begin + devicePublicKey.x.size(); - copy(begin, end, devicePublicKey.x.begin()); - begin = end; - end = begin + devicePublicKey.y.size(); - copy(begin, end, devicePublicKey.y.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 1), generateEccKeyPairTimeMs, buffer); + if (!response) { + return response.error(); } - return result; + Ecc256::PublicKey::array devicePublicKey; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + devicePublicKey.x.size(); + copy(begin, end, devicePublicKey.x.begin()); + begin = end; + end = begin + devicePublicKey.y.size(); + copy(begin, end, devicePublicKey.y.begin()); + return devicePublicKey; } -error_code DS28C39::readRng(span<uint_least8_t> data) { +Result<void> DS28C39::readRng(span<uint_least8_t> data) const { const span<uint_least8_t>::index_type maxDataSize = 64; if ((data.size() < 1) || (data.size() > maxDataSize)) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + maxDataSize]; buffer[0] = 0xD2; buffer[1] = static_cast<uint_least8_t>(data.size() - 1); - span<uint_least8_t> response(buffer, 1 + data.size()); - const error_code result = - runCommand(make_span(buffer, 2), trngGenerationTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), data.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), trngGenerationTimeMs, + make_span(buffer, 1 + data.size())); + if (!response) { + return response.error(); } - return result; + copy(response.value().begin(), response.value().end(), data.begin()); + return none; } -error_code +Result<void> DS28C39::authenticatePublicKey(Ecc256::Signature::const_span certificate, span<const uint_least8_t> customization) { static const span<const uint_least8_t>::index_type maxCustomizationSize = 32; @@ -219,7 +223,7 @@ 2 * Ecc256::Scalar::size; if (customization.size() < 1 || customization.size() > maxCustomizationSize) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[1 + signatureSize + maxCustomizationSize]; @@ -231,11 +235,11 @@ return runCommand(make_span(request, requestIt), verifyEcdsaSignatureTimeMs); } -error_code +Result<void> DS28C39::authenticatedWriteMemory(int pageNum, Page::const_span page, Ecc256::Signature::const_span signature) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size]; @@ -248,43 +252,40 @@ return runCommand(request, verifyEcdsaSignatureTimeMs + writeMemoryTimeMs); } -error_code DS28C39::runCommand(span<const uint_least8_t> request, int delayTime, - span<uint_least8_t> & response) { - const span<const uint_least8_t>::index_type responseInputSize = - response.size(); - error_code result = doRunCommand(request, delayTime, response); - if (result) { - return result; +Result<span<uint_least8_t> > +DS28C39::runCommand(span<const uint_least8_t> request, int delayTime, + span<uint_least8_t> response) const { + const Result<span<uint_least8_t> > responseOutput = + doRunCommand(request, delayTime, response); + if (!responseOutput) { + return responseOutput; } - if (response.empty()) { - return make_error_code(InvalidResponseError); + if (responseOutput.value().empty()) { + return InvalidResponseError; } // Parse command result byte. - switch (response[0]) { + switch (responseOutput.value().front()) { case 0xAA: // Success response. - if (response.size() != responseInputSize) { - result = make_error_code(InvalidResponseError); - } break; case 0x00: - result = make_error_code(AuthenticationError); - break; + return AuthenticationError; default: - result.assign(response[0], errorCategory()); - break; + return error_code(responseOutput.value().front(), errorCategory()); } - response = response.subspan(1); - return result; + if (responseOutput.value().size() != response.size()) { + return InvalidResponseError; + } + return responseOutput.value().subspan(1); } -error_code DS28C39::runCommand(span<const uint_least8_t> request, - int delayTime) { +Result<void> DS28C39::runCommand(span<const uint_least8_t> request, + int delayTime) { uint_least8_t buffer; - span<uint_least8_t> response(&buffer, 1); - return runCommand(request, delayTime, response); + MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1))); + return none; } const error_category & DS28C39::errorCategory() { @@ -321,17 +322,6 @@ return instance; } -error_code readRomIdAndManId(DS28C39 & ds28c39, Core::RomId::span romId, - Core::ManId::span manId) { - DS28C39::Status status; - const error_code result = ds28c39.readStatus(false, status); - if (!result) { - copy(make_span(status.romId), romId); - copy(make_span(status.manId), manId); - } - return result; -} - DS28C39::PageAuthenticationData & DS28C39::PageAuthenticationData::setAnonymousRomId() { std::fill(romId().begin(), romId().end(), 0xFF);
--- a/MaximInterfaceDevices/DS28C39.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28C39.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS28C39 -#define MaximInterfaceDevices_DS28C39 +#ifndef MaximInterfaceDevices_DS28C39_hpp +#define MaximInterfaceDevices_DS28C39_hpp #include <stdint.h> #include <MaximInterfaceCore/Algorithm.hpp> @@ -96,13 +96,15 @@ EntropyNotHealthy = 0xDD }; - typedef Core::array<PageProtection, memoryPages - 2> PageProtectionList; - typedef Core::array<uint_least8_t, 2> RomVersion; + typedef Core::array_span<PageProtection, memoryPages - 2> + PageProtectionList; - PageProtectionList pageProtection; + typedef Core::array_span<uint_least8_t, 2> RomVersion; + + PageProtectionList::array pageProtection; Core::RomId::array romId; Core::ManId::array manId; - RomVersion romVersion; + RomVersion::array romVersion; EntropyHealthTestStatus entropyHealthTestStatus; }; @@ -116,51 +118,50 @@ /// @brief Write memory with no protection. /// @param pageNum Number of page to write. /// @param page Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code readMemory(int pageNum, - Page::span page); + /// @returns Data that was read. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + readMemory(int pageNum) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - readStatus(bool entropyHealthTest, Status & status); + /// @returns Status that was read. + MaximInterfaceDevices_EXPORT Core::Result<Status> + readStatus(bool entropyHealthTest) const; /// @brief Set the protection settings of a page. /// @param pageNum Number of page to write. /// @param protection Protection to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code + /// @returns Computed page signature. + MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::Signature::array> computeAndReadPageAuthentication(int pageNum, bool anonymous, - Page::const_span challenge, - Core::Ecc256::Signature::span signature); + Page::const_span challenge) const; /// Permanently disable the device. - MaximInterfaceDevices_EXPORT Core::error_code disableDevice(); + MaximInterfaceDevices_EXPORT Core::Result<void> disableDevice(); /// @brief Generate the device's ECDSA public key from the PUF private key. - /// @param[out] devicePublicKey Device Public Key - MaximInterfaceDevices_EXPORT Core::error_code - readDevicePublicKey(Core::Ecc256::PublicKey::span devicePublicKey); + /// @returns Device Public Key + MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::PublicKey::array> + readDevicePublicKey() const; /// @brief Read a block of random data from the RNG. /// @param[out] data Random data from RNG with length from 1 to 64. - MaximInterfaceDevices_EXPORT Core::error_code - readRng(Core::span<uint_least8_t> data); + MaximInterfaceDevices_EXPORT Core::Result<void> + readRng(Core::span<uint_least8_t> data) const; /// @brief /// Authenticate a public key for authenticated writes using the @@ -169,7 +170,7 @@ /// Certificate to use for authentication of the Write Public Key. /// @param customization /// Certificate customization with length from 1 to 32. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatePublicKey(Core::Ecc256::Signature::const_span certificate, Core::span<const uint_least8_t> customization); @@ -177,7 +178,7 @@ /// @param pageNum Number of page to write. /// @param page Data to write. /// @param signature Signature to use for authentication of page data. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatedWriteMemory(int pageNum, Page::const_span page, Core::Ecc256::Signature::const_span signature); @@ -185,29 +186,31 @@ errorCategory(); protected: - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<Core::span<uint_least8_t> > runCommand(Core::span<const uint_least8_t> request, int delayTime, - Core::span<uint_least8_t> & response); + Core::span<uint_least8_t> response) const; - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> runCommand(Core::span<const uint_least8_t> request, int delayTime); private: Core::RunCommand doRunCommand; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS28C39::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS28C39::ErrorValue e) { return Core::error_code(e, DS28C39::errorCategory()); } -/// @brief Read the device ROM ID and MAN ID using the Read Status command. -/// @param ds28c39 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. -MaximInterfaceDevices_EXPORT Core::error_code -readRomIdAndManId(DS28C39 & ds28c39, Core::RomId::span romId, - Core::ManId::span manId); - /// Format page authentication input data. class DS28C39::PageAuthenticationData { public: @@ -327,13 +330,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index romIdIdx = 0; - static const index pageIdx = romIdIdx + Core::RomId::size; - static const index challengeIdx = pageIdx + Page::size; - static const index pageNumIdx = challengeIdx + Page::size; - static const index manIdIdx = pageNumIdx + 1; + static const size_t romIdIdx = 0; + static const size_t pageIdx = romIdIdx + Core::RomId::size; + static const size_t challengeIdx = pageIdx + Page::size; + static const size_t pageNumIdx = challengeIdx + Page::size; + static const size_t manIdIdx = pageNumIdx + 1; Result::array result_; };
--- a/MaximInterfaceDevices/DS28C40.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28C40.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2019 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -39,6 +39,7 @@ using namespace Core; using std::copy; +using std::pair; static const int readMemoryTimeMs = 2; static const int writeMemoryTimeMs = 150; @@ -73,9 +74,9 @@ const int DS28C40::memoryPages; const int DS28C40::protectionBlocks; -error_code DS28C40::writeMemory(int pageNum, Page::const_span page) { +Result<void> DS28C40::writeMemory(int pageNum, Page::const_span page) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size]; @@ -85,29 +86,28 @@ return runCommand(request, writeMemoryTimeMs); } -error_code DS28C40::readMemory(int pageNum, Page::span page) { +Result<DS28C40::Page::array> DS28C40::readMemory(int pageNum) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + Page::size]; buffer[0] = 0x44; buffer[1] = pageNum; - span<uint_least8_t> response(buffer); - const error_code result = - runCommand(make_span(buffer, 2), readMemoryTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), page.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer); + if (!response) { + return response.error(); } - return result; + Page::array page; + copy(response.value().begin(), response.value().end(), page.begin()); + return page; } -error_code -DS28C40::encryptedReadMemory(int pageNum, KeySecret secret, - EncryptionChallenge::span encryptionChallenge, - Page::span encryptedPage) { +Result<pair<DS28C40::EncryptionChallenge::array, DS28C40::Page::array> > +DS28C40::encryptedReadMemory(int pageNum, KeySecret secret) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 3; @@ -116,27 +116,26 @@ buffer[0] = 0x4B; buffer[1] = pageNum; buffer[2] = secret; - span<uint_least8_t> response(buffer, responseSize); - const error_code result = - runCommand(make_span(buffer, requestSize), - readMemoryTimeMs + computeTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = - begin + encryptionChallenge.size(); - copy(begin, end, encryptionChallenge.begin()); - begin = end; - end = begin + encryptedPage.size(); - copy(begin, end, encryptedPage.begin()); + const Result<span<uint_least8_t> > response = runCommand( + make_span(buffer, requestSize), readMemoryTimeMs + computeTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + pair<EncryptionChallenge::array, Page::array> data; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + data.first.size(); + copy(begin, end, data.first.begin()); + begin = end; + end = begin + data.second.size(); + copy(begin, end, data.second.begin()); + return data; } -error_code DS28C40::readBlockProtection(int blockNumber, - Optional<KeySecret> & keySecret, - BlockProtection & protection) { +Result<pair<Optional<DS28C40::KeySecret>, DS28C40::BlockProtection> > +DS28C40::readBlockProtection(int blockNumber) const { if (blockNumber < 0 || blockNumber >= protectionBlocks) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 2; @@ -144,39 +143,40 @@ uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)]; buffer[0] = 0xAA; buffer[1] = blockNumber; - span<uint_least8_t> response(buffer, responseSize); - const error_code result = - runCommand(make_span(buffer, requestSize), readMemoryTimeMs, response); - if (result) { - return result; + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), readMemoryTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - if ((response[0] & 0x3F) != blockNumber) { - return make_error_code(InvalidResponseError); + if ((response.value()[0] & 0x3F) != blockNumber) { + return InvalidResponseError; } - switch (response[0] >> 6) { + pair<Optional<KeySecret>, BlockProtection> data; + switch (response.value()[0] >> 6) { case 0: - keySecret = none; + data.first = none; break; case 1: - keySecret = KeySecretA; + data.first = KeySecretA; break; case 2: - keySecret = KeySecretB; + data.first = KeySecretB; break; default: - return make_error_code(InvalidResponseError); + return InvalidResponseError; } - if ((response[1] & 0x20) != 0) { - return make_error_code(InvalidResponseError); + if ((response.value()[1] & 0x20) != 0) { + return InvalidResponseError; } - protection = response[1]; - return error_code(); + data.second = response.value()[1]; + return data; } -error_code DS28C40::setBlockProtection(int blockNum, KeySecret keySecret, - const BlockProtection & protection) { +Result<void> DS28C40::setBlockProtection(int blockNum, KeySecret keySecret, + const BlockProtection & protection) { if (blockNum < 0 || blockNum >= protectionBlocks || keySecret == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t request[] = { @@ -187,12 +187,10 @@ return runCommand(request, writeStateTimeMs); } -error_code -DS28C40::computeAndReadPageAuthentication(int pageNum, KeySecret key, - Page::const_span challenge, - Ecc256::Signature::span signature) { +Result<Ecc256::Signature::array> DS28C40::computeAndReadEcdsaPageAuthentication( + int pageNum, KeySecret key, Page::const_span challenge) const { if (pageNum < 0 || pageNum >= memoryPages || key == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 3 + Page::size; @@ -202,26 +200,26 @@ buffer[1] = pageNum; buffer[2] = key + 3; copy(challenge.begin(), challenge.end(), buffer + 3); - span<uint_least8_t> response(buffer, responseSize); - const error_code result = runCommand(make_span(buffer, requestSize), - generateEcdsaSignatureTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = begin + signature.s.size(); - copy(begin, end, signature.s.begin()); - begin = end; - end = begin + signature.r.size(); - copy(begin, end, signature.r.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + Ecc256::Signature::array signature; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + signature.s.size(); + copy(begin, end, signature.s.begin()); + begin = end; + end = begin + signature.r.size(); + copy(begin, end, signature.r.begin()); + return signature; } -error_code DS28C40::computeAndReadPageAuthentication(int pageNum, - KeySecret secret, - Page::const_span challenge, - Page::span hmac) { +Result<DS28C40::Page::array> DS28C40::computeAndReadSha256PageAuthentication( + int pageNum, KeySecret secret, Page::const_span challenge) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 3 + Page::size; @@ -231,21 +229,23 @@ buffer[1] = pageNum; buffer[2] = secret; copy(challenge.begin(), challenge.end(), buffer + 3); - span<uint_least8_t> response(buffer, responseSize); - const error_code result = - runCommand(make_span(buffer, requestSize), computeTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), hmac.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), computeTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + Page::array hmac; + copy(response.value().begin(), response.value().end(), hmac.begin()); + return hmac; } -error_code DS28C40::computeMultiblockHash(bool firstBlock, bool lastBlock, - span<const uint_least8_t> data) { +Result<void> DS28C40::computeMultiblockHash(bool firstBlock, bool lastBlock, + span<const uint_least8_t> data) { const span<const uint_least8_t>::index_type maxDataSize = 64; if (data.size() < 1 || data.size() > maxDataSize) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[2 + maxDataSize]; @@ -261,21 +261,21 @@ return runCommand(make_span(buffer, 2 + data.size()), computeTimeMs); } -error_code DS28C40::verifyEcdsaSignature( +Result<void> DS28C40::verifyEcdsaSignature( KeySecret key, bool authorityKey, GpioState gpioState, Ecc256::Signature::const_span signature, span<const uint_least8_t> data) { return verifyEcdsaSignature(key, authorityKey, DataInput, gpioState, signature, data); } -error_code DS28C40::verifyEcdsaSignature( +Result<void> DS28C40::verifyEcdsaSignature( KeySecret key, bool authorityKey, GpioState gpioState, Ecc256::Signature::const_span signature, Page::const_span hash) { return verifyEcdsaSignature(key, authorityKey, HashInput, gpioState, signature, hash); } -error_code +Result<void> DS28C40::verifyEcdsaSignature(KeySecret key, bool authorityKey, GpioState gpioState, Ecc256::Signature::const_span signature) { @@ -283,13 +283,13 @@ span<const uint_least8_t>()); } -error_code DS28C40::verifyEcdsaSignature( +Result<void> DS28C40::verifyEcdsaSignature( KeySecret key, bool authorityKey, HashType hashType, GpioState gpioState, Ecc256::Signature::const_span signature, span<const uint_least8_t> buffer) { const span<const uint_least8_t>::index_type maxBufferSize = 61; if (buffer.size() > maxBufferSize) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + 2 * Ecc256::Scalar::size + maxBufferSize]; @@ -317,7 +317,7 @@ } // else: Go to default case. default: - return make_error_code(InvalidParameterError); + return InvalidParameterError; } *requestIt |= hashType << 3; if (gpioState != Unchanged) { @@ -334,13 +334,13 @@ (hashType == DataInput ? computeTimeMs : 0)); } -error_code DS28C40::authenticateEcdsaPublicKey( +Result<void> DS28C40::authenticateEcdsaPublicKey( KeySecret key, Ecc256::Signature::const_span cert, span<const uint_least8_t> certCustomization) { return authenticateEcdsaPublicKey(key, true, cert, certCustomization, NULL); } -error_code DS28C40::authenticateEcdsaPublicKey( +Result<void> DS28C40::authenticateEcdsaPublicKey( KeySecret key, bool authWrites, Ecc256::Signature::const_span cert, span<const uint_least8_t> certCustomization, span<const uint_least8_t> ecdhCustomization) { @@ -348,7 +348,7 @@ &ecdhCustomization); } -error_code DS28C40::authenticateEcdsaPublicKey( +Result<void> DS28C40::authenticateEcdsaPublicKey( KeySecret key, bool authWrites, Ecc256::Signature::const_span cert, span<const uint_least8_t> certCustomization, const span<const uint_least8_t> * ecdhCustomization) { @@ -364,11 +364,11 @@ ecdhCustomization->size() <= maxEcdhCustomizationSize && certCustomization.size() + ecdhCustomization->size() <= maxTotalCustomizationSize)))) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } if (key == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t @@ -395,14 +395,14 @@ return runCommand(make_span(request, requestIt), delay); } -error_code DS28C40::authenticatedEcdsaWriteMemory( +Result<void> DS28C40::authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Ecc256::Signature::const_span signature) { return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature, NULL); } -error_code DS28C40::authenticatedEcdsaWriteMemory( +Result<void> DS28C40::authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Ecc256::Signature::const_span signature, EncryptionChallenge::const_span challenge) { @@ -410,12 +410,12 @@ &challenge); } -error_code DS28C40::authenticatedEcdsaWriteMemory( +Result<void> DS28C40::authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Ecc256::Signature::const_span signature, const EncryptionChallenge::const_span * challenge) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size + @@ -437,25 +437,26 @@ return runCommand(make_span(request, requestIt), delay); } -error_code DS28C40::authenticatedSha256WriteMemory(int pageNum, bool useSecretS, - Page::const_span newPageData, - Page::const_span hmac) { +Result<void> +DS28C40::authenticatedSha256WriteMemory(int pageNum, bool useSecretS, + Page::const_span newPageData, + Page::const_span hmac) { return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac, NULL); } -error_code DS28C40::authenticatedSha256WriteMemory( +Result<void> DS28C40::authenticatedSha256WriteMemory( int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac, EncryptionChallenge::const_span challenge) { return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac, &challenge); } -error_code DS28C40::authenticatedSha256WriteMemory( +Result<void> DS28C40::authenticatedSha256WriteMemory( int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac, const EncryptionChallenge::const_span * challenge) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[3 + 2 * Page::size + EncryptionChallenge::size]; @@ -473,12 +474,12 @@ return runCommand(make_span(request, requestIt), delay); } -error_code +Result<void> DS28C40::computeAndWriteSha256Secret(int pageNum, KeySecret masterSecret, KeySecret destinationSecret, Page::const_span partialSecret) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[3 + Page::size]; @@ -489,75 +490,73 @@ return runCommand(request, writeMemoryTimeMs + computeTimeMs); } -error_code DS28C40::generateEcc256KeyPair(KeySecret key) { +Result<void> DS28C40::generateEcc256KeyPair(KeySecret key) { if (key == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t request[] = {0xCB, key == KeySecretB}; return runCommand(request, generateEccKeyPairTimeMs); } -error_code DS28C40::readRng(span<uint_least8_t> data) { +Result<void> DS28C40::readRng(span<uint_least8_t> data) const { const span<uint_least8_t>::index_type maxDataSize = 64; if ((data.size() < 1) || (data.size() > maxDataSize)) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + maxDataSize]; buffer[0] = readRngCmd; buffer[1] = static_cast<uint_least8_t>(data.size() - 1); - span<uint_least8_t> response(buffer, 1 + data.size()); - const error_code result = - runCommand(make_span(buffer, 2), trngGenerationTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), data.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), trngGenerationTimeMs, + make_span(buffer, 1 + data.size())); + if (!response) { + return response.error(); } - return result; + copy(response.value().begin(), response.value().end(), data.begin()); + return none; } -error_code DS28C40::entropyHealthTest() { +Result<void> DS28C40::entropyHealthTest() const { const uint_least8_t request[] = {readRngCmd, 0x80}; return runCommand(request, trngOnDemandCheckTimeMs); } -error_code DS28C40::runCommand(span<const uint_least8_t> request, int delayTime, - span<uint_least8_t> & response) { - const span<const uint_least8_t>::index_type responseInputSize = - response.size(); - error_code result = doRunCommand(request, delayTime, response); - if (result) { - return result; +Result<span<uint_least8_t> > +DS28C40::runCommand(span<const uint_least8_t> request, int delayTime, + span<uint_least8_t> response) const { + const Result<span<uint_least8_t> > responseOutput = + doRunCommand(request, delayTime, response); + if (!responseOutput) { + return responseOutput; } - if (response.empty()) { - return make_error_code(InvalidResponseError); + if (responseOutput.value().empty()) { + return InvalidResponseError; } // Parse command result byte. - switch (response[0]) { + switch (responseOutput.value().front()) { case 0xAA: // Success response. - if (response.size() != responseInputSize) { - result = make_error_code(InvalidResponseError); - } break; case 0x00: - result = make_error_code(AuthenticationError); - break; + return AuthenticationError; default: - result.assign(response[0], errorCategory()); - break; + return error_code(responseOutput.value().front(), errorCategory()); } - response = response.subspan(1); - return result; + if (responseOutput.value().size() != response.size()) { + return InvalidResponseError; + } + return responseOutput.value().subspan(1); } -error_code DS28C40::runCommand(span<const uint_least8_t> request, - int delayTime) { +Result<void> DS28C40::runCommand(span<const uint_least8_t> request, + int delayTime) const { uint_least8_t buffer; - span<uint_least8_t> response(&buffer, 1); - return runCommand(request, delayTime, response); + MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1))); + return none; } const error_category & DS28C40::errorCategory() { @@ -594,33 +593,20 @@ return instance; } -error_code computeMultiblockHash(DS28C40 & device, - span<const uint_least8_t> data) { - error_code result; +Result<void> computeMultiblockHash(DS28C40 & device, + span<const uint_least8_t> data) { span<const uint_least8_t>::index_type dataIdx = 0; - while (dataIdx < data.size() && !result) { + while (dataIdx < data.size()) { const span<const uint_least8_t>::index_type remainingSize = data.size() - dataIdx; const span<const uint_least8_t>::index_type chunkSize = std::min<span<const uint_least8_t>::index_type>(remainingSize, 64); - result = + MaximInterfaceCore_TRY( device.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize, - data.subspan(dataIdx, chunkSize)); + data.subspan(dataIdx, chunkSize))); dataIdx += chunkSize; } - return result; -} - -error_code readRomIdAndManId(DS28C40 & device, RomId::span romId, - ManId::span manId) { - DS28C40::Page::array page; - error_code result = device.readMemory(DS28C40::romOptionsPage, page); - if (!result) { - const DS28C40::RomOptions romOptions(page); - copy(romOptions.romId(), romId); - copy(romOptions.manId(), manId); - } - return result; + return none; } static void setAnonymous(RomId::span romId) {
--- a/MaximInterfaceDevices/DS28C40.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28C40.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2019 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,10 +30,11 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS28C40 -#define MaximInterfaceDevices_DS28C40 +#ifndef MaximInterfaceDevices_DS28C40_hpp +#define MaximInterfaceDevices_DS28C40_hpp #include <stdint.h> +#include <utility> #include <MaximInterfaceCore/Algorithm.hpp> #include <MaximInterfaceCore/array_span.hpp> #include <MaximInterfaceCore/Ecc256.hpp> @@ -140,38 +141,35 @@ /// @brief Write memory with no protection. /// @param pageNum Number of page to write. /// @param page Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code readMemory(int pageNum, - Page::span page); + /// @returns Data that was read. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + readMemory(int pageNum) const; /// @brief Read memory with encryption. /// @param pageNum Number of page to read from. /// @param secret Secret to use for encryption. - /// @param[out] challenge Encryption challenge that was read. - /// @param[out] encryptedPage Encrypted page data that was read. - MaximInterfaceDevices_EXPORT Core::error_code - encryptedReadMemory(int pageNum, KeySecret secret, - EncryptionChallenge::span challenge, - Page::span encryptedPage); + /// @returns Encryption challenge and encrypted page data that was read. + MaximInterfaceDevices_EXPORT + Core::Result<std::pair<EncryptionChallenge::array, Page::array> > + encryptedReadMemory(int pageNum, KeySecret secret) const; /// @brief Read the protection settings of a block. /// @param blockNum Number of block to read. - /// @param[out] keySecret Secret key set on the block or empty if not set. - /// @param[out] protection Protection that was read. - MaximInterfaceDevices_EXPORT Core::error_code - readBlockProtection(int blockNum, Core::Optional<KeySecret> & keySecret, - BlockProtection & protection); + /// @returns Secret/Key and protection set on the block. + MaximInterfaceDevices_EXPORT + Core::Result<std::pair<Core::Optional<KeySecret>, BlockProtection> > + readBlockProtection(int blockNum) const; /// @brief Set the protection settings of a block. /// @param blockNum Number of block to write. /// @param keySecret Secret/Key A or B. /// @param protection Protection to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> setBlockProtection(int blockNum, KeySecret keySecret, const BlockProtection & protection); @@ -181,11 +179,10 @@ /// Private key to use for authentication. /// Key S cannot be used with this command. /// @param challenge Random challenge used to prevent replay attacks. - /// @param[out] signature Computed page signature. - MaximInterfaceDevices_EXPORT Core::error_code - computeAndReadPageAuthentication(int pageNum, KeySecret key, - Page::const_span challenge, - Core::Ecc256::Signature::span signature); + /// @returns Computed page signature. + MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::Signature::array> + computeAndReadEcdsaPageAuthentication(int pageNum, KeySecret key, + Page::const_span challenge) const; /// @brief Compute and read page authentication with HMAC. /// @param pageNum Number of page to authenticate. @@ -193,17 +190,17 @@ /// Secret to use for authentication. /// Secret S cannot be used with this command. /// @param challenge Random challenge used to prevent replay attacks. - /// @param[out] hmac Computed page HMAC. - MaximInterfaceDevices_EXPORT Core::error_code - computeAndReadPageAuthentication(int pageNum, KeySecret secret, - Page::const_span challenge, Page::span hmac); + /// @returns Computed page HMAC. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + computeAndReadSha256PageAuthentication(int pageNum, KeySecret secret, + Page::const_span challenge) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeMultiblockHash(bool firstBlock, bool lastBlock, Core::span<const uint_least8_t> data); @@ -213,7 +210,7 @@ /// @param gpioState New state of the GPIO pin if verification successful. /// @param signature Signature to verify. /// @param data Data to verify with length from 1 to 64. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> verifyEcdsaSignature(KeySecret key, bool authorityKey, GpioState gpioState, Core::Ecc256::Signature::const_span signature, Core::span<const uint_least8_t> data); @@ -224,7 +221,7 @@ /// @param gpioState New state of the GPIO pin if verification successful. /// @param signature Signature to verify. /// @param hash Hash of data to verify. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> verifyEcdsaSignature(KeySecret key, bool authorityKey, GpioState gpioState, Core::Ecc256::Signature::const_span signature, Page::const_span hash); @@ -235,7 +232,7 @@ /// @param authorityKey Use the authority key instead of the standard key. /// @param gpioState New state of the GPIO pin if verification successful. /// @param signature Signature to verify. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> verifyEcdsaSignature(KeySecret key, bool authorityKey, GpioState gpioState, Core::Ecc256::Signature::const_span signature); @@ -245,7 +242,7 @@ /// @param cert Certificate to use for authentication of Public Key S. /// @param certCustomization /// Certificate customization with length from 1 to 32. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticateEcdsaPublicKey(KeySecret key, Core::Ecc256::Signature::const_span cert, Core::span<const uint_least8_t> certCustomization); @@ -261,7 +258,7 @@ /// Certificate customization with length from 1 to 32. /// @param ecdhCustomization ECDH customization with length from 1 to 48. /// @note The maximum total customization length is 60 bytes. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticateEcdsaPublicKey(KeySecret key, bool authWrites, Core::Ecc256::Signature::const_span cert, Core::span<const uint_least8_t> certCustomization, @@ -273,7 +270,7 @@ /// Use Public Key S instead of the authority key set in the block protection. /// @param newPageData Data to write. /// @param signature Signature to use for authentication of page data. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatedEcdsaWriteMemory(int pageNum, bool useKeyS, Page::const_span newPageData, Core::Ecc256::Signature::const_span signature); @@ -285,7 +282,7 @@ /// @param newPageData Encrypted data to write. /// @param signature Signature to use for authentication of page data. /// @param challenge Challenge to use for decryption of page data. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatedEcdsaWriteMemory(int pageNum, bool useKeyS, Page::const_span newPageData, Core::Ecc256::Signature::const_span signature, @@ -297,7 +294,7 @@ /// Use Secret S instead of the secret set in the block protection. /// @param newPageData Data to write. /// @param hmac HMAC to use for authentication of page data. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatedSha256WriteMemory(int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac); @@ -309,9 +306,11 @@ /// @param newPageData Data to write. /// @param hmac HMAC to use for authentication of page data. /// @param challenge Challenge to use for decryption of page data. - MaximInterfaceDevices_EXPORT Core::error_code authenticatedSha256WriteMemory( - int pageNum, bool useSecretS, Page::const_span newPageData, - Page::const_span hmac, EncryptionChallenge::const_span challenge); + MaximInterfaceDevices_EXPORT Core::Result<void> + authenticatedSha256WriteMemory(int pageNum, bool useSecretS, + Page::const_span newPageData, + Page::const_span hmac, + EncryptionChallenge::const_span challenge); /// @brief Compute a derivative SHA-256 secret from an existing secret. /// @param pageNum Number of page to use in computation. @@ -319,23 +318,23 @@ /// @param destinationSecret /// Destination secret to receive the computation result. /// @param partialSecret Partial secret to use in computation. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeAndWriteSha256Secret(int pageNum, KeySecret masterSecret, KeySecret destinationSecret, Page::const_span partialSecret); /// @brief Generate a new ECDSA key pair. /// @param key Key to generate. Key S cannot be used with this command. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> generateEcc256KeyPair(KeySecret key); /// @brief Read a block of random data from the RNG. /// @param[out] data Random data from RNG with length from 1 to 64. - MaximInterfaceDevices_EXPORT Core::error_code - readRng(Core::span<uint_least8_t> data); + MaximInterfaceDevices_EXPORT Core::Result<void> + readRng(Core::span<uint_least8_t> data) const; /// Run entropy health test on the RNG. - MaximInterfaceDevices_EXPORT Core::error_code entropyHealthTest(); + MaximInterfaceDevices_EXPORT Core::Result<void> entropyHealthTest() const; MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); @@ -343,36 +342,46 @@ private: enum HashType { HashInput, DataInput, THASH }; - Core::error_code + Core::Result<void> verifyEcdsaSignature(KeySecret key, bool authorityKey, HashType hashType, GpioState gpioState, Core::Ecc256::Signature::const_span signature, Core::span<const uint_least8_t> buffer); - Core::error_code authenticateEcdsaPublicKey( + Core::Result<void> authenticateEcdsaPublicKey( KeySecret key, bool authWrites, Core::Ecc256::Signature::const_span cert, Core::span<const uint_least8_t> certCustomization, const Core::span<const uint_least8_t> * ecdhCustomization); - Core::error_code authenticatedEcdsaWriteMemory( + Core::Result<void> authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Core::Ecc256::Signature::const_span signature, const EncryptionChallenge::const_span * challenge); - Core::error_code authenticatedSha256WriteMemory( + Core::Result<void> authenticatedSha256WriteMemory( int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac, const EncryptionChallenge::const_span * challenge); - Core::error_code runCommand(Core::span<const uint_least8_t> request, - int delayTime, - Core::span<uint_least8_t> & response); + Core::Result<Core::span<uint_least8_t> > + runCommand(Core::span<const uint_least8_t> request, int delayTime, + Core::span<uint_least8_t> response) const; - Core::error_code runCommand(Core::span<const uint_least8_t> request, - int delayTime); + Core::Result<void> runCommand(Core::span<const uint_least8_t> request, + int delayTime) const; Core::RunCommand doRunCommand; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS28C40::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS28C40::ErrorValue e) { return Core::error_code(e, DS28C40::errorCategory()); } @@ -381,19 +390,9 @@ /// Hash arbitrary length data with successive Compute Multiblock Hash commands. /// @param device Device for computation. /// @param data Data to hash. -MaximInterfaceDevices_EXPORT Core::error_code +MaximInterfaceDevices_EXPORT Core::Result<void> computeMultiblockHash(DS28C40 & device, Core::span<const uint_least8_t> data); -/// @brief -/// Read the device ROM ID and MAN ID using the Read Memory command on the -/// ROM Options page. -/// @param device 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. -MaximInterfaceDevices_EXPORT Core::error_code -readRomIdAndManId(DS28C40 & device, Core::RomId::span romId, - Core::ManId::span manId); - /// Format page authentication input data. class DS28C40::PageAuthenticationData { public: @@ -513,13 +512,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index romIdIdx = 0; - static const index pageIdx = romIdIdx + Core::RomId::size; - static const index challengeIdx = pageIdx + Page::size; - static const index pageNumIdx = challengeIdx + Page::size; - static const index manIdIdx = pageNumIdx + 1; + static const size_t romIdIdx = 0; + static const size_t pageIdx = romIdIdx + Core::RomId::size; + static const size_t challengeIdx = pageIdx + Page::size; + static const size_t pageNumIdx = challengeIdx + Page::size; + static const size_t manIdIdx = pageNumIdx + 1; Result::array result_; }; @@ -827,13 +824,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index encryptionChallengeIdx = 0; - static const index romIdIdx = + static const size_t encryptionChallengeIdx = 0; + static const size_t romIdIdx = encryptionChallengeIdx + EncryptionChallenge::size; - static const index pageNumIdx = romIdIdx + Core::RomId::size; - static const index manIdIdx = pageNumIdx + 1; + static const size_t pageNumIdx = romIdIdx + Core::RomId::size; + static const size_t manIdIdx = pageNumIdx + 1; Result::array result_; };
--- a/MaximInterfaceDevices/DS28E15_22_25.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E15_22_25.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -31,10 +31,13 @@ *******************************************************************************/ #include <algorithm> -#include <MaximInterfaceCore/crc.hpp> +#include <MaximInterfaceCore/Crc.hpp> #include <MaximInterfaceCore/Error.hpp> #include "DS28E15_22_25.hpp" +#define TRY MaximInterfaceCore_TRY +#define TRY_VALUE MaximInterfaceCore_TRY_VALUE + namespace MaximInterfaceDevices { using namespace Core; @@ -48,27 +51,18 @@ static const int ds28e22_25_pagesPerBlock = 2; -static error_code +static Result<void> 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); - if (result) { - return result; - } + TRY(master.writeBlock(data)); uint_least8_t response[2]; - result = master.readByte(response[0]); - if (result) { - return result; + TRY_VALUE(response[0], master.readByte()); + TRY_VALUE(response[1], master.readByteSetLevel(level)); + if (calculateCrc16(calculateCrc16(crcStart, data), response) != 0xB001u) { + return DS28E15_22_25::CrcError; } - result = master.readByteSetLevel(response[1], level); - if (result) { - return result; - } - if (calculateCrc16(calculateCrc16(crcStart, data), response) != 0xB001) { - result = make_error_code(DS28E15_22_25::CrcError); - } - return result; + return none; } const int DS28E15_22_25::segmentsPerPage; @@ -79,11 +73,11 @@ return *this; } -error_code +Result<void> DS28E15_22_25::writeCommandWithCrc(Command command, uint_least8_t parameter, OneWireMaster::Level level) const { - error_code result = selectRom(*master); - if (!result) { + Result<void> result = selectRom(*master); + if (result) { const uint_least8_t data[] = {static_cast<uint_least8_t>(command), parameter}; result = writeDataWithCrc(*master, data, level); @@ -91,44 +85,41 @@ return result; } -static error_code readDataWithCrc(OneWireMaster & master, - span<uint_least8_t> data) { - error_code result = master.readBlock(data); - if (result) { +static Result<void> readDataWithCrc(OneWireMaster & master, + span<uint_least8_t> data) { + Result<void> result = master.readBlock(data); + if (!result) { return result; } uint_least8_t response[2]; result = master.readBlock(response); - if (result) { + if (!result) { return result; } - if (calculateCrc16(calculateCrc16(data), response) != 0xB001) { - result = make_error_code(DS28E15_22_25::CrcError); + if (calculateCrc16(calculateCrc16(data), response) != 0xB001u) { + result = DS28E15_22_25::CrcError; } return result; } -static error_code readCsByte(OneWireMaster & master) { - uint_least8_t response; - error_code result = master.readByte(response); - if (result) { - return result; +static Result<void> readCsByte(OneWireMaster & master) { + const Result<uint_least8_t> response = master.readByte(); + if (!response) { + return response.error(); } - if (response != 0xAA) { - result = make_error_code(DS28E15_22_25::OperationFailure); - } - return result; + return (response.value() == 0xAA) ? makeResult(none) + : DS28E15_22_25::OperationFailure; } -static error_code releaseSequence(OneWireMaster & master, Sleep & sleep, - int delayTimeMs) { - error_code result = master.writeBytePower(0xAA); - if (result) { +static Result<void> releaseSequence(OneWireMaster & master, Sleep & sleep, + int delayTimeMs) { + Result<void> result = master.writeBytePower(0xAA); + if (!result) { return result; } sleep(delayTimeMs); result = master.setLevel(OneWireMaster::NormalLevel); - if (result) { + if (!result) { return result; } return readCsByte(master); @@ -215,29 +206,29 @@ return *this; } -error_code +Result<void> DS28E15_22_25::writeAuthBlockProtection(BlockProtection newProtection, Page::const_span mac) { - error_code result = + Result<void> result = writeCommandWithCrc(AuthWriteBlockProtection, newProtection.statusByte(), OneWireMaster::StrongLevel); - if (result) { + if (!result) { return result; } sleep->invoke(shaComputationDelayMs); result = master->setLevel(OneWireMaster::NormalLevel); - if (result) { + if (!result) { return result; } result = writeDataWithCrc(*master, mac); - if (result) { + if (!result) { return result; } result = readCsByte(*master); - if (result) { + if (!result) { return result; } @@ -245,10 +236,10 @@ return result; } -error_code DS28E15_22_25::writeBlockProtection(BlockProtection protection) { - error_code result = +Result<void> DS28E15_22_25::writeBlockProtection(BlockProtection protection) { + Result<void> result = writeCommandWithCrc(WriteBlockProtection, protection.statusByte()); - if (result) { + if (!result) { return result; } @@ -256,52 +247,51 @@ return result; } -error_code DS28E15_22_25::doReadBlockProtection(int blockNum, - BlockProtection & protection, - Variant variant) const { +Result<DS28E15_22_25::BlockProtection> +DS28E15_22_25::doReadBlockProtection(int blockNum, Variant variant) const { uint_least8_t buffer = blockNum; if (variant == DS28E22 || variant == DS28E25) { buffer *= ds28e22_25_pagesPerBlock; } - error_code result = writeCommandWithCrc(ReadStatus, buffer); - if (!result) { - result = master->readByte(buffer); - if (!result) { - protection.setStatusByte(buffer); - } - } - return result; + TRY(writeCommandWithCrc(ReadStatus, buffer)); + TRY_VALUE(buffer, master->readByte()); + return BlockProtection(buffer); } -error_code DS28E15_22_25::computeReadPageMac(int page_num, bool anon, - Page::span mac) const { - error_code result = +Result<DS28E15_22_25::Page::array> +DS28E15_22_25::computeReadPageMac(int page_num, bool anon) const { + Result<void> result = writeCommandWithCrc(ComputePageMac, (anon ? 0xE0 : 0x00) | page_num, OneWireMaster::StrongLevel); - if (result) { - return result; + if (!result) { + return result.error(); } sleep->invoke(shaComputationDelayMs * 2); result = master->setLevel(OneWireMaster::NormalLevel); - if (result) { - return result; + if (!result) { + return result.error(); } result = readCsByte(*master); - if (result) { - return result; + if (!result) { + return result.error(); } + Page::array mac; result = readDataWithCrc(*master, mac); - return result; + if (!result) { + return result.error(); + } + + return mac; } -error_code DS28E15_22_25::doComputeSecret(int page_num, bool lock, - bool lowPower) { - error_code result = writeCommandWithCrc(ComputeAndLockSecret, - lock ? (0xE0 | page_num) : page_num); - if (result) { +Result<void> DS28E15_22_25::doComputeSecret(int page_num, bool lock, + bool lowPower) { + Result<void> result = writeCommandWithCrc( + ComputeAndLockSecret, lock ? (0xE0 | page_num) : page_num); + if (!result) { return result; } @@ -311,12 +301,12 @@ return result; } -error_code DS28E15_22_25::doWriteScratchpad(Page::const_span data, - Variant variant) { +Result<void> DS28E15_22_25::doWriteScratchpad(Page::const_span data, + Variant variant) { const uint_least8_t parameter = (variant == DS28E22 || variant == DS28E25) ? 0x20 : 0x00; - error_code result = writeCommandWithCrc(ReadWriteScratchpad, parameter); - if (result) { + Result<void> result = writeCommandWithCrc(ReadWriteScratchpad, parameter); + if (!result) { return result; } @@ -324,23 +314,28 @@ return result; } -error_code DS28E15_22_25::doReadScratchpad(Page::span data, - Variant variant) const { +Result<DS28E15_22_25::Page::array> +DS28E15_22_25::doReadScratchpad(Variant variant) const { const uint_least8_t parameter = (variant == DS28E22 || variant == DS28E25) ? 0x2F : 0x0F; - error_code result = writeCommandWithCrc(ReadWriteScratchpad, parameter); - if (result) { - return result; + Result<void> result = writeCommandWithCrc(ReadWriteScratchpad, parameter); + if (!result) { + return result.error(); } + Page::array data; result = readDataWithCrc(*master, data); - return result; + if (!result) { + return result.error(); + } + + return data; } -error_code DS28E15_22_25::doLoadSecret(bool lock, bool lowPower) { - error_code result = +Result<void> DS28E15_22_25::doLoadSecret(bool lock, bool lowPower) { + Result<void> result = writeCommandWithCrc(LoadAndLockSecret, lock ? 0xE0 : 0x00); - if (result) { + if (!result) { return result; } @@ -348,47 +343,49 @@ return result; } -error_code DS28E15_22_25::readPage(int page, Page::span rdbuf) const { - error_code result = writeCommandWithCrc(ReadMemory, page); - if (result) { - return result; +Result<DS28E15_22_25::Page::array> DS28E15_22_25::readPage(int page) const { + const Result<void> result = writeCommandWithCrc(ReadMemory, page); + if (!result) { + return result.error(); } - result = continueReadPage(rdbuf); - return result; + return continueReadPage(); } -error_code DS28E15_22_25::continueReadPage(Page::span rdbuf) const { - return readDataWithCrc(*master, rdbuf); +Result<DS28E15_22_25::Page::array> DS28E15_22_25::continueReadPage() const { + Page::array rdbuf; + TRY(readDataWithCrc(*master, rdbuf)); + return rdbuf; } -error_code DS28E15_22_25::doWriteAuthSegment(Segment::const_span newData, - Page::const_span mac, - Variant variant, bool continuing) { +Result<void> DS28E15_22_25::doWriteAuthSegment(Segment::const_span newData, + Page::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 = + Result<void> result = writeDataWithCrc(*master, newData, OneWireMaster::StrongLevel, crcStart); - if (result) { + if (!result) { return result; } sleep->invoke(shaComputationDelayMs); result = master->setLevel(OneWireMaster::NormalLevel); - if (result) { + if (!result) { return result; } result = writeDataWithCrc(*master, mac); - if (result) { + if (!result) { return result; } result = readCsByte(*master); - if (result) { + if (!result) { return result; } @@ -396,13 +393,13 @@ return result; } -error_code DS28E15_22_25::doWriteAuthSegment(int pageNum, int segmentNum, - Segment::const_span newData, - Page::const_span mac, - Variant variant) { - error_code result = +Result<void> DS28E15_22_25::doWriteAuthSegment(int pageNum, int segmentNum, + Segment::const_span newData, + Page::const_span mac, + Variant variant) { + Result<void> result = writeCommandWithCrc(AuthWriteMemory, (segmentNum << 5) | pageNum); - if (result) { + if (!result) { return result; } @@ -410,30 +407,32 @@ return result; } -error_code DS28E15_22_25::doContinueWriteAuthSegment( +Result<void> DS28E15_22_25::doContinueWriteAuthSegment( Segment::const_span newData, Page::const_span mac, Variant variant) { return doWriteAuthSegment(newData, mac, variant, true); } -error_code DS28E15_22_25::readSegment(int page, int segment, - Segment::span data) const { - error_code result = writeCommandWithCrc(ReadMemory, (segment << 5) | page); - if (result) { - return result; +Result<DS28E15_22_25::Segment::array> +DS28E15_22_25::readSegment(int page, int segment) const { + Result<void> result = writeCommandWithCrc(ReadMemory, (segment << 5) | page); + if (!result) { + return result.error(); } - result = continueReadSegment(data); - return result; + return continueReadSegment(); } -error_code DS28E15_22_25::continueReadSegment(Segment::span data) const { - return master->readBlock(data); +Result<DS28E15_22_25::Segment::array> +DS28E15_22_25::continueReadSegment() const { + Segment::array data; + TRY(master->readBlock(data)); + return data; } -error_code DS28E15_22_25::writeSegment(int page, int block, - Segment::const_span data) { - error_code result = writeCommandWithCrc(WriteMemory, (block << 5) | page); - if (result) { +Result<void> DS28E15_22_25::writeSegment(int page, int block, + Segment::const_span data) { + Result<void> result = writeCommandWithCrc(WriteMemory, (block << 5) | page); + if (!result) { return result; } @@ -441,9 +440,9 @@ return result; } -error_code DS28E15_22_25::continueWriteSegment(Segment::const_span data) { - error_code result = writeDataWithCrc(*master, data); - if (result) { +Result<void> DS28E15_22_25::continueWriteSegment(Segment::const_span data) { + Result<void> result = writeDataWithCrc(*master, data); + if (!result) { return result; } @@ -451,10 +450,10 @@ return result; } -error_code +Result<void> DS28E15_22_25::doReadAllBlockProtection(span<BlockProtection> protection, Variant variant) const { - error_code result = writeCommandWithCrc(ReadStatus, 0); + Result<void> result = writeCommandWithCrc(ReadStatus, 0); if (!result) { if (variant == DS28E22 || variant == DS28E25) { // Need to read extra data on DS28E22 to get CRC16. @@ -502,151 +501,166 @@ case OperationFailure: return "Operation Failure"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance; } -error_code DS28E15_22_25::loadSecret(bool lock) { +Result<void> DS28E15_22_25::loadSecret(bool lock) { // Use worst-case low power timing if the device type is not known. return doLoadSecret(lock, true); } -error_code DS28E15_22_25::computeSecret(int pageNum, bool lock) { +Result<void> DS28E15_22_25::computeSecret(int pageNum, bool lock) { // Use worst-case low power timing if the device type is not known. return doComputeSecret(pageNum, lock, true); } -error_code DS28E15_22_25::readPersonality(Personality & personality) const { - error_code result = writeCommandWithCrc(ReadStatus, 0xE0); +Result<DS28E15_22_25::Personality> DS28E15_22_25::readPersonality() const { + Result<void> result = writeCommandWithCrc(ReadStatus, 0xE0); + if (!result) { + return result.error(); + } + + uint_least8_t data[4]; + result = readDataWithCrc(*master, data); if (!result) { - uint_least8_t data[4]; - result = readDataWithCrc(*master, data); - if (!result) { - personality.PB1 = data[0]; - personality.PB2 = data[1]; - personality.manId[0] = data[2]; - personality.manId[1] = data[3]; - } + return result.error(); } - return result; + + Personality personality; + personality.PB1 = data[0]; + personality.PB2 = data[1]; + personality.manId[0] = data[2]; + personality.manId[1] = data[3]; + return personality; } const int DS28EL15::memoryPages; const int DS28EL15::protectionBlocks; -error_code DS28EL15::writeScratchpad(Page::const_span data) { +Result<void> DS28EL15::writeScratchpad(Page::const_span data) { return doWriteScratchpad(data, DS28E15); } -error_code DS28EL15::readScratchpad(Page::span data) const { - return doReadScratchpad(data, DS28E15); +Result<DS28E15_22_25::Page::array> DS28EL15::readScratchpad() const { + return doReadScratchpad(DS28E15); } -error_code DS28EL15::readBlockProtection(int blockNum, - BlockProtection & protection) const { - return doReadBlockProtection(blockNum, protection, DS28E15); +Result<DS28E15_22_25::BlockProtection> +DS28EL15::readBlockProtection(int blockNum) const { + return doReadBlockProtection(blockNum, DS28E15); } -error_code DS28EL15::writeAuthSegment(int pageNum, int segmentNum, - Segment::const_span newData, - Page::const_span mac) { +Result<void> DS28EL15::writeAuthSegment(int pageNum, int segmentNum, + Segment::const_span newData, + Page::const_span mac) { return doWriteAuthSegment(pageNum, segmentNum, newData, mac, DS28E15); } -error_code DS28EL15::continueWriteAuthSegment(Segment::const_span newData, - Page::const_span mac) { +Result<void> DS28EL15::continueWriteAuthSegment(Segment::const_span newData, + Page::const_span mac) { return doContinueWriteAuthSegment(newData, mac, DS28E15); } -error_code DS28EL15::readAllBlockProtection( - span<BlockProtection, protectionBlocks> protection) const { - return doReadAllBlockProtection(protection, DS28E15); +Result<array<DS28E15_22_25::BlockProtection, DS28E15::protectionBlocks> > +DS28EL15::readAllBlockProtection() const { + array<BlockProtection, protectionBlocks> protection; + TRY(doReadAllBlockProtection(protection, DS28E15)); + return protection; } -error_code DS28E15::loadSecret(bool lock) { return doLoadSecret(lock, false); } +Result<void> DS28E15::loadSecret(bool lock) { + return doLoadSecret(lock, false); +} -error_code DS28E15::computeSecret(int pageNum, bool lock) { +Result<void> DS28E15::computeSecret(int pageNum, bool lock) { return doComputeSecret(pageNum, lock, false); } const int DS28EL22::memoryPages; const int DS28EL22::protectionBlocks; -error_code DS28EL22::writeScratchpad(Page::const_span data) { +Result<void> DS28EL22::writeScratchpad(Page::const_span data) { return doWriteScratchpad(data, DS28E22); } -error_code DS28EL22::readScratchpad(Page::span data) const { - return doReadScratchpad(data, DS28E22); +Result<DS28E15_22_25::Page::array> DS28EL22::readScratchpad() const { + return doReadScratchpad(DS28E22); } -error_code DS28EL22::readBlockProtection(int blockNum, - BlockProtection & protection) const { - return doReadBlockProtection(blockNum, protection, DS28E22); +Result<DS28E15_22_25::BlockProtection> +DS28EL22::readBlockProtection(int blockNum) const { + return doReadBlockProtection(blockNum, DS28E22); } -error_code DS28EL22::writeAuthSegment(int pageNum, int segmentNum, - Segment::const_span newData, - Page::const_span mac) { +Result<void> DS28EL22::writeAuthSegment(int pageNum, int segmentNum, + Segment::const_span newData, + Page::const_span mac) { return doWriteAuthSegment(pageNum, segmentNum, newData, mac, DS28E22); } -error_code DS28EL22::continueWriteAuthSegment(Segment::const_span newData, - Page::const_span mac) { +Result<void> DS28EL22::continueWriteAuthSegment(Segment::const_span newData, + Page::const_span mac) { return doContinueWriteAuthSegment(newData, mac, DS28E22); } -error_code DS28EL22::readAllBlockProtection( - span<BlockProtection, protectionBlocks> protection) const { - return doReadAllBlockProtection(protection, DS28E22); +Result<array<DS28E15_22_25::BlockProtection, DS28E22::protectionBlocks> > +DS28EL22::readAllBlockProtection() const { + array<BlockProtection, protectionBlocks> protection; + TRY(doReadAllBlockProtection(protection, DS28E22)); + return protection; } -error_code DS28E22::loadSecret(bool lock) { return doLoadSecret(lock, false); } +Result<void> DS28E22::loadSecret(bool lock) { + return doLoadSecret(lock, false); +} -error_code DS28E22::computeSecret(int pageNum, bool lock) { +Result<void> DS28E22::computeSecret(int pageNum, bool lock) { return doComputeSecret(pageNum, lock, false); } const int DS28EL25::memoryPages; const int DS28EL25::protectionBlocks; -error_code DS28EL25::writeScratchpad(Page::const_span data) { +Result<void> DS28EL25::writeScratchpad(Page::const_span data) { return doWriteScratchpad(data, DS28E25); } -error_code DS28EL25::readScratchpad(Page::span data) const { - return doReadScratchpad(data, DS28E25); +Result<DS28E15_22_25::Page::array> DS28EL25::readScratchpad() const { + return doReadScratchpad(DS28E25); } -error_code DS28EL25::readBlockProtection(int blockNum, - BlockProtection & protection) const { - return doReadBlockProtection(blockNum, protection, DS28E25); +Result<DS28E15_22_25::BlockProtection> +DS28EL25::readBlockProtection(int blockNum) const { + return doReadBlockProtection(blockNum, DS28E25); } -error_code DS28EL25::writeAuthSegment(int pageNum, int segmentNum, - Segment::const_span newData, - Page::const_span mac) { +Result<void> DS28EL25::writeAuthSegment(int pageNum, int segmentNum, + Segment::const_span newData, + Page::const_span mac) { return doWriteAuthSegment(pageNum, segmentNum, newData, mac, DS28E25); } -error_code DS28EL25::continueWriteAuthSegment(Segment::const_span newData, - Page::const_span mac) { +Result<void> DS28EL25::continueWriteAuthSegment(Segment::const_span newData, + Page::const_span mac) { return doContinueWriteAuthSegment(newData, mac, DS28E25); } -error_code DS28EL25::readAllBlockProtection( - span<BlockProtection, protectionBlocks> protection) const { - return doReadAllBlockProtection(protection, DS28E25); +Result<array<DS28E15_22_25::BlockProtection, DS28E25::protectionBlocks> > +DS28EL25::readAllBlockProtection() const { + array<BlockProtection, protectionBlocks> protection; + TRY(doReadAllBlockProtection(protection, DS28E25)); + return protection; } -error_code DS28E25::loadSecret(bool lock) { return doLoadSecret(lock, false); } +Result<void> DS28E25::loadSecret(bool lock) { + return doLoadSecret(lock, false); +} -error_code DS28E25::computeSecret(int pageNum, bool lock) { +Result<void> DS28E25::computeSecret(int pageNum, bool lock) { return doComputeSecret(pageNum, lock, false); }
--- a/MaximInterfaceDevices/DS28E15_22_25.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E15_22_25.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS28E15_22_25 -#define MaximInterfaceDevices_DS28E15_22_25 +#ifndef MaximInterfaceDevices_DS28E15_22_25_hpp +#define MaximInterfaceDevices_DS28E15_22_25_hpp #include <stdint.h> #include <MaximInterfaceCore/Algorithm.hpp> @@ -48,6 +48,9 @@ /// @brief /// Interface to the DS28E15/22/25 series of authenticators /// including low power variants. +/// @details +/// Const member functions should not affect the state of the memory, +/// block protection, or secret on the device. class DS28E15_22_25 { public: enum ErrorValue { CrcError = 1, OperationFailure }; @@ -91,54 +94,51 @@ this->selectRom = selectRom; } - // Const member functions should not affect the state of the memory, - // block protection, or secret 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. - MaximInterfaceDevices_EXPORT Core::error_code - readSegment(int pageNum, int segmentNum, Segment::span data) const; + /// @returns Buffer to read data from the segment into. + MaximInterfaceDevices_EXPORT Core::Result<Segment::array> + readSegment(int pageNum, int segmentNum) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - continueReadSegment(Segment::span data) const; + /// @returns Buffer to read data from the segment into. + MaximInterfaceDevices_EXPORT Core::Result<Segment::array> + continueReadSegment() const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeSegment(int pageNum, int segmentNum, Segment::const_span data); /// @brief Continue an in-progress Write Memory command. /// @param[in] data Data to write to the memory segment. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> continueWriteSegment(Segment::const_span data); /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - readPage(int pageNum, Page::span rdbuf) const; + /// @returns Buffer to read data from the page into. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + readPage(int pageNum) const; /// @brief Continue an in-progress readPageOperation. - /// @param[out] rdbuf Buffer to read data from the page into. - MaximInterfaceDevices_EXPORT Core::error_code - continueReadPage(Page::span rdbuf) const; + /// @returns Buffer to read data from the page into. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + continueReadPage() 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. - MaximInterfaceDevices_EXPORT Core::error_code - computeReadPageMac(int pageNum, bool anon, Page::span mac) const; + /// @returns The device computed MAC. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + computeReadPageMac(int pageNum, bool anon) const; /// @brief /// Update the status of a memory protection block using the @@ -146,7 +146,7 @@ /// @param protection /// Desired protection status for the block. /// It is not possible to disable existing protections. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeBlockProtection(BlockProtection protection); /// @brief @@ -154,26 +154,26 @@ /// Authenticated Write Page Protection command. /// @param newProtection New protection status to write. /// @param[in] mac Write MAC computed for this operation. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeAuthBlockProtection(BlockProtection newProtection, Page::const_span mac); /// @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. - MaximInterfaceDevices_EXPORT Core::error_code loadSecret(bool lock); + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code computeSecret(int pageNum, - bool lock); + MaximInterfaceDevices_EXPORT Core::Result<void> computeSecret(int pageNum, + bool lock); /// @brief Read the personality bytes using the Read Status command. - /// @param[out] personality Receives personality read from device. - MaximInterfaceDevices_EXPORT Core::error_code - readPersonality(Personality & personality) const; + /// @returns Receives personality read from device. + MaximInterfaceDevices_EXPORT Core::Result<Personality> + readPersonality() const; MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); @@ -187,29 +187,28 @@ ~DS28E15_22_25() {} - Core::error_code doWriteScratchpad(Page::const_span data, Variant variant); - - Core::error_code doReadScratchpad(Page::span data, Variant variant) const; + Core::Result<void> doWriteScratchpad(Page::const_span data, Variant variant); - Core::error_code doReadBlockProtection(int blockNum, - BlockProtection & protection, - Variant variant) const; + Core::Result<Page::array> doReadScratchpad(Variant variant) const; + + Core::Result<BlockProtection> doReadBlockProtection(int blockNum, + Variant variant) const; - Core::error_code doWriteAuthSegment(int pageNum, int segmentNum, - Segment::const_span newData, - Page::const_span mac, Variant variant); + Core::Result<void> doWriteAuthSegment(int pageNum, int segmentNum, + Segment::const_span newData, + Page::const_span mac, Variant variant); - Core::error_code doContinueWriteAuthSegment(Segment::const_span newData, - Page::const_span mac, - Variant variant); + Core::Result<void> doContinueWriteAuthSegment(Segment::const_span newData, + Page::const_span mac, + Variant variant); - Core::error_code + Core::Result<void> doReadAllBlockProtection(Core::span<BlockProtection> protection, Variant variant) const; - Core::error_code doLoadSecret(bool lock, bool lowPower); + Core::Result<void> doLoadSecret(bool lock, bool lowPower); - Core::error_code doComputeSecret(int pageNum, bool lock, bool lowPower); + Core::Result<void> doComputeSecret(int pageNum, bool lock, bool lowPower); private: enum Command { @@ -225,11 +224,11 @@ AuthWriteBlockProtection = 0xCC, }; - Core::error_code doWriteAuthSegment(Segment::const_span newData, - Page::const_span mac, Variant variant, - bool continuing); + Core::Result<void> doWriteAuthSegment(Segment::const_span newData, + Page::const_span mac, Variant variant, + bool continuing); - Core::error_code + Core::Result<void> writeCommandWithCrc(Command command, uint_least8_t parameter, Core::OneWireMaster::Level level = Core::OneWireMaster::NormalLevel) const; @@ -239,6 +238,16 @@ Core::Sleep * sleep; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS28E15_22_25::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS28E15_22_25::ErrorValue e) { return Core::error_code(e, DS28E15_22_25::errorCategory()); } @@ -256,41 +265,41 @@ /// @brief Perform Write Scratchpad operation on the device. /// @param[in] data Data to write to the scratchpad. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeScratchpad(Page::const_span data); /// @brief Perform a Read Scratchpad operation on the device. - /// @param[out] data Buffer to read data from the scratchpad into. - MaximInterfaceDevices_EXPORT Core::error_code - readScratchpad(Page::span data) const; + /// @returns Buffer to read data from the scratchpad into. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> readScratchpad() 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. - MaximInterfaceDevices_EXPORT Core::error_code - readBlockProtection(int blockNum, BlockProtection & protection) const; + /// @returns Receives protection status read from device. + MaximInterfaceDevices_EXPORT Core::Result<BlockProtection> + readBlockProtection(int blockNum) 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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeAuthSegment(int pageNum, int segmentNum, Segment::const_span newData, Page::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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> continueWriteAuthSegment(Segment::const_span newData, Page::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. - MaximInterfaceDevices_EXPORT Core::error_code readAllBlockProtection( - Core::span<BlockProtection, protectionBlocks> protection) const; + /// @returns Receives protection statuses read from device. + MaximInterfaceDevices_EXPORT + Core::Result<Core::array<BlockProtection, protectionBlocks> > + readAllBlockProtection() const; }; /// Interface to the DS28E15 authenticator. @@ -304,14 +313,14 @@ /// @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. - MaximInterfaceDevices_EXPORT Core::error_code loadSecret(bool lock); + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code computeSecret(int pageNum, - bool lock); + MaximInterfaceDevices_EXPORT Core::Result<void> computeSecret(int pageNum, + bool lock); }; /// Interface to the DS28EL22 (low power) authenticator. @@ -327,41 +336,41 @@ /// @brief Perform Write Scratchpad operation on the device. /// @param[in] data Data to write to the scratchpad. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeScratchpad(Page::const_span data); /// @brief Perform a Read Scratchpad operation on the device. - /// @param[out] data Buffer to read data from the scratchpad into. - MaximInterfaceDevices_EXPORT Core::error_code - readScratchpad(Page::span data) const; + /// @returns Buffer to read data from the scratchpad into. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> readScratchpad() 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. - MaximInterfaceDevices_EXPORT Core::error_code - readBlockProtection(int blockNum, BlockProtection & protection) const; + /// @returns Receives protection status read from device. + MaximInterfaceDevices_EXPORT Core::Result<BlockProtection> + readBlockProtection(int blockNum) 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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeAuthSegment(int pageNum, int segmentNum, Segment::const_span newData, Page::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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> continueWriteAuthSegment(Segment::const_span newData, Page::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. - MaximInterfaceDevices_EXPORT Core::error_code readAllBlockProtection( - Core::span<BlockProtection, protectionBlocks> protection) const; + /// @returns Receives protection statuses read from device. + MaximInterfaceDevices_EXPORT + Core::Result<Core::array<BlockProtection, protectionBlocks> > + readAllBlockProtection() const; }; /// Interface to the DS28E22 authenticator. @@ -375,14 +384,14 @@ /// @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. - MaximInterfaceDevices_EXPORT Core::error_code loadSecret(bool lock); + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code computeSecret(int pageNum, - bool lock); + MaximInterfaceDevices_EXPORT Core::Result<void> computeSecret(int pageNum, + bool lock); }; /// Interface to the DS28EL25 (low power) authenticator. @@ -398,41 +407,41 @@ /// @brief Perform Write Scratchpad operation on the device. /// @param[in] data Data to write to the scratchpad. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeScratchpad(Page::const_span data); /// @brief Perform a Read Scratchpad operation on the device. - /// @param[out] data Buffer to read data from the scratchpad into. - MaximInterfaceDevices_EXPORT Core::error_code - readScratchpad(Page::span data) const; + /// @returns Buffer to read data from the scratchpad into. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> readScratchpad() 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. - MaximInterfaceDevices_EXPORT Core::error_code - readBlockProtection(int blockNum, BlockProtection & protection) const; + /// @returns Receives protection status read from device. + MaximInterfaceDevices_EXPORT Core::Result<BlockProtection> + readBlockProtection(int blockNum) 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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> writeAuthSegment(int pageNum, int segmentNum, Segment::const_span newData, Page::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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> continueWriteAuthSegment(Segment::const_span newData, Page::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. - MaximInterfaceDevices_EXPORT Core::error_code readAllBlockProtection( - Core::span<BlockProtection, protectionBlocks> protection) const; + /// @returns Receives protection statuses read from device. + MaximInterfaceDevices_EXPORT + Core::Result<Core::array<BlockProtection, protectionBlocks> > + readAllBlockProtection() const; }; /// Interface to the DS28E25 authenticator. @@ -445,14 +454,14 @@ /// @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. - MaximInterfaceDevices_EXPORT Core::error_code loadSecret(bool lock); + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code computeSecret(int pageNum, - bool lock); + MaximInterfaceDevices_EXPORT Core::Result<void> computeSecret(int pageNum, + bool lock); }; /// Represents the status of a memory protection block. @@ -523,20 +532,11 @@ static const unsigned int readProtectionMask = 0x80, writeProtectionMask = 0x40, eepromEmulationMask = 0x20, - authProtectionMask = 0x10, blockNumMask = 0x0F; + 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: @@ -666,14 +666,12 @@ /// @} private: - typedef Result::span::index_type index; - - static const index romIdIdx = 0; - static const index manIdIdx = romIdIdx + Core::RomId::size; - static const index pageNumIdx = manIdIdx + Core::ManId::size; - static const index segmentNumIdx = pageNumIdx + 1; - static const index oldDataIdx = segmentNumIdx + 1; - static const index newDataIdx = oldDataIdx + Segment::size; + static const size_t romIdIdx = 0; + static const size_t manIdIdx = romIdIdx + Core::RomId::size; + static const size_t pageNumIdx = manIdIdx + Core::ManId::size; + static const size_t segmentNumIdx = pageNumIdx + 1; + static const size_t oldDataIdx = segmentNumIdx + 1; + static const size_t newDataIdx = oldDataIdx + Segment::size; Result::array result_; }; @@ -759,13 +757,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index romIdIdx = 0; - static const index manIdIdx = romIdIdx + Core::RomId::size; - static const index blockNumIdx = manIdIdx + Core::ManId::size; - static const index oldProtectionIdx = blockNumIdx + 2; - static const index newProtectionIdx = oldProtectionIdx + 4; + static const size_t romIdIdx = 0; + static const size_t manIdIdx = romIdIdx + Core::RomId::size; + static const size_t blockNumIdx = manIdIdx + Core::ManId::size; + static const size_t oldProtectionIdx = blockNumIdx + 2; + static const size_t newProtectionIdx = oldProtectionIdx + 4; Result::array result_; BlockProtection oldProtection_; @@ -893,13 +889,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index pageIdx = 0; - static const index scratchpadIdx = pageIdx + Page::size; - static const index romIdIdx = scratchpadIdx + Page::size; - static const index manIdIdx = romIdIdx + Core::RomId::size; - static const index pageNumIdx = manIdIdx + Core::ManId::size; + static const size_t pageIdx = 0; + static const size_t scratchpadIdx = pageIdx + Page::size; + static const size_t romIdIdx = scratchpadIdx + Page::size; + static const size_t manIdIdx = romIdIdx + Core::RomId::size; + static const size_t pageNumIdx = manIdIdx + Core::ManId::size; Result::array result_; };
--- a/MaximInterfaceDevices/DS28E16.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E16.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -50,9 +50,9 @@ const int DS28E16::masterSecretPage; const int DS28E16::memoryPages; -error_code DS28E16::writeMemory(int pageNum, Page::const_span page) { +Result<void> DS28E16::writeMemory(int pageNum, Page::const_span page) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size]; @@ -62,49 +62,51 @@ return runCommand(request, writeMemoryTimeMs); } -error_code DS28E16::readMemory(int pageNum, Page::span page) { +Result<DS28E16::Page::array> DS28E16::readMemory(int pageNum) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + Page::size * 2]; 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) { - response = response.first(Page::size); - copy(response.begin(), response.end(), page.begin()); + Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer); + if (!response) { + return response.error(); } - return result; + Page::array page; + response.value() = response.value().first(Page::size); + copy(response.value().begin(), response.value().end(), page.begin()); + return page; } -error_code DS28E16::readStatus(Status & status) { - uint_least8_t buffer[1 + Status::PageProtectionList::csize + 2]; +Result<DS28E16::Status> DS28E16::readStatus() const { + uint_least8_t buffer[1 + Status::PageProtectionList::size + 2]; buffer[0] = 0xAA; - span<uint_least8_t> response(buffer); - const error_code result = - runCommand(make_span(buffer, 1), readMemoryTimeMs, 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; - } - status.manId = *responseIt; + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 1), readMemoryTimeMs, buffer); + if (!response) { + return response.error(); + } + Status status; + span<uint_least8_t>::const_iterator responseIt = response.value().begin(); + for (Status::PageProtectionList::array::iterator it = + status.pageProtection.begin(); + it != status.pageProtection.end(); ++it) { + *it = *responseIt; ++responseIt; - status.deviceVersion = *responseIt; } - return result; + status.manId = *responseIt; + ++responseIt; + status.deviceVersion = *responseIt; + return status; } -error_code DS28E16::setPageProtection(int pageNum, - const PageProtection & protection) { +Result<void> DS28E16::setPageProtection(int pageNum, + const PageProtection & protection) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t request[] = { @@ -113,12 +115,10 @@ return runCommand(request, shortWriteMemoryTimeMs); } -error_code -DS28E16::computeAndReadPageAuthentication(int pageNum, bool anonymous, - DoublePage::const_span challenge, - DoublePage::span hmac) { +Result<DS28E16::DoublePage::array> DS28E16::computeAndReadPageAuthentication( + int pageNum, bool anonymous, DoublePage::const_span challenge) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 3 + DoublePage::size; @@ -131,20 +131,22 @@ } buffer[2] = 0x02; copy(challenge.begin(), challenge.end(), buffer + 3); - span<uint_least8_t> response(buffer, responseSize); - const error_code result = - runCommand(make_span(buffer, requestSize), computationTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), hmac.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), computationTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + DoublePage::array hmac; + copy(response.value().begin(), response.value().end(), hmac.begin()); + return hmac; } -error_code DS28E16::computeSecret(int bindingDataPageNum, - bool constantBindingData, bool anonymous, - DoublePage::const_span partialSecret) { +Result<void> DS28E16::computeSecret(int bindingDataPageNum, + bool constantBindingData, bool anonymous, + DoublePage::const_span partialSecret) { if (bindingDataPageNum < 0 || bindingDataPageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[3 + DoublePage::size]; @@ -161,27 +163,29 @@ return runCommand(request, computationTimeMs); } -error_code DS28E16::decrementCounter() { +Result<void> DS28E16::decrementCounter() { const uint_least8_t request = 0xC9; return runCommand(make_span(&request, 1), writeMemoryTimeMs); } -error_code DS28E16::lockOutDisableDevice() { - const DisableDevicePassword::array password = {}; +Result<void> DS28E16::lockOutDisableDevice() { + const DisableDevicePassword::array password = {0}; return disableDevice(LockOutDisableDevice, password); } -error_code +Result<void> DS28E16::setDisableDevicePassword(DisableDevicePassword::const_span password) { return disableDevice(SetDisableDevicePassword, password); } -error_code DS28E16::disableDevice(DisableDevicePassword::const_span password) { +Result<void> +DS28E16::disableDevice(DisableDevicePassword::const_span password) { return disableDevice(DisableDevice, password); } -error_code DS28E16::disableDevice(DisableDeviceOperation operation, - DisableDevicePassword::const_span password) { +Result<void> +DS28E16::disableDevice(DisableDeviceOperation operation, + DisableDevicePassword::const_span password) { const uint_least8_t request[] = { 0x33, static_cast<uint_least8_t>(operation), password[0], password[1], @@ -191,43 +195,40 @@ return runCommand(request, shortWriteMemoryTimeMs); } -error_code DS28E16::runCommand(span<const uint_least8_t> request, int delayTime, - span<uint_least8_t> & response) { - const span<const uint_least8_t>::index_type responseInputSize = - response.size(); - error_code result = doRunCommand(request, delayTime, response); - if (result) { - return result; +Result<span<uint_least8_t> > +DS28E16::runCommand(span<const uint_least8_t> request, int delayTime, + span<uint_least8_t> response) const { + const Result<span<uint_least8_t> > responseOutput = + doRunCommand(request, delayTime, response); + if (!responseOutput) { + return responseOutput; } - if (response.empty()) { - return make_error_code(InvalidResponseError); + if (responseOutput.value().empty()) { + return InvalidResponseError; } // Parse command result byte. - switch (response[0]) { + switch (responseOutput.value().front()) { case 0xAA: // Success response. - if (response.size() != responseInputSize) { - result = make_error_code(InvalidResponseError); - } break; case 0x00: - result = make_error_code(AuthenticationError); - break; + return AuthenticationError; default: - result.assign(response[0], errorCategory()); - break; + return error_code(responseOutput.value().front(), errorCategory()); } - response = response.subspan(1); - return result; + if (responseOutput.value().size() != response.size()) { + return InvalidResponseError; + } + return responseOutput.value().subspan(1); } -error_code DS28E16::runCommand(span<const uint_least8_t> request, - int delayTime) { +Result<void> DS28E16::runCommand(span<const uint_least8_t> request, + int delayTime) { uint_least8_t buffer; - span<uint_least8_t> response(&buffer, 1); - return runCommand(request, delayTime, response); + MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1))); + return none; } const error_category & DS28E16::errorCategory() { @@ -264,15 +265,6 @@ return instance; } -error_code readManId(DS28E16 & device, uint_least8_t & manId) { - DS28E16::Status status; - const error_code result = device.readStatus(status); - if (!result) { - manId = status.manId; - } - return result; -} - DS28E16::PageAuthenticationData & DS28E16::PageAuthenticationData::setAnonymousRomId() { fill(romId().begin(), romId().end(), 0xFF);
--- a/MaximInterfaceDevices/DS28E16.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E16.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS28E16 -#define MaximInterfaceDevices_DS28E16 +#ifndef MaximInterfaceDevices_DS28E16_hpp +#define MaximInterfaceDevices_DS28E16_hpp #include <stdint.h> #include <MaximInterfaceCore/Algorithm.hpp> @@ -91,9 +91,9 @@ typedef Core::FlagSet<PageProtectionType, 4> PageProtection; struct Status { - typedef Core::array<PageProtection, memoryPages> PageProtectionList; + typedef Core::array_span<PageProtection, memoryPages> PageProtectionList; - PageProtectionList pageProtection; + PageProtectionList::array pageProtection; uint_least8_t manId; uint_least8_t deviceVersion; }; @@ -108,48 +108,47 @@ /// @brief Write memory with no protection. /// @param pageNum Number of page to write. /// @param page Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code readMemory(int pageNum, - Page::span page); + /// @returns Data that was read. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + readMemory(int pageNum) const; /// @brief Reads the current status of the device. - /// @param[out] status Status that was read. - MaximInterfaceDevices_EXPORT Core::error_code readStatus(Status & status); + /// @returns Status that was read. + MaximInterfaceDevices_EXPORT Core::Result<Status> readStatus() const; /// @brief Set the protection settings of a page. /// @param pageNum Number of page to write. /// @param protection Protection to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> setPageProtection(int pageNum, const PageProtection & protection); /// @brief Compute and read page authentication with HMAC. /// @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] hmac Computed page HMAC. - MaximInterfaceDevices_EXPORT Core::error_code + /// @returns Computed page HMAC. + MaximInterfaceDevices_EXPORT Core::Result<DoublePage::array> computeAndReadPageAuthentication(int pageNum, bool anonymous, - DoublePage::const_span challenge, - DoublePage::span hmac); + DoublePage::const_span challenge) const; /// Decrement the decrement-only counter. - MaximInterfaceDevices_EXPORT Core::error_code decrementCounter(); + MaximInterfaceDevices_EXPORT Core::Result<void> decrementCounter(); /// Set password that will be subsequently used to disable the device. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> setDisableDevicePassword(DisableDevicePassword::const_span password); /// @brief Lock-out all disable functionality for the device. /// @note Only allowed prior to setting password. - MaximInterfaceDevices_EXPORT Core::error_code lockOutDisableDevice(); + MaximInterfaceDevices_EXPORT Core::Result<void> lockOutDisableDevice(); /// Permanently disable the device. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> disableDevice(DisableDevicePassword::const_span password); /// @brief @@ -162,7 +161,7 @@ /// @note /// This command should be executed prior to the /// Compute and Read Page Authentication command. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeSecret(int bindingDataPageNum, bool constantBindingData, bool anonymous, DoublePage::const_span partialSecret); @@ -170,11 +169,11 @@ errorCategory(); protected: - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<Core::span<uint_least8_t> > runCommand(Core::span<const uint_least8_t> request, int delayTime, - Core::span<uint_least8_t> & response); + Core::span<uint_least8_t> response) const; - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> runCommand(Core::span<const uint_least8_t> request, int delayTime); private: @@ -184,22 +183,26 @@ DisableDevice = 0x00 }; - Core::error_code disableDevice(DisableDeviceOperation operation, - DisableDevicePassword::const_span password); + Core::Result<void> disableDevice(DisableDeviceOperation operation, + DisableDevicePassword::const_span password); Core::RunCommand doRunCommand; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS28E16::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS28E16::ErrorValue e) { return Core::error_code(e, DS28E16::errorCategory()); } -/// @brief Read the device MAN ID using the Read Status command. -/// @param device Device to read. -/// @param[out] manId Read MAN ID valid when operation is successful. -MaximInterfaceDevices_EXPORT Core::error_code readManId(DS28E16 & device, - uint_least8_t & manId); - /// Format page authentication input data. class DS28E16::PageAuthenticationData { public: @@ -317,13 +320,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index romIdIdx = 0; - static const index pageIdx = romIdIdx + Core::RomId::size; - static const index challengeIdx = pageIdx + 2 * Page::size; - static const index pageNumIdx = challengeIdx + DoublePage::size; - static const index manIdIdx = pageNumIdx + 1; + static const size_t romIdIdx = 0; + static const size_t pageIdx = romIdIdx + Core::RomId::size; + static const size_t challengeIdx = pageIdx + 2 * Page::size; + static const size_t pageNumIdx = challengeIdx + DoublePage::size; + static const size_t manIdIdx = pageNumIdx + 1; Result::array result_; };
--- a/MaximInterfaceDevices/DS28E17.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E17.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -31,58 +31,54 @@ *******************************************************************************/ #include <stddef.h> -#include <MaximInterfaceCore/crc.hpp> +#include <MaximInterfaceCore/Crc.hpp> #include <MaximInterfaceCore/Error.hpp> #include <MaximInterfaceCore/OneWireMaster.hpp> #include "DS28E17.hpp" +#define TRY MaximInterfaceCore_TRY +#define TRY_VALUE MaximInterfaceCore_TRY_VALUE + namespace MaximInterfaceDevices { using namespace Core; -error_code DS28E17::writeDataWithStop(uint_least8_t I2C_addr, - span<const uint_least8_t> data, - uint_least8_t * wr_status) { +Result<void> DS28E17::writeDataWithStop(uint_least8_t I2C_addr, + span<const uint_least8_t> data) { return sendPacket(WriteDataWithStopCmd, &I2C_addr, data, - span<uint_least8_t>(), wr_status); + span<uint_least8_t>()); } -error_code DS28E17::writeDataNoStop(uint_least8_t I2C_addr, - span<const uint_least8_t> data, - uint_least8_t * wr_status) { - return sendPacket(WriteDataNoStopCmd, &I2C_addr, data, span<uint_least8_t>(), - wr_status); +Result<void> DS28E17::writeDataNoStop(uint_least8_t I2C_addr, + span<const uint_least8_t> data) { + return sendPacket(WriteDataNoStopCmd, &I2C_addr, data, span<uint_least8_t>()); } -error_code DS28E17::writeDataOnly(span<const uint_least8_t> data, - uint_least8_t * wr_status) { - return sendPacket(WriteDataOnlyCmd, NULL, data, span<uint_least8_t>(), - wr_status); +Result<void> DS28E17::writeDataOnly(span<const uint_least8_t> data) { + return sendPacket(WriteDataOnlyCmd, NULL, data, span<uint_least8_t>()); } -error_code DS28E17::writeDataOnlyWithStop(span<const uint_least8_t> data, - uint_least8_t * wr_status) { - return sendPacket(WriteDataOnlyWithStopCmd, NULL, data, span<uint_least8_t>(), - wr_status); +Result<void> DS28E17::writeDataOnlyWithStop(span<const uint_least8_t> data) { + return sendPacket(WriteDataOnlyWithStopCmd, NULL, data, + span<uint_least8_t>()); } -error_code DS28E17::writeReadDataWithStop(uint_least8_t I2C_addr, - 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, read_data, - wr_status); +Result<void> +DS28E17::writeReadDataWithStop(uint_least8_t I2C_addr, + span<const uint_least8_t> write_data, + span<uint_least8_t> read_data) { + return sendPacket(WriteReadDataWithStopCmd, &I2C_addr, write_data, read_data); } -error_code DS28E17::readDataWithStop(uint_least8_t I2C_addr, - span<uint_least8_t> data) { +Result<void> DS28E17::readDataWithStop(uint_least8_t I2C_addr, + span<uint_least8_t> data) { return sendPacket(ReadDataWithStopCmd, &I2C_addr, span<const uint_least8_t>(), - data, NULL); + data); } -error_code DS28E17::writeConfigReg(I2CSpeed speed) { - error_code result = selectRom(*master); - if (!result) { +Result<void> DS28E17::writeConfigReg(I2CSpeed speed) { + Result<void> result = selectRom(*master); + if (result) { // Send CMD and Data const uint_least8_t send_block[] = {WriteConfigurationCmd, static_cast<uint_least8_t>(speed)}; @@ -91,97 +87,86 @@ return result; } -error_code DS28E17::readConfigReg(I2CSpeed & speed) { - error_code result = selectRom(*master); - if (!result) { - // Send CMD and receive Data - result = master->writeByte(ReadConfigurationCmd); - if (!result) { - uint_least8_t config; - result = master->readByte(config); - if (!result) { - switch (config) { - case Speed100kHz: - case Speed400kHz: - case Speed900kHz: - speed = static_cast<I2CSpeed>(config); - break; - - default: - result = make_error_code(OutOfRangeError); - break; - } - } - } +Result<DS28E17::I2CSpeed> DS28E17::readConfigReg() const { + TRY(selectRom(*master)); + // Send CMD and receive Data + TRY(master->writeByte(ReadConfigurationCmd)); + uint_least8_t config; + TRY_VALUE(config, master->readByte()); + switch (config) { + case Speed100kHz: + case Speed400kHz: + case Speed900kHz: + return static_cast<I2CSpeed>(config); } - return result; + return OutOfRangeError; } -error_code DS28E17::enableSleepMode() { - error_code result = selectRom(*master); - if (!result) { +Result<void> DS28E17::enableSleepMode() { + Result<void> result = selectRom(*master); + if (result) { // Send CMD result = master->writeByte(EnableSleepModeCmd); } return result; } -error_code DS28E17::readDeviceRevision(uint_least8_t & rev) { - error_code result = selectRom(*master); +Result<uint_least8_t> DS28E17::readDeviceRevision() const { + Result<void> result = selectRom(*master); if (!result) { - // Send CMD and receive Data - result = master->writeByte(ReadDeviceRevisionCmd); - if (!result) { - result = master->readByte(rev); - } + return result.error(); } - return result; + result = master->writeByte(ReadDeviceRevisionCmd); + if (!result) { + return result.error(); + } + return master->readByte(); } -error_code DS28E17::sendPacket(Command command, const uint_least8_t * I2C_addr, - span<const uint_least8_t> write_data, - span<uint_least8_t> read_data, - uint_least8_t * wr_status) { +Result<void> DS28E17::sendPacket(Command command, + const uint_least8_t * I2C_addr, + span<const uint_least8_t> write_data, + span<uint_least8_t> read_data) { const int pollLimit = 10000; const span<const uint_least8_t>::index_type maxDataLen = 255; if ((!write_data.empty() && write_data.size() > maxDataLen) || (!read_data.empty() && read_data.size() > maxDataLen)) { - return make_error_code(OutOfRangeError); + return OutOfRangeError; } - error_code result = selectRom(*master); - if (result) { + Result<void> result = selectRom(*master); + if (!result) { return result; } uint_fast16_t crc16 = calculateCrc16(command); result = master->writeByte(command); - if (result) { + if (!result) { return result; } if (I2C_addr) { crc16 = calculateCrc16(crc16, *I2C_addr); result = master->writeByte(*I2C_addr); - if (result) { + if (!result) { return result; } } if (!write_data.empty()) { crc16 = calculateCrc16(crc16, static_cast<uint_fast8_t>(write_data.size())); result = master->writeByte(static_cast<uint_least8_t>(write_data.size())); - if (result) { + if (!result) { return result; } crc16 = calculateCrc16(crc16, write_data); result = master->writeBlock(write_data); - if (result) { + if (!result) { return result; } } if (!read_data.empty()) { crc16 = calculateCrc16(crc16, static_cast<uint_fast8_t>(read_data.size())); result = master->writeByte(static_cast<uint_least8_t>(read_data.size())); - if (result) { + if (!result) { return result; } } @@ -189,45 +174,33 @@ const uint_least8_t crc16Bytes[] = {static_cast<uint_least8_t>(crc16), static_cast<uint_least8_t>(crc16 >> 8)}; result = master->writeBlock(crc16Bytes); - if (result) { + if (!result) { return result; } // Poll for Zero 1-Wire bit and return if an error occurs int poll_count = 0; - bool recvbit; + bool recvBit; do { if (poll_count++ < pollLimit) { - return make_error_code(TimeoutError); - } - result = master->readBit(recvbit); - if (result) { - return result; + return TimeoutError; } - } while (recvbit); + TRY_VALUE(recvBit, master->readBit()); + } while (recvBit); uint_least8_t status; - result = master->readByte(status); - if (result) { - return result; - } + TRY_VALUE(status, master->readByte()); if ((status & 0x1) == 0x1) { - return make_error_code(InvalidCrc16Error); + return InvalidCrc16Error; } if ((status & 0x2) == 0x2) { - return make_error_code(AddressNackError); + return AddressNackError; } if ((status & 0x8) == 0x8) { - return make_error_code(InvalidStartError); + return InvalidStartError; } if (!write_data.empty()) { - result = master->readByte(status); - if (result) { - return result; - } - if (wr_status) { - *wr_status = status; - } + TRY_VALUE(status, master->readByte()); if (status != 0) { - return make_error_code(WriteNackError); + return error_code(status, errorCategory()); } } if (!read_data.empty()) { @@ -257,13 +230,11 @@ case InvalidStartError: return "Invalid Start Error"; - - case WriteNackError: + } + if (condition >= 1 && condition <= 255) { return "Write Nack Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance;
--- a/MaximInterfaceDevices/DS28E17.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E17.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS28E17 -#define MaximInterfaceDevices_DS28E17 +#ifndef MaximInterfaceDevices_DS28E17_hpp +#define MaximInterfaceDevices_DS28E17_hpp #include <stdint.h> #include <MaximInterfaceCore/SelectRom.hpp> @@ -55,13 +55,13 @@ /// provides 1-Wire access for a single I2C interface. class DS28E17 { public: + // Values from 1-255 represent the Write Status byte. enum ErrorValue { - TimeoutError = 1, + TimeoutError = 256, OutOfRangeError, InvalidCrc16Error, AddressNackError, - InvalidStartError, - WriteNackError + InvalidStartError }; enum I2CSpeed { Speed100kHz, Speed400kHz, Speed900kHz }; @@ -81,14 +81,12 @@ /// I2C slave address. The least significant bit of the I2C /// address is automatically cleared by the command. /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + /// @returns + /// Values from 1-255 in the DS28E17 category represent the Write Status + /// indicating which write byte did not acknowledge. + MaximInterfaceDevices_EXPORT Core::Result<void> writeDataWithStop(uint_least8_t I2C_addr, - Core::span<const uint_least8_t> data, - uint_least8_t * wr_status = NULL); + Core::span<const uint_least8_t> data); /// @brief Write Data No Stop command. /// @details Output on I2C: S, Address + Write, Write Data [1-255] @@ -96,35 +94,29 @@ /// I2C slave address. The least significant bit of the I2C address /// is automatically cleared by the command. /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - writeDataNoStop(uint_least8_t I2C_addr, Core::span<const uint_least8_t> data, - uint_least8_t * wr_status = NULL); + /// @returns + /// Values from 1-255 in the DS28E17 category represent the Write Status + /// indicating which write byte did not acknowledge. + MaximInterfaceDevices_EXPORT Core::Result<void> + writeDataNoStop(uint_least8_t I2C_addr, Core::span<const uint_least8_t> data); /// @brief Write Data Only command. /// @details Output on I2C: Write Data [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. - MaximInterfaceDevices_EXPORT Core::error_code - writeDataOnly(Core::span<const uint_least8_t> data, - uint_least8_t * wr_status = NULL); + /// @returns + /// Values from 1-255 in the DS28E17 category represent the Write Status + /// indicating which write byte did not acknowledge. + MaximInterfaceDevices_EXPORT Core::Result<void> + writeDataOnly(Core::span<const uint_least8_t> data); /// @brief Write Data Only With Stop command. /// @details Output on I2C: Write Data [1-255], P /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - writeDataOnlyWithStop(Core::span<const uint_least8_t> data, - uint_least8_t * wr_status = NULL); + /// @returns + /// Values from 1-255 in the DS28E17 category represent the Write Status + /// indicating which write byte did not acknowledge. + MaximInterfaceDevices_EXPORT Core::Result<void> + writeDataOnlyWithStop(Core::span<const uint_least8_t> data); /// @brief Write, Read Data With Stop command. /// @details Output on I2C: @@ -135,13 +127,13 @@ /// is automatically cleared and set by the command. /// @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. - MaximInterfaceDevices_EXPORT Core::error_code writeReadDataWithStop( - uint_least8_t I2C_addr, Core::span<const uint_least8_t> write_data, - Core::span<uint_least8_t> read_data, uint_least8_t * wr_status = NULL); + /// @returns + /// Values from 1-255 in the DS28E17 category represent the Write Status + /// indicating which write byte did not acknowledge. + MaximInterfaceDevices_EXPORT Core::Result<void> + writeReadDataWithStop(uint_least8_t I2C_addr, + Core::span<const uint_least8_t> write_data, + Core::span<uint_least8_t> read_data); /// @brief Read Data With Stop command. /// @details Output on I2C: @@ -150,28 +142,29 @@ /// 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 with length 1-255. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> readDataWithStop(uint_least8_t I2C_addr, Core::span<uint_least8_t> data); /// Write to Configuration Register of DS28E17. - MaximInterfaceDevices_EXPORT Core::error_code writeConfigReg(I2CSpeed speed); + MaximInterfaceDevices_EXPORT Core::Result<void> + writeConfigReg(I2CSpeed speed); /// @brief Read the Configuration Register of DS28E17. - /// @param[out] speed Speed read from configuration register. - MaximInterfaceDevices_EXPORT Core::error_code readConfigReg(I2CSpeed & speed); + /// @returns speed Speed read from configuration register. + MaximInterfaceDevices_EXPORT Core::Result<I2CSpeed> readConfigReg() const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code enableSleepMode(); + MaximInterfaceDevices_EXPORT Core::Result<void> enableSleepMode(); /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - readDeviceRevision(uint_least8_t & rev); + /// @returns Device Revision. + MaximInterfaceDevices_EXPORT Core::Result<uint_least8_t> + readDeviceRevision() const; MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); @@ -190,15 +183,24 @@ ReadDeviceRevisionCmd = 0xC3 }; - Core::error_code sendPacket(Command command, const uint_least8_t * I2C_addr, - Core::span<const uint_least8_t> write_data, - Core::span<uint_least8_t> read_data, - uint_least8_t * wr_status); + Core::Result<void> sendPacket(Command command, const uint_least8_t * I2C_addr, + Core::span<const uint_least8_t> write_data, + Core::span<uint_least8_t> read_data); Core::SelectRom selectRom; Core::OneWireMaster * master; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS28E17::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS28E17::ErrorValue e) { return Core::error_code(e, DS28E17::errorCategory()); }
--- a/MaximInterfaceDevices/DS28E38.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E38.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -54,9 +54,9 @@ const int DS28E38::privateKeyPage; const int DS28E38::memoryPages; -error_code DS28E38::writeMemory(int pageNum, Page::const_span page) { +Result<void> DS28E38::writeMemory(int pageNum, Page::const_span page) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size]; @@ -66,69 +66,71 @@ return runCommand(request, writeMemoryTimeMs); } -error_code DS28E38::readMemory(int pageNum, Page::span page) { +Result<DS28E38::Page::array> DS28E38::readMemory(int pageNum) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + Page::size]; buffer[0] = 0x44; buffer[1] = pageNum; - span<uint_least8_t> response(buffer); - const error_code result = - runCommand(make_span(buffer, 2), readMemoryTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), page.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer); + if (!response) { + return response.error(); } - return result; + Page::array page; + copy(response.value().begin(), response.value().end(), page.begin()); + return page; } -error_code DS28E38::readStatus(bool entropyHealthTest, Status & status) { +Result<DS28E38::Status> DS28E38::readStatus(bool entropyHealthTest) const { int delay = readMemoryTimeMs; if (entropyHealthTest) { delay += trngOnDemandCheckTimeMs; } - uint_least8_t buffer[Status::PageProtectionList::csize + ManId::size + - Status::RomVersion::csize + 2]; + uint_least8_t buffer[Status::PageProtectionList::size + ManId::size + + Status::RomVersion::size + 2]; buffer[0] = 0xAA; buffer[1] = entropyHealthTest ? 0x01 : 0x00; - span<uint_least8_t> response(buffer); - error_code result = runCommand(make_span(buffer, 2), delay, response); - if (!result) { - span<uint_least8_t>::const_iterator responseIt = response.begin(); - for (Status::PageProtectionList::iterator it = - status.pageProtection.begin(); - it != status.pageProtection.end(); ++it) { - *it = *responseIt; - ++responseIt; - } - span<uint_least8_t>::const_iterator responseItEnd = - responseIt + status.manId.size(); - copy(responseIt, responseItEnd, status.manId.begin()); - responseIt = responseItEnd; - responseItEnd = responseIt + status.romVersion.size(); - copy(responseIt, responseItEnd, status.romVersion.begin()); - responseIt = responseItEnd; - switch (*responseIt) { - case Status::TestNotPerformed: - case Status::EntropyHealthy: - case Status::EntropyNotHealthy: - status.entropyHealthTestStatus = - static_cast<Status::EntropyHealthTestStatus>(*responseIt); - break; + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), delay, buffer); + if (!response) { + return response.error(); + } + Status status; + span<uint_least8_t>::const_iterator responseIt = response.value().begin(); + for (Status::PageProtectionList::array::iterator it = + status.pageProtection.begin(); + it != status.pageProtection.end(); ++it) { + *it = *responseIt; + ++responseIt; + } + span<uint_least8_t>::const_iterator responseItEnd = + responseIt + status.manId.size(); + copy(responseIt, responseItEnd, status.manId.begin()); + responseIt = responseItEnd; + responseItEnd = responseIt + status.romVersion.size(); + copy(responseIt, responseItEnd, status.romVersion.begin()); + responseIt = responseItEnd; + switch (*responseIt) { + case Status::TestNotPerformed: + case Status::EntropyHealthy: + case Status::EntropyNotHealthy: + status.entropyHealthTestStatus = + static_cast<Status::EntropyHealthTestStatus>(*responseIt); + break; - default: - result = make_error_code(InvalidResponseError); - break; - } + default: + return InvalidResponseError; } - return result; + return status; } -error_code DS28E38::setPageProtection(int pageNum, - const PageProtection & protection) { +Result<void> DS28E38::setPageProtection(int pageNum, + const PageProtection & protection) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } int delay = writeStateTimeMs; @@ -141,12 +143,11 @@ return runCommand(request, delay); } -error_code +Result<Ecc256::Signature::array> DS28E38::computeAndReadPageAuthentication(int pageNum, bool anonymous, - Page::const_span challenge, - Ecc256::Signature::span signature) { + Page::const_span challenge) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 2 + Page::size; @@ -155,33 +156,35 @@ buffer[0] = 0xA5; buffer[1] = pageNum | (anonymous ? 0xE0 : 0x00); copy(challenge.begin(), challenge.end(), buffer + 2); - span<uint_least8_t> response(buffer, responseSize); - const error_code result = runCommand(make_span(buffer, requestSize), - generateEcdsaSignatureTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = begin + signature.s.size(); - copy(begin, end, signature.s.begin()); - begin = end; - end = begin + signature.r.size(); - copy(begin, end, signature.r.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + Ecc256::Signature::array signature; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + signature.s.size(); + copy(begin, end, signature.s.begin()); + begin = end; + end = begin + signature.r.size(); + copy(begin, end, signature.r.begin()); + return signature; } -error_code DS28E38::decrementCounter() { +Result<void> DS28E38::decrementCounter() { const uint_least8_t request = 0xC9; return runCommand(make_span(&request, 1), writeMemoryTimeMs); } -error_code DS28E38::disableDevice() { +Result<void> DS28E38::disableDevice() { const uint_least8_t request[] = {0x33, 0x9E, 0xA7, 0x49, 0xFB, 0x10, 0x62, 0x0A, 0x26}; return runCommand(request, writeStateTimeMs); } -error_code DS28E38::generateEcc256KeyPair(bool privateKeyPuf, - bool writeProtectEnable) { +Result<void> DS28E38::generateEcc256KeyPair(bool privateKeyPuf, + bool writeProtectEnable) { int delay = generateEccKeyPairTimeMs; if (writeProtectEnable) { delay += writeStateTimeMs; @@ -196,61 +199,59 @@ return runCommand(request, delay); } -error_code DS28E38::readRng(span<uint_least8_t> data) { +Result<void> DS28E38::readRng(span<uint_least8_t> data) const { const span<uint_least8_t>::index_type maxDataSize = 64; if ((data.size() < 1) || (data.size() > maxDataSize)) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + maxDataSize]; buffer[0] = 0xD2; buffer[1] = static_cast<uint_least8_t>(data.size() - 1); - span<uint_least8_t> response(buffer, 1 + data.size()); - const error_code result = - runCommand(make_span(buffer, 2), trngGenerationTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), data.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), trngGenerationTimeMs, + make_span(buffer, 1 + data.size())); + if (!response) { + return response.error(); } - return result; + copy(response.value().begin(), response.value().end(), data.begin()); + return none; } -error_code DS28E38::runCommand(span<const uint_least8_t> request, int delayTime, - span<uint_least8_t> & response) { - const span<const uint_least8_t>::index_type responseInputSize = - response.size(); - error_code result = doRunCommand(request, delayTime, response); - if (result) { - return result; +Result<span<uint_least8_t> > +DS28E38::runCommand(span<const uint_least8_t> request, int delayTime, + span<uint_least8_t> response) const { + const Result<span<uint_least8_t> > responseOutput = + doRunCommand(request, delayTime, response); + if (!responseOutput) { + return responseOutput; } - if (response.empty()) { - return make_error_code(InvalidResponseError); + if (responseOutput.value().empty()) { + return InvalidResponseError; } // Parse command result byte. - switch (response[0]) { + switch (responseOutput.value().front()) { case 0xAA: // Success response. - if (response.size() != responseInputSize) { - result = make_error_code(InvalidResponseError); - } break; case 0x00: - result = make_error_code(InvalidResponseError); - break; + return InvalidResponseError; default: - result.assign(response[0], errorCategory()); - break; + return error_code(responseOutput.value().front(), errorCategory()); } - response = response.subspan(1); - return result; + if (responseOutput.value().size() != response.size()) { + return InvalidResponseError; + } + return responseOutput.value().subspan(1); } -error_code DS28E38::runCommand(span<const uint_least8_t> request, - int delayTime) { +Result<void> DS28E38::runCommand(span<const uint_least8_t> request, + int delayTime) { uint_least8_t buffer; - span<uint_least8_t> response(&buffer, 1); - return runCommand(request, delayTime, response); + MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1))); + return none; } const error_category & DS28E38::errorCategory() { @@ -284,15 +285,6 @@ 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);
--- a/MaximInterfaceDevices/DS28E38.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E38.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS28E38 -#define MaximInterfaceDevices_DS28E38 +#ifndef MaximInterfaceDevices_DS28E38_hpp +#define MaximInterfaceDevices_DS28E38_hpp #include <stdint.h> #include <MaximInterfaceCore/Algorithm.hpp> @@ -94,12 +94,12 @@ EntropyNotHealthy = 0xDD }; - typedef Core::array<PageProtection, memoryPages> PageProtectionList; - typedef Core::array<uint_least8_t, 2> RomVersion; + typedef Core::array_span<PageProtection, memoryPages> PageProtectionList; + typedef Core::array_span<uint_least8_t, 2> RomVersion; - PageProtectionList pageProtection; + PageProtectionList::array pageProtection; Core::ManId::array manId; - RomVersion romVersion; + RomVersion::array romVersion; EntropyHealthTestStatus entropyHealthTestStatus; }; @@ -113,81 +113,84 @@ /// @brief Write memory with no protection. /// @param pageNum Number of page to write. /// @param page Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code readMemory(int pageNum, - Page::span page); + /// @returns Data that was read. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + readMemory(int pageNum) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - readStatus(bool entropyHealthTest, Status & status); + /// @returns status Status that was read. + MaximInterfaceDevices_EXPORT Core::Result<Status> + readStatus(bool entropyHealthTest) const; /// @brief Set the protection settings of a page. /// @param pageNum Number of page to write. /// @param protection Protection to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code + /// @returns Computed page signature. + MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::Signature::array> computeAndReadPageAuthentication(int pageNum, bool anonymous, - Page::const_span challenge, - Core::Ecc256::Signature::span signature); + Page::const_span challenge) const; /// Decrement the decrement-only counter. - MaximInterfaceDevices_EXPORT Core::error_code decrementCounter(); + MaximInterfaceDevices_EXPORT Core::Result<void> decrementCounter(); /// Permanently disable the device. - MaximInterfaceDevices_EXPORT Core::error_code disableDevice(); + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code - readRng(Core::span<uint_least8_t> data); + MaximInterfaceDevices_EXPORT Core::Result<void> + readRng(Core::span<uint_least8_t> data) const; MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); protected: - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<Core::span<uint_least8_t> > runCommand(Core::span<const uint_least8_t> request, int delayTime, - Core::span<uint_least8_t> & response); + Core::span<uint_least8_t> response) const; - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> runCommand(Core::span<const uint_least8_t> request, int delayTime); private: Core::RunCommand doRunCommand; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS28E38::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS28E38::ErrorValue e) { return Core::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. -MaximInterfaceDevices_EXPORT Core::error_code -readManId(DS28E38 & ds28e38, Core::ManId::span manId); - /// Format page authentication input data. class DS28E38::PageAuthenticationData { public: @@ -307,13 +310,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index romIdIdx = 0; - static const index pageIdx = romIdIdx + Core::RomId::size; - static const index challengeIdx = pageIdx + Page::size; - static const index pageNumIdx = challengeIdx + Page::size; - static const index manIdIdx = pageNumIdx + 1; + static const size_t romIdIdx = 0; + static const size_t pageIdx = romIdIdx + Core::RomId::size; + static const size_t challengeIdx = pageIdx + Page::size; + static const size_t pageNumIdx = challengeIdx + Page::size; + static const size_t manIdIdx = pageNumIdx + 1; Result::array result_; };
--- a/MaximInterfaceDevices/DS28E39.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E39.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -56,9 +56,9 @@ const int DS28E39::writePublicKeyYPage; const int DS28E39::memoryPages; -error_code DS28E39::writeMemory(int pageNum, Page::const_span page) { +Result<void> DS28E39::writeMemory(int pageNum, Page::const_span page) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size]; @@ -68,69 +68,71 @@ return runCommand(request, writeMemoryTimeMs); } -error_code DS28E39::readMemory(int pageNum, Page::span page) { +Result<DS28E39::Page::array> DS28E39::readMemory(int pageNum) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + Page::size]; buffer[0] = 0x44; buffer[1] = pageNum; - span<uint_least8_t> response(buffer); - const error_code result = - runCommand(make_span(buffer, 2), readMemoryTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), page.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer); + if (!response) { + return response.error(); } - return result; + Page::array page; + copy(response.value().begin(), response.value().end(), page.begin()); + return page; } -error_code DS28E39::readStatus(bool entropyHealthTest, Status & status) { +Result<DS28E39::Status> DS28E39::readStatus(bool entropyHealthTest) const { int delay = readMemoryTimeMs; if (entropyHealthTest) { delay += trngOnDemandCheckTimeMs; } - uint_least8_t buffer[Status::PageProtectionList::csize + ManId::size + - Status::RomVersion::csize + 2]; + uint_least8_t buffer[Status::PageProtectionList::size + ManId::size + + Status::RomVersion::size + 2]; buffer[0] = 0xAA; buffer[1] = entropyHealthTest ? 0x01 : 0x00; - span<uint_least8_t> response(buffer); - error_code result = runCommand(make_span(buffer, 2), delay, response); - if (!result) { - span<uint_least8_t>::const_iterator responseIt = response.begin(); - for (Status::PageProtectionList::iterator it = - status.pageProtection.begin(); - it != status.pageProtection.end(); ++it) { - *it = *responseIt; - ++responseIt; - } - span<uint_least8_t>::const_iterator responseItEnd = - responseIt + status.manId.size(); - copy(responseIt, responseItEnd, status.manId.begin()); - responseIt = responseItEnd; - responseItEnd = responseIt + status.romVersion.size(); - copy(responseIt, responseItEnd, status.romVersion.begin()); - responseIt = responseItEnd; - switch (*responseIt) { - case Status::TestNotPerformed: - case Status::EntropyHealthy: - case Status::EntropyNotHealthy: - status.entropyHealthTestStatus = - static_cast<Status::EntropyHealthTestStatus>(*responseIt); - break; + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), delay, buffer); + if (!response) { + return response.error(); + } + Status status; + span<uint_least8_t>::const_iterator responseIt = response.value().begin(); + for (Status::PageProtectionList::array::iterator it = + status.pageProtection.begin(); + it != status.pageProtection.end(); ++it) { + *it = *responseIt; + ++responseIt; + } + span<uint_least8_t>::const_iterator responseItEnd = + responseIt + status.manId.size(); + copy(responseIt, responseItEnd, status.manId.begin()); + responseIt = responseItEnd; + responseItEnd = responseIt + status.romVersion.size(); + copy(responseIt, responseItEnd, status.romVersion.begin()); + responseIt = responseItEnd; + switch (*responseIt) { + case Status::TestNotPerformed: + case Status::EntropyHealthy: + case Status::EntropyNotHealthy: + status.entropyHealthTestStatus = + static_cast<Status::EntropyHealthTestStatus>(*responseIt); + break; - default: - result = make_error_code(InvalidResponseError); - break; - } + default: + return InvalidResponseError; } - return result; + return status; } -error_code DS28E39::setPageProtection(int pageNum, - const PageProtection & protection) { +Result<void> DS28E39::setPageProtection(int pageNum, + const PageProtection & protection) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } int delay = writeStateTimeMs; @@ -143,12 +145,11 @@ return runCommand(request, delay); } -error_code +Result<Ecc256::Signature::array> DS28E39::computeAndReadPageAuthentication(int pageNum, bool anonymous, - Page::const_span challenge, - Ecc256::Signature::span signature) { + Page::const_span challenge) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 2 + Page::size; @@ -157,68 +158,71 @@ buffer[0] = 0xA5; buffer[1] = pageNum | (anonymous ? 0xE0 : 0x00); copy(challenge.begin(), challenge.end(), buffer + 2); - span<uint_least8_t> response(buffer, responseSize); - const error_code result = runCommand(make_span(buffer, requestSize), - generateEcdsaSignatureTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = begin + signature.s.size(); - copy(begin, end, signature.s.begin()); - begin = end; - end = begin + signature.r.size(); - copy(begin, end, signature.r.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + Ecc256::Signature::array signature; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + signature.s.size(); + copy(begin, end, signature.s.begin()); + begin = end; + end = begin + signature.r.size(); + copy(begin, end, signature.r.begin()); + return signature; } -error_code DS28E39::decrementCounter() { +Result<void> DS28E39::decrementCounter() { const uint_least8_t request = 0xC9; return runCommand(make_span(&request, 1), writeMemoryTimeMs); } -error_code DS28E39::disableDevice() { +Result<void> DS28E39::disableDevice() { const uint_least8_t request[] = {0x33, 0x9E, 0xA7, 0x49, 0xFB, 0x10, 0x62, 0x0A, 0x26}; return runCommand(request, writeStateTimeMs); } -error_code -DS28E39::readDevicePublicKey(Ecc256::PublicKey::span devicePublicKey) { +Result<Ecc256::PublicKey::array> DS28E39::readDevicePublicKey() const { uint_least8_t buffer[1 + 2 * Ecc256::Scalar::size]; buffer[0] = 0xCB; - span<uint_least8_t> response(buffer); - const error_code result = - runCommand(make_span(buffer, 1), generateEccKeyPairTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = begin + devicePublicKey.x.size(); - copy(begin, end, devicePublicKey.x.begin()); - begin = end; - end = begin + devicePublicKey.y.size(); - copy(begin, end, devicePublicKey.y.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 1), generateEccKeyPairTimeMs, buffer); + if (!response) { + return response.error(); } - return result; + Ecc256::PublicKey::array devicePublicKey; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + devicePublicKey.x.size(); + copy(begin, end, devicePublicKey.x.begin()); + begin = end; + end = begin + devicePublicKey.y.size(); + copy(begin, end, devicePublicKey.y.begin()); + return devicePublicKey; } -error_code DS28E39::readRng(span<uint_least8_t> data) { +Result<void> DS28E39::readRng(span<uint_least8_t> data) const { const span<uint_least8_t>::index_type maxDataSize = 64; if ((data.size() < 1) || (data.size() > maxDataSize)) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + maxDataSize]; buffer[0] = 0xD2; buffer[1] = static_cast<uint_least8_t>(data.size() - 1); - span<uint_least8_t> response(buffer, 1 + data.size()); - const error_code result = - runCommand(make_span(buffer, 2), trngGenerationTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), data.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), trngGenerationTimeMs, + make_span(buffer, 1 + data.size())); + if (!response) { + return response.error(); } - return result; + copy(response.value().begin(), response.value().end(), data.begin()); + return none; } -error_code +Result<void> DS28E39::authenticatePublicKey(Ecc256::Signature::const_span certificate, span<const uint_least8_t> customization) { static const span<const uint_least8_t>::index_type maxCustomizationSize = 32; @@ -226,7 +230,7 @@ 2 * Ecc256::Scalar::size; if (customization.size() < 1 || customization.size() > maxCustomizationSize) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[1 + signatureSize + maxCustomizationSize]; @@ -238,11 +242,11 @@ return runCommand(make_span(request, requestIt), verifyEcdsaSignatureTimeMs); } -error_code +Result<void> DS28E39::authenticatedWriteMemory(int pageNum, Page::const_span page, Ecc256::Signature::const_span signature) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size]; @@ -255,43 +259,40 @@ return runCommand(request, verifyEcdsaSignatureTimeMs + writeMemoryTimeMs); } -error_code DS28E39::runCommand(span<const uint_least8_t> request, int delayTime, - span<uint_least8_t> & response) { - const span<const uint_least8_t>::index_type responseInputSize = - response.size(); - error_code result = doRunCommand(request, delayTime, response); - if (result) { - return result; +Result<span<uint_least8_t> > +DS28E39::runCommand(span<const uint_least8_t> request, int delayTime, + span<uint_least8_t> response) const { + const Result<span<uint_least8_t> > responseOutput = + doRunCommand(request, delayTime, response); + if (!responseOutput) { + return responseOutput; } - if (response.empty()) { - return make_error_code(InvalidResponseError); + if (responseOutput.value().empty()) { + return InvalidResponseError; } // Parse command result byte. - switch (response[0]) { + switch (responseOutput.value().front()) { case 0xAA: // Success response. - if (response.size() != responseInputSize) { - result = make_error_code(InvalidResponseError); - } break; case 0x00: - result = make_error_code(AuthenticationError); - break; + return AuthenticationError; default: - result.assign(response[0], errorCategory()); - break; + return error_code(responseOutput.value().front(), errorCategory()); } - response = response.subspan(1); - return result; + if (responseOutput.value().size() != response.size()) { + return InvalidResponseError; + } + return responseOutput.value().subspan(1); } -error_code DS28E39::runCommand(span<const uint_least8_t> request, - int delayTime) { +Result<void> DS28E39::runCommand(span<const uint_least8_t> request, + int delayTime) { uint_least8_t buffer; - span<uint_least8_t> response(&buffer, 1); - return runCommand(request, delayTime, response); + MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1))); + return none; } const error_category & DS28E39::errorCategory() { @@ -328,15 +329,6 @@ return instance; } -error_code readManId(DS28E39 & ds28e39, ManId::span manId) { - DS28E39::Status status; - const error_code result = ds28e39.readStatus(false, status); - if (!result) { - copy(make_span(status.manId), manId); - } - return result; -} - DS28E39::PageAuthenticationData & DS28E39::PageAuthenticationData::setAnonymousRomId() { std::fill(romId().begin(), romId().end(), 0xFF);
--- a/MaximInterfaceDevices/DS28E39.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E39.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS28E39 -#define MaximInterfaceDevices_DS28E39 +#ifndef MaximInterfaceDevices_DS28E39_hpp +#define MaximInterfaceDevices_DS28E39_hpp #include <stdint.h> #include <MaximInterfaceCore/Algorithm.hpp> @@ -98,12 +98,14 @@ EntropyNotHealthy = 0xDD }; - typedef Core::array<PageProtection, memoryPages - 2> PageProtectionList; - typedef Core::array<uint_least8_t, 2> RomVersion; + typedef Core::array_span<PageProtection, memoryPages - 2> + PageProtectionList; - PageProtectionList pageProtection; + typedef Core::array_span<uint_least8_t, 2> RomVersion; + + PageProtectionList::array pageProtection; Core::ManId::array manId; - RomVersion romVersion; + RomVersion::array romVersion; EntropyHealthTestStatus entropyHealthTestStatus; }; @@ -117,54 +119,53 @@ /// @brief Write memory with no protection. /// @param pageNum Number of page to write. /// @param page Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code readMemory(int pageNum, - Page::span page); + /// @returns Data that was read. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + readMemory(int pageNum) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code - readStatus(bool entropyHealthTest, Status & status); + /// @returns Status that was read. + MaximInterfaceDevices_EXPORT Core::Result<Status> + readStatus(bool entropyHealthTest) const; /// @brief Set the protection settings of a page. /// @param pageNum Number of page to write. /// @param protection Protection to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code + /// @returns Computed page signature. + MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::Signature::array> computeAndReadPageAuthentication(int pageNum, bool anonymous, - Page::const_span challenge, - Core::Ecc256::Signature::span signature); + Page::const_span challenge) const; /// Decrement the decrement-only counter. - MaximInterfaceDevices_EXPORT Core::error_code decrementCounter(); + MaximInterfaceDevices_EXPORT Core::Result<void> decrementCounter(); /// Permanently disable the device. - MaximInterfaceDevices_EXPORT Core::error_code disableDevice(); + MaximInterfaceDevices_EXPORT Core::Result<void> disableDevice(); /// @brief Generate the device's ECDSA public key from the PUF private key. - /// @param[out] devicePublicKey Device Public Key - MaximInterfaceDevices_EXPORT Core::error_code - readDevicePublicKey(Core::Ecc256::PublicKey::span devicePublicKey); + /// @returns Device Public Key + MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::PublicKey::array> + readDevicePublicKey() const; /// @brief Read a block of random data from the RNG. /// @param[out] data Random data from RNG with length from 1 to 64. - MaximInterfaceDevices_EXPORT Core::error_code - readRng(Core::span<uint_least8_t> data); + MaximInterfaceDevices_EXPORT Core::Result<void> + readRng(Core::span<uint_least8_t> data) const; /// @brief /// Authenticate a public key for authenticated writes using the @@ -173,7 +174,7 @@ /// Certificate to use for authentication of the Write Public Key. /// @param customization /// Certificate customization with length from 1 to 32. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatePublicKey(Core::Ecc256::Signature::const_span certificate, Core::span<const uint_least8_t> customization); @@ -181,7 +182,7 @@ /// @param pageNum Number of page to write. /// @param page Data to write. /// @param signature Signature to use for authentication of page data. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatedWriteMemory(int pageNum, Page::const_span page, Core::Ecc256::Signature::const_span signature); @@ -189,27 +190,31 @@ errorCategory(); protected: - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<Core::span<uint_least8_t> > runCommand(Core::span<const uint_least8_t> request, int delayTime, - Core::span<uint_least8_t> & response); + Core::span<uint_least8_t> response) const; - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> runCommand(Core::span<const uint_least8_t> request, int delayTime); private: Core::RunCommand doRunCommand; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS28E39::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS28E39::ErrorValue e) { return Core::error_code(e, DS28E39::errorCategory()); } -/// @brief Read the device MAN ID using the Read Status command. -/// @param ds28e39 Device to read. -/// @param[out] manId Read MAN ID valid when operation is successful. -MaximInterfaceDevices_EXPORT Core::error_code -readManId(DS28E39 & ds28e39, Core::ManId::span manId); - /// Format page authentication input data. class DS28E39::PageAuthenticationData { public: @@ -329,13 +334,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index romIdIdx = 0; - static const index pageIdx = romIdIdx + Core::RomId::size; - static const index challengeIdx = pageIdx + Page::size; - static const index pageNumIdx = challengeIdx + Page::size; - static const index manIdIdx = pageNumIdx + 1; + static const size_t romIdIdx = 0; + static const size_t pageIdx = romIdIdx + Core::RomId::size; + static const size_t challengeIdx = pageIdx + Page::size; + static const size_t pageNumIdx = challengeIdx + Page::size; + static const size_t manIdIdx = pageNumIdx + 1; Result::array result_; };
--- a/MaximInterfaceDevices/DS28E83_DS28E84.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E83_DS28E84.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -39,6 +39,7 @@ using namespace Core; using std::copy; +using std::pair; static const int readMemoryTimeMs = 2; static const int writeMemoryTimeMs = 100; @@ -84,9 +85,9 @@ const int DS28E84::memoryPages; const int DS28E84::protectionBlocks; -error_code DS28E83_DS28E84::writeMemory(int pageNum, Page::const_span page) { +Result<void> DS28E83_DS28E84::writeMemory(int pageNum, Page::const_span page) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size]; @@ -96,28 +97,30 @@ return runCommand(request, writeMemoryTimeMs); } -error_code DS28E83_DS28E84::readMemory(int pageNum, Page::span page) { +Result<DS28E83_DS28E84::Page::array> +DS28E83_DS28E84::readMemory(int pageNum) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + Page::size]; buffer[0] = 0x44; buffer[1] = pageNum; - span<uint_least8_t> response(buffer); - const error_code result = - runCommand(make_span(buffer, 2), readMemoryTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), page.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer); + if (!response) { + return response.error(); } - return result; + Page::array page; + copy(response.value().begin(), response.value().end(), page.begin()); + return page; } -error_code DS28E83_DS28E84::encryptedReadMemory( - int pageNum, KeySecret secret, - EncryptionChallenge::span encryptionChallenge, Page::span encryptedPage) { +Result<pair<DS28E83_DS28E84::EncryptionChallenge::array, + DS28E83_DS28E84::Page::array> > +DS28E83_DS28E84::encryptedReadMemory(int pageNum, KeySecret secret) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 3; @@ -126,27 +129,27 @@ buffer[0] = 0x4B; buffer[1] = pageNum; buffer[2] = secret; - span<uint_least8_t> response(buffer, responseSize); - const error_code result = - runCommand(make_span(buffer, requestSize), - readMemoryTimeMs + computeTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = - begin + encryptionChallenge.size(); - copy(begin, end, encryptionChallenge.begin()); - begin = end; - end = begin + encryptedPage.size(); - copy(begin, end, encryptedPage.begin()); + const Result<span<uint_least8_t> > response = runCommand( + make_span(buffer, requestSize), readMemoryTimeMs + computeTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + pair<EncryptionChallenge::array, Page::array> data; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + data.first.size(); + copy(begin, end, data.first.begin()); + begin = end; + end = begin + data.second.size(); + copy(begin, end, data.second.begin()); + return data; } -error_code DS28E83_DS28E84::readBlockProtection(int blockNumber, - Optional<KeySecret> & keySecret, - BlockProtection & protection) { +Result<pair<Optional<DS28E83_DS28E84::KeySecret>, + DS28E83_DS28E84::BlockProtection> > +DS28E83_DS28E84::readBlockProtection(int blockNumber) const { if (blockNumber < 0 || blockNumber >= protectionBlocks) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 2; @@ -154,40 +157,41 @@ uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)]; buffer[0] = 0xAA; buffer[1] = blockNumber; - span<uint_least8_t> response(buffer, responseSize); - const error_code result = - runCommand(make_span(buffer, requestSize), readMemoryTimeMs, response); - if (result) { - return result; + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), readMemoryTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - if ((response[0] & 0x3F) != blockNumber) { - return make_error_code(InvalidResponseError); + if ((response.value()[0] & 0x3F) != blockNumber) { + return InvalidResponseError; } - switch (response[0] >> 6) { + pair<Optional<KeySecret>, BlockProtection> data; + switch (response.value()[0] >> 6) { case 0: - keySecret = none; + data.first = none; break; case 1: - keySecret = KeySecretA; + data.first = KeySecretA; break; case 2: - keySecret = KeySecretB; + data.first = KeySecretB; break; default: - return make_error_code(InvalidResponseError); + return InvalidResponseError; } - if ((response[1] & 0x20) != 0) { - return make_error_code(InvalidResponseError); + if ((response.value()[1] & 0x20) != 0) { + return InvalidResponseError; } - protection = response[1]; - return error_code(); + data.second = response.value()[1]; + return data; } -error_code +Result<void> DS28E83_DS28E84::setBlockProtection(int blockNum, KeySecret keySecret, const BlockProtection & protection) { if (blockNum < 0 || blockNum >= protectionBlocks || keySecret == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t request[] = { @@ -198,11 +202,11 @@ return runCommand(request, writeStateTimeMs); } -error_code DS28E83_DS28E84::computeAndReadPageAuthentication( - int pageNum, KeySecret key, Page::const_span challenge, - Ecc256::Signature::span signature) { +Result<Ecc256::Signature::array> +DS28E83_DS28E84::computeAndReadEcdsaPageAuthentication( + int pageNum, KeySecret key, Page::const_span challenge) const { if (pageNum < 0 || pageNum >= memoryPages || key == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 3 + Page::size; @@ -212,26 +216,27 @@ buffer[1] = pageNum; buffer[2] = key + 3; copy(challenge.begin(), challenge.end(), buffer + 3); - span<uint_least8_t> response(buffer, responseSize); - const error_code result = runCommand(make_span(buffer, requestSize), - generateEcdsaSignatureTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = begin + signature.s.size(); - copy(begin, end, signature.s.begin()); - begin = end; - end = begin + signature.r.size(); - copy(begin, end, signature.r.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + Ecc256::Signature::array signature; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + signature.s.size(); + copy(begin, end, signature.s.begin()); + begin = end; + end = begin + signature.r.size(); + copy(begin, end, signature.r.begin()); + return signature; } -error_code -DS28E83_DS28E84::computeAndReadPageAuthentication(int pageNum, KeySecret secret, - Page::const_span challenge, - Page::span hmac) { +Result<DS28E83_DS28E84::Page::array> +DS28E83_DS28E84::computeAndReadSha256PageAuthentication( + int pageNum, KeySecret secret, Page::const_span challenge) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 3 + Page::size; @@ -241,22 +246,24 @@ buffer[1] = pageNum; buffer[2] = secret; copy(challenge.begin(), challenge.end(), buffer + 3); - span<uint_least8_t> response(buffer, responseSize); - const error_code result = - runCommand(make_span(buffer, requestSize), computeTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), hmac.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), computeTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + Page::array hmac; + copy(response.value().begin(), response.value().end(), hmac.begin()); + return hmac; } -error_code +Result<void> DS28E83_DS28E84::computeMultiblockHash(bool firstBlock, bool lastBlock, span<const uint_least8_t> data) { const span<const uint_least8_t>::index_type maxDataSize = 64; if (data.size() < 1 || data.size() > maxDataSize) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[2 + maxDataSize]; @@ -272,21 +279,21 @@ return runCommand(make_span(buffer, 2 + data.size()), computeTimeMs); } -error_code DS28E83_DS28E84::verifyEcdsaSignature( +Result<void> DS28E83_DS28E84::verifyEcdsaSignature( KeySecret key, bool authorityKey, GpioState gpioState, Ecc256::Signature::const_span signature, span<const uint_least8_t> data) { return verifyEcdsaSignature(key, authorityKey, DataInput, gpioState, signature, data); } -error_code DS28E83_DS28E84::verifyEcdsaSignature( +Result<void> DS28E83_DS28E84::verifyEcdsaSignature( KeySecret key, bool authorityKey, GpioState gpioState, Ecc256::Signature::const_span signature, Page::const_span hash) { return verifyEcdsaSignature(key, authorityKey, HashInput, gpioState, signature, hash); } -error_code +Result<void> DS28E83_DS28E84::verifyEcdsaSignature(KeySecret key, bool authorityKey, GpioState gpioState, Ecc256::Signature::const_span signature) { @@ -294,13 +301,13 @@ span<const uint_least8_t>()); } -error_code DS28E83_DS28E84::verifyEcdsaSignature( +Result<void> DS28E83_DS28E84::verifyEcdsaSignature( KeySecret key, bool authorityKey, HashType hashType, GpioState gpioState, Ecc256::Signature::const_span signature, span<const uint_least8_t> buffer) { const span<const uint_least8_t>::index_type maxBufferSize = 61; if (buffer.size() > maxBufferSize) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + 2 * Ecc256::Scalar::size + maxBufferSize]; @@ -328,7 +335,7 @@ } // else: Go to default case. default: - return make_error_code(InvalidParameterError); + return InvalidParameterError; } *requestIt |= hashType << 3; if (gpioState != Unchanged) { @@ -345,13 +352,13 @@ (hashType == DataInput ? computeTimeMs : 0)); } -error_code DS28E83_DS28E84::authenticateEcdsaPublicKey( +Result<void> DS28E83_DS28E84::authenticateEcdsaPublicKey( KeySecret key, Ecc256::Signature::const_span cert, span<const uint_least8_t> certCustomization) { return authenticateEcdsaPublicKey(key, true, cert, certCustomization, NULL); } -error_code DS28E83_DS28E84::authenticateEcdsaPublicKey( +Result<void> DS28E83_DS28E84::authenticateEcdsaPublicKey( KeySecret key, bool authWrites, Ecc256::Signature::const_span cert, span<const uint_least8_t> certCustomization, span<const uint_least8_t> ecdhCustomization) { @@ -359,7 +366,7 @@ &ecdhCustomization); } -error_code DS28E83_DS28E84::authenticateEcdsaPublicKey( +Result<void> DS28E83_DS28E84::authenticateEcdsaPublicKey( KeySecret key, bool authWrites, Ecc256::Signature::const_span cert, span<const uint_least8_t> certCustomization, const span<const uint_least8_t> * ecdhCustomization) { @@ -375,11 +382,11 @@ ecdhCustomization->size() <= maxEcdhCustomizationSize && certCustomization.size() + ecdhCustomization->size() <= maxTotalCustomizationSize)))) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } if (key == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t @@ -406,14 +413,14 @@ return runCommand(make_span(request, requestIt), delay); } -error_code DS28E83_DS28E84::authenticatedEcdsaWriteMemory( +Result<void> DS28E83_DS28E84::authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Ecc256::Signature::const_span signature) { return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature, NULL); } -error_code DS28E83_DS28E84::authenticatedEcdsaWriteMemory( +Result<void> DS28E83_DS28E84::authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Ecc256::Signature::const_span signature, EncryptionChallenge::const_span challenge) { @@ -421,12 +428,12 @@ &challenge); } -error_code DS28E83_DS28E84::authenticatedEcdsaWriteMemory( +Result<void> DS28E83_DS28E84::authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Ecc256::Signature::const_span signature, const EncryptionChallenge::const_span * challenge) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size + @@ -448,7 +455,7 @@ return runCommand(make_span(request, requestIt), delay); } -error_code +Result<void> DS28E83_DS28E84::authenticatedSha256WriteMemory(int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac) { @@ -456,18 +463,18 @@ NULL); } -error_code DS28E83_DS28E84::authenticatedSha256WriteMemory( +Result<void> DS28E83_DS28E84::authenticatedSha256WriteMemory( int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac, EncryptionChallenge::const_span challenge) { return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac, &challenge); } -error_code DS28E83_DS28E84::authenticatedSha256WriteMemory( +Result<void> DS28E83_DS28E84::authenticatedSha256WriteMemory( int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac, const EncryptionChallenge::const_span * challenge) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[3 + 2 * Page::size + EncryptionChallenge::size]; @@ -485,11 +492,11 @@ return runCommand(make_span(request, requestIt), delay); } -error_code DS28E83_DS28E84::computeAndWriteSha256Secret( +Result<void> DS28E83_DS28E84::computeAndWriteSha256Secret( int pageNum, KeySecret masterSecret, KeySecret destinationSecret, Page::const_span partialSecret) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[3 + Page::size]; @@ -500,76 +507,73 @@ return runCommand(request, writeMemoryTimeMs + computeTimeMs); } -error_code DS28E83_DS28E84::generateEcc256KeyPair(KeySecret key) { +Result<void> DS28E83_DS28E84::generateEcc256KeyPair(KeySecret key) { if (key == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t request[] = {0xCB, key == KeySecretB}; return runCommand(request, generateEccKeyPairTimeMs); } -error_code DS28E83_DS28E84::readRng(span<uint_least8_t> data) { +Result<void> DS28E83_DS28E84::readRng(span<uint_least8_t> data) const { const span<uint_least8_t>::index_type maxDataSize = 64; if ((data.size() < 1) || (data.size() > maxDataSize)) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + maxDataSize]; buffer[0] = readRngCmd; buffer[1] = static_cast<uint_least8_t>(data.size() - 1); - span<uint_least8_t> response(buffer, 1 + data.size()); - const error_code result = - runCommand(make_span(buffer, 2), trngGenerationTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), data.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), trngGenerationTimeMs, + make_span(buffer, 1 + data.size())); + if (!response) { + return response.error(); } - return result; + copy(response.value().begin(), response.value().end(), data.begin()); + return none; } -error_code DS28E83_DS28E84::entropyHealthTest() { +Result<void> DS28E83_DS28E84::entropyHealthTest() const { const uint_least8_t request[] = {readRngCmd, 0x80}; return runCommand(request, trngOnDemandCheckTimeMs); } -error_code DS28E83_DS28E84::runCommand(span<const uint_least8_t> request, - int delayTime, - span<uint_least8_t> & response) { - const span<const uint_least8_t>::index_type responseInputSize = - response.size(); - error_code result = doRunCommand(request, delayTime, response); - if (result) { - return result; +Result<span<uint_least8_t> > +DS28E83_DS28E84::runCommand(span<const uint_least8_t> request, int delayTime, + span<uint_least8_t> response) const { + const Result<span<uint_least8_t> > responseOutput = + doRunCommand(request, delayTime, response); + if (!responseOutput) { + return responseOutput; } - if (response.empty()) { - return make_error_code(InvalidResponseError); + if (responseOutput.value().empty()) { + return InvalidResponseError; } // Parse command result byte. - switch (response[0]) { + switch (responseOutput.value().front()) { case 0xAA: // Success response. - if (response.size() != responseInputSize) { - result = make_error_code(InvalidResponseError); - } break; case 0x00: - result = make_error_code(AuthenticationError); - break; + return AuthenticationError; default: - result.assign(response[0], errorCategory()); - break; + return error_code(responseOutput.value().front(), errorCategory()); } - response = response.subspan(1); - return result; + if (responseOutput.value().size() != response.size()) { + return InvalidResponseError; + } + return responseOutput.value().subspan(1); } -error_code DS28E83_DS28E84::runCommand(span<const uint_least8_t> request, - int delayTime) { +Result<void> DS28E83_DS28E84::runCommand(span<const uint_least8_t> request, + int delayTime) const { uint_least8_t buffer; - span<uint_least8_t> response(&buffer, 1); - return runCommand(request, delayTime, response); + MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1))); + return none; } const error_category & DS28E83_DS28E84::errorCategory() { @@ -606,43 +610,30 @@ return instance; } -error_code DS28E84::decrementCounter() { +Result<void> DS28E84::decrementCounter() { const uint_least8_t request = 0xC9; return runCommand(make_span(&request, 1), writeMemoryTimeMs); } -error_code DS28E84::deviceStateControl(StateOperation operation) { +Result<void> DS28E84::deviceStateControl(StateOperation operation) { const uint_least8_t request[] = {0x55, operation == Backup}; return runCommand(request, writeMemoryTimeMs); } -error_code computeMultiblockHash(DS28E83_DS28E84 & device, - span<const uint_least8_t> data) { - error_code result; +Result<void> computeMultiblockHash(DS28E83_DS28E84 & device, + span<const uint_least8_t> data) { span<const uint_least8_t>::index_type dataIdx = 0; - while (dataIdx < data.size() && !result) { + while (dataIdx < data.size()) { const span<const uint_least8_t>::index_type remainingSize = data.size() - dataIdx; const span<const uint_least8_t>::index_type chunkSize = std::min<span<const uint_least8_t>::index_type>(remainingSize, 64); - result = + MaximInterfaceCore_TRY( device.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize, - data.subspan(dataIdx, chunkSize)); + data.subspan(dataIdx, chunkSize))); dataIdx += chunkSize; } - return result; -} - -error_code readRomIdAndManId(DS28E83_DS28E84 & device, RomId::span romId, - ManId::span manId) { - DS28E83_DS28E84::Page::array page; - error_code result = device.readMemory(DS28E83_DS28E84::romOptionsPage, page); - if (!result) { - const DS28E83_DS28E84::RomOptions romOptions(page); - copy(romOptions.romId(), romId); - copy(romOptions.manId(), manId); - } - return result; + return none; } static void setAnonymous(RomId::span romId) {
--- a/MaximInterfaceDevices/DS28E83_DS28E84.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28E83_DS28E84.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,10 +30,11 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS28E83_DS28E84 -#define MaximInterfaceDevices_DS28E83_DS28E84 +#ifndef MaximInterfaceDevices_DS28E83_DS28E84_hpp +#define MaximInterfaceDevices_DS28E83_DS28E84_hpp #include <stdint.h> +#include <utility> #include <MaximInterfaceCore/Algorithm.hpp> #include <MaximInterfaceCore/array_span.hpp> #include <MaximInterfaceCore/Ecc256.hpp> @@ -141,38 +142,35 @@ /// @brief Write memory with no protection. /// @param pageNum Number of page to write. /// @param page Data to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> 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. - MaximInterfaceDevices_EXPORT Core::error_code readMemory(int pageNum, - Page::span page); + /// @returns Data that was read. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + readMemory(int pageNum) const; /// @brief Read memory with encryption. /// @param pageNum Number of page to read from. /// @param secret Secret to use for encryption. - /// @param[out] challenge Encryption challenge that was read. - /// @param[out] encryptedPage Encrypted page data that was read. - MaximInterfaceDevices_EXPORT Core::error_code - encryptedReadMemory(int pageNum, KeySecret secret, - EncryptionChallenge::span challenge, - Page::span encryptedPage); + /// @returns Encryption challenge and encrypted page data that was read. + MaximInterfaceDevices_EXPORT + Core::Result<std::pair<EncryptionChallenge::array, Page::array> > + encryptedReadMemory(int pageNum, KeySecret secret) const; /// @brief Read the protection settings of a block. /// @param blockNum Number of block to read. - /// @param[out] keySecret Secret key set on the block or empty if not set. - /// @param[out] protection Protection that was read. - MaximInterfaceDevices_EXPORT Core::error_code - readBlockProtection(int blockNum, Core::Optional<KeySecret> & keySecret, - BlockProtection & protection); + /// @returns Secret/Key and protection set on the block. + MaximInterfaceDevices_EXPORT + Core::Result<std::pair<Core::Optional<KeySecret>, BlockProtection> > + readBlockProtection(int blockNum) const; /// @brief Set the protection settings of a block. /// @param blockNum Number of block to write. /// @param keySecret Secret/Key A or B. /// @param protection Protection to write. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> setBlockProtection(int blockNum, KeySecret keySecret, const BlockProtection & protection); @@ -182,11 +180,10 @@ /// Private key to use for authentication. /// Key S cannot be used with this command. /// @param challenge Random challenge used to prevent replay attacks. - /// @param[out] signature Computed page signature. - MaximInterfaceDevices_EXPORT Core::error_code - computeAndReadPageAuthentication(int pageNum, KeySecret key, - Page::const_span challenge, - Core::Ecc256::Signature::span signature); + /// @returns Computed page signature. + MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::Signature::array> + computeAndReadEcdsaPageAuthentication(int pageNum, KeySecret key, + Page::const_span challenge) const; /// @brief Compute and read page authentication with HMAC. /// @param pageNum Number of page to authenticate. @@ -194,17 +191,17 @@ /// Secret to use for authentication. /// Secret S cannot be used with this command. /// @param challenge Random challenge used to prevent replay attacks. - /// @param[out] hmac Computed page HMAC. - MaximInterfaceDevices_EXPORT Core::error_code - computeAndReadPageAuthentication(int pageNum, KeySecret secret, - Page::const_span challenge, Page::span hmac); + /// @returns Computed page HMAC. + MaximInterfaceDevices_EXPORT Core::Result<Page::array> + computeAndReadSha256PageAuthentication(int pageNum, KeySecret secret, + Page::const_span challenge) const; /// @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. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeMultiblockHash(bool firstBlock, bool lastBlock, Core::span<const uint_least8_t> data); @@ -214,7 +211,7 @@ /// @param gpioState New state of the GPIO pin if verification successful. /// @param signature Signature to verify. /// @param data Data to verify with length from 1 to 64. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> verifyEcdsaSignature(KeySecret key, bool authorityKey, GpioState gpioState, Core::Ecc256::Signature::const_span signature, Core::span<const uint_least8_t> data); @@ -225,7 +222,7 @@ /// @param gpioState New state of the GPIO pin if verification successful. /// @param signature Signature to verify. /// @param hash Hash of data to verify. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> verifyEcdsaSignature(KeySecret key, bool authorityKey, GpioState gpioState, Core::Ecc256::Signature::const_span signature, Page::const_span hash); @@ -236,7 +233,7 @@ /// @param authorityKey Use the authority key instead of the standard key. /// @param gpioState New state of the GPIO pin if verification successful. /// @param signature Signature to verify. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> verifyEcdsaSignature(KeySecret key, bool authorityKey, GpioState gpioState, Core::Ecc256::Signature::const_span signature); @@ -246,7 +243,7 @@ /// @param cert Certificate to use for authentication of Public Key S. /// @param certCustomization /// Certificate customization with length from 1 to 32. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticateEcdsaPublicKey(KeySecret key, Core::Ecc256::Signature::const_span cert, Core::span<const uint_least8_t> certCustomization); @@ -262,7 +259,7 @@ /// Certificate customization with length from 1 to 32. /// @param ecdhCustomization ECDH customization with length from 1 to 48. /// @note The maximum total customization length is 60 bytes. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticateEcdsaPublicKey(KeySecret key, bool authWrites, Core::Ecc256::Signature::const_span cert, Core::span<const uint_least8_t> certCustomization, @@ -274,7 +271,7 @@ /// Use Public Key S instead of the authority key set in the block protection. /// @param newPageData Data to write. /// @param signature Signature to use for authentication of page data. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatedEcdsaWriteMemory(int pageNum, bool useKeyS, Page::const_span newPageData, Core::Ecc256::Signature::const_span signature); @@ -286,7 +283,7 @@ /// @param newPageData Encrypted data to write. /// @param signature Signature to use for authentication of page data. /// @param challenge Challenge to use for decryption of page data. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatedEcdsaWriteMemory(int pageNum, bool useKeyS, Page::const_span newPageData, Core::Ecc256::Signature::const_span signature, @@ -298,7 +295,7 @@ /// Use Secret S instead of the secret set in the block protection. /// @param newPageData Data to write. /// @param hmac HMAC to use for authentication of page data. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> authenticatedSha256WriteMemory(int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac); @@ -310,9 +307,11 @@ /// @param newPageData Data to write. /// @param hmac HMAC to use for authentication of page data. /// @param challenge Challenge to use for decryption of page data. - MaximInterfaceDevices_EXPORT Core::error_code authenticatedSha256WriteMemory( - int pageNum, bool useSecretS, Page::const_span newPageData, - Page::const_span hmac, EncryptionChallenge::const_span challenge); + MaximInterfaceDevices_EXPORT Core::Result<void> + authenticatedSha256WriteMemory(int pageNum, bool useSecretS, + Page::const_span newPageData, + Page::const_span hmac, + EncryptionChallenge::const_span challenge); /// @brief Compute a derivative SHA-256 secret from an existing secret. /// @param pageNum Number of page to use in computation. @@ -320,61 +319,71 @@ /// @param destinationSecret /// Destination secret to receive the computation result. /// @param partialSecret Partial secret to use in computation. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> computeAndWriteSha256Secret(int pageNum, KeySecret masterSecret, KeySecret destinationSecret, Page::const_span partialSecret); /// @brief Generate a new ECDSA key pair. /// @param key Key to generate. Key S cannot be used with this command. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> generateEcc256KeyPair(KeySecret key); /// @brief Read a block of random data from the RNG. /// @param[out] data Random data from RNG with length from 1 to 64. - MaximInterfaceDevices_EXPORT Core::error_code - readRng(Core::span<uint_least8_t> data); + MaximInterfaceDevices_EXPORT Core::Result<void> + readRng(Core::span<uint_least8_t> data) const; /// Run entropy health test on the RNG. - MaximInterfaceDevices_EXPORT Core::error_code entropyHealthTest(); + MaximInterfaceDevices_EXPORT Core::Result<void> entropyHealthTest() const; MaximInterfaceDevices_EXPORT static const Core::error_category & errorCategory(); protected: - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<Core::span<uint_least8_t> > runCommand(Core::span<const uint_least8_t> request, int delayTime, - Core::span<uint_least8_t> & response); + Core::span<uint_least8_t> response) const; - MaximInterfaceDevices_EXPORT Core::error_code - runCommand(Core::span<const uint_least8_t> request, int delayTime); + MaximInterfaceDevices_EXPORT Core::Result<void> + runCommand(Core::span<const uint_least8_t> request, int delayTime) const; private: enum HashType { HashInput, DataInput, THASH }; - Core::error_code + Core::Result<void> verifyEcdsaSignature(KeySecret key, bool authorityKey, HashType hashType, GpioState gpioState, Core::Ecc256::Signature::const_span signature, Core::span<const uint_least8_t> buffer); - Core::error_code authenticateEcdsaPublicKey( + Core::Result<void> authenticateEcdsaPublicKey( KeySecret key, bool authWrites, Core::Ecc256::Signature::const_span cert, Core::span<const uint_least8_t> certCustomization, const Core::span<const uint_least8_t> * ecdhCustomization); - Core::error_code authenticatedEcdsaWriteMemory( + Core::Result<void> authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Core::Ecc256::Signature::const_span signature, const EncryptionChallenge::const_span * challenge); - Core::error_code authenticatedSha256WriteMemory( + Core::Result<void> authenticatedSha256WriteMemory( int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac, const EncryptionChallenge::const_span * challenge); Core::RunCommand doRunCommand; }; +} // namespace MaximInterfaceDevices +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceDevices::DS28E83_DS28E84::ErrorValue> + : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceDevices { + inline Core::error_code make_error_code(DS28E83_DS28E84::ErrorValue e) { return Core::error_code(e, DS28E83_DS28E84::errorCategory()); } @@ -402,16 +411,16 @@ static const int memoryPages = 107; static const int protectionBlocks = 24; - enum StateOperation { Backup, Restore }; + enum StateOperation { Restore, Backup }; explicit DS28E84(const Core::RunCommand & runCommand) : DS28E83_DS28E84(runCommand) {} /// Decrement the decrement-only counter. - MaximInterfaceDevices_EXPORT Core::error_code decrementCounter(); + MaximInterfaceDevices_EXPORT Core::Result<void> decrementCounter(); /// Back up or restore the state of the device to non-volatile memory. - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> deviceStateControl(StateOperation operation); }; @@ -419,20 +428,10 @@ /// Hash arbitrary length data with successive Compute Multiblock Hash commands. /// @param device Device for computation. /// @param data Data to hash. -MaximInterfaceDevices_EXPORT Core::error_code +MaximInterfaceDevices_EXPORT Core::Result<void> computeMultiblockHash(DS28E83_DS28E84 & device, Core::span<const uint_least8_t> data); -/// @brief -/// Read the device ROM ID and MAN ID using the Read Memory command on the -/// ROM Options page. -/// @param device 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. -MaximInterfaceDevices_EXPORT Core::error_code -readRomIdAndManId(DS28E83_DS28E84 & device, Core::RomId::span romId, - Core::ManId::span manId); - /// Format page authentication input data. class DS28E83_DS28E84::PageAuthenticationData { public: @@ -552,13 +551,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index romIdIdx = 0; - static const index pageIdx = romIdIdx + Core::RomId::size; - static const index challengeIdx = pageIdx + Page::size; - static const index pageNumIdx = challengeIdx + Page::size; - static const index manIdIdx = pageNumIdx + 1; + static const size_t romIdIdx = 0; + static const size_t pageIdx = romIdIdx + Core::RomId::size; + static const size_t challengeIdx = pageIdx + Page::size; + static const size_t pageNumIdx = challengeIdx + Page::size; + static const size_t manIdIdx = pageNumIdx + 1; Result::array result_; }; @@ -866,13 +863,11 @@ /// @} private: - typedef Result::span::index_type index; - - static const index encryptionChallengeIdx = 0; - static const index romIdIdx = + static const size_t encryptionChallengeIdx = 0; + static const size_t romIdIdx = encryptionChallengeIdx + EncryptionChallenge::size; - static const index pageNumIdx = romIdIdx + Core::RomId::size; - static const index manIdIdx = pageNumIdx + 1; + static const size_t pageNumIdx = romIdIdx + Core::RomId::size; + static const size_t manIdIdx = pageNumIdx + 1; Result::array result_; };
--- a/MaximInterfaceDevices/DS9400.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS9400.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -32,58 +32,46 @@ #include "DS9400.hpp" +#define TRY MaximInterfaceCore_TRY +#define TRY_VALUE MaximInterfaceCore_TRY_VALUE + namespace MaximInterfaceDevices { using namespace Core; -error_code DS9400::waitAwake() { - error_code result; +Result<void> DS9400::waitAwake() { uint_least8_t data; do { - result = uart->readByte(data); - } while (!result && data != 0xA5); - return result; + TRY_VALUE(data, uart->readByte()); + } while (data != 0xA5); + return none; } -error_code DS9400::start() { return uart->writeByte('S'); } +Result<void> DS9400::start() { return uart->writeByte('S'); } -error_code DS9400::start(uint_least8_t address) { - error_code result = start(); - if (!result) { - result = writeByte(address); - } - return result; +Result<void> DS9400::start(uint_least8_t address) { + TRY(start()); + TRY(writeByte(address)); + return none; } -error_code DS9400::stop() { return uart->writeByte('P'); } +Result<void> DS9400::stop() { return uart->writeByte('P'); } -error_code DS9400::writeByte(uint_least8_t data) { +Result<void> DS9400::writeByte(uint_least8_t data) { const uint_least8_t packet[] = {'Q', data}; - error_code result = uart->clearReadBuffer(); - if (!result) { - result = uart->writeBlock(packet); - if (!result) { - result = uart->readByte(data); - if (!result && data != 0) { - result = make_error_code(I2CMaster::NackError); - } - } - } - return result; + TRY(uart->clearReadBuffer()); + TRY(uart->writeBlock(packet)); + TRY_VALUE(data, uart->readByte()); + return (data == 0) ? makeResult(none) : I2CMaster::NackError; } -error_code DS9400::readByte(AckStatus status, uint_least8_t & data) { - error_code result = uart->clearReadBuffer(); - if (!result) { - result = uart->writeByte(status == Ack ? 'R' : 'N'); - if (!result) { - result = uart->readByte(data); - } - } - return result; +Result<uint_least8_t> DS9400::readByte(DoAck doAck) { + TRY(uart->clearReadBuffer()); + TRY(uart->writeByte(doAck == Ack ? 'R' : 'N')); + return uart->readByte(); } -error_code DS9400::configure(uint_least8_t config) { +Result<void> DS9400::configure(uint_least8_t config) { const uint_least8_t packet[] = {'C', config}; return uart->writeBlock(packet); }
--- a/MaximInterfaceDevices/DS9400.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS9400.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS9400 -#define MaximInterfaceDevices_DS9400 +#ifndef MaximInterfaceDevices_DS9400_hpp +#define MaximInterfaceDevices_DS9400_hpp #include <MaximInterfaceCore/I2CMaster.hpp> #include <MaximInterfaceCore/Uart.hpp> @@ -45,23 +45,24 @@ void setUart(Core::Uart & uart) { this->uart = &uart; } - MaximInterfaceDevices_EXPORT Core::error_code waitAwake(); + MaximInterfaceDevices_EXPORT Core::Result<void> waitAwake(); - MaximInterfaceDevices_EXPORT Core::error_code start(); + MaximInterfaceDevices_EXPORT Core::Result<void> start(); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> start(uint_least8_t address); - MaximInterfaceDevices_EXPORT virtual Core::error_code stop(); + MaximInterfaceDevices_EXPORT virtual Core::Result<void> stop(); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> writeByte(uint_least8_t data); - MaximInterfaceDevices_EXPORT virtual Core::error_code - readByte(AckStatus status, uint_least8_t & data); + MaximInterfaceDevices_EXPORT virtual Core::Result<uint_least8_t> + readByte(DoAck doAck); protected: - MaximInterfaceDevices_EXPORT Core::error_code configure(uint_least8_t config); + MaximInterfaceDevices_EXPORT Core::Result<void> + configure(uint_least8_t config); private: Core::Uart * uart;
--- a/MaximInterfaceDevices/DS9481P_300.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS9481P_300.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -33,6 +33,8 @@ #include <MaximInterfaceCore/Error.hpp> #include "DS9481P_300.hpp" +#define TRY MaximInterfaceCore_TRY + namespace MaximInterfaceDevices { using namespace Core; @@ -41,209 +43,149 @@ : serialPort(&serialPort), currentBus(OneWire), ds2480b(sleep, serialPort), oneWireMaster_(*this), ds9400(serialPort), i2cMaster_(*this) {} -error_code DS9481P_300::connect(const std::string & portName) { - error_code result = serialPort->connect(portName); - if (!result) { +Result<void> DS9481P_300::connect(const std::string & portName) { + Result<void> result = serialPort->connect(portName); + if (result) { result = selectOneWire(); if (result) { - serialPort->disconnect(); + currentBus = OneWire; } else { - currentBus = OneWire; - } - } - return result; -} - -error_code DS9481P_300::disconnect() { return serialPort->disconnect(); } - -bool DS9481P_300::connected() const { return serialPort->connected(); } - -std::string DS9481P_300::portName() const { return serialPort->portName(); } - -error_code DS9481P_300::selectOneWire() { - // Escape DS9400 mode. - error_code result = ds9400.escape(); - if (!result) { - result = ds2480b.initialize(); - } - return result; -} - -error_code DS9481P_300::selectBus(Bus newBus) { - error_code result; - if (currentBus != newBus) { - switch (currentBus) { - case OneWire: // Next bus I2C. - // Escape DS2480 Mode. - result = ds2480b.escape(); - if (!result) { - // Wait for awake notification. - result = ds9400.waitAwake(); - } - break; - - case I2C: // Next bus OneWire. - result = selectOneWire(); - break; - } - if (!result) { - currentBus = newBus; + serialPort->disconnect(); } } return result; } -error_code DS9481P_300::OneWireMaster::reset() { - error_code result = parent->selectBus(OneWire); - if (!result) { - result = OneWireMasterDecorator::reset(); - } - return result; +Result<void> DS9481P_300::disconnect() { return serialPort->disconnect(); } + +Result<void> DS9481P_300::selectOneWire() { + // Escape DS9400 mode. + TRY(ds9400.escape()); + TRY(ds2480b.initialize()); + return none; } -error_code DS9481P_300::OneWireMaster::touchBitSetLevel(bool & sendRecvBit, - Level afterLevel) { - error_code result = parent->selectBus(OneWire); - if (!result) { - result = OneWireMasterDecorator::touchBitSetLevel(sendRecvBit, afterLevel); +Result<void> DS9481P_300::selectBus(Bus newBus) { + if (currentBus != newBus) { + switch (currentBus) { + case OneWire: // Next bus I2C. + // Escape DS2480 Mode. + TRY(ds2480b.escape()); + // Wait for awake notification. + TRY(ds9400.waitAwake()); + break; + + case I2C: // Next bus OneWire. + TRY(selectOneWire()); + break; + } + currentBus = newBus; } - return result; -} - -error_code DS9481P_300::OneWireMaster::writeByteSetLevel(uint_least8_t sendByte, - Level afterLevel) { - error_code result = parent->selectBus(OneWire); - if (!result) { - result = OneWireMasterDecorator::writeByteSetLevel(sendByte, afterLevel); - } - return result; + return none; } -error_code -DS9481P_300::OneWireMaster::readByteSetLevel(uint_least8_t & recvByte, - Level afterLevel) { - error_code result = parent->selectBus(OneWire); - if (!result) { - result = OneWireMasterDecorator::readByteSetLevel(recvByte, afterLevel); - } - return result; +Result<void> DS9481P_300::OneWireMaster::reset() { + TRY(parent->selectBus(OneWire)); + return OneWireMasterDecorator::reset(); } -error_code -DS9481P_300::OneWireMaster::writeBlock(span<const uint_least8_t> sendBuf) { - error_code result = parent->selectBus(OneWire); - if (!result) { - result = OneWireMasterDecorator::writeBlock(sendBuf); - } - return result; +Result<bool> DS9481P_300::OneWireMaster::touchBitSetLevel(bool sendBit, + Level afterLevel) { + TRY(parent->selectBus(OneWire)); + return OneWireMasterDecorator::touchBitSetLevel(sendBit, afterLevel); } -error_code DS9481P_300::OneWireMaster::readBlock(span<uint_least8_t> recvBuf) { - error_code result = parent->selectBus(OneWire); - if (!result) { - result = OneWireMasterDecorator::readBlock(recvBuf); - } - return result; +Result<void> +DS9481P_300::OneWireMaster::writeByteSetLevel(uint_least8_t sendByte, + Level afterLevel) { + TRY(parent->selectBus(OneWire)); + return OneWireMasterDecorator::writeByteSetLevel(sendByte, afterLevel); } -error_code DS9481P_300::OneWireMaster::setSpeed(Speed newSpeed) { - error_code result = parent->selectBus(OneWire); - if (!result) { - result = OneWireMasterDecorator::setSpeed(newSpeed); - } - return result; +Result<uint_least8_t> +DS9481P_300::OneWireMaster::readByteSetLevel(Level afterLevel) { + TRY(parent->selectBus(OneWire)); + return OneWireMasterDecorator::readByteSetLevel(afterLevel); } -error_code DS9481P_300::OneWireMaster::setLevel(Level newLevel) { - error_code result = parent->selectBus(OneWire); - if (!result) { - result = OneWireMasterDecorator::setLevel(newLevel); - } - return result; +Result<void> +DS9481P_300::OneWireMaster::writeBlock(span<const uint_least8_t> sendBuf) { + TRY(parent->selectBus(OneWire)); + return OneWireMasterDecorator::writeBlock(sendBuf); +} + +Result<void> +DS9481P_300::OneWireMaster::readBlock(span<uint_least8_t> recvBuf) { + TRY(parent->selectBus(OneWire)); + return OneWireMasterDecorator::readBlock(recvBuf); } -error_code DS9481P_300::OneWireMaster::triplet(TripletData & data) { - error_code result = parent->selectBus(OneWire); - if (!result) { - result = OneWireMasterDecorator::triplet(data); - } - return result; +Result<void> DS9481P_300::OneWireMaster::setSpeed(Speed newSpeed) { + TRY(parent->selectBus(OneWire)); + return OneWireMasterDecorator::setSpeed(newSpeed); } -error_code DS9481P_300::I2CMaster::start(uint_least8_t address) { - error_code result = parent->selectBus(I2C); - if (!result) { - result = I2CMasterDecorator::start(address); - } - return result; +Result<void> DS9481P_300::OneWireMaster::setLevel(Level newLevel) { + TRY(parent->selectBus(OneWire)); + return OneWireMasterDecorator::setLevel(newLevel); } -error_code DS9481P_300::I2CMaster::stop() { - error_code result = parent->selectBus(I2C); - if (!result) { - result = I2CMasterDecorator::stop(); - } - return result; +Result<OneWireMaster::TripletData> +DS9481P_300::OneWireMaster::triplet(bool sendBit) { + TRY(parent->selectBus(OneWire)); + return OneWireMasterDecorator::triplet(sendBit); } -error_code DS9481P_300::I2CMaster::writeByte(uint_least8_t data) { - error_code result = parent->selectBus(I2C); - if (!result) { - result = I2CMasterDecorator::writeByte(data); - } - return result; +Result<void> DS9481P_300::I2CMaster::start(uint_least8_t address) { + TRY(parent->selectBus(I2C)); + return I2CMasterDecorator::start(address); } -error_code DS9481P_300::I2CMaster::writeBlock(span<const uint_least8_t> data) { - error_code result = parent->selectBus(I2C); - if (!result) { - result = I2CMasterDecorator::writeBlock(data); - } - return result; +Result<void> DS9481P_300::I2CMaster::stop() { + TRY(parent->selectBus(I2C)); + return I2CMasterDecorator::stop(); +} + +Result<void> DS9481P_300::I2CMaster::writeByte(uint_least8_t data) { + TRY(parent->selectBus(I2C)); + return I2CMasterDecorator::writeByte(data); } -error_code DS9481P_300::I2CMaster::doWritePacket(uint_least8_t address, - span<const uint_least8_t> data, - bool sendStop) { - error_code result = parent->selectBus(I2C); - if (!result) { - result = I2CMasterDecorator::doWritePacket(address, data, sendStop); - } - return result; +Result<void> +DS9481P_300::I2CMaster::writeBlock(span<const uint_least8_t> data) { + TRY(parent->selectBus(I2C)); + return I2CMasterDecorator::writeBlock(data); } -error_code DS9481P_300::I2CMaster::readByte(AckStatus status, - uint_least8_t & data) { - error_code result = parent->selectBus(I2C); - if (!result) { - result = I2CMasterDecorator::readByte(status, data); - } - return result; +Result<void> DS9481P_300::I2CMaster::writePacket(uint_least8_t address, + span<const uint_least8_t> data, + DoStop doStop) { + TRY(parent->selectBus(I2C)); + return I2CMasterDecorator::writePacket(address, data, doStop); } -error_code DS9481P_300::I2CMaster::readBlock(AckStatus status, - span<uint_least8_t> data) { - error_code result = parent->selectBus(I2C); - if (!result) { - result = I2CMasterDecorator::readBlock(status, data); - } - return result; +Result<uint_least8_t> DS9481P_300::I2CMaster::readByte(DoAck doAck) { + TRY(parent->selectBus(I2C)); + return I2CMasterDecorator::readByte(doAck); } -error_code DS9481P_300::I2CMaster::doReadPacket(uint_least8_t address, - span<uint_least8_t> data, - bool sendStop) { - error_code result = parent->selectBus(I2C); - if (!result) { - result = I2CMasterDecorator::doReadPacket(address, data, sendStop); - } - return result; +Result<void> DS9481P_300::I2CMaster::readBlock(span<uint_least8_t> data, + DoAck doAck) { + TRY(parent->selectBus(I2C)); + return I2CMasterDecorator::readBlock(data, doAck); } -error_code DS9481P_300::DS2480BWithEscape::escape() { +Result<void> DS9481P_300::I2CMaster::readPacket(uint_least8_t address, + span<uint_least8_t> data, + DoStop doStop) { + TRY(parent->selectBus(I2C)); + return I2CMasterDecorator::readPacket(address, data, doStop); +} + +Result<void> DS9481P_300::DS2480BWithEscape::escape() { return sendCommand(0xE5); } -error_code DS9481P_300::DS9400WithEscape::escape() { return configure('O'); } +Result<void> DS9481P_300::DS9400WithEscape::escape() { return configure('O'); } } // namespace MaximInterfaceDevices
--- a/MaximInterfaceDevices/DS9481P_300.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS9481P_300.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceDevices_DS9481P_300 -#define MaximInterfaceDevices_DS9481P_300 +#ifndef MaximInterfaceDevices_DS9481P_300_hpp +#define MaximInterfaceDevices_DS9481P_300_hpp #include <MaximInterfaceCore/I2CMasterDecorator.hpp> #include <MaximInterfaceCore/OneWireMasterDecorator.hpp> @@ -57,14 +57,10 @@ ds9400.setUart(serialPort); } - MaximInterfaceDevices_EXPORT Core::error_code + MaximInterfaceDevices_EXPORT Core::Result<void> connect(const std::string & portName); - MaximInterfaceDevices_EXPORT Core::error_code disconnect(); - - MaximInterfaceDevices_EXPORT bool connected() const; - - MaximInterfaceDevices_EXPORT std::string portName() const; + MaximInterfaceDevices_EXPORT Core::Result<void> disconnect(); /// Access the 1-Wire master when connected to an adapter. Core::OneWireMaster & oneWireMaster() { return oneWireMaster_; } @@ -78,31 +74,31 @@ explicit OneWireMaster(DS9481P_300 & parent) : OneWireMasterDecorator(parent.ds2480b), parent(&parent) {} - MaximInterfaceDevices_EXPORT virtual Core::error_code reset(); + MaximInterfaceDevices_EXPORT virtual Core::Result<void> reset(); - MaximInterfaceDevices_EXPORT virtual Core::error_code - touchBitSetLevel(bool & sendRecvBit, Level afterLevel); + MaximInterfaceDevices_EXPORT virtual Core::Result<bool> + touchBitSetLevel(bool sendBit, Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> writeByteSetLevel(uint_least8_t sendByte, Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code - readByteSetLevel(uint_least8_t & recvByte, Level afterLevel); + MaximInterfaceDevices_EXPORT virtual Core::Result<uint_least8_t> + readByteSetLevel(Level afterLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> writeBlock(Core::span<const uint_least8_t> sendBuf); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> readBlock(Core::span<uint_least8_t> recvBuf); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> setSpeed(Speed newSpeed); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> setLevel(Level newLevel); - MaximInterfaceDevices_EXPORT virtual Core::error_code - triplet(TripletData & data); + MaximInterfaceDevices_EXPORT virtual Core::Result<TripletData> + triplet(bool sendBit); private: DS9481P_300 * parent; @@ -113,31 +109,30 @@ explicit I2CMaster(DS9481P_300 & parent) : I2CMasterDecorator(parent.ds9400), parent(&parent) {} - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> start(uint_least8_t address); - MaximInterfaceDevices_EXPORT virtual Core::error_code stop(); + MaximInterfaceDevices_EXPORT virtual Core::Result<void> stop(); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> writeByte(uint_least8_t data); - MaximInterfaceDevices_EXPORT virtual Core::error_code + MaximInterfaceDevices_EXPORT virtual Core::Result<void> writeBlock(Core::span<const uint_least8_t> data); - MaximInterfaceDevices_EXPORT virtual Core::error_code - readByte(AckStatus status, uint_least8_t & data); + MaximInterfaceDevices_EXPORT virtual Core::Result<void> + writePacket(uint_least8_t address, Core::span<const uint_least8_t> data, + DoStop doStop); - MaximInterfaceDevices_EXPORT virtual Core::error_code - readBlock(AckStatus status, Core::span<uint_least8_t> data); + MaximInterfaceDevices_EXPORT virtual Core::Result<uint_least8_t> + readByte(DoAck doAck); - protected: - MaximInterfaceDevices_EXPORT virtual Core::error_code - doWritePacket(uint_least8_t address, Core::span<const uint_least8_t> data, - bool sendStop); + MaximInterfaceDevices_EXPORT virtual Core::Result<void> + readBlock(Core::span<uint_least8_t> data, DoAck doAck); - MaximInterfaceDevices_EXPORT virtual Core::error_code - doReadPacket(uint_least8_t address, Core::span<uint_least8_t> data, - bool sendStop); + MaximInterfaceDevices_EXPORT virtual Core::Result<void> + readPacket(uint_least8_t address, Core::span<uint_least8_t> data, + DoStop doStop); private: DS9481P_300 * parent; @@ -148,14 +143,14 @@ DS2480BWithEscape(Core::Sleep & sleep, Core::Uart & uart) : DS2480B(sleep, uart) {} - Core::error_code escape(); + Core::Result<void> escape(); }; class DS9400WithEscape : public DS9400 { public: explicit DS9400WithEscape(Core::Uart & uart) : DS9400(uart) {} - Core::error_code escape(); + Core::Result<void> escape(); }; enum Bus { OneWire, I2C }; @@ -167,8 +162,8 @@ DS9400WithEscape ds9400; I2CMaster i2cMaster_; - Core::error_code selectOneWire(); - Core::error_code selectBus(Bus newBus); + Core::Result<void> selectOneWire(); + Core::Result<void> selectBus(Bus newBus); friend class OneWireMaster; friend class I2CMaster;
--- a/MaximInterfaceMbed/I2CMaster.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceMbed/I2CMaster.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -36,40 +36,49 @@ using namespace MaximInterfaceCore; -error_code I2CMaster::start(uint_least8_t address) { +Result<void> I2CMaster::start(uint_least8_t address) { i2c->start(); return writeByte(address); } -error_code I2CMaster::stop() { +Result<void> I2CMaster::stop() { i2c->stop(); - return error_code(); + return none; } -error_code I2CMaster::writeByte(uint_least8_t data) { - return (i2c->write(data) == 1) ? error_code() : make_error_code(NackError); +Result<void> I2CMaster::writeByte(uint_least8_t data) { + return (i2c->write(data) == 1) ? makeResult(none) : NackError; } -error_code I2CMaster::doWritePacket(uint_least8_t address, +Result<void> I2CMaster::writePacket(uint_least8_t address, 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); + DoStop doStop) { + const Result<void> result = + (i2c->write(address, reinterpret_cast<const char *>(data.data()), + data.size(), doStop != Stop) == 0) + ? makeResult(none) + : NackError; + if (doStop == StopOnError && !result) { + i2c->stop(); + } + return result; } -error_code I2CMaster::readByte(AckStatus status, uint_least8_t & data) { - data = i2c->read(status == Ack); - return error_code(); +Result<uint_least8_t> I2CMaster::readByte(DoAck doAck) { + return i2c->read(doAck == Ack); } -error_code I2CMaster::doReadPacket(uint_least8_t address, - 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); +Result<void> I2CMaster::readPacket(uint_least8_t address, + span<uint_least8_t> data, DoStop doStop) { + const Result<void> result = + (i2c->read(address, reinterpret_cast<char *>(data.data()), data.size(), + doStop != Stop) == 0) + ? makeResult(none) + : NackError; + if (doStop == StopOnError && !result) { + i2c->stop(); + } + return result; } } // namespace MaximInterfaceMbed
--- a/MaximInterfaceMbed/I2CMaster.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceMbed/I2CMaster.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceMbed_I2CMaster -#define MaximInterfaceMbed_I2CMaster +#ifndef MaximInterfaceMbed_I2CMaster_hpp +#define MaximInterfaceMbed_I2CMaster_hpp #include <MaximInterfaceCore/I2CMaster.hpp> #include <mbed-os/drivers/I2C.h> @@ -45,24 +45,22 @@ void setI2C(mbed::I2C & i2c) { this->i2c = &i2c; } - virtual MaximInterfaceCore::error_code start(uint_least8_t address); - - virtual MaximInterfaceCore::error_code stop(); + virtual MaximInterfaceCore::Result<void> start(uint_least8_t address); - virtual MaximInterfaceCore::error_code writeByte(uint_least8_t data); + virtual MaximInterfaceCore::Result<void> stop(); - virtual MaximInterfaceCore::error_code readByte(AckStatus status, - uint_least8_t & data); + virtual MaximInterfaceCore::Result<void> writeByte(uint_least8_t data); -protected: - virtual MaximInterfaceCore::error_code - doReadPacket(uint_least8_t address, - MaximInterfaceCore::span<uint_least8_t> data, bool sendStop); + virtual MaximInterfaceCore::Result<void> + writePacket(uint_least8_t address, + MaximInterfaceCore::span<const uint_least8_t> data, + DoStop doStop); - virtual MaximInterfaceCore::error_code - doWritePacket(uint_least8_t address, - MaximInterfaceCore::span<const uint_least8_t> data, - bool sendStop); + virtual MaximInterfaceCore::Result<uint_least8_t> readByte(DoAck doAck); + + virtual MaximInterfaceCore::Result<void> + readPacket(uint_least8_t address, + MaximInterfaceCore::span<uint_least8_t> data, DoStop doStop); private: mbed::I2C * i2c;
--- a/MaximInterfaceMbed/Sleep.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceMbed/Sleep.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -37,11 +37,6 @@ void sleep(int ms) { wait_ms(ms); } -Sleep & Sleep::instance() { - static Sleep instance; - return instance; -} - void Sleep::invoke(int ms) const { sleep(ms); } } // namespace MaximInterfaceMbed
--- a/MaximInterfaceMbed/Sleep.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceMbed/Sleep.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,24 +30,18 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceMbed_Sleep -#define MaximInterfaceMbed_Sleep +#ifndef MaximInterfaceMbed_Sleep_hpp +#define MaximInterfaceMbed_Sleep_hpp #include <MaximInterfaceCore/Sleep.hpp> -#include <MaximInterfaceCore/Uncopyable.hpp> namespace MaximInterfaceMbed { void sleep(int ms); -class Sleep : public MaximInterfaceCore::Sleep, - private MaximInterfaceCore::Uncopyable { +class Sleep : public MaximInterfaceCore::Sleep { public: - static Sleep & instance(); virtual void invoke(int ms) const; - -private: - Sleep() {} }; } // namespace MaximInterfaceMbed
--- a/MaximInterfaceMbed/Uart.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceMbed/Uart.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -40,64 +40,61 @@ static const int timeout_ms = 10000; -error_code Uart::setBaudRate(int_least32_t baudRate) { +Result<void> Uart::setBaudRate(int_least32_t baudRate) { serial->baud(baudRate); - return error_code(); + return none; } -error_code Uart::sendBreak() { +Result<void> Uart::sendBreak() { serial->send_break(); - return error_code(); + return none; } -error_code Uart::clearReadBuffer() { +Result<void> Uart::clearReadBuffer() { while (serial->readable()) { serial->getc(); } - return error_code(); + return none; } -error_code Uart::writeByte(uint_least8_t data) { +Result<void> Uart::writeByte(uint_least8_t data) { if (!serial->writeable()) { mbed::Timer timer; timer.start(); while (!serial->writeable()) { if (timer.read_ms() >= timeout_ms) { - return make_error_code(HardwareError); + return HardwareError; } } } serial->putc(data); - return error_code(); + return none; } -error_code Uart::readByte(uint_least8_t & data) { +Result<uint_least8_t> Uart::readByte() { if (!serial->readable()) { mbed::Timer timer; timer.start(); while (!serial->readable()) { if (timer.read_ms() >= timeout_ms) { - return make_error_code(TimeoutError); + return TimeoutError; } } } - data = serial->getc(); - return error_code(); + return serial->getc(); } const error_category & Uart::errorCategory() { static class : public error_category { public: - virtual const char * name() const { return "mbed UART"; } + virtual const char * name() const { return "Mbed UART"; } virtual std::string message(int condition) const { switch (condition) { case HardwareError: return "Hardware Error"; - - default: - return defaultErrorMessage(condition); } + return defaultErrorMessage(condition); } } instance; return instance;
--- a/MaximInterfaceMbed/Uart.hpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceMbed/Uart.hpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -30,8 +30,8 @@ * ownership rights. *******************************************************************************/ -#ifndef MaximInterfaceMbed_Uart -#define MaximInterfaceMbed_Uart +#ifndef MaximInterfaceMbed_Uart_hpp +#define MaximInterfaceMbed_Uart_hpp #include <MaximInterfaceCore/Uart.hpp> #include <mbed-os/drivers/Serial.h> @@ -49,15 +49,15 @@ void setSerial(mbed::Serial & serial) { this->serial = &serial; } - virtual MaximInterfaceCore::error_code setBaudRate(int_least32_t baudRate); + virtual MaximInterfaceCore::Result<void> setBaudRate(int_least32_t baudRate); - virtual MaximInterfaceCore::error_code sendBreak(); + virtual MaximInterfaceCore::Result<void> sendBreak(); - virtual MaximInterfaceCore::error_code clearReadBuffer(); + virtual MaximInterfaceCore::Result<void> clearReadBuffer(); - virtual MaximInterfaceCore::error_code writeByte(uint_least8_t data); + virtual MaximInterfaceCore::Result<void> writeByte(uint_least8_t data); - virtual MaximInterfaceCore::error_code readByte(uint_least8_t & data); + virtual MaximInterfaceCore::Result<uint_least8_t> readByte(); static const MaximInterfaceCore::error_category & errorCategory(); @@ -65,6 +65,15 @@ mbed::Serial * serial; }; +} // namespace MaximInterfaceMbed +namespace MaximInterfaceCore { + +template <> +struct is_error_code_enum<MaximInterfaceMbed::Uart::ErrorValue> : true_type {}; + +} // namespace MaximInterfaceCore +namespace MaximInterfaceMbed { + inline MaximInterfaceCore::error_code make_error_code(Uart::ErrorValue e) { return MaximInterfaceCore::error_code(e, Uart::errorCategory()); }
--- a/mbed_lib.json Mon Jul 22 11:44:07 2019 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -{ - "name": "MaximInterface", - "macros": ["__STDC_LIMIT_MACROS"] -} \ No newline at end of file