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 | |
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]>
-rw-r--r-- | api/tinyb/BluetoothAdapter.hpp | 36 | ||||
-rw-r--r-- | api/tinyb/BluetoothDevice.hpp | 97 | ||||
-rw-r--r-- | api/tinyb/BluetoothEvent.hpp | 5 | ||||
-rw-r--r-- | api/tinyb/BluetoothGattCharacteristic.hpp | 20 | ||||
-rw-r--r-- | api/tinyb/BluetoothGattDescriptor.hpp | 10 | ||||
-rw-r--r-- | api/tinyb/BluetoothObject.hpp | 24 | ||||
-rw-r--r-- | examples/esstinyb.cpp | 2 | ||||
-rw-r--r-- | include/BluetoothNotificationHandler.hpp | 11 | ||||
-rw-r--r-- | include/tinyb_utils.hpp | 2 | ||||
-rw-r--r-- | java/BluetoothGattCharacteristic.java | 4 | ||||
-rw-r--r-- | java/jni/BluetoothGattCharacteristic.cxx | 8 | ||||
-rw-r--r-- | java/jni/helper.hpp | 2 | ||||
-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 |
19 files changed, 563 insertions, 28 deletions
diff --git a/api/tinyb/BluetoothAdapter.hpp b/api/tinyb/BluetoothAdapter.hpp index e7bb5eb1..12bec0d2 100644 --- a/api/tinyb/BluetoothAdapter.hpp +++ b/api/tinyb/BluetoothAdapter.hpp @@ -43,9 +43,11 @@ class tinyb::BluetoothAdapter: public BluetoothObject friend class tinyb::BluetoothManager; friend class tinyb::BluetoothEventManager; friend class tinyb::BluetoothDevice; +friend class tinyb::BluetoothNotificationHandler; private: Adapter1 *object; + /** Removes a device from the list of devices available on this adapter. * @param[in] arg_device The path of the device on DBus * @return TRUE if device was successfully removed @@ -54,7 +56,6 @@ private: const std::string &arg_device ); - protected: BluetoothAdapter(Adapter1 *object); @@ -63,6 +64,12 @@ protected: std::string *name = nullptr, std::string *identifier = nullptr, BluetoothObject *parent = nullptr); + + std::function<void(bool)> powered_callback; + std::function<void(bool)> discoverable_callback; + std::function<void(bool)> pairable_callback; + std::function<void(bool)> discovering_callback; + public: static std::string java_class() { @@ -122,7 +129,7 @@ public: std::string get_name (); /** Returns the friendly name of this adapter. - * @return The friendly name of this adapter, or NULL if not set. + * @return The friendly name of this adapter. */ std::string get_alias (); @@ -144,6 +151,12 @@ public: */ void set_powered (bool value); + void enable_powered_notifications( + std::function<void(BluetoothAdapter &adapter, bool powered, void *userdata)> callback, + void *userdata); + void enable_powered_notifications(std::function<void(bool powered)> callback); + void disable_powered_notifications(); + /** Returns the discoverable state the adapter. * @return The discoverable state of the adapter. */ @@ -153,6 +166,13 @@ public: */ void set_discoverable (bool value); + void enable_discoverable_notifications( + std::function<void(BluetoothAdapter &adapter, bool discoverable, void *userdata)> callback, + void *userdata); + void enable_discoverable_notifications(std::function<void(bool discoverable)> callback); + void disable_discoverable_notifications(); + + /** Returns the discoverable timeout the adapter. * @return The discoverable timeout of the adapter. */ @@ -172,6 +192,12 @@ public: */ void set_pairable (bool value); + void enable_pairable_notifications( + std::function<void(BluetoothAdapter &adapter, bool pairable, void *userdata)> callback, + void *userdata); + void enable_pairable_notifications(std::function<void(bool pairable)> callback); + void disable_pairable_notifications(); + /** Returns the timeout in seconds after which pairable state turns off * automatically, 0 means never. * @return The pairable timeout of the adapter. @@ -188,6 +214,12 @@ public: */ bool get_discovering (); + void enable_discovering_notifications( + std::function<void(BluetoothAdapter &adapter, bool discovering, void *userdata)> callback, + void *userdata); + void enable_discovering_notifications(std::function<void(bool discovering)> callback); + void disable_discovering_notifications(); + /** Returns the UUIDs of the adapter. * @return Array containing the UUIDs of the adapter, ends with NULL. */ diff --git a/api/tinyb/BluetoothDevice.hpp b/api/tinyb/BluetoothDevice.hpp index 79cda77f..145a5871 100644 --- a/api/tinyb/BluetoothDevice.hpp +++ b/api/tinyb/BluetoothDevice.hpp @@ -29,6 +29,7 @@ #include "BluetoothManager.hpp" #include <cstdint> #include <vector> +#include <functional> /* Forward declaration of types */ struct _Object; @@ -47,6 +48,7 @@ friend class tinyb::BluetoothManager; friend class tinyb::BluetoothEventManager; friend class tinyb::BluetoothAdapter; friend class tinyb::BluetoothGattService; +friend class tinyb::BluetoothNotificationHandler; private: Device1 *object; @@ -59,6 +61,13 @@ protected: std::string *name = nullptr, std::string *identifier = nullptr, BluetoothObject *parent = nullptr); + + std::function<void(int16_t)> rssi_callback; + std::function<void(bool)> trusted_callback; + std::function<void(bool)> paired_callback; + std::function<void(bool)> connected_callback; + std::function<void(bool)> blocked_callback; + public: static std::string java_class() { @@ -176,6 +185,20 @@ public: */ bool get_paired (); + /** Registers a callback which will be called when the paired property changes. + * @param callback The callback function to be called. + * @param device Will contain a reference to this device + * @param paired Will contain the new value of the paired property + * @param userdata Data provided by the user to be attached to the callback. Can be nullptr. The caller retains ownership of this data and will have to clear it after disabling this notification. + */ + void enable_paired_notifications( + std::function<void(BluetoothDevice &device, bool paired, void *userdata)> callback, + void *userdata); + /** Unregisters the callback set with enable_paired_notifications. No more notifications will + * be sent after this operation completes. + */ + void disable_paired_notifications(); + /** Returns the trusted state the device. * @return The trusted state of the device. */ @@ -185,6 +208,22 @@ public: */ void set_trusted (bool value); + /** Registers a callback which will be called when the trusted property changes. + * @param callback The callback function to be called. + * @param device Will contain a reference to this device + * @param trusted Will contain the new value of the trusted property + * @param userdata Data provided by the user to be attached to the callback. Can be nullptr. The caller retains ownership of this data and will have to clear it after disabling this notification. + */ + void enable_trusted_notifications( + std::function<void(BluetoothDevice &device, bool trusted, void *userdata)> callback, + void *userdata); + void enable_trusted_notifications( + std::function<void(bool trusted)> callback); + /** Unregisters the callback set with enable_trusted_notifications. No more notifications will + * be sent after this operation completes. + */ + void disable_trusted_notifications(); + /** Returns the blocked state the device. * @return The blocked state of the device. */ @@ -194,6 +233,23 @@ public: */ void set_blocked (bool value); + /** Registers a callback which will be called when the blocked property changes. + * @param callback The callback function to be called. + * @param device Will contain a reference to this device + * @param blocked Will contain the new value of the trusted property + * @param userdata Data provided by the user to be attached to the callback. Can be nullptr. + * The caller retains ownership of this data and might have to deallocate it after disabling this notification. + */ + void enable_blocked_notifications( + std::function<void(BluetoothDevice &device, bool blocked, void *userdata)> callback, + void *userdata); + void enable_blocked_notifications( + std::function<void(bool blocked)> callback); + /** Unregisters the callback set with enable_trusted_notifications. No more notifications will + * be sent after this operation completes. + */ + void disable_blocked_notifications(); + /** Returns if device uses only pre-Bluetooth 2.1 pairing mechanism. * @return True if device uses only pre-Bluetooth 2.1 pairing mechanism. */ @@ -204,11 +260,52 @@ public: */ int16_t get_rssi (); + + /** Registers a callback which will be called when the RSSI property changes. + * @param callback The callback function to be called. + * @param device Will contain a reference to this device + * @param rssi Will contain the new value of the rssi property + * @param userdata Data provided by the user to be attached to the callback. Can be nullptr. The caller retains ownership of this data and will have to clear it after disabling this notification. + */ + void enable_rssi_notifications( + std::function<void(BluetoothDevice &device, int16_t rssi, void *userdata)> callback, + void *userdata = nullptr); + /** Registers a callback which will be called when the RSSI property changes. + * @param callback The callback function to be called. + * @param rssi Will contain the new value of the rssi property + */ + void enable_rssi_notifications( + std::function<void(int16_t rssi)> callback); + /** Unregisters the callback set with enable_rssi_notifications. No more notifications will + * be sent after this operation completes. + */ + void disable_rssi_notifications(); + /** Returns the connected state of the device. * @return The connected state of the device. */ bool get_connected (); + /** Registers a callback which will be called when the connected property changes. + * @param callback The callback function to be called. + * @param device Will contain a reference to this device + * @param connected Will contain the new value of the connected property + * @param userdata Data provided by the user to be attached to the callback. Can be nullptr. The caller retains ownership of this data and will have to clear it after disabling this notification. + */ + void enable_connected_notifications( + std::function<void(BluetoothDevice &device, bool connected, void *userdata)> callback, + void *userdata); + /** Registers a callback which will be called when the connected property changes. + * @param callback The callback function to be called. + * @param connected Will contain the new value of the connected property + */ + void enable_connected_notifications( + std::function<void(bool connected)> callback); + /** Unregisters the callback set with enable_connected_notifications. No more notifications will + * be sent after this operation completes. + */ + void disable_connected_notifications(); + /** Returns the UUIDs of the device. * @return Array containing the UUIDs of the device, ends with NULL. */ diff --git a/api/tinyb/BluetoothEvent.hpp b/api/tinyb/BluetoothEvent.hpp index 75cca633..9435c02a 100644 --- a/api/tinyb/BluetoothEvent.hpp +++ b/api/tinyb/BluetoothEvent.hpp @@ -25,12 +25,13 @@ #include <string> #include <condition_variable> #include <atomic> +#include <functional> #include "BluetoothObject.hpp" #pragma once using namespace tinyb; -typedef void (*BluetoothCallback)(BluetoothObject &, void *); +typedef std::function<void (BluetoothObject &, void *)> BluetoothCallback; class tinyb::BluetoothEvent { private: @@ -106,7 +107,7 @@ public: BluetoothEvent(BluetoothType type, std::string *name, std::string *identifier, BluetoothObject *parent, bool execute_once = true, - BluetoothCallback cb = generic_callback, void *data = NULL); + BluetoothCallback cb = nullptr, void *data = NULL); ~BluetoothEvent(); BluetoothType get_type() const { diff --git a/api/tinyb/BluetoothGattCharacteristic.hpp b/api/tinyb/BluetoothGattCharacteristic.hpp index 7d838381..9a480cef 100644 --- a/api/tinyb/BluetoothGattCharacteristic.hpp +++ b/api/tinyb/BluetoothGattCharacteristic.hpp @@ -28,6 +28,7 @@ #include "BluetoothGattDescriptor.hpp" #include <string> #include <vector> +#include <functional> /* Forward declaration of types */ struct _Object; @@ -35,6 +36,7 @@ typedef struct _Object Object; struct _GattCharacteristic1; typedef struct _GattCharacteristic1 GattCharacteristic1; + /** * Provides access to Bluetooth GATT characteristic. Follows the BlueZ adapter API * available at: http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/gatt-api.txt @@ -46,6 +48,7 @@ friend class tinyb::BluetoothGattService; friend class tinyb::BluetoothGattDescriptor; friend class tinyb::BluetoothManager; friend class tinyb::BluetoothEventManager; +friend class BluetoothNotificationHandler; private: GattCharacteristic1 *object; @@ -58,6 +61,12 @@ protected: std::string *name = nullptr, std::string *identifier = nullptr, BluetoothObject *parent = nullptr); + + std::function<void(std::vector<unsigned char> &)> value_changed_callback; + + bool start_notify (); + bool stop_notify (); + public: static std::string java_class() { @@ -97,11 +106,12 @@ public: */ bool write_value (const std::vector<unsigned char> &arg_value); - bool start_notify ( - ); - - bool stop_notify ( - ); + bool enable_value_notifications( + std::function<void(BluetoothGattCharacteristic &characteristic, std::vector<unsigned char> &value,void *userdata)> callback, + void *user_data); + bool enable_value_notifications( + std::function<void(std::vector<unsigned char> &value)> callback); + bool disable_value_notifications(); /* D-Bus property accessors: */ /** Get the UUID of this characteristic. diff --git a/api/tinyb/BluetoothGattDescriptor.hpp b/api/tinyb/BluetoothGattDescriptor.hpp index 82f64a3c..2e7fb365 100644 --- a/api/tinyb/BluetoothGattDescriptor.hpp +++ b/api/tinyb/BluetoothGattDescriptor.hpp @@ -42,6 +42,7 @@ class tinyb::BluetoothGattDescriptor: public BluetoothObject friend class tinyb::BluetoothGattCharacteristic; friend class tinyb::BluetoothManager; friend class tinyb::BluetoothEventManager; +friend class tinyb::BluetoothNotificationHandler; private: GattDescriptor1 *object; @@ -56,6 +57,8 @@ protected: std::string *identifier = nullptr, BluetoothObject *parent = nullptr); + std::function<void(std::vector<unsigned char> &)> value_changed_callback; + public: static std::string java_class() { @@ -88,6 +91,13 @@ public: const std::vector<unsigned char> &arg_value ); + bool enable_value_notifications( + std::function<void(BluetoothGattDescriptor &descriptor, std::vector<unsigned char> &value,void *userdata)> callback, + void *user_data); + bool enable_value_notifications( + std::function<void(std::vector<unsigned char> &value)> callback); + bool disable_value_notifications(); + /* D-Bus property accessors: */ /** Get the UUID of this descriptor. * @return The 128 byte UUID of this descriptor, NULL if an error occurred diff --git a/api/tinyb/BluetoothObject.hpp b/api/tinyb/BluetoothObject.hpp index 804f39ed..cfabcc16 100644 --- a/api/tinyb/BluetoothObject.hpp +++ b/api/tinyb/BluetoothObject.hpp @@ -22,8 +22,10 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include <memory> #pragma once +#include <memory> +#include <mutex> +#include <atomic> #define JAVA_PACKAGE "tinyb" @@ -43,14 +45,34 @@ enum class BluetoothType { class BluetoothManager; class BluetoothAdapter; class BluetoothDevice; + class BluetoothDeviceChangeHandler; class BluetoothGattService; class BluetoothGattCharacteristic; + class BluetoothNotificationHandler; class BluetoothGattDescriptor; class BluetoothException; } + class tinyb::BluetoothObject { +protected: + std::mutex lk; + std::atomic_bool valid; + + bool lock() { + if (valid) { + lk.lock(); + return true; + } else { + return false; + } + } + + void unlock() { + lk.unlock(); + } + public: static BluetoothType class_type() { return BluetoothType::NONE; } diff --git a/examples/esstinyb.cpp b/examples/esstinyb.cpp index 1e34eccf..4f153aae 100644 --- a/examples/esstinyb.cpp +++ b/examples/esstinyb.cpp @@ -136,7 +136,6 @@ int main(int argc, char **argv) bool bt_error = false; /* Activate the temperature measurements by enabling notifications */ add_signal_handler(); - temp_characteristic->start_notify(); while (!bt_error && !interrupted) { /* Read temperature data and display it */ try { @@ -154,7 +153,6 @@ int main(int argc, char **argv) bt_error = true; } } - temp_characteristic->stop_notify(); delete temp_characteristic; } diff --git a/include/BluetoothNotificationHandler.hpp b/include/BluetoothNotificationHandler.hpp new file mode 100644 index 00000000..3acdb1d2 --- /dev/null +++ b/include/BluetoothNotificationHandler.hpp @@ -0,0 +1,11 @@ +#include <gio/gio.h> + +class tinyb::BluetoothNotificationHandler { + +public: + static void on_properties_changed_adapter(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata); + static void on_properties_changed_device(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata); + static void on_properties_changed_characteristic(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata); + static void on_properties_changed_descriptor(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata); + +}; diff --git a/include/tinyb_utils.hpp b/include/tinyb_utils.hpp index e47f3c55..6f96378f 100644 --- a/include/tinyb_utils.hpp +++ b/include/tinyb_utils.hpp @@ -28,11 +28,13 @@ #include "generated-code.h" #include <vector> +#include <stdexcept> extern GDBusObjectManager *gdbus_manager; namespace tinyb { std::vector<unsigned char> from_gbytes_to_vector(const GBytes *bytes); GBytes *from_vector_to_gbytes(const std::vector<unsigned char>& array); + std::vector<unsigned char> from_iter_to_vector(GVariant *iter); void handle_error(GError *error); }; diff --git a/java/BluetoothGattCharacteristic.java b/java/BluetoothGattCharacteristic.java index b8582768..359fbb70 100644 --- a/java/BluetoothGattCharacteristic.java +++ b/java/BluetoothGattCharacteristic.java @@ -81,9 +81,9 @@ public class BluetoothGattCharacteristic extends BluetoothObject */ public native boolean writeValue(byte[] argValue); - public native boolean startNotify(); + public native boolean enableValueNotifications(Runnable runnable); - public native boolean stopNotify(); + public native boolean disableValueNotifications(); /* D-Bus property accessors: */ /** Get the UUID of this characteristic. diff --git a/java/jni/BluetoothGattCharacteristic.cxx b/java/jni/BluetoothGattCharacteristic.cxx index b86b3b48..cc8b15c1 100644 --- a/java/jni/BluetoothGattCharacteristic.cxx +++ b/java/jni/BluetoothGattCharacteristic.cxx @@ -130,12 +130,12 @@ jboolean Java_tinyb_BluetoothGattCharacteristic_writeValue(JNIEnv *env, jobject return JNI_FALSE; } -jboolean Java_tinyb_BluetoothGattCharacteristic_startNotify(JNIEnv *env, jobject obj) +jboolean Java_tinyb_BluetoothGattCharacteristic_enableValueNotifications(JNIEnv *env, jobject obj, jobject runnable) { try { BluetoothGattCharacteristic *obj_gatt_char = getInstance<BluetoothGattCharacteristic>(env, obj); - return obj_gatt_char->start_notify() ? JNI_TRUE : JNI_FALSE; + return JNI_FALSE; } catch (std::bad_alloc &e) { raise_java_oom_exception(env, e); } catch (BluetoothException &e) { @@ -150,12 +150,12 @@ jboolean Java_tinyb_BluetoothGattCharacteristic_startNotify(JNIEnv *env, jobject return JNI_FALSE; } -jboolean Java_tinyb_BluetoothGattCharacteristic_stopNotify(JNIEnv *env, jobject obj) +jboolean Java_tinyb_BluetoothGattCharacteristic_disableValueNotifications(JNIEnv *env, jobject obj) { try { BluetoothGattCharacteristic *obj_gatt_char = getInstance<BluetoothGattCharacteristic>(env, obj); - return obj_gatt_char->stop_notify() ? JNI_TRUE : JNI_FALSE; + return JNI_FALSE; } catch (std::bad_alloc &e) { raise_java_oom_exception(env, e); } catch (BluetoothException &e) { diff --git a/java/jni/helper.hpp b/java/jni/helper.hpp index 51c18b00..d5795973 100644 --- a/java/jni/helper.hpp +++ b/java/jni/helper.hpp @@ -65,7 +65,7 @@ template <typename T> jobject generic_clone(JNIEnv *env, jobject obj) { T *obj_generic = getInstance<T>(env, obj); - T *copy_generic = new T(*obj_generic); + T *copy_generic = obj_generic->clone(); jclass generic_class = search_class(env, *copy_generic); jmethodID generic_ctor = search_method(env, generic_class, "<init>", "(J)V", false); 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) { |