From ae2d05eee4ffcec4c0611d907779ce8ef61d3a6e Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sun, 19 Jul 2015 21:39:28 +0200 Subject: o Going back to a bunch of cpp files instead of launcher+bunch of header files. This ends up with an easier build file and faster builds with CMake's "OBJECT" library type. --- .clang-format | 2 +- README.md | 2 +- apps/CMakeLists.txt | 74 +++++++---------- apps/SoilMoisture.cpp | 3 +- apps/apps.cpp | 75 +++++++++++++++++ apps/apps.h | 34 +++++--- apps/ble-inspect-device.cpp | 79 ++++++++++++++++++ apps/ble-inspect-device.h | 74 ----------------- apps/ble-scan.cpp | 85 +++++++++++++++++++ apps/ble-scan.h | 79 ------------------ apps/generate.cpp | 76 ----------------- apps/launcher.cpp | 104 ------------------------ apps/sample-add-timestamp.cpp | 101 +++++++++++++++++++++++ apps/sample-add-timestamp.h | 95 ---------------------- apps/sample-convert.cpp | 124 ++++++++++++++++++++++++++++ apps/sample-convert.h | 118 --------------------------- apps/sample-select.cpp | 124 ++++++++++++++++++++++++++++ apps/sample-select.h | 119 --------------------------- apps/sm-db-insert.cpp | 89 ++++++++++++++++++++ apps/sm-db-insert.h | 82 ------------------- apps/sm-db-select.cpp | 84 +++++++++++++++++++ apps/sm-db-select.h | 78 ------------------ apps/sm-get-value.cpp | 185 ++++++++++++++++++++++++++++++++++++++++++ apps/sm-get-value.h | 180 ---------------------------------------- apps/sm-serial-read-all.cpp | 171 ++++++++++++++++++++++++++++++++++++++ apps/sm-serial-read-all.h | 167 -------------------------------------- apps/sm-serial-read.cpp | 111 +++++++++++++++++++++++++ apps/sm-serial-read.h | 107 ------------------------ 28 files changed, 1282 insertions(+), 1340 deletions(-) create mode 100644 apps/ble-inspect-device.cpp delete mode 100644 apps/ble-inspect-device.h create mode 100644 apps/ble-scan.cpp delete mode 100644 apps/ble-scan.h delete mode 100644 apps/generate.cpp delete mode 100644 apps/launcher.cpp create mode 100644 apps/sample-add-timestamp.cpp delete mode 100644 apps/sample-add-timestamp.h create mode 100644 apps/sample-convert.cpp delete mode 100644 apps/sample-convert.h create mode 100644 apps/sample-select.cpp delete mode 100644 apps/sample-select.h create mode 100644 apps/sm-db-insert.cpp delete mode 100644 apps/sm-db-insert.h create mode 100644 apps/sm-db-select.cpp delete mode 100644 apps/sm-db-select.h create mode 100644 apps/sm-get-value.cpp delete mode 100644 apps/sm-get-value.h create mode 100644 apps/sm-serial-read-all.cpp delete mode 100644 apps/sm-serial-read-all.h create mode 100644 apps/sm-serial-read.cpp delete mode 100644 apps/sm-serial-read.h diff --git a/.clang-format b/.clang-format index e480c65..94252a1 100644 --- a/.clang-format +++ b/.clang-format @@ -12,7 +12,7 @@ AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: true -AllowShortFunctionsOnASingleLine: None +AllowShortFunctionsOnASingleLine: Empty AlwaysBreakAfterDefinitionReturnType: false AlwaysBreakTemplateDeclarations: true AlwaysBreakBeforeMultilineStrings: true diff --git a/README.md b/README.md index e4603e4..5b5f5b1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Building: mkdir build cd build - cmake .. + cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/opt/ble-toys make -j This will build a Debug release by default. Add `-DCMAKE_BUILD_TYPE=Release` to build a release build. diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 8ba5a0a..b8255d1 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -9,6 +9,16 @@ list(APPEND APPS sm-get-value) list(APPEND APPS sm-serial-read) list(APPEND APPS sm-serial-read-all) +add_library(apps OBJECT + apps.cpp apps.h + SoilMoisture.cpp SoilMoisture.h) +target_include_directories(apps + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC "${PROJECT_SOURCE_DIR}/include" + PUBLIC "${PROJECT_SOURCE_DIR}/json/src" + PUBLIC "${PROJECT_SOURCE_DIR}/sensor/include" + PUBLIC "${LOG4CPLUS_INCLUDE_DIRECTORIES}") + # Boost find_package(Boost COMPONENTS regex system program_options REQUIRED) @@ -30,50 +40,24 @@ if(LOG4CPLUS_LIBRARIES MATCHES NOTFOUND) message(FATAL_ERROR "Could not find log4cplus library files") endif() -add_executable(generate generate.cpp) - -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/generated) - -add_custom_command( - OUTPUT generated/apps-list.gen.h - COMMAND generate ${CMAKE_CURRENT_BINARY_DIR}/generated/apps-list.gen.h ${APPS} - DEPENDS generate ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt) - -foreach(app ${APPS}) - list(APPEND APPS_SOURCES ${app}.h) -endforeach() - -list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/generated/apps-list.gen.h) -list(APPEND SOURCES SoilMoisture.cpp SoilMoisture.h) -list(APPEND SOURCES apps.cpp apps.h) - -add_executable(launcher launcher.cpp - ${SOURCES} - ${APPS_SOURCES}) -target_include_directories(launcher - PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/generated - PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} - PUBLIC "${PROJECT_SOURCE_DIR}/include" - PUBLIC "${PROJECT_SOURCE_DIR}/json/src" - PUBLIC "${PROJECT_SOURCE_DIR}/sensor/include" - PUBLIC "${LOG4CPLUS_INCLUDE_DIRECTORIES}") - -target_link_libraries(launcher ble) -target_link_libraries(launcher trygvis-sensor) -target_link_libraries(launcher ${Boost_LIBRARIES}) -target_link_libraries(launcher ${BLUEZ_LIBRARIES}) -target_link_libraries(launcher ${PQXX_LIBRARIES}) -target_link_libraries(launcher ${LOG4CPLUS_LIBRARIES}) -target_link_libraries(launcher ${CMAKE_THREAD_LIBS_INIT}) - foreach(app ${APPS}) - add_custom_command( - TARGET launcher POST_BUILD - COMMAND ln -sf ../libexec/launcher ${app}) - - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${app} DESTINATION bin) + add_executable(${app} ${app}.cpp $) + + target_include_directories(${app} + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC "${PROJECT_SOURCE_DIR}/include" + PUBLIC "${PROJECT_SOURCE_DIR}/json/src" + PUBLIC "${PROJECT_SOURCE_DIR}/sensor/include" + PUBLIC "${LOG4CPLUS_INCLUDE_DIRECTORIES}") + + target_link_libraries(${app} + ble + trygvis-sensor + ${Boost_LIBRARIES} + ${BLUEZ_LIBRARIES} + ${PQXX_LIBRARIES} + ${LOG4CPLUS_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT}) + + install(TARGETS ${app} RUNTIME DESTINATION bin) endforeach() - -set_target_properties(launcher PROPERTIES INSTALL_RPATH "\\$ORIGIN/../lib/trygvis") -install(TARGETS launcher - RUNTIME DESTINATION libexec) diff --git a/apps/SoilMoisture.cpp b/apps/SoilMoisture.cpp index 044ba21..1d6888c 100644 --- a/apps/SoilMoisture.cpp +++ b/apps/SoilMoisture.cpp @@ -69,8 +69,7 @@ SoilMoisture SoilMoisture::create(shared_ptr gatt) { } SoilMoisture::SoilMoisture(shared_ptr gatt, BluetoothGattService &s, BluetoothGattCharacteristic &c) - : gatt(std::move(gatt)), s(s), c(c) { -} + : gatt(std::move(gatt)), s(s), c(c) {} ByteBuffer SoilMoisture::writeAndRead(ByteBuffer &requestBytes) { requestBytes.setCursor(0); diff --git a/apps/apps.cpp b/apps/apps.cpp index b353e85..916b0e0 100644 --- a/apps/apps.cpp +++ b/apps/apps.cpp @@ -1,5 +1,7 @@ #include "apps.h" #include +#include +#include namespace trygvis { namespace apps { @@ -43,5 +45,78 @@ std::string get_hostname() { void app_execution::usage() { cerr << desc << endl; } + +const po::options_description logging_options() { + po::options_description desc; + + return desc; +} + +void setup_logging(string app_name) { + Appender *console = new ConsoleAppender(true, true); + + string pattern = string("%-5p ") /*"%6r "*/ + app_name + "/%-20c %m%n"; // add %M (function name) + + PatternLayout *layout = new PatternLayout(LOG4CPLUS_TEXT(pattern)); + console->setLayout(auto_ptr(layout)); + + Hierarchy &h = Logger::getDefaultHierarchy(); + h.getRoot().addAppender(SharedAppenderPtr(console)); +} + +int launch_app(app *app, int argc, const char *argv[]) { + po::options_description all("Options"); + + auto all_options = all.add_options(); + all_options("help", "This help message"); + app->add_options(all_options); + + all.add(logging_options()); + app->add_extra_options(all); + + po::variables_map vm; + + try { + auto parsed = po::parse_command_line(argc, argv, all); + po::store(parsed, vm); + + po::notify(vm); + + auto unrecognized = po::collect_unrecognized(parsed.options, po::include_positional); + + if (vm.count("help")) { + cerr << all << "\n"; + return EXIT_FAILURE; + } + + if (unrecognized.size()) { + cerr << "Unrecognized option: " << unrecognized.at(0) << "\n"; + return EXIT_FAILURE; + } + + setup_logging(app->app_name); + + Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("main")); + + app_execution execution(all, vm, logger); + + return app->main(execution); + } catch (po::required_option &e) { + cerr << "Missing required option: " << e.get_option_name() << endl; + cerr << all << endl; + return EXIT_FAILURE; + } catch (po::unknown_option &e) { + cerr << e.what() << endl; + return EXIT_FAILURE; + } +} + +int real_main(app *app, int argc, const char *argv[]) { + if (argc == 0) { + return EXIT_FAILURE; + } + + return launch_app(app, argc, argv); +} } } diff --git a/apps/apps.h b/apps/apps.h index 4a69b05..e9338a4 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -16,8 +16,7 @@ using json = nlohmann::json; class missing_key : public std::runtime_error { public: - missing_key(const json::string_t key) : runtime_error("Missing key: " + key), key(key) { - } + missing_key(const json::string_t key) : runtime_error("Missing key: " + key), key(key) {} const json::string_t key; }; @@ -33,11 +32,17 @@ T get(json j, std::string key) { return ref; } +class unknown_app : public std::runtime_error { +public: + unknown_app(const std::string &app_name) : runtime_error("Unknown application: " + app_name), app_name(app_name) {} + + const std::string app_name; +}; + class app_execution { public: app_execution(po::options_description desc, po::variables_map vm, Logger logger) - : desc(desc), vm(vm), logger(logger) { - } + : desc(desc), vm(vm), logger(logger) {} const po::options_description desc; const po::variables_map vm; @@ -48,14 +53,19 @@ public: class app { public: - app(std::string app_name) : app_name(app_name) { - } + app(std::string app_name) : app_name(app_name) {} + + app(const app &) = delete; + + app(app &&) = default; virtual ~app() = default; - virtual void add_options(po::options_description_easy_init &options){}; + app &operator=(const app &) = delete; + + virtual void add_options(po::options_description_easy_init &options) {} - virtual void add_extra_options(po::options_description &options){}; + virtual void add_extra_options(po::options_description &options) {} virtual int main(app_execution &execution) = 0; @@ -64,14 +74,14 @@ public: std::string get_hostname(); +int real_main(app *app, int argc, const char *argv[]); + template class noop_delete { public: - void operator()(T *) const { - } + void operator()(T *) const {} }; -static inline void noop_deleter(void *) { -} +static inline void noop_deleter(void *) {} } } diff --git a/apps/ble-inspect-device.cpp b/apps/ble-inspect-device.cpp new file mode 100644 index 0000000..763dd9a --- /dev/null +++ b/apps/ble-inspect-device.cpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include "ble/Bluetooth.h" +#include "apps.h" + +namespace trygvis { +namespace apps { + +using namespace std; +using namespace trygvis::bluetooth; +using namespace trygvis::apps; + +class ble_inspect_device : public app { +public: + ble_inspect_device() : app("ble-inspect-device") {} + + ~ble_inspect_device() = default; + + void add_options(po::options_description_easy_init &options) override { + options("device", po::value()->required(), "The MAC of the device to inspect"); + } + + void scan_callback(BluetoothDevice &device) { + cout << "Inspecting device: " << device.getMac().str() << endl; + + auto gatt = device.connectGatt(); + + gatt->discoverServices(); + + vector services = gatt->getServices(); + cout << "Device has " << services.size() << " services" << endl; + + for (auto &s : services) { + const vector characteristics = s->getCharacteristics(); + + cout << "Service: UUID: " << s->getUuid() << ", has " << characteristics.size() << " characteristics" + << endl; + + for (auto &c : characteristics) { + cout << "Characteristic: UUID: " << c->getUuid() << ", properties: " << (int) c->getProperties() + << endl; + } + } + } + + int main(app_execution &execution) override { + string mac_str = execution.vm["device"].as(); + + BluetoothSystem bluetoothSystem; + + try { + Mac mac = Mac::parseMac(mac_str); + + shared_ptr adapter = getAdapter(0); + + BluetoothDevice &device = adapter->getDevice(mac); + + scan_callback(device); + + return EXIT_SUCCESS; + } catch (std::runtime_error ex) { + cout << "std::runtime_error: " << ex.what() << endl; + return EXIT_FAILURE; + } catch (std::exception ex) { + cout << "std::exception: " << ex.what() << endl; + return EXIT_FAILURE; + } + } +}; +} +} + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new ble_inspect_device(), argc, argv); +} diff --git a/apps/ble-inspect-device.h b/apps/ble-inspect-device.h deleted file mode 100644 index ff19ba1..0000000 --- a/apps/ble-inspect-device.h +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include -#include -#include "ble/Bluetooth.h" -#include "apps.h" - -namespace trygvis { -namespace apps { - -using namespace std; -using namespace trygvis::bluetooth; -using namespace trygvis::apps; - -class ble_inspect_device : public app { -public: - ble_inspect_device() : app("ble-inspect-device") { - } - - ~ble_inspect_device() = default; - - void add_options(po::options_description_easy_init &options) override { - options("device", po::value()->required(), "The MAC of the device to inspect"); - } - - void scan_callback(BluetoothDevice &device) { - cout << "Inspecting device: " << device.getMac().str() << endl; - - auto gatt = device.connectGatt(); - - gatt->discoverServices(); - - vector services = gatt->getServices(); - cout << "Device has " << services.size() << " services" << endl; - - for (auto &s : services) { - const vector characteristics = s->getCharacteristics(); - - cout << "Service: UUID: " << s->getUuid() << ", has " << characteristics.size() << " characteristics" - << endl; - - for (auto &c : characteristics) { - cout << "Characteristic: UUID: " << c->getUuid() << ", properties: " << (int) c->getProperties() - << endl; - } - } - } - - int main(app_execution &execution) override { - string mac_str = execution.vm["device"].as(); - - BluetoothSystem bluetoothSystem; - - try { - Mac mac = Mac::parseMac(mac_str); - - shared_ptr adapter = getAdapter(0); - - BluetoothDevice &device = adapter->getDevice(mac); - - scan_callback(device); - - return EXIT_SUCCESS; - } catch (std::runtime_error ex) { - cout << "std::runtime_error: " << ex.what() << endl; - return EXIT_FAILURE; - } catch (std::exception ex) { - cout << "std::exception: " << ex.what() << endl; - return EXIT_FAILURE; - } - } -}; -} -} diff --git a/apps/ble-scan.cpp b/apps/ble-scan.cpp new file mode 100644 index 0000000..839a9fa --- /dev/null +++ b/apps/ble-scan.cpp @@ -0,0 +1,85 @@ +#include "ble/Bluetooth.h" +#include "apps.h" + +#include +#include "apps.h" + +namespace trygvis { +namespace apps { + +using namespace std; +using namespace trygvis::bluetooth; +using namespace trygvis::apps; + +namespace ble_scan_utils { + +static std::function onSignal; + +static void signal_handler(int signal) { + onSignal(signal); +} +} + +class ble_scan : public app { +public: + ble_scan() : app("ble-scan") {} + + ~ble_scan() = default; + + void add_options(po::options_description_easy_init &options) override { + options("adapter", po::value()->default_value(0), "Which adapter to use."); + } + + int main(app_execution &execution) override { + BluetoothSystem bluetoothSystem; + shared_ptr adapter; + + struct sigaction sigIntHandler; + + ble_scan_utils::onSignal = [&](int signal) { adapter->stopScan(); }; + + sigIntHandler.sa_handler = &ble_scan_utils::signal_handler; + sigemptyset(&sigIntHandler.sa_mask); + sigIntHandler.sa_flags = 0; + + sigaction(SIGINT, &sigIntHandler, NULL); + + try { + auto adapter_index = execution.vm["adapter"].as(); + + adapter = getAdapter(adapter_index); + + set seen_devices; + + cout << "Scanning with adapter #" << adapter_index << ", mac=" << adapter->getMac().str() << endl; + + adapter->runScan([&](BluetoothDevice &device) { + auto mac = device.getMac(); + + cout << "Found: " << mac.str() << endl; + + seen_devices.insert(mac); + }); + + cout << "Stopped. Found " << seen_devices.size() << " devices." << endl; + + for_each(begin(seen_devices), end(seen_devices), [&](auto mac) { cout << mac.str() << endl; }); + + return EXIT_SUCCESS; + } catch (std::runtime_error ex) { + cout << "std::runtime_error: " << ex.what() << endl; + return EXIT_FAILURE; + } catch (std::exception ex) { + cout << "std::exception: " << ex.what() << endl; + return EXIT_FAILURE; + } + } +}; +} +} + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new ble_scan(), argc, argv); +} diff --git a/apps/ble-scan.h b/apps/ble-scan.h deleted file mode 100644 index 2c183e3..0000000 --- a/apps/ble-scan.h +++ /dev/null @@ -1,79 +0,0 @@ -#include "ble/Bluetooth.h" -#include "apps.h" - -#include - -namespace trygvis { -namespace apps { - -using namespace std; -using namespace trygvis::bluetooth; -using namespace trygvis::apps; - -namespace ble_scan_utils { - -static std::function onSignal; - -static void signal_handler(int signal) { - onSignal(signal); -} -} - -class ble_scan : public app { -public: - ble_scan() : app("ble-scan") { - } - - ~ble_scan() = default; - - void add_options(po::options_description_easy_init &options) override { - options("adapter", po::value()->default_value(0), "Which adapter to use."); - } - - int main(app_execution &execution) override { - BluetoothSystem bluetoothSystem; - shared_ptr adapter; - - struct sigaction sigIntHandler; - - ble_scan_utils::onSignal = [&](int signal) { adapter->stopScan(); }; - - sigIntHandler.sa_handler = &ble_scan_utils::signal_handler; - sigemptyset(&sigIntHandler.sa_mask); - sigIntHandler.sa_flags = 0; - - sigaction(SIGINT, &sigIntHandler, NULL); - - try { - auto adapter_index = execution.vm["adapter"].as(); - - adapter = getAdapter(adapter_index); - - set seen_devices; - - cout << "Scanning with adapter #" << adapter_index << ", mac=" << adapter->getMac().str() << endl; - - adapter->runScan([&](BluetoothDevice &device) { - auto mac = device.getMac(); - - cout << "Found: " << mac.str() << endl; - - seen_devices.insert(mac); - }); - - cout << "Stopped. Found " << seen_devices.size() << " devices." << endl; - - for_each(begin(seen_devices), end(seen_devices), [&](auto mac) { cout << mac.str() << endl; }); - - return EXIT_SUCCESS; - } catch (std::runtime_error ex) { - cout << "std::runtime_error: " << ex.what() << endl; - return EXIT_FAILURE; - } catch (std::exception ex) { - cout << "std::exception: " << ex.what() << endl; - return EXIT_FAILURE; - } - } -}; -} -} diff --git a/apps/generate.cpp b/apps/generate.cpp deleted file mode 100644 index a088e6e..0000000 --- a/apps/generate.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include -#include - -using namespace std; - -int main(int argc, char *argv[]) { - cout << "Generating " << argv[1] << endl; - - ofstream out; - - out.open(argv[1], ofstream::out); - - if (!out.is_open()) { - return EXIT_FAILURE; - } - - out << "#pragma once" << endl - << endl - << "#include " << endl - << "#include " << endl - << endl; - - vector> apps; - - regex r("-"); - for (int i = 2; i < argc; i++) { - string app_name = argv[i]; - stringstream buf; - - regex_replace(ostream_iterator(buf), app_name.begin(), app_name.end(), r, "_"); - string class_name = buf.str(); - - apps.emplace_back(make_pair(app_name, class_name)); - } - - for_each(begin(apps), end(apps), [&](pair pair) { - // out << "class " << pair.second << ";" << endl; - out << "#include \"" << pair.first << ".h\"" << endl; - }); - out << endl; - - bool first = true; - - out << "namespace trygvis {" << endl - << "namespace apps {" << endl - << endl - << "template" << endl - << "int launch_app(int argc, const char *argv[]);" << endl - << endl; - - out << "int launch(const std::string app_name, int argc, const char *argv[]) {" << endl; - - for_each(begin(apps), end(apps), [&](auto pair) { - out << " "; - if (!first) { - out << "} else "; - } else { - first = false; - } - - out << "if (boost::ends_with(app_name, \"" << pair.first << "\")) {" << endl - << " return launch_app<" << pair.second << ">(argc, argv);" << endl; - }); - - out << " } else {" << endl - << " return EXIT_FAILURE;" << endl - << " }" << endl - << "}" << endl - << endl - << "}" << endl - << "}" << endl; - - return EXIT_SUCCESS; -} diff --git a/apps/launcher.cpp b/apps/launcher.cpp deleted file mode 100644 index 0b97a59..0000000 --- a/apps/launcher.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "apps.h" -#include "apps-list.gen.h" -#include -#include - -namespace trygvis { -namespace apps { - -using namespace std; - -const po::options_description logging_options() { - po::options_description desc; - - return desc; -} - -void setup_logging(string app_name) { - Appender *console = new ConsoleAppender(true, true); - - string pattern = string("%-5p ") /*"%6r "*/ + app_name + "/%-20c %m%n"; // add %M (function name) - - PatternLayout *layout = new PatternLayout(LOG4CPLUS_TEXT(pattern)); - console->setLayout(auto_ptr(layout)); - - Hierarchy &h = Logger::getDefaultHierarchy(); - h.getRoot().addAppender(SharedAppenderPtr(console)); -} - -template -int launch_app(int argc, const char *argv[]) { - App app; - - po::options_description all("Options"); - - auto all_options = all.add_options(); - all_options("help", "This help message"); - app.add_options(all_options); - - all.add(logging_options()); - app.add_extra_options(all); - - po::variables_map vm; - - try { - auto parsed = po::parse_command_line(argc, argv, all); - po::store(parsed, vm); - - po::notify(vm); - - auto unrecognized = po::collect_unrecognized(parsed.options, po::include_positional); - - if (vm.count("help")) { - cerr << all << "\n"; - return EXIT_FAILURE; - } - - if (unrecognized.size()) { - cerr << "Unrecognized option: " << unrecognized.at(0) << "\n"; - return EXIT_FAILURE; - } - - setup_logging(app.app_name); - - Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("main")); - - app_execution execution(all, vm, logger); - - return app.main(execution); - } catch (po::required_option &e) { - cerr << "Missing required option: " << e.get_option_name() << endl; - cerr << all << endl; - return EXIT_FAILURE; - } catch (po::unknown_option &e) { - cerr << e.what() << endl; - return EXIT_FAILURE; - } -} -} -} - -using namespace std; -using namespace trygvis::apps; - -int main(int argc, const char *argv[]) { - if (argc == 0) { - return EXIT_FAILURE; - } - - string app_name; - if (boost::ends_with(argv[0], "launcher")) { - if (argc <= 1) { - cerr << "Missing required argument: app" << endl; - return EXIT_FAILURE; - } - - app_name = argv[1]; - --argc; - ++argv; - } else { - app_name = argv[0]; - } - - return launch(app_name, argc, argv); -} diff --git a/apps/sample-add-timestamp.cpp b/apps/sample-add-timestamp.cpp new file mode 100644 index 0000000..8bc4bac --- /dev/null +++ b/apps/sample-add-timestamp.cpp @@ -0,0 +1,101 @@ +#include "trygvis/sensor.h" +#include "trygvis/sensor/io.h" +#include "apps.h" +#include +#include "apps.h" + +namespace trygvis { +namespace apps { + +using namespace std; +using namespace trygvis::apps; +using namespace trygvis::sensor; +using namespace trygvis::sensor::io; +namespace po = boost::program_options; + +class TimestampAddingSampleOutputStream : public SampleOutputStream { +public: + TimestampAddingSampleOutputStream(shared_ptr output, KeyDictionary &dict, string timestamp_name) + : timestamp_key(dict.indexOf(timestamp_name)) { + if (input_time_resolution_ == time_resolution::MILLISECONDS) { + factor = 1000; + } else { + factor = 1; + } + } + + virtual void write(SampleRecord const &sample) override { + time_t now = time(NULL) * factor; + + SampleRecord updated_sample(sample); + + updated_sample.set(timestamp_key, std::to_string(now)); + + output_->write(updated_sample); + }; + +private: + const SampleKey *timestamp_key; + time_resolution input_time_resolution_; + int factor; + shared_ptr output_; +}; + +class sample_add_timestamp : public app { +private: + string timestamp_name; + time_resolution resolution; + sample_format_type output_format; + +public: + sample_add_timestamp() : app("sample-add-timestamp") {} + + ~sample_add_timestamp() = default; + + void add_options(po::options_description_easy_init &options) override { + options("resolution", po::value(&resolution)->default_value(time_resolution::SECONDS)); + options("timestamp-name", po::value(×tamp_name)->default_value("timestamp")); + options("output-format", + po::value(&output_format)->default_value(sample_format_type::KEY_VALUE)); + } + + const int buffer_size = 1024; + + int main(app_execution &execution) override { + shared_ptr input; + + input = shared_ptr(&cin, noop_deleter); + + KeyDictionary dict; + + sample_output_stream_options options = {}; + auto unique_output_stream = + open_sample_output_stream(shared_ptr(&cout, noop_deleter), dict, output_format, options); + shared_ptr output_stream{std::move(unique_output_stream)}; + auto p = make_shared(output_stream, dict, timestamp_name); + auto parser = open_sample_stream_parser(p, dict); + + int recordCount = 0; + + while (!input->eof()) { + char buffer[buffer_size]; + input->read(buffer, buffer_size); + size_t gcount = (size_t) input->gcount(); + + recordCount++; + + mutable_buffers_1 b = boost::asio::buffer(buffer, gcount); + parser->process(b); + } + + return EXIT_SUCCESS; + }; +}; +} +} + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new sample_add_timestamp(), argc, argv); +} diff --git a/apps/sample-add-timestamp.h b/apps/sample-add-timestamp.h deleted file mode 100644 index 8439519..0000000 --- a/apps/sample-add-timestamp.h +++ /dev/null @@ -1,95 +0,0 @@ -#include "trygvis/sensor.h" -#include "trygvis/sensor/io.h" -#include "apps.h" -#include - -namespace trygvis { -namespace apps { - -using namespace std; -using namespace trygvis::apps; -using namespace trygvis::sensor; -using namespace trygvis::sensor::io; -namespace po = boost::program_options; - -class TimestampAddingSampleOutputStream : public SampleOutputStream { -public: - TimestampAddingSampleOutputStream(shared_ptr output, KeyDictionary &dict, string timestamp_name) - : timestamp_key(dict.indexOf(timestamp_name)) { - if (input_time_resolution_ == time_resolution::MILLISECONDS) { - factor = 1000; - } else { - factor = 1; - } - } - - virtual void write(SampleRecord const &sample) override { - time_t now = time(NULL) * factor; - - SampleRecord updated_sample(sample); - - updated_sample.set(timestamp_key, std::to_string(now)); - - output_->write(updated_sample); - }; - -private: - const SampleKey *timestamp_key; - time_resolution input_time_resolution_; - int factor; - shared_ptr output_; -}; - -class sample_add_timestamp : public app { -private: - string timestamp_name; - time_resolution resolution; - sample_format_type output_format; - -public: - sample_add_timestamp() : app("sample-add-timestamp") { - } - - ~sample_add_timestamp() = default; - - void add_options(po::options_description_easy_init &options) override { - options("resolution", po::value(&resolution)->default_value(time_resolution::SECONDS)); - options("timestamp-name", po::value(×tamp_name)->default_value("timestamp")); - options("output-format", - po::value(&output_format)->default_value(sample_format_type::KEY_VALUE)); - } - - const int buffer_size = 1024; - - int main(app_execution &execution) override { - shared_ptr input; - - input = shared_ptr(&cin, noop_deleter); - - KeyDictionary dict; - - sample_output_stream_options options = {}; - auto unique_output_stream = - open_sample_output_stream(shared_ptr(&cout, noop_deleter), dict, output_format, options); - shared_ptr output_stream{std::move(unique_output_stream)}; - auto p = make_shared(output_stream, dict, timestamp_name); - auto parser = open_sample_stream_parser(p, dict); - - int recordCount = 0; - - while (!input->eof()) { - char buffer[buffer_size]; - input->read(buffer, buffer_size); - size_t gcount = (size_t) input->gcount(); - - recordCount++; - - mutable_buffers_1 b = boost::asio::buffer(buffer, gcount); - parser->process(b); - } - - return EXIT_SUCCESS; - }; -}; -} -} diff --git a/apps/sample-convert.cpp b/apps/sample-convert.cpp new file mode 100644 index 0000000..f592291 --- /dev/null +++ b/apps/sample-convert.cpp @@ -0,0 +1,124 @@ +#include "trygvis/sensor.h" +#include "trygvis/sensor/io.h" +#include "json.hpp" +#include "apps.h" +#include +#include +#include "apps.h" + +namespace trygvis { +namespace apps { + +using namespace std; +using namespace trygvis::apps; +using namespace trygvis::sensor; +using namespace trygvis::sensor::io; +using boost::tokenizer; +namespace po = boost::program_options; + +class sample_convert : public app { +private: + string fields; + string timestamp_field; + bool add_timestamp; + string input_file, output_file; + sample_format_type output_format; + + string table_name; + +public: + sample_convert() : app("sample-convert") {} + + ~sample_convert() = default; + + void add_options(po::options_description_easy_init &options) override { + options("input", po::value(&input_file)->default_value("-")); + // ("input-format", po::value(&input_format)->default_value("csv")) + options("output", po::value(&output_file)->default_value("-")); + options("output-format", + po::value(&output_format)->default_value(sample_format_type::KEY_VALUE)); + options("fields", po::value(&fields)); + options("add-timestamp", po::value(&add_timestamp)->default_value(true)); + options("timestamp-field", po::value(×tamp_field)->default_value("timestamp")); + } + + void add_extra_options(po::options_description &all_options) override { + po::options_description sql("SQL"); + sql.add_options()("table-name", po::value(&table_name)); + + all_options.add(sql); + }; + + int main(app_execution &execution) override { + auto desc = execution.desc; + auto vm = execution.vm; + + KeyDictionary dict; + + istream *inputStream; + if (input_file == "-") { + inputStream = &cin; + } else { + inputStream = new ifstream(input_file); + if (inputStream->fail()) { + cerr << "Unable to open input file " << input_file << endl; + return EXIT_FAILURE; + } + } + + shared_ptr outputStream; + if (output_file == "-") { + outputStream = shared_ptr(&cout, noop_deleter); + } else { + outputStream = make_shared(output_file); + if (outputStream->fail()) { + cerr << "Unable to open output file " << output_file << endl; + return EXIT_FAILURE; + } + } + + sample_output_stream_options options; + trygvis::sensor::io::timestamp_field_option tf(timestamp_field); + + options.push_back(&tf); + + table_name_option tno(table_name); + if (table_name != "") { + options.push_back(&tno); + } + + tokenizer<> tok(fields); + output_fields_option fs; + std::copy(tok.begin(), tok.end(), std::back_inserter(fs.fields)); + if (!fs.fields.empty()) { + options.push_back(&fs); + } + + unique_ptr o = open_sample_output_stream(outputStream, dict, output_format, options); + + if (add_timestamp) { + o = make_unique(move(o), dict, timestamp_field); + } + + shared_ptr output(move(o)); + + auto input = make_shared(output, dict); + + char data[100]; + while (!inputStream->eof()) { + inputStream->get(data[0]); + auto buf = boost::asio::buffer(data, 1); + input->process(buf); + } + + return EXIT_SUCCESS; + } +}; +} +} + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new sample_convert(), argc, argv); +} diff --git a/apps/sample-convert.h b/apps/sample-convert.h deleted file mode 100644 index 9a2f99a..0000000 --- a/apps/sample-convert.h +++ /dev/null @@ -1,118 +0,0 @@ -#include "trygvis/sensor.h" -#include "trygvis/sensor/io.h" -#include "json.hpp" -#include "apps.h" -#include -#include - -namespace trygvis { -namespace apps { - -using namespace std; -using namespace trygvis::apps; -using namespace trygvis::sensor; -using namespace trygvis::sensor::io; -using boost::tokenizer; -namespace po = boost::program_options; - -class sample_convert : public app { -private: - string fields; - string timestamp_field; - bool add_timestamp; - string input_file, output_file; - sample_format_type output_format; - - string table_name; - -public: - sample_convert() : app("sample-convert") { - } - - ~sample_convert() = default; - - void add_options(po::options_description_easy_init &options) override { - options("input", po::value(&input_file)->default_value("-")); - // ("input-format", po::value(&input_format)->default_value("csv")) - options("output", po::value(&output_file)->default_value("-")); - options("output-format", - po::value(&output_format)->default_value(sample_format_type::KEY_VALUE)); - options("fields", po::value(&fields)); - options("add-timestamp", po::value(&add_timestamp)->default_value(true)); - options("timestamp-field", po::value(×tamp_field)->default_value("timestamp")); - } - - void add_extra_options(po::options_description &all_options) override { - po::options_description sql("SQL"); - sql.add_options()("table-name", po::value(&table_name)); - - all_options.add(sql); - }; - - int main(app_execution &execution) override { - auto desc = execution.desc; - auto vm = execution.vm; - - KeyDictionary dict; - - istream *inputStream; - if (input_file == "-") { - inputStream = &cin; - } else { - inputStream = new ifstream(input_file); - if (inputStream->fail()) { - cerr << "Unable to open input file " << input_file << endl; - return EXIT_FAILURE; - } - } - - shared_ptr outputStream; - if (output_file == "-") { - outputStream = shared_ptr(&cout, noop_deleter); - } else { - outputStream = make_shared(output_file); - if (outputStream->fail()) { - cerr << "Unable to open output file " << output_file << endl; - return EXIT_FAILURE; - } - } - - sample_output_stream_options options; - trygvis::sensor::io::timestamp_field_option tf(timestamp_field); - - options.push_back(&tf); - - table_name_option tno(table_name); - if (table_name != "") { - options.push_back(&tno); - } - - tokenizer<> tok(fields); - output_fields_option fs; - std::copy(tok.begin(), tok.end(), std::back_inserter(fs.fields)); - if (!fs.fields.empty()) { - options.push_back(&fs); - } - - unique_ptr o = open_sample_output_stream(outputStream, dict, output_format, options); - - if (add_timestamp) { - o = make_unique(move(o), dict, timestamp_field); - } - - shared_ptr output(move(o)); - - auto input = make_shared(output, dict); - - char data[100]; - while (!inputStream->eof()) { - inputStream->get(data[0]); - auto buf = boost::asio::buffer(data, 1); - input->process(buf); - } - - return EXIT_SUCCESS; - } -}; -} -} diff --git a/apps/sample-select.cpp b/apps/sample-select.cpp new file mode 100644 index 0000000..d067af4 --- /dev/null +++ b/apps/sample-select.cpp @@ -0,0 +1,124 @@ +#include "trygvis/sensor.h" +#include "apps.h" +#include + +namespace trygvis { +namespace apps { + +using namespace std; +using namespace trygvis::apps; +using namespace trygvis::sensor; +using boost::tokenizer; +namespace po = boost::program_options; + +class sample_select : public app { +private: + string fields; + +public: + sample_select() : app("sample-select") {} + + ~sample_select() = default; + + void add_options(po::options_description_easy_init &options) override { + options("fields", po::value(&fields)->required()); + } + + int main(app_execution &execution) override { + tokenizer<> tok(fields); + + for (tokenizer<>::iterator beg = tok.begin(); beg != tok.end(); ++beg) { + cout << *beg << "\n"; + } + + /* + KeyDictionary dict; + + relative_key = dict.indexOf(relative_name); + + auto sample_buffer = make_shared(); + auto parser = open_sample_input_stream(sample_buffer, dict); + while (!input.fail()) { + char buffer[buffer_size]; + input.read(buffer, buffer_size); + auto count = (size_t) input.gcount(); + + cerr << "eof? " << input.eof() << endl; + mutable_buffers_1 b = boost::asio::buffer(buffer, count); + parser->process(b); + } + + if (sample_buffer->samples.empty()) { + cerr << "Could not find any samples" << endl; + return EXIT_FAILURE; + } + + time_t end_time = buf.st_mtim.tv_sec; + + SampleRecord sample = *--sample_buffer->samples.end(); + + o s = sample.at(relative_key); + if (!s) { + cerr << "Missing key '" + relative_name + "'." << endl; + cerr << "Found " << sample_buffer->samples.size() << " samples." << endl; + cerr << "keys: " << sample.to_string() << endl; + return EXIT_FAILURE; + } + + long relative; + try { + relative = boost::lexical_cast(s.get()); + } catch (const boost::bad_lexical_cast &e) { + cerr << "Bad integer value '" + s.get() + "'." << endl; + return EXIT_FAILURE; + } + + if (relative_resolution == time_resolution::MILLISECONDS) { + relative /= 1000; + } + + time_t start_time = end_time - relative; + cerr << "end_time " << end_time << endl; + cerr << "relative " << relative << endl; + cerr << "start_time " << start_time << endl; + + // Restart the reading of the input file and add the adjusted timestamp + input.clear(ios::eofbit); + input.seekg(0); + if(input.fail()) { + cerr << "Coult not seek input file" << endl; + return EXIT_FAILURE; + } + + vector options = {}; + unique_ptr unique_output_stream = open_sample_output_stream(shared_ptr(&cout, + noop_deleter), dict, parser->type(), options); + shared_ptr output_stream{std::move(unique_output_stream)}; + shared_ptr p = make_shared(output_stream, dict, + timestamp_name, relative_name, relative_resolution, start_time); + parser = open_sample_stream_parser(p, dict, parser->type()); + + int recordCount = 0; + + while (!input.eof()) { + char buffer[buffer_size]; + input.read(buffer, buffer_size); + size_t gcount = (size_t)input.gcount(); + + recordCount++; + + mutable_buffers_1 b = boost::asio::buffer(buffer, gcount); + parser->process(b); + } + */ + return EXIT_SUCCESS; + }; +}; +} +} + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new sample_select(), argc, argv); +} diff --git a/apps/sample-select.h b/apps/sample-select.h deleted file mode 100644 index 8ae5cc3..0000000 --- a/apps/sample-select.h +++ /dev/null @@ -1,119 +0,0 @@ -#include "trygvis/sensor.h" -#include "apps.h" -#include - -namespace trygvis { -namespace apps { - -using namespace std; -using namespace trygvis::apps; -using namespace trygvis::sensor; -using boost::tokenizer; -namespace po = boost::program_options; - -class sample_select : public app { -private: - string fields; - -public: - sample_select() : app("sample-select") { - } - - ~sample_select() = default; - - void add_options(po::options_description_easy_init &options) override { - options("fields", po::value(&fields)->required()); - } - - int main(app_execution &execution) override { - tokenizer<> tok(fields); - - for (tokenizer<>::iterator beg = tok.begin(); beg != tok.end(); ++beg) { - cout << *beg << "\n"; - } - - /* - KeyDictionary dict; - - relative_key = dict.indexOf(relative_name); - - auto sample_buffer = make_shared(); - auto parser = open_sample_input_stream(sample_buffer, dict); - while (!input.fail()) { - char buffer[buffer_size]; - input.read(buffer, buffer_size); - auto count = (size_t) input.gcount(); - - cerr << "eof? " << input.eof() << endl; - mutable_buffers_1 b = boost::asio::buffer(buffer, count); - parser->process(b); - } - - if (sample_buffer->samples.empty()) { - cerr << "Could not find any samples" << endl; - return EXIT_FAILURE; - } - - time_t end_time = buf.st_mtim.tv_sec; - - SampleRecord sample = *--sample_buffer->samples.end(); - - o s = sample.at(relative_key); - if (!s) { - cerr << "Missing key '" + relative_name + "'." << endl; - cerr << "Found " << sample_buffer->samples.size() << " samples." << endl; - cerr << "keys: " << sample.to_string() << endl; - return EXIT_FAILURE; - } - - long relative; - try { - relative = boost::lexical_cast(s.get()); - } catch (const boost::bad_lexical_cast &e) { - cerr << "Bad integer value '" + s.get() + "'." << endl; - return EXIT_FAILURE; - } - - if (relative_resolution == time_resolution::MILLISECONDS) { - relative /= 1000; - } - - time_t start_time = end_time - relative; - cerr << "end_time " << end_time << endl; - cerr << "relative " << relative << endl; - cerr << "start_time " << start_time << endl; - - // Restart the reading of the input file and add the adjusted timestamp - input.clear(ios::eofbit); - input.seekg(0); - if(input.fail()) { - cerr << "Coult not seek input file" << endl; - return EXIT_FAILURE; - } - - vector options = {}; - unique_ptr unique_output_stream = open_sample_output_stream(shared_ptr(&cout, - noop_deleter), dict, parser->type(), options); - shared_ptr output_stream{std::move(unique_output_stream)}; - shared_ptr p = make_shared(output_stream, dict, - timestamp_name, relative_name, relative_resolution, start_time); - parser = open_sample_stream_parser(p, dict, parser->type()); - - int recordCount = 0; - - while (!input.eof()) { - char buffer[buffer_size]; - input.read(buffer, buffer_size); - size_t gcount = (size_t)input.gcount(); - - recordCount++; - - mutable_buffers_1 b = boost::asio::buffer(buffer, gcount); - parser->process(b); - } - */ - return EXIT_SUCCESS; - }; -}; -} -} diff --git a/apps/sm-db-insert.cpp b/apps/sm-db-insert.cpp new file mode 100644 index 0000000..b93be09 --- /dev/null +++ b/apps/sm-db-insert.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include "json.hpp" +#include "apps.h" +#include + +namespace trygvis { +namespace apps { + +template +using o = boost::optional; +using namespace std; +using json = nlohmann::json; + +class sm_db_insert : public app { +public: + sm_db_insert() : app("sm-db-insert") {} + + ~sm_db_insert() = default; + + void add_options(po::options_description_easy_init &options) override { + options("file", po::value()->required(), "The file to read"); + } + + int main(app_execution &execution) override { + auto file = execution.vm["file"].as(); + cout << "reading from " << file << endl; + + fstream f(file); + + json j; + + j << f; + + pqxx::connection c("host=localhost dbname=soil-moisture"); + + pqxx::work work(c); + + string mac = j["mac"]; // "aa:bb:cc:dd:ee:ff"; + + auto select_device = "select id from soil_moisture_device where mac=$1"; + auto rs = work.parameterized(select_device)(mac).exec(); + + if (!rs.size()) { + cout << "New device: " << mac << endl; + + auto insert_device = "insert into soil_moisture_device(mac) values($1) returning id"; + rs = work.parameterized(insert_device)(mac).exec(); + } + + auto deviceId = rs.begin()["id"].as(); + + int sensor = j["sensor"]; + + auto select_sensor = "select id from soil_moisture_sensor where device=$1 and sensor=$2"; + rs = work.parameterized(select_sensor)(deviceId)(sensor).exec(); + + if (!rs.size()) { + cout << "New sensor: " << sensor << endl; + + auto insert_sensor = "insert into soil_moisture_sensor(device, sensor) values($1, $2) returning id"; + rs = work.parameterized(insert_sensor)(deviceId)(sensor).exec(); + } + auto sensorId = rs.begin()["id"].as(); + + unsigned long timestamp = get(j, "timestamp"); + unsigned int value = get(j, "value"); + + auto insert_sample = "insert into soil_moisture_sample(sensor, timestamp, value) values($1, $2, $3)"; + work.parameterized(insert_sample)(sensorId)(timestamp)(value).exec(); + + cout << "Sample inserted" << endl; + + work.commit(); + + return EXIT_SUCCESS; + } +}; +} +} + + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new sm_db_insert(), argc, argv); +} diff --git a/apps/sm-db-insert.h b/apps/sm-db-insert.h deleted file mode 100644 index 7e08268..0000000 --- a/apps/sm-db-insert.h +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include -#include -#include -#include "json.hpp" -#include - -namespace trygvis { -namespace apps { - -template -using o = boost::optional; -using namespace std; -using json = nlohmann::json; - -class sm_db_insert : public app { -public: - sm_db_insert() : app("sm-db-insert") { - } - - ~sm_db_insert() = default; - - void add_options(po::options_description_easy_init &options) override { - options("file", po::value()->required(), "The file to read"); - } - - int main(app_execution &execution) override { - auto file = execution.vm["file"].as(); - cout << "reading from " << file << endl; - - fstream f(file); - - json j; - - j << f; - - pqxx::connection c("host=localhost dbname=soil-moisture"); - - pqxx::work work(c); - - string mac = j["mac"]; // "aa:bb:cc:dd:ee:ff"; - - auto select_device = "select id from soil_moisture_device where mac=$1"; - auto rs = work.parameterized(select_device)(mac).exec(); - - if (!rs.size()) { - cout << "New device: " << mac << endl; - - auto insert_device = "insert into soil_moisture_device(mac) values($1) returning id"; - rs = work.parameterized(insert_device)(mac).exec(); - } - - auto deviceId = rs.begin()["id"].as(); - - int sensor = j["sensor"]; - - auto select_sensor = "select id from soil_moisture_sensor where device=$1 and sensor=$2"; - rs = work.parameterized(select_sensor)(deviceId)(sensor).exec(); - - if (!rs.size()) { - cout << "New sensor: " << sensor << endl; - - auto insert_sensor = "insert into soil_moisture_sensor(device, sensor) values($1, $2) returning id"; - rs = work.parameterized(insert_sensor)(deviceId)(sensor).exec(); - } - auto sensorId = rs.begin()["id"].as(); - - unsigned long timestamp = get(j, "timestamp"); - unsigned int value = get(j, "value"); - - auto insert_sample = "insert into soil_moisture_sample(sensor, timestamp, value) values($1, $2, $3)"; - work.parameterized(insert_sample)(sensorId)(timestamp)(value).exec(); - - cout << "Sample inserted" << endl; - - work.commit(); - - return EXIT_SUCCESS; - } -}; -} -} diff --git a/apps/sm-db-select.cpp b/apps/sm-db-select.cpp new file mode 100644 index 0000000..2390733 --- /dev/null +++ b/apps/sm-db-select.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include "json.hpp" +#include "apps.h" + +namespace trygvis { +namespace apps { + +template +using o = boost::optional; +using namespace std; +using json = nlohmann::json; + +class sm_db_select : public app { +public: + sm_db_select() : app("sm-db-select") {} + + ~sm_db_select() = default; + + int main(app_execution &execution) override { + string mac = "aa:bb:cc:dd:ee:ff"; + int sensor = 1; + + json j; + + pqxx::connection c("host=localhost dbname=soil-moisture"); + + pqxx::work work(c); + + auto rs = work.parameterized("select id from soil_moisture_device where mac=$1")(mac).exec(); + + if (!rs.size()) { + cout << "Unknown device: " << mac << endl; + return EXIT_FAILURE; + } + + auto deviceId = rs.begin()["id"].as(); + + rs = work.parameterized("select id from soil_moisture_sensor where device=$1 and sensor=$2")(deviceId)(sensor) + .exec(); + + if (!rs.size()) { + cout << "Unknown sensor: " << sensor << endl; + return EXIT_FAILURE; + } + + auto sensorId = rs.begin()["id"].as(); + + rs = work.parameterized("select timestamp, sensor, value from soil_moisture_sample where sensor=$1")(sensorId) + .exec(); + + json points = json::array(); + for (auto sample : rs) { + json s; + s.push_back(sample["timestamp"].as()); + s.push_back(sample["sensor"].as()); + s.push_back(sample["value"].as()); + points.push_back({s}); + } + + json o; + o["columns"] = json::array({"time", "sensor", "value"}); + o["points"] = json(points); + j.push_back(o); + + cout << "JSON" << endl; + cout << setw(2) << j << endl; + cout << "JSON" << endl; + + work.commit(); + + return EXIT_SUCCESS; + } +}; +} +} + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new sm_db_select(), argc, argv); +} diff --git a/apps/sm-db-select.h b/apps/sm-db-select.h deleted file mode 100644 index 78678c5..0000000 --- a/apps/sm-db-select.h +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include -#include "json.hpp" - -namespace trygvis { -namespace apps { - -template -using o = boost::optional; -using namespace std; -using json = nlohmann::json; - -class sm_db_select : public app { -public: - sm_db_select() : app("sm-db-select") { - } - - ~sm_db_select() = default; - - int main(app_execution &execution) override { - string mac = "aa:bb:cc:dd:ee:ff"; - int sensor = 1; - - json j; - - pqxx::connection c("host=localhost dbname=soil-moisture"); - - pqxx::work work(c); - - auto rs = work.parameterized("select id from soil_moisture_device where mac=$1")(mac).exec(); - - if (!rs.size()) { - cout << "Unknown device: " << mac << endl; - return EXIT_FAILURE; - } - - auto deviceId = rs.begin()["id"].as(); - - rs = work.parameterized("select id from soil_moisture_sensor where device=$1 and sensor=$2")(deviceId)(sensor) - .exec(); - - if (!rs.size()) { - cout << "Unknown sensor: " << sensor << endl; - return EXIT_FAILURE; - } - - auto sensorId = rs.begin()["id"].as(); - - rs = work.parameterized("select timestamp, sensor, value from soil_moisture_sample where sensor=$1")(sensorId) - .exec(); - - json points = json::array(); - for (auto sample : rs) { - json s; - s.push_back(sample["timestamp"].as()); - s.push_back(sample["sensor"].as()); - s.push_back(sample["value"].as()); - points.push_back({s}); - } - - json o; - o["columns"] = json::array({"time", "sensor", "value"}); - o["points"] = json(points); - j.push_back(o); - - cout << "JSON" << endl; - cout << setw(2) << j << endl; - cout << "JSON" << endl; - - work.commit(); - - return EXIT_SUCCESS; - } -}; -} -} diff --git a/apps/sm-get-value.cpp b/apps/sm-get-value.cpp new file mode 100644 index 0000000..19b0066 --- /dev/null +++ b/apps/sm-get-value.cpp @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include +#include "ble/Bluetooth.h" +#include "SoilMoisture.h" +#include "trygvis/sensor.h" +#include "trygvis/sensor/io.h" +#include "apps.h" + +namespace trygvis { +namespace apps { + +// I'm lazy +using namespace std; +using namespace std::chrono; +using namespace trygvis::apps; +using namespace trygvis::bluetooth; +using namespace trygvis::sensor; +using namespace trygvis::sensor::io; + +class sm_get_value : public app { +public: + sm_get_value() : app("sm-get-value") {} + + ~sm_get_value() = default; + + bool loop; + sample_format_type format; + unsigned int sleepTime; + vector sensorIndexes; + vector> sensors; + + KeyDictionary dict; + SampleKey *hostname_key = dict.indexOf("hostname"); + SampleKey *device_key = dict.indexOf("device"); + SampleKey *timestamp_key = dict.indexOf("timestamp_ms"); + + void add_options(po::options_description_easy_init &options) override { + auto default_sleep = po::value<>(&sleepTime)->default_value(0); + auto default_format = po::value(&format)->default_value(sample_format_type::KEY_VALUE); + + options("device", po::value()->required(), "MAC of device to poll"); + options("sensor", po::value>(&sensorIndexes)->multitoken(), + "Sensor to poll, defaults to all"); + options("sleep", default_sleep, + "How long to sleep in seconds between each poll. If not given, it will exit after first poll"); + options("format", default_format, "Output format"); + } + + int main(app_execution &execution) override { + __attribute__((unused)) BluetoothSystem bluetoothSystem; + + auto desc = execution.desc; + auto vm = execution.vm; + + try { + if (!vm.count("device")) { + cerr << "Missing required option: device" << endl; + cerr << desc << "\n"; + return EXIT_FAILURE; + } + + auto mac_string = vm["device"].as(); + + Mac mac = Mac::parseMac(mac_string); + + auto adapter = getAdapter(0); + + auto &device = adapter->getDevice(mac); + + loop = sleepTime > 0; + + do { + try { + LOG4CPLUS_INFO(execution.logger, "Connecting to device: " + device.getMac().str()); + auto gatt = device.connectGatt(); + + withConnection(format, gatt); + } catch (runtime_error &e) { + LOG4CPLUS_ERROR(execution.logger, "Exception: " << e.what()); + } + + if (loop) { + LOG4CPLUS_DEBUG(execution.logger, + "Sleeping for " + std::to_string(sleepTime) + " seconds after failure."); + + auto targetTime = system_clock::now() + seconds(sleepTime); + this_thread::sleep_until(targetTime); + } + } while (loop); + + return EXIT_SUCCESS; + } catch (std::runtime_error ex) { + cout << "std::runtime_error: " << ex.what() << endl; + return EXIT_FAILURE; + } catch (std::exception ex) { + cout << "std::exception: " << ex.what() << endl; + return EXIT_FAILURE; + } + } + + void read_sensors(SoilMoisture &soilMoisture, string mac) { + auto epoch = system_clock::now().time_since_epoch(); + auto timestamp = duration_cast(epoch).count(); + auto unique_output_stream = open_sample_output_stream(shared_ptr(&cout, noop_deleter), dict, format); + shared_ptr output_stream{std::move(unique_output_stream)}; + + int i = 0; + for (auto s : sensors) { + auto sensor = s.first; + auto name = s.second; + + uint16_t value = soilMoisture.getValue((uint8_t) sensor); + + auto sensor_key = dict.indexOf("sensor" + std::to_string(i)); + auto sensor_name_key = dict.indexOf("sensor_name" + std::to_string(i)); + + auto sample = SampleRecord(dict) + .set(hostname_key, get_hostname()) + .set(device_key, mac) + .set(timestamp_key, std::to_string(timestamp)) + .set(sensor_key, std::to_string(value)) + .set(sensor_name_key, name); + + output_stream->write(sample); + + i++; + } + } + + void withConnection(sample_format_type format, shared_ptr gatt) { + SoilMoisture soilMoisture = SoilMoisture::create(gatt); + + const int sensorCount = soilMoisture.getSensorCount(); + + if (sensorCount == 0) { + throw runtime_error("Sensor count is 0"); + } + + // If the user didn't specify any sensors, add all. + if (sensors.size() == 0) { + for (unsigned int i = 0; i < sensorCount; i++) { + sensorIndexes.push_back(i); + } + } + + for_each(begin(sensorIndexes), end(sensorIndexes), [&](auto i) { + if (i >= sensorCount) { + // Ignore invalid sensors + return; + } + + sensors.push_back(make_pair(i, soilMoisture.getName(i))); + }); + + auto mac = gatt->getDevice().getMac().str(); + + if (!loop) { + read_sensors(soilMoisture, mac); + } else { + time_point targetTime; + targetTime = system_clock::now(); + + do { + read_sensors(soilMoisture, mac); + + do { + targetTime = targetTime + seconds(sleepTime); + } while (targetTime < system_clock::now()); + + this_thread::sleep_until(targetTime); + } while (loop); + } + } +}; +} +} + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new sm_get_value(), argc, argv); +} diff --git a/apps/sm-get-value.h b/apps/sm-get-value.h deleted file mode 100644 index 5893d23..0000000 --- a/apps/sm-get-value.h +++ /dev/null @@ -1,180 +0,0 @@ -#include -#include -#include -#include -#include -#include "ble/Bluetooth.h" -#include "SoilMoisture.h" -#include "trygvis/sensor.h" -#include "trygvis/sensor/io.h" -#include "apps.h" - -namespace trygvis { -namespace apps { - -// I'm lazy -using namespace std; -using namespace std::chrono; -using namespace trygvis::apps; -using namespace trygvis::bluetooth; -using namespace trygvis::sensor; -using namespace trygvis::sensor::io; - -class sm_get_value : public app { -public: - sm_get_value() : app("sm-get-value") { - } - - ~sm_get_value() = default; - - bool loop; - sample_format_type format; - unsigned int sleepTime; - vector sensorIndexes; - vector> sensors; - - KeyDictionary dict; - SampleKey *hostname_key = dict.indexOf("hostname"); - SampleKey *device_key = dict.indexOf("device"); - SampleKey *timestamp_key = dict.indexOf("timestamp_ms"); - - void add_options(po::options_description_easy_init &options) override { - auto default_sleep = po::value<>(&sleepTime)->default_value(0); - auto default_format = po::value(&format)->default_value(sample_format_type::KEY_VALUE); - - options("device", po::value()->required(), "MAC of device to poll"); - options("sensor", po::value>(&sensorIndexes)->multitoken(), - "Sensor to poll, defaults to all"); - options("sleep", default_sleep, - "How long to sleep in seconds between each poll. If not given, it will exit after first poll"); - options("format", default_format, "Output format"); - } - - int main(app_execution &execution) override { - __attribute__((unused)) BluetoothSystem bluetoothSystem; - - auto desc = execution.desc; - auto vm = execution.vm; - - try { - if (!vm.count("device")) { - cerr << "Missing required option: device" << endl; - cerr << desc << "\n"; - return EXIT_FAILURE; - } - - auto mac_string = vm["device"].as(); - - Mac mac = Mac::parseMac(mac_string); - - auto adapter = getAdapter(0); - - auto &device = adapter->getDevice(mac); - - loop = sleepTime > 0; - - do { - try { - LOG4CPLUS_INFO(execution.logger, "Connecting to device: " + device.getMac().str()); - auto gatt = device.connectGatt(); - - withConnection(format, gatt); - } catch (runtime_error &e) { - LOG4CPLUS_ERROR(execution.logger, "Exception: " << e.what()); - } - - if (loop) { - LOG4CPLUS_DEBUG(execution.logger, - "Sleeping for " + std::to_string(sleepTime) + " seconds after failure."); - - auto targetTime = system_clock::now() + seconds(sleepTime); - this_thread::sleep_until(targetTime); - } - } while (loop); - - return EXIT_SUCCESS; - } catch (std::runtime_error ex) { - cout << "std::runtime_error: " << ex.what() << endl; - return EXIT_FAILURE; - } catch (std::exception ex) { - cout << "std::exception: " << ex.what() << endl; - return EXIT_FAILURE; - } - } - - void read_sensors(SoilMoisture &soilMoisture, string mac) { - auto epoch = system_clock::now().time_since_epoch(); - auto timestamp = duration_cast(epoch).count(); - auto unique_output_stream = open_sample_output_stream(shared_ptr(&cout, noop_deleter), dict, format); - shared_ptr output_stream{std::move(unique_output_stream)}; - - int i = 0; - for (auto s : sensors) { - auto sensor = s.first; - auto name = s.second; - - uint16_t value = soilMoisture.getValue((uint8_t) sensor); - - auto sensor_key = dict.indexOf("sensor" + std::to_string(i)); - auto sensor_name_key = dict.indexOf("sensor_name" + std::to_string(i)); - - auto sample = SampleRecord(dict) - .set(hostname_key, get_hostname()) - .set(device_key, mac) - .set(timestamp_key, std::to_string(timestamp)) - .set(sensor_key, std::to_string(value)) - .set(sensor_name_key, name); - - output_stream->write(sample); - - i++; - } - } - - void withConnection(sample_format_type format, shared_ptr gatt) { - SoilMoisture soilMoisture = SoilMoisture::create(gatt); - - const int sensorCount = soilMoisture.getSensorCount(); - - if (sensorCount == 0) { - throw runtime_error("Sensor count is 0"); - } - - // If the user didn't specify any sensors, add all. - if (sensors.size() == 0) { - for (unsigned int i = 0; i < sensorCount; i++) { - sensorIndexes.push_back(i); - } - } - - for_each(begin(sensorIndexes), end(sensorIndexes), [&](auto i) { - if (i >= sensorCount) { - // Ignore invalid sensors - return; - } - - sensors.push_back(make_pair(i, soilMoisture.getName(i))); - }); - - auto mac = gatt->getDevice().getMac().str(); - - if (!loop) { - read_sensors(soilMoisture, mac); - } else { - time_point targetTime; - targetTime = system_clock::now(); - - do { - read_sensors(soilMoisture, mac); - - do { - targetTime = targetTime + seconds(sleepTime); - } while (targetTime < system_clock::now()); - - this_thread::sleep_until(targetTime); - } while (loop); - } - } -}; -} -} diff --git a/apps/sm-serial-read-all.cpp b/apps/sm-serial-read-all.cpp new file mode 100644 index 0000000..bf5ef11 --- /dev/null +++ b/apps/sm-serial-read-all.cpp @@ -0,0 +1,171 @@ +#include "trygvis/sensor.h" +#include "trygvis/sensor/io.h" +#include "json.hpp" +#include "apps.h" +#include +#include + +namespace trygvis { +namespace apps { + +using namespace boost::asio; +using namespace std; +using namespace std::chrono; +using namespace trygvis::apps; +using namespace trygvis::sensor; +using namespace trygvis::sensor::io; +namespace po = boost::program_options; +using json = nlohmann::json; + +namespace sm_serial_read_all_utils { + +class port_handler { +public: + port_handler(string &port_name, serial_port &port, unique_ptr parser) + : port_name(port_name), port(port), parser(move(parser)) {} + + void run() { + auto packet = make_shared>(1024); + + while (port.is_open()) { + std::size_t some = port.read_some(buffer); + + mutable_buffers_1 chunk = boost::asio::buffer(data, some); + parser->process(chunk); + } + + cerr << "port closed" << endl; + dead_ = true; + } + + bool dead() const { + return dead_; + } + + const string port_name; + +private: + static const size_t size = 1024; + bool dead_ = false; + serial_port &port; + uint8_t data[size]; + mutable_buffers_1 buffer = boost::asio::buffer(data, size); + + unique_ptr parser; +}; +} + +// This only supports Linux +#if 1 + +#include +#include + +vector &&find_ports() { + DIR *dir = opendir("/dev"); + vector ports; + + if (!dir) { + return move(ports); + } + + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + string name = entry->d_name; + + if (name.find("ttyS") || name.find("ttyUSB") || name.find("ttyACM")) { + ports.emplace_back("/dev/" + name); + } + } + + closedir(dir); + + return move(ports); +} + +#endif + +class sm_serial_read_all : public app { + typedef trygvis::apps::sm_serial_read_all_utils::port_handler port_handler; + +public: + sm_serial_read_all() : app("sm-serial-read-all") {} + + ~sm_serial_read_all() = default; + + bool run = true; + sample_format_type format; + + void add_options(po::options_description_easy_init &options) override { + options("port", po::value()->required(), "The serial port to read"); + options("format", po::value(&format)->default_value(sample_format_type::KEY_VALUE), + "Output format"); + } + + static void handler_thread(port_handler *handler) { + handler->run(); + } + + int main(app_execution &execution) override { + auto desc = execution.desc; + auto vm = execution.vm; + + io_service io_service; + uint32_t baud_rate = 115200; + + map active_ports; + + KeyDictionary outputDict; + auto output_stream = shared_ptr(&cout, noop_deleter); + auto output = open_sample_output_stream(output_stream, outputDict, format); + auto tso = thread_safe_sample_output_stream(move(output)); + shared_ptr thread_safe_output(move(tso)); + + while (run) { + // Port cleanup + for (auto it = active_ports.begin(); it != active_ports.end(); ++it) { + if (it->second->dead()) { + cerr << "Removing dead port " << it->second->port_name << endl; + it = active_ports.erase(it); + } + } + + // Discover new ports + auto ports = find_ports(); + + for (auto port_name : ports) { + if (active_ports.find(port_name) != active_ports.end()) { + cerr << "New port " << port_name; + + serial_port port(io_service); + port.open(port_name); + port.set_option(serial_port_base::baud_rate(baud_rate)); + port.set_option(serial_port_base::character_size(8)); + port.set_option(serial_port_base::parity(serial_port_base::parity::none)); + port.set_option(serial_port_base::stop_bits(serial_port_base::stop_bits::one)); + port.set_option(serial_port_base::flow_control(serial_port_base::flow_control::none)); + + KeyDictionary parserDict; // TODO: dette feiler + unique_ptr parser = + open_sample_stream_parser(thread_safe_output, parserDict, sample_format_type::KEY_VALUE); + + auto handler = new port_handler(port_name, port, move(parser)); + active_ports[port_name] = handler; + std::thread thread(handler_thread, handler); + } + } + + sleep(1); + } + + return EXIT_SUCCESS; + } +}; +} +} + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new sm_serial_read_all(), argc, argv); +} diff --git a/apps/sm-serial-read-all.h b/apps/sm-serial-read-all.h deleted file mode 100644 index b87727b..0000000 --- a/apps/sm-serial-read-all.h +++ /dev/null @@ -1,167 +0,0 @@ -#include "trygvis/sensor.h" -#include "trygvis/sensor/io.h" -#include "json.hpp" -#include "apps.h" -#include -#include - -namespace trygvis { -namespace apps { - -using namespace boost::asio; -using namespace std; -using namespace std::chrono; -using namespace trygvis::apps; -using namespace trygvis::sensor; -using namespace trygvis::sensor::io; -namespace po = boost::program_options; -using json = nlohmann::json; - -namespace sm_serial_read_all_utils { - -class port_handler { -public: - port_handler(string &port_name, serial_port &port, unique_ptr parser) - : port_name(port_name), port(port), parser(move(parser)) { - } - - void run() { - auto packet = make_shared>(1024); - - while (port.is_open()) { - std::size_t some = port.read_some(buffer); - - mutable_buffers_1 chunk = boost::asio::buffer(data, some); - parser->process(chunk); - } - - cerr << "port closed" << endl; - dead_ = true; - } - - bool dead() const { - return dead_; - } - - const string port_name; - -private: - static const size_t size = 1024; - bool dead_ = false; - serial_port &port; - uint8_t data[size]; - mutable_buffers_1 buffer = boost::asio::buffer(data, size); - - unique_ptr parser; -}; -} - -// This only supports Linux -#if 1 - -#include -#include - -vector &&find_ports() { - DIR *dir = opendir("/dev"); - vector ports; - - if (!dir) { - return move(ports); - } - - struct dirent *entry; - while ((entry = readdir(dir)) != NULL) { - string name = entry->d_name; - - if (name.find("ttyS") || name.find("ttyUSB") || name.find("ttyACM")) { - ports.emplace_back("/dev/" + name); - } - } - - closedir(dir); - - return move(ports); -} - -#endif - -class sm_serial_read_all : public app { - typedef trygvis::apps::sm_serial_read_all_utils::port_handler port_handler; - -public: - sm_serial_read_all() : app("sm-serial-read-all") { - } - - ~sm_serial_read_all() = default; - - bool run = true; - sample_format_type format; - - void add_options(po::options_description_easy_init &options) override { - options("port", po::value()->required(), "The serial port to read"); - options("format", po::value(&format)->default_value(sample_format_type::KEY_VALUE), - "Output format"); - } - - static void handler_thread(port_handler *handler) { - handler->run(); - } - - int main(app_execution &execution) override { - auto desc = execution.desc; - auto vm = execution.vm; - - io_service io_service; - uint32_t baud_rate = 115200; - - map active_ports; - - KeyDictionary outputDict; - auto output_stream = shared_ptr(&cout, noop_deleter); - auto output = open_sample_output_stream(output_stream, outputDict, format); - auto tso = thread_safe_sample_output_stream(move(output)); - shared_ptr thread_safe_output(move(tso)); - - while (run) { - // Port cleanup - for (auto it = active_ports.begin(); it != active_ports.end(); ++it) { - if (it->second->dead()) { - cerr << "Removing dead port " << it->second->port_name << endl; - it = active_ports.erase(it); - } - } - - // Discover new ports - auto ports = find_ports(); - - for (auto port_name : ports) { - if (active_ports.find(port_name) != active_ports.end()) { - cerr << "New port " << port_name; - - serial_port port(io_service); - port.open(port_name); - port.set_option(serial_port_base::baud_rate(baud_rate)); - port.set_option(serial_port_base::character_size(8)); - port.set_option(serial_port_base::parity(serial_port_base::parity::none)); - port.set_option(serial_port_base::stop_bits(serial_port_base::stop_bits::one)); - port.set_option(serial_port_base::flow_control(serial_port_base::flow_control::none)); - - KeyDictionary parserDict; // TODO: dette feiler - unique_ptr parser = - open_sample_stream_parser(thread_safe_output, parserDict, sample_format_type::KEY_VALUE); - - auto handler = new port_handler(port_name, port, move(parser)); - active_ports[port_name] = handler; - std::thread thread(handler_thread, handler); - } - } - - sleep(1); - } - - return EXIT_SUCCESS; - } -}; -} -} diff --git a/apps/sm-serial-read.cpp b/apps/sm-serial-read.cpp new file mode 100644 index 0000000..5005554 --- /dev/null +++ b/apps/sm-serial-read.cpp @@ -0,0 +1,111 @@ +#include "trygvis/sensor.h" +#include "trygvis/sensor/io.h" +#include "json.hpp" +#include "apps.h" +#include +#include +#include + +namespace trygvis { +namespace apps { + +using namespace boost::asio; +using namespace std; +using namespace std::chrono; +using namespace trygvis::apps; +using namespace trygvis::sensor; +using namespace trygvis::sensor::io; +namespace po = boost::program_options; +using json = nlohmann::json; + +namespace sm_serial_read_utils { + +class port_handler { +public: + port_handler(string port_name, serial_port &serial_port, shared_ptr input) + : port_name(port_name), port(serial_port), input(input) {} + + void run() { + auto packet = make_shared>(1024); + + while (port.is_open()) { + std::size_t some = port.read_some(buffer); + + mutable_buffers_1 chunk = boost::asio::buffer(data, some); + input->process(chunk); + } + + cerr << "port closed" << endl; + } + + +private: + static const size_t size = 1024; + string port_name; + serial_port &port; + uint8_t data[size]; + mutable_buffers_1 buffer = boost::asio::buffer(data, size); + + shared_ptr input; +}; +} + +class sm_serial_read : public app { + typedef trygvis::apps::sm_serial_read_utils::port_handler port_handler; + +public: + sm_serial_read() : app("sm-serial-read") {} + + ~sm_serial_read() = default; + + sample_format_type format; + + void add_options(po::options_description_easy_init &options) override { + options("port", po::value()->required(), "The serial port to read"); + options("format", po::value(&format)->default_value(sample_format_type::KEY_VALUE), + "Output format"); + } + + int main(app_execution &execution) override { + auto desc = execution.desc; + auto vm = execution.vm; + + KeyDictionary dict; + + uint32_t baud_rate = 115200; + auto port_name = vm["port"].as(); + + io_service io_service; + + serial_port port(io_service); + port.open(port_name); + port.set_option(serial_port_base::baud_rate(baud_rate)); + port.set_option(serial_port_base::character_size(8)); + port.set_option(serial_port_base::parity(serial_port_base::parity::none)); + port.set_option(serial_port_base::stop_bits(serial_port_base::stop_bits::one)); + port.set_option(serial_port_base::flow_control(serial_port_base::flow_control::none)); + + if (port.is_open()) { + cerr << "port is open" << endl; + } else { + cerr << "port is not open" << endl; + } + + shared_ptr outputStream = shared_ptr(&cout, noop_deleter); + shared_ptr output = open_sample_output_stream(outputStream, dict, format); + + shared_ptr input = make_shared(output, dict); + + port_handler(port_name, port, input).run(); + + return EXIT_SUCCESS; + } +}; +} +} + +int main(int argc, const char *argv[]) { + using namespace trygvis::apps; + + return real_main(new sm_serial_read(), argc, argv); +} diff --git a/apps/sm-serial-read.h b/apps/sm-serial-read.h deleted file mode 100644 index dcfcc73..0000000 --- a/apps/sm-serial-read.h +++ /dev/null @@ -1,107 +0,0 @@ -#include "trygvis/sensor.h" -#include "trygvis/sensor/io.h" -#include "json.hpp" -#include "apps.h" -#include -#include -#include - -namespace trygvis { -namespace apps { - -using namespace boost::asio; -using namespace std; -using namespace std::chrono; -using namespace trygvis::apps; -using namespace trygvis::sensor; -using namespace trygvis::sensor::io; -namespace po = boost::program_options; -using json = nlohmann::json; - -namespace sm_serial_read_utils { - -class port_handler { -public: - port_handler(string port_name, serial_port &serial_port, shared_ptr input) - : port_name(port_name), port(serial_port), input(input) { - } - - void run() { - auto packet = make_shared>(1024); - - while (port.is_open()) { - std::size_t some = port.read_some(buffer); - - mutable_buffers_1 chunk = boost::asio::buffer(data, some); - input->process(chunk); - } - - cerr << "port closed" << endl; - } - - -private: - static const size_t size = 1024; - string port_name; - serial_port &port; - uint8_t data[size]; - mutable_buffers_1 buffer = boost::asio::buffer(data, size); - - shared_ptr input; -}; -} - -class sm_serial_read : public app { - typedef trygvis::apps::sm_serial_read_utils::port_handler port_handler; - -public: - sm_serial_read() : app("sm-serial-read") { - } - - ~sm_serial_read() = default; - - sample_format_type format; - - void add_options(po::options_description_easy_init &options) override { - options("port", po::value()->required(), "The serial port to read"); - options("format", po::value(&format)->default_value(sample_format_type::KEY_VALUE), - "Output format"); - } - - int main(app_execution &execution) override { - auto desc = execution.desc; - auto vm = execution.vm; - - KeyDictionary dict; - - uint32_t baud_rate = 115200; - auto port_name = vm["port"].as(); - - io_service io_service; - - serial_port port(io_service); - port.open(port_name); - port.set_option(serial_port_base::baud_rate(baud_rate)); - port.set_option(serial_port_base::character_size(8)); - port.set_option(serial_port_base::parity(serial_port_base::parity::none)); - port.set_option(serial_port_base::stop_bits(serial_port_base::stop_bits::one)); - port.set_option(serial_port_base::flow_control(serial_port_base::flow_control::none)); - - if (port.is_open()) { - cerr << "port is open" << endl; - } else { - cerr << "port is not open" << endl; - } - - shared_ptr outputStream = shared_ptr(&cout, noop_deleter); - shared_ptr output = open_sample_output_stream(outputStream, dict, format); - - shared_ptr input = make_shared(output, dict); - - port_handler(port_name, port, input).run(); - - return EXIT_SUCCESS; - } -}; -} -} -- cgit v1.2.3