#include #include #include "../device/adc_device.h" #include "../device/adc_device_attribute.h" #include "../device/adc_device_command.h" #include "../net/adc_endpoint.h" #include "../net/adc_netproto.h" #include "../net/asio/adc_device_netserver_asio.h" class Device1 : public adc::AdcGenericDevice, adc::AdcDeviceCommand> { typedef adc::AdcGenericDevice, adc::AdcDeviceCommand> base_t; public: template Device1(R&& id) : base_t(id) { } }; class Device2 : public adc::AdcGenericDevice, adc::AdcDeviceCommand> { typedef adc::AdcGenericDevice, adc::AdcDeviceCommand> base_t; public: template Device2(R&& id) : base_t(id) { } }; using t_t = std::tuple; static t_t tuple_val{7.7, "TUPVAL"}; t_t gt() { return tuple_val; } void st(const t_t& v) { tuple_val = v; } int main(int argc, char* argv[]) { /* CREATE AND INIT DEVICES */ int dev1_val1 = 1; Device1 dev1("DEVICE#1"); Device2 dev2("DEVICE#2"); // device#1 dev1.addCommand("DEV1::COM1", []() { std::cout << "EXEC DEV1::COM1\n"; }); dev1.addAttribute( "DEV1::ATTR1", [&dev1_val1]() { return dev1_val1; }, [&dev1_val1](const int& v) { dev1_val1 = v; }); dev1.addAttribute("DEV1::ATTR2", gt, st); // device#2 // read-only attr dev2.addAttribute(0x1ul, [&dev1_val1]() { return dev1_val1; }); // write-only dev2.addAttribute(0xfful, [&dev1_val1](const int& v) { dev1_val1 = v; }); /* COMMANDLINE OPTS */ cxxopts::Options options(argv[0], "ADC-library test device network server (ASIO implementation)\n"); options.allow_unrecognised_options(); options.add_options()("h,help", "Print usage"); options.add_options()( "endpoints", "endpoints server will be listening for. For 'local' endpoint the '@' symbol at the beginning of the path " "means " "abstract namespace socket.", cxxopts::value>()->default_value("local://stream/ADC_ASIO_TEST_SERVER")); options.positional_help("[endpoint0] [enpoint1] ... [endpointN]"); options.parse_positional({"endpoints"}); try { auto opt_result = options.parse(argc, argv); if (opt_result["help"].count()) { std::cout << options.help(); std::cout << "\n"; std::cout << "[endpoint0] [enpoint1] ... [endpointN] - endpoints server will be listening for. For 'local' " "endpoint the '@' symbol at the beginning of the path " "means abstract namespace socket." << "\n"; return 0; } asio::io_context io_ctx; asio::signal_set signals(io_ctx, SIGINT, SIGTERM); signals.async_wait([&](std::error_code, int) { io_ctx.stop(); }); using server_t = adc::impl::AdcDeviceNetServerASIO; adc::impl::AdcDeviceNetServerASIO server("TEST SRV", io_ctx); server.setupSignals(); server.addDevice(&dev1); server.addDevice( &dev2, {}, // adc::traits::adc_char_identity{}, adc::utils::AdcDefaultValueConverter<>::deserialize); auto epnt = opt_result["endpoints"].as>(); for (auto& ep : epnt) { adc::AdcEndpointParser epn(ep); if (epn.isValid()) { if (epn.isLocalSeqpacket() || epn.isLocalStream()) { if (epn.path()[0] == '@') { // replace '@' to '\0' (use of UNIX abstract namespace) auto it = std::ranges::find(ep, '@'); *it = '\0'; epn = adc::AdcEndpointParser(ep); } } std::cout << "try to start listenning at '" << ep << "' ..."; server.start>(epn); std::cout << "\tOK\n"; } else { std::cerr << "Unrecognized endpoint: '" << ep << "'! Ignore!\n"; } } io_ctx.run(); } catch (const cxxopts::exceptions::exception& ex) { std::cerr << "\nAn error occured while parsing input options: " << ex.what() << "\n"; return 127; } catch (const std::system_error& ex) { std::cerr << "\nAn error ocured: " << ex.what() << "\n"; std::cerr << "Category: " << ex.code().category().name() << "; message: " << ex.code().message() << "\n"; return 128; } return 0; }