aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--README.md10
-rw-r--r--apps/CMakeLists.txt16
-rw-r--r--apps/sm-get-value.cpp139
-rw-r--r--ble/log.h11
5 files changed, 170 insertions, 14 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0cf3b20..0d48449 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,14 @@ find_package(PkgConfig)
# Use Clang by default: http://stackoverflow.com/a/7031553/245614
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
+
+IF(NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE Debug CACHE STRING
+ "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
+ FORCE)
+ENDIF(NOT CMAKE_BUILD_TYPE)
# Boost
set(Boost_USE_STATIC_LIBS OFF)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ec9c88c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# My BLE (Bluetooth Low Energy) Toys
+
+Building:
+
+ mkdir build
+ cd build
+ cmake ..
+ 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 e210716..9d68f79 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -2,7 +2,7 @@ set(APPS sm-get-value ble-inspect-device)
set(shared_sources SoilMoisture.cpp)
# Boost
-find_package(Boost COMPONENTS system log thread REQUIRED)
+find_package(Boost COMPONENTS system log thread program_options REQUIRED)
# Bluez
pkg_check_modules(BLUEZ bluez REQUIRED)
@@ -10,8 +10,21 @@ pkg_check_modules(BLUEZ bluez REQUIRED)
# pthreads
find_package(Threads REQUIRED)
+pkg_check_modules(PQXX libpqxx REQUIRED)
+
+include(ExternalProject)
+ExternalProject_Add(
+ JSON
+ PREFIX json
+ GIT_REPOSITORY https://github.com/nlohmann/json.git
+ GIT_TAG ec42245951fceb7594bfb24746c7449986c3c2a4
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND "")
+
foreach(app ${APPS})
include_directories("${PROJECT_SOURCE_DIR}/include")
+ include_directories("${CMAKE_BINARY_DIR}/apps/json/src/JSON/src")
add_executable(${app} ${app}.cpp ${shared_sources})
add_dependencies(${app} ble)
@@ -19,5 +32,6 @@ foreach(app ${APPS})
target_link_libraries(${app} ble)
target_link_libraries(${app} ${Boost_LIBRARIES})
target_link_libraries(${app} ${BLUEZ_LIBRARIES})
+ target_link_libraries(${app} ${PQXX_LIBRARIES})
target_link_libraries(${app} ${CMAKE_THREAD_LIBS_INIT})
endforeach(app)
diff --git a/apps/sm-get-value.cpp b/apps/sm-get-value.cpp
index 46177f2..97858f4 100644
--- a/apps/sm-get-value.cpp
+++ b/apps/sm-get-value.cpp
@@ -1,34 +1,137 @@
#include <iostream>
+#include <iomanip>
+#include <chrono>
#include <boost/uuid/uuid_io.hpp>
#include <boost/optional.hpp>
+#include <boost/program_options.hpp>
+#include <thread>
#include "ble/Bluetooth.h"
#include "SoilMoisture.h"
+#include "json.hpp"
+// I'm lazy
using namespace std;
+using namespace std::chrono;
using namespace trygvis::bluetooth;
using namespace trygvis::soil_moisture;
+using json = nlohmann::json;
-bool loop = true;
+enum class Format {
+ PLAIN,
+ JSON
+};
+
+void validate(boost::any &v, const std::vector<std::string> &values, Format *, int) {
+ using namespace boost::program_options;
+
+ const std::string &s = validators::get_single_string(values);
+
+ if (s == "json") {
+ v = boost::any(Format::JSON);
+ } else if (s == "plain") {
+ v = boost::any(Format::PLAIN);
+ } else {
+ throw validation_error(validation_error::invalid_option_value);
+ }
+}
+
+namespace boost {
+
+template<>
+string lexical_cast(const Format &arg) {
+ if (arg == Format::PLAIN)
+ return "plain";
+ else if (arg == Format::JSON)
+ return "json";
+ else
+ throw std::runtime_error("Unknown Format value: " + to_string(static_cast<std::underlying_type<Format>::type>(arg)));
+}
+
+}
+
+bool loop;
+Format format;
+time_point<system_clock> targetTime;
+unsigned int sleepTime;
+vector<unsigned int> sensors;
void withConnection(BluetoothGatt &gatt) {
SoilMoisture soilMoisture = SoilMoisture::create(gatt);
- int sensorCount = soilMoisture.getSensorCount();
+ const int sensorCount = soilMoisture.getSensorCount();
- while (loop) {
- for (uint8_t i = 0; i < sensorCount; i++) {
- uint16_t value = soilMoisture.getValue(i);
+ if (sensorCount == 0) {
+ throw runtime_error("Sensor count is 0");
+ }
- cout << "sensor=" << to_string(i) << ", value=" << (int) value << endl;
+ // If the user didn't specify any sensors, add all.
+ if (sensors.size() == 0) {
+ for (int i = 0; i < sensorCount; i++) {
+ sensors.push_back(i);
}
-
- sleep(1);
}
+
+ auto device = gatt.getDevice().getMac();
+
+ targetTime = system_clock::now();
+
+ do {
+ for (auto sensor : sensors) {
+ if (sensor >= sensorCount) {
+ // Ignore invalid sensors
+ continue;
+ }
+
+ auto epoch = system_clock::now().time_since_epoch();
+ auto timestamp = duration_cast<seconds>(epoch).count();
+ uint16_t value = soilMoisture.getValue((uint8_t) sensor);
+
+ if (format == Format::PLAIN) {
+ cout << "device=" << device.str()
+ << ", sensor=" << to_string(sensor)
+ << ", timestamp=" << to_string(timestamp)
+ << ", value=" << (int) value << endl;
+ } else if (format == Format::JSON) {
+ json j;
+ j["device"] = device.str();
+ j["sensor"] = sensor;
+ j["timestamp"] = timestamp;
+ j["value"] = value;
+ cout << j << endl;
+ }
+ }
+
+ targetTime = targetTime + seconds(sleepTime);
+ this_thread::sleep_until(targetTime);
+ } while (loop);
}
int main(int argc, char *argv[]) {
- if (argc != 2) {
- cerr << "usage: " << argv[0] << " [mac]" << endl;
+ namespace po = boost::program_options;
+
+ po::options_description desc("Options");
+ desc.add_options()
+ ("help", "produce help message")
+ ("device", po::value<string>()->required(), "MAC of device to poll")
+ ("sensor", po::value<vector<unsigned int>>(&sensors)->multitoken(), "Sensor to poll, defaults to all")
+ ("sleep", po::value<unsigned int>(&sleepTime)->default_value(0),
+ "How long to sleep in seconds between each poll. If not give, it will exit after first poll")
+ ("format", po::value<Format>(&format)->default_value(Format::PLAIN), "Output format");
+
+ po::variables_map vm;
+ auto parsed = po::parse_command_line(argc, argv, desc);
+ po::store(parsed, vm);
+ po::notify(vm);
+
+ auto unrecognized = po::collect_unrecognized(parsed.options, po::include_positional);
+
+ if (vm.count("help")) {
+ cerr << desc << "\n";
+ return EXIT_FAILURE;
+ }
+
+ if (unrecognized.size()) {
+ cerr << "Unrecognized option: " << unrecognized.at(0) << "\n";
return EXIT_FAILURE;
}
@@ -36,13 +139,23 @@ int main(int argc, char *argv[]) {
BluetoothSystem bluetoothSystem;
try {
- Mac mac = Mac::parseMac(argv[1]);
+ if (!vm.count("device")) {
+ cerr << "Missing required option: device" << endl;
+ cerr << desc << "\n";
+ return EXIT_FAILURE;
+ }
+
+ auto MAC = vm["device"].as<string>();
+ cout << "MAC " << MAC << "wat" << endl;
+ Mac mac = Mac::parseMac(MAC);
auto &adapter = getAdapter(0);
auto &device = adapter.getDevice(mac);
- while (loop) {
+ loop = sleepTime > 0;
+
+ do {
cout << "Connecting to device: " << device.getMac().str() << endl;
auto &gatt = device.connectGatt();
@@ -52,7 +165,7 @@ int main(int argc, char *argv[]) {
cout << "exception: " << e.what() << endl;
}
gatt.disconnect();
- }
+ } while (loop);
return EXIT_SUCCESS;
} catch (std::runtime_error ex) {
diff --git a/ble/log.h b/ble/log.h
index 1d62121..479c81c 100644
--- a/ble/log.h
+++ b/ble/log.h
@@ -3,6 +3,8 @@
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
+
+#ifdef DEBUG
#define D BOOST_LOG_TRIVIAL(debug)
#define I BOOST_LOG_TRIVIAL(info)
#define W BOOST_LOG_TRIVIAL(warning)
@@ -10,5 +12,14 @@
#define DF BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": "
#define IF BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": "
#define WF BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": "
+#else
+#define D if (false) BOOST_LOG_TRIVIAL(debug)
+#define I if (false) BOOST_LOG_TRIVIAL(info)
+#define W if (false) BOOST_LOG_TRIVIAL(warning)
+
+#define DF if (false) BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": "
+#define IF if (false) BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": "
+#define WF if (false) BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": "
+#endif
#endif