diff options
author | Trygve Laugstøl <trygvis@inamo.no> | 2015-06-21 00:15:04 +0200 |
---|---|---|
committer | Trygve Laugstøl <trygvis@inamo.no> | 2015-06-21 00:15:43 +0200 |
commit | c56840f03cf139d60c6d90b55cf16e70f6ae2bc2 (patch) | |
tree | c9f19ab065496ac704fbf855da031ef5643eefa3 /apps | |
parent | d91e500592790f1ef22ebfe921f273a61ff6252f (diff) | |
download | ble-toys-c56840f03cf139d60c6d90b55cf16e70f6ae2bc2.tar.gz ble-toys-c56840f03cf139d60c6d90b55cf16e70f6ae2bc2.tar.bz2 ble-toys-c56840f03cf139d60c6d90b55cf16e70f6ae2bc2.tar.xz ble-toys-c56840f03cf139d60c6d90b55cf16e70f6ae2bc2.zip |
o Going all header file based and single-executable to launch all apps.
o Ading CMake magic to generate the launcher
Diffstat (limited to 'apps')
-rw-r--r-- | apps/CMakeLists.txt | 59 | ||||
-rw-r--r-- | apps/apps.cpp | 63 | ||||
-rw-r--r-- | apps/apps.h | 40 | ||||
-rw-r--r-- | apps/ble-inspect-device.cpp | 58 | ||||
-rw-r--r-- | apps/ble-inspect-device.h | 79 | ||||
-rw-r--r-- | apps/generate.cpp | 71 | ||||
-rw-r--r-- | apps/launcher.cpp | 94 | ||||
-rw-r--r-- | apps/log4cplus-test.cpp | 50 | ||||
-rw-r--r-- | apps/sample-add-timestamp.h (renamed from apps/sample-add-timestamp.cpp) | 8 | ||||
-rw-r--r-- | apps/sample-convert.h (renamed from apps/sample-convert.cpp) | 7 | ||||
-rw-r--r-- | apps/sample-select.h (renamed from apps/sample-select.cpp) | 7 | ||||
-rw-r--r-- | apps/sm-db-insert.cpp | 78 | ||||
-rw-r--r-- | apps/sm-db-insert.h | 80 | ||||
-rw-r--r-- | apps/sm-db-select.cpp | 82 | ||||
-rw-r--r-- | apps/sm-db-select.h | 81 | ||||
-rw-r--r-- | apps/sm-get-value.h (renamed from apps/sm-get-value.cpp) | 8 | ||||
-rw-r--r-- | apps/sm-serial-read-all.h (renamed from apps/sm-serial-read-all.cpp) | 14 | ||||
-rw-r--r-- | apps/sm-serial-read.h (renamed from apps/sm-serial-read.cpp) | 15 |
18 files changed, 488 insertions, 406 deletions
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 988a989..c9eea9e 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,4 +1,3 @@ -list(APPEND APPS log4cplus-test) list(APPEND APPS ble-inspect-device) list(APPEND APPS sample-add-timestamp) list(APPEND APPS sample-convert) @@ -9,10 +8,6 @@ list(APPEND APPS sm-get-value) list(APPEND APPS sm-serial-read) list(APPEND APPS sm-serial-read-all) -add_library(trygvis-apps - SoilMoisture.cpp - apps.cpp) - # Boost find_package(Boost COMPONENTS regex system program_options REQUIRED) @@ -34,20 +29,44 @@ if(LOG4CPLUS_LIBRARIES MATCHES NOTFOUND) message(FATAL_ERROR "Could not find log4cplus library files") endif() -include_directories("${PROJECT_SOURCE_DIR}/include") -include_directories("${PROJECT_SOURCE_DIR}/json/src") -include_directories("${PROJECT_SOURCE_DIR}/sensor/include") -include_directories("${LOG4CPLUS_INCLUDE_DIRECTORIES}") +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_executable(${app} ${app}.cpp) - - target_link_libraries(${app} ble) - target_link_libraries(${app} trygvis-apps) - target_link_libraries(${app} trygvis-sensor) - target_link_libraries(${app} ${Boost_LIBRARIES}) - target_link_libraries(${app} ${BLUEZ_LIBRARIES}) - target_link_libraries(${app} ${PQXX_LIBRARIES}) - target_link_libraries(${app} ${LOG4CPLUS_LIBRARIES}) - target_link_libraries(${app} ${CMAKE_THREAD_LIBS_INIT}) -endforeach(app) + add_custom_command( + TARGET launcher POST_BUILD + COMMAND ln -sf launcher ${app}) +endforeach() diff --git a/apps/apps.cpp b/apps/apps.cpp index b9ee81c..783c0b0 100644 --- a/apps/apps.cpp +++ b/apps/apps.cpp @@ -1,8 +1,4 @@ #include "apps.h" -#include <log4cplus/logger.h> -#include <log4cplus/consoleappender.h> -#include <log4cplus/layout.h> -#include <log4cplus/configurator.h> #include <netdb.h> namespace trygvis { @@ -12,65 +8,6 @@ using namespace log4cplus; using namespace std; namespace po = boost::program_options; -const po::options_description logging_options() { - po::options_description desc; - - return desc; -} - -void setup_logging(po::variables_map vm) { - Appender *console = new ConsoleAppender(true, true); - PatternLayout* layout = new PatternLayout(LOG4CPLUS_TEXT("%-5p %r %-20c %m%n")); - console->setLayout(auto_ptr<Layout>(layout)); - - Hierarchy &h = Logger::getDefaultHierarchy(); - h.getRoot().addAppender(SharedAppenderPtr(console)); -} - -int launch_app(int argc, char *argv[], app &app) { - po::options_description all("Options"); - - auto all_options = all.add_options(); - 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(vm); - - app_execution execution(all, vm); - - 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; - } -} - std::string get_hostname() { struct addrinfo hints, *info, *p; // int gai_result; diff --git a/apps/apps.h b/apps/apps.h index 8173c51..7569a9f 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -3,27 +3,53 @@ #include <boost/program_options.hpp> #include <log4cplus/logger.h> #include <log4cplus/loggingmacros.h> +#include "json.hpp" +#include <exception> namespace trygvis { namespace apps { namespace po = boost::program_options; +using namespace log4cplus; + +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) { + } + + const json::string_t key; +}; + +template<typename T> +T get(json j, std::string key) { + auto ref = j[key]; + + if (ref.is_null()) { + throw missing_key(key); + } + + return ref; +} class app_execution { public: - app_execution(po::options_description desc, po::variables_map vm) : desc(desc), vm(vm) { + app_execution(po::options_description desc, po::variables_map vm, Logger logger) : desc(desc), vm(vm), logger(logger) { } - po::options_description desc; - po::variables_map vm; + const po::options_description desc; + const po::variables_map vm; + const log4cplus::Logger logger; void usage(); }; class app { public: - app(std::string app_name): _app_name(app_name), logger(log4cplus::Logger::getInstance(LOG4CPLUS_TEXT(app_name))) { + app(std::string app_name) : app_name(app_name) { } + virtual ~app() = default; virtual void add_options(po::options_description_easy_init &options) { @@ -34,13 +60,9 @@ public: virtual int main(app_execution &execution) = 0; -protected: - const std::string _app_name; - const log4cplus::Logger logger; + const std::string app_name; }; -int launch_app(int argc, char *argv[], app &app); - std::string get_hostname(); template<typename T> diff --git a/apps/ble-inspect-device.cpp b/apps/ble-inspect-device.cpp deleted file mode 100644 index e4e7113..0000000 --- a/apps/ble-inspect-device.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include <exception> -#include <iostream> -#include <vector> -#include <boost/uuid/uuid_io.hpp> -#include "ble/Bluetooth.h" - -using namespace std; -using namespace trygvis::bluetooth; - -void scan_callback(BluetoothDevice &device) { - cout << "Inspecting device: " << device.getMac().str() << endl; - - auto &gatt = device.connectGatt(); - - gatt.discoverServices(); - - vector<BluetoothGattService *> services = gatt.getServices(); - cout << "Device has " << services.size() << " services" << endl; - - for (auto &s: services) { - const vector<BluetoothGattCharacteristic *> 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; - } - } - - gatt.disconnect(); -} - -int main(int argc, char *argv[]) { - if (argc != 2) { - cerr << "usage: " << argv[0] << " [mac]" << endl; - return EXIT_FAILURE; - } - - BluetoothSystem bluetoothSystem; - - try { - Mac mac = Mac::parseMac(argv[1]); - - BluetoothAdapter &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-inspect-device.h b/apps/ble-inspect-device.h new file mode 100644 index 0000000..bf79b2c --- /dev/null +++ b/apps/ble-inspect-device.h @@ -0,0 +1,79 @@ +#include <exception> +#include <iostream> +#include <vector> +#include <boost/uuid/uuid_io.hpp> +#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<string>()->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 < BluetoothGattService * > services = gatt.getServices(); + cout << "Device has " << services.size() << " services" << endl; + + for (auto &s: services) { + const vector<BluetoothGattCharacteristic *> 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; + } + } + + gatt.disconnect(); + } + + int main(app_execution &execution) override { + string mac_str = execution.vm["mac"].as<string>(); + + BluetoothSystem bluetoothSystem; + + try { + Mac mac = Mac::parseMac(mac_str); + + BluetoothAdapter &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/generate.cpp b/apps/generate.cpp new file mode 100644 index 0000000..f0bf0fd --- /dev/null +++ b/apps/generate.cpp @@ -0,0 +1,71 @@ +#include <cstdlib> +#include <iostream> +#include <fstream> +#include <regex> + +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 + << "#include <string>" << endl + << endl; + + vector<pair<string, string>> apps; + + regex r("-"); + for (int i = 2; i < argc; i++) { + string app_name = argv[i]; + stringstream buf; + + regex_replace(ostream_iterator<char>(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<string, string> pair) { +// out << "class " << pair.second << ";" << endl; + out << "#include \"" << pair.first << ".h\"" << endl; + }); + out << endl; + + bool first = true; + + out << "template<typename App>" << endl + << "int launch_app(int argc, const char *argv[]);" + << 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 (app_name == \"" << pair.first << "\") {" << endl + << " return launch_app<" << pair.second << ">(argc, argv);" << endl; + }); + + out << " } else {" << endl + << " return EXIT_FAILURE;" << endl + << " }" << endl + << "}" << endl; + + return EXIT_SUCCESS; +} diff --git a/apps/launcher.cpp b/apps/launcher.cpp new file mode 100644 index 0000000..dc31abd --- /dev/null +++ b/apps/launcher.cpp @@ -0,0 +1,94 @@ +#include "apps.h" +#include "apps-list.gen.h" +#include <log4cplus/consoleappender.h> +#include <log4cplus/configurator.h> +#include <boost/algorithm/string/predicate.hpp> + +using namespace trygvis::apps; +using namespace std; + +const po::options_description logging_options() { + po::options_description desc; + + return desc; +} + +void setup_logging(po::variables_map vm) { + Appender *console = new ConsoleAppender(true, true); + PatternLayout *layout = new PatternLayout(LOG4CPLUS_TEXT("%-5p" /*" %6r"*/ " %-20c %m%n")); + console->setLayout(auto_ptr<Layout>(layout)); + + Hierarchy &h = Logger::getDefaultHierarchy(); + h.getRoot().addAppender(SharedAppenderPtr(console)); +} + +template<typename App> +int launch_app(int argc, const char *argv[]) { + App app; + + po::options_description all("Options"); + + auto all_options = all.add_options(); + 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(vm); + + Logger logger = Logger::getInstance(LOG4CPLUS_TEXT(app.app_name)); + + 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 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 = &argv[1]; + } else { + app_name = argv[0]; + } + + return launch(app_name, argc, argv); +} diff --git a/apps/log4cplus-test.cpp b/apps/log4cplus-test.cpp deleted file mode 100644 index 39d9884..0000000 --- a/apps/log4cplus-test.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include <log4cplus/logger.h> -#include <log4cplus/configurator.h> -#include <iomanip> - -namespace trygvis { -using namespace log4cplus; -using namespace std; - -class LogSetup { -public: - LogSetup(string name) : logger(Logger::getInstance(LOG4CPLUS_TEXT(name))) { - } - -protected: - Logger logger; -}; - -class MyService : LogSetup { -public: - MyService() : LogSetup("trygvis.MyService") { - } - - void launchMissiles() { - LOG4CPLUS_DEBUG(logger, "some debug message"); - LOG4CPLUS_INFO(logger, "some info message"); - LOG4CPLUS_WARN(logger, "some warning message"); - } -}; -} - -using namespace std; -using namespace log4cplus; -using namespace trygvis; - -int main() { - BasicConfigurator config; - config.configure(); - - cout << "Hello world!" << endl; - - Logger l = Logger::getRoot(); - - l.setLogLevel(INFO_LOG_LEVEL); - - MyService myService; - - myService.launchMissiles(); - - return EXIT_SUCCESS; -} diff --git a/apps/sample-add-timestamp.cpp b/apps/sample-add-timestamp.h index 22d81a6..13d2216 100644 --- a/apps/sample-add-timestamp.cpp +++ b/apps/sample-add-timestamp.h @@ -52,6 +52,7 @@ private: public: sample_add_timestamp() : app("sample-add-timestamp") { } + ~sample_add_timestamp() = default; void add_options(po::options_description_easy_init &options) override { @@ -96,10 +97,3 @@ public: } } - -using namespace trygvis::apps; - -int main(int argc, char *argv[]) { - sample_add_timestamp app; - return launch_app(argc, argv, app); -} diff --git a/apps/sample-convert.cpp b/apps/sample-convert.h index 2dc34b3..0b805be 100644 --- a/apps/sample-convert.cpp +++ b/apps/sample-convert.h @@ -119,10 +119,3 @@ public: } } - -using namespace trygvis::apps; - -int main(int argc, char *argv[]) { - sample_convert app; - return launch_app(argc, argv, app); -} diff --git a/apps/sample-select.cpp b/apps/sample-select.h index c4304da..2701338 100644 --- a/apps/sample-select.cpp +++ b/apps/sample-select.h @@ -119,10 +119,3 @@ public: } } - -using namespace trygvis::apps; - -int main(int argc, char *argv[]) { - sample_select app; - return launch_app(argc, argv, app); -} diff --git a/apps/sm-db-insert.cpp b/apps/sm-db-insert.cpp deleted file mode 100644 index a3ebb76..0000000 --- a/apps/sm-db-insert.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include <boost/optional.hpp> -#include <boost/lexical_cast.hpp> -#include <pqxx/connection.hxx> -#include <pqxx/transaction.hxx> -#include "json.hpp" -#include <fstream> - -template<class T> -using o = boost::optional<T>; -using namespace std; -using json = nlohmann::json; - -class missing_key : public runtime_error { -public: - missing_key(const json::string_t key) : runtime_error("Missing key: " + key), key(key) { - } - - const json::string_t key; -}; - -template<typename T> -T get(json j, string key) { - auto ref = j[key]; - - if (ref.is_null()) { - throw missing_key(key); - } - - return ref; -} - -int main(int argc, char *argv[]) { - cout << "reading from " << argv[1] << endl; - - fstream f(argv[1]); - - 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 rs = work.parameterized("select id from soil_moisture_device where mac=$1")(mac).exec(); - - if (!rs.size()) { - cout << "New device: " << mac << endl; - - rs = work.parameterized("insert into soil_moisture_device(mac) values($1) returning id")(mac).exec(); - } - - auto deviceId = rs.begin()["id"].as<int>(); - - int sensor = j["sensor"]; - - rs = work.parameterized("select id from soil_moisture_sensor where device=$1 and sensor=$2")(deviceId)(sensor).exec(); - - if (!rs.size()) { - cout << "New sensor: " << sensor << endl; - - rs = work.parameterized("insert into soil_moisture_sensor(device, sensor) values($1, $2) returning id")(deviceId)(sensor).exec(); - } - auto sensorId = rs.begin()["id"].as<int>(); - - unsigned long timestamp = get<unsigned long>(j, "timestamp"); - unsigned int value = get<unsigned int>(j, "value"); - - work.parameterized("insert into soil_moisture_sample(sensor, timestamp, value) values($1, $2, $3)")(sensorId)(timestamp)(value).exec(); - - cout << "Sample inserted" << endl; - - work.commit(); - - return EXIT_SUCCESS; -} diff --git a/apps/sm-db-insert.h b/apps/sm-db-insert.h new file mode 100644 index 0000000..b786e41 --- /dev/null +++ b/apps/sm-db-insert.h @@ -0,0 +1,80 @@ +#include <boost/optional.hpp> +#include <boost/lexical_cast.hpp> +#include <pqxx/connection.hxx> +#include <pqxx/transaction.hxx> +#include "json.hpp" +#include <fstream> + +namespace trygvis { +namespace apps { + +template<class T> +using o = boost::optional<T>; +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<string>()->required(), "The file to read"); + } + + int main(app_execution &execution) override { + auto file = execution.vm["file"].as<string>(); + 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 rs = work.parameterized("select id from soil_moisture_device where mac=$1")(mac).exec(); + + if (!rs.size()) { + cout << "New device: " << mac << endl; + + rs = work.parameterized("insert into soil_moisture_device(mac) values($1) returning id")(mac).exec(); + } + + auto deviceId = rs.begin()["id"].as<int>(); + + int sensor = j["sensor"]; + + rs = work.parameterized("select id from soil_moisture_sensor where device=$1 and sensor=$2")(deviceId)(sensor).exec(); + + if (!rs.size()) { + cout << "New sensor: " << sensor << endl; + + rs = work.parameterized("insert into soil_moisture_sensor(device, sensor) values($1, $2) returning id")(deviceId)(sensor).exec(); + } + auto sensorId = rs.begin()["id"].as<int>(); + + unsigned long timestamp = get<unsigned long>(j, "timestamp"); + unsigned int value = get<unsigned int>(j, "value"); + + work.parameterized("insert into soil_moisture_sample(sensor, timestamp, value) values($1, $2, $3)")(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 deleted file mode 100644 index 8bcce32..0000000 --- a/apps/sm-db-select.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include <boost/optional.hpp> -#include <boost/lexical_cast.hpp> -#include <pqxx/connection.hxx> -#include <pqxx/transaction.hxx> -#include "json.hpp" - -template<class T> -using o = boost::optional<T>; -using namespace std; -using json = nlohmann::json; - -class missing_key : public runtime_error { -public: - missing_key(const json::string_t key) : runtime_error("Missing key: " + key), key(key) { - } - - const json::string_t key; -}; - -template<typename T> -T get(json j, string key) { - auto ref = j[key]; - - if (ref.is_null()) { - throw missing_key(key); - } - - return ref; -} - -int main(int argc, char *argv[]) { - 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<int>(); - - 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<int>(); - - 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<unsigned long>()); - s.push_back(sample["sensor"].as<unsigned long>()); - s.push_back(sample["value"].as<unsigned long>()); - 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-db-select.h b/apps/sm-db-select.h new file mode 100644 index 0000000..fcbe91b --- /dev/null +++ b/apps/sm-db-select.h @@ -0,0 +1,81 @@ +#include <boost/optional.hpp> +#include <boost/lexical_cast.hpp> +#include <pqxx/connection.hxx> +#include <pqxx/transaction.hxx> +#include "json.hpp" + +namespace trygvis { +namespace apps { + +template<class T> +using o = boost::optional<T>; +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<int>(); + + 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<int>(); + + 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<unsigned long>()); + s.push_back(sample["sensor"].as<unsigned long>()); + s.push_back(sample["value"].as<unsigned long>()); + 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.h index 883495a..e0275c1 100644 --- a/apps/sm-get-value.cpp +++ b/apps/sm-get-value.h @@ -15,7 +15,6 @@ using namespace std::chrono; using namespace trygvis::apps; using namespace trygvis::bluetooth; using namespace trygvis::sensor; -namespace po = boost::program_options; using json = nlohmann::json; bool loop; @@ -128,7 +127,7 @@ public: loop = sleepTime > 0; do { - LOG4CPLUS_INFO(logger, "Connecting to device: " + device.getMac().str()); + LOG4CPLUS_INFO(execution.logger, "Connecting to device: " + device.getMac().str()); auto &gatt = device.connectGatt(); try { @@ -152,8 +151,3 @@ public: } } - -int main(int argc, char *argv[]) { - sm_get_value app; - return trygvis::apps::launch_app(argc, argv, app); -} diff --git a/apps/sm-serial-read-all.cpp b/apps/sm-serial-read-all.h index 5fa3f79..39b585a 100644 --- a/apps/sm-serial-read-all.cpp +++ b/apps/sm-serial-read-all.h @@ -17,8 +17,7 @@ using namespace trygvis::sensor::io; namespace po = boost::program_options; using json = nlohmann::json; -sample_format_type format; -string hostname = get_hostname(); +namespace sm_serial_read_all_utils { class port_handler { public: @@ -56,6 +55,8 @@ private: unique_ptr<SampleStreamParser> parser; }; +} + // This only supports Linux #if 1 @@ -87,6 +88,7 @@ vector<string> &&find_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") { @@ -95,6 +97,7 @@ public: ~sm_serial_read_all() = default; bool run = true; + sample_format_type format; void add_options(po::options_description_easy_init &options) override { options @@ -166,10 +169,3 @@ public: } } - -using namespace trygvis::apps; - -int main(int argc, char *argv[]) { - sm_serial_read_all app; - return launch_app(argc, argv, app); -} diff --git a/apps/sm-serial-read.cpp b/apps/sm-serial-read.h index 8c4c299..a3e3872 100644 --- a/apps/sm-serial-read.cpp +++ b/apps/sm-serial-read.h @@ -18,8 +18,7 @@ using namespace trygvis::sensor::io; namespace po = boost::program_options; using json = nlohmann::json; -sample_format_type format; -string hostname = get_hostname(); +namespace sm_serial_read_utils { class port_handler { public: @@ -51,7 +50,10 @@ private: shared_ptr<KeyValueSampleStreamParser> 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") { @@ -59,6 +61,8 @@ public: ~sm_serial_read() = default; + sample_format_type format; + void add_options(po::options_description_easy_init &options) override { options ("help", "produce help message") @@ -105,10 +109,3 @@ public: } } - -using namespace trygvis::apps; - -int main(int argc, char *argv[]) { - sm_serial_read app; - return launch_app(argc, argv, app); -} |