diff options
author | Petre Eftime <[email protected]> | 2016-05-25 12:43:12 +0300 |
---|---|---|
committer | Petre Eftime <[email protected]> | 2016-06-30 12:54:55 +0300 |
commit | 04f2c650964f5a9fa55dc9a6b87cdd69f0a2b2a9 (patch) | |
tree | 5ebf389cbad78cb7fba8d2c5fa6a7fa396c3a98a /src | |
parent | 34bd85eec952b8031dedd58882a9bcfeef57d848 (diff) |
Add support for notifications
GATT Characteristics support push notifications as per BLE spec
Other objects support most relevant "virtual" notifications (DBus properties changed)
Signed-off-by: Petre Eftime <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/BluetoothAdapter.cpp | 108 | ||||
-rw-r--r-- | src/BluetoothDevice.cpp | 126 | ||||
-rw-r--r-- | src/BluetoothEvent.cpp | 9 | ||||
-rw-r--r-- | src/BluetoothGattCharacteristic.cpp | 55 | ||||
-rw-r--r-- | src/BluetoothGattDescriptor.cpp | 49 | ||||
-rw-r--r-- | src/BluetoothManager.cpp | 2 | ||||
-rw-r--r-- | src/tinyb_utils.cpp | 21 |
7 files changed, 361 insertions, 9 deletions
diff --git a/src/BluetoothAdapter.cpp b/src/BluetoothAdapter.cpp index 49f69cb6..74f2c38d 100644 --- a/src/BluetoothAdapter.cpp +++ b/src/BluetoothAdapter.cpp @@ -24,6 +24,7 @@ #include "generated-code.h" #include "tinyb_utils.hpp" +#include "BluetoothNotificationHandler.hpp" #include "BluetoothAdapter.hpp" #include "BluetoothDevice.hpp" #include "BluetoothManager.hpp" @@ -31,6 +32,55 @@ using namespace tinyb; +void BluetoothNotificationHandler::on_properties_changed_adapter(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata) { + + auto c = static_cast<BluetoothAdapter*>(userdata); + + if (!c->lock()) + return; + + if(g_variant_n_children(changed_properties) > 0) { + GVariantIter *iter = NULL; + + GVariant *value; + const gchar *key; + g_variant_get(changed_properties, "a{sv}", &iter); + while (iter != nullptr && g_variant_iter_loop(iter, "{&sv}", &key, &value)) { + auto powered_callback = c->powered_callback; + if (powered_callback != nullptr && g_ascii_strncasecmp(key, "powered", 8) == 0) { + bool new_value; + g_variant_get(value, "b", &new_value); + powered_callback(new_value); + continue; + } + auto discoverable_callback = c->discoverable_callback; + if (discoverable_callback != nullptr && g_ascii_strncasecmp(key, "discoverable", 13) == 0) { + bool new_value; + g_variant_get(value, "b", &new_value); + discoverable_callback(new_value); + continue; + } + auto pairable_callback = c->pairable_callback; + if (pairable_callback != nullptr && g_ascii_strncasecmp(key, "pairable", 9) == 0) { + bool new_value; + g_variant_get(value, "b", &new_value); + pairable_callback(new_value); + continue; + } + auto discovering_callback = c->discovering_callback; + if (discovering_callback != nullptr && g_ascii_strncasecmp(key, "discovering", 12) == 0) { + bool new_value; + g_variant_get(value, "b", &new_value); + discovering_callback(new_value); + continue; + } + } + g_variant_iter_free (iter); + } + + c->unlock(); +} + std::string BluetoothAdapter::get_class_name() const { return std::string("BluetoothAdapter"); @@ -55,6 +105,10 @@ BluetoothAdapter::BluetoothAdapter(Adapter1 *object) { this->object = object; g_object_ref(object); + + g_signal_connect(G_DBUS_PROXY(object), "g-properties-changed", + G_CALLBACK(BluetoothNotificationHandler::on_properties_changed_adapter), this); + valid = true; } BluetoothAdapter::BluetoothAdapter(const BluetoothAdapter &object) @@ -69,6 +123,10 @@ BluetoothAdapter *BluetoothAdapter::clone() const BluetoothAdapter::~BluetoothAdapter() { + valid = false; + g_signal_handlers_disconnect_by_data(object, this); + lk.lock(); + g_object_unref(object); } @@ -151,8 +209,6 @@ bool BluetoothAdapter::remove_device ( return result; } - - /* D-Bus property accessors: */ std::string BluetoothAdapter::get_address () { @@ -184,6 +240,18 @@ bool BluetoothAdapter::get_powered () return adapter1_get_powered (object); } +void BluetoothAdapter::enable_powered_notifications( + std::function<void(BluetoothAdapter &adapter, bool powered, void *userdata)> callback, + void *userdata) { + powered_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothAdapter::enable_powered_notifications(std::function<void(bool powered)> callback) { + powered_callback = callback; +} +void BluetoothAdapter::disable_powered_notifications() { + powered_callback = nullptr; +} + void BluetoothAdapter::set_powered (bool value) { if (get_powered() != value) @@ -200,6 +268,18 @@ void BluetoothAdapter::set_discoverable (bool value) adapter1_set_discoverable (object, value); } +void BluetoothAdapter::enable_discoverable_notifications( + std::function<void(BluetoothAdapter &adapter, bool discoverable, void *userdata)> callback, + void *userdata) { + discoverable_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothAdapter::enable_discoverable_notifications(std::function<void(bool discoverable)> callback) { + discoverable_callback = callback; +} +void BluetoothAdapter::disable_discoverable_notifications() { + discoverable_callback = nullptr; +} + unsigned int BluetoothAdapter::get_discoverable_timeout () { return adapter1_get_discoverable_timeout (object); @@ -215,6 +295,18 @@ bool BluetoothAdapter::get_pairable () return adapter1_get_pairable (object); } +void BluetoothAdapter::enable_pairable_notifications( + std::function<void(BluetoothAdapter &adapter, bool pairable, void *userdata)> callback, + void *userdata) { + pairable_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothAdapter::enable_pairable_notifications(std::function<void(bool pairable)> callback) { + pairable_callback = callback; +} +void BluetoothAdapter::disable_pairable_notifications() { + pairable_callback = nullptr; +} + void BluetoothAdapter::set_pairable (bool value) { adapter1_set_pairable (object, value); @@ -235,6 +327,18 @@ bool BluetoothAdapter::get_discovering () return adapter1_get_discovering (object); } +void BluetoothAdapter::enable_discovering_notifications( + std::function<void(BluetoothAdapter &adapter, bool discovering, void *userdata)> callback, + void *userdata) { + discovering_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothAdapter::enable_discovering_notifications(std::function<void(bool discovering)> callback) { + discovering_callback = callback; +} +void BluetoothAdapter::disable_discovering_notifications() { + discovering_callback = nullptr; +} + std::vector<std::string> BluetoothAdapter::get_uuids () { const char * const *uuids_c = adapter1_get_uuids (object); diff --git a/src/BluetoothDevice.cpp b/src/BluetoothDevice.cpp index 1b76a849..943efc67 100644 --- a/src/BluetoothDevice.cpp +++ b/src/BluetoothDevice.cpp @@ -24,6 +24,7 @@ #include "generated-code.h" #include "tinyb_utils.hpp" +#include "BluetoothNotificationHandler.hpp" #include "BluetoothDevice.hpp" #include "BluetoothGattService.hpp" #include "BluetoothManager.hpp" @@ -31,6 +32,62 @@ using namespace tinyb; +void BluetoothNotificationHandler::on_properties_changed_device(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata) { + + auto c = static_cast<BluetoothDevice*>(userdata); + + if (!c->lock()) + return; + + if(g_variant_n_children(changed_properties) > 0) { + GVariantIter *iter = NULL; + + GVariant *value; + const gchar *key; + g_variant_get(changed_properties, "a{sv}", &iter); + while (iter != nullptr && g_variant_iter_loop(iter, "{&sv}", &key, &value)) { + auto rssi_callback = c->rssi_callback; + if (rssi_callback != nullptr && g_ascii_strncasecmp(key, "rssi", 5) == 0) { + int16_t new_value; + g_variant_get(value, "n", &new_value); + rssi_callback(new_value); + continue; + } + auto blocked_callback = c->blocked_callback; + if (blocked_callback != nullptr && g_ascii_strncasecmp(key, "blocked", 8) == 0) { + bool new_value; + g_variant_get(value, "b", &new_value); + blocked_callback(new_value); + continue; + } + auto trusted_callback = c->trusted_callback; + if (trusted_callback != nullptr && g_ascii_strncasecmp(key, "trusted", 8) == 0) { + bool new_value; + g_variant_get(value, "b", &new_value); + trusted_callback(new_value); + continue; + } + auto paired_callback = c->paired_callback; + if (paired_callback != nullptr && g_ascii_strncasecmp(key, "paired", 7) == 0) { + bool new_value; + g_variant_get(value, "b", &new_value); + paired_callback(new_value); + continue; + } + auto connected_callback = c->connected_callback; + if (connected_callback != nullptr && g_ascii_strncasecmp(key, "connected", 10) == 0) { + bool new_value; + g_variant_get(value, "b", &new_value); + connected_callback(new_value); + continue; + } + } + g_variant_iter_free (iter); + } + + c->unlock(); +} + std::string BluetoothDevice::get_class_name() const { return std::string("BluetoothDevice"); @@ -55,6 +112,10 @@ BluetoothDevice::BluetoothDevice(Device1 *object) { this->object = object; g_object_ref(object); + + g_signal_connect(G_DBUS_PROXY(object), "g-properties-changed", + G_CALLBACK(BluetoothNotificationHandler::on_properties_changed_device), this); + valid = true; } BluetoothDevice::BluetoothDevice(const BluetoothDevice &object) @@ -64,6 +125,10 @@ BluetoothDevice::BluetoothDevice(const BluetoothDevice &object) BluetoothDevice::~BluetoothDevice() { + valid = false; + g_signal_handlers_disconnect_by_data(object, this); + lk.lock(); + g_object_unref(object); } @@ -240,6 +305,15 @@ bool BluetoothDevice::get_paired () return device1_get_paired (object); } +void BluetoothDevice::enable_paired_notifications( + std::function<void(BluetoothDevice &, bool, void *)> callback, + void *userdata) { + paired_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::disable_paired_notifications() { + paired_callback = nullptr; +} + bool BluetoothDevice::get_trusted () { return device1_get_trusted (object); @@ -250,6 +324,19 @@ void BluetoothDevice::set_trusted (bool value) device1_set_trusted (object, value); } +void BluetoothDevice::enable_trusted_notifications( + std::function<void(BluetoothDevice &, bool, void *)> callback, + void *userdata) { + trusted_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_trusted_notifications( + std::function<void(bool)> callback) { + trusted_callback = callback; +} +void BluetoothDevice::disable_trusted_notifications() { + trusted_callback = nullptr; +} + bool BluetoothDevice::get_blocked () { return device1_get_blocked (object); @@ -260,6 +347,19 @@ void BluetoothDevice::set_blocked (bool value) device1_set_blocked (object, value); } +void BluetoothDevice::enable_blocked_notifications( + std::function<void(BluetoothDevice &, bool, void *)> callback, + void *userdata) { + blocked_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_blocked_notifications( + std::function<void(bool)> callback) { + blocked_callback = callback; +} +void BluetoothDevice::disable_blocked_notifications() { + blocked_callback = nullptr; +} + bool BluetoothDevice::get_legacy_pairing () { return device1_get_legacy_pairing (object); @@ -270,11 +370,37 @@ int16_t BluetoothDevice::get_rssi () return device1_get_rssi (object); } +void BluetoothDevice::enable_rssi_notifications( + std::function<void(BluetoothDevice &, int16_t, void *)> callback, + void *userdata) { + rssi_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_rssi_notifications( + std::function<void(int16_t)> callback) { + rssi_callback = callback; +} +void BluetoothDevice::disable_rssi_notifications() { + rssi_callback = nullptr; +} + bool BluetoothDevice::get_connected () { return device1_get_connected (object); } +void BluetoothDevice::enable_connected_notifications( + std::function<void(BluetoothDevice &, bool, void *)> callback, + void *userdata) { + connected_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_connected_notifications( + std::function<void(bool)> callback) { + connected_callback = callback; +} +void BluetoothDevice::disable_connected_notifications() { + connected_callback = nullptr; +} + std::vector<std::string> BluetoothDevice::get_uuids () { diff --git a/src/BluetoothEvent.cpp b/src/BluetoothEvent.cpp index 1b68f629..ee797343 100644 --- a/src/BluetoothEvent.cpp +++ b/src/BluetoothEvent.cpp @@ -36,12 +36,15 @@ BluetoothEvent::BluetoothEvent(BluetoothType type, std::string *name, this->parent = nullptr; this->execute_once = execute_once; - this->cb = cb; - if (cb == generic_callback) + if (cb == nullptr) { this->data = static_cast<void *>(&cv); - else + this->cb = generic_callback; + } + else { + this->cb = cb; this->data = data; + } } bool BluetoothEvent::execute_callback(BluetoothObject &object) diff --git a/src/BluetoothGattCharacteristic.cpp b/src/BluetoothGattCharacteristic.cpp index b8784883..d947ad72 100644 --- a/src/BluetoothGattCharacteristic.cpp +++ b/src/BluetoothGattCharacteristic.cpp @@ -24,6 +24,7 @@ #include "generated-code.h" #include "tinyb_utils.hpp" +#include "BluetoothNotificationHandler.hpp" #include "BluetoothGattCharacteristic.hpp" #include "BluetoothGattService.hpp" #include "BluetoothGattDescriptor.hpp" @@ -31,6 +32,27 @@ using namespace tinyb; +void BluetoothNotificationHandler::on_properties_changed_characteristic(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata) { + + auto c = static_cast<BluetoothGattCharacteristic*>(userdata); + + if(g_variant_n_children(changed_properties) > 0) { + GVariantIter *iter = NULL; + + GVariant *value; + const gchar *key; + g_variant_get(changed_properties, "a{sv}", &iter); + while (iter != nullptr && g_variant_iter_loop(iter, "{&sv}", &key, &value)) { + auto value_callback = c->value_changed_callback; + if (value_callback != nullptr && g_ascii_strncasecmp(key, "value", 5) == 0) { + std::vector<unsigned char> new_value = from_iter_to_vector(value); + value_callback(new_value); + } + } + g_variant_iter_free (iter); + } +} + std::string BluetoothGattCharacteristic::get_class_name() const { return std::string("BluetoothGattCharacteristic"); @@ -55,15 +77,20 @@ BluetoothGattCharacteristic::BluetoothGattCharacteristic(GattCharacteristic1 *ob { this->object = object; g_object_ref(object); + + g_signal_connect(G_DBUS_PROXY(object), "g-properties-changed", + G_CALLBACK(BluetoothNotificationHandler::on_properties_changed_characteristic), this); } BluetoothGattCharacteristic::BluetoothGattCharacteristic(const BluetoothGattCharacteristic &object) { BluetoothGattCharacteristic(object.object); + } BluetoothGattCharacteristic::~BluetoothGattCharacteristic() { + g_signal_handlers_disconnect_by_data(object, this); g_object_unref(object); } @@ -135,6 +162,31 @@ bool BluetoothGattCharacteristic::write_value ( return result; } +bool BluetoothGattCharacteristic::enable_value_notifications( + std::function<void(BluetoothGattCharacteristic &, std::vector<unsigned char> &,void *)> callback, + void *userdata) +{ + value_changed_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); + start_notify(); + return true; +} + +bool BluetoothGattCharacteristic::enable_value_notifications( + std::function<void(std::vector<unsigned char> &)> callback) +{ + value_changed_callback = callback; + start_notify(); + return true; +} + +bool BluetoothGattCharacteristic::disable_value_notifications() +{ + stop_notify(); + value_changed_callback = nullptr; + return true; +} + + bool BluetoothGattCharacteristic::start_notify () { GError *error = NULL; @@ -144,6 +196,7 @@ bool BluetoothGattCharacteristic::start_notify () NULL, &error ); + handle_error(error); return result; } @@ -161,8 +214,6 @@ bool BluetoothGattCharacteristic::stop_notify () return result; } - - /* D-Bus property accessors: */ std::string BluetoothGattCharacteristic::get_uuid () { diff --git a/src/BluetoothGattDescriptor.cpp b/src/BluetoothGattDescriptor.cpp index b0c5fd64..bd210347 100644 --- a/src/BluetoothGattDescriptor.cpp +++ b/src/BluetoothGattDescriptor.cpp @@ -24,12 +24,34 @@ #include "generated-code.h" #include "tinyb_utils.hpp" +#include "BluetoothNotificationHandler.hpp" #include "BluetoothGattDescriptor.hpp" #include "BluetoothGattCharacteristic.hpp" #include "BluetoothException.hpp" using namespace tinyb; +void BluetoothNotificationHandler::on_properties_changed_descriptor(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata) { + + auto c = static_cast<BluetoothGattDescriptor*>(userdata); + + if(g_variant_n_children(changed_properties) > 0) { + GVariantIter *iter = NULL; + + GVariant *value; + const gchar *key; + g_variant_get(changed_properties, "a{sv}", &iter); + while (iter != nullptr && g_variant_iter_loop(iter, "{&sv}", &key, &value)) { + auto value_callback = c->value_changed_callback; + if (value_callback != nullptr && g_ascii_strncasecmp(key, "value", 5) == 0) { + std::vector<unsigned char> new_value = from_iter_to_vector(value); + value_callback(new_value); + } + } + g_variant_iter_free (iter); + } +} + std::string BluetoothGattDescriptor::get_class_name() const { return std::string("BluetoothGattDescriptor"); @@ -54,6 +76,10 @@ BluetoothGattDescriptor::BluetoothGattDescriptor(GattDescriptor1 *object) { this->object = object; g_object_ref(object); + + g_signal_connect(G_DBUS_PROXY(object), "g-properties-changed", + G_CALLBACK(BluetoothNotificationHandler::on_properties_changed_descriptor), this); + valid = true; } BluetoothGattDescriptor::BluetoothGattDescriptor(const BluetoothGattDescriptor &object) @@ -63,6 +89,10 @@ BluetoothGattDescriptor::BluetoothGattDescriptor(const BluetoothGattDescriptor & BluetoothGattDescriptor::~BluetoothGattDescriptor() { + valid = false; + g_signal_handlers_disconnect_by_data(object, this); + lk.lock(); + g_object_unref(object); } @@ -136,7 +166,26 @@ bool BluetoothGattDescriptor::write_value ( return result; } +bool BluetoothGattDescriptor::enable_value_notifications( + std::function<void(BluetoothGattDescriptor &, std::vector<unsigned char> &,void *)> callback, + void *userdata) +{ + value_changed_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); + return true; +} +bool BluetoothGattDescriptor::enable_value_notifications( + std::function<void(std::vector<unsigned char> &)> callback) +{ + value_changed_callback = callback; + return true; +} + +bool BluetoothGattDescriptor::disable_value_notifications() +{ + value_changed_callback = nullptr; + return true; +} /* D-Bus property accessors: */ std::string BluetoothGattDescriptor::get_uuid () diff --git a/src/BluetoothManager.cpp b/src/BluetoothManager.cpp index a7459f4a..9363617e 100644 --- a/src/BluetoothManager.cpp +++ b/src/BluetoothManager.cpp @@ -33,9 +33,7 @@ #include "BluetoothException.hpp" #include "version.h" -#include <pthread.h> #include <cassert> -#include <iostream> using namespace tinyb; diff --git a/src/tinyb_utils.cpp b/src/tinyb_utils.cpp index 449ef1ed..97a17898 100644 --- a/src/tinyb_utils.cpp +++ b/src/tinyb_utils.cpp @@ -52,6 +52,27 @@ GBytes *tinyb::from_vector_to_gbytes(const std::vector<unsigned char>& vector) return result; } +std::vector<unsigned char> tinyb::from_iter_to_vector(GVariant *iter) +{ + GVariantIter *value_iter; + guchar value_byte; + + g_variant_get (iter, + "ay", + &value_iter); + + if (value_iter == nullptr) + throw std::invalid_argument("GVariant should be a container of an array of bytes"); + + std::vector<unsigned char> value; + while (g_variant_iter_loop(value_iter, "y", &value_byte)) { + value.push_back(value_byte); + } + + g_variant_iter_free(value_iter); + return value; +} + void tinyb::handle_error(GError *error) { if (error != nullptr) { |