add adc_device.h header file (AdcGenericDevice class)
This commit is contained in:
203
device/adc_device.h
Normal file
203
device/adc_device.h
Normal file
@@ -0,0 +1,203 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <system_error>
|
||||
|
||||
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<adc::AdcGenericDeviceErrorCode> : 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<AdcGenericDeviceErrorCode>(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<int>(ec), AdcGenericDeviceErrorCategory::get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace traits
|
||||
{
|
||||
|
||||
// ADC device attribute concept
|
||||
template <typename T>
|
||||
concept adc_device_attr_c = requires {
|
||||
typename T::ident_t;
|
||||
&T::ident;
|
||||
&T::serialize;
|
||||
&T::deserialize;
|
||||
// std::declval<T>().operator int();
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept adc_device_cmd_c = requires {
|
||||
typename T::ident_t;
|
||||
&T::ident;
|
||||
&T::operator();
|
||||
};
|
||||
|
||||
|
||||
} // namespace traits
|
||||
|
||||
|
||||
template <typename IdentT, traits::adc_device_attr_c AttributeT, traits::adc_device_cmd_c CommandT>
|
||||
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 <typename... CtorArgTs>
|
||||
AdcGenericDevice& addAttribute(CtorArgTs&&... ctor_args)
|
||||
{
|
||||
return addAttribute(AttributeT{std::forward<CtorArgTs>(ctor_args)...});
|
||||
}
|
||||
|
||||
|
||||
AdcGenericDevice& delAttribute(const attr_ident_t& attr_ident)
|
||||
{
|
||||
_deviceAttributes.erase(attr_ident);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template <std::ranges::output_range<cmd_ident_t> ResultT>
|
||||
AdcGenericDevice& commandIdents(ResultT& idents)
|
||||
{
|
||||
std::ranges::copy(_deviceCommands | std::views::keys, std::back_inserter(idents));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <std::ranges::output_range<attr_ident_t> ResultT>
|
||||
AdcGenericDevice& attributeIdents(ResultT& idents)
|
||||
{
|
||||
std::ranges::copy(_deviceAttributes | std::views::keys, std::back_inserter(idents));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
IdentT _ident;
|
||||
|
||||
std::map<attr_ident_t, AttributeT> _deviceAttributes;
|
||||
std::map<cmd_ident_t, CommandT> _deviceCommands;
|
||||
};
|
||||
|
||||
} // namespace adc
|
||||
Reference in New Issue
Block a user