From 1c79026a3486cddfdbacf461738dac5f38fa8d44 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Mon, 20 May 2024 01:24:40 +0300 Subject: [PATCH] add adc_device.h header file (AdcGenericDevice class) --- CMakeLists.txt | 3 +- device/adc_device.h | 203 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 device/adc_device.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ad9aab..4bc65c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,8 @@ set(ADC_COMMON_HEADERS set(ADC_DEVICE_HEADERS device/adc_device_attribute.h - device/adc_device_command.h + device/adc_device_command.h + device/adc_device.h ) option(BUILD_TESTS "Build tests" ON) diff --git a/device/adc_device.h b/device/adc_device.h new file mode 100644 index 0000000..47ead98 --- /dev/null +++ b/device/adc_device.h @@ -0,0 +1,203 @@ +#pragma once + +#include +#include +#include +#include + +namespace adc +{ + +// error codes +enum class AdcGenericDeviceErrorCode : int { ERROR_OK, ERROR_ATTR_IDENT, ERROR_COMMAND_IDENT, ERROR_UNKNOWN }; + + +} // namespace adc + + +namespace std +{ +template <> +class is_error_code_enum : public true_type +{ +}; +} // namespace std + + + +namespace adc +{ + + +// error category +struct AdcGenericDeviceErrorCategory : public std::error_category { + AdcGenericDeviceErrorCategory() : std::error_category() {} + + const char* name() const noexcept { return "ADC_GENERIC_DEVICE"; } + + std::string message(int ec) const + { + AdcGenericDeviceErrorCode err = static_cast(ec); + + switch (err) { + case AdcGenericDeviceErrorCode::ERROR_OK: + return "OK"; + case AdcGenericDeviceErrorCode::ERROR_ATTR_IDENT: + return "invalid attribute identificator"; + case AdcGenericDeviceErrorCode::ERROR_COMMAND_IDENT: + return "invalid command identificator"; + default: + return "UNKNOWN"; + } + } + + static const AdcGenericDeviceErrorCategory& get() + { + static const AdcGenericDeviceErrorCategory constInst; + return constInst; + } +}; + + +inline std::error_code make_error_code(AdcGenericDeviceErrorCode ec) +{ + return std::error_code(static_cast(ec), AdcGenericDeviceErrorCategory::get()); +} + + + +namespace traits +{ + +// ADC device attribute concept +template +concept adc_device_attr_c = requires { + typename T::ident_t; + &T::ident; + &T::serialize; + &T::deserialize; + // std::declval().operator int(); +}; + + +template +concept adc_device_cmd_c = requires { + typename T::ident_t; + &T::ident; + &T::operator(); +}; + + +} // namespace traits + + +template +class AdcGenericDevice +{ +public: + typedef IdentT ident_t; + typedef AttributeT attribute_t; + typedef CommandT command_t; + + using attr_ident_t = typename AttributeT::ident_t; + using cmd_ident_t = typename CommandT::ident_t; + + /* CONSTRUCTORS AND DESTRUCTOR */ + AdcGenericDevice(const IdentT& ident) : _ident(ident) {} + + virtual ~AdcGenericDevice() = default; + + + /* PUBLIC METHODS */ + + IdentT ident() const { return _ident; } + + AdcGenericDevice& operator()(const cmd_ident_t& cmd_ident) + { + auto it = _deviceCommands.find(cmd_ident); + + if (it != _deviceCommands.end()) { + *it(); + } else { + throw std::system_error(AdcGenericDeviceErrorCode::ERROR_COMMAND_IDENT); + } + + return *this; + } + + + AttributeT& operator[](const attr_ident_t& attr_ident) + { + auto it = _deviceAttributes.find(attr_ident); + if (it != _deviceAttributes.end()) { + return it->second; + } + + throw std::system_error(AdcGenericDeviceErrorCode::ERROR_ATTR_IDENT); + } + + + AdcGenericDevice& addCommand(CommandT&& cmd) + { + auto id = cmd.ident(); + _deviceCommands.emplace(id, std::move(cmd)); + + return *this; + } + + + AdcGenericDevice& delCommand(const cmd_ident_t& cmd_ident) + { + _deviceCommands.erase(cmd_ident); + + return *this; + } + + + AdcGenericDevice& addAttribute(AttributeT&& attr) + { + auto id = attr.ident(); + _deviceAttributes.emplace(id, std::move(attr)); + + return *this; + } + + template + AdcGenericDevice& addAttribute(CtorArgTs&&... ctor_args) + { + return addAttribute(AttributeT{std::forward(ctor_args)...}); + } + + + AdcGenericDevice& delAttribute(const attr_ident_t& attr_ident) + { + _deviceAttributes.erase(attr_ident); + + return *this; + } + + + template ResultT> + AdcGenericDevice& commandIdents(ResultT& idents) + { + std::ranges::copy(_deviceCommands | std::views::keys, std::back_inserter(idents)); + + return *this; + } + + template ResultT> + AdcGenericDevice& attributeIdents(ResultT& idents) + { + std::ranges::copy(_deviceAttributes | std::views::keys, std::back_inserter(idents)); + + return *this; + } + +protected: + IdentT _ident; + + std::map _deviceAttributes; + std::map _deviceCommands; +}; + +} // namespace adc