...
This commit is contained in:
@@ -5,12 +5,14 @@ project(adclib LANGUAGES CXX DESCRIPTION "Abstract Device Components Library")
|
|||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
option(BUILD_EXAM "Build examples" ON)
|
option(ADCLIB_BUILD_EXAM "Build examples" ON)
|
||||||
|
|
||||||
# ------- dependencies -------
|
# ------- dependencies -------
|
||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
|
set(SNPLIB_BUILD_EXAMPLES OFF)
|
||||||
|
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
snplib
|
snplib
|
||||||
GIT_REPOSITORY https://timur@git.sao.ru/timur/snipplib.git
|
GIT_REPOSITORY https://timur@git.sao.ru/timur/snipplib.git
|
||||||
@@ -22,9 +24,10 @@ FetchContent_Declare(
|
|||||||
|
|
||||||
FetchContent_MakeAvailable(snplib)
|
FetchContent_MakeAvailable(snplib)
|
||||||
|
|
||||||
|
set(ADCLIB_HEADERS
|
||||||
set(ADCLIB_HEADERS include/adclib/adclib_device.h
|
include/adclib/adclib_device.h
|
||||||
include/adclib/adclib_common.h)
|
include/adclib/adclib_common.h
|
||||||
|
)
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} INTERFACE ${ADCLIB_HEADERS})
|
add_library(${PROJECT_NAME} INTERFACE ${ADCLIB_HEADERS})
|
||||||
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_23)
|
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_23)
|
||||||
@@ -37,13 +40,14 @@ target_include_directories(
|
|||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} INTERFACE snipplib)
|
target_link_libraries(${PROJECT_NAME} INTERFACE snipplib)
|
||||||
|
|
||||||
if(BUILD_EXAM)
|
if(ADCLIB_BUILD_EXAM)
|
||||||
add_executable(device_exam examples/device_exam.cpp)
|
add_executable(device_exam examples/device_exam.cpp)
|
||||||
target_link_libraries(device_exam PRIVATE ${PROJECT_NAME})
|
target_link_libraries(device_exam PRIVATE ${PROJECT_NAME})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
install(TARGETS ${PROJECT_NAME}
|
install(
|
||||||
|
TARGETS ${PROJECT_NAME}
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,15 +10,14 @@ int main()
|
|||||||
double d = 8.1;
|
double d = 8.1;
|
||||||
std::string s{"dwedjkwlk"};
|
std::string s{"dwedjkwlk"};
|
||||||
|
|
||||||
AdcGenericDevice<> dev;
|
AdcGenericDevice<> dev("DEV#1");
|
||||||
|
|
||||||
dev.addAttr(
|
dev.addAttr(
|
||||||
"1", [&i]() -> adc_result_t<int> { return i; },
|
"1", [&i]() -> adc_result_t<int> { return i; },
|
||||||
[&i](int ii) -> adc_error_t {
|
[&i](int ii) -> adc_error_t {
|
||||||
i = ii;
|
i = ii;
|
||||||
return AdcDeviceErrorCode::ERROR_OK;
|
return AdcDeviceErrorCode::ERROR_OK;
|
||||||
},
|
});
|
||||||
std::tuple<double, long>{});
|
|
||||||
|
|
||||||
dev.addAttr("2", [&d]() -> adc_result_t<double> { return d; }, nullptr);
|
dev.addAttr("2", [&d]() -> adc_result_t<double> { return d; }, nullptr);
|
||||||
|
|
||||||
|
|||||||
@@ -102,37 +102,33 @@ inline std::error_code make_error_code(AdcDeviceErrorCode ec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace details
|
|
||||||
{
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept snplib_getter_c = std::same_as<T, std::nullptr_t> || requires(T t) {
|
concept adclib_attr_getter_c = std::same_as<T, std::nullptr_t> || requires(T t) {
|
||||||
{ t() } -> adc_result_c;
|
{ t() } -> adc_result_c;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept snplib_setter_c =
|
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<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>);
|
std::same_as<adc_error_t, typename snplib::snplib_func_traits_t<T>::ret_t>);
|
||||||
|
|
||||||
|
|
||||||
// deduce value type from getter and setter
|
// deduce value type from getter and setter
|
||||||
template <snplib_getter_c GT, snplib_setter_c ST>
|
template <adclib_attr_getter_c GT, adclib_attr_setter_c ST>
|
||||||
using snplib_attr_value_deduced_t =
|
using snplib_attr_value_deduced_t =
|
||||||
std::conditional_t<std::is_null_pointer_v<GT>,
|
std::conditional_t<std::is_null_pointer_v<GT>,
|
||||||
std::conditional_t<std::is_null_pointer_v<ST>, void, snplib::snplib_func_arg1_t<ST>>,
|
std::conditional_t<std::is_null_pointer_v<ST>, void, snplib::snplib_func_arg1_t<ST>>,
|
||||||
typename std::invoke_result_t<GT>::value_type>;
|
typename std::invoke_result_t<GT>::value_type>;
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template <std::formattable<char> ATTR_ID_T = std::string_view, std::formattable<char> CMD_ID_T = std::string_view>
|
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
|
class AdcGenericDevice
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
template <typename VT>
|
template <typename VT>
|
||||||
struct attr_t {
|
struct attr_t {
|
||||||
ATTR_ID_T id;
|
|
||||||
|
|
||||||
std::function<adc_result_t<VT>()> getter;
|
std::function<adc_result_t<VT>()> getter;
|
||||||
std::function<adc_error_t(VT const&)> setter;
|
std::function<adc_error_t(VT const&)> setter;
|
||||||
|
|
||||||
@@ -178,9 +174,9 @@ protected:
|
|||||||
attr_proxy_t(AdcGenericDevice& dev, ATTR_ID_T id) : _dev(dev), _id(std::move(id)) {}
|
attr_proxy_t(AdcGenericDevice& dev, ATTR_ID_T id) : _dev(dev), _id(std::move(id)) {}
|
||||||
|
|
||||||
template <typename VT>
|
template <typename VT>
|
||||||
operator adc_result_t<VT>()
|
operator adc_result_t<VT>() const
|
||||||
{
|
{
|
||||||
auto const& attr = _dev._attrs.template get<attr_t<VT>>(_id);
|
auto attr = _dev._attrs.template get<attr_t<VT>>(_id);
|
||||||
if (attr) {
|
if (attr) {
|
||||||
if (attr.value().getter) {
|
if (attr.value().getter) {
|
||||||
return attr.value().getter();
|
return attr.value().getter();
|
||||||
@@ -200,7 +196,7 @@ protected:
|
|||||||
template <typename VT>
|
template <typename VT>
|
||||||
adc_error_t operator=(VT&& val)
|
adc_error_t operator=(VT&& val)
|
||||||
{
|
{
|
||||||
auto const& attr = _dev._attrs.template get<attr_t<VT>>(_id);
|
auto attr = _dev._attrs.template get<attr_t<VT>>(_id);
|
||||||
if (attr) {
|
if (attr) {
|
||||||
if (attr.value().setter) {
|
if (attr.value().setter) {
|
||||||
return attr.value().setter(std::forward<VT>(val));
|
return attr.value().setter(std::forward<VT>(val));
|
||||||
@@ -221,16 +217,26 @@ protected:
|
|||||||
ATTR_ID_T _id;
|
ATTR_ID_T _id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DEV_ID_T _devId;
|
||||||
|
|
||||||
std::unordered_map<CMD_ID_T, std::function<void()>> _commands{};
|
std::unordered_map<CMD_ID_T, std::function<void()>> _commands{};
|
||||||
snplib::HeterogenMap<ATTR_ID_T> _attrs{};
|
snplib::HeterogenMap<ATTR_ID_T> _attrs{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef DEV_ID_T device_id_t;
|
||||||
typedef ATTR_ID_T attr_id_t;
|
typedef ATTR_ID_T attr_id_t;
|
||||||
typedef CMD_ID_T cmd_id_t;
|
typedef CMD_ID_T cmd_id_t;
|
||||||
|
|
||||||
enum AttrAccessType { ATTR_ACCESS_RW, ATTR_ACCESS_RO, ATTR_ACCESS_WO };
|
enum AttrAccessType { ATTR_ACCESS_RW, ATTR_ACCESS_RO, ATTR_ACCESS_WO };
|
||||||
|
|
||||||
AdcGenericDevice() {}
|
AdcGenericDevice(device_id_t id) : _devId(id) {}
|
||||||
|
|
||||||
|
virtual ~AdcGenericDevice() = default;
|
||||||
|
|
||||||
|
device_id_t id() const
|
||||||
|
{
|
||||||
|
return _devId;
|
||||||
|
}
|
||||||
|
|
||||||
template <snplib::snplib_callable_c ET>
|
template <snplib::snplib_callable_c ET>
|
||||||
void addCommand(CMD_ID_T id, ET&& exec_func)
|
void addCommand(CMD_ID_T id, ET&& exec_func)
|
||||||
@@ -239,24 +245,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// template <typename GT, typename ST, typename... VTs>
|
// template <typename GT, typename ST, typename... VTs>
|
||||||
template <details::snplib_getter_c GT, details::snplib_setter_c ST, typename... VTs>
|
template <adclib_attr_getter_c GT, adclib_attr_setter_c ST>
|
||||||
void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter, std::tuple<VTs...> = std::tuple())
|
void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter)
|
||||||
{
|
{
|
||||||
// static_assert(!(std::is_null_pointer_v<GT> && std::is_null_pointer_v<ST>),
|
using v_t = snplib_attr_value_deduced_t<GT, ST>;
|
||||||
// "Getter and setter cannot be nullptr_t at the same time!");
|
|
||||||
|
|
||||||
// // deduce attribute value type
|
|
||||||
// using ret_t = std::invoke_result_t<GT>;
|
|
||||||
|
|
||||||
// static_assert(adc_result_c<ret_t>, "Invalid return type of the getter!");
|
|
||||||
|
|
||||||
// using v_t = typename ret_t::value_type;
|
|
||||||
|
|
||||||
// static_assert(std::invocable<ST, v_t const&>, "Invalid setter type!");
|
|
||||||
// static_assert(std::convertible_to<std::invoke_result_t<ST, v_t const&>, adc_error_t>,
|
|
||||||
// "Invalid return type of the setter!");
|
|
||||||
|
|
||||||
using v_t = details::snplib_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!");
|
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>) {
|
if constexpr (!std::is_null_pointer_v<GT> && !std::is_null_pointer_v<ST>) {
|
||||||
@@ -264,34 +256,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
_attrs.push(std::move(id), attr_t<v_t>{.getter = std::forward<GT>(getter), .setter = std::forward<ST>(setter)});
|
_attrs.push(std::move(id), attr_t<v_t>{.getter = std::forward<GT>(getter), .setter = std::forward<ST>(setter)});
|
||||||
|
|
||||||
// if constexpr (sizeof...(VTs)) {
|
|
||||||
// auto func = [id, this]<size_t I>() {
|
|
||||||
// using u_t = std::tuple_element_t<I, std::tuple<VTs...>>;
|
|
||||||
// if constexpr (!requires(u_t u, v_t v) {
|
|
||||||
// u = v;
|
|
||||||
// v = u;
|
|
||||||
// }) {
|
|
||||||
// static_assert(false, "Invalid user type!");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if constexpr (!std::same_as<u_t, v_t>) {
|
|
||||||
// _attrs.push(std::move(id), attr_t<u_t>{.getter = [id, this]() -> adc_result_t<u_t> {
|
|
||||||
// auto const& attr = _attrs.template
|
|
||||||
// get<attr_t<v_t>>(id); if (attr) {
|
|
||||||
// adc_result_t v = attr.getter();
|
|
||||||
// if (v) {
|
|
||||||
// return
|
|
||||||
// adc_result_t(static_cast<u_t>(v.value()));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return AdcDeviceErrorCode::ERROR_UNKNOWN;
|
|
||||||
// },
|
|
||||||
// .setter = []() {}});
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
adc_error_t operator()(CMD_ID_T id)
|
adc_error_t operator()(CMD_ID_T id)
|
||||||
|
|||||||
Reference in New Issue
Block a user