From a83e6f5960a549d54991495336bd12d549127d91 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 6 Mar 2015 21:07:34 +0100 Subject: o Starting on a tool to convert between sample formats. --- .gitignore | 1 + apps/CMakeLists.txt | 2 + apps/SoilMoistureIo.cpp | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ apps/SoilMoistureIo.h | 56 +++++++++++++++++++++++++ apps/sample-convert.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++++ apps/sm-serial-read.cpp | 81 +++++++++++++++++++++--------------- sample.json | 6 +++ 7 files changed, 317 insertions(+), 34 deletions(-) create mode 100644 apps/SoilMoistureIo.cpp create mode 100644 apps/SoilMoistureIo.h create mode 100644 apps/sample-convert.cpp create mode 100644 sample.json diff --git a/.gitignore b/.gitignore index 5331b61..cdaf6a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ noble .idea build +*.log diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 7fa9443..ec45a6b 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,5 +1,6 @@ set(APPS ble-inspect-device + sample-convert sm-db-insert sm-db-select sm-get-value @@ -8,6 +9,7 @@ set(APPS list(APPEND APPS log4cplus-test) list(APPEND shared_sources SoilMoisture.cpp) +list(APPEND shared_sources SoilMoistureIo.cpp) list(APPEND shared_sources apps.cpp) # Boost diff --git a/apps/SoilMoistureIo.cpp b/apps/SoilMoistureIo.cpp new file mode 100644 index 0000000..1280fc6 --- /dev/null +++ b/apps/SoilMoistureIo.cpp @@ -0,0 +1,107 @@ +#include "SoilMoistureIo.h" + +#include "json.hpp" +#include + +namespace trygvis { +namespace soil_moisture { + +using namespace std; +using json = nlohmann::json; + +CsvSampleOutputStream::CsvSampleOutputStream(ostream &stream, vector fields) : + stream(stream), fields(fields) { + + auto i = fields.begin(); + while (true) { + stream << *i; + + i++; + + if (i != fields.end()) { + stream << ","; + } else { + break; + } + } + + stream << endl; +} + +void CsvSampleOutputStream::write(it values) { + auto i = fields.begin(); + while (true) { + auto field = *i; + auto value = values.find(field); + + if (value != values.end()) { + stream << value->second; + } + + i++; + + if (i != fields.end()) { + stream << ","; + } else { + break; + } + } + + stream << endl; +} + +JsonSampleOutputStream::JsonSampleOutputStream(ostream &stream, vector fields) : + stream(stream), fields(fields) { +} + +void JsonSampleOutputStream::write(it values) { + json doc; + + for (auto &f: fields) { + auto value = values.find(f); + + if (value != values.end()) { + doc[f] = value->second; + } + } + + stream << doc << endl; +} + +SqlSampleOutputStream::SqlSampleOutputStream(ostream &stream, vector fields) : + stream(stream), fields(fields) { +} + +void SqlSampleOutputStream::write(it values) { + auto i = fields.begin(); + + stringstream fs, vs; + + while (true) { + auto field = *i; + + fs << field; + + auto value = values.find(field); + + if (value != values.end()) { + vs << "'" << value->second << "'"; + } else { + vs << "NULL"; + } + + i++; + + if (i != fields.end()) { + fs << ","; + vs << ","; + } else { + break; + } + } + + stream << "INSERT INTO (" << fs << ") VALUES(" << vs << ")" << endl; +} + +} +} diff --git a/apps/SoilMoistureIo.h b/apps/SoilMoistureIo.h new file mode 100644 index 0000000..739758a --- /dev/null +++ b/apps/SoilMoistureIo.h @@ -0,0 +1,56 @@ +#ifndef SOIL_MOISTURE_IO_H +#define SOIL_MOISTURE_IO_H + +#include +#include +#include + +namespace trygvis { +namespace soil_moisture { + +using namespace std; + +class SampleOutputStream { +public: + typedef map it; + + virtual void write(it values) = 0; +}; + +class CsvSampleOutputStream : public SampleOutputStream { +public: + CsvSampleOutputStream(ostream& stream, vector fields); + + void write(it values); + +private: + ostream& stream; + vector fields; +}; + +class JsonSampleOutputStream : public SampleOutputStream { +public: + JsonSampleOutputStream(ostream& stream, vector fields); + + void write(it values); + +private: + ostream& stream; + vector fields; +}; + +class SqlSampleOutputStream : public SampleOutputStream { +public: + SqlSampleOutputStream(ostream& stream, vector fields); + + void write(it values); + +private: + ostream& stream; + vector fields; +}; + +} +} + +#endif diff --git a/apps/sample-convert.cpp b/apps/sample-convert.cpp new file mode 100644 index 0000000..2e448ca --- /dev/null +++ b/apps/sample-convert.cpp @@ -0,0 +1,98 @@ +#include "SoilMoistureIo.h" +#include "json.hpp" +#include "apps.h" + +enum class Format { + PLAIN, + JSON, + SQL +}; + +void validate(boost::any &v, const std::vector &values, Format *, int) { + using namespace boost::program_options; + + const std::string &s = validators::get_single_string(values); + + if (s == "plain") { + v = boost::any(Format::PLAIN); + } else if (s == "json") { + v = boost::any(Format::JSON); + } else if (s == "sql") { + v = boost::any(Format::SQL); + } else { + throw validation_error(validation_error::invalid_option_value); + } +} + +namespace boost { + +template<> +std::string lexical_cast(const Format &arg) { + if (arg == Format::PLAIN) + return "plain"; + else if (arg == Format::JSON) + return "json"; + else if (arg == Format::SQL) + return "sql"; + else + throw std::runtime_error("Unknown format value: " + lexical_cast(arg)); +} + +} + +namespace trygvis { +namespace apps { + +using namespace std; +using namespace trygvis::apps; +using namespace trygvis::soil_moisture; +namespace po = boost::program_options; + +Format inputFormat, outputFormat; + +class sample_convert : public app { + +public: +// void add_options(po::options_description_easy_init &options) override { +// options +// ("help", "produce help message") +// ("input-format", po::value(&inputFormat)->default_value(Format::PLAIN)) +// ("output-format", po::value(&outputFormat)->default_value(Format::PLAIN)) +// } + + int main(app_execution &execution) override { + auto desc = execution.desc; + auto vm = execution.vm; + + shared_ptr sampleStream; + + auto field_names = vector({ + "hostname", + "device_type", + "device", + "timestamp", + "sensor", + "value" + }); + + sampleStream = make_shared(cout, field_names); + + map values; + values["hostname"] = "my-hostname"; + values["extra"] = "wat"; + + sampleStream->write(values); + + return EXIT_SUCCESS; + } + +}; + +} +} + +using namespace trygvis::apps; +int main(int argc, char *argv[]) { + sample_convert app; + return launch_app(argc, argv, app); +} diff --git a/apps/sm-serial-read.cpp b/apps/sm-serial-read.cpp index f1cabad..d605ae4 100644 --- a/apps/sm-serial-read.cpp +++ b/apps/sm-serial-read.cpp @@ -1,12 +1,10 @@ -#include -#include +#include "SoilMoistureIo.h" +#include "json.hpp" +#include "apps.h" #include #include #include #include -#include -#include "json.hpp" -#include "apps.h" enum class Format { PLAIN, @@ -53,6 +51,7 @@ using namespace boost::asio; using namespace std; using namespace std::chrono; using namespace trygvis::apps; +using namespace trygvis::soil_moisture; namespace po = boost::program_options; using json = nlohmann::json; @@ -61,8 +60,8 @@ string hostname = get_hostname(); class port_handler { public: - port_handler(string device, serial_port &serial_port) : - device(device), port(serial_port) { + port_handler(string device, serial_port &serial_port, shared_ptr stream) : + device(device), port(serial_port), stream(stream) { } void run() { @@ -86,12 +85,11 @@ public: } void on_packet(shared_ptr> packet) { -// std::chrono::time_point ; auto timestamp = std::chrono::system_clock::now().time_since_epoch().count(); auto s = std::string((char *) packet->data(), packet->size()); cerr << "packet: " << s << endl; - static const boost::regex e("#(\\d+) = (\\d+)"); + static const boost::regex e("([a-zA-Z0-9]+)=([0-9]+)"); std::string::const_iterator start = s.begin(); std::string::const_iterator end = s.end(); @@ -104,27 +102,17 @@ public: start = what[0].second; static const string device_type = "serial"; - if (format == Format::JSON) { - json j; - j["hostname"] = hostname; - j["device_type"] = device_type; - j["device"] = device; - j["timestamp"] = timestamp; - j["sensor"] = sensor; - j["value"] = value; - cout << j << endl; - } else if (format == Format::SQL) { - cout << "INSERT INTO serial_sample(hostname, device_type, device, sensor, timestamp, value) VALUES(" - << hostname << ", " - << device_type << ", " - << device << ", " - << timestamp << ", " - << sensor << ", " - << value << ");" - << endl; - } else { // plain - cout << "sensor #" << sensor << " = " << value << endl; - } + map values; + values["hostname"] = hostname; + values["device_type"] = device_type; + values["device"] = device; + values["timestamp"] = to_string(timestamp); + values["sensor"] = sensor; + values["value"] = value; + +// cerr << sensor << " => " << value << endl; + + stream->write(values); flags |= boost::match_prev_avail; flags |= boost::match_not_bob; @@ -138,6 +126,8 @@ private: serial_port &port; uint8_t data[size]; mutable_buffers_1 buffer = boost::asio::buffer(data, size); + + shared_ptr stream; }; class sm_serial_read : public app { @@ -159,12 +149,13 @@ public: io_service io_service; - serial_port port(io_service, 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)); - port.set_option(serial_port_base::parity(serial_port_base::parity::even)); - port.set_option(serial_port_base::stop_bits(serial_port_base::stop_bits::two)); if (port.is_open()) { cerr << "port is open" << endl; @@ -172,7 +163,28 @@ public: cerr << "port is not open" << endl; } - port_handler(port_name, port).run(); + auto field_names = vector({ + "hostname", + "device_type", + "device", + "timestamp", + "sensor", + "value" + }); + shared_ptr sampleStream; + + if (format == Format::JSON) { + sampleStream = make_shared(cout, field_names); + } else if (format == Format::SQL) { + sampleStream = make_shared(cout, field_names); + } else if (format == Format::PLAIN) { + sampleStream = make_shared(cout, field_names); + } else { + cerr << "Unsupported format: " << boost::lexical_cast(format) << endl; + return EXIT_FAILURE; + } + + port_handler(port_name, port, sampleStream).run(); return EXIT_SUCCESS; } @@ -183,6 +195,7 @@ public: } using namespace trygvis::apps; + int main(int argc, char *argv[]) { sm_serial_read app; return launch_app(argc, argv, app); diff --git a/sample.json b/sample.json new file mode 100644 index 0000000..3ff82d4 --- /dev/null +++ b/sample.json @@ -0,0 +1,6 @@ +{ + "mac": "aa:bb:cc:dd:ee:ff", + "sensor": 1, + "timestamp": 124, + "value": 123 +} -- cgit v1.2.3