diff --git a/include/adclib/adclib_device1.h b/include/adclib/adclib_device1.h new file mode 100644 index 0000000..2af49b9 --- /dev/null +++ b/include/adclib/adclib_device1.h @@ -0,0 +1,309 @@ +#pragma once + + + +/**************************************************************************************** + * ABSTRACT DEVICE COMPONENTS LIBRARY * + ****************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + + + +#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 : 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(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(ec), AdcDeviceErrorCategory::get()); +} + + +template +concept adclib_command_exec_t = snplib::snplib_callable_c && (snplib::snplib_func_traits_t::arity == 0) && + std::same_as::ret_t>; + +template +concept adclib_attr_getter_c = std::same_as || requires(T t) { + { t() } -> adc_result_c; +}; + +template +concept adclib_attr_setter_c = + std::same_as || (snplib::snplib_callable_c && (snplib::snplib_func_traits_t::arity >= 1) && + std::same_as::ret_t>); + + +// deduce value type from getter and setter +template +using adclib_attr_value_deduced_t = std::conditional_t< + std::is_null_pointer_v, + std::conditional_t, void, std::remove_cvref_t>>, + typename std::invoke_result_t::value_type>; + + +template +struct adclib_is_deduced_void_t { + static constexpr bool value = std::is_void_v>; +}; + +// conversional function signature: +// "from": adc_result_t func(const adc_result_t&) +// "to": adc_result_t func(const adc_result_t&) +template +concept adclib_attr_conv_from_func_c = + std::same_as || + (std::invocable&> && !std::is_void_v&>>); + +template +concept adclib_attr_conv_to_func_c = std::same_as || + (snplib::snplib_callable_c && (snplib::snplib_func_traits_t::arity == 1) && + std::same_as, typename snplib::snplib_func_traits_t::ret_t>); + +template CONV_FROM_T, adclib_attr_conv_to_func_c CONV_TO_T> +using adclib_attr_user_deduced_t = + std::conditional_t, + std::conditional_t, + void, + std::remove_cvref_t>>, + typename snplib::snplib_func_traits_t::ret_t>; + + + +template DEV_ID_T = std::string, + std::formattable ATTR_ID_T = std::string, + std::formattable CMD_ID_T = std::string> +class AdcGenericDevice +{ +protected: + template + using attr_getter_t = std::function()>; + + template + using attr_setter_t = std::function; + + typedef std::vector serialized_t; + typedef std::function attr_serial_func_t; + typedef std::function attr_deserial_func_t; + + struct attr_t { + template SerialFuncT, + std::convertible_to DeserialFuncT> + attr_t(AdcGenericDevice& dev, ATTR_ID_T id, SerialFuncT&& serial_func, DeserialFuncT&& deserial_func) + : _dev(dev), + _id(std::move(id)), + _serializer(std::forward(serial_func)), + _deserializer(std::forward(deserial_func)) + { + } + + template + operator adc_result_t() const + { + auto getter = _dev._attrGetter.template get>(_id); + if (getter) { + if (getter.value()) { + return getter.value()(); + } else { + return std::unexpected(AdcDeviceErrorCode::ERROR_WO_ATTR); + } + } + + if (getter.error() == snplib::HeterogenMap::ERROR_NO_ELEM) { + return std::unexpected(AdcDeviceErrorCode::ERROR_NO_ATTR_ID); + } + + // fallback ... + return std::unexpected(AdcDeviceErrorCode::ERROR_UNKNOWN); + } + + template + adc_error_t operator=(VT&& val) + { + auto setter = _dev._attrSetter.template get>>(_id); + if (setter) { + if (setter.value()) { + return setter.value()(std::forward(val)); + } else { + return AdcDeviceErrorCode::ERROR_WO_ATTR; + } + } + + if (setter.error() == snplib::HeterogenMap::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) { + } + } + + 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> _commands{}; + + snplib::HeterogenMap _attrGetter{}; + snplib::HeterogenMap _attrSetter{}; + +public: + static constexpr std::tuple + 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 + // void addCommand(CMD_ID_T id, ET&& exec_func) + // { + // _commands.emplace(std::move(id), std::forward(exec_func)); + // } + + template + void addCommand(CMD_ID_T id, ET&& exec_func) + { + _commands.emplace(std::move(id), std::forward(exec_func)); + } + + template + void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter, std::tuple = std::tuple<>{}) + { + using v_t = adclib_attr_value_deduced_t; + static_assert(!std::is_void_v, "Getter and setter cannot be nullptr_t at the same time!"); + + if constexpr (!std::is_null_pointer_v && !std::is_null_pointer_v) { + static_assert(std::invocable, "Invalid setter argument type!"); + } + + // _attrGetter.push() + } +}; + + +} // namespace adc \ No newline at end of file