aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/CMakeLists.txt80
-rw-r--r--apps/SoilMoisture.cpp50
-rw-r--r--apps/SoilMoisture.h26
-rw-r--r--apps/apps.cpp2
-rw-r--r--apps/apps.h69
-rw-r--r--apps/ble-inspect-device.cpp8
-rw-r--r--apps/ble-scan.cpp4
-rw-r--r--apps/diller_util.cpp19
-rw-r--r--apps/diller_util.h14
-rw-r--r--apps/mqtt_support.h72
-rw-r--r--apps/sm-diller.cpp423
-rw-r--r--apps/sm-get-value.cpp12
-rw-r--r--ble/BluetoothImpl.h131
-rw-r--r--ble/LinuxBluetooth.cpp31
-rw-r--r--include/ble/Bluetooth.h49
m---------json0
-rw-r--r--sensor/include/trygvis/sensor.h43
-rw-r--r--sensor/include/trygvis/sensor/io.h2
-rw-r--r--sensor/main/io.cpp30
-rw-r--r--sensor/main/sensor.cpp2
-rw-r--r--sensor/test/SampleTest.cpp16
-rw-r--r--test/ByteBufferTest.cpp2
22 files changed, 865 insertions, 220 deletions
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index 34fbd30..98c9915 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -1,21 +1,3 @@
-list(APPEND APPS ble-inspect-device)
-list(APPEND APPS ble-scan)
-list(APPEND APPS sample-add-timestamp)
-list(APPEND APPS sample-convert)
-list(APPEND APPS sample-select)
-list(APPEND APPS sm-db-insert)
-list(APPEND APPS sm-db-select)
-list(APPEND APPS sm-get-value)
-list(APPEND APPS sm-serial-read)
-list(APPEND APPS sm-serial-read-all)
-
-list(APPEND INCLUDE_DIRECTORIES
- ${CMAKE_CURRENT_SOURCE_DIR}
- "${PROJECT_SOURCE_DIR}/include"
- "${PROJECT_SOURCE_DIR}/json/src"
- "${PROJECT_SOURCE_DIR}/gsl/include"
- "${PROJECT_SOURCE_DIR}/sensor/include")
-
#### Find all packages
function(find_header_and_lib PREFIX HEADER_NAME LIBRARY_NAME)
@@ -70,8 +52,6 @@ list(APPEND LIBRARIES "${LOG4CPLUS_LIBRARY}")
find_header_and_lib(MOSQUITTO mosquitto.h mosquitto)
if(MOSQUITTO_OK STREQUAL "OK")
- list(APPEND APPS mqtt-publish)
- set(mqtt-publish_SOURCES mqtt_support.cpp mqtt_support.h)
list(APPEND INCLUDE_DIRECTORIES "${MOSQUITTO_INCLUDE_DIRECTORY}")
list(APPEND LIBRARIES "${MOSQUITTO_LIBRARY}")
else()
@@ -81,26 +61,56 @@ endif()
message(STATUS "Dependency summary:")
message(STATUS "Log4cplus: -I${LOG4CPLUS_INCLUDE_DIRECTORY}, -L${LOG4CPLUS_LIBRARY}")
message(STATUS "Mosquitto: -I${MOSQUITTO_INCLUDE_DIRECTORY}, -L${MOSQUITTO_LIBRARY}")
-message(STATUS "Mosquittopp: -I${MOSQUITTOPP_INCLUDE_DIRECTORY}, -L${MOSQUITTOPP_LIBRARY}")
add_library(apps OBJECT
apps.cpp apps.h
- SoilMoisture.cpp SoilMoisture.h)
-target_include_directories(apps PUBLIC ${INCLUDE_DIRECTORIES})
+ SoilMoisture.cpp SoilMoisture.h
+ diller_util.cpp diller_util.h)
+target_include_directories(apps PUBLIC
+ "${PROJECT_SOURCE_DIR}/include"
+ "${PROJECT_SOURCE_DIR}/json/src"
+ )
-foreach(app ${APPS})
- add_executable(${app} ${app}.cpp $<TARGET_OBJECTS:apps> ${${app}_SOURCES})
+function(add_app)
+ cmake_parse_arguments(ADD_APP "" "NAME" "EXTRA" ${ARGN})
- target_include_directories(${app} PUBLIC ${INCLUDE_DIRECTORIES})
+ set(app "${ADD_APP_NAME}")
- target_link_libraries(${app}
- ble
- trygvis-sensor
- ${LIBRARIES}
- ${Boost_LIBRARIES}
- ${BLUEZ_LIBRARIES}
- ${PQXX_LIBRARIES}
- ${CMAKE_THREAD_LIBS_INIT})
+ add_executable(${app} ${app}.cpp $<TARGET_OBJECTS:apps> "${ADD_APP_EXTRA}")
+
+ target_include_directories(${app} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ "${PROJECT_SOURCE_DIR}/include"
+ "${PROJECT_SOURCE_DIR}/json/src"
+ "${PROJECT_SOURCE_DIR}/gsl/include"
+ "${PROJECT_SOURCE_DIR}/sensor/include"
+ )
+ target_link_libraries(${app}
+ ble
+ trygvis-sensor
+ ${LIBRARIES}
+ ${Boost_LIBRARIES}
+ ${BLUEZ_LIBRARIES}
+ ${PQXX_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ )
install(TARGETS ${app} RUNTIME DESTINATION bin)
-endforeach()
+endfunction()
+
+add_app(NAME ble-inspect-device)
+add_app(NAME ble-scan)
+add_app(NAME sample-add-timestamp)
+add_app(NAME sample-convert)
+add_app(NAME sample-select)
+add_app(NAME sm-db-insert)
+add_app(NAME sm-db-select)
+add_app(NAME sm-get-value)
+add_app(NAME sm-serial-read)
+add_app(NAME sm-serial-read-all)
+
+if(MOSQUITTO_OK STREQUAL "OK")
+ set(MQTT_SOURCES mqtt_support.cpp mqtt_support.h)
+ add_app(NAME mqtt-publish EXTRA "${MQTT_SOURCES}")
+ add_app(NAME sm-diller EXTRA "${MQTT_SOURCES}")
+endif()
diff --git a/apps/SoilMoisture.cpp b/apps/SoilMoisture.cpp
index 13578f6..4b9dfe5 100644
--- a/apps/SoilMoisture.cpp
+++ b/apps/SoilMoisture.cpp
@@ -16,6 +16,7 @@ auto bluetooth_base_uuid =
const boost::uuids::uuid soil_moisture_service = makeUuid(trygvis_io_base_uuid, 0x00, 0x10);
const boost::uuids::uuid soil_moisture_characteristic = makeUuid(trygvis_io_base_uuid, 0x00, 0x11);
const boost::uuids::uuid temperature_characteristic = makeUuid(bluetooth_base_uuid, 0x2a, 0x1e);
+const boost::uuids::uuid light_characteristic = makeUuid(trygvis_io_base_uuid, 0x00, 0x12);
using namespace trygvis::bluetooth;
@@ -64,13 +65,15 @@ ByteBuffer createSetUpdateInterval(uint8_t sensor, uint8_t interval_in_seconds)
SoilMoisture SoilMoisture::create(shared_ptr<BluetoothGatt> gatt) {
gatt->discoverServices();
- auto service = gatt->findService(soil_moisture_service);
+ o<shared_ptr<BluetoothGattService>> s = gatt->findService(soil_moisture_service);
- if (!service) {
+ if (!s) {
throw runtime_error("The device is missing the soil moisture service");
}
- auto c = service->findCharacteristic(soil_moisture_characteristic);
+ shared_ptr<BluetoothGattService> &service = *s;
+
+ o<shared_ptr<BluetoothGattCharacteristic>> c = service->findCharacteristic(soil_moisture_characteristic);
if (!c) {
throw runtime_error("The device is missing the soil moisture characteristic");
@@ -78,16 +81,20 @@ SoilMoisture SoilMoisture::create(shared_ptr<BluetoothGatt> gatt) {
auto temperature = service->findCharacteristic(temperature_characteristic);
- return SoilMoisture(gatt, *service, c.get(), temperature);
+ auto light = service->findCharacteristic(light_characteristic);
+
+ return SoilMoisture(gatt, service, c.operator*(), temperature, light);
}
-SoilMoisture::SoilMoisture(const shared_ptr<BluetoothGatt> &gatt, BluetoothGattService &s,
- const BluetoothGattCharacteristic &soilMoistureCharacteristic,
- const o<const BluetoothGattCharacteristic &> temperatureCharacteristic)
+SoilMoisture::SoilMoisture(const shared_ptr<BluetoothGatt> &gatt,
+ const shared_ptr<BluetoothGattService> &s,
+ const BluetoothGattCharacteristicPtr &soilMoistureCharacteristic,
+ const o<BluetoothGattCharacteristicPtr> temperatureCharacteristic,
+ const o<BluetoothGattCharacteristicPtr> lightCharacteristic)
: gatt(gatt), s(s), soilMoistureCharacteristic(soilMoistureCharacteristic),
- temperatureCharacteristic(temperatureCharacteristic) {}
+ temperatureCharacteristic(temperatureCharacteristic), lightCharacteristic(lightCharacteristic) { }
-ByteBuffer SoilMoisture::writeAndRead(const BluetoothGattCharacteristic &c, ByteBuffer &requestBytes) {
+ByteBuffer SoilMoisture::writeAndRead(const BluetoothGattCharacteristicPtr &c, ByteBuffer &requestBytes) {
requestBytes.setCursor(0);
uint8_t expectedCode = requestBytes.get8(0);
@@ -131,14 +138,15 @@ string SoilMoisture::getName(uint8_t sensor) {
buffer.copy(bytes, bytesLeft);
if (bytesLeft == 0 || bytesLeft < (bytes[0] + 1)) {
- throw runtime_error("Bad response from device. buffer size: " + to_string(bytesLeft) + ", buffer[0]=" + to_string((int)bytes[0]));
+ throw runtime_error("Bad response from device. buffer size: " + to_string(bytesLeft) + ", buffer[0]=" +
+ to_string((int) bytes[0]));
}
- return string((const char *)&bytes[1], bytes[0]);
+ return string((const char *) &bytes[1], bytes[0]);
}
bool SoilMoisture::hasTemperatureSensor() {
- return temperatureCharacteristic.is_initialized();
+ return (bool) temperatureCharacteristic;
}
/**
@@ -149,9 +157,7 @@ o<double> SoilMoisture::readTemperature() {
return o<double>();
}
- auto &c = temperatureCharacteristic.get();
-
- auto responseBytes = gatt->readValue(c);
+ auto responseBytes = gatt->readValue(*temperatureCharacteristic);
if (responseBytes.getSize() < 2) {
throw runtime_error("Unexpected number of bytes read: " + to_string(responseBytes.getSize()));
@@ -168,5 +174,19 @@ o<double> SoilMoisture::readTemperature() {
return o<double>(temperature);
}
+void SoilMoisture::setLight(uint8_t light, uint8_t value) {
+ if (!lightCharacteristic) {
+ return;
+ }
+
+ auto responseBytes = gatt->readValue(*lightCharacteristic);
+
+ if (responseBytes.getSize() < 2) {
+ throw runtime_error("Unexpected number of bytes read: " + to_string(responseBytes.getSize()));
+ }
+
+ bitset<8> b0 = responseBytes.read8();
+}
+
}
}
diff --git a/apps/SoilMoisture.h b/apps/SoilMoisture.h
index 99b698d..0ad1d15 100644
--- a/apps/SoilMoisture.h
+++ b/apps/SoilMoisture.h
@@ -2,13 +2,14 @@
#include <ble/Bluetooth.h>
#include <boost/uuid/uuid.hpp>
+#include <experimental/optional>
namespace trygvis {
namespace sensor {
using namespace trygvis::bluetooth;
-template <typename T>
-using o = boost::optional<T>;
+template<typename T>
+using o = std::experimental::optional<T>;
enum class sm_cmd_code : uint8_t {
SM_CMD_GET_SENSOR_COUNT = 1,
@@ -18,6 +19,8 @@ enum class sm_cmd_code : uint8_t {
SM_CMD_SET_SENSOR_NAME = 5,
SM_CMD_GET_SENSOR_NAME = 6,
SM_CMD_SET_UPDATE_INTERVAL = 7,
+ // 8 is used
+ SM_CMD_SET_LIGHT = 9,
SM_CMD_FAIL = 255,
};
@@ -38,17 +41,22 @@ public:
o<double> readTemperature();
+ void setLight(uint8_t light, uint8_t value);
+
private:
- SoilMoisture(const shared_ptr<BluetoothGatt> &gatt, BluetoothGattService &s,
- const BluetoothGattCharacteristic &soilMoistureCharacteristic,
- const o<const BluetoothGattCharacteristic &> temperatureCharacteristic);
+ SoilMoisture(const shared_ptr<BluetoothGatt> &gatt,
+ const shared_ptr<BluetoothGattService> &s,
+ const shared_ptr<BluetoothGattCharacteristic> &soilMoistureCharacteristic,
+ const o<BluetoothGattCharacteristicPtr> temperatureCharacteristic,
+ const o<BluetoothGattCharacteristicPtr> lightCharacteristic);
- ByteBuffer writeAndRead(const BluetoothGattCharacteristic &c, ByteBuffer &requestBytes);
+ ByteBuffer writeAndRead(const BluetoothGattCharacteristicPtr &c, ByteBuffer &requestBytes);
shared_ptr<BluetoothGatt> gatt;
- BluetoothGattService &s;
- const BluetoothGattCharacteristic &soilMoistureCharacteristic;
- const o<const BluetoothGattCharacteristic &> temperatureCharacteristic;
+ shared_ptr<BluetoothGattService> s;
+ const BluetoothGattCharacteristicPtr soilMoistureCharacteristic;
+ const o<BluetoothGattCharacteristicPtr> temperatureCharacteristic;
+ const o<BluetoothGattCharacteristicPtr> lightCharacteristic;
};
}
}
diff --git a/apps/apps.cpp b/apps/apps.cpp
index b21d27e..56abc7b 100644
--- a/apps/apps.cpp
+++ b/apps/apps.cpp
@@ -56,7 +56,7 @@ const po::options_description logging_options() {
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)
+ string pattern = "%-5p %D{%Y-%m-%d %H:%M:%S} " + app_name + "/%-20c %m%n"; // add %M (function name)
PatternLayout *layout = new PatternLayout(LOG4CPLUS_TEXT(pattern));
console->setLayout(auto_ptr<Layout>(layout));
diff --git a/apps/apps.h b/apps/apps.h
index f3d6eae..9173ae0 100644
--- a/apps/apps.h
+++ b/apps/apps.h
@@ -8,6 +8,8 @@
#include <iosfwd>
#include <experimental/optional>
#include <json.hpp>
+#include <mutex>
+#include <condition_variable>
namespace trygvis {
namespace apps {
@@ -22,12 +24,61 @@ 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;
};
-template <typename T>
+class waitable {
+protected:
+ std::condition_variable cv;
+ std::mutex mutex;
+
+ waitable() {
+ }
+
+ virtual ~waitable() {
+ }
+
+public:
+ void wait() {
+ std::unique_lock<std::mutex> lock(mutex);
+ cv.wait(lock);
+ }
+
+ template<class Predicate>
+ void wait(Predicate predicate) {
+ std::unique_lock<std::mutex> lock(mutex);
+ cv.wait(lock, predicate);
+ }
+
+ template<class Rep, class Period>
+ std::cv_status wait_for(const std::chrono::duration<Rep, Period> &rel_time) {
+ std::unique_lock<std::mutex> lock(mutex);
+ return cv.wait_for(lock, rel_time);
+ }
+
+ template<class Rep, class Period, class Predicate>
+ bool wait_for(const std::chrono::duration<Rep, Period> &rel_time, Predicate predicate) {
+ std::unique_lock<std::mutex> lock(mutex);
+ return cv.wait_for(lock, rel_time, predicate);
+ }
+
+ template<class Clock, class Duration>
+ std::cv_status wait_until(const std::chrono::time_point<Clock, Duration> &timeout_time) {
+ std::unique_lock<std::mutex> lock(mutex);
+ return cv.wait_until(lock, timeout_time);
+ };
+
+ template<class Clock, class Duration, class Predicate>
+ bool wait_until(const std::chrono::time_point<Clock, Duration> &timeout_time,
+ Predicate predicate) {
+ std::unique_lock<std::mutex> lock(mutex);
+ return cv.wait_until(lock, timeout_time, predicate);
+ }
+};
+
+template<typename T>
T get(json j, std::string key) {
auto ref = j[key];
@@ -41,7 +92,7 @@ T get(json j, std::string key) {
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;
@@ -52,7 +103,7 @@ 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;
@@ -62,9 +113,9 @@ public:
app &operator=(const app &) = delete;
- virtual void add_options(po::options_description_easy_init &options) {}
+ 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;
@@ -75,12 +126,12 @@ std::string get_hostname();
int real_main(app *app, int argc, const char *argv[]);
-template <typename T>
+template<typename T>
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
index 2140e03..baee93a 100644
--- a/apps/ble-inspect-device.cpp
+++ b/apps/ble-inspect-device.cpp
@@ -29,11 +29,11 @@ public:
gatt->discoverServices();
- vector<BluetoothGattService *> services = gatt->getServices();
+ auto services = gatt->getServices();
cout << "Device has " << services.size() << " services" << endl;
for (auto &s : services) {
- const vector<BluetoothGattCharacteristic *> characteristics = s->getCharacteristics();
+ auto characteristics = s->getCharacteristics();
cout << "Service: UUID: " << s->getUuid() << ", has " << characteristics.size() << " characteristics"
<< endl;
@@ -60,10 +60,10 @@ public:
scan_callback(device);
return EXIT_SUCCESS;
- } catch (std::runtime_error ex) {
+ } catch (std::runtime_error &ex) {
cout << "std::runtime_error: " << ex.what() << endl;
return EXIT_FAILURE;
- } catch (std::exception ex) {
+ } 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
index 158af14..b148752 100644
--- a/apps/ble-scan.cpp
+++ b/apps/ble-scan.cpp
@@ -67,10 +67,10 @@ public:
for_each(begin(seen_devices), end(seen_devices), [&](auto mac) { cout << mac.str() << endl; });
return EXIT_SUCCESS;
- } catch (std::runtime_error ex) {
+ } catch (std::runtime_error &ex) {
cout << "std::runtime_error: " << ex.what() << endl;
return EXIT_FAILURE;
- } catch (std::exception ex) {
+ } catch (std::exception &ex) {
cout << "std::exception: " << ex.what() << endl;
return EXIT_FAILURE;
}
diff --git a/apps/diller_util.cpp b/apps/diller_util.cpp
new file mode 100644
index 0000000..420ebc6
--- /dev/null
+++ b/apps/diller_util.cpp
@@ -0,0 +1,19 @@
+#include "diller_util.h"
+
+#include <string>
+
+namespace trygvis {
+namespace diller {
+
+using namespace std;
+
+string diller_topic_for_property_value(const string &device, const string &property) {
+ return "/diller/" + device + "/property/" + property + "/value";
+}
+
+string diller_topic_for_property_name(const string &device, const string &property) {
+ return "/diller/" + device + "/property/" + property + "/name";
+}
+
+}; // namespace diller
+}; // namespace trygvis
diff --git a/apps/diller_util.h b/apps/diller_util.h
new file mode 100644
index 0000000..c7b74f2
--- /dev/null
+++ b/apps/diller_util.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <string>
+
+namespace trygvis {
+namespace diller {
+
+using std::string;
+
+string diller_topic_for_property_value(const string &device, const string &property);
+string diller_topic_for_property_name(const string &device, const string &property);
+
+}; // namespace diller
+}; // namespace trygvis
diff --git a/apps/mqtt_support.h b/apps/mqtt_support.h
index 48a6c39..ab319fd 100644
--- a/apps/mqtt_support.h
+++ b/apps/mqtt_support.h
@@ -2,10 +2,10 @@
#define TRYGVIS_MQTT_SUPPORT_H
#include <mutex>
+#include <shared_mutex>
#include <string>
#include <exception>
#include <cstring>
-#include <span.h>
#include <log4cplus/logger.h>
#include <log4cplus/loggingmacros.h>
#include <atomic>
@@ -13,16 +13,14 @@
#include <limits.h>
#include <experimental/optional>
#include "mosquitto.h"
+#include "apps.h"
namespace trygvis {
namespace mqtt_support {
-template<typename T>
-using o = std::experimental::optional<T>;
-
+using namespace trygvis::apps;
using namespace std;
using namespace log4cplus;
-using namespace gsl;
static inline
string error_to_string(int rc) {
@@ -32,6 +30,26 @@ string error_to_string(int rc) {
return string(mosquitto_strerror(rc));
}
+static
+vector<string> mqtt_tokenize_topic(string path) {
+ char **topics;
+ int topic_count;
+ int i;
+
+ mosquitto_sub_topic_tokenise(path.c_str(), &topics, &topic_count);
+
+ vector<string> res;
+ for (i = 0; i < topic_count; i++) {
+ if (topics[i] != NULL) {
+ res.emplace_back(topics[i]);
+ }
+ }
+
+ mosquitto_sub_topic_tokens_free(&topics, topic_count);
+
+ return res;
+}
+
class mqtt_error : public std::runtime_error {
public:
@@ -79,7 +97,7 @@ enum mqtt_client_personality {
};
template<mqtt_client_personality personality>
-class mqtt_client : private mqtt_lib {
+class mqtt_client : public waitable, private mqtt_lib {
template<bool>
struct personality_tag {
};
@@ -101,8 +119,8 @@ class mqtt_client : private mqtt_lib {
// bool should_reconnect_;
int unacked_messages_;
- condition_variable cv;
- mutex cv_mutex;
+// condition_variable cv;
+// mutex cv_mutex;
void assert_success(const string &function, int rc) {
if (rc != MOSQ_ERR_SUCCESS) {
@@ -113,9 +131,20 @@ class mqtt_client : private mqtt_lib {
public:
mqtt_client(const string &host, const int port, const int keep_alive, const o<string> &client_id,
const bool clean_session) :
- host(host), port(port), connecting_(false), connected_(false), /*should_reconnect_(false),*/
- keep_alive(keep_alive), unacked_messages_(0) {
- mosquitto = mosquitto_new(client_id ? (*client_id).c_str() : nullptr, clean_session, this);
+ host(host), port(port), connecting_(false), connected_(false), /*should_reconnect_(false),*/
+ keep_alive(keep_alive), unacked_messages_(0) {
+ const char *id = nullptr;
+
+ if (client_id) {
+ id = client_id->c_str();
+ }
+ else {
+ if (!clean_session) {
+ throw mqtt_error("If client id is not specified, clean session must be true", MOSQ_ERR_INVAL);
+ }
+ }
+
+ mosquitto = mosquitto_new(id, clean_session, this);
if (!mosquitto) {
string err = strerror(errno);
throw runtime_error("Could not initialize mosquitto instance: " + err);
@@ -162,11 +191,6 @@ private:
}
public:
- void wait() {
- unique_lock<mutex> lk(cv_mutex);
- cv.wait(lk);
- }
-
int unacked_messages() {
guard lock(this_mutex);
return unacked_messages_;
@@ -235,7 +259,7 @@ private:
void on_disconnect_wrapper(int rc) {
guard lock(this_mutex);
- LOG4CPLUS_INFO(logger, "Disconnected");
+ LOG4CPLUS_INFO(logger, "Disconnected, rc=" << error_to_string(rc));
bool was_connecting = connecting_, was_connected = connected_;
connecting_ = connected_ = false;
@@ -320,6 +344,18 @@ public:
assert_success("mosquitto_subscribe", rc);
}
+ void publish(int *mid, const string &topic, int qos, bool retain, const string &s) {
+ auto len = s.length();
+
+ auto int_max = std::numeric_limits<int>::max();
+
+ if (len > int_max) {
+ len = static_cast<decltype(len)>(int_max);
+ }
+
+ publish(mid, topic, qos, retain, static_cast<int>(len), s.c_str());
+ }
+
void publish(int *mid, const string &topic, int qos, bool retain, int payload_len, const void *payload) {
// if (!connected_) {
// throw mqtt_error("not connected", MOSQ_ERR_NO_CONN);
@@ -329,7 +365,7 @@ public:
int rc = mosquitto_publish(mosquitto, mid, topic.c_str(), payload_len, payload, qos, retain);
- if(rc == MOSQ_ERR_SUCCESS) {
+ if (rc == MOSQ_ERR_SUCCESS) {
guard lock(this_mutex);
unacked_messages_++;
}
diff --git a/apps/sm-diller.cpp b/apps/sm-diller.cpp
new file mode 100644
index 0000000..2b1d63d
--- /dev/null
+++ b/apps/sm-diller.cpp
@@ -0,0 +1,423 @@
+#include "ble/Bluetooth.h"
+#include "SoilMoisture.h"
+#include "diller_util.h"
+#include "trygvis/sensor.h"
+#include "trygvis/sensor/io.h"
+#include "apps.h"
+#include "mqtt_support.h"
+
+#include <boost/uuid/uuid_io.hpp>
+#include <log4cplus/loggingmacros.h>
+#include <iostream>
+#include <iomanip>
+#include <chrono>
+#include <list>
+#include <thread>
+#include <typeinfo>
+
+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;
+using namespace trygvis::mqtt_support;
+using namespace trygvis::diller;
+
+static struct {
+ string server;
+ string client_id;
+ int sleep_time;
+} opts;
+
+struct device_command {
+ virtual ~device_command() {
+ }
+};
+
+struct set_light final : public virtual device_command {
+ set_light(uint8_t light, uint8_t value) : light(light), value(value) {
+ }
+
+ virtual ~set_light() {
+ }
+
+ const uint8_t light;
+ const uint8_t value;
+};
+
+struct diller_command {
+ diller_command() {
+ cerr << "diller_command" << endl;
+ }
+
+ virtual ~diller_command() {
+ cerr << "~diller_command" << endl;
+ }
+};
+
+struct publish_soil_moisture_value final : public virtual diller_command {
+ publish_soil_moisture_value(uint8_t sensor, int value) : sensor(sensor), value(value) {
+ cerr << "publish_soil_moisture_value, this=" << (this) << endl;
+ }
+
+ virtual ~publish_soil_moisture_value() {
+ cerr << "~publish_soil_moisture_value, this=" << (this) << endl;
+ }
+
+ const int sensor;
+ const int value;
+};
+
+struct publish_soil_moisture_sensor_name final : public virtual diller_command {
+ publish_soil_moisture_sensor_name(uint8_t sensor, string name) : sensor(sensor), name(name) {
+ }
+
+ virtual ~publish_soil_moisture_sensor_name() {
+ }
+
+ const int sensor;
+ const string name;
+};
+
+atomic<bool> loop{true};
+
+mutex main_mutex;
+condition_variable main_cv;
+std::list<unique_ptr<device_command>> to_device;
+std::list<unique_ptr<diller_command>> to_diller;
+
+class diller_mqtt_client : public mqtt_client<polling> {
+public:
+ diller_mqtt_client(const Mac mac, const string &host, const int port, const int keep_alive,
+ const o<string> &client_id, const bool clean_session) :
+ mqtt_client(host, port, keep_alive, client_id, clean_session), mac(mac),
+ light_path(diller_topic_for_property_value(mac.str(), "light")) {
+ }
+
+ void run() {
+ connect();
+
+ while (loop) {
+ poll();
+
+ std::unique_lock<std::mutex> lock(main_mutex);
+ auto res = main_cv.wait_for(lock, 1s);
+
+ if (res == cv_status::no_timeout) {
+ if (!to_diller.empty()) {
+ diller_command &command = *to_diller.front();
+
+ if (typeid(command) == typeid(struct publish_soil_moisture_value &)) {
+ auto cmd = dynamic_cast<struct publish_soil_moisture_value &>(command);
+
+ LOG4CPLUS_DEBUG(logger, "Publishing soil moisture value: sensor=" << cmd.sensor
+ << ", value=" << cmd.value);
+
+ int mid;
+
+ const string topic = diller_topic_for_property_value(mac.str(), "soil-moisture-" +
+ std::to_string(cmd.sensor));
+ auto qos = 0;
+ publish(&mid, topic, qos, false, std::to_string(cmd.value));
+
+ LOG4CPLUS_DEBUG(logger, "Published as " << mid);
+ } else if (typeid(command) == typeid(struct publish_soil_moisture_sensor_name &)) {
+ auto cmd = dynamic_cast<struct publish_soil_moisture_sensor_name &>(command);
+
+ LOG4CPLUS_DEBUG(logger, "Publishing soil moisture sensor name: sensor=" << cmd.sensor
+ << ", name=" << cmd.name);
+
+ int mid;
+
+ const string topic = diller_topic_for_property_name(mac.str(), "soil-moisture-" +
+ std::to_string(cmd.sensor));
+ auto qos = 0;
+ publish(&mid, topic, qos, true, cmd.name);
+
+ LOG4CPLUS_DEBUG(logger, "Published as " << mid);
+ }
+
+ to_diller.pop_front();
+ }
+ }
+ }
+
+ LOG4CPLUS_INFO(logger, "Stopping");
+
+ disconnect();
+
+ LOG4CPLUS_INFO(logger, "Stopped");
+ }
+
+protected:
+ void on_connect(int rc) override {
+ if (rc == MOSQ_ERR_SUCCESS) {
+ LOG4CPLUS_INFO(logger, "Subscribing to " << light_path);
+ subscribe(nullptr, light_path, 0);
+ }
+ }
+
+ void on_message(const struct mosquitto_message *message) override {
+ LOG4CPLUS_INFO(logger, "got message: " << message->topic);
+
+ auto segments = mqtt_tokenize_topic(message->topic);
+
+ // /diller/aa:bb:cc:dd:ee:ff/property/light/value
+ if (segments.size() != 5 ||
+ segments[0] != "diller" ||
+ // $mac
+ segments[2] != "property" ||
+ // $property
+ segments[4] != "value") {
+ LOG4CPLUS_INFO(logger, "Unknown message topic: " << message->topic);
+ return;
+ }
+
+ if (message->payloadlen != 1) {
+ LOG4CPLUS_WARN(logger, "Unknown message payload, expected exactly one byte, got " << message->payloadlen <<
+ " bytes on topic " << message->topic);
+ return;
+ }
+
+ auto property_name = segments[3];
+
+ if (property_name == "light") {
+ std::unique_lock<std::mutex> lock(main_mutex);
+ uint8_t value = static_cast<uint8_t *>(message->payload)[0];
+
+ const int light = 0;
+
+ LOG4CPLUS_INFO(logger,
+ "Pushing command set_light(light=" << light << ", value=" << static_cast<int>(value) << ")");
+
+ to_device.push_back(make_unique<set_light>(light, value));
+ main_cv.notify_all();
+ } else {
+ LOG4CPLUS_INFO(logger, "Unknown property name " << property_name);
+ }
+ }
+
+private:
+ const Mac mac;
+ const string light_path;
+
+ Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("diller_mqtt_client"));
+};
+
+void mqtt_thread(Mac &mac) {
+ Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("mqtt_thread"));
+
+ try {
+ diller_mqtt_client mqtt_client(mac, opts.server, 1883, 60, o<string>(opts.client_id), true);
+
+ mqtt_client.run();
+ } catch (std::runtime_error &ex) {
+ LOG4CPLUS_WARN(logger, "std::exception: " << ex.what());
+ } catch (std::exception &ex) {
+ LOG4CPLUS_WARN(logger, "std::exception: " << ex.what());
+ }
+}
+
+class sm_diller : public app {
+public:
+ sm_diller() : app("sm-diller") { }
+
+ ~sm_diller() = default;
+
+ std::chrono::duration<int> sleep_time;
+ vector<uint8_t> sensorIndexes;
+ vector<pair<uint8_t, string>> sensors;
+
+ void add_options(po::options_description_easy_init &options) override {
+ auto opt_server = po::value<string>(&opts.server)->required();
+ auto opt_client_id = po::value<string>(&opts.client_id)->default_value("sm-diller-" + get_hostname());
+ auto default_sleep = po::value<>(&opts.sleep_time)->default_value(10);
+
+ options("server", opt_server, "MQTT server");
+ options("client-id", opt_client_id, "MQTT client id");
+
+ options("device", po::value<string>()->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");
+ }
+
+ int main(app_execution &execution) override {
+ BluetoothSystem bluetoothSystem;
+
+ auto desc = execution.desc;
+ auto vm = execution.vm;
+
+ std::thread mqtt_t;
+ int ret;
+
+ try {
+ if (!vm.count("device")) {
+ cerr << "Missing required option: device" << endl;
+ cerr << desc << "\n";
+ return EXIT_FAILURE;
+ }
+
+ auto mac_string = vm["device"].as<string>();
+
+ Mac mac = Mac::parseMac(mac_string);
+
+ auto adapter = bluetoothSystem.getAdapter("0");
+
+ auto device = adapter->getDevice(mac);
+
+ sleep_time = std::chrono::seconds(opts.sleep_time);
+
+ mqtt_t = std::thread(mqtt_thread, std::ref(mac));
+
+ do {
+ try {
+ LOG4CPLUS_INFO(execution.logger, "Connecting to device: " << device->getMac().str());
+ auto gatt = device->connectGatt();
+
+ withConnection(execution.logger, gatt);
+ } catch (BluetoothException &e) {
+ LOG4CPLUS_ERROR(execution.logger, "Bluetooth error: " << e.what());
+ } catch (runtime_error &e) {
+ LOG4CPLUS_ERROR(execution.logger, "Exception: " << e.what());
+ }
+
+ LOG4CPLUS_DEBUG(execution.logger, "Sleeping for " << std::to_string(sleep_time.count()));
+
+ this_thread::sleep_until(system_clock::now() + sleep_time);
+ } while (loop);
+
+ unique_lock <mutex> lock(main_mutex);
+ main_cv.notify_all();
+
+ ret = EXIT_SUCCESS;
+ } catch (std::runtime_error &ex) {
+ LOG4CPLUS_WARN(execution.logger, "std::runtime_error: " << ex.what());
+ ret = EXIT_FAILURE;
+ } catch (std::exception &ex) {
+ LOG4CPLUS_WARN(execution.logger, "std::exception: " << ex.what());
+ ret = EXIT_FAILURE;
+ }
+
+ if (mqtt_t.joinable()) {
+ mqtt_t.join();
+ }
+
+ return ret;
+ }
+
+ void read_sensors(SoilMoisture &soilMoisture, string mac) {
+ auto epoch = system_clock::now().time_since_epoch();
+ auto timestamp = duration_cast<seconds>(epoch).count();
+
+ auto tempO = soilMoisture.readTemperature();
+ if (tempO) {
+ tempO.value();
+ }
+
+ for (auto s : sensors) {
+ auto sensor = s.first;
+ auto name = s.second;
+
+ uint16_t value = soilMoisture.getValue(sensor);
+
+ {
+ unique_lock <mutex> lock(main_mutex);
+ to_diller.push_back(make_unique<publish_soil_moisture_value>(sensor, value));
+ }
+ }
+
+ main_cv.notify_all();
+ }
+
+ void withConnection(const Logger &logger, shared_ptr<BluetoothGatt> gatt) {
+ SoilMoisture soilMoisture = SoilMoisture::create(gatt);
+
+ if (sensors.empty()) {
+ 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 (uint8_t i = 0; i < sensorCount; i++) {
+ sensorIndexes.push_back(i);
+ }
+ }
+
+ for_each(begin(sensorIndexes), end(sensorIndexes), [&](uint8_t i) {
+ if (i >= sensorCount) {
+ // Ignore invalid sensors
+ return;
+ }
+
+ auto name = soilMoisture.getName(i);
+ sensors.push_back(make_pair(i, name));
+
+ unique_lock <mutex> lock(main_mutex);
+ to_diller.push_back(make_unique<publish_soil_moisture_sensor_name>(i, name));
+ });
+
+ main_cv.notify_all();
+ }
+
+ auto mac = gatt->getDevice().getMac().str();
+ if (!loop) {
+ read_sensors(soilMoisture, mac);
+ } else {
+ std::chrono::time_point<system_clock> target_time;
+ target_time = system_clock::now();
+
+ do {
+ target_time = target_time + seconds(sleep_time);
+
+ read_sensors(soilMoisture, mac);
+
+ do {
+ unique_lock <mutex> lock(main_mutex);
+ auto res = main_cv.wait_until(lock, target_time);
+
+ if (res == cv_status::no_timeout) {
+ LOG4CPLUS_DEBUG(logger, "no_timeout, to_device.size()=" << to_device.size());
+ }
+
+ if (!to_device.empty()) {
+ device_command &command = *std::move(to_device.front());
+ to_device.pop_front();
+ if (typeid(command) == typeid(set_light &)) {
+ auto sl = dynamic_cast<const set_light &>(command);
+ LOG4CPLUS_DEBUG(logger, "performing Set light: light=" << static_cast<int>(sl.light)
+ << ", value=" << static_cast<int>(sl.value));
+
+ try {
+ soilMoisture.setLight(sl.light, sl.value);
+ } catch (std::runtime_error &e) {
+ LOG4CPLUS_WARN(logger,
+ "Could not execute setLight, light=" << static_cast<int>(sl.light)
+ << ", value=" << static_cast<int>(sl.value)
+ << ", error: " << e.what());
+ }
+ }
+ }
+ } while (target_time > system_clock::now());
+ } while (loop);
+ }
+ }
+};
+
+}
+}
+
+int main(int argc, const char *argv[]) {
+ using app_t = trygvis::apps::sm_diller;
+
+ return real_main(new app_t(), argc, argv);
+}
diff --git a/apps/sm-get-value.cpp b/apps/sm-get-value.cpp
index 0572155..42f5da3 100644
--- a/apps/sm-get-value.cpp
+++ b/apps/sm-get-value.cpp
@@ -35,9 +35,9 @@ public:
vector<pair<unsigned int, string>> sensors;
KeyDictionary dict;
- SampleKey *hostname_key = dict.indexOf("hostname");
- SampleKey *device_key = dict.indexOf("device");
- SampleKey *timestamp_key = dict.indexOf("timestamp_ms");
+ const SampleKey *hostname_key = dict.indexOf("hostname");
+ const SampleKey *device_key = dict.indexOf("device");
+ const 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);
@@ -96,10 +96,10 @@ public:
} while (loop);
return EXIT_SUCCESS;
- } catch (std::runtime_error ex) {
+ } catch (std::runtime_error &ex) {
cout << "std::runtime_error: " << ex.what() << endl;
return EXIT_FAILURE;
- } catch (std::exception ex) {
+ } catch (std::exception &ex) {
cout << "std::exception: " << ex.what() << endl;
return EXIT_FAILURE;
}
@@ -118,7 +118,7 @@ public:
auto tempO = soilMoisture.readTemperature();
if (tempO) {
- sample.set(dict.indexOf("temperature"), std::to_string(tempO.get()));
+ sample.set(dict.indexOf("temperature"), std::to_string(tempO.value()));
}
int i = 0;
diff --git a/ble/BluetoothImpl.h b/ble/BluetoothImpl.h
index 4627443..8663b20 100644
--- a/ble/BluetoothImpl.h
+++ b/ble/BluetoothImpl.h
@@ -26,8 +26,6 @@ namespace bluetooth {
// Utility typedefs
typedef boost::uuids::uuid uuid_t;
-template<class t>
-using o = boost::optional<t>;
using namespace log4cplus;
// Logging
@@ -43,18 +41,45 @@ protected:
// Shared classes
+namespace detail {
+
+template<typename T, typename U>
+struct constify2;
+
+template<typename T, typename U>
+struct constify2<T *, U *> {
+ typedef T *type;
+};
+
+template<typename T, typename U>
+struct constify2<T *, U const *> {
+ typedef T const *type;
+};
+
+}
+
+template<typename A, typename B>
+class CollectionImpl : public Collection<A> {
+public:
+ CollectionImpl(B &b) : b(b) {
+ }
+
+private:
+ B &b;
+};
+
class DefaultBluetoothGattCharacteristic : protected LogSetup, public BluetoothGattCharacteristic {
public:
- DefaultBluetoothGattCharacteristic(BluetoothGattService &service, uint16_t handle, uuid_t uuid, uint8_t properties,
- uint16_t valueHandle)
- : LogSetup("BluetoothGattCharacteristic"), service(service), handle(handle), uuid(uuid),
- properties(properties), valueHandle(valueHandle) {
+ DefaultBluetoothGattCharacteristic(const BluetoothGattServicePtr &service, uint16_t handle, uuid_t uuid,
+ uint8_t properties, uint16_t valueHandle)
+ : LogSetup("BluetoothGattCharacteristic"), service(service), handle(handle), uuid(uuid),
+ properties(properties), valueHandle(valueHandle) {
}
virtual ~DefaultBluetoothGattCharacteristic() {
}
- BluetoothGattService &getService() const {
+ BluetoothGattServicePtr getService() const {
return service;
}
@@ -75,22 +100,29 @@ public:
}
protected:
- BluetoothGattService &service;
+ BluetoothGattServicePtr service;
uint16_t handle;
uuid_t uuid;
uint8_t properties;
uint16_t valueHandle;
};
+template<typename DeviceType, typename CharacteristicType>
class DefaultBluetoothGattService : public BluetoothGattService {
public:
- DefaultBluetoothGattService(BluetoothDevice &device, const uuid_t uuid, const uint16_t handle,
+ DefaultBluetoothGattService(DeviceType &device, const uuid_t uuid, const uint16_t handle,
const uint16_t endGroupHandle)
- : device(device), uuid(uuid), handle(handle), endGroupHandle(endGroupHandle) {
+ : device(device), uuid(uuid), handle(handle), endGroupHandle(endGroupHandle) {
+ }
+
+ DefaultBluetoothGattService(const DefaultBluetoothGattService &o) = delete;
+
+ DefaultBluetoothGattService(DefaultBluetoothGattService &&o) noexcept
+ : device(std::move(o.device)), uuid(std::move(o.uuid)), handle(std::move(o.handle)),
+ endGroupHandle(std::move(o.endGroupHandle)), characteristics(std::move(o.characteristics)) {
}
virtual ~DefaultBluetoothGattService() {
- removeCharacteristics();
}
virtual BluetoothDevice &getDevice() const {
@@ -109,62 +141,63 @@ public:
return endGroupHandle;
}
- virtual const vector<BluetoothGattCharacteristic *> getCharacteristics() const {
- return characteristics;
+ virtual vector<shared_ptr<BluetoothGattCharacteristic>> getCharacteristics() const {
+ vector<shared_ptr<BluetoothGattCharacteristic>> cs(characteristics.size());
+ std::copy(begin(characteristics), end(characteristics), begin(cs));
+ return cs;
}
- virtual void addCharacteristic(BluetoothGattCharacteristic *characteristic) {
- characteristics.push_back(characteristic);
+ virtual void addCharacteristic(shared_ptr<CharacteristicType> &&characteristic) {
+ characteristics.emplace_back(characteristic);
}
- virtual const o<const BluetoothGattCharacteristic &> findCharacteristic(uuid_t uuid) const {
- for (auto c: characteristics) {
+ virtual o<shared_ptr<BluetoothGattCharacteristic>> findCharacteristic(uuid_t uuid) {
+ for (auto &c: characteristics) {
if (memcmp(c->getUuid().data, uuid.data, 16) == 0) {
- return o<const BluetoothGattCharacteristic &>(*c);
+ return o<shared_ptr<BluetoothGattCharacteristic>>(c);
}
}
- return o<const BluetoothGattCharacteristic &>();
+ return o<shared_ptr<BluetoothGattCharacteristic>>();
}
protected:
- BluetoothDevice &device;
+ DeviceType &device;
const uuid_t uuid;
const uint16_t handle;
const uint16_t endGroupHandle;
- vector<BluetoothGattCharacteristic *> characteristics;
-
- void removeCharacteristics() {
- for (auto &c: characteristics) {
- delete c;
- }
- characteristics.clear();
- }
+ vector<shared_ptr<BluetoothGattCharacteristic>> characteristics;
};
-template<class _D>
+template<class _D, class _S>
class DefaultBluetoothGatt : protected LogSetup, public BluetoothGatt {
public:
virtual _D &getDevice() const {
return device;
}
- virtual const vector<BluetoothGattService *> getServices() const {
- return services;
- };
+// virtual Collection <BluetoothGattService> getServices() const {
+// return CollectionImpl<BluetoothGattService, vector<_S>>(services);
+// }
- virtual const o<BluetoothGattService &> findService(uuid_t uuid) const {
- for (auto s: services) {
+ virtual vector<shared_ptr<BluetoothGattService>> getServices() const {
+ vector<shared_ptr<BluetoothGattService>> ss(services.size());
+ std::copy(begin(services), end(services), begin(ss));
+ return ss;
+ }
+
+ virtual o <BluetoothGattServicePtr> findService(uuid_t uuid) {
+ for (auto &s: services) {
if (memcmp(s->getUuid().data, uuid.data, 16) == 0) {
- return o<BluetoothGattService &>(*s);
+ return o<shared_ptr<BluetoothGattService>>(s);
}
}
- return o<BluetoothGattService &>();
+ return o<shared_ptr<BluetoothGattService>>();
}
- virtual void addService(BluetoothGattService *service) {
- services.push_back(service);
+ void addService(shared_ptr<_S> service) {
+ services.emplace_back(service);
}
protected:
@@ -172,18 +205,18 @@ protected:
}
virtual ~DefaultBluetoothGatt() {
- removeServices();
+// removeServices();
}
void removeServices() {
- for (auto s: services) {
- delete s;
- }
+// for (auto s: services) {
+// delete s;
+// }
services.clear();
}
_D &device;
- vector<BluetoothGattService *> services;
+ vector<shared_ptr<_S>> services;
};
template<class A>
@@ -199,8 +232,12 @@ public:
}
protected:
- DefaultBluetoothDevice(A &adapter, Mac &mac) : LogSetup("BluetoothDevice"),
- adapter(adapter), mac(mac) {
+ DefaultBluetoothDevice(A &adapter, Mac &mac) :
+ LogSetup("BluetoothDevice"), adapter(adapter), mac(mac) {
+ }
+
+ DefaultBluetoothDevice(DefaultBluetoothDevice &&o) noexcept :
+ LogSetup("BluetoothDevice"), adapter(std::move(o.adapter)), mac(std::move(o.mac)) {
}
virtual ~DefaultBluetoothDevice() {
@@ -223,7 +260,7 @@ class DefaultBluetoothAdapter : protected LogSetup, public BluetoothAdapter {
public:
protected:
DefaultBluetoothAdapter(Mac &mac) :
- LogSetup("BluetoothAdapter"), mac(mac) {
+ LogSetup("BluetoothAdapter"), mac(mac) {
}
Mac const &getMac() override {
@@ -233,7 +270,7 @@ protected:
Mac &mac;
};
-shared_ptr<BluetoothAdapter> getAdapterImpl(string name);
+shared_ptr <BluetoothAdapter> getAdapterImpl(string name);
}
};
diff --git a/ble/LinuxBluetooth.cpp b/ble/LinuxBluetooth.cpp
index 587016c..d4073d1 100644
--- a/ble/LinuxBluetooth.cpp
+++ b/ble/LinuxBluetooth.cpp
@@ -28,6 +28,15 @@ class LinuxBluetoothAdapter;
class LinuxBluetoothManager;
+class LinuxBluetoothGattService : public DefaultBluetoothGattService<LinuxBluetoothDevice, DefaultBluetoothGattCharacteristic> {
+public:
+ LinuxBluetoothGattService(LinuxBluetoothDevice &device, const uuid_t uuid, const uint16_t handle,
+ const uint16_t endGroupHandle) : DefaultBluetoothGattService(device, uuid, handle, endGroupHandle) {
+ };
+
+ LinuxBluetoothGattService(const LinuxBluetoothGattService &o) = delete;
+};
+
class LinuxBluetoothAdapter final : public DefaultBluetoothAdapter {
public:
LinuxBluetoothAdapter(int hciDeviceId, Mac &mac);
@@ -72,7 +81,7 @@ private:
LinuxBluetoothGatt *gatt;
};
-class LinuxBluetoothGatt final : public DefaultBluetoothGatt<LinuxBluetoothDevice> {
+class LinuxBluetoothGatt final : public DefaultBluetoothGatt<LinuxBluetoothDevice, LinuxBluetoothGattService> {
public:
LinuxBluetoothGatt(LinuxBluetoothDevice &device);
@@ -86,9 +95,9 @@ public:
void discoverServices() override;
- void writeValue(const BluetoothGattCharacteristic &c, const ByteBuffer &bytes) override;
+ void writeValue(const BluetoothGattCharacteristicPtr &c, const ByteBuffer &bytes) override;
- ByteBuffer readValue(const BluetoothGattCharacteristic &c) override;
+ ByteBuffer readValue(const BluetoothGattCharacteristicPtr &c) override;
private:
void connect();
@@ -252,24 +261,24 @@ uuid_t readUuid(BluetoothDevice *device, const ByteBuffer &bytes) {
return u;
}
-void LinuxBluetoothGatt::writeValue(const BluetoothGattCharacteristic &c, const ByteBuffer &bytes) {
- LOG_DEBUG("Writing to characteristic " << c.getUuid() << ": " << bytes.toString());
+void LinuxBluetoothGatt::writeValue(const BluetoothGattCharacteristicPtr &c, const ByteBuffer &bytes) {
+ LOG_DEBUG("Writing to characteristic " << c->getUuid() << ": " << bytes.toString());
shared_ptr<uint8_t> buffer(new uint8_t[MAX_MTU]);
ByteBuffer out = ByteBuffer(buffer, MAX_MTU);
- AttPdu::makeWrite(out, c.getValueHandle(), bytes);
+ AttPdu::makeWrite(out, c->getValueHandle(), bytes);
ByteBuffer in = writeAndRead(out, buffer, MAX_MTU);
AttPdu::parseWrite(in);
}
-ByteBuffer LinuxBluetoothGatt::readValue(const BluetoothGattCharacteristic &c) {
+ByteBuffer LinuxBluetoothGatt::readValue(const BluetoothGattCharacteristicPtr &c) {
shared_ptr<uint8_t> buffer(new uint8_t[MAX_MTU]);
ByteBuffer out = ByteBuffer(buffer, MAX_MTU);
- AttPdu::makeRead(out, c.getValueHandle());
+ AttPdu::makeRead(out, c->getValueHandle());
ByteBuffer in = writeAndRead(out, buffer, MAX_MTU);
@@ -279,7 +288,7 @@ ByteBuffer LinuxBluetoothGatt::readValue(const BluetoothGattCharacteristic &c) {
auto response = in.view();
- LOG_DEBUG("Value of characteristic " << c.getUuid() << "=" << response.toString());
+ LOG_DEBUG("Value of characteristic " << c->getUuid() << "=" << response.toString());
return response;
}
@@ -308,7 +317,7 @@ void LinuxBluetoothGatt::discoverServices() {
uuid_t u = readUuid(&device, data.value);
- addService(new DefaultBluetoothGattService(device, u, data.handle, endGroupHandle));
+ addService(make_shared<LinuxBluetoothGattService>(device, u, data.handle, endGroupHandle));
}
// auto last = values.back();
@@ -358,7 +367,7 @@ void LinuxBluetoothGatt::discoverServices() {
// ", valueHandle: 0x" << setw(4) << setfill('0') << hex << (int) valueHandle <<
// ", uuid: " << uuid;
- s->addCharacteristic(new DefaultBluetoothGattCharacteristic(*s, c.handle, uuid, properties, valueHandle));
+ s->addCharacteristic(std::move(make_shared<DefaultBluetoothGattCharacteristic>(s, c.handle, uuid, properties, valueHandle)));
}
startHandle = lastHandle + (uint8_t) 2;
diff --git a/include/ble/Bluetooth.h b/include/ble/Bluetooth.h
index 8da602f..f2b5b13 100644
--- a/include/ble/Bluetooth.h
+++ b/include/ble/Bluetooth.h
@@ -2,7 +2,7 @@
#define BLUETOOTH_H
#include <boost/uuid/uuid.hpp>
-#include <boost/optional.hpp>
+#include <experimental/optional>
#include <iosfwd>
#include <stdexcept>
#include <vector>
@@ -15,6 +15,8 @@ namespace trygvis {
namespace bluetooth {
using namespace std;
+template<typename T>
+using o = std::experimental::optional<T>;
struct SpecUuid {
public:
@@ -38,18 +40,21 @@ class BluetoothGattService;
class BluetoothGattCharacteristic;
+typedef shared_ptr<BluetoothGattCharacteristic> BluetoothGattCharacteristicPtr;
+typedef shared_ptr<BluetoothGattService> BluetoothGattServicePtr;
+
class BluetoothException : public runtime_error {
public:
BluetoothException(const BluetoothAdapter *adapter, string const &what) :
- runtime_error(what), adapter(adapter), device(nullptr) {
+ runtime_error(what), adapter(adapter), device(nullptr) {
}
BluetoothException(const BluetoothDevice *device, string const &what) :
- runtime_error(what), adapter(nullptr), device(device) {
+ runtime_error(what), adapter(nullptr), device(device) {
}
BluetoothException(string const &what) :
- runtime_error(what), adapter(nullptr), device(nullptr) {
+ runtime_error(what), adapter(nullptr), device(nullptr) {
}
const BluetoothAdapter *adapter;
@@ -83,12 +88,26 @@ private:
uint8_t bytes[6];
};
+template<typename T>
+class Iterator {
+public:
+private:
+};
+
+template<typename T>
+class Collection {
+public:
+ Iterator<T> begin();
+
+ Iterator<T> end();
+};
+
class BluetoothGattCharacteristic {
public:
virtual ~BluetoothGattCharacteristic() {
};
- virtual BluetoothGattService &getService() const = 0;
+ virtual BluetoothGattServicePtr getService() const = 0;
virtual uint16_t getHandle() const = 0;
@@ -112,11 +131,9 @@ public:
virtual uint16_t getEndGroupHandle() const = 0;
- virtual const vector<BluetoothGattCharacteristic *> getCharacteristics() const = 0;
-
- virtual void addCharacteristic(BluetoothGattCharacteristic *characteristic) = 0;
+ virtual vector<shared_ptr<BluetoothGattCharacteristic>> getCharacteristics() const = 0;
- virtual const boost::optional<const BluetoothGattCharacteristic &> findCharacteristic(boost::uuids::uuid uuid) const = 0;
+ virtual o<BluetoothGattCharacteristicPtr> findCharacteristic(boost::uuids::uuid uuid) = 0;
};
class BluetoothGatt {
@@ -126,23 +143,23 @@ public:
virtual ~BluetoothGatt();
// No copying
- BluetoothGatt(const BluetoothGatt&) = delete;
+ BluetoothGatt(const BluetoothGatt &) = delete;
- BluetoothGatt& operator=(const BluetoothGatt&) = delete;
+ BluetoothGatt &operator=(const BluetoothGatt &) = delete;
virtual BluetoothDevice &getDevice() const = 0;
virtual bool isConnected() const = 0;
- virtual void writeValue(const BluetoothGattCharacteristic &c, const ByteBuffer &bytes) = 0;
+ virtual void writeValue(const BluetoothGattCharacteristicPtr &c, const ByteBuffer &bytes) = 0;
- virtual ByteBuffer readValue(const BluetoothGattCharacteristic &c) = 0;
+ virtual ByteBuffer readValue(const BluetoothGattCharacteristicPtr &c) = 0;
virtual void discoverServices() = 0;
- virtual const vector<BluetoothGattService *> getServices() const = 0;
+ virtual vector<shared_ptr<BluetoothGattService>> getServices() const = 0;
- virtual const boost::optional<BluetoothGattService &> findService(boost::uuids::uuid uuid) const = 0;
+ virtual o<BluetoothGattServicePtr> findService(boost::uuids::uuid uuid) = 0;
};
class BluetoothDevice {
@@ -168,7 +185,7 @@ public:
virtual void runScan(std::function<void(const shared_ptr<BluetoothDevice> &device)>) = 0;
- virtual shared_ptr <BluetoothDevice> getDevice(Mac &mac) = 0;
+ virtual shared_ptr<BluetoothDevice> getDevice(Mac &mac) = 0;
protected:
BluetoothAdapter();
diff --git a/json b/json
-Subproject 2c720b26abcd8ef757291f2baf1311a4aab5812
+Subproject c012b29ae5397af1608842ba915ad6b4133a030
diff --git a/sensor/include/trygvis/sensor.h b/sensor/include/trygvis/sensor.h
index c109a2a..09372b9 100644
--- a/sensor/include/trygvis/sensor.h
+++ b/sensor/include/trygvis/sensor.h
@@ -5,15 +5,16 @@
#include <iostream>
#include <memory>
#include <vector>
-#include <boost/optional/optional.hpp>
+#include <algorithm>
+#include <experimental/optional>
namespace trygvis {
namespace sensor {
-using namespace std;
+//using namespace std;
-template<typename A>
-using o = boost::optional<A>;
+template<typename T>
+using o = std::experimental::optional<T>;
enum class sample_format_type {
AUTO,
@@ -24,7 +25,7 @@ enum class sample_format_type {
RRD,
};
-string to_string(const sample_format_type &arg);
+std::string to_string(const sample_format_type &arg);
std::ostream& operator<<(std::ostream& os, sample_format_type const& type);
@@ -39,9 +40,9 @@ std::ostream& operator<<(std::ostream& os, time_resolution const& type);
std::istream& operator>>(std::istream& is, time_resolution & type);
-class sample_exception : public runtime_error {
+class sample_exception : public std::runtime_error {
public:
- sample_exception(const string &what) : runtime_error(what) {
+ sample_exception(const std::string &what) : runtime_error(what) {
}
};
@@ -51,13 +52,13 @@ class SampleKey;
class KeyDictionary;
-using SampleKeyVector = vector<SampleKey *>;
+using SampleKeyVector = std::vector<SampleKey *>;
using SampleKeyIndex = SampleKeyVector::size_type;
struct SampleKey {
private:
SampleKey(const SampleKey& that) = delete;
- SampleKey(SampleKeyIndex index, const string &name) : index(index), name(name) {
+ SampleKey(SampleKeyIndex index, const std::string &name) : index(index), name(name) {
if (name.length() == 0) {
throw sample_exception("Bad sample key.");
}
@@ -72,7 +73,7 @@ public:
}
const SampleKeyIndex index;
- const string name;
+ const std::string name;
};
class KeyDictionary {
@@ -88,7 +89,7 @@ public:
KeyDictionary& operator=(const KeyDictionary&) = delete;
- SampleKey *indexOf(const string &key) {
+ const SampleKey *indexOf(const std::string &key) {
SampleKeyIndex i = 0;
for (auto ptr = keys.cbegin(); ptr != keys.cend(); ptr++, i++) {
if ((*ptr)->name == key) {
@@ -111,8 +112,8 @@ public:
return keys.at(i);
}
- vector<SampleKey *> findIndexes(SampleKeyVector &keys) {
- vector<SampleKey *> indexes;
+ std::vector<const SampleKey *> findIndexes(SampleKeyVector &keys) {
+ std::vector<const SampleKey *> indexes;
for (auto &key: keys) {
auto index = indexOf(key->name);
@@ -152,7 +153,7 @@ private:
class SampleRecord {
public:
- typedef vector<o<string>> vec;
+ typedef std::vector<o<std::string>> vec;
SampleRecord(KeyDictionary &dict) : dict(dict) {
}
@@ -179,19 +180,19 @@ public:
return values.empty();
}
- const o<string> at(const SampleKey *key) const {
+ const o<std::string> at(const SampleKey *key) const {
SampleKeyIndex index = key->index;
if (index >= values.size()) {
- return o<string>();
+ return o<std::string>();
}
return values.at(index);
}
SampleRecord& set(const SampleKey *key, const std::string &value) {
- values.resize(max(values.size(), key->index + 1));
+ values.resize(std::max(values.size(), key->index + 1));
- values.at(key->index).reset(value);
+ values.at(key->index) = value;
return *this;
}
@@ -199,9 +200,9 @@ public:
template<class A>
const o<A> lexical_at(const SampleKey *key) const;
- string to_string() const {
+ std::string to_string() const {
SampleKeyIndex i = 0;
- string s;
+ std::string s;
for (auto ptr = values.begin(); ptr != values.end(); ptr++, i++) {
auto o = *ptr;
@@ -209,7 +210,7 @@ public:
continue;
}
- auto value = o.get();
+ auto value = *o;
s += dict.at(i)->name + " = " + value + ", ";
}
diff --git a/sensor/include/trygvis/sensor/io.h b/sensor/include/trygvis/sensor/io.h
index 71b0b84..304091b 100644
--- a/sensor/include/trygvis/sensor/io.h
+++ b/sensor/include/trygvis/sensor/io.h
@@ -187,7 +187,7 @@ public:
void write(SampleRecord const &sample) override;
private:
- vector<SampleKey *> keys;
+ vector<const SampleKey *> keys;
shared_ptr<ostream> stream;
const SampleKey *timestamp_key;
};
diff --git a/sensor/main/io.cpp b/sensor/main/io.cpp
index 96a98f6..9e822c3 100644
--- a/sensor/main/io.cpp
+++ b/sensor/main/io.cpp
@@ -45,17 +45,17 @@ unique_ptr<SampleOutputStream> open_sample_output_stream(
auto tsf = options.find_option<timestamp_field_option>();
- auto timestamp_key = dict.indexOf(tsf ? tsf.get()->name : "timestamp");
+ auto timestamp_key = dict.indexOf(tsf ? tsf.value()->name : "timestamp");
return make_unique<RrdSampleOutputStream>(output, dict, timestamp_key, of);
} else if (type == sample_format_type::SQL) {
auto tno = options.find_option<table_name_option>();
- if (!tno.is_initialized()) {
+ if (!tno) {
throw missing_required_option_error("table name");
}
- return make_unique<SqlSampleOutputStream>(move(output), dict, tno.get()->name);
+ return make_unique<SqlSampleOutputStream>(move(output), dict, tno.value()->name);
} else {
throw sample_exception("No writer for format type: " + to_string(type));
}
@@ -144,7 +144,7 @@ void CsvSampleOutputStream::write(SampleRecord const &sample) {
auto o = sample.at(sampleKey);
if (o) {
- s << o.get();
+ s << o.value();
}
}
@@ -152,7 +152,7 @@ void CsvSampleOutputStream::write(SampleRecord const &sample) {
}
void CsvSampleOutputStream::writeHeader() {
- auto &s = *stream.get();
+ auto &s = *stream;
auto i = dict.begin();
while (i != dict.end()) {
@@ -187,7 +187,7 @@ void JsonSampleOutputStream::write(SampleRecord const &sample) {
auto value = sample.at(sampleKey);
if (value) {
- doc[key->name] = value.get();
+ doc[key->name] = value.value();
}
}
} else {
@@ -197,7 +197,7 @@ void JsonSampleOutputStream::write(SampleRecord const &sample) {
if (o) {
// Make sure that the key is registered in the dictionary
dict.indexOf(sampleKey->name);
- doc[sampleKey->name] = o.get();
+ doc[sampleKey->name] = o.value();
}
}
}
@@ -230,7 +230,7 @@ void KeyValueSampleOutputStream::write(SampleRecord const &sample) {
} else {
*s << ", ";
}
- *s << key->name << "=" << value.get();
+ *s << key->name << "=" << value.value();
}
}
} else {
@@ -245,7 +245,7 @@ void KeyValueSampleOutputStream::write(SampleRecord const &sample) {
}
// Make sure that the key is registered in the dictionary
dict.indexOf(sampleKey->name);
- *s << sampleKey->name << "=" << o.get();
+ *s << sampleKey->name << "=" << o.value();
}
}
}
@@ -260,7 +260,7 @@ RrdSampleOutputStream::RrdSampleOutputStream(shared_ptr<ostream> stream,
stream(move(stream)), timestamp_key(timestamp_key) {
if (output_fields) {
- for (auto field : output_fields.get()->fields) {
+ for (auto field : output_fields.value()->fields) {
keys.emplace_back(dict.indexOf(field));
}
} else {
@@ -284,7 +284,7 @@ void RrdSampleOutputStream::write(SampleRecord const &sample) {
return;
}
- auto timestamp = timestampO.get();
+ auto timestamp = timestampO.value();
s << timestamp;
@@ -303,7 +303,7 @@ void RrdSampleOutputStream::write(SampleRecord const &sample) {
s << ":";
}
- s << (value ? value.get() : "U");
+ s << (value ? value.value() : "U");
}
s << endl << flush;
@@ -319,7 +319,7 @@ void SqlSampleOutputStream::write(SampleRecord const &sample) {
fs.reserve(1024);
vs.reserve(1024);
- auto &s = *stream.get();
+ auto &s = *stream;
bool first = true;
if (!dict.empty()) {
@@ -336,7 +336,7 @@ void SqlSampleOutputStream::write(SampleRecord const &sample) {
vs += ", ";
}
fs += "\"" + key->name + "\"";
- vs += "'" + value.get() + "'";
+ vs += "'" + value.value() + "'";
}
}
} else {
@@ -354,7 +354,7 @@ void SqlSampleOutputStream::write(SampleRecord const &sample) {
dict.indexOf(sample_key->name);
fs += "\"" + sample_key->name + "\"";
- vs += "'" + o.get() + "'";
+ vs += "'" + o.value() + "'";
}
}
}
diff --git a/sensor/main/sensor.cpp b/sensor/main/sensor.cpp
index 1c0c666..0988e0d 100644
--- a/sensor/main/sensor.cpp
+++ b/sensor/main/sensor.cpp
@@ -80,7 +80,7 @@ const o<long> SampleRecord::lexical_at(const SampleKey *key) const {
return o<long>();
}
- return o<long>(boost::lexical_cast<long>(value.get()));
+ return o<long>(boost::lexical_cast<long>(*value));
}
//
//template<class A>
diff --git a/sensor/test/SampleTest.cpp b/sensor/test/SampleTest.cpp
index 8479e75..0fffc04 100644
--- a/sensor/test/SampleTest.cpp
+++ b/sensor/test/SampleTest.cpp
@@ -49,13 +49,13 @@ BOOST_AUTO_TEST_CASE(key_value_parser2) {
SampleRecord& sample = buffer->samples[0];
auto it = dict.begin();
BOOST_CHECK_EQUAL((*it)->name, "now");
- BOOST_CHECK_EQUAL(!sample.at(*it).operator!(), true);
- BOOST_CHECK_EQUAL(sample.at(*it).get(), "1");
+ BOOST_CHECK_EQUAL(!!sample.at(*it), true);
+ BOOST_CHECK_EQUAL(sample.at(*it).value(), "1");
BOOST_CHECK_EQUAL((*it++)->index, 0);
BOOST_CHECK_EQUAL((*it)->name, "sensor 1");
- BOOST_CHECK_EQUAL(!sample.at(*it).operator!(), true);
- BOOST_CHECK_EQUAL(sample.at(*it).get(), "0.000999999833333");
+ BOOST_CHECK_EQUAL(!!sample.at(*it), true);
+ BOOST_CHECK_EQUAL(sample.at(*it).value(), "0.000999999833333");
BOOST_CHECK_EQUAL((*it++)->index, 1);
}
@@ -112,12 +112,12 @@ BOOST_AUTO_TEST_CASE(key_value_parser_without_newline) {
SampleRecord& sample = buffer->samples[0];
auto it = dict.begin();
BOOST_CHECK_EQUAL((*it)->name, "now");
- BOOST_CHECK_EQUAL(!sample.at(*it).operator!(), true);
- BOOST_CHECK_EQUAL(sample.at(*it).get(), "1");
+ BOOST_CHECK_EQUAL(!!sample.at(*it), true);
+ BOOST_CHECK_EQUAL(sample.at(*it).value(), "1");
BOOST_CHECK_EQUAL((*it++)->index, 0);
BOOST_CHECK_EQUAL((*it)->name, "sensor");
- BOOST_CHECK_EQUAL(!sample.at(*it).operator!(), true);
- BOOST_CHECK_EQUAL(sample.at(*it).get(), "123");
+ BOOST_CHECK_EQUAL(!!sample.at(*it), true);
+ BOOST_CHECK_EQUAL(sample.at(*it).value(), "123");
BOOST_CHECK_EQUAL((*it++)->index, 1);
}
diff --git a/test/ByteBufferTest.cpp b/test/ByteBufferTest.cpp
index 6a1c4cb..4a612d2 100644
--- a/test/ByteBufferTest.cpp
+++ b/test/ByteBufferTest.cpp
@@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE(empty_buffer) {
try {
buffer.read8();
BOOST_FAIL("Expected exception");
- } catch (ByteBufferException e) {
+ } catch (ByteBufferException &e) {
}
}