...
This commit is contained in:
309
include/adclib/adclib_device1.h
Normal file
309
include/adclib/adclib_device1.h
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* ABSTRACT DEVICE COMPONENTS LIBRARY *
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
|
#include <format>
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <system_error>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
|
#include <snipplib/concepts/snplib_traits.h>
|
||||||
|
#include <snipplib/containers/snplib_hmap.h>
|
||||||
|
#include <snipplib/serialization/snplib_serialization.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "adclib_common.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace adc
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
enum class AdcDeviceErrorCode : int {
|
||||||
|
ERROR_OK,
|
||||||
|
ERROR_NO_CMD_ID,
|
||||||
|
ERROR_NO_ATTR_ID,
|
||||||
|
ERROR_RO_ATTR,
|
||||||
|
ERROR_WO_ATTR,
|
||||||
|
ERROR_ATTR_RANGE,
|
||||||
|
ERROR_SERIALIZATION,
|
||||||
|
ERROR_DESERIALIZATION,
|
||||||
|
ERROR_UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace adc
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class is_error_code_enum<adc::AdcDeviceErrorCode> : public true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
|
||||||
|
namespace adc
|
||||||
|
{
|
||||||
|
|
||||||
|
// error category
|
||||||
|
|
||||||
|
struct AdcDeviceErrorCategory : std::error_category {
|
||||||
|
const char* name() const noexcept
|
||||||
|
{
|
||||||
|
return "ADCLIB-DEVICE-ERR-CATEGORY";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message(int ec) const
|
||||||
|
{
|
||||||
|
AdcDeviceErrorCode err = static_cast<AdcDeviceErrorCode>(ec);
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
case AdcDeviceErrorCode::ERROR_OK:
|
||||||
|
return "OK";
|
||||||
|
case AdcDeviceErrorCode::ERROR_NO_CMD_ID:
|
||||||
|
return "invalid command ID";
|
||||||
|
case AdcDeviceErrorCode::ERROR_NO_ATTR_ID:
|
||||||
|
return "invalid attribute ID";
|
||||||
|
case AdcDeviceErrorCode::ERROR_RO_ATTR:
|
||||||
|
return "read-only attribute";
|
||||||
|
case AdcDeviceErrorCode::ERROR_WO_ATTR:
|
||||||
|
return "write-only attribute";
|
||||||
|
case AdcDeviceErrorCode::ERROR_ATTR_RANGE:
|
||||||
|
return "value is out of attribute range ";
|
||||||
|
case AdcDeviceErrorCode::ERROR_SERIALIZATION:
|
||||||
|
return "serialization error";
|
||||||
|
case AdcDeviceErrorCode::ERROR_DESERIALIZATION:
|
||||||
|
return "deserialization error";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const AdcDeviceErrorCategory& get()
|
||||||
|
{
|
||||||
|
static const AdcDeviceErrorCategory constInst;
|
||||||
|
return constInst;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::error_code make_error_code(AdcDeviceErrorCode ec)
|
||||||
|
{
|
||||||
|
return std::error_code(static_cast<int>(ec), AdcDeviceErrorCategory::get());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept adclib_command_exec_t = snplib::snplib_callable_c<T> && (snplib::snplib_func_traits_t<T>::arity == 0) &&
|
||||||
|
std::same_as<adc_error_t, typename snplib::snplib_func_traits_t<T>::ret_t>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept adclib_attr_getter_c = std::same_as<T, std::nullptr_t> || requires(T t) {
|
||||||
|
{ t() } -> adc_result_c;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept adclib_attr_setter_c =
|
||||||
|
std::same_as<T, std::nullptr_t> || (snplib::snplib_callable_c<T> && (snplib::snplib_func_traits_t<T>::arity >= 1) &&
|
||||||
|
std::same_as<adc_error_t, typename snplib::snplib_func_traits_t<T>::ret_t>);
|
||||||
|
|
||||||
|
|
||||||
|
// deduce value type from getter and setter
|
||||||
|
template <adclib_attr_getter_c GT, adclib_attr_setter_c ST>
|
||||||
|
using adclib_attr_value_deduced_t = std::conditional_t<
|
||||||
|
std::is_null_pointer_v<GT>,
|
||||||
|
std::conditional_t<std::is_null_pointer_v<ST>, void, std::remove_cvref_t<snplib::snplib_func_arg1_t<ST>>>,
|
||||||
|
typename std::invoke_result_t<GT>::value_type>;
|
||||||
|
|
||||||
|
|
||||||
|
template <adclib_attr_getter_c GT, adclib_attr_setter_c ST>
|
||||||
|
struct adclib_is_deduced_void_t {
|
||||||
|
static constexpr bool value = std::is_void_v<adclib_attr_value_deduced_t<GT, ST>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// conversional function signature:
|
||||||
|
// "from": adc_result_t<UT> func(const adc_result_t<VT>&)
|
||||||
|
// "to": adc_result_t<VT> func(const adc_result_t<UT>&)
|
||||||
|
template <typename T, typename VT>
|
||||||
|
concept adclib_attr_conv_from_func_c =
|
||||||
|
std::same_as<T, std::nullptr_t> ||
|
||||||
|
(std::invocable<T, const adc_result_t<VT>&> && !std::is_void_v<std::invoke_result_t<T, const adc_result_t<VT>&>>);
|
||||||
|
|
||||||
|
template <typename T, typename VT>
|
||||||
|
concept adclib_attr_conv_to_func_c = std::same_as<T, std::nullptr_t> ||
|
||||||
|
(snplib::snplib_callable_c<T> && (snplib::snplib_func_traits_t<T>::arity == 1) &&
|
||||||
|
std::same_as<adc_result_t<VT>, typename snplib::snplib_func_traits_t<T>::ret_t>);
|
||||||
|
|
||||||
|
template <typename VT, adclib_attr_conv_from_func_c<VT> CONV_FROM_T, adclib_attr_conv_to_func_c<VT> CONV_TO_T>
|
||||||
|
using adclib_attr_user_deduced_t =
|
||||||
|
std::conditional_t<std::is_null_pointer_v<CONV_FROM_T>,
|
||||||
|
std::conditional_t<std::is_null_pointer_v<CONV_TO_T>,
|
||||||
|
void,
|
||||||
|
std::remove_cvref_t<snplib::snplib_func_arg1_t<CONV_TO_T>>>,
|
||||||
|
typename snplib::snplib_func_traits_t<CONV_FROM_T>::ret_t>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <std::formattable<char> DEV_ID_T = std::string,
|
||||||
|
std::formattable<char> ATTR_ID_T = std::string,
|
||||||
|
std::formattable<char> CMD_ID_T = std::string>
|
||||||
|
class AdcGenericDevice
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
template <typename VT>
|
||||||
|
using attr_getter_t = std::function<adc_result_t<VT>()>;
|
||||||
|
|
||||||
|
template <typename VT>
|
||||||
|
using attr_setter_t = std::function<adc_error_t(VT const&)>;
|
||||||
|
|
||||||
|
typedef std::vector<char> serialized_t;
|
||||||
|
typedef std::function<adc_error_t(serialized_t&)> attr_serial_func_t;
|
||||||
|
typedef std::function<adc_error_t(serialized_t const&)> attr_deserial_func_t;
|
||||||
|
|
||||||
|
struct attr_t {
|
||||||
|
template <std::convertible_to<attr_serial_func_t> SerialFuncT,
|
||||||
|
std::convertible_to<attr_deserial_func_t> DeserialFuncT>
|
||||||
|
attr_t(AdcGenericDevice& dev, ATTR_ID_T id, SerialFuncT&& serial_func, DeserialFuncT&& deserial_func)
|
||||||
|
: _dev(dev),
|
||||||
|
_id(std::move(id)),
|
||||||
|
_serializer(std::forward<SerialFuncT>(serial_func)),
|
||||||
|
_deserializer(std::forward<DeserialFuncT>(deserial_func))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename VT>
|
||||||
|
operator adc_result_t<VT>() const
|
||||||
|
{
|
||||||
|
auto getter = _dev._attrGetter.template get<attr_getter_t<VT>>(_id);
|
||||||
|
if (getter) {
|
||||||
|
if (getter.value()) {
|
||||||
|
return getter.value()();
|
||||||
|
} else {
|
||||||
|
return std::unexpected(AdcDeviceErrorCode::ERROR_WO_ATTR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getter.error() == snplib::HeterogenMap<ATTR_ID_T>::ERROR_NO_ELEM) {
|
||||||
|
return std::unexpected(AdcDeviceErrorCode::ERROR_NO_ATTR_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback ...
|
||||||
|
return std::unexpected(AdcDeviceErrorCode::ERROR_UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename VT>
|
||||||
|
adc_error_t operator=(VT&& val)
|
||||||
|
{
|
||||||
|
auto setter = _dev._attrSetter.template get<attr_setter_t<std::remove_cvref_t<VT>>>(_id);
|
||||||
|
if (setter) {
|
||||||
|
if (setter.value()) {
|
||||||
|
return setter.value()(std::forward<VT>(val));
|
||||||
|
} else {
|
||||||
|
return AdcDeviceErrorCode::ERROR_WO_ATTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setter.error() == snplib::HeterogenMap<ATTR_ID_T>::ERROR_NO_ELEM) {
|
||||||
|
return AdcDeviceErrorCode::ERROR_NO_ATTR_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback ...
|
||||||
|
return AdcDeviceErrorCode::ERROR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_error_t serialize(snplib::snplib_output_char_range_c auto& output,
|
||||||
|
snplib::snplib_serialization_params_c auto const& params)
|
||||||
|
{
|
||||||
|
if constexpr (std::same_as<serialized_t, decltype(output)>) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_error_t deserialize(snplib::snplib_input_char_range_c auto const& input,
|
||||||
|
snplib::snplib_serialization_params_c auto const& params)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AdcGenericDevice& _dev;
|
||||||
|
ATTR_ID_T _id;
|
||||||
|
attr_serial_func_t _serializer;
|
||||||
|
attr_deserial_func_t _deserializer;
|
||||||
|
};
|
||||||
|
|
||||||
|
DEV_ID_T _devId;
|
||||||
|
|
||||||
|
std::unordered_map<CMD_ID_T, std::function<adc_error_t()>> _commands{};
|
||||||
|
|
||||||
|
snplib::HeterogenMap<ATTR_ID_T> _attrGetter{};
|
||||||
|
snplib::HeterogenMap<ATTR_ID_T> _attrSetter{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr std::tuple<bool,
|
||||||
|
char,
|
||||||
|
short,
|
||||||
|
int,
|
||||||
|
long,
|
||||||
|
long long,
|
||||||
|
unsigned char,
|
||||||
|
unsigned short,
|
||||||
|
unsigned int,
|
||||||
|
unsigned long,
|
||||||
|
unsigned long long,
|
||||||
|
float,
|
||||||
|
double,
|
||||||
|
long double>
|
||||||
|
arithmetic_types{};
|
||||||
|
|
||||||
|
typedef DEV_ID_T device_id_t;
|
||||||
|
typedef ATTR_ID_T attr_id_t;
|
||||||
|
typedef CMD_ID_T cmd_id_t;
|
||||||
|
|
||||||
|
enum AttrAccessType { ATTR_ACCESS_RW, ATTR_ACCESS_RO, ATTR_ACCESS_WO };
|
||||||
|
|
||||||
|
AdcGenericDevice(device_id_t id) : _devId(id) {}
|
||||||
|
|
||||||
|
virtual ~AdcGenericDevice() = default;
|
||||||
|
|
||||||
|
device_id_t id() const
|
||||||
|
{
|
||||||
|
return _devId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// template <snplib::snplib_callable_c ET>
|
||||||
|
// void addCommand(CMD_ID_T id, ET&& exec_func)
|
||||||
|
// {
|
||||||
|
// _commands.emplace(std::move(id), std::forward<ET>(exec_func));
|
||||||
|
// }
|
||||||
|
|
||||||
|
template <adclib_command_exec_t ET>
|
||||||
|
void addCommand(CMD_ID_T id, ET&& exec_func)
|
||||||
|
{
|
||||||
|
_commands.emplace(std::move(id), std::forward<ET>(exec_func));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename GT, typename ST, typename... VTs>
|
||||||
|
void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter, std::tuple<VTs...> = std::tuple<>{})
|
||||||
|
{
|
||||||
|
using v_t = adclib_attr_value_deduced_t<GT, ST>;
|
||||||
|
static_assert(!std::is_void_v<v_t>, "Getter and setter cannot be nullptr_t at the same time!");
|
||||||
|
|
||||||
|
if constexpr (!std::is_null_pointer_v<GT> && !std::is_null_pointer_v<ST>) {
|
||||||
|
static_assert(std::invocable<ST, v_t const&>, "Invalid setter argument type!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// _attrGetter.push()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace adc
|
||||||
Reference in New Issue
Block a user