From cdaf51206a95494d8de43fd5461313efff6badd7 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sat, 15 Feb 2020 11:19:27 +0100 Subject: C++ tinyb_hci: Working HCIScanner showing AD packets, demonstrating new HCI classes See scripts/build-x86_64.sh and README.md for build instructions. See scripts/run-hci_scanner.sh to start new HCI scanner (C++). New HCI C++ implementation redised in libtinyb_hci.so w/o GLIB/DBus dependencies, but 'libbluetooth.so' dependency. Following Class datastructures are complete: - HCIUtil: Exception types, uint128_t and endian conversions - General UUID interface and its efficient UUID16, UUID32 + UUID128 implementation. Conversion 'toString', respecting endianess, and UUID* -> UUID128 conversion. Requird member comparison operations due to using interface - HCIAdapter with its opened HCISession, as well as its discovered HCIDevices - HCIAdapter discover includes multiple advertising AD records, up to 25 according to the spec. - HCIAdapter parses full AD segment. TODO: Handle few more AD types API/Impl Details: - Datastructures utilize 'vector>' collections. - Most attributes are specified 'const' -> immutable for efficancy - Convenient collection access member operations - etc .. RESULTS: - Fast AD scanning of multiple devices w/ UUID and RSSI - Proper integration into tinyb project TODO: - Handle few more AD types - Test multiple parallel HCISession from HCIAdapter - HCIAdapter.connect() - Represent GATT Service, Characteristics and Description - Catch up with the Java binding step by step --- .gitignore | 2 + .settings/language.settings.xml | 48 +++ CMakeLists.txt | 3 +- api/tinyb_hci/HCITypes.hpp | 267 +++++++++++++ api/tinyb_hci/HCIUtil.hpp | 290 ++++++++++++++ api/tinyb_hci/UUID.hpp | 174 ++++++++ examples/CMakeLists.txt | 7 + examples/HCIScanner.cpp | 71 ++++ examples/TinyBTest01.cpp | 106 +++++ java/CMakeLists.txt | 12 +- java/jni/CMakeLists.txt | 1 + java/jni/HCIAdapter.cxx | 34 ++ java/jni/HCIDevice.cxx | 34 ++ java/jni/HCIEvent.cxx | 87 ++++ java/jni/HCIGattCharacteristic.cxx | 34 ++ java/jni/HCIGattDescriptor.cxx | 34 ++ java/jni/HCIGattService.cxx | 34 ++ java/jni/HCIManager.cxx | 30 ++ java/jni/HCIObject.cxx | 34 ++ java/tinyb/dbus/DBusDevice.java | 4 - java/tinyb/hci/HCIAdapter.java | 199 +++++++++ java/tinyb/hci/HCIDevice.java | 231 +++++++++++ java/tinyb/hci/HCIEvent.java | 62 +++ java/tinyb/hci/HCIGattCharacteristic.java | 115 ++++++ java/tinyb/hci/HCIGattDescriptor.java | 86 ++++ java/tinyb/hci/HCIGattService.java | 90 +++++ java/tinyb/hci/HCIManager.java | 137 +++++++ java/tinyb/hci/HCIObject.java | 91 +++++ scripts/build-armhf.sh | 20 + scripts/build-x86_64.sh | 22 + scripts/run-hci_scanner.sh | 8 + scripts/run-java-scanner.sh | 6 +- src/BluetoothAdapter.cpp | 459 --------------------- src/BluetoothDevice.cpp | 642 ------------------------------ src/BluetoothEvent.cpp | 111 ------ src/BluetoothGattCharacteristic.cpp | 324 --------------- src/BluetoothGattDescriptor.cpp | 244 ------------ src/BluetoothGattService.cpp | 148 ------- src/BluetoothManager.cpp | 411 ------------------- src/BluetoothObject.cpp | 64 --- src/BluetoothUUID.cpp | 89 ----- src/CMakeLists.txt | 75 ---- src/org.bluez.xml | 195 --------- src/tinyb.pc.cmake | 11 - src/tinyb/BluetoothAdapter.cpp | 459 +++++++++++++++++++++ src/tinyb/BluetoothDevice.cpp | 642 ++++++++++++++++++++++++++++++ src/tinyb/BluetoothEvent.cpp | 111 ++++++ src/tinyb/BluetoothGattCharacteristic.cpp | 324 +++++++++++++++ src/tinyb/BluetoothGattDescriptor.cpp | 244 ++++++++++++ src/tinyb/BluetoothGattService.cpp | 148 +++++++ src/tinyb/BluetoothManager.cpp | 411 +++++++++++++++++++ src/tinyb/BluetoothObject.cpp | 64 +++ src/tinyb/BluetoothUUID.cpp | 89 +++++ src/tinyb/CMakeLists.txt | 75 ++++ src/tinyb/org.bluez.xml | 195 +++++++++ src/tinyb/tinyb.pc.cmake | 11 + src/tinyb/tinyb_utils.cpp | 95 +++++ src/tinyb_hci/CMakeLists.txt | 44 ++ src/tinyb_hci/HCIDiscovery.cpp | 316 +++++++++++++++ src/tinyb_hci/HCIScanner.cpp | 77 ++++ src/tinyb_hci/HCITypes.cpp | 283 +++++++++++++ src/tinyb_hci/HCIUtil.cpp | 143 +++++++ src/tinyb_hci/HCItemp.cpp | 34 ++ src/tinyb_hci/UUID.cpp | 113 ++++++ src/tinyb_hci/tinyb_hci.pc.cmake | 11 + src/tinyb_utils.cpp | 95 ----- 66 files changed, 6252 insertions(+), 2878 deletions(-) create mode 100644 .settings/language.settings.xml create mode 100644 api/tinyb_hci/HCITypes.hpp create mode 100644 api/tinyb_hci/HCIUtil.hpp create mode 100644 api/tinyb_hci/UUID.hpp create mode 100644 examples/HCIScanner.cpp create mode 100644 examples/TinyBTest01.cpp create mode 100644 java/jni/HCIAdapter.cxx create mode 100644 java/jni/HCIDevice.cxx create mode 100644 java/jni/HCIEvent.cxx create mode 100644 java/jni/HCIGattCharacteristic.cxx create mode 100644 java/jni/HCIGattDescriptor.cxx create mode 100644 java/jni/HCIGattService.cxx create mode 100644 java/jni/HCIManager.cxx create mode 100644 java/jni/HCIObject.cxx create mode 100644 java/tinyb/hci/HCIAdapter.java create mode 100644 java/tinyb/hci/HCIDevice.java create mode 100644 java/tinyb/hci/HCIEvent.java create mode 100644 java/tinyb/hci/HCIGattCharacteristic.java create mode 100644 java/tinyb/hci/HCIGattDescriptor.java create mode 100644 java/tinyb/hci/HCIGattService.java create mode 100644 java/tinyb/hci/HCIManager.java create mode 100644 java/tinyb/hci/HCIObject.java create mode 100755 scripts/build-armhf.sh create mode 100755 scripts/build-x86_64.sh create mode 100755 scripts/run-hci_scanner.sh delete mode 100644 src/BluetoothAdapter.cpp delete mode 100644 src/BluetoothDevice.cpp delete mode 100644 src/BluetoothEvent.cpp delete mode 100644 src/BluetoothGattCharacteristic.cpp delete mode 100644 src/BluetoothGattDescriptor.cpp delete mode 100644 src/BluetoothGattService.cpp delete mode 100644 src/BluetoothManager.cpp delete mode 100644 src/BluetoothObject.cpp delete mode 100644 src/BluetoothUUID.cpp delete mode 100644 src/CMakeLists.txt delete mode 100644 src/org.bluez.xml delete mode 100644 src/tinyb.pc.cmake create mode 100644 src/tinyb/BluetoothAdapter.cpp create mode 100644 src/tinyb/BluetoothDevice.cpp create mode 100644 src/tinyb/BluetoothEvent.cpp create mode 100644 src/tinyb/BluetoothGattCharacteristic.cpp create mode 100644 src/tinyb/BluetoothGattDescriptor.cpp create mode 100644 src/tinyb/BluetoothGattService.cpp create mode 100644 src/tinyb/BluetoothManager.cpp create mode 100644 src/tinyb/BluetoothObject.cpp create mode 100644 src/tinyb/BluetoothUUID.cpp create mode 100644 src/tinyb/CMakeLists.txt create mode 100644 src/tinyb/org.bluez.xml create mode 100644 src/tinyb/tinyb.pc.cmake create mode 100644 src/tinyb/tinyb_utils.cpp create mode 100644 src/tinyb_hci/CMakeLists.txt create mode 100644 src/tinyb_hci/HCIDiscovery.cpp create mode 100644 src/tinyb_hci/HCIScanner.cpp create mode 100644 src/tinyb_hci/HCITypes.cpp create mode 100644 src/tinyb_hci/HCIUtil.cpp create mode 100644 src/tinyb_hci/HCItemp.cpp create mode 100644 src/tinyb_hci/UUID.cpp create mode 100644 src/tinyb_hci/tinyb_hci.pc.cmake delete mode 100644 src/tinyb_utils.cpp diff --git a/.gitignore b/.gitignore index b11ae151..46d92d3b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build*/ +dist*/ # Object files *.o @@ -21,3 +22,4 @@ build*/ # Archive files *.jar +/Debug/ diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml new file mode 100644 index 00000000..75cc2ade --- /dev/null +++ b/.settings/language.settings.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index d9461864..bfee0bbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,8 @@ if (DOXYGEN_FOUND) endif () endif (DOXYGEN_FOUND) -add_subdirectory (src) +add_subdirectory (src/tinyb) +add_subdirectory (src/tinyb_hci) if (BUILDEXAMPLES) add_subdirectory (examples) diff --git a/api/tinyb_hci/HCITypes.hpp b/api/tinyb_hci/HCITypes.hpp new file mode 100644 index 00000000..8e512167 --- /dev/null +++ b/api/tinyb_hci/HCITypes.hpp @@ -0,0 +1,267 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef HCITYPES_HPP_ +#define HCITYPES_HPP_ + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +#include "HCIUtil.hpp" +#include "UUID.hpp" + +#define JAVA_MAIN_PACKAGE "org/tinyb" +#define JAVA_DBUS_PACKAGE "tinyb/hci" + +extern "C" { + #include + #include + #include +} + +namespace tinyb_hci { + +/** +// ************************************************* +// ************************************************* +// ************************************************* + */ + +class HCIObject +{ +protected: + std::mutex lk; + std::atomic_bool valid; + + HCIObject() : valid(true) {} + + bool lock() { + if (valid) { + lk.lock(); + return true; + } else { + return false; + } + } + + void unlock() { + lk.unlock(); + } + +public: + bool isValid() { return valid; } +}; + +// ************************************************* +// ************************************************* +// ************************************************* + +class HCISession; // forward +class HCIDevice; // forward + +class HCIAdapter : public HCIObject +{ +friend class HCISession; + +private: + static int getDefaultDevId(); + static int getDevId(bdaddr_t &bdaddr); + static int getDevId(const std::string &hcidev); + + const int to_send_req_poll_ms = 1000; + struct hci_dev_info dev_info; + std::vector> sessions; + std::vector> discoveredDevices; + + bool validateDevInfo(); + void sessionClosed(HCISession& s); + + void addDevice(std::shared_ptr const &device); + +protected: + +public: + const int dev_id; + + /** + * Using the default adapter device + */ + HCIAdapter(); + + /** + * @param[in] mac address + */ + HCIAdapter(bdaddr_t &mac); + + /** + * @param[in] hcidev shall be 'hci[0-9]' + */ + HCIAdapter(const std::string &hcidev); + + /** + * @param[in] dev_id an already identified HCI device id + */ + HCIAdapter(const int dev_id); + + ~HCIAdapter(); + + bool hasDevId() const { return 0 <= dev_id; } + + std::string getAddress() const; + std::string getName() const; + + /** + * Returns a reference to the newly opened session + * if successful, otherwise nullptr is returned. + */ + std::shared_ptr open(); + + // device discovery aka device scanning + + /** + * Returns a reference to the newly opened discovery session + * if successful, otherwise nullptr is returned. + */ + std::shared_ptr startDiscovery(); + + /** + * Closes the discovery session. + * @return true if no error, otherwise false. + */ + bool stopDiscovery(HCISession& s); + + /** + * Discovery devices up until timeoutMS in milliseconds. + * @return true if no error, otherwise false. + */ + bool discoverDevices(HCISession& s, int timeoutMS); + + /** Returns discovered devices from a discovery */ + std::vector> getDevices() { return discoveredDevices; } + + /** Discards all discovered devices. */ + void removeDevices() { discoveredDevices.clear(); } + + /** Returns index >= 0 if found, otherwise -1 */ + int findDevice(bdaddr_t const & mac) const; + + std::shared_ptr getDevice(int index) const { return discoveredDevices.at(index); } + + std::string toString() const; +}; + +// ************************************************* +// ************************************************* +// ************************************************* + +class HCISession +{ +friend class HCIAdapter; + +private: + static std::atomic_int name_counter; + HCIAdapter &adapter; + + /** HCI device handle, open, close etc. dd < 0 is uninitialized */ + int _dd; + + HCISession(HCIAdapter &a, int dd) + : adapter(a), _dd(dd), name(name_counter.fetch_add(1)) + {} + +public: + const int name; + + ~HCISession() { close(); } + + const HCIAdapter &getAdapter() { return adapter; } + + bool close(); + bool isOpen() const { return 0 <= _dd; } + int dd() const { return _dd; } +}; + +inline bool operator<(const HCISession& lhs, const HCISession& rhs) +{ return lhs.name < rhs.name; } + +inline bool operator==(const HCISession& lhs, const HCISession& rhs) +{ return lhs.name == rhs.name; } + +inline bool operator!=(const HCISession& lhs, const HCISession& rhs) +{ return !(lhs == rhs); } + +// ************************************************* +// ************************************************* +// ************************************************* + +class HCIDevice : public HCIObject +{ +friend class HCIAdapter; +private: + std::string name; + uint8_t rssi; + std::vector> services; + + void setLastRSSI(uint8_t newRSSI) { rssi=newRSSI; } + + void addService(std::shared_ptr const &uuid); + + void setName(std::string &n) { name = n; } + +public: + /** Device mac address */ + const bdaddr_t mac; + + HCIDevice(const bdaddr_t &mac, const std::string &name, uint8_t rssi); + std::string getAddress() const; + std::string getName() const { return name; } + uint8_t getLastRSSI() const { return rssi; } + std::vector> getServices() const { return services; } + + /** Returns index >= 0 if found, otherwise -1 */ + int findService(std::shared_ptr const &uuid) const; + + std::string toString() const; +}; + +inline bool operator<(const HCIDevice& lhs, const HCIDevice& rhs) +{ return bacmp(&lhs.mac, &rhs.mac)<0; } + +inline bool operator==(const HCIDevice& lhs, const HCIDevice& rhs) +{ return !bacmp(&lhs.mac, &rhs.mac); } + +inline bool operator!=(const HCIDevice& lhs, const HCIDevice& rhs) +{ return !(lhs == rhs); } + +} // namespace tinyb_hci + +#endif /* HCITYPES_HPP_ */ diff --git a/api/tinyb_hci/HCIUtil.hpp b/api/tinyb_hci/HCIUtil.hpp new file mode 100644 index 00000000..61a47767 --- /dev/null +++ b/api/tinyb_hci/HCIUtil.hpp @@ -0,0 +1,290 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef HCIUTIL_HPP_ +#define HCIUTIL_HPP_ + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { + #include +} + +namespace tinyb_hci { + + /** + * Returns current monotonic time in milliseconds. + */ + int64_t getCurrentMilliseconds(); + + #define E_FILE_LINE __FILE__,__LINE__ + + class RuntimeException : public std::exception { + protected: + RuntimeException(std::string const type, std::string const m, const char* file=__FILE__, int line=__LINE__) noexcept + : msg(std::string(type).append(" @ ").append(file).append(":").append(std::to_string(line)).append(": ").append(m)) { } + + public: + const std::string msg; + + RuntimeException(std::string const m, const char* file=__FILE__, int line=__LINE__) noexcept + : RuntimeException("RuntimeException", m, file, line) {} + + virtual ~RuntimeException() noexcept { } + + virtual const char* what() const noexcept override; + }; + + class InternalError : public RuntimeException { + public: + InternalError(std::string const m, const char* file=__FILE__, int line=__LINE__) noexcept + : RuntimeException("InternalError", m, file, line) {} + }; + + class NullPointerException : public RuntimeException { + public: + NullPointerException(std::string const m, const char* file=__FILE__, int line=__LINE__) noexcept + : RuntimeException("NullPointerException", m, file, line) {} + }; + + class IllegalArgumentException : public RuntimeException { + public: + IllegalArgumentException(std::string const m, const char* file=__FILE__, int line=__LINE__) noexcept + : RuntimeException("IllegalArgumentException", m, file, line) {} + }; + + class UnsupportedOperationException : public RuntimeException { + public: + UnsupportedOperationException(std::string const m, const char* file=__FILE__, int line=__LINE__) noexcept + : RuntimeException("UnsupportedOperationException", m, file, line) {} + }; + + /** + // ************************************************* + // ************************************************* + // ************************************************* + */ + + struct uint128_t { + uint8_t data[16]; + + bool operator==(uint128_t const &o) const { + if( this == &o ) { + return true; + } + return !std::memcmp(data, o.data, 16); + } + bool operator!=(uint128_t const &o) const + { return !(*this == o); } + }; + + inline uint128_t bswap(uint128_t const & source) { + uint128_t dest; + uint8_t const * const s = source.data; + uint8_t * const d = dest.data; + for(int i=0; i<16; i++) { + d[i] = s[15-i]; + } + return dest; + } + + /** + * On the i386 the host byte order is Least Significant Byte first (LSB) or Little-Endian, + * whereas the network byte order, as used on the Internet, is Most Significant Byte first (MSB) or Big-Endian. + * See #include + * + * Bluetooth is LSB or Little-Endian! + */ + +#if __BYTE_ORDER == __BIG_ENDIAN + inline uint16_t be_to_cpu(uint16_t const & n) { + return n; + } + inline uint16_t cpu_to_be(uint16_t const & h) { + return h; + } + inline uint16_t le_to_cpu(uint16_t const & l) { + return bswap_16(l); + } + inline uint16_t cpu_to_le(uint16_t const & h) { + return bswap_16(h); + } + + inline uint32_t be_to_cpu(uint32_t const & n) { + return n; + } + inline uint32_t cpu_to_be(uint32_t const & h) { + return h; + } + inline uint32_t le_to_cpu(uint32_t const & l) { + return bswap_32(l); + } + inline uint32_t cpu_to_le(uint32_t const & h) { + return bswap_32(h); + } + + inline uint128_t be_to_cpu(uint128_t const & n) { + return n; + } + inline uint128_t cpu_to_be(uint128_t const & h) { + return n; + } + inline uint128_t le_to_cpu(uint128_t const & l) { + return bswap(l); + } + inline uint128_t cpu_to_le(uint128_t const & h) { + return bswap(h); + } +#elif __BYTE_ORDER == __LITTLE_ENDIAN + inline uint16_t be_to_cpu(uint16_t const & n) { + return bswap_16(n); + } + inline uint16_t cpu_to_be(uint16_t const & h) { + return bswap_16(h); + } + inline uint16_t le_to_cpu(uint16_t const & l) { + return l; + } + inline uint16_t cpu_to_le(uint16_t const & h) { + return h; + } + + inline uint32_t be_to_cpu(uint32_t const & n) { + return bswap_32(n); + } + inline uint32_t cpu_to_be(uint32_t const & h) { + return bswap_32(h); + } + inline uint32_t le_to_cpu(uint32_t const & l) { + return l; + } + inline uint32_t cpu_to_le(uint32_t const & h) { + return h; + } + + inline uint128_t be_to_cpu(uint128_t const & n) { + return bswap(n); + } + inline uint128_t cpu_to_be(uint128_t const & h) { + return bswap(h); + } + inline uint128_t le_to_cpu(uint128_t const & l) { + return l; + } + inline uint128_t cpu_to_le(uint128_t const & h) { + return h; + } +#else + #error "Unexpected __BYTE_ORDER" +#endif + + inline uint16_t get_uint16(uint8_t const * buffer, int const byte_offset) + { + uint16_t const * p = (uint16_t const *) ( buffer + byte_offset ); + return *p; + } + inline uint16_t get_uint16(uint8_t const * buffer, int const byte_offset, bool littleEndian) + { + uint16_t const * p = (uint16_t const *) ( buffer + byte_offset ); + return littleEndian ? le_to_cpu(*p) : be_to_cpu(*p); + } + + inline uint32_t get_uint32(uint8_t const * buffer, int const byte_offset) + { + uint32_t const * p = (uint32_t const *) ( buffer + byte_offset ); + return *p; + } + inline uint32_t get_uint32(uint8_t const * buffer, int const byte_offset, bool littleEndian) + { + uint32_t const * p = (uint32_t const *) ( buffer + byte_offset ); + return littleEndian ? le_to_cpu(*p) : be_to_cpu(*p); + } + + inline uint128_t get_uint128(uint8_t const * buffer, int const byte_offset) + { + uint128_t const * p = (uint128_t const *) ( buffer + byte_offset ); + return *p; + } + inline uint128_t get_uint128(uint8_t const * buffer, int const byte_offset, bool littleEndian) + { + uint128_t const * p = (uint128_t const *) ( buffer + byte_offset ); + return littleEndian ? le_to_cpu(*p) : be_to_cpu(*p); + } + + /** + * Merge the given 'uuid16' into a 'base_uuid' copy at the given little endian 'uuid16_le_octet_index' position. + *

+ * The given 'uuid16' value will be added with the 'base_uuid' copy at the given position. + *

+ *
+     * base_uuid: 00000000-0000-1000-8000-00805F9B34FB
+     *    uuid16: DCBA
+     * uuid16_le_octet_index: 12
+     *    result: 0000DCBA-0000-1000-8000-00805F9B34FB
+     *
+     * LE: low-mem - FB349B5F8000-0080-0010-0000-ABCD0000 - high-mem
+     *                                           ^ index 12
+     * LE: uuid16 -> value.data[12+13]
+     *
+     * BE: low-mem - 0000DCBA-0000-1000-8000-00805F9B34FB - high-mem
+     *                   ^ index 2
+     * BE: uuid16 -> value.data[2+3]
+     * 
+ */ + uint128_t merge_uint128(uint128_t const & base_uuid, uint16_t const uuid16, int const uuid16_le_octet_index); + + /** + * Merge the given 'uuid32' into a 'base_uuid' copy at the given little endian 'uuid32_le_octet_index' position. + *

+ * The given 'uuid32' value will be added with the 'base_uuid' copy at the given position. + *

+ *
+     * base_uuid: 00000000-0000-1000-8000-00805F9B34FB
+     *    uuid32: 87654321
+     * uuid32_le_octet_index: 12
+     *    result: 87654321-0000-1000-8000-00805F9B34FB
+     *
+     * LE: low-mem - FB349B5F8000-0080-0010-0000-12345678 - high-mem
+     *                                           ^ index 12
+     * LE: uuid32 -> value.data[12..15]
+     *
+     * BE: low-mem - 87654321-0000-1000-8000-00805F9B34FB - high-mem
+     *               ^ index 0
+     * BE: uuid32 -> value.data[0..3]
+     * 
+ */ + uint128_t merge_uint128(uint128_t const & base_uuid, uint32_t const uuid32, int const uuid32_le_octet_index); + +} // namespace tinyb_hci + +#endif /* HCIUTIL_HPP_ */ diff --git a/api/tinyb_hci/UUID.hpp b/api/tinyb_hci/UUID.hpp new file mode 100644 index 00000000..f2463308 --- /dev/null +++ b/api/tinyb_hci/UUID.hpp @@ -0,0 +1,174 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef UUID_HPP_ +#define UUID_HPP_ + +#pragma once +#include +#include +#include +#include +#include + +#include "HCIUtil.hpp" + +namespace tinyb_hci { + +class UUID128; + +/** + * Bluetooth UUID + *

+ * Bluetooth is LSB or Little-Endian! + *

+ *

+ * BASE_UUID '00000000-0000-1000-8000-00805F9B34FB' + *

+ */ +extern UUID128 BT_BASE_UUID; + +class UUID { +public: + /** Underlying integer value present octet count */ + enum class Type : int { + UUID16=2, UUID32=4, UUID128=16 + }; + Type const type; + UUID(Type const type) : type(type) {} + virtual ~UUID() {}; + UUID(const UUID &o) noexcept = default; + UUID(UUID &&o) noexcept = default; + UUID& operator=(const UUID &o) noexcept = default; + UUID& operator=(UUID &&o) noexcept = default; + + virtual bool operator==(UUID const &o) const = 0; + virtual bool operator!=(UUID const &o) const = 0; + + Type getType() const { return type; } + virtual std::string toString() const = 0; + virtual std::string toUUID128String(UUID128 const & base_uuid=BT_BASE_UUID, int const le_octet_index=12) const = 0; +}; + +class UUID16 : public UUID { +public: + uint16_t const value; + + UUID16(uint16_t const v) + : UUID(Type::UUID16), value(v) { } + + UUID16(uint8_t const * const buffer, int const byte_offset, bool littleEndian) + : UUID(Type::UUID16), value(get_uint16(buffer, byte_offset, littleEndian)) { } + + UUID16(const UUID16 &o) noexcept = default; + UUID16(UUID16 &&o) noexcept = default; + UUID16& operator=(const UUID16 &o) noexcept = default; + UUID16& operator=(UUID16 &&o) noexcept = default; + + bool operator==(UUID const &o) const override { + if( this == &o ) { + return true; + } + return type == o.type && value == static_cast(&o)->value; + } + bool operator!=(UUID const &o) const override + { return !(*this == o); } + + std::string toString() const override; + std::string toUUID128String(UUID128 const & base_uuid=BT_BASE_UUID, int const le_octet_index=12) const override; +}; + +class UUID32 : public UUID { +public: + uint32_t const value; + + UUID32(uint32_t const v) + : UUID(Type::UUID32), value(v) {} + + UUID32(uint8_t const * const buffer, int const byte_offset, bool const littleEndian) + : UUID(Type::UUID32), value(get_uint32(buffer, byte_offset, littleEndian)) { } + + UUID32(const UUID32 &o) noexcept = default; + UUID32(UUID32 &&o) noexcept = default; + UUID32& operator=(const UUID32 &o) noexcept = default; + UUID32& operator=(UUID32 &&o) noexcept = default; + + bool operator==(UUID const &o) const override { + if( this == &o ) { + return true; + } + return type == o.type && value == static_cast(&o)->value; + } + bool operator!=(UUID const &o) const override + { return !(*this == o); } + + std::string toString() const override; + std::string toUUID128String(UUID128 const & base_uuid=BT_BASE_UUID, int const le_octet_index=12) const override; +}; + +class UUID128 : public UUID { +public: + uint128_t const value; + + /** Creates an instance by given big-endian byte array of 16 bytes */ + UUID128(uint8_t const bigEndianBytes[]) + : UUID128(bigEndianBytes, 0, false) + { } + + UUID128(uint128_t const v) + : UUID(Type::UUID128), value(v) {} + + UUID128(uint8_t const * const buffer, int const byte_offset, bool const littleEndian) + : UUID(Type::UUID128), value(get_uint128(buffer, byte_offset, littleEndian)) { } + + UUID128(UUID128 const & base_uuid, UUID16 const & uuid16, int const uuid16_le_octet_index); + + UUID128(UUID128 const & base_uuid, UUID32 const & uuid32, int const uuid32_le_octet_index); + + UUID128(const UUID128 &o) noexcept = default; + UUID128(UUID128 &&o) noexcept = default; + UUID128& operator=(const UUID128 &o) noexcept = default; + UUID128& operator=(UUID128 &&o) noexcept = default; + + bool operator==(UUID const &o) const override { + if( this == &o ) { + return true; + } + return type == o.type && value == static_cast(&o)->value; + } + bool operator!=(UUID const &o) const override + { return !(*this == o); } + + std::string toString() const override; + std::string toUUID128String(UUID128 const & base_uuid=BT_BASE_UUID, int const le_octet_index=12) const override { + (void)base_uuid; + (void)le_octet_index; + return toString(); + } +}; + +} /* namespace tinyb_hci */ + +#endif /* UUID_HPP_ */ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 52352bdc..16bfcc00 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -40,6 +40,11 @@ set_target_properties(list_mfg PROPERTIES CXX_STANDARD 11) +add_executable (hci_scanner HCIScanner.cpp) +set_target_properties(list_mfg + PROPERTIES + CXX_STANDARD 11) + include_directories(${PROJECT_SOURCE_DIR}/api) target_link_libraries (hellotinyb tinyb) @@ -49,3 +54,5 @@ target_link_libraries (esstinyb tinyb) target_link_libraries (notifications tinyb) target_link_libraries (uuid tinyb) target_link_libraries (list_mfg tinyb) +target_link_libraries (hci_scanner tinyb_hci) + diff --git a/examples/HCIScanner.cpp b/examples/HCIScanner.cpp new file mode 100644 index 00000000..47c57afe --- /dev/null +++ b/examples/HCIScanner.cpp @@ -0,0 +1,71 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +int main(int argc, char *argv[]) +{ + int err = 0; + + tinyb_hci::HCIAdapter adapter; // default + if( !adapter.hasDevId() ) { + fprintf(stderr, "Default adapter not available.\n"); + exit(1); + } + if( !adapter.isValid() ) { + fprintf(stderr, "Adapter invalid.\n"); + exit(1); + } + fprintf(stderr, "Adapter: device %s, address %s\n", + adapter.getName().c_str(), adapter.getAddress().c_str()); + + while( !err ) { + std::shared_ptr session = adapter.startDiscovery(); + if( nullptr == session ) { + fprintf(stderr, "Adapter start discovery failed.\n"); + exit(1); + } + + // do something + if( !adapter.discoverDevices(*session, 1000) ) { + fprintf(stderr, "Adapter discovery failed.\n"); + err = 1; + } + + fprintf(stderr, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"); + fprintf(stderr, "Discovery Results HCIAdapter:\n"); + fprintf(stderr, "%s\n", adapter.toString().c_str()); + fprintf(stderr, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"); + + if( !adapter.stopDiscovery(*session) ) { + fprintf(stderr, "Adapter stop discovery failed.\n"); + err = 1; + } + } + +out: + return err; +} + diff --git a/examples/TinyBTest01.cpp b/examples/TinyBTest01.cpp new file mode 100644 index 00000000..c50ad776 --- /dev/null +++ b/examples/TinyBTest01.cpp @@ -0,0 +1,106 @@ +/* + * Author: Petre Eftime + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +using namespace tinyb; + +int main(int argc, char **argv) +{ + if (argc < 2) { + std::cerr << "Run as: " << argv[0] << " " << std::endl; + exit(1); + } + + BluetoothManager *manager = nullptr; + try { + manager = BluetoothManager::get_bluetooth_manager(); + } catch(const std::runtime_error& e) { + std::cerr << "Error while initializing libtinyb: " << e.what() << std::endl; + exit(1); + } + + /* Start the discovery of devices */ + bool ret = manager->start_discovery(); + std::cout << "Started = " << (ret ? "true" : "false") << std::endl; + + std::unique_ptr temperature_service; + + std::string device_mac(argv[1]); + auto sensor_tag = manager->find(nullptr, &device_mac, nullptr, std::chrono::seconds(10)); + if (sensor_tag == nullptr) { + std::cout << "Device not found" << std::endl; + return 1; + } + sensor_tag->enable_connected_notifications([] (BluetoothDevice &d, bool connected, void *usedata) + { if (connected) std::cout << "Connected " << d.get_name() << std::endl; }, NULL); + + if (sensor_tag != nullptr) { + /* Connect to the device and get the list of services exposed by it */ + sensor_tag->connect(); + std::string service_uuid("f000aa00-0451-4000-b000-000000000000"); + std::cout << "Waiting for service " << service_uuid << "to be discovered" << std::endl; + temperature_service = sensor_tag->find(&service_uuid); + } else { + ret = manager->stop_discovery(); + std::cerr << "SensorTag not found after 30 seconds, exiting" << std::endl; + return 1; + } + + /* Stop the discovery (the device was found or timeout was over) */ + ret = manager->stop_discovery(); + std::cout << "Stopped = " << (ret ? "true" : "false") << std::endl; + + auto value_uuid = std::string("f000aa01-0451-4000-b000-000000000000"); + auto temp_value = temperature_service->find(&value_uuid); + + auto config_uuid = std::string("f000aa02-0451-4000-b000-000000000000"); + auto temp_config = temperature_service->find(&config_uuid); + + auto period_uuid = std::string("f000aa03-0451-4000-b000-000000000000"); + auto temp_period = temperature_service->find(&period_uuid); + + /* Activate the temperature measurements */ + std::vector config_on {0x01}; + temp_config->write_value(config_on); + temp_period->write_value({100}); + temp_value->enable_value_notifications(data_callback, nullptr); + + std::mutex m; + std::unique_lock lock(m); + + std::signal(SIGINT, signal_handler); + + cv.wait(lock); + + /* Disconnect from the device */ + if (sensor_tag != nullptr) + sensor_tag->disconnect(); +} diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt index 0d7f80fb..867525b4 100644 --- a/java/CMakeLists.txt +++ b/java/CMakeLists.txt @@ -44,7 +44,15 @@ set(JAVA_CLASSES org.tinyb.BluetoothAdapter tinyb.dbus.DBusGattDescriptor tinyb.dbus.DBusGattService tinyb.dbus.DBusManager - tinyb.dbus.DBusObject) + tinyb.dbus.DBusObject + tinyb.hci.HCIAdapter + tinyb.hci.HCIDevice + tinyb.hci.HCIEvent + tinyb.hci.HCIGattCharacteristic + tinyb.hci.HCIGattDescriptor + tinyb.hci.HCIGattService + tinyb.hci.HCIManager + tinyb.hci.HCIObject) add_custom_command (TARGET tinybjar POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Generating JNI headers.." @@ -53,6 +61,6 @@ add_custom_command (TARGET tinybjar ) set(JNI_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/tinybjar.dir/jni") -install (FILES ${CMAKE_CURRENT_BINARY_DIR}/tinyb.jar DESTINATION ${CMAKE_INSTALL_LIBDIR}/../lib/java) +install (FILES ${CMAKE_CURRENT_BINARY_DIR}/tinyb2.jar DESTINATION ${CMAKE_INSTALL_LIBDIR}/../lib/java) add_subdirectory (jni) diff --git a/java/jni/CMakeLists.txt b/java/jni/CMakeLists.txt index 411883a6..dc613084 100644 --- a/java/jni/CMakeLists.txt +++ b/java/jni/CMakeLists.txt @@ -8,6 +8,7 @@ endif (JNI_FOUND) set (tinyb_LIB_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/api ${PROJECT_SOURCE_DIR}/api/tinyb + ${PROJECT_SOURCE_DIR}/api/tinyb_hci ${PROJECT_SOURCE_DIR}/include ) diff --git a/java/jni/HCIAdapter.cxx b/java/jni/HCIAdapter.cxx new file mode 100644 index 00000000..d357483d --- /dev/null +++ b/java/jni/HCIAdapter.cxx @@ -0,0 +1,34 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tinyb_hci/HCITypes.hpp" + +#include "tinyb_hci_HCIAdapter.h" + +#include "JNIMem.hpp" +#include "helper_base.hpp" + +using namespace tinyb_hci; + diff --git a/java/jni/HCIDevice.cxx b/java/jni/HCIDevice.cxx new file mode 100644 index 00000000..d2fb2f98 --- /dev/null +++ b/java/jni/HCIDevice.cxx @@ -0,0 +1,34 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tinyb_hci/HCITypes.hpp" + +#include "tinyb_hci_HCIDevice.h" + +#include "JNIMem.hpp" +#include "helper_base.hpp" + +using namespace tinyb_hci; + diff --git a/java/jni/HCIEvent.cxx b/java/jni/HCIEvent.cxx new file mode 100644 index 00000000..b1bc89c5 --- /dev/null +++ b/java/jni/HCIEvent.cxx @@ -0,0 +1,87 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tinyb_hci_HCIEvent.h" + +jobject Java_tinyb_hci_HCIEvent_getType(JNIEnv *env, jobject obj) +{ + (void)env; + (void)obj; + + return NULL; +} + +jstring Java_tinyb_hci_HCIEvent_getName(JNIEnv *env, jobject obj) +{ + (void)env; + (void)obj; + + return NULL; +} + +jstring Java_tinyb_hci_HCIEvent_getIdentifier(JNIEnv *env, jobject obj) +{ + (void)env; + (void)obj; + + return NULL; +} + +jboolean Java_tinyb_hci_HCIEvent_executeCallback(JNIEnv *env, jobject obj) +{ + (void)env; + (void)obj; + + return JNI_FALSE; +} + +jboolean Java_tinyb_hci_HCIEvent_hasCallback(JNIEnv *env, jobject obj) +{ + (void)env; + (void)obj; + + return JNI_FALSE; +} + +void Java_tinyb_hci_HCIEvent_init(JNIEnv *env, jobject obj, jobject type, jstring name, + jstring identifier, jobject parent, jobject callback, + jobject arg_data) +{ + (void)env; + (void)obj; + (void)type; + (void)name; + (void)identifier; + (void)parent; + (void)callback; + (void)arg_data; +} + +void Java_tinyb_hci_HCIEvent_delete(JNIEnv *env, jobject obj) +{ + (void)env; + (void)obj; +} + diff --git a/java/jni/HCIGattCharacteristic.cxx b/java/jni/HCIGattCharacteristic.cxx new file mode 100644 index 00000000..7237ffde --- /dev/null +++ b/java/jni/HCIGattCharacteristic.cxx @@ -0,0 +1,34 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tinyb_hci/HCITypes.hpp" + +#include "tinyb_hci_HCIGattCharacteristic.h" + +#include "JNIMem.hpp" +#include "helper_base.hpp" + +using namespace tinyb_hci; + diff --git a/java/jni/HCIGattDescriptor.cxx b/java/jni/HCIGattDescriptor.cxx new file mode 100644 index 00000000..5060170b --- /dev/null +++ b/java/jni/HCIGattDescriptor.cxx @@ -0,0 +1,34 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tinyb_hci/HCITypes.hpp" + +#include "tinyb_hci_HCIGattDescriptor.h" + +#include "JNIMem.hpp" +#include "helper_base.hpp" + +using namespace tinyb_hci; + diff --git a/java/jni/HCIGattService.cxx b/java/jni/HCIGattService.cxx new file mode 100644 index 00000000..7ad8d822 --- /dev/null +++ b/java/jni/HCIGattService.cxx @@ -0,0 +1,34 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tinyb_hci/HCITypes.hpp" + +#include "tinyb_hci_HCIGattService.h" + +#include "JNIMem.hpp" +#include "helper_base.hpp" + +using namespace tinyb_hci; + diff --git a/java/jni/HCIManager.cxx b/java/jni/HCIManager.cxx new file mode 100644 index 00000000..218e98d7 --- /dev/null +++ b/java/jni/HCIManager.cxx @@ -0,0 +1,30 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tinyb_hci/HCITypes.hpp" + +#include "JNIMem.hpp" +#include "helper_base.hpp" + diff --git a/java/jni/HCIObject.cxx b/java/jni/HCIObject.cxx new file mode 100644 index 00000000..0f261eba --- /dev/null +++ b/java/jni/HCIObject.cxx @@ -0,0 +1,34 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tinyb_hci/HCITypes.hpp" + +#include "tinyb_hci_HCIObject.h" + +#include "JNIMem.hpp" +#include "helper_base.hpp" + +using namespace tinyb_hci; + diff --git a/java/tinyb/dbus/DBusDevice.java b/java/tinyb/dbus/DBusDevice.java index bb1919b9..f01bd9e1 100644 --- a/java/tinyb/dbus/DBusDevice.java +++ b/java/tinyb/dbus/DBusDevice.java @@ -64,10 +64,6 @@ public class DBusDevice extends DBusObject implements BluetoothDevice @Override public native boolean disconnect() throws BluetoothException; - public native void connectAsyncStart() throws BluetoothException; - - public native boolean connectAsyncFinish() throws BluetoothException; - @Override public native boolean connect() throws BluetoothException; diff --git a/java/tinyb/hci/HCIAdapter.java b/java/tinyb/hci/HCIAdapter.java new file mode 100644 index 00000000..71c9d818 --- /dev/null +++ b/java/tinyb/hci/HCIAdapter.java @@ -0,0 +1,199 @@ +/** + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package tinyb.hci; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import org.tinyb.BluetoothAdapter; +import org.tinyb.BluetoothDevice; +import org.tinyb.BluetoothException; +import org.tinyb.BluetoothManager; +import org.tinyb.BluetoothNotification; +import org.tinyb.BluetoothType; +import org.tinyb.TransportType; + +public class HCIAdapter extends HCIObject implements BluetoothAdapter +{ + private final String address; + private final String name; + + /* pp */ HCIAdapter(final String address, final String name) + { + super(compHash(address, name)); + this.address = address; + this.name = name; + } + + @Override + public boolean equals(final Object obj) + { + if (obj == null || !(obj instanceof HCIDevice)) { + return false; + } + final HCIAdapter other = (HCIAdapter)obj; + return address.equals(other.address) && name.equals(other.name); + } + + @Override + public String getAddress() { return address; } + + @Override + public String getName() { return name; } + + public String getInterfaceName() { + throw new UnsupportedOperationException(); // FIXME + } + + @Override + public native BluetoothType getBluetoothType(); + + @Override + public native BluetoothAdapter clone(); + + static BluetoothType class_type() { return BluetoothType.ADAPTER; } + + @Override + public BluetoothDevice find(final String name, final String address, final long timeoutMS) { + final BluetoothManager manager = HCIManager.getBluetoothManager(); + return (BluetoothDevice) manager.find(BluetoothType.DEVICE, name, address, this, timeoutMS); + } + + @Override + public BluetoothDevice find(final String name, final String address) { + return find(name, address, 0); + } + + /* D-Bus method calls: */ + + @Override + public native boolean startDiscovery() throws BluetoothException; + + @Override + public native boolean stopDiscovery() throws BluetoothException; + + @Override + public native List getDevices(); + + @Override + public native int removeDevices() throws BluetoothException; + + /* D-Bus property accessors: */ + + @Override + public native String getAlias(); + + @Override + public native void setAlias(String value); + + @Override + public native long getBluetoothClass(); + + @Override + public native boolean getPowered(); + + @Override + public native void enablePoweredNotifications(BluetoothNotification callback); + + @Override + public native void disablePoweredNotifications(); + + @Override + public native void setPowered(boolean value); + + @Override + public native boolean getDiscoverable(); + + @Override + public native void enableDiscoverableNotifications(BluetoothNotification callback); + + @Override + public native void disableDiscoverableNotifications(); + + @Override + public native void setDiscoverable(boolean value); + + @Override + public native long getDiscoverableTimeout(); + + @Override + public native void setDiscoverableTimout(long value); + + @Override + public native BluetoothDevice connectDevice(String address, String addressType); + + @Override + public native boolean getPairable(); + + @Override + public native void enablePairableNotifications(BluetoothNotification callback); + + @Override + public native void disablePairableNotifications(); + + @Override + public native void setPairable(boolean value); + + @Override + public native long getPairableTimeout(); + + @Override + public native void setPairableTimeout(long value); + + @Override + public native boolean getDiscovering(); + + @Override + public native void enableDiscoveringNotifications(BluetoothNotification callback); + + @Override + public native void disableDiscoveringNotifications(); + + @Override + public native String[] getUUIDs(); + + @Override + public native String getModalias(); + + @Override + public void setDiscoveryFilter(final List uuids, final int rssi, final int pathloss, final TransportType transportType) { + final List uuidsFmt = new ArrayList<>(uuids.size()); + for (final UUID uuid : uuids) { + uuidsFmt.add(uuid.toString()); + } + setDiscoveryFilter(uuidsFmt, rssi, pathloss, transportType.ordinal()); + } + + public void setRssiDiscoveryFilter(final int rssi) { + setDiscoveryFilter(Collections.EMPTY_LIST, rssi, 0, TransportType.AUTO); + } + + private native void delete(); + + private native void setDiscoveryFilter(List uuids, int rssi, int pathloss, int transportType); +} diff --git a/java/tinyb/hci/HCIDevice.java b/java/tinyb/hci/HCIDevice.java new file mode 100644 index 00000000..b9a41a53 --- /dev/null +++ b/java/tinyb/hci/HCIDevice.java @@ -0,0 +1,231 @@ +/** + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package tinyb.hci; + +import java.util.List; +import java.util.Map; + +import org.tinyb.BluetoothDevice; +import org.tinyb.BluetoothException; +import org.tinyb.BluetoothGattService; +import org.tinyb.BluetoothManager; +import org.tinyb.BluetoothNotification; +import org.tinyb.BluetoothType; + +import tinyb.dbus.DBusObject; + +public class HCIDevice extends HCIObject implements BluetoothDevice +{ + private final HCIAdapter adapter; + private final String address; + private final String name; + + /* pp */ HCIDevice(final HCIAdapter adptr, final String address, final String name) + { + super(compHash(address, name)); + this.adapter = adptr; + this.address = address; + this.name = name; + } + + @Override + public boolean equals(final Object obj) + { + if (obj == null || !(obj instanceof HCIDevice)) { + return false; + } + final HCIDevice other = (HCIDevice)obj; + return address.equals(other.address) && name.equals(other.name); + } + + @Override + public String getAddress() { return address; } + + @Override + public String getName() { return name; } + + @Override + public BluetoothType getBluetoothType() { return class_type(); } + + @Override + public native HCIDevice clone(); + + static BluetoothType class_type() { return BluetoothType.DEVICE; } + + @Override + public BluetoothGattService find(final String UUID, final long timeoutMS) { + final BluetoothManager manager = HCIManager.getBluetoothManager(); + return (BluetoothGattService) manager.find(BluetoothType.GATT_SERVICE, + null, UUID, this, timeoutMS); + } + + @Override + public BluetoothGattService find(final String UUID) { + return find(UUID, 0); + } + + /* D-Bus method calls: */ + + @Override + public native boolean disconnect() throws BluetoothException; + + @Override + public native boolean connect() throws BluetoothException; + + @Override + public native boolean connectProfile(String arg_UUID) throws BluetoothException; + + @Override + public native boolean disconnectProfile(String arg_UUID) throws BluetoothException; + + @Override + public boolean pair() throws BluetoothException + { throw new UnsupportedOperationException(); } // FIXME + + @Override + public native boolean remove() throws BluetoothException; + + @Override + public boolean cancelPairing() throws BluetoothException + { throw new UnsupportedOperationException(); } // FIXME + + @Override + public native List getServices(); + + /* D-Bus property accessors: */ + + @Override + public String getAlias() { return null; } // FIXME + + @Override + public void setAlias(final String value) + { throw new UnsupportedOperationException(); } // FIXME + + @Override + public native int getBluetoothClass(); + + @Override + public native short getAppearance(); + + @Override + public native String getIcon(); + + @Override + public native boolean getPaired(); + + @Override + public native void enablePairedNotifications(BluetoothNotification callback); + + @Override + public native void disablePairedNotifications(); + + @Override + public native boolean getTrusted(); + + @Override + public native void enableTrustedNotifications(BluetoothNotification callback); + + @Override + public native void disableTrustedNotifications(); + + @Override + public native void setTrusted(boolean value); + + @Override + public native boolean getBlocked(); + + @Override + public native void enableBlockedNotifications(BluetoothNotification callback); + + @Override + public native void disableBlockedNotifications(); + + @Override + public native void setBlocked(boolean value); + + @Override + public native boolean getLegacyPairing(); + + @Override + public native short getRSSI(); + + @Override + public native void enableRSSINotifications(BluetoothNotification callback); + + @Override + public native void disableRSSINotifications(); + + @Override + public native boolean getConnected(); + + @Override + public native void enableConnectedNotifications(BluetoothNotification callback); + + @Override + public native void disableConnectedNotifications(); + + @Override + public native String[] getUUIDs(); + + @Override + public native String getModalias(); + + @Override + public native HCIAdapter getAdapter(); + + @Override + public native Map getManufacturerData(); + + @Override + public native void enableManufacturerDataNotifications(BluetoothNotification > callback); + + @Override + public native void disableManufacturerDataNotifications(); + + + @Override + public native Map getServiceData(); + + @Override + public native void enableServiceDataNotifications(BluetoothNotification > callback); + + @Override + public native void disableServiceDataNotifications(); + + @Override + public native short getTxPower (); + + @Override + public native boolean getServicesResolved (); + + @Override + public native void enableServicesResolvedNotifications(BluetoothNotification callback); + + @Override + public native void disableServicesResolvedNotifications(); + + private native void delete(); +} diff --git a/java/tinyb/hci/HCIEvent.java b/java/tinyb/hci/HCIEvent.java new file mode 100644 index 00000000..4dc30ec3 --- /dev/null +++ b/java/tinyb/hci/HCIEvent.java @@ -0,0 +1,62 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package tinyb.hci; + +import org.tinyb.BluetoothCallback; +import org.tinyb.BluetoothEvent; +import org.tinyb.BluetoothType; + +public class HCIEvent implements BluetoothEvent +{ + private long nativeInstance; + + @Override + public native BluetoothType getType(); + @Override + public native String getName(); + @Override + public native String getIdentifier(); + @Override + public native boolean executeCallback(); + @Override + public native boolean hasCallback(); + + private native void init(BluetoothType type, String name, String identifier, + HCIObject parent, BluetoothCallback cb, Object data); + private native void delete(); + + public HCIEvent(final BluetoothType type, final String name, final String identifier, + final HCIObject parent, final BluetoothCallback cb, final Object data) + { + init(type, name, identifier, parent, cb, data); + } + + @Override + protected void finalize() + { + delete(); + } +} diff --git a/java/tinyb/hci/HCIGattCharacteristic.java b/java/tinyb/hci/HCIGattCharacteristic.java new file mode 100644 index 00000000..a2047e1e --- /dev/null +++ b/java/tinyb/hci/HCIGattCharacteristic.java @@ -0,0 +1,115 @@ +/** + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package tinyb.hci; + +import java.util.List; + +import org.tinyb.BluetoothException; +import org.tinyb.BluetoothGattCharacteristic; +import org.tinyb.BluetoothGattDescriptor; +import org.tinyb.BluetoothGattService; +import org.tinyb.BluetoothManager; +import org.tinyb.BluetoothNotification; +import org.tinyb.BluetoothType; + +public class HCIGattCharacteristic extends HCIObject implements BluetoothGattCharacteristic +{ + private final String uuid; + + /* pp */ HCIGattCharacteristic(final String uuid) + { + super(uuid.hashCode()); + this.uuid = uuid; + } + + @Override + public boolean equals(final Object obj) + { + if (obj == null || !(obj instanceof HCIGattCharacteristic)) { + return false; + } + final HCIGattCharacteristic other = (HCIGattCharacteristic)obj; + return uuid.equals(other.uuid); + } + + @Override + public String getUUID() { return uuid; } + + @Override + public native BluetoothType getBluetoothType(); + @Override + public native HCIGattCharacteristic clone(); + + static BluetoothType class_type() { return BluetoothType.GATT_CHARACTERISTIC; } + + @Override + public BluetoothGattDescriptor find(final String UUID, final long timeoutMS) { + final BluetoothManager manager = HCIManager.getBluetoothManager(); + return (BluetoothGattDescriptor) manager.find(BluetoothType.GATT_DESCRIPTOR, + null, UUID, this, timeoutMS); + } + + @Override + public BluetoothGattDescriptor find(final String UUID) { + return find(UUID, 0); + } + + /* D-Bus method calls: */ + + @Override + public native byte[] readValue() throws BluetoothException; + + @Override + public native void enableValueNotifications(BluetoothNotification callback); + + @Override + public native void disableValueNotifications(); + + @Override + public native boolean writeValue(byte[] argValue) throws BluetoothException; + + /* D-Bus property accessors: */ + + @Override + public native BluetoothGattService getService(); + + @Override + public native byte[] getValue(); + + @Override + public native boolean getNotifying(); + + @Override + public native String[] getFlags(); + + @Override + public native List getDescriptors(); + + private native void init(HCIGattCharacteristic obj); + + private native void delete(); + +} diff --git a/java/tinyb/hci/HCIGattDescriptor.java b/java/tinyb/hci/HCIGattDescriptor.java new file mode 100644 index 00000000..b04816a4 --- /dev/null +++ b/java/tinyb/hci/HCIGattDescriptor.java @@ -0,0 +1,86 @@ +/** + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package tinyb.hci; + +import org.tinyb.BluetoothException; +import org.tinyb.BluetoothGattDescriptor; +import org.tinyb.BluetoothNotification; +import org.tinyb.BluetoothType; + +public class HCIGattDescriptor extends HCIObject implements BluetoothGattDescriptor +{ + private final String uuid; + + /* pp */ HCIGattDescriptor(final String uuid) + { + super(uuid.hashCode()); + this.uuid = uuid; + } + + @Override + public boolean equals(final Object obj) + { + if (obj == null || !(obj instanceof HCIGattDescriptor)) { + return false; + } + final HCIGattDescriptor other = (HCIGattDescriptor)obj; + return uuid.equals(other.uuid); + } + + @Override + public String getUUID() { return uuid; } + + @Override + public native BluetoothType getBluetoothType(); + @Override + public native BluetoothGattDescriptor clone(); + + static BluetoothType class_type() { return BluetoothType.GATT_DESCRIPTOR; } + + /* D-Bus method calls: */ + + @Override + public native byte[] readValue(); + + @Override + public native boolean writeValue(byte[] argValue) throws BluetoothException; + + @Override + public native void enableValueNotifications(BluetoothNotification callback); + + @Override + public native void disableValueNotifications(); + + /* D-Bus property accessors: */ + + @Override + public native HCIGattCharacteristic getCharacteristic(); + + @Override + public native byte[] getValue(); + + private native void delete(); +} diff --git a/java/tinyb/hci/HCIGattService.java b/java/tinyb/hci/HCIGattService.java new file mode 100644 index 00000000..584f68b3 --- /dev/null +++ b/java/tinyb/hci/HCIGattService.java @@ -0,0 +1,90 @@ +/** + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package tinyb.hci; + +import java.util.List; + +import org.tinyb.BluetoothGattCharacteristic; +import org.tinyb.BluetoothGattService; +import org.tinyb.BluetoothManager; +import org.tinyb.BluetoothType; + +public class HCIGattService extends HCIObject implements BluetoothGattService +{ + private final String uuid; + + /* pp */ HCIGattService(final String uuid) + { + super(uuid.hashCode()); + this.uuid = uuid; + } + + @Override + public boolean equals(final Object obj) + { + if (obj == null || !(obj instanceof HCIGattService)) { + return false; + } + final HCIGattService other = (HCIGattService)obj; + return uuid.equals(other.uuid); + } + + @Override + public String getUUID() { return uuid; } + + @Override + public native BluetoothType getBluetoothType(); + + @Override + public native BluetoothGattService clone(); + + static BluetoothType class_type() { return BluetoothType.GATT_SERVICE; } + + @Override + public BluetoothGattCharacteristic find(final String UUID, final long timeoutMS) { + final BluetoothManager manager = HCIManager.getBluetoothManager(); + return (HCIGattCharacteristic) manager.find(BluetoothType.GATT_CHARACTERISTIC, + null, UUID, this, timeoutMS); + } + + @Override + public BluetoothGattCharacteristic find(final String UUID) { + return find(UUID, 0); + } + + /* D-Bus property accessors: */ + + @Override + public native HCIDevice getDevice(); + + @Override + public native boolean getPrimary(); + + @Override + public native List getCharacteristics(); + + private native void delete(); +} diff --git a/java/tinyb/hci/HCIManager.java b/java/tinyb/hci/HCIManager.java new file mode 100644 index 00000000..7afba39c --- /dev/null +++ b/java/tinyb/hci/HCIManager.java @@ -0,0 +1,137 @@ +/** + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package tinyb.hci; + +import java.util.ArrayList; +import java.util.List; + +import org.tinyb.BluetoothAdapter; +import org.tinyb.BluetoothDevice; +import org.tinyb.BluetoothException; +import org.tinyb.BluetoothGattService; +import org.tinyb.BluetoothObject; +import org.tinyb.BluetoothManager; +import org.tinyb.BluetoothType; + +public class HCIManager implements BluetoothManager +{ + private static HCIManager inst; + private final List adapters = new ArrayList(); + + public native BluetoothType getBluetoothType(); + + private HCIObject find(final int type, final String name, final String identifier, final BluetoothObject parent, final long milliseconds) + { throw new UnsupportedOperationException(); } // FIXME + + @Override + public HCIObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent, final long timeoutMS) { + return find(type.ordinal(), name, identifier, parent, timeoutMS); + } + + @Override + public HCIObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent) { + return find(type, name, identifier, parent, 0); + } + + @SuppressWarnings("unchecked") + @Override + public T find(final String name, final String identifier, final BluetoothObject parent, final long timeoutMS) { + return (T) find(HCIObject.class_type().ordinal(), name, identifier, parent, timeoutMS); + } + + @SuppressWarnings("unchecked") + @Override + public T find(final String name, final String identifier, final BluetoothObject parent) { + return (T) find(name, identifier, parent, 0); + } + + @Override + public BluetoothObject getObject(final BluetoothType type, final String name, + final String identifier, final BluetoothObject parent) { + return getObject(type.ordinal(), name, identifier, parent); + } + private BluetoothObject getObject(final int type, final String name, final String identifier, final BluetoothObject parent) + { throw new UnsupportedOperationException(); } // FIXME + + @Override + public List getObjects(final BluetoothType type, final String name, + final String identifier, final BluetoothObject parent) { + return getObjects(type.ordinal(), name, identifier, parent); + } + private List getObjects(final int type, final String name, final String identifier, final BluetoothObject parent) + { throw new UnsupportedOperationException(); } // FIXME + + @Override + public List getAdapters() { return adapters; } + + @Override + public List getDevices() { return getDefaultAdapter().getDevices(); } + + @Override + public List getServices() { throw new UnsupportedOperationException(); } // FIXME + + @Override + public boolean setDefaultAdapter(final BluetoothAdapter adapter) { throw new UnsupportedOperationException(); } // FIXME + + @Override + public BluetoothAdapter getDefaultAdapter() { return adapters.get(0); } + + @Override + public boolean startDiscovery() throws BluetoothException { return getDefaultAdapter().startDiscovery(); } + + @Override + public boolean stopDiscovery() throws BluetoothException { return getDefaultAdapter().stopDiscovery(); } + + @Override + public boolean getDiscovering() throws BluetoothException { return getDefaultAdapter().getDiscovering(); } + + private native HCIAdapter init() throws BluetoothException; + private native void delete(); + + private HCIManager() + { + adapters.add(init()); + } + + /** Returns an instance of BluetoothManager, to be used instead of constructor. + * @return An initialized BluetoothManager instance. + */ + public static synchronized BluetoothManager getBluetoothManager() throws RuntimeException, BluetoothException + { + if (inst == null) + { + inst = new HCIManager(); + } + return inst; + } + + @Override + protected void finalize() + { + adapters.clear(); + delete(); + } +} diff --git a/java/tinyb/hci/HCIObject.java b/java/tinyb/hci/HCIObject.java new file mode 100644 index 00000000..85a903e5 --- /dev/null +++ b/java/tinyb/hci/HCIObject.java @@ -0,0 +1,91 @@ +/** + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package tinyb.hci; + +import org.tinyb.BluetoothFactory; +import org.tinyb.BluetoothObject; +import org.tinyb.BluetoothType; + +public abstract class HCIObject implements BluetoothObject +{ + private final int hashValue; + private boolean isValid; + + static { + try { + System.loadLibrary(BluetoothFactory.JavaNativeLibBasename); + } catch (final Throwable e) { + System.err.println("Failed to load native library "+BluetoothFactory.JavaNativeLibBasename); + e.printStackTrace(); + throw e; // fwd exception - end here + } + } + + static BluetoothType class_type() { return BluetoothType.NONE; } + + /* pp */ static int compHash(final String a, final String b) { + // 31 * x == (x << 5) - x + final int hash = 31 + a.hashCode(); + return ((hash << 5) - hash) + b.hashCode(); + } + + protected HCIObject(final int hashValue) + { + this.hashValue = hashValue; + isValid = true; + } + + @Override + public abstract boolean equals(final Object obj); + + @Override + public final int hashCode() { + return hashValue; + } + + @Override + protected void finalize() + { + close(); + } + + @Override + public synchronized void close() { + if (!isValid) { + return; + } + isValid = false; + delete(); + } + @Override + public native BluetoothType getBluetoothType(); + + @Override + public BluetoothObject clone() + { throw new UnsupportedOperationException(); } // FIXME + + private native void delete(); +} diff --git a/scripts/build-armhf.sh b/scripts/build-armhf.sh new file mode 100755 index 00000000..06304872 --- /dev/null +++ b/scripts/build-armhf.sh @@ -0,0 +1,20 @@ +#! /bin/sh + +sdir=`dirname $(readlink -f $0)` +rootdir=`dirname $sdir` +echo rootdir $rootdir + +export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-armhf + +cd $rootdir +rm -rf dist-armhf +mkdir -p dist-armhf/bin +# rm -rf build-armhf +mkdir build-armhf +cd build-armhf +cmake -DCMAKE_INSTALL_PREFIX=$rootdir/dist-armhf -DBUILDJAVA=ON -DBUILDEXAMPLES=ON .. +make +make install +cp -a examples/* $rootdir/dist-armhf/bin + +cd $rootdir diff --git a/scripts/build-x86_64.sh b/scripts/build-x86_64.sh new file mode 100755 index 00000000..e181b87a --- /dev/null +++ b/scripts/build-x86_64.sh @@ -0,0 +1,22 @@ +#! /bin/sh + +sdir=`dirname $(readlink -f $0)` +rootdir=`dirname $sdir` +echo rootdir $rootdir + +# +# export JAVA_HOME=/opt-linux-x86_64/jdk1.8.0_121 +# + +cd $rootdir +rm -rf dist-x86_64 +mkdir -p dist-x86_64/bin +# rm -rf build-x86_64 +mkdir build-x86_64 +cd build-x86_64 +cmake -DCMAKE_INSTALL_PREFIX=$rootdir/dist-x86_64 -DBUILDJAVA=ON -DBUILDEXAMPLES=ON .. +make +make install +cp -a examples/* $rootdir/dist-x86_64/bin + +cd $rootdir diff --git a/scripts/run-hci_scanner.sh b/scripts/run-hci_scanner.sh new file mode 100755 index 00000000..afb733df --- /dev/null +++ b/scripts/run-hci_scanner.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ ! -e bin/hci_scanner -o ! -e lib/libtinyb.so -o ! -e lib/libtinyb_hci.so ] ; then + echo run from dist directory + exit 1 +fi +hciconfig hci0 reset +LD_LIBRARY_PATH=`pwd`/lib bin/hci_scanner $* diff --git a/scripts/run-java-scanner.sh b/scripts/run-java-scanner.sh index 90fdcb9a..eb214d60 100755 --- a/scripts/run-java-scanner.sh +++ b/scripts/run-java-scanner.sh @@ -1,7 +1,7 @@ #!/bin/sh -if [ ! -e java/tinyb2.jar -o ! -e examples/java/ScannerTinyB.jar ] ; then - echo run from build directory +if [ ! -e lib/java/tinyb2.jar -o ! -e bin/java/ScannerTinyB.jar -o ! -e lib/libtinyb.so -o ! -e lib/libtinyb_hci.so ] ; then + echo run from dist directory exit 1 fi -java -cp java/tinyb2.jar:examples/java/ScannerTinyB.jar -Djava.library.path=`pwd`/java/jni:`pwd`/src ScannerTinyB $* +java -cp lib/java/tinyb2.jar:bin/java/ScannerTinyB.jar -Djava.library.path=`pwd`/lib ScannerTinyB $* diff --git a/src/BluetoothAdapter.cpp b/src/BluetoothAdapter.cpp deleted file mode 100644 index eab4eacd..00000000 --- a/src/BluetoothAdapter.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Author: Petre Eftime - * Copyright (c) 2015 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "orgbluez-dbus.h" -#include "tinyb_utils.hpp" -#include "BluetoothNotificationHandler.hpp" -#include "BluetoothAdapter.hpp" -#include "BluetoothDevice.hpp" -#include "BluetoothManager.hpp" -#include "BluetoothException.hpp" - -using namespace tinyb; - -void BluetoothNotificationHandler::on_properties_changed_adapter(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata) { - - auto c = static_cast(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"); -} - -std::string BluetoothAdapter::get_java_class() const -{ - return std::string(JAVA_DBUS_PACKAGE "/DBusAdapter"); -} - -std::string BluetoothAdapter::get_object_path() const -{ - return std::string(g_dbus_proxy_get_object_path(G_DBUS_PROXY(object))); -} - -BluetoothType BluetoothAdapter::get_bluetooth_type() const -{ - return BluetoothType::ADAPTER; -} - -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) -{ - BluetoothAdapter(object.object); -} - -BluetoothAdapter *BluetoothAdapter::clone() const -{ - return new BluetoothAdapter(object); -} - -BluetoothAdapter::~BluetoothAdapter() -{ - valid = false; - g_signal_handlers_disconnect_by_data(object, this); - lk.lock(); - - g_object_unref(object); -} - -std::unique_ptr BluetoothAdapter::make(Object *object, - BluetoothType type, std::string *name, std::string *identifier, - BluetoothObject *parent) -{ - Adapter1 *adapter; - if((type == BluetoothType::NONE || type == BluetoothType::ADAPTER) && - (adapter = object_get_adapter1(object)) != NULL) { - - std::unique_ptr p(new BluetoothAdapter(adapter)); - g_object_unref(adapter); - - if ((name == nullptr || *name == p->get_name()) && - (identifier == nullptr || *identifier == p->get_address()) && - (parent == nullptr)) - return p; - } - - return std::unique_ptr(); -} - -std::vector> BluetoothAdapter::get_devices() -{ - std::vector> vector; - GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); - - for (l = objects; l != NULL; l = l->next) { - Object *object = OBJECT(l->data); - - auto p = BluetoothDevice::make(object, - BluetoothType::DEVICE, NULL, NULL, this); - if (p != nullptr) - vector.push_back(std::move(p)); - } - g_list_free_full(objects, g_object_unref); - - return vector; -} - -/* D-Bus method calls: */ -bool BluetoothAdapter::start_discovery () -{ - GError *error = NULL; - if (get_discovering() == true) - return true; - bool result = adapter1_call_start_discovery_sync( - object, - NULL, - &error - ); - handle_error(error); - return result; -} - -bool BluetoothAdapter::stop_discovery () -{ - GError *error = NULL; - if (get_discovering() == false) - return true; - bool result = adapter1_call_stop_discovery_sync( - object, - NULL, - &error - ); - handle_error(error); - return result; -} - -bool BluetoothAdapter::remove_device ( - const std::string &arg_device) -{ - GError *error = NULL; - bool result = adapter1_call_remove_device_sync( - object, - arg_device.c_str(), - NULL, - &error - ); - handle_error(error); - return result; -} - -bool BluetoothAdapter::set_discovery_filter (std::vector uuids, - int16_t rssi, uint16_t pathloss, const TransportType &transport) -{ - GError *error = NULL; - bool result = true; - GVariantDict dict; - g_variant_dict_init(&dict, NULL); - - if (uuids.size() > 0) - { - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("a(s)")); - - for (std::vector::iterator i = uuids.begin(); i != uuids.end(); ++i) - g_variant_builder_add(builder, "(s)", (*i).get_string().c_str()); - - GVariant *uuids_variant = g_variant_new("a(s)", builder); - g_variant_builder_unref(builder); - g_variant_dict_insert_value(&dict, "UUIDs", uuids_variant); - } - - if (rssi != 0) - g_variant_dict_insert_value(&dict, "RSSI", g_variant_new_int16(rssi)); - - if (pathloss != 0) - g_variant_dict_insert_value(&dict, "Pathloss", g_variant_new_uint16(pathloss)); - - std::string transport_str; - - if (transport == TransportType::AUTO) - transport_str = "auto"; - else if (transport == TransportType::BREDR) - transport_str = "bredr"; - else if (transport == TransportType::LE) - transport_str = "le"; - - if (!transport_str.empty()) - g_variant_dict_insert_value(&dict, "Transport", g_variant_new_string(transport_str.c_str())); - - GVariant *variant = g_variant_dict_end(&dict); - - result = adapter1_call_set_discovery_filter_sync( - object, - variant, - NULL, - &error - ); - - handle_error(error); - return result; -} - -/* D-Bus property accessors: */ -std::string BluetoothAdapter::get_address () -{ - return std::string(adapter1_get_address (object)); -} - -std::string BluetoothAdapter::get_name () -{ - return std::string(adapter1_get_name (object)); -} - -std::string BluetoothAdapter::get_alias () -{ - return std::string(adapter1_get_alias (object)); -} - -void BluetoothAdapter::set_alias (const std::string &value) -{ - adapter1_set_alias (object, value.c_str()); -} - -unsigned int BluetoothAdapter::get_class () -{ - return adapter1_get_class (object); -} - -bool BluetoothAdapter::get_powered () -{ - return adapter1_get_powered (object); -} - -void BluetoothAdapter::enable_powered_notifications( - std::function callback, - void *userdata) { - powered_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothAdapter::enable_powered_notifications(std::function callback) { - powered_callback = callback; -} -void BluetoothAdapter::disable_powered_notifications() { - powered_callback = nullptr; -} - -void BluetoothAdapter::set_powered (bool value) -{ - if (get_powered() != value) - adapter1_set_powered (object, value); -} - -bool BluetoothAdapter::get_discoverable () -{ - return adapter1_get_discoverable (object); -} - -void BluetoothAdapter::set_discoverable (bool value) -{ - adapter1_set_discoverable (object, value); -} - -void BluetoothAdapter::enable_discoverable_notifications( - std::function callback, - void *userdata) { - discoverable_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothAdapter::enable_discoverable_notifications(std::function callback) { - discoverable_callback = callback; -} -void BluetoothAdapter::disable_discoverable_notifications() { - discoverable_callback = nullptr; -} - -unsigned int BluetoothAdapter::get_discoverable_timeout () -{ - return adapter1_get_discoverable_timeout (object); -} - -void BluetoothAdapter::set_discoverable_timeout (unsigned int value) -{ - adapter1_set_discoverable_timeout (object, value); -} - -bool BluetoothAdapter::get_pairable () -{ - return adapter1_get_pairable (object); -} - -void BluetoothAdapter::enable_pairable_notifications( - std::function callback, - void *userdata) { - pairable_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothAdapter::enable_pairable_notifications(std::function callback) { - pairable_callback = callback; -} -void BluetoothAdapter::disable_pairable_notifications() { - pairable_callback = nullptr; -} - -void BluetoothAdapter::set_pairable (bool value) -{ - adapter1_set_pairable (object, value); -} - -unsigned int BluetoothAdapter::get_pairable_timeout () -{ - return adapter1_get_pairable_timeout (object); -} - -void BluetoothAdapter::set_pairable_timeout (unsigned int value) -{ - adapter1_set_pairable_timeout (object, value); -} - -bool BluetoothAdapter::get_discovering () -{ - return adapter1_get_discovering (object); -} - -void BluetoothAdapter::enable_discovering_notifications( - std::function callback, - void *userdata) { - discovering_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothAdapter::enable_discovering_notifications(std::function callback) { - discovering_callback = callback; -} -void BluetoothAdapter::disable_discovering_notifications() { - discovering_callback = nullptr; -} - -std::vector BluetoothAdapter::get_uuids () -{ - const char * const *uuids_c = adapter1_get_uuids (object); - std::vector uuids; - for (int i = 0; uuids_c[i] != NULL ;i++) - uuids.push_back(std::string(uuids_c[i])); - return uuids; -} - -std::unique_ptr BluetoothAdapter::get_modalias () -{ - const gchar *modalias= adapter1_get_modalias (object); - if (modalias == nullptr) - return std::unique_ptr(); - return std::unique_ptr(new std::string(modalias)); -} - -std::unique_ptr BluetoothAdapter::connect_device ( - const std::string &arg_address, const std::string &arg_address_type) -{ - bool result = true; - GError *error = NULL; - GVariantDict dict; - gchar *object_path = nullptr; - - g_variant_dict_init(&dict, NULL); - g_variant_dict_insert_value(&dict, "Address", g_variant_new_string(arg_address.c_str())); - g_variant_dict_insert_value(&dict, "AddressType", g_variant_new_string(arg_address_type.c_str())); - GVariant *variant = g_variant_dict_end(&dict); - - result = adapter1_call_connect_device_sync( - object, - variant, - &object_path, - NULL, - &error - ); - handle_error(error); - - if( result && nullptr != object_path ) { - - Device1 *device = device1_proxy_new_for_bus_sync( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.bluez", - object_path, - NULL, - &error); - g_free(object_path); - handle_error(error); - - if (device == nullptr) { - std::string error_msg("Error occured while instantiating device: "); - error_msg += error->message; - g_error_free(error); - throw BluetoothException(error_msg); - } - std::unique_ptr p(new BluetoothDevice(device)); - g_object_unref(device); - return p; - } - g_free(object_path); - return std::unique_ptr(); -} - diff --git a/src/BluetoothDevice.cpp b/src/BluetoothDevice.cpp deleted file mode 100644 index 97538cd4..00000000 --- a/src/BluetoothDevice.cpp +++ /dev/null @@ -1,642 +0,0 @@ -/* - * Author: Petre Eftime - * Copyright (c) 2015 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "orgbluez-dbus.h" -#include "tinyb_utils.hpp" -#include "BluetoothNotificationHandler.hpp" -#include "BluetoothDevice.hpp" -#include "BluetoothGattService.hpp" -#include "BluetoothManager.hpp" -#include "BluetoothException.hpp" - -using namespace tinyb; - -void BluetoothNotificationHandler::on_properties_changed_device(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata) { - - auto c = static_cast(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; - } - auto mfg_callback = c->mfg_callback; - if (mfg_callback != nullptr && g_ascii_strncasecmp(key, "manufacturerdata", 16) == 0) { - std::map> new_value; - - GVariantIter *iter; - g_variant_get (value, "a{qv}", &iter); - - GVariant *array; - uint16_t key; - uint8_t val; - - while (g_variant_iter_loop(iter, "{qv}", &key, &array)) { - GVariantIter it_array; - g_variant_iter_init(&it_array, array); - while(g_variant_iter_loop(&it_array, "y", &val)) { - new_value[key].push_back(val); - } - } - - g_variant_iter_free(iter); - mfg_callback(new_value); - continue; - } - auto service_callback = c->service_callback; - if (service_callback != nullptr && g_ascii_strncasecmp(key, "servicedata", 11) == 0) { - std::map> new_value; - - GVariantIter *iter; - g_variant_get (value, "a{sv}", &iter); - - GVariant *array; - const char* key; - uint8_t val; - - while (g_variant_iter_loop(iter, "{sv}", &key, &array)) { - GVariantIter it_array; - g_variant_iter_init(&it_array, array); - while(g_variant_iter_loop(&it_array, "y", &val)) { - new_value[key].push_back(val); - } - } - - g_variant_iter_free(iter); - service_callback(new_value); - continue; - } - auto services_resolved_callback = c->services_resolved_callback; - if (services_resolved_callback != nullptr && g_ascii_strncasecmp(key, "servicesresolved", 16) == 0) { - bool new_value; - g_variant_get(value, "b", &new_value); - services_resolved_callback(new_value); - continue; - } - } - g_variant_iter_free (iter); - } - - c->unlock(); -} - -std::string BluetoothDevice::get_class_name() const -{ - return std::string("BluetoothDevice"); -} - -std::string BluetoothDevice::get_java_class() const -{ - return std::string(JAVA_DBUS_PACKAGE "/DBusDevice"); -} - -std::string BluetoothDevice::get_object_path() const -{ - return std::string(g_dbus_proxy_get_object_path(G_DBUS_PROXY(object))); -} - -BluetoothType BluetoothDevice::get_bluetooth_type() const -{ - return BluetoothType::DEVICE; -} - -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) -{ - BluetoothDevice(object.object); -} - -BluetoothDevice::~BluetoothDevice() -{ - valid = false; - g_signal_handlers_disconnect_by_data(object, this); - lk.lock(); - - g_object_unref(object); -} - -std::unique_ptr BluetoothDevice::make(Object *object, - BluetoothType type, std::string *name, std::string *identifier, - BluetoothObject *parent) -{ - Device1 *device; - if((type == BluetoothType::NONE || type == BluetoothType::DEVICE) && - (device = object_get_device1(object)) != NULL) { - - std::unique_ptr p(new BluetoothDevice(device)); - g_object_unref(device); - - if ((name == nullptr || *name == p->get_name()) && - (identifier == nullptr || *identifier == p->get_address()) && - (parent == nullptr || *parent == p->get_adapter())) - return p; - } - - return std::unique_ptr(); -} - -BluetoothDevice *BluetoothDevice::clone() const -{ - return new BluetoothDevice(object); -} - -std::vector> BluetoothDevice::get_services() -{ - std::vector> vector; - GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); - - for (l = objects; l != NULL; l = l->next) { - Object *object = OBJECT(l->data); - - auto p = BluetoothGattService::make(object, - BluetoothType::GATT_SERVICE, NULL, NULL, this); - if (p != nullptr) - vector.push_back(std::move(p)); - } - g_list_free_full(objects, g_object_unref); - - return vector; -} - -/* D-Bus method calls: */ -bool BluetoothDevice::disconnect () -{ - GError *error = NULL; - bool result; - result = device1_call_disconnect_sync( - object, - NULL, - &error - ); - handle_error(error); - return result; -} - -void BluetoothDevice::connect_async_start () -{ - device1_call_connect ( - object, // Device1 *proxy, - NULL, // GCancellable *cancellable, - NULL, // GAsyncReadyCallback callback, - NULL // gpointer user_data) - ); -} - -bool BluetoothDevice::connect_async_finish () -{ - GError *error = NULL; - bool result; - result = device1_call_connect_finish ( - object, // Device1 *proxy, - NULL, // GAsyncResult *res, - &error // GError **error) - ); - handle_error(error); - return result; -} - -bool BluetoothDevice::connect () -{ - GError *error = NULL; - bool result; - result = device1_call_connect_sync( - object, - NULL, - &error - ); - handle_error(error); - return result; -} - -bool BluetoothDevice::connect_profile ( - const std::string &arg_UUID) -{ - GError *error = NULL; - bool result; - result = device1_call_connect_profile_sync( - object, - arg_UUID.c_str(), - NULL, - &error - ); - handle_error(error); - return result; -} - -bool BluetoothDevice::disconnect_profile ( - const std::string &arg_UUID) -{ - GError *error = NULL; - bool result; - result = device1_call_disconnect_profile_sync( - object, - arg_UUID.c_str(), - NULL, - &error - ); - handle_error(error); - return result; -} - -bool BluetoothDevice::pair () -{ - GError *error = NULL; - bool result; - result = device1_call_pair_sync( - object, - NULL, - &error - ); - handle_error(error); - return result; -} - -// Remove the device (like an unpair) -bool BluetoothDevice::remove_device(){ - BluetoothAdapter ba = get_adapter(); - return ba.remove_device(get_object_path()); -} - -bool BluetoothDevice::cancel_pairing () -{ - GError *error = NULL; - bool result; - result = device1_call_cancel_pairing_sync( - object, - NULL, - &error - ); - handle_error(error); - return result; -} - - - -/* D-Bus property accessors: */ -std::string BluetoothDevice::get_address () -{ - return std::string(device1_get_address (object)); -} - -std::string BluetoothDevice::get_name () -{ - const gchar *name = device1_get_name(object); - if (name == nullptr) - return std::string(device1_get_alias(object)); - return std::string(name); -} - -std::string BluetoothDevice::get_alias () -{ - return device1_get_alias (object); -} - -void BluetoothDevice::set_alias (const std::string &value) -{ - device1_set_alias (object, value.c_str()); -} - -unsigned int BluetoothDevice::get_class () -{ - return device1_get_class (object); -} - -uint16_t BluetoothDevice::get_appearance () -{ - return device1_get_appearance (object); -} - -std::unique_ptr BluetoothDevice::get_icon () -{ - const gchar *icon = device1_get_icon (object); - if (icon == nullptr) - return std::unique_ptr(); - return std::unique_ptr(new std::string(icon)); -} - -bool BluetoothDevice::get_paired () -{ - return device1_get_paired (object); -} - -void BluetoothDevice::enable_paired_notifications( - std::function callback, - void *userdata) { - paired_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothDevice::enable_paired_notifications( - std::function callback) { - paired_callback = callback; -} -void BluetoothDevice::disable_paired_notifications() { - paired_callback = nullptr; -} - -bool BluetoothDevice::get_trusted () -{ - return device1_get_trusted (object); -} - -void BluetoothDevice::set_trusted (bool value) -{ - device1_set_trusted (object, value); -} - -void BluetoothDevice::enable_trusted_notifications( - std::function callback, - void *userdata) { - trusted_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothDevice::enable_trusted_notifications( - std::function callback) { - trusted_callback = callback; -} -void BluetoothDevice::disable_trusted_notifications() { - trusted_callback = nullptr; -} - -bool BluetoothDevice::get_blocked () -{ - return device1_get_blocked (object); -} - -void BluetoothDevice::set_blocked (bool value) -{ - device1_set_blocked (object, value); -} - -void BluetoothDevice::enable_blocked_notifications( - std::function callback, - void *userdata) { - blocked_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothDevice::enable_blocked_notifications( - std::function callback) { - blocked_callback = callback; -} -void BluetoothDevice::disable_blocked_notifications() { - blocked_callback = nullptr; -} - -bool BluetoothDevice::get_legacy_pairing () -{ - return device1_get_legacy_pairing (object); -} - -int16_t BluetoothDevice::get_rssi () -{ - return device1_get_rssi (object); -} - -void BluetoothDevice::enable_rssi_notifications( - std::function callback, - void *userdata) { - rssi_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothDevice::enable_rssi_notifications( - std::function 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 callback, - void *userdata) { - connected_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothDevice::enable_connected_notifications( - std::function callback) { - connected_callback = callback; -} -void BluetoothDevice::disable_connected_notifications() { - connected_callback = nullptr; -} - -std::vector BluetoothDevice::get_uuids () -{ - - const char * const *uuids_c = device1_get_uuids (object); - std::vector uuids; - for (int i = 0; uuids_c[i] != NULL ;i++) - uuids.push_back(std::string(uuids_c[i])); - return uuids; -} - -std::unique_ptr BluetoothDevice::get_modalias () -{ - const gchar *modalias= device1_get_modalias (object); - if (modalias == nullptr) - return std::unique_ptr(); - return std::unique_ptr(new std::string(modalias)); -} - -BluetoothAdapter BluetoothDevice::get_adapter () -{ - GError *error = NULL; - - Adapter1 *adapter = adapter1_proxy_new_for_bus_sync( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.bluez", - device1_get_adapter (object), - NULL, - &error); - - if (adapter == NULL) { - std::string error_msg("Error occured while instantiating adapter: "); - error_msg += error->message; - g_error_free(error); - throw BluetoothException(error_msg); - } - - auto res = BluetoothAdapter(adapter); - g_object_unref(adapter); - return res; -} - -std::map> BluetoothDevice::get_manufacturer_data() -{ - std::map> m_data; - GVariant *v = device1_dup_manufacturer_data (object); - - if (v == nullptr) - return m_data; - - GVariantIter *iter; - g_variant_get (v, "a{qv}", &iter); - - GVariant *array; - uint16_t key; - uint8_t val; - - while (g_variant_iter_loop(iter, "{qv}", &key, &array)) { - - GVariantIter it_array; - g_variant_iter_init(&it_array, array); - while(g_variant_iter_loop(&it_array, "y", &val)) { - m_data[key].push_back(val); - } - } - - g_variant_iter_free(iter); - g_variant_unref(v); - - return m_data; -} - -void BluetoothDevice::enable_manufacturer_data_notifications( - std::function> &, void *)> callback, - void *userdata) { - mfg_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothDevice::enable_manufacturer_data_notifications( - std::function> &)> callback) { - mfg_callback = callback; -} -void BluetoothDevice::disable_manufacturer_data_notifications() { - mfg_callback = nullptr; -} - -std::map> BluetoothDevice::get_service_data() -{ - std::map> m_data; - GVariant *v = device1_dup_service_data (object); - - if (v == nullptr) - return m_data; - - GVariantIter *iter; - g_variant_get (v, "a{sv}", &iter); - - GVariant *array; - const char* key; - uint8_t val; - - while (g_variant_iter_loop(iter, "{sv}", &key, &array)) { - - GVariantIter it_array; - g_variant_iter_init(&it_array, array); - while(g_variant_iter_loop(&it_array, "y", &val)) { - m_data[key].push_back(val); - } - } - - g_variant_iter_free(iter); - g_variant_unref(v); - - return m_data; -} - -void BluetoothDevice::enable_service_data_notifications( - std::function> &, void *)> callback, - void *userdata) { - service_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothDevice::enable_service_data_notifications( - std::function> &)> callback) { - service_callback = callback; -} -void BluetoothDevice::disable_service_data_notifications() { - service_callback = nullptr; -} - -int16_t BluetoothDevice::get_tx_power () -{ - return device1_get_tx_power (object); -} - -bool BluetoothDevice::get_services_resolved () -{ - return device1_get_services_resolved (object); -} - -void BluetoothDevice::enable_services_resolved_notifications( - std::function callback, - void *userdata) { - services_resolved_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); -} -void BluetoothDevice::enable_services_resolved_notifications( - std::function callback) { - services_resolved_callback = callback; -} -void BluetoothDevice::disable_services_resolved_notifications() { - services_resolved_callback = nullptr; -} - diff --git a/src/BluetoothEvent.cpp b/src/BluetoothEvent.cpp deleted file mode 100644 index 10558edb..00000000 --- a/src/BluetoothEvent.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Author: Petre Eftime - * Copyright (c) 2016 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "orgbluez-dbus.h" -#include "BluetoothEvent.hpp" -#include "BluetoothManager.hpp" - -void BluetoothEvent::generic_callback(BluetoothObject &object, void *data) -{ - - if (data == nullptr) - return; - - BluetoothConditionVariable *generic_data = static_cast(data); - - generic_data->result = object.clone(); - generic_data->notify(); -} - -BluetoothEvent::BluetoothEvent(BluetoothType type, std::string *name, - std::string *identifier, BluetoothObject *parent, bool execute_once, - BluetoothCallback cb, void *data) -{ - canceled = false; - this->type = type; - if (name != nullptr) - this->name = new std::string(*name); - else - this->name = nullptr; - - if (identifier != nullptr) - this->identifier = new std::string(*identifier); - else - this->identifier = nullptr; - - if (parent != nullptr) - this->parent = parent->clone(); - else - this->parent = nullptr; - - this->execute_once = execute_once; - - if (cb == nullptr) { - this->data = static_cast(&cv); - this->cb = generic_callback; - } - else { - this->cb = cb; - this->data = data; - } -} - -bool BluetoothEvent::execute_callback(BluetoothObject &object) -{ - if (has_callback()) { - cb(object, data); - cv.notify(); - return execute_once; - } - - return true; -} - -void BluetoothEvent::wait(std::chrono::milliseconds timeout) -{ - if (!canceled && execute_once == true) { - if (timeout == std::chrono::milliseconds::zero()) - cv.wait(); - else - cv.wait_for(timeout); - } -} - -void BluetoothEvent::cancel() -{ - BluetoothManager *manager = BluetoothManager::get_bluetooth_manager(); - manager->remove_event(*this); - - cv.notify(); -} - -BluetoothEvent::~BluetoothEvent() -{ - if (name != nullptr) - delete name; - if (identifier != nullptr) - delete identifier; - if (parent != nullptr) - delete parent; -} diff --git a/src/BluetoothGattCharacteristic.cpp b/src/BluetoothGattCharacteristic.cpp deleted file mode 100644 index 30914e9e..00000000 --- a/src/BluetoothGattCharacteristic.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Author: Petre Eftime - * Copyright (c) 2015 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "orgbluez-dbus.h" -#include "tinyb_utils.hpp" -#include "BluetoothNotificationHandler.hpp" -#include "BluetoothGattCharacteristic.hpp" -#include "BluetoothGattService.hpp" -#include "BluetoothGattDescriptor.hpp" -#include "BluetoothException.hpp" - -using namespace tinyb; - -void BluetoothNotificationHandler::on_properties_changed_characteristic(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata) { - - auto c = static_cast(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 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"); -} - -std::string BluetoothGattCharacteristic::get_java_class() const -{ - return std::string(JAVA_DBUS_PACKAGE "/DBusGattCharacteristic"); -} - -std::string BluetoothGattCharacteristic::get_object_path() const -{ - return std::string(g_dbus_proxy_get_object_path(G_DBUS_PROXY(object))); -} - -BluetoothType BluetoothGattCharacteristic::get_bluetooth_type() const -{ - return BluetoothType::GATT_CHARACTERISTIC; -} - -BluetoothGattCharacteristic::BluetoothGattCharacteristic(GattCharacteristic1 *object) -{ - 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); -} - -BluetoothGattCharacteristic *BluetoothGattCharacteristic::clone() const -{ - return new BluetoothGattCharacteristic(object); -} - -std::unique_ptr BluetoothGattCharacteristic::make( - Object *object, BluetoothType type, std::string *name, - std::string *identifier, BluetoothObject *parent) -{ - GattCharacteristic1 *characteristic; - if((type == BluetoothType::NONE || type == BluetoothType::GATT_CHARACTERISTIC) && - (characteristic = object_get_gatt_characteristic1(object)) != NULL) { - - std::unique_ptr p( - new BluetoothGattCharacteristic(characteristic)); - g_object_unref(characteristic); - - if ((name == nullptr) && - (identifier == nullptr || *identifier == p->get_uuid()) && - (parent == nullptr || *parent == p->get_service())) - return p; - } - - return std::unique_ptr(); -} - -/* D-Bus method calls: */ -std::vector BluetoothGattCharacteristic::read_value (uint16_t offset) -{ - GError *error = NULL; - GVariant *result_variant; - - GVariantDict dict; - g_variant_dict_init(&dict, NULL); - - if (offset != 0) - g_variant_dict_insert_value(&dict, "offset", g_variant_new_uint16(offset)); - - GVariant *variant = g_variant_dict_end(&dict); - - gatt_characteristic1_call_read_value_sync( - object, - variant, - &result_variant, - NULL, - &error - ); - - handle_error(error); - - GBytes *result_gbytes = g_variant_get_data_as_bytes(result_variant); - std::vector result = from_gbytes_to_vector(result_gbytes); - - /* free the gbytes array */ - g_bytes_unref(result_gbytes); - - return result; -} - -bool BluetoothGattCharacteristic::write_value ( - const std::vector &arg_value, uint16_t offset) -{ - GError *error = NULL; - bool result = true; - - gboolean trusted = true; - GBytes *arg_value_gbytes = from_vector_to_gbytes(arg_value); - GVariant *value = g_variant_new_from_bytes( - G_VARIANT_TYPE_BYTESTRING, arg_value_gbytes, trusted); - - GVariantDict dict; - g_variant_dict_init(&dict, NULL); - - if (offset != 0) - g_variant_dict_insert_value(&dict, "offset", g_variant_new_uint16(offset)); - - GVariant *variant = g_variant_dict_end(&dict); - - result = gatt_characteristic1_call_write_value_sync( - object, - value, - variant, - NULL, - &error - ); - - /* freeing the GBytes allocated inside from_vector_to_gbytes function */ - g_bytes_unref(arg_value_gbytes); - - handle_error(error); - - return result; -} - -bool BluetoothGattCharacteristic::enable_value_notifications( - std::function &,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 &)> 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; - bool result; - result = gatt_characteristic1_call_start_notify_sync( - object, - NULL, - &error - ); - - handle_error(error); - return result; -} - -bool BluetoothGattCharacteristic::stop_notify () -{ - GError *error = NULL; - bool result; - result = gatt_characteristic1_call_stop_notify_sync( - object, - NULL, - &error - ); - handle_error(error); - return result; -} - -/* D-Bus property accessors: */ -std::string BluetoothGattCharacteristic::get_uuid () -{ - return std::string(gatt_characteristic1_get_uuid (object)); -} - -BluetoothGattService BluetoothGattCharacteristic::get_service () -{ - GError *error = NULL; - - GattService1 *service = gatt_service1_proxy_new_for_bus_sync( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.bluez", - gatt_characteristic1_get_service (object), - NULL, - &error); - - if (service == nullptr) { - std::string error_msg("Error occured while instantiating service: "); - error_msg += error->message; - g_error_free(error); - throw BluetoothException(error_msg); - } - - auto res = BluetoothGattService(service); - g_object_unref(service); - return res; -} - -std::vector BluetoothGattCharacteristic::get_value () -{ - GVariant *value_variant = gatt_characteristic1_get_value (object); - GBytes *value_gbytes = g_variant_get_data_as_bytes(value_variant); - std::vector result; - - try { - result = from_gbytes_to_vector(value_gbytes); - } catch (std::exception &e) { - g_bytes_unref(value_gbytes); - throw e; - } - - g_bytes_unref(value_gbytes); - - return result; -} - -bool BluetoothGattCharacteristic::get_notifying () -{ - return gatt_characteristic1_get_notifying (object); -} - -std::vector BluetoothGattCharacteristic::get_flags () -{ - const char * const *flags_c = gatt_characteristic1_get_flags (object); - std::vector flags; - for (int i = 0; flags_c[i] != NULL ;i++) - flags.push_back(std::string(flags_c[i])); - return flags; - -} - -std::vector> BluetoothGattCharacteristic::get_descriptors () -{ - std::vector> vector; - GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); - - for (l = objects; l != NULL; l = l->next) { - Object *object = OBJECT(l->data); - - auto p = BluetoothGattDescriptor::make(object, - BluetoothType::GATT_DESCRIPTOR, NULL, NULL, this); - if (p != nullptr) - vector.push_back(std::move(p)); - } - g_list_free_full(objects, g_object_unref); - - return vector; -} - - diff --git a/src/BluetoothGattDescriptor.cpp b/src/BluetoothGattDescriptor.cpp deleted file mode 100644 index 72acdd37..00000000 --- a/src/BluetoothGattDescriptor.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Author: Petre Eftime - * Copyright (c) 2015 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "orgbluez-dbus.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(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 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"); -} - -std::string BluetoothGattDescriptor::get_java_class() const -{ - return std::string(JAVA_DBUS_PACKAGE "/DBusGattDescriptor"); -} - -std::string BluetoothGattDescriptor::get_object_path() const -{ - return std::string(g_dbus_proxy_get_object_path(G_DBUS_PROXY(object))); -} - -BluetoothType BluetoothGattDescriptor::get_bluetooth_type() const -{ - return BluetoothType::GATT_DESCRIPTOR; -} - -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) -{ - BluetoothGattDescriptor(object.object); -} - -BluetoothGattDescriptor::~BluetoothGattDescriptor() -{ - valid = false; - g_signal_handlers_disconnect_by_data(object, this); - lk.lock(); - - g_object_unref(object); -} - -std::unique_ptr BluetoothGattDescriptor::make( - Object *object, BluetoothType type, std::string *name, - std::string *identifier, BluetoothObject *parent) -{ - GattDescriptor1 *descriptor; - if((type == BluetoothType::NONE || type == BluetoothType::GATT_DESCRIPTOR) && - (descriptor = object_get_gatt_descriptor1(object)) != NULL) { - - std::unique_ptr p( - new BluetoothGattDescriptor(descriptor)); - g_object_unref(descriptor); - - if ((name == nullptr) && - (identifier == nullptr || *identifier == p->get_uuid()) && - (parent == nullptr || *parent == p->get_characteristic())) - return p; - } - - return std::unique_ptr(); -} - - - -BluetoothGattDescriptor *BluetoothGattDescriptor::clone() const -{ - return new BluetoothGattDescriptor(object); -} - -/* D-Bus method calls: */ -std::vector BluetoothGattDescriptor::read_value (uint16_t offset) -{ - GError *error = NULL; - gchar *result_chars; - - GVariantDict dict; - g_variant_dict_init(&dict, NULL); - - if (offset != 0) - g_variant_dict_insert_value(&dict, "offset", g_variant_new_uint16(offset)); - - GVariant *variant = g_variant_dict_end(&dict); - - gatt_descriptor1_call_read_value_sync( - object, - variant, - &result_chars, - NULL, - &error - ); - handle_error(error); - - std::vector result = from_chars_to_vector(result_chars); - - g_free(result_chars); - - return result; -} - -bool BluetoothGattDescriptor::write_value ( - const std::vector &arg_value, uint16_t offset) -{ - GError *error = NULL; - bool result; - - gchar *arg_value_chars = const_cast(reinterpret_cast(arg_value.data())); - - GVariantDict dict; - g_variant_dict_init(&dict, NULL); - - if (offset != 0) - g_variant_dict_insert_value(&dict, "offset", g_variant_new_uint16(offset)); - - GVariant *variant = g_variant_dict_end(&dict); - - result = gatt_descriptor1_call_write_value_sync( - object, - arg_value_chars, - variant, - NULL, - &error - ); - handle_error(error); - - return result; -} - -bool BluetoothGattDescriptor::enable_value_notifications( - std::function &,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 &)> 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 () -{ - return std::string(gatt_descriptor1_get_uuid (object)); -} - -BluetoothGattCharacteristic BluetoothGattDescriptor::get_characteristic () -{ - GError *error = NULL; - - GattCharacteristic1* characteristic = gatt_characteristic1_proxy_new_for_bus_sync( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.bluez", - gatt_descriptor1_get_characteristic (object), - NULL, - &error); - - if (characteristic == NULL) { - std::string error_msg("Error occured while instantiating characteristic: "); - error_msg += error->message; - g_error_free(error); - throw BluetoothException(error_msg); - } - - auto res = BluetoothGattCharacteristic(characteristic); - g_object_unref(characteristic); - return res; -} - -std::vector BluetoothGattDescriptor::get_value () -{ - gchar *value_chars = const_cast(gatt_descriptor1_get_value (object)); - std::vector result; - - result = from_chars_to_vector(value_chars); - - return result; -} diff --git a/src/BluetoothGattService.cpp b/src/BluetoothGattService.cpp deleted file mode 100644 index d63893eb..00000000 --- a/src/BluetoothGattService.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Author: Petre Eftime - * Copyright (c) 2015 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "orgbluez-dbus.h" -#include "tinyb_utils.hpp" -#include "BluetoothGattService.hpp" -#include "BluetoothGattCharacteristic.hpp" -#include "BluetoothDevice.hpp" -#include "BluetoothException.hpp" - -using namespace tinyb; - -std::string BluetoothGattService::get_class_name() const -{ - return std::string("BluetoothGattService"); -} - -std::string BluetoothGattService::get_java_class() const -{ - return std::string(JAVA_DBUS_PACKAGE "/DBusGattService"); -} - -std::string BluetoothGattService::get_object_path() const -{ - return std::string(g_dbus_proxy_get_object_path(G_DBUS_PROXY(object))); -} - -BluetoothType BluetoothGattService::get_bluetooth_type() const -{ - return BluetoothType::GATT_SERVICE; -} - -BluetoothGattService::BluetoothGattService(GattService1 *object) -{ - this->object = object; - g_object_ref(object); -} - -BluetoothGattService::BluetoothGattService(const BluetoothGattService &object) -{ - BluetoothGattService(object.object); -} - -BluetoothGattService::~BluetoothGattService() -{ - g_object_unref(object); -} - -std::unique_ptr BluetoothGattService::make( - Object *object, BluetoothType type, std::string *name, - std::string *identifier, BluetoothObject *parent) -{ - GattService1 *service; - if((type == BluetoothType::NONE || type == BluetoothType::GATT_SERVICE) && - (service = object_get_gatt_service1(object)) != NULL) { - - std::unique_ptr p( - new BluetoothGattService(service)); - g_object_unref(service); - - if ((name == nullptr) && - (identifier == nullptr || *identifier == p->get_uuid()) && - (parent == nullptr || *parent == p->get_device())) - return p; - } - - return std::unique_ptr(); -} - -BluetoothGattService *BluetoothGattService::clone() const -{ - return new BluetoothGattService(object); -} - -/* D-Bus property accessors: */ -std::string BluetoothGattService::get_uuid () -{ - return std::string(gatt_service1_get_uuid (object)); -} - -BluetoothDevice BluetoothGattService::get_device () -{ - GError *error = NULL; - - Device1 *device = device1_proxy_new_for_bus_sync( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.bluez", - gatt_service1_get_device (object), - NULL, - &error); - - if (device == nullptr) { - std::string error_msg("Error occured while instantiating device: "); - error_msg += error->message; - g_error_free(error); - throw BluetoothException(error_msg); - } - - auto res = BluetoothDevice(device); - g_object_unref(device); - return res; -} - -bool BluetoothGattService::get_primary () -{ - return gatt_service1_get_primary (object); -} - -std::vector> BluetoothGattService::get_characteristics () -{ - std::vector> vector; - GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); - - for (l = objects; l != NULL; l = l->next) { - Object *object = OBJECT(l->data); - - auto p = BluetoothGattCharacteristic::make(object, - BluetoothType::GATT_CHARACTERISTIC, NULL, NULL, this); - if (p != nullptr) - vector.push_back(std::move(p)); - } - g_list_free_full(objects, g_object_unref); - - return vector; -} - diff --git a/src/BluetoothManager.cpp b/src/BluetoothManager.cpp deleted file mode 100644 index b6868d09..00000000 --- a/src/BluetoothManager.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Author: Petre Eftime - * Copyright (c) 2015 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "orgbluez-dbus.h" -#include "BluetoothManager.hpp" -#include "BluetoothAdapter.hpp" -#include "BluetoothDevice.hpp" -#include "BluetoothGattService.hpp" -#include "BluetoothGattCharacteristic.hpp" -#include "BluetoothGattDescriptor.hpp" -#include "BluetoothEvent.hpp" -#include "BluetoothException.hpp" -#include "version.h" - -#include - -using namespace tinyb; - -class tinyb::BluetoothEventManager { -public: - static void on_interface_added (GDBusObject *object, - GDBusInterface *interface, gpointer user_data) { - GDBusInterfaceInfo *info = g_dbus_interface_get_info(interface); - BluetoothType type = BluetoothType::NONE; - BluetoothManager *manager = BluetoothManager::get_bluetooth_manager(); - - /* Unknown interface, ignore */ - if (info == NULL) - return; - - if(IS_GATT_SERVICE1_PROXY(interface)) { - type = BluetoothType::GATT_SERVICE; - auto obj = new BluetoothGattService(GATT_SERVICE1(interface)); - auto uuid = obj->get_uuid(); - auto parent = obj->get_device(); - manager->handle_event(type, nullptr, &uuid, &parent, *obj); - } - else if(IS_GATT_CHARACTERISTIC1_PROXY(interface)) { - type = BluetoothType::GATT_CHARACTERISTIC; - auto obj = new BluetoothGattCharacteristic(GATT_CHARACTERISTIC1(interface)); - auto uuid = obj->get_uuid(); - auto parent = obj->get_service(); - manager->handle_event(type, nullptr, &uuid, &parent, *obj); - } - else if(IS_GATT_DESCRIPTOR1_PROXY(interface)) { - type = BluetoothType::GATT_DESCRIPTOR; - auto obj = new BluetoothGattDescriptor(GATT_DESCRIPTOR1(interface)); - auto uuid = obj->get_uuid(); - auto parent = obj->get_characteristic(); - manager->handle_event(type, nullptr, &uuid, &parent, *obj); - } - else if(IS_DEVICE1_PROXY(interface)) { - type = BluetoothType::DEVICE; - auto obj = new BluetoothDevice(DEVICE1(interface)); - auto name = obj->get_name(); - auto uuid = obj->get_address(); - auto parent = obj->get_adapter(); - manager->handle_event(type, &name, &uuid, &parent, *obj); - } - else if(IS_ADAPTER1_PROXY(interface)) { - type = BluetoothType::ADAPTER; - auto obj = new BluetoothAdapter(ADAPTER1(interface)); - auto name = obj->get_name(); - auto uuid = obj->get_address(); - manager->handle_event(type, &name, &uuid, nullptr, *obj); - } - } - - static void on_object_added (GDBusObjectManager *manager, - GDBusObject *object, gpointer user_data) { - GList *l, *interfaces = g_dbus_object_get_interfaces(object); - - for(l = interfaces; l != NULL; l = l->next) - on_interface_added(object, (GDBusInterface *)l->data, user_data); - - g_list_free_full(interfaces, g_object_unref); - } -}; - -GDBusObjectManager *gdbus_manager = NULL; -GMainContext *manager_context = NULL; -GThread *manager_thread = NULL; - -std::string BluetoothManager::get_class_name() const -{ - return std::string("BluetoothManager"); -} - -std::string BluetoothManager::get_java_class() const -{ - return std::string(JAVA_DBUS_PACKAGE "/DBusManager"); -} - -std::string BluetoothManager::get_object_path() const -{ - return std::string("/"); -} - -BluetoothType BluetoothManager::get_bluetooth_type() const -{ - return BluetoothType::NONE; -} - -std::string BluetoothManager::get_api_version() { - return std::string(gVERSION_API); -} - -std::string BluetoothManager::get_library_version() { - return std::string(gVERSION_SHORT); -} - -std::unique_ptr BluetoothManager::get_object( - BluetoothType type, std::string *name, std::string *identifier, - BluetoothObject *parent) -{ - auto list = get_objects(type, name, identifier, parent); - if (list.empty()) - return std::unique_ptr(); - return std::move(list.front()); -} - -std::vector> BluetoothManager::get_objects( - BluetoothType type, std::string *name, std::string *identifier, - BluetoothObject *parent) -{ - std::vector> vector; - GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); - - for (l = objects; l != NULL; l = l->next) { - Object *object = OBJECT(l->data); - - auto p_service = BluetoothGattService::make(object, type, name, identifier, parent); - if (p_service != nullptr) - vector.push_back(std::move(p_service)); - - auto p_characteristic = BluetoothGattCharacteristic::make(object, type, name, identifier, parent); - if (p_characteristic != nullptr) - vector.push_back(std::move(p_characteristic)); - - auto p_descriptor = BluetoothGattDescriptor::make(object, type, name, identifier, parent); - if (p_descriptor != nullptr) - vector.push_back(std::move(p_descriptor)); - - auto p_device = BluetoothDevice::make(object, type, name, identifier, parent); - if (p_device != nullptr) - vector.push_back(std::move(p_device)); - - auto p_adapter = BluetoothAdapter::make(object, type, name, identifier, parent); - if (p_adapter != nullptr) - vector.push_back(std::move(p_adapter)); - } - g_list_free_full(objects, g_object_unref); - return vector; -} - -std::unique_ptr BluetoothManager::find(BluetoothType type, - std::string *name, std::string* identifier, BluetoothObject *parent, - std::chrono::milliseconds timeout) -{ - std::shared_ptr event(new BluetoothEvent(type, name, - identifier, parent)); - add_event(event); - - auto object = get_object(type, name, identifier, parent); - - if (object == nullptr) { - event->wait(timeout); - object = std::unique_ptr(event->get_result()); - } - - event->cancel(); - return object; -} - -std::weak_ptr BluetoothManager::find(BluetoothType type, - std::string *name, std::string* identifier, BluetoothObject *parent, - BluetoothCallback cb, bool execute_once, - std::chrono::milliseconds timeout) -{ - std::shared_ptr event(new BluetoothEvent(type, name, - identifier, parent)); - add_event(event); - return std::weak_ptr(event); -} - -void BluetoothManager::handle_event(BluetoothType type, std::string *name, - std::string *identifier, BluetoothObject *parent, BluetoothObject &object) -{ - for (auto it = event_list.begin(); - it != event_list.end();) { - if ((*it)->get_type() != BluetoothType::NONE && ((*it)->get_type()) != type) { - ++it; - continue; /* this event does not match */ - } - if ((*it)->get_name() != NULL) - if (name == NULL || *((*it)->get_name()) != *name) { - ++it; - continue; /* this event does not match */ - } - if ((*it)->get_identifier() != NULL) - if (identifier == NULL || *((*it)->get_identifier()) != *identifier) { - ++it; - continue; /* this event does not match */ - } - if ((*it)->get_parent() != NULL) - if (parent == NULL || *((*it)->get_parent()) != *parent) { - ++it; - continue; /* this event does not match */ - } - /* The event matches, execute and see if it needs to reexecute */ - if ((*it)->execute_callback(object)) - it = event_list.erase(it); - else - ++it; - } -} - -static gpointer init_manager_thread(void *data) -{ - GMainLoop *loop; - GDBusObjectManager *gdbus_manager = (GDBusObjectManager *) data; - - g_main_context_push_thread_default(manager_context); - - loop = g_main_loop_new(manager_context, FALSE); - - g_signal_connect(gdbus_manager, - "interface-added", - G_CALLBACK(BluetoothEventManager::on_interface_added), - NULL); - - g_signal_connect(gdbus_manager, - "object-added", - G_CALLBACK(BluetoothEventManager::on_object_added), - NULL); - - g_main_context_pop_thread_default(manager_context); - - g_main_loop_run(loop); - - return NULL; -} - -BluetoothManager::BluetoothManager() : event_list() -{ - GError *error = NULL; - GList *objects, *l; - - manager_context = g_main_context_new (); - g_main_context_push_thread_default(manager_context); - - gdbus_manager = object_manager_client_new_for_bus_sync( - G_BUS_TYPE_SYSTEM, - G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, - "org.bluez", - "/", - NULL, /* GCancellable */ - &error); - - if (gdbus_manager == nullptr) { - std::string error_str("Error getting object manager client: "); - error_str += error->message; - g_error_free(error); - throw std::runtime_error(error_str); - } - - g_main_context_pop_thread_default(manager_context); - - manager_thread = g_thread_new("BluetoothManager-Thread", init_manager_thread, gdbus_manager); - - objects = g_dbus_object_manager_get_objects(gdbus_manager); - - default_adapter = nullptr; - for (l = objects; l != NULL; l = l->next) { - Object *object = (Object *) l->data; - Adapter1 *adapter = object_get_adapter1(object); - if (adapter != NULL) { - default_adapter = std::unique_ptr(new BluetoothAdapter(adapter)); - g_object_unref(adapter); - break; - } - } - g_list_free_full(objects, g_object_unref); - - if (default_adapter == nullptr) { - throw BluetoothException("No adapter installed or not recognized by system"); - } -} - -BluetoothManager *BluetoothManager::get_bluetooth_manager() -{ - static BluetoothManager bluetooth_manager; - return &bluetooth_manager; -} - -BluetoothManager::BluetoothManager(const BluetoothManager &) -{ - /* Should not be called */ -} - -BluetoothManager::~BluetoothManager() -{ - /* Should not be called */ -} - -std::vector> BluetoothManager::get_adapters() -{ - std::vector> vector; - GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); - - for (l = objects; l != NULL; l = l->next) { - Object *object = OBJECT(l->data); - - auto p = BluetoothAdapter::make(object); - if (p != nullptr) - vector.push_back(std::move(p)); - } - g_list_free_full(objects, g_object_unref); - - return vector; -} - -std::vector> BluetoothManager::get_devices() -{ - std::vector> vector; - GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); - - for (l = objects; l != NULL; l = l->next) { - Object *object = OBJECT(l->data); - - auto p = BluetoothDevice::make(object); - if (p != nullptr) - vector.push_back(std::move(p)); - } - g_list_free_full(objects, g_object_unref); - - return vector; -} - -std::vector> BluetoothManager::get_services() -{ - std::vector> vector; - GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); - - for (l = objects; l != NULL; l = l->next) { - Object *object = OBJECT(l->data); - - auto p = BluetoothGattService::make(object); - if (p != nullptr) - vector.push_back(std::move(p)); - } - g_list_free_full(objects, g_object_unref); - - return vector; -} - -bool BluetoothManager::set_default_adapter(BluetoothAdapter &adapter) -{ - default_adapter = std::unique_ptr(adapter.clone()); - return true; -} - -std::unique_ptr BluetoothManager::get_default_adapter() -{ - return std::unique_ptr(default_adapter->clone()); -} - -bool BluetoothManager::start_discovery() -{ - if (default_adapter != nullptr) - return default_adapter->start_discovery(); - else - return false; -} - -bool BluetoothManager::stop_discovery() -{ - if (default_adapter != NULL) - return default_adapter->stop_discovery(); - else - return false; -} - -bool BluetoothManager::get_discovering() -{ - if (default_adapter != NULL) - return default_adapter->get_discovering(); - else - return false; -} diff --git a/src/BluetoothObject.cpp b/src/BluetoothObject.cpp deleted file mode 100644 index 2e8ddaf4..00000000 --- a/src/BluetoothObject.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Author: Petre Eftime - * Copyright (c) 2015 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "BluetoothObject.hpp" -#include - -using namespace tinyb; - -std::string BluetoothObject::get_java_class() const -{ - return std::string(JAVA_DBUS_PACKAGE "/DBusObject"); -} - -std::string BluetoothObject::get_class_name() const -{ - return std::string("BluetoothObject"); -} - -std::string BluetoothObject::get_object_path() const -{ - return std::string(); -} - -BluetoothType BluetoothObject::get_bluetooth_type() const -{ - return BluetoothType::NONE; -} - -BluetoothObject *BluetoothObject::clone() const -{ - return NULL; -} - -bool BluetoothObject::operator==(const BluetoothObject &other) const -{ - return (this->get_bluetooth_type() == other.get_bluetooth_type()) - && (this->get_object_path() == other.get_object_path()); -} - -bool BluetoothObject::operator!=(const BluetoothObject &other) const -{ - return !(*this == other); -} diff --git a/src/BluetoothUUID.cpp b/src/BluetoothUUID.cpp deleted file mode 100644 index ce8124a5..00000000 --- a/src/BluetoothUUID.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "BluetoothUUID.hpp" -#include -#include - -using namespace tinyb; - -BluetoothUUID::BluetoothUUID(const BluetoothUUID &other) { - uuid[0] = other.uuid[0]; - uuid[1] = other.uuid[1]; -} - -BluetoothUUID::BluetoothUUID(const char str[]) { - int len = strlen(str); - const char *err_msg = "UUID does not have a valid format"; - - if (len == 4 || len == 8) { - /* 16bit or 32bit UUID: number + base UUID */ - uuid[0] = strtoul(str, NULL, 16) << 32 | 0x00001000ULL; - uuid[1] = 0x800000805f9b34fbULL; - } else if (len == 36) { - /* 128bit UUID */ - char u[37]; - strcpy(u, str); - - if (u[8] == '-') { - u[8] = ' '; - uuid[0] = strtoul(u + 0, NULL, 16) << 32; - } else { - throw std::invalid_argument(err_msg); - } - if (u[13] == '-') { - u[13] = ' '; - uuid[0] = uuid[0] | strtoul(u + 9, NULL, 16) << 16; - } else throw std::invalid_argument(err_msg); - if (u[18] == '-') { - u[18] = ' '; - uuid[0] = uuid[0] | strtoul(u + 14, NULL, 16); - } else throw std::invalid_argument(err_msg); - - if (u[23] == '-') { - u[23] = ' '; - uuid[1] = strtoul(u + 19, NULL, 16) << 48; - } else throw std::invalid_argument(err_msg); - - uuid[1] = uuid[1] | strtoul(u + 24, NULL, 16); - } else throw std::invalid_argument(err_msg); -} - -BluetoothUUID::BluetoothUUID(const std::string &str) : BluetoothUUID(str.c_str()) {} - -std::string BluetoothUUID::get_string() -{ - char u[37]; - snprintf(u, 37, "%08lx-%04llx-%04llx-%04lx-%012llx", - (uuid[0] >> 32), - ((uuid[0] >> 16) & 0xFFFFULL), - (uuid[0] & 0xFFFFULL), - (uuid[1] >> 48), - (uuid[1] & ~(0xFFFFULL << 48))); - return std::string(u); -} - -std::string BluetoothUUID::get_short_string() -{ - char u[9]; - if (is_short()) { - uint32_t suuid = get_short(); - if (suuid & 0xFFFF == suuid) - snprintf(u, 9, "%04dx", suuid); - else - snprintf(u, 9, "%08dx", suuid); - return std::string(u); - } else { - return get_string(); - } -} - -uint32_t BluetoothUUID::get_short() { - if (is_short()) - return uuid[0] >> 32; - return 0; -} - -bool BluetoothUUID::is_short() -{ - if (uuid[1] == 0x800000805f9b34fbULL && uuid[0] & 0xffffffffULL == 0x00001000ULL) - return true; - return false; -} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 8d5babfa..00000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,75 +0,0 @@ -set (tinyb_LIB_INCLUDE_DIRS - ${PROJECT_SOURCE_DIR}/api - ${PROJECT_SOURCE_DIR}/api/tinyb - ${PROJECT_SOURCE_DIR}/include -) - -include_directories( - ${tinyb_LIB_INCLUDE_DIRS} - ${GLIB2_INCLUDE_DIRS} - ${GIO_INCLUDE_DIRS} - ${GIO-UNIX_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR} -) - -set (tinyb_LIB_SRCS - ${PROJECT_SOURCE_DIR}/src/BluetoothObject.cpp - ${PROJECT_SOURCE_DIR}/src/BluetoothEvent.cpp - ${PROJECT_SOURCE_DIR}/src/BluetoothManager.cpp - ${PROJECT_SOURCE_DIR}/src/BluetoothAdapter.cpp - ${PROJECT_SOURCE_DIR}/src/BluetoothDevice.cpp - ${PROJECT_SOURCE_DIR}/src/BluetoothGattService.cpp - ${PROJECT_SOURCE_DIR}/src/BluetoothGattCharacteristic.cpp - ${PROJECT_SOURCE_DIR}/src/BluetoothGattDescriptor.cpp - ${PROJECT_SOURCE_DIR}/src/BluetoothUUID.cpp - ${PROJECT_SOURCE_DIR}/src/tinyb_utils.cpp -# autogenerated files - ${CMAKE_CURRENT_BINARY_DIR}/version.c - ${CMAKE_CURRENT_BINARY_DIR}/orgbluez-dbus.c -) - -set (tinyb_LIB_GLOB_HEADERS - ${PROJECT_SOURCE_DIR}/api/tinyb.hpp -) - -find_program(GDBUS_CODEGEN NAMES gdbus-codegen) -if (NOT GDBUS_CODEGEN) - message(FATAL_ERROR "gdbus-codegen not found") -else () - message(STATUS "gdbus-codegen found") -endif () - -add_custom_command(OUTPUT orgbluez-dbus.c orgbluez-dbus.h - COMMAND ${GDBUS_CODEGEN} - --interface-prefix org.bluez - --generate-c-code orgbluez-dbus - --c-generate-object-manager ${PROJECT_SOURCE_DIR}/src/org.bluez.xml - DEPENDS ${PROJECT_SOURCE_DIR}/src/org.bluez.xml - COMMENT "Generating dbus code from org.bluez.xml") - -add_library (tinyb SHARED ${tinyb_LIB_SRCS}) -target_link_libraries ( - tinyb - ${CMAKE_THREAD_LIBS_INIT} - ${GLIB2_LIBRARIES} - ${GIO_LIBRARIES} -) - -set_target_properties( - tinyb - PROPERTIES - SOVERSION ${tinyb_VERSION_MAJOR} - VERSION ${tinyb_VERSION_STRING} - CXX_STANDARD 11 -) -install (FILES ${tinyb_LIB_GLOB_HEADERS} DESTINATION include/) -install (DIRECTORY ${PROJECT_SOURCE_DIR}/api/tinyb/ DESTINATION include/tinyb) - -macro (tinyb_CREATE_INSTALL_PKGCONFIG generated_file install_location) - configure_file (${generated_file}.cmake ${CMAKE_CURRENT_BINARY_DIR}/${generated_file} @ONLY) - install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${generated_file} DESTINATION ${install_location}) -endmacro (tinyb_CREATE_INSTALL_PKGCONFIG) -tinyb_create_install_pkgconfig (tinyb.pc lib${LIB_SUFFIX}/pkgconfig) - -install(TARGETS tinyb LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) - diff --git a/src/org.bluez.xml b/src/org.bluez.xml deleted file mode 100644 index da200c6b..00000000 --- a/src/org.bluez.xml +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tinyb.pc.cmake b/src/tinyb.pc.cmake deleted file mode 100644 index 1c9fbaf8..00000000 --- a/src/tinyb.pc.cmake +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib@LIB_SUFFIX@ -includedir=${prefix}/include - -Name: tinyb -Description: Tiny BLE library -Version: @tinyb_VERSION_STRING@ - -Libs: -L${libdir} -ltinyb -Cflags: -I${includedir} diff --git a/src/tinyb/BluetoothAdapter.cpp b/src/tinyb/BluetoothAdapter.cpp new file mode 100644 index 00000000..eab4eacd --- /dev/null +++ b/src/tinyb/BluetoothAdapter.cpp @@ -0,0 +1,459 @@ +/* + * Author: Petre Eftime + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "orgbluez-dbus.h" +#include "tinyb_utils.hpp" +#include "BluetoothNotificationHandler.hpp" +#include "BluetoothAdapter.hpp" +#include "BluetoothDevice.hpp" +#include "BluetoothManager.hpp" +#include "BluetoothException.hpp" + +using namespace tinyb; + +void BluetoothNotificationHandler::on_properties_changed_adapter(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata) { + + auto c = static_cast(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"); +} + +std::string BluetoothAdapter::get_java_class() const +{ + return std::string(JAVA_DBUS_PACKAGE "/DBusAdapter"); +} + +std::string BluetoothAdapter::get_object_path() const +{ + return std::string(g_dbus_proxy_get_object_path(G_DBUS_PROXY(object))); +} + +BluetoothType BluetoothAdapter::get_bluetooth_type() const +{ + return BluetoothType::ADAPTER; +} + +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) +{ + BluetoothAdapter(object.object); +} + +BluetoothAdapter *BluetoothAdapter::clone() const +{ + return new BluetoothAdapter(object); +} + +BluetoothAdapter::~BluetoothAdapter() +{ + valid = false; + g_signal_handlers_disconnect_by_data(object, this); + lk.lock(); + + g_object_unref(object); +} + +std::unique_ptr BluetoothAdapter::make(Object *object, + BluetoothType type, std::string *name, std::string *identifier, + BluetoothObject *parent) +{ + Adapter1 *adapter; + if((type == BluetoothType::NONE || type == BluetoothType::ADAPTER) && + (adapter = object_get_adapter1(object)) != NULL) { + + std::unique_ptr p(new BluetoothAdapter(adapter)); + g_object_unref(adapter); + + if ((name == nullptr || *name == p->get_name()) && + (identifier == nullptr || *identifier == p->get_address()) && + (parent == nullptr)) + return p; + } + + return std::unique_ptr(); +} + +std::vector> BluetoothAdapter::get_devices() +{ + std::vector> vector; + GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); + + for (l = objects; l != NULL; l = l->next) { + Object *object = OBJECT(l->data); + + auto p = BluetoothDevice::make(object, + BluetoothType::DEVICE, NULL, NULL, this); + if (p != nullptr) + vector.push_back(std::move(p)); + } + g_list_free_full(objects, g_object_unref); + + return vector; +} + +/* D-Bus method calls: */ +bool BluetoothAdapter::start_discovery () +{ + GError *error = NULL; + if (get_discovering() == true) + return true; + bool result = adapter1_call_start_discovery_sync( + object, + NULL, + &error + ); + handle_error(error); + return result; +} + +bool BluetoothAdapter::stop_discovery () +{ + GError *error = NULL; + if (get_discovering() == false) + return true; + bool result = adapter1_call_stop_discovery_sync( + object, + NULL, + &error + ); + handle_error(error); + return result; +} + +bool BluetoothAdapter::remove_device ( + const std::string &arg_device) +{ + GError *error = NULL; + bool result = adapter1_call_remove_device_sync( + object, + arg_device.c_str(), + NULL, + &error + ); + handle_error(error); + return result; +} + +bool BluetoothAdapter::set_discovery_filter (std::vector uuids, + int16_t rssi, uint16_t pathloss, const TransportType &transport) +{ + GError *error = NULL; + bool result = true; + GVariantDict dict; + g_variant_dict_init(&dict, NULL); + + if (uuids.size() > 0) + { + GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("a(s)")); + + for (std::vector::iterator i = uuids.begin(); i != uuids.end(); ++i) + g_variant_builder_add(builder, "(s)", (*i).get_string().c_str()); + + GVariant *uuids_variant = g_variant_new("a(s)", builder); + g_variant_builder_unref(builder); + g_variant_dict_insert_value(&dict, "UUIDs", uuids_variant); + } + + if (rssi != 0) + g_variant_dict_insert_value(&dict, "RSSI", g_variant_new_int16(rssi)); + + if (pathloss != 0) + g_variant_dict_insert_value(&dict, "Pathloss", g_variant_new_uint16(pathloss)); + + std::string transport_str; + + if (transport == TransportType::AUTO) + transport_str = "auto"; + else if (transport == TransportType::BREDR) + transport_str = "bredr"; + else if (transport == TransportType::LE) + transport_str = "le"; + + if (!transport_str.empty()) + g_variant_dict_insert_value(&dict, "Transport", g_variant_new_string(transport_str.c_str())); + + GVariant *variant = g_variant_dict_end(&dict); + + result = adapter1_call_set_discovery_filter_sync( + object, + variant, + NULL, + &error + ); + + handle_error(error); + return result; +} + +/* D-Bus property accessors: */ +std::string BluetoothAdapter::get_address () +{ + return std::string(adapter1_get_address (object)); +} + +std::string BluetoothAdapter::get_name () +{ + return std::string(adapter1_get_name (object)); +} + +std::string BluetoothAdapter::get_alias () +{ + return std::string(adapter1_get_alias (object)); +} + +void BluetoothAdapter::set_alias (const std::string &value) +{ + adapter1_set_alias (object, value.c_str()); +} + +unsigned int BluetoothAdapter::get_class () +{ + return adapter1_get_class (object); +} + +bool BluetoothAdapter::get_powered () +{ + return adapter1_get_powered (object); +} + +void BluetoothAdapter::enable_powered_notifications( + std::function callback, + void *userdata) { + powered_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothAdapter::enable_powered_notifications(std::function callback) { + powered_callback = callback; +} +void BluetoothAdapter::disable_powered_notifications() { + powered_callback = nullptr; +} + +void BluetoothAdapter::set_powered (bool value) +{ + if (get_powered() != value) + adapter1_set_powered (object, value); +} + +bool BluetoothAdapter::get_discoverable () +{ + return adapter1_get_discoverable (object); +} + +void BluetoothAdapter::set_discoverable (bool value) +{ + adapter1_set_discoverable (object, value); +} + +void BluetoothAdapter::enable_discoverable_notifications( + std::function callback, + void *userdata) { + discoverable_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothAdapter::enable_discoverable_notifications(std::function callback) { + discoverable_callback = callback; +} +void BluetoothAdapter::disable_discoverable_notifications() { + discoverable_callback = nullptr; +} + +unsigned int BluetoothAdapter::get_discoverable_timeout () +{ + return adapter1_get_discoverable_timeout (object); +} + +void BluetoothAdapter::set_discoverable_timeout (unsigned int value) +{ + adapter1_set_discoverable_timeout (object, value); +} + +bool BluetoothAdapter::get_pairable () +{ + return adapter1_get_pairable (object); +} + +void BluetoothAdapter::enable_pairable_notifications( + std::function callback, + void *userdata) { + pairable_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothAdapter::enable_pairable_notifications(std::function callback) { + pairable_callback = callback; +} +void BluetoothAdapter::disable_pairable_notifications() { + pairable_callback = nullptr; +} + +void BluetoothAdapter::set_pairable (bool value) +{ + adapter1_set_pairable (object, value); +} + +unsigned int BluetoothAdapter::get_pairable_timeout () +{ + return adapter1_get_pairable_timeout (object); +} + +void BluetoothAdapter::set_pairable_timeout (unsigned int value) +{ + adapter1_set_pairable_timeout (object, value); +} + +bool BluetoothAdapter::get_discovering () +{ + return adapter1_get_discovering (object); +} + +void BluetoothAdapter::enable_discovering_notifications( + std::function callback, + void *userdata) { + discovering_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothAdapter::enable_discovering_notifications(std::function callback) { + discovering_callback = callback; +} +void BluetoothAdapter::disable_discovering_notifications() { + discovering_callback = nullptr; +} + +std::vector BluetoothAdapter::get_uuids () +{ + const char * const *uuids_c = adapter1_get_uuids (object); + std::vector uuids; + for (int i = 0; uuids_c[i] != NULL ;i++) + uuids.push_back(std::string(uuids_c[i])); + return uuids; +} + +std::unique_ptr BluetoothAdapter::get_modalias () +{ + const gchar *modalias= adapter1_get_modalias (object); + if (modalias == nullptr) + return std::unique_ptr(); + return std::unique_ptr(new std::string(modalias)); +} + +std::unique_ptr BluetoothAdapter::connect_device ( + const std::string &arg_address, const std::string &arg_address_type) +{ + bool result = true; + GError *error = NULL; + GVariantDict dict; + gchar *object_path = nullptr; + + g_variant_dict_init(&dict, NULL); + g_variant_dict_insert_value(&dict, "Address", g_variant_new_string(arg_address.c_str())); + g_variant_dict_insert_value(&dict, "AddressType", g_variant_new_string(arg_address_type.c_str())); + GVariant *variant = g_variant_dict_end(&dict); + + result = adapter1_call_connect_device_sync( + object, + variant, + &object_path, + NULL, + &error + ); + handle_error(error); + + if( result && nullptr != object_path ) { + + Device1 *device = device1_proxy_new_for_bus_sync( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.bluez", + object_path, + NULL, + &error); + g_free(object_path); + handle_error(error); + + if (device == nullptr) { + std::string error_msg("Error occured while instantiating device: "); + error_msg += error->message; + g_error_free(error); + throw BluetoothException(error_msg); + } + std::unique_ptr p(new BluetoothDevice(device)); + g_object_unref(device); + return p; + } + g_free(object_path); + return std::unique_ptr(); +} + diff --git a/src/tinyb/BluetoothDevice.cpp b/src/tinyb/BluetoothDevice.cpp new file mode 100644 index 00000000..97538cd4 --- /dev/null +++ b/src/tinyb/BluetoothDevice.cpp @@ -0,0 +1,642 @@ +/* + * Author: Petre Eftime + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "orgbluez-dbus.h" +#include "tinyb_utils.hpp" +#include "BluetoothNotificationHandler.hpp" +#include "BluetoothDevice.hpp" +#include "BluetoothGattService.hpp" +#include "BluetoothManager.hpp" +#include "BluetoothException.hpp" + +using namespace tinyb; + +void BluetoothNotificationHandler::on_properties_changed_device(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata) { + + auto c = static_cast(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; + } + auto mfg_callback = c->mfg_callback; + if (mfg_callback != nullptr && g_ascii_strncasecmp(key, "manufacturerdata", 16) == 0) { + std::map> new_value; + + GVariantIter *iter; + g_variant_get (value, "a{qv}", &iter); + + GVariant *array; + uint16_t key; + uint8_t val; + + while (g_variant_iter_loop(iter, "{qv}", &key, &array)) { + GVariantIter it_array; + g_variant_iter_init(&it_array, array); + while(g_variant_iter_loop(&it_array, "y", &val)) { + new_value[key].push_back(val); + } + } + + g_variant_iter_free(iter); + mfg_callback(new_value); + continue; + } + auto service_callback = c->service_callback; + if (service_callback != nullptr && g_ascii_strncasecmp(key, "servicedata", 11) == 0) { + std::map> new_value; + + GVariantIter *iter; + g_variant_get (value, "a{sv}", &iter); + + GVariant *array; + const char* key; + uint8_t val; + + while (g_variant_iter_loop(iter, "{sv}", &key, &array)) { + GVariantIter it_array; + g_variant_iter_init(&it_array, array); + while(g_variant_iter_loop(&it_array, "y", &val)) { + new_value[key].push_back(val); + } + } + + g_variant_iter_free(iter); + service_callback(new_value); + continue; + } + auto services_resolved_callback = c->services_resolved_callback; + if (services_resolved_callback != nullptr && g_ascii_strncasecmp(key, "servicesresolved", 16) == 0) { + bool new_value; + g_variant_get(value, "b", &new_value); + services_resolved_callback(new_value); + continue; + } + } + g_variant_iter_free (iter); + } + + c->unlock(); +} + +std::string BluetoothDevice::get_class_name() const +{ + return std::string("BluetoothDevice"); +} + +std::string BluetoothDevice::get_java_class() const +{ + return std::string(JAVA_DBUS_PACKAGE "/DBusDevice"); +} + +std::string BluetoothDevice::get_object_path() const +{ + return std::string(g_dbus_proxy_get_object_path(G_DBUS_PROXY(object))); +} + +BluetoothType BluetoothDevice::get_bluetooth_type() const +{ + return BluetoothType::DEVICE; +} + +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) +{ + BluetoothDevice(object.object); +} + +BluetoothDevice::~BluetoothDevice() +{ + valid = false; + g_signal_handlers_disconnect_by_data(object, this); + lk.lock(); + + g_object_unref(object); +} + +std::unique_ptr BluetoothDevice::make(Object *object, + BluetoothType type, std::string *name, std::string *identifier, + BluetoothObject *parent) +{ + Device1 *device; + if((type == BluetoothType::NONE || type == BluetoothType::DEVICE) && + (device = object_get_device1(object)) != NULL) { + + std::unique_ptr p(new BluetoothDevice(device)); + g_object_unref(device); + + if ((name == nullptr || *name == p->get_name()) && + (identifier == nullptr || *identifier == p->get_address()) && + (parent == nullptr || *parent == p->get_adapter())) + return p; + } + + return std::unique_ptr(); +} + +BluetoothDevice *BluetoothDevice::clone() const +{ + return new BluetoothDevice(object); +} + +std::vector> BluetoothDevice::get_services() +{ + std::vector> vector; + GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); + + for (l = objects; l != NULL; l = l->next) { + Object *object = OBJECT(l->data); + + auto p = BluetoothGattService::make(object, + BluetoothType::GATT_SERVICE, NULL, NULL, this); + if (p != nullptr) + vector.push_back(std::move(p)); + } + g_list_free_full(objects, g_object_unref); + + return vector; +} + +/* D-Bus method calls: */ +bool BluetoothDevice::disconnect () +{ + GError *error = NULL; + bool result; + result = device1_call_disconnect_sync( + object, + NULL, + &error + ); + handle_error(error); + return result; +} + +void BluetoothDevice::connect_async_start () +{ + device1_call_connect ( + object, // Device1 *proxy, + NULL, // GCancellable *cancellable, + NULL, // GAsyncReadyCallback callback, + NULL // gpointer user_data) + ); +} + +bool BluetoothDevice::connect_async_finish () +{ + GError *error = NULL; + bool result; + result = device1_call_connect_finish ( + object, // Device1 *proxy, + NULL, // GAsyncResult *res, + &error // GError **error) + ); + handle_error(error); + return result; +} + +bool BluetoothDevice::connect () +{ + GError *error = NULL; + bool result; + result = device1_call_connect_sync( + object, + NULL, + &error + ); + handle_error(error); + return result; +} + +bool BluetoothDevice::connect_profile ( + const std::string &arg_UUID) +{ + GError *error = NULL; + bool result; + result = device1_call_connect_profile_sync( + object, + arg_UUID.c_str(), + NULL, + &error + ); + handle_error(error); + return result; +} + +bool BluetoothDevice::disconnect_profile ( + const std::string &arg_UUID) +{ + GError *error = NULL; + bool result; + result = device1_call_disconnect_profile_sync( + object, + arg_UUID.c_str(), + NULL, + &error + ); + handle_error(error); + return result; +} + +bool BluetoothDevice::pair () +{ + GError *error = NULL; + bool result; + result = device1_call_pair_sync( + object, + NULL, + &error + ); + handle_error(error); + return result; +} + +// Remove the device (like an unpair) +bool BluetoothDevice::remove_device(){ + BluetoothAdapter ba = get_adapter(); + return ba.remove_device(get_object_path()); +} + +bool BluetoothDevice::cancel_pairing () +{ + GError *error = NULL; + bool result; + result = device1_call_cancel_pairing_sync( + object, + NULL, + &error + ); + handle_error(error); + return result; +} + + + +/* D-Bus property accessors: */ +std::string BluetoothDevice::get_address () +{ + return std::string(device1_get_address (object)); +} + +std::string BluetoothDevice::get_name () +{ + const gchar *name = device1_get_name(object); + if (name == nullptr) + return std::string(device1_get_alias(object)); + return std::string(name); +} + +std::string BluetoothDevice::get_alias () +{ + return device1_get_alias (object); +} + +void BluetoothDevice::set_alias (const std::string &value) +{ + device1_set_alias (object, value.c_str()); +} + +unsigned int BluetoothDevice::get_class () +{ + return device1_get_class (object); +} + +uint16_t BluetoothDevice::get_appearance () +{ + return device1_get_appearance (object); +} + +std::unique_ptr BluetoothDevice::get_icon () +{ + const gchar *icon = device1_get_icon (object); + if (icon == nullptr) + return std::unique_ptr(); + return std::unique_ptr(new std::string(icon)); +} + +bool BluetoothDevice::get_paired () +{ + return device1_get_paired (object); +} + +void BluetoothDevice::enable_paired_notifications( + std::function callback, + void *userdata) { + paired_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_paired_notifications( + std::function callback) { + paired_callback = callback; +} +void BluetoothDevice::disable_paired_notifications() { + paired_callback = nullptr; +} + +bool BluetoothDevice::get_trusted () +{ + return device1_get_trusted (object); +} + +void BluetoothDevice::set_trusted (bool value) +{ + device1_set_trusted (object, value); +} + +void BluetoothDevice::enable_trusted_notifications( + std::function callback, + void *userdata) { + trusted_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_trusted_notifications( + std::function callback) { + trusted_callback = callback; +} +void BluetoothDevice::disable_trusted_notifications() { + trusted_callback = nullptr; +} + +bool BluetoothDevice::get_blocked () +{ + return device1_get_blocked (object); +} + +void BluetoothDevice::set_blocked (bool value) +{ + device1_set_blocked (object, value); +} + +void BluetoothDevice::enable_blocked_notifications( + std::function callback, + void *userdata) { + blocked_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_blocked_notifications( + std::function callback) { + blocked_callback = callback; +} +void BluetoothDevice::disable_blocked_notifications() { + blocked_callback = nullptr; +} + +bool BluetoothDevice::get_legacy_pairing () +{ + return device1_get_legacy_pairing (object); +} + +int16_t BluetoothDevice::get_rssi () +{ + return device1_get_rssi (object); +} + +void BluetoothDevice::enable_rssi_notifications( + std::function callback, + void *userdata) { + rssi_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_rssi_notifications( + std::function 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 callback, + void *userdata) { + connected_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_connected_notifications( + std::function callback) { + connected_callback = callback; +} +void BluetoothDevice::disable_connected_notifications() { + connected_callback = nullptr; +} + +std::vector BluetoothDevice::get_uuids () +{ + + const char * const *uuids_c = device1_get_uuids (object); + std::vector uuids; + for (int i = 0; uuids_c[i] != NULL ;i++) + uuids.push_back(std::string(uuids_c[i])); + return uuids; +} + +std::unique_ptr BluetoothDevice::get_modalias () +{ + const gchar *modalias= device1_get_modalias (object); + if (modalias == nullptr) + return std::unique_ptr(); + return std::unique_ptr(new std::string(modalias)); +} + +BluetoothAdapter BluetoothDevice::get_adapter () +{ + GError *error = NULL; + + Adapter1 *adapter = adapter1_proxy_new_for_bus_sync( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.bluez", + device1_get_adapter (object), + NULL, + &error); + + if (adapter == NULL) { + std::string error_msg("Error occured while instantiating adapter: "); + error_msg += error->message; + g_error_free(error); + throw BluetoothException(error_msg); + } + + auto res = BluetoothAdapter(adapter); + g_object_unref(adapter); + return res; +} + +std::map> BluetoothDevice::get_manufacturer_data() +{ + std::map> m_data; + GVariant *v = device1_dup_manufacturer_data (object); + + if (v == nullptr) + return m_data; + + GVariantIter *iter; + g_variant_get (v, "a{qv}", &iter); + + GVariant *array; + uint16_t key; + uint8_t val; + + while (g_variant_iter_loop(iter, "{qv}", &key, &array)) { + + GVariantIter it_array; + g_variant_iter_init(&it_array, array); + while(g_variant_iter_loop(&it_array, "y", &val)) { + m_data[key].push_back(val); + } + } + + g_variant_iter_free(iter); + g_variant_unref(v); + + return m_data; +} + +void BluetoothDevice::enable_manufacturer_data_notifications( + std::function> &, void *)> callback, + void *userdata) { + mfg_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_manufacturer_data_notifications( + std::function> &)> callback) { + mfg_callback = callback; +} +void BluetoothDevice::disable_manufacturer_data_notifications() { + mfg_callback = nullptr; +} + +std::map> BluetoothDevice::get_service_data() +{ + std::map> m_data; + GVariant *v = device1_dup_service_data (object); + + if (v == nullptr) + return m_data; + + GVariantIter *iter; + g_variant_get (v, "a{sv}", &iter); + + GVariant *array; + const char* key; + uint8_t val; + + while (g_variant_iter_loop(iter, "{sv}", &key, &array)) { + + GVariantIter it_array; + g_variant_iter_init(&it_array, array); + while(g_variant_iter_loop(&it_array, "y", &val)) { + m_data[key].push_back(val); + } + } + + g_variant_iter_free(iter); + g_variant_unref(v); + + return m_data; +} + +void BluetoothDevice::enable_service_data_notifications( + std::function> &, void *)> callback, + void *userdata) { + service_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_service_data_notifications( + std::function> &)> callback) { + service_callback = callback; +} +void BluetoothDevice::disable_service_data_notifications() { + service_callback = nullptr; +} + +int16_t BluetoothDevice::get_tx_power () +{ + return device1_get_tx_power (object); +} + +bool BluetoothDevice::get_services_resolved () +{ + return device1_get_services_resolved (object); +} + +void BluetoothDevice::enable_services_resolved_notifications( + std::function callback, + void *userdata) { + services_resolved_callback = std::bind(callback, std::ref(*this), std::placeholders::_1, userdata); +} +void BluetoothDevice::enable_services_resolved_notifications( + std::function callback) { + services_resolved_callback = callback; +} +void BluetoothDevice::disable_services_resolved_notifications() { + services_resolved_callback = nullptr; +} + diff --git a/src/tinyb/BluetoothEvent.cpp b/src/tinyb/BluetoothEvent.cpp new file mode 100644 index 00000000..10558edb --- /dev/null +++ b/src/tinyb/BluetoothEvent.cpp @@ -0,0 +1,111 @@ +/* + * Author: Petre Eftime + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "orgbluez-dbus.h" +#include "BluetoothEvent.hpp" +#include "BluetoothManager.hpp" + +void BluetoothEvent::generic_callback(BluetoothObject &object, void *data) +{ + + if (data == nullptr) + return; + + BluetoothConditionVariable *generic_data = static_cast(data); + + generic_data->result = object.clone(); + generic_data->notify(); +} + +BluetoothEvent::BluetoothEvent(BluetoothType type, std::string *name, + std::string *identifier, BluetoothObject *parent, bool execute_once, + BluetoothCallback cb, void *data) +{ + canceled = false; + this->type = type; + if (name != nullptr) + this->name = new std::string(*name); + else + this->name = nullptr; + + if (identifier != nullptr) + this->identifier = new std::string(*identifier); + else + this->identifier = nullptr; + + if (parent != nullptr) + this->parent = parent->clone(); + else + this->parent = nullptr; + + this->execute_once = execute_once; + + if (cb == nullptr) { + this->data = static_cast(&cv); + this->cb = generic_callback; + } + else { + this->cb = cb; + this->data = data; + } +} + +bool BluetoothEvent::execute_callback(BluetoothObject &object) +{ + if (has_callback()) { + cb(object, data); + cv.notify(); + return execute_once; + } + + return true; +} + +void BluetoothEvent::wait(std::chrono::milliseconds timeout) +{ + if (!canceled && execute_once == true) { + if (timeout == std::chrono::milliseconds::zero()) + cv.wait(); + else + cv.wait_for(timeout); + } +} + +void BluetoothEvent::cancel() +{ + BluetoothManager *manager = BluetoothManager::get_bluetooth_manager(); + manager->remove_event(*this); + + cv.notify(); +} + +BluetoothEvent::~BluetoothEvent() +{ + if (name != nullptr) + delete name; + if (identifier != nullptr) + delete identifier; + if (parent != nullptr) + delete parent; +} diff --git a/src/tinyb/BluetoothGattCharacteristic.cpp b/src/tinyb/BluetoothGattCharacteristic.cpp new file mode 100644 index 00000000..30914e9e --- /dev/null +++ b/src/tinyb/BluetoothGattCharacteristic.cpp @@ -0,0 +1,324 @@ +/* + * Author: Petre Eftime + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "orgbluez-dbus.h" +#include "tinyb_utils.hpp" +#include "BluetoothNotificationHandler.hpp" +#include "BluetoothGattCharacteristic.hpp" +#include "BluetoothGattService.hpp" +#include "BluetoothGattDescriptor.hpp" +#include "BluetoothException.hpp" + +using namespace tinyb; + +void BluetoothNotificationHandler::on_properties_changed_characteristic(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer userdata) { + + auto c = static_cast(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 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"); +} + +std::string BluetoothGattCharacteristic::get_java_class() const +{ + return std::string(JAVA_DBUS_PACKAGE "/DBusGattCharacteristic"); +} + +std::string BluetoothGattCharacteristic::get_object_path() const +{ + return std::string(g_dbus_proxy_get_object_path(G_DBUS_PROXY(object))); +} + +BluetoothType BluetoothGattCharacteristic::get_bluetooth_type() const +{ + return BluetoothType::GATT_CHARACTERISTIC; +} + +BluetoothGattCharacteristic::BluetoothGattCharacteristic(GattCharacteristic1 *object) +{ + 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); +} + +BluetoothGattCharacteristic *BluetoothGattCharacteristic::clone() const +{ + return new BluetoothGattCharacteristic(object); +} + +std::unique_ptr BluetoothGattCharacteristic::make( + Object *object, BluetoothType type, std::string *name, + std::string *identifier, BluetoothObject *parent) +{ + GattCharacteristic1 *characteristic; + if((type == BluetoothType::NONE || type == BluetoothType::GATT_CHARACTERISTIC) && + (characteristic = object_get_gatt_characteristic1(object)) != NULL) { + + std::unique_ptr p( + new BluetoothGattCharacteristic(characteristic)); + g_object_unref(characteristic); + + if ((name == nullptr) && + (identifier == nullptr || *identifier == p->get_uuid()) && + (parent == nullptr || *parent == p->get_service())) + return p; + } + + return std::unique_ptr(); +} + +/* D-Bus method calls: */ +std::vector BluetoothGattCharacteristic::read_value (uint16_t offset) +{ + GError *error = NULL; + GVariant *result_variant; + + GVariantDict dict; + g_variant_dict_init(&dict, NULL); + + if (offset != 0) + g_variant_dict_insert_value(&dict, "offset", g_variant_new_uint16(offset)); + + GVariant *variant = g_variant_dict_end(&dict); + + gatt_characteristic1_call_read_value_sync( + object, + variant, + &result_variant, + NULL, + &error + ); + + handle_error(error); + + GBytes *result_gbytes = g_variant_get_data_as_bytes(result_variant); + std::vector result = from_gbytes_to_vector(result_gbytes); + + /* free the gbytes array */ + g_bytes_unref(result_gbytes); + + return result; +} + +bool BluetoothGattCharacteristic::write_value ( + const std::vector &arg_value, uint16_t offset) +{ + GError *error = NULL; + bool result = true; + + gboolean trusted = true; + GBytes *arg_value_gbytes = from_vector_to_gbytes(arg_value); + GVariant *value = g_variant_new_from_bytes( + G_VARIANT_TYPE_BYTESTRING, arg_value_gbytes, trusted); + + GVariantDict dict; + g_variant_dict_init(&dict, NULL); + + if (offset != 0) + g_variant_dict_insert_value(&dict, "offset", g_variant_new_uint16(offset)); + + GVariant *variant = g_variant_dict_end(&dict); + + result = gatt_characteristic1_call_write_value_sync( + object, + value, + variant, + NULL, + &error + ); + + /* freeing the GBytes allocated inside from_vector_to_gbytes function */ + g_bytes_unref(arg_value_gbytes); + + handle_error(error); + + return result; +} + +bool BluetoothGattCharacteristic::enable_value_notifications( + std::function &,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 &)> 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; + bool result; + result = gatt_characteristic1_call_start_notify_sync( + object, + NULL, + &error + ); + + handle_error(error); + return result; +} + +bool BluetoothGattCharacteristic::stop_notify () +{ + GError *error = NULL; + bool result; + result = gatt_characteristic1_call_stop_notify_sync( + object, + NULL, + &error + ); + handle_error(error); + return result; +} + +/* D-Bus property accessors: */ +std::string BluetoothGattCharacteristic::get_uuid () +{ + return std::string(gatt_characteristic1_get_uuid (object)); +} + +BluetoothGattService BluetoothGattCharacteristic::get_service () +{ + GError *error = NULL; + + GattService1 *service = gatt_service1_proxy_new_for_bus_sync( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.bluez", + gatt_characteristic1_get_service (object), + NULL, + &error); + + if (service == nullptr) { + std::string error_msg("Error occured while instantiating service: "); + error_msg += error->message; + g_error_free(error); + throw BluetoothException(error_msg); + } + + auto res = BluetoothGattService(service); + g_object_unref(service); + return res; +} + +std::vector BluetoothGattCharacteristic::get_value () +{ + GVariant *value_variant = gatt_characteristic1_get_value (object); + GBytes *value_gbytes = g_variant_get_data_as_bytes(value_variant); + std::vector result; + + try { + result = from_gbytes_to_vector(value_gbytes); + } catch (std::exception &e) { + g_bytes_unref(value_gbytes); + throw e; + } + + g_bytes_unref(value_gbytes); + + return result; +} + +bool BluetoothGattCharacteristic::get_notifying () +{ + return gatt_characteristic1_get_notifying (object); +} + +std::vector BluetoothGattCharacteristic::get_flags () +{ + const char * const *flags_c = gatt_characteristic1_get_flags (object); + std::vector flags; + for (int i = 0; flags_c[i] != NULL ;i++) + flags.push_back(std::string(flags_c[i])); + return flags; + +} + +std::vector> BluetoothGattCharacteristic::get_descriptors () +{ + std::vector> vector; + GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); + + for (l = objects; l != NULL; l = l->next) { + Object *object = OBJECT(l->data); + + auto p = BluetoothGattDescriptor::make(object, + BluetoothType::GATT_DESCRIPTOR, NULL, NULL, this); + if (p != nullptr) + vector.push_back(std::move(p)); + } + g_list_free_full(objects, g_object_unref); + + return vector; +} + + diff --git a/src/tinyb/BluetoothGattDescriptor.cpp b/src/tinyb/BluetoothGattDescriptor.cpp new file mode 100644 index 00000000..72acdd37 --- /dev/null +++ b/src/tinyb/BluetoothGattDescriptor.cpp @@ -0,0 +1,244 @@ +/* + * Author: Petre Eftime + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "orgbluez-dbus.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(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 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"); +} + +std::string BluetoothGattDescriptor::get_java_class() const +{ + return std::string(JAVA_DBUS_PACKAGE "/DBusGattDescriptor"); +} + +std::string BluetoothGattDescriptor::get_object_path() const +{ + return std::string(g_dbus_proxy_get_object_path(G_DBUS_PROXY(object))); +} + +BluetoothType BluetoothGattDescriptor::get_bluetooth_type() const +{ + return BluetoothType::GATT_DESCRIPTOR; +} + +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) +{ + BluetoothGattDescriptor(object.object); +} + +BluetoothGattDescriptor::~BluetoothGattDescriptor() +{ + valid = false; + g_signal_handlers_disconnect_by_data(object, this); + lk.lock(); + + g_object_unref(object); +} + +std::unique_ptr BluetoothGattDescriptor::make( + Object *object, BluetoothType type, std::string *name, + std::string *identifier, BluetoothObject *parent) +{ + GattDescriptor1 *descriptor; + if((type == BluetoothType::NONE || type == BluetoothType::GATT_DESCRIPTOR) && + (descriptor = object_get_gatt_descriptor1(object)) != NULL) { + + std::unique_ptr p( + new BluetoothGattDescriptor(descriptor)); + g_object_unref(descriptor); + + if ((name == nullptr) && + (identifier == nullptr || *identifier == p->get_uuid()) && + (parent == nullptr || *parent == p->get_characteristic())) + return p; + } + + return std::unique_ptr(); +} + + + +BluetoothGattDescriptor *BluetoothGattDescriptor::clone() const +{ + return new BluetoothGattDescriptor(object); +} + +/* D-Bus method calls: */ +std::vector BluetoothGattDescriptor::read_value (uint16_t offset) +{ + GError *error = NULL; + gchar *result_chars; + + GVariantDict dict; + g_variant_dict_init(&dict, NULL); + + if (offset != 0) + g_variant_dict_insert_value(&dict, "offset", g_variant_new_uint16(offset)); + + GVariant *variant = g_variant_dict_end(&dict); + + gatt_descriptor1_call_read_value_sync( + object, + variant, + &result_chars, + NULL, + &error + ); + handle_error(error); + + std::vector result = from_chars_to_vector(result_chars); + + g_free(result_chars); + + return result; +} + +bool BluetoothGattDescriptor::write_value ( + const std::vector &arg_value, uint16_t offset) +{ + GError *error = NULL; + bool result; + + gchar *arg_value_chars = const_cast(reinterpret_cast(arg_value.data())); + + GVariantDict dict; + g_variant_dict_init(&dict, NULL); + + if (offset != 0) + g_variant_dict_insert_value(&dict, "offset", g_variant_new_uint16(offset)); + + GVariant *variant = g_variant_dict_end(&dict); + + result = gatt_descriptor1_call_write_value_sync( + object, + arg_value_chars, + variant, + NULL, + &error + ); + handle_error(error); + + return result; +} + +bool BluetoothGattDescriptor::enable_value_notifications( + std::function &,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 &)> 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 () +{ + return std::string(gatt_descriptor1_get_uuid (object)); +} + +BluetoothGattCharacteristic BluetoothGattDescriptor::get_characteristic () +{ + GError *error = NULL; + + GattCharacteristic1* characteristic = gatt_characteristic1_proxy_new_for_bus_sync( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.bluez", + gatt_descriptor1_get_characteristic (object), + NULL, + &error); + + if (characteristic == NULL) { + std::string error_msg("Error occured while instantiating characteristic: "); + error_msg += error->message; + g_error_free(error); + throw BluetoothException(error_msg); + } + + auto res = BluetoothGattCharacteristic(characteristic); + g_object_unref(characteristic); + return res; +} + +std::vector BluetoothGattDescriptor::get_value () +{ + gchar *value_chars = const_cast(gatt_descriptor1_get_value (object)); + std::vector result; + + result = from_chars_to_vector(value_chars); + + return result; +} diff --git a/src/tinyb/BluetoothGattService.cpp b/src/tinyb/BluetoothGattService.cpp new file mode 100644 index 00000000..d63893eb --- /dev/null +++ b/src/tinyb/BluetoothGattService.cpp @@ -0,0 +1,148 @@ +/* + * Author: Petre Eftime + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "orgbluez-dbus.h" +#include "tinyb_utils.hpp" +#include "BluetoothGattService.hpp" +#include "BluetoothGattCharacteristic.hpp" +#include "BluetoothDevice.hpp" +#include "BluetoothException.hpp" + +using namespace tinyb; + +std::string BluetoothGattService::get_class_name() const +{ + return std::string("BluetoothGattService"); +} + +std::string BluetoothGattService::get_java_class() const +{ + return std::string(JAVA_DBUS_PACKAGE "/DBusGattService"); +} + +std::string BluetoothGattService::get_object_path() const +{ + return std::string(g_dbus_proxy_get_object_path(G_DBUS_PROXY(object))); +} + +BluetoothType BluetoothGattService::get_bluetooth_type() const +{ + return BluetoothType::GATT_SERVICE; +} + +BluetoothGattService::BluetoothGattService(GattService1 *object) +{ + this->object = object; + g_object_ref(object); +} + +BluetoothGattService::BluetoothGattService(const BluetoothGattService &object) +{ + BluetoothGattService(object.object); +} + +BluetoothGattService::~BluetoothGattService() +{ + g_object_unref(object); +} + +std::unique_ptr BluetoothGattService::make( + Object *object, BluetoothType type, std::string *name, + std::string *identifier, BluetoothObject *parent) +{ + GattService1 *service; + if((type == BluetoothType::NONE || type == BluetoothType::GATT_SERVICE) && + (service = object_get_gatt_service1(object)) != NULL) { + + std::unique_ptr p( + new BluetoothGattService(service)); + g_object_unref(service); + + if ((name == nullptr) && + (identifier == nullptr || *identifier == p->get_uuid()) && + (parent == nullptr || *parent == p->get_device())) + return p; + } + + return std::unique_ptr(); +} + +BluetoothGattService *BluetoothGattService::clone() const +{ + return new BluetoothGattService(object); +} + +/* D-Bus property accessors: */ +std::string BluetoothGattService::get_uuid () +{ + return std::string(gatt_service1_get_uuid (object)); +} + +BluetoothDevice BluetoothGattService::get_device () +{ + GError *error = NULL; + + Device1 *device = device1_proxy_new_for_bus_sync( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.bluez", + gatt_service1_get_device (object), + NULL, + &error); + + if (device == nullptr) { + std::string error_msg("Error occured while instantiating device: "); + error_msg += error->message; + g_error_free(error); + throw BluetoothException(error_msg); + } + + auto res = BluetoothDevice(device); + g_object_unref(device); + return res; +} + +bool BluetoothGattService::get_primary () +{ + return gatt_service1_get_primary (object); +} + +std::vector> BluetoothGattService::get_characteristics () +{ + std::vector> vector; + GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); + + for (l = objects; l != NULL; l = l->next) { + Object *object = OBJECT(l->data); + + auto p = BluetoothGattCharacteristic::make(object, + BluetoothType::GATT_CHARACTERISTIC, NULL, NULL, this); + if (p != nullptr) + vector.push_back(std::move(p)); + } + g_list_free_full(objects, g_object_unref); + + return vector; +} + diff --git a/src/tinyb/BluetoothManager.cpp b/src/tinyb/BluetoothManager.cpp new file mode 100644 index 00000000..b6868d09 --- /dev/null +++ b/src/tinyb/BluetoothManager.cpp @@ -0,0 +1,411 @@ +/* + * Author: Petre Eftime + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "orgbluez-dbus.h" +#include "BluetoothManager.hpp" +#include "BluetoothAdapter.hpp" +#include "BluetoothDevice.hpp" +#include "BluetoothGattService.hpp" +#include "BluetoothGattCharacteristic.hpp" +#include "BluetoothGattDescriptor.hpp" +#include "BluetoothEvent.hpp" +#include "BluetoothException.hpp" +#include "version.h" + +#include + +using namespace tinyb; + +class tinyb::BluetoothEventManager { +public: + static void on_interface_added (GDBusObject *object, + GDBusInterface *interface, gpointer user_data) { + GDBusInterfaceInfo *info = g_dbus_interface_get_info(interface); + BluetoothType type = BluetoothType::NONE; + BluetoothManager *manager = BluetoothManager::get_bluetooth_manager(); + + /* Unknown interface, ignore */ + if (info == NULL) + return; + + if(IS_GATT_SERVICE1_PROXY(interface)) { + type = BluetoothType::GATT_SERVICE; + auto obj = new BluetoothGattService(GATT_SERVICE1(interface)); + auto uuid = obj->get_uuid(); + auto parent = obj->get_device(); + manager->handle_event(type, nullptr, &uuid, &parent, *obj); + } + else if(IS_GATT_CHARACTERISTIC1_PROXY(interface)) { + type = BluetoothType::GATT_CHARACTERISTIC; + auto obj = new BluetoothGattCharacteristic(GATT_CHARACTERISTIC1(interface)); + auto uuid = obj->get_uuid(); + auto parent = obj->get_service(); + manager->handle_event(type, nullptr, &uuid, &parent, *obj); + } + else if(IS_GATT_DESCRIPTOR1_PROXY(interface)) { + type = BluetoothType::GATT_DESCRIPTOR; + auto obj = new BluetoothGattDescriptor(GATT_DESCRIPTOR1(interface)); + auto uuid = obj->get_uuid(); + auto parent = obj->get_characteristic(); + manager->handle_event(type, nullptr, &uuid, &parent, *obj); + } + else if(IS_DEVICE1_PROXY(interface)) { + type = BluetoothType::DEVICE; + auto obj = new BluetoothDevice(DEVICE1(interface)); + auto name = obj->get_name(); + auto uuid = obj->get_address(); + auto parent = obj->get_adapter(); + manager->handle_event(type, &name, &uuid, &parent, *obj); + } + else if(IS_ADAPTER1_PROXY(interface)) { + type = BluetoothType::ADAPTER; + auto obj = new BluetoothAdapter(ADAPTER1(interface)); + auto name = obj->get_name(); + auto uuid = obj->get_address(); + manager->handle_event(type, &name, &uuid, nullptr, *obj); + } + } + + static void on_object_added (GDBusObjectManager *manager, + GDBusObject *object, gpointer user_data) { + GList *l, *interfaces = g_dbus_object_get_interfaces(object); + + for(l = interfaces; l != NULL; l = l->next) + on_interface_added(object, (GDBusInterface *)l->data, user_data); + + g_list_free_full(interfaces, g_object_unref); + } +}; + +GDBusObjectManager *gdbus_manager = NULL; +GMainContext *manager_context = NULL; +GThread *manager_thread = NULL; + +std::string BluetoothManager::get_class_name() const +{ + return std::string("BluetoothManager"); +} + +std::string BluetoothManager::get_java_class() const +{ + return std::string(JAVA_DBUS_PACKAGE "/DBusManager"); +} + +std::string BluetoothManager::get_object_path() const +{ + return std::string("/"); +} + +BluetoothType BluetoothManager::get_bluetooth_type() const +{ + return BluetoothType::NONE; +} + +std::string BluetoothManager::get_api_version() { + return std::string(gVERSION_API); +} + +std::string BluetoothManager::get_library_version() { + return std::string(gVERSION_SHORT); +} + +std::unique_ptr BluetoothManager::get_object( + BluetoothType type, std::string *name, std::string *identifier, + BluetoothObject *parent) +{ + auto list = get_objects(type, name, identifier, parent); + if (list.empty()) + return std::unique_ptr(); + return std::move(list.front()); +} + +std::vector> BluetoothManager::get_objects( + BluetoothType type, std::string *name, std::string *identifier, + BluetoothObject *parent) +{ + std::vector> vector; + GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); + + for (l = objects; l != NULL; l = l->next) { + Object *object = OBJECT(l->data); + + auto p_service = BluetoothGattService::make(object, type, name, identifier, parent); + if (p_service != nullptr) + vector.push_back(std::move(p_service)); + + auto p_characteristic = BluetoothGattCharacteristic::make(object, type, name, identifier, parent); + if (p_characteristic != nullptr) + vector.push_back(std::move(p_characteristic)); + + auto p_descriptor = BluetoothGattDescriptor::make(object, type, name, identifier, parent); + if (p_descriptor != nullptr) + vector.push_back(std::move(p_descriptor)); + + auto p_device = BluetoothDevice::make(object, type, name, identifier, parent); + if (p_device != nullptr) + vector.push_back(std::move(p_device)); + + auto p_adapter = BluetoothAdapter::make(object, type, name, identifier, parent); + if (p_adapter != nullptr) + vector.push_back(std::move(p_adapter)); + } + g_list_free_full(objects, g_object_unref); + return vector; +} + +std::unique_ptr BluetoothManager::find(BluetoothType type, + std::string *name, std::string* identifier, BluetoothObject *parent, + std::chrono::milliseconds timeout) +{ + std::shared_ptr event(new BluetoothEvent(type, name, + identifier, parent)); + add_event(event); + + auto object = get_object(type, name, identifier, parent); + + if (object == nullptr) { + event->wait(timeout); + object = std::unique_ptr(event->get_result()); + } + + event->cancel(); + return object; +} + +std::weak_ptr BluetoothManager::find(BluetoothType type, + std::string *name, std::string* identifier, BluetoothObject *parent, + BluetoothCallback cb, bool execute_once, + std::chrono::milliseconds timeout) +{ + std::shared_ptr event(new BluetoothEvent(type, name, + identifier, parent)); + add_event(event); + return std::weak_ptr(event); +} + +void BluetoothManager::handle_event(BluetoothType type, std::string *name, + std::string *identifier, BluetoothObject *parent, BluetoothObject &object) +{ + for (auto it = event_list.begin(); + it != event_list.end();) { + if ((*it)->get_type() != BluetoothType::NONE && ((*it)->get_type()) != type) { + ++it; + continue; /* this event does not match */ + } + if ((*it)->get_name() != NULL) + if (name == NULL || *((*it)->get_name()) != *name) { + ++it; + continue; /* this event does not match */ + } + if ((*it)->get_identifier() != NULL) + if (identifier == NULL || *((*it)->get_identifier()) != *identifier) { + ++it; + continue; /* this event does not match */ + } + if ((*it)->get_parent() != NULL) + if (parent == NULL || *((*it)->get_parent()) != *parent) { + ++it; + continue; /* this event does not match */ + } + /* The event matches, execute and see if it needs to reexecute */ + if ((*it)->execute_callback(object)) + it = event_list.erase(it); + else + ++it; + } +} + +static gpointer init_manager_thread(void *data) +{ + GMainLoop *loop; + GDBusObjectManager *gdbus_manager = (GDBusObjectManager *) data; + + g_main_context_push_thread_default(manager_context); + + loop = g_main_loop_new(manager_context, FALSE); + + g_signal_connect(gdbus_manager, + "interface-added", + G_CALLBACK(BluetoothEventManager::on_interface_added), + NULL); + + g_signal_connect(gdbus_manager, + "object-added", + G_CALLBACK(BluetoothEventManager::on_object_added), + NULL); + + g_main_context_pop_thread_default(manager_context); + + g_main_loop_run(loop); + + return NULL; +} + +BluetoothManager::BluetoothManager() : event_list() +{ + GError *error = NULL; + GList *objects, *l; + + manager_context = g_main_context_new (); + g_main_context_push_thread_default(manager_context); + + gdbus_manager = object_manager_client_new_for_bus_sync( + G_BUS_TYPE_SYSTEM, + G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, + "org.bluez", + "/", + NULL, /* GCancellable */ + &error); + + if (gdbus_manager == nullptr) { + std::string error_str("Error getting object manager client: "); + error_str += error->message; + g_error_free(error); + throw std::runtime_error(error_str); + } + + g_main_context_pop_thread_default(manager_context); + + manager_thread = g_thread_new("BluetoothManager-Thread", init_manager_thread, gdbus_manager); + + objects = g_dbus_object_manager_get_objects(gdbus_manager); + + default_adapter = nullptr; + for (l = objects; l != NULL; l = l->next) { + Object *object = (Object *) l->data; + Adapter1 *adapter = object_get_adapter1(object); + if (adapter != NULL) { + default_adapter = std::unique_ptr(new BluetoothAdapter(adapter)); + g_object_unref(adapter); + break; + } + } + g_list_free_full(objects, g_object_unref); + + if (default_adapter == nullptr) { + throw BluetoothException("No adapter installed or not recognized by system"); + } +} + +BluetoothManager *BluetoothManager::get_bluetooth_manager() +{ + static BluetoothManager bluetooth_manager; + return &bluetooth_manager; +} + +BluetoothManager::BluetoothManager(const BluetoothManager &) +{ + /* Should not be called */ +} + +BluetoothManager::~BluetoothManager() +{ + /* Should not be called */ +} + +std::vector> BluetoothManager::get_adapters() +{ + std::vector> vector; + GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); + + for (l = objects; l != NULL; l = l->next) { + Object *object = OBJECT(l->data); + + auto p = BluetoothAdapter::make(object); + if (p != nullptr) + vector.push_back(std::move(p)); + } + g_list_free_full(objects, g_object_unref); + + return vector; +} + +std::vector> BluetoothManager::get_devices() +{ + std::vector> vector; + GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); + + for (l = objects; l != NULL; l = l->next) { + Object *object = OBJECT(l->data); + + auto p = BluetoothDevice::make(object); + if (p != nullptr) + vector.push_back(std::move(p)); + } + g_list_free_full(objects, g_object_unref); + + return vector; +} + +std::vector> BluetoothManager::get_services() +{ + std::vector> vector; + GList *l, *objects = g_dbus_object_manager_get_objects(gdbus_manager); + + for (l = objects; l != NULL; l = l->next) { + Object *object = OBJECT(l->data); + + auto p = BluetoothGattService::make(object); + if (p != nullptr) + vector.push_back(std::move(p)); + } + g_list_free_full(objects, g_object_unref); + + return vector; +} + +bool BluetoothManager::set_default_adapter(BluetoothAdapter &adapter) +{ + default_adapter = std::unique_ptr(adapter.clone()); + return true; +} + +std::unique_ptr BluetoothManager::get_default_adapter() +{ + return std::unique_ptr(default_adapter->clone()); +} + +bool BluetoothManager::start_discovery() +{ + if (default_adapter != nullptr) + return default_adapter->start_discovery(); + else + return false; +} + +bool BluetoothManager::stop_discovery() +{ + if (default_adapter != NULL) + return default_adapter->stop_discovery(); + else + return false; +} + +bool BluetoothManager::get_discovering() +{ + if (default_adapter != NULL) + return default_adapter->get_discovering(); + else + return false; +} diff --git a/src/tinyb/BluetoothObject.cpp b/src/tinyb/BluetoothObject.cpp new file mode 100644 index 00000000..2e8ddaf4 --- /dev/null +++ b/src/tinyb/BluetoothObject.cpp @@ -0,0 +1,64 @@ +/* + * Author: Petre Eftime + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "BluetoothObject.hpp" +#include + +using namespace tinyb; + +std::string BluetoothObject::get_java_class() const +{ + return std::string(JAVA_DBUS_PACKAGE "/DBusObject"); +} + +std::string BluetoothObject::get_class_name() const +{ + return std::string("BluetoothObject"); +} + +std::string BluetoothObject::get_object_path() const +{ + return std::string(); +} + +BluetoothType BluetoothObject::get_bluetooth_type() const +{ + return BluetoothType::NONE; +} + +BluetoothObject *BluetoothObject::clone() const +{ + return NULL; +} + +bool BluetoothObject::operator==(const BluetoothObject &other) const +{ + return (this->get_bluetooth_type() == other.get_bluetooth_type()) + && (this->get_object_path() == other.get_object_path()); +} + +bool BluetoothObject::operator!=(const BluetoothObject &other) const +{ + return !(*this == other); +} diff --git a/src/tinyb/BluetoothUUID.cpp b/src/tinyb/BluetoothUUID.cpp new file mode 100644 index 00000000..ce8124a5 --- /dev/null +++ b/src/tinyb/BluetoothUUID.cpp @@ -0,0 +1,89 @@ +#include "BluetoothUUID.hpp" +#include +#include + +using namespace tinyb; + +BluetoothUUID::BluetoothUUID(const BluetoothUUID &other) { + uuid[0] = other.uuid[0]; + uuid[1] = other.uuid[1]; +} + +BluetoothUUID::BluetoothUUID(const char str[]) { + int len = strlen(str); + const char *err_msg = "UUID does not have a valid format"; + + if (len == 4 || len == 8) { + /* 16bit or 32bit UUID: number + base UUID */ + uuid[0] = strtoul(str, NULL, 16) << 32 | 0x00001000ULL; + uuid[1] = 0x800000805f9b34fbULL; + } else if (len == 36) { + /* 128bit UUID */ + char u[37]; + strcpy(u, str); + + if (u[8] == '-') { + u[8] = ' '; + uuid[0] = strtoul(u + 0, NULL, 16) << 32; + } else { + throw std::invalid_argument(err_msg); + } + if (u[13] == '-') { + u[13] = ' '; + uuid[0] = uuid[0] | strtoul(u + 9, NULL, 16) << 16; + } else throw std::invalid_argument(err_msg); + if (u[18] == '-') { + u[18] = ' '; + uuid[0] = uuid[0] | strtoul(u + 14, NULL, 16); + } else throw std::invalid_argument(err_msg); + + if (u[23] == '-') { + u[23] = ' '; + uuid[1] = strtoul(u + 19, NULL, 16) << 48; + } else throw std::invalid_argument(err_msg); + + uuid[1] = uuid[1] | strtoul(u + 24, NULL, 16); + } else throw std::invalid_argument(err_msg); +} + +BluetoothUUID::BluetoothUUID(const std::string &str) : BluetoothUUID(str.c_str()) {} + +std::string BluetoothUUID::get_string() +{ + char u[37]; + snprintf(u, 37, "%08lx-%04llx-%04llx-%04lx-%012llx", + (uuid[0] >> 32), + ((uuid[0] >> 16) & 0xFFFFULL), + (uuid[0] & 0xFFFFULL), + (uuid[1] >> 48), + (uuid[1] & ~(0xFFFFULL << 48))); + return std::string(u); +} + +std::string BluetoothUUID::get_short_string() +{ + char u[9]; + if (is_short()) { + uint32_t suuid = get_short(); + if (suuid & 0xFFFF == suuid) + snprintf(u, 9, "%04dx", suuid); + else + snprintf(u, 9, "%08dx", suuid); + return std::string(u); + } else { + return get_string(); + } +} + +uint32_t BluetoothUUID::get_short() { + if (is_short()) + return uuid[0] >> 32; + return 0; +} + +bool BluetoothUUID::is_short() +{ + if (uuid[1] == 0x800000805f9b34fbULL && uuid[0] & 0xffffffffULL == 0x00001000ULL) + return true; + return false; +} diff --git a/src/tinyb/CMakeLists.txt b/src/tinyb/CMakeLists.txt new file mode 100644 index 00000000..32a9a02e --- /dev/null +++ b/src/tinyb/CMakeLists.txt @@ -0,0 +1,75 @@ +set (tinyb_LIB_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/api + ${PROJECT_SOURCE_DIR}/api/tinyb + ${PROJECT_SOURCE_DIR}/include +) + +include_directories( + ${tinyb_LIB_INCLUDE_DIRS} + ${GLIB2_INCLUDE_DIRS} + ${GIO_INCLUDE_DIRS} + ${GIO-UNIX_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} +) + +set (tinyb_LIB_SRCS + ${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothObject.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothEvent.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothManager.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothAdapter.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothDevice.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothGattService.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothGattCharacteristic.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothGattDescriptor.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothUUID.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb/tinyb_utils.cpp +# autogenerated files + ${CMAKE_CURRENT_BINARY_DIR}/../version.c + ${CMAKE_CURRENT_BINARY_DIR}/orgbluez-dbus.c +) + +set (tinyb_LIB_GLOB_HEADERS + ${PROJECT_SOURCE_DIR}/api/tinyb.hpp +) + +find_program(GDBUS_CODEGEN NAMES gdbus-codegen) +if (NOT GDBUS_CODEGEN) + message(FATAL_ERROR "gdbus-codegen not found") +else () + message(STATUS "gdbus-codegen found") +endif () + +add_custom_command(OUTPUT orgbluez-dbus.c orgbluez-dbus.h + COMMAND ${GDBUS_CODEGEN} + --interface-prefix org.bluez + --generate-c-code orgbluez-dbus + --c-generate-object-manager ${PROJECT_SOURCE_DIR}/src/tinyb/org.bluez.xml + DEPENDS ${PROJECT_SOURCE_DIR}/src/tinyb/org.bluez.xml + COMMENT "Generating dbus code from org.bluez.xml") + +add_library (tinyb SHARED ${tinyb_LIB_SRCS}) +target_link_libraries ( + tinyb + ${CMAKE_THREAD_LIBS_INIT} + ${GLIB2_LIBRARIES} + ${GIO_LIBRARIES} +) + +set_target_properties( + tinyb + PROPERTIES + SOVERSION ${tinyb_VERSION_MAJOR} + VERSION ${tinyb_VERSION_STRING} + CXX_STANDARD 11 +) +install (FILES ${tinyb_LIB_GLOB_HEADERS} DESTINATION include/) +install (DIRECTORY ${PROJECT_SOURCE_DIR}/api/tinyb/ DESTINATION include/tinyb) + +macro (tinyb_CREATE_INSTALL_PKGCONFIG generated_file install_location) + configure_file (${generated_file}.cmake ${CMAKE_CURRENT_BINARY_DIR}/${generated_file} @ONLY) + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${generated_file} DESTINATION ${install_location}) +endmacro (tinyb_CREATE_INSTALL_PKGCONFIG) +tinyb_create_install_pkgconfig (tinyb.pc lib${LIB_SUFFIX}/pkgconfig) + +install(TARGETS tinyb LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + diff --git a/src/tinyb/org.bluez.xml b/src/tinyb/org.bluez.xml new file mode 100644 index 00000000..da200c6b --- /dev/null +++ b/src/tinyb/org.bluez.xml @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tinyb/tinyb.pc.cmake b/src/tinyb/tinyb.pc.cmake new file mode 100644 index 00000000..1c9fbaf8 --- /dev/null +++ b/src/tinyb/tinyb.pc.cmake @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib@LIB_SUFFIX@ +includedir=${prefix}/include + +Name: tinyb +Description: Tiny BLE library +Version: @tinyb_VERSION_STRING@ + +Libs: -L${libdir} -ltinyb +Cflags: -I${includedir} diff --git a/src/tinyb/tinyb_utils.cpp b/src/tinyb/tinyb_utils.cpp new file mode 100644 index 00000000..89c76b81 --- /dev/null +++ b/src/tinyb/tinyb_utils.cpp @@ -0,0 +1,95 @@ +/* + * Author: Andrei Vasiliu + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "tinyb_utils.hpp" +#include "BluetoothException.hpp" + +std::vector tinyb::from_chars_to_vector(const gchar *chars) +{ + std::vector::size_type chars_size = strlen((const char*)chars); + + if (chars_size == 0) + throw std::runtime_error("Trying to read empty value"); + + std::vector result(chars, chars + chars_size); + + return result; +} + +std::vector tinyb::from_gbytes_to_vector(const GBytes *bytes) +{ + gsize result_size; + const unsigned char *aux_array = (const unsigned char *)g_bytes_get_data(const_cast(bytes), &result_size); + + if (aux_array == nullptr || result_size == 0) + throw std::runtime_error("Trying to read empty value"); + + std::vector result(result_size); + std::copy(aux_array, aux_array + result_size, result.begin()); + + return result; +} + +/* it allocates memory - the result that is being returned is from heap */ +GBytes *tinyb::from_vector_to_gbytes(const std::vector& vector) +{ + unsigned int vector_size = vector.size(); + const unsigned char *vector_content = vector.data(); + + GBytes *result = g_bytes_new(vector_content, vector_size); + if (result == nullptr) + throw std::bad_alloc(); + + return result; +} + +std::vector 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 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) { + BluetoothException e(error->message); + g_error_free(error); + throw e; + } +} diff --git a/src/tinyb_hci/CMakeLists.txt b/src/tinyb_hci/CMakeLists.txt new file mode 100644 index 00000000..c5881086 --- /dev/null +++ b/src/tinyb_hci/CMakeLists.txt @@ -0,0 +1,44 @@ +set (tinyb_hci_LIB_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/api + ${PROJECT_SOURCE_DIR}/api/tinyb_hci + ${PROJECT_SOURCE_DIR}/include +) + +include_directories( + ${tinyb_hci_LIB_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} +) + +set (tinyb_hci_LIB_SRCS + ${PROJECT_SOURCE_DIR}/src/tinyb_hci/HCIUtil.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb_hci/UUID.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb_hci/HCITypes.cpp + ${PROJECT_SOURCE_DIR}/src/tinyb_hci/HCIDiscovery.cpp +# autogenerated files + ${CMAKE_CURRENT_BINARY_DIR}/../version.c +) + +add_library (tinyb_hci SHARED ${tinyb_hci_LIB_SRCS}) +target_link_libraries ( + tinyb_hci + ${CMAKE_THREAD_LIBS_INIT} + bluetooth +) + +set_target_properties( + tinyb_hci + PROPERTIES + SOVERSION ${tinyb_VERSION_MAJOR} + VERSION ${tinyb_VERSION_STRING} + CXX_STANDARD 11 +) +install (DIRECTORY ${PROJECT_SOURCE_DIR}/api/tinyb_hci/ DESTINATION include/tinyb_hci) + +macro (tinyb_CREATE_INSTALL_PKGCONFIG generated_file install_location) + configure_file (${generated_file}.cmake ${CMAKE_CURRENT_BINARY_DIR}/${generated_file} @ONLY) + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${generated_file} DESTINATION ${install_location}) +endmacro (tinyb_CREATE_INSTALL_PKGCONFIG) +tinyb_create_install_pkgconfig (tinyb_hci.pc lib${LIB_SUFFIX}/pkgconfig) + +install(TARGETS tinyb_hci LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + diff --git a/src/tinyb_hci/HCIDiscovery.cpp b/src/tinyb_hci/HCIDiscovery.cpp new file mode 100644 index 00000000..9ff35f7d --- /dev/null +++ b/src/tinyb_hci/HCIDiscovery.cpp @@ -0,0 +1,316 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include + +#include "HCITypes.hpp" + +using namespace tinyb_hci; + +#define AD_FLAGS_LIMITED_MODE_BIT 0x01 +#define AD_FLAGS_GENERAL_MODE_BIT 0x02 + +#define AD_TYPE_FLAGS 0x01 /* flags */ +#define AD_TYPE_UUID16_SOME 0x02 /* 16-bit UUID, more available */ +#define AD_TYPE_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ +#define AD_TYPE_UUID32_SOME 0x04 /* 32-bit UUID, more available */ +#define AD_TYPE_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ +#define AD_TYPE_UUID128_SOME 0x06 /* 128-bit UUID, more available */ +#define AD_TYPE_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ + +#define AD_TYPE_NAME_SHORT 0x08 /* shortened local name */ +#define AD_TYPE_NAME_COMPLETE 0x09 /* complete local name */ +#define AD_TYPE_TX_POWER 0x0A /* transmit power level */ +#define AD_TYPE_DEVICE_ID 0x10 /* device ID */ +#define AD_TYPE_MANUFACTURE_SPECIFIC 0xFF + +#define HCI_LE_Advertising_Report 0x3E + +/** + * See Bluetooth Core Specification V5.2 [Vol. 3, Part C, 11, p 1392] + * and Bluetooth Core Specification Supplement V9, Part A: 1, p 9 + 2 Examples, p25.. + * and Assigned Numbers + *

+ * https://www.bluetooth.com/specifications/archived-specifications/ + *

+ */ +static int read_ad_struct_elem(uint8_t *ad_len, uint8_t *ad_type, uint8_t **ad_data, + uint8_t *data, int offset, int size) +{ + if (offset < size) { + uint8_t len = data[offset]; // covers: type + data, less len field itself + + if (len == 0) { + return 0; // end of significant part + } + + if (len + offset > size) { + return -ENOENT; + } + + *ad_type = data[offset + 1]; + *ad_data = data + offset + 2; // net data ptr + *ad_len = len - 1; // less type -> net data length + + return offset + 1 + len; // next ad_struct offset: + len + type + data + } + return -ENOENT; +} + +/** + * See Bluetooth Core Specification V5.2 [Vol. 4, Part E, 7.7.65.2, p 2382] + *

+ * https://www.bluetooth.com/specifications/archived-specifications/ + *

+ */ +bool HCIAdapter::discoverDevices(HCISession& session, int timeoutMS) +{ + bool ok = true; + uint8_t buf[HCI_MAX_EVENT_SIZE]; + struct hci_filter nf, of; + socklen_t olen; + int len_read = -1; + const int64_t t0 = getCurrentMilliseconds(); + + if( !session.isOpen() ) { + fprintf(stderr, "Session not open\n"); + return false; + } + + olen = sizeof(of); + if (getsockopt(session.dd(), SOL_HCI, HCI_FILTER, &of, &olen) < 0) { + fprintf(stderr, "Could not get socket options\n"); + return false; + } + + hci_filter_clear(&nf); + hci_filter_set_ptype(HCI_EVENT_PKT, &nf); + hci_filter_set_event(EVT_LE_META_EVENT, &nf); + + if (setsockopt(session.dd(), SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) { + fprintf(stderr, "Could not set socket options\n"); + return false; + } + + int64_t t1, td; + + while ( ( ( t1 = getCurrentMilliseconds() ) - t0 ) < timeoutMS ) { + uint8_t hci_type; + hci_event_hdr *ehdr; + evt_le_meta_event *meta; + int num_reports, i; + uint8_t *i_octets; + uint8_t ra_evt_type[0x19]; + uint8_t ra_bdaddr_type[0x19]; + bdaddr_t ra_bdaddr[0x19]; + uint8_t ra_length_data[0x19]; + uint8_t *ra_data[0x19]; + uint8_t ra_rssi[0x19]; + std::string ra_address[0x19]; + std::string ra_name_short[0x19]; + std::string ra_name_complete[0x19]; + std::vector> services[0x19]; + + if( timeoutMS ) { + struct pollfd p; + int n; + + p.fd = session.dd(); p.events = POLLIN; + while ((n = poll(&p, 1, timeoutMS)) < 0) { + if (errno == EAGAIN /* || errno == EINTR */ ) { + // cont temp unavail, but end on interruption + continue; + } + ok = false; + goto done; + } + if (!n) { + goto done; // timeout + } + } + + while ((len_read = read(session.dd(), buf, sizeof(buf))) < 0) { + if (errno == EAGAIN /* || errno == EINTR */ ) { + // cont temp unavail, but end on interruption + continue; + } + ok = false; + goto done; + } + + t1 = getCurrentMilliseconds(); + td = t1 - t0; + + // HCI_LE_Advertising_Report == 0x3E == EVT_LE_META_EVENT + hci_type = buf[0]; + fprintf(stderr, "[%7.7" PRId64"] hci-type 0x%.2X\n", td, hci_type); + + ehdr = (hci_event_hdr*)(void*) ( buf + HCI_TYPE_LEN ); + fprintf(stderr, "[%7.7" PRId64"] hci-event-hdr event 0x%.2X, plen %d\n", + td, ehdr->evt, ehdr->plen); + + len_read -= (1 + HCI_EVENT_HDR_SIZE); + meta = (evt_le_meta_event*)(void *) ( buf + ( HCI_TYPE_LEN + HCI_EVENT_HDR_SIZE ) ); + + fprintf(stderr, "[%7.7" PRId64"] hci-subevent 0x%.2X, remaining-len %d\n", + td, meta->subevent, len_read); + + // 0x3E 0x02 + if ( HCI_LE_Advertising_Report != ehdr->evt || meta->subevent != EVT_LE_ADVERTISING_REPORT ) { + continue; // next .. + } + + num_reports = (int) meta->data[0]; + i_octets = meta->data + 1; + fprintf(stderr, "[%7.7" PRId64"] num_reports %d\n", td, num_reports); + + if( 0 >= num_reports || num_reports > 0x19 ) { + ok = false; + continue; // oops ? + } + + for(i = 0; i < num_reports && i < 0x19; i++) { + ra_evt_type[i] = *i_octets++; + } + for(i = 0; i < num_reports && i < 0x19; i++) { + ra_bdaddr_type[i] = *i_octets++; + } + for(i = 0; i < num_reports && i < 0x19; i++) { + char addr[18]; + bacpy( &ra_bdaddr[i], (const bdaddr_t *)i_octets ); + i_octets += 6; + + ba2str( &ra_bdaddr[i], addr ); + ra_address[i] = std::string(addr); + fprintf(stderr, "[%7.7" PRId64"] Address[%d] %s\n", td, i, ra_address[i].c_str()); + } + for(i = 0; i < num_reports && i < 0x19; i++) { + ra_length_data[i] = *i_octets++; + } + for(i = 0; i < num_reports && i < 0x19; i++) { + int offset = 0; + uint8_t ad_len, ad_type, *ad_data; + char name[30]; + size_t name_len; + ra_data[i] = i_octets; + i_octets += ra_length_data[i]; + fprintf(stderr, "[%7.7" PRId64"] AD-Struct[%d] start: size %d\n", td, i, ra_length_data[i]); + + while( 0 < ( offset = read_ad_struct_elem( &ad_len, &ad_type, &ad_data, + ra_data[i], offset, ra_length_data[i] ) ) ) + { + fprintf(stderr, "read_ad_struct_elem: offset %d @ size %d: net ad_len %d, ad_type 0x%.2X\n", + offset, ra_length_data[i], ad_len, ad_type); + + // Guaranteed: ad_len >= 0! + switch ( ad_type ) { + case AD_TYPE_UUID16_SOME: + case AD_TYPE_UUID16_ALL: + for(int j=0; j uuid(new UUID16(ad_data, j*2, true)); + services[i].push_back(std::move(uuid)); + } + break; + case AD_TYPE_UUID32_SOME: + case AD_TYPE_UUID32_ALL: + for(int j=0; j uuid(new UUID32(ad_data, j*4, true)); + services[i].push_back(std::move(uuid)); + } + break; + case AD_TYPE_UUID128_SOME: + case AD_TYPE_UUID128_ALL: + for(int j=0; j uuid(new UUID128(ad_data, j*16, true)); + services[i].push_back(std::move(uuid)); + } + break; + case AD_TYPE_NAME_SHORT: + case AD_TYPE_NAME_COMPLETE: + memset(name, 0, sizeof(name)); + name_len = std::min((size_t)ad_len, sizeof(name) - 1); // less EOS + memcpy(name, ad_data, name_len); + if( AD_TYPE_NAME_COMPLETE == ad_type ) { + ra_name_complete[i] = std::string(name); + } else { + ra_name_short[i] = std::string(name); + } + break; + case AD_TYPE_TX_POWER: + case AD_TYPE_DEVICE_ID: + // ??? + break; + } + } + } + for(i = 0; i < num_reports && i < 0x19; i++) { + ra_rssi[i] = *i_octets++; + } + for(i = 0; i < num_reports && i < 0x19; i++) { + std::string & use_name = ra_name_complete[i].length()>0 ? + ra_name_complete[i] : ra_name_short[i]; + + fprintf(stderr, "[%7.7" PRId64"] Report %d/%d, event-type 0x%.2X\n", td, i, num_reports, ra_evt_type[i]); + fprintf(stderr, "[%7.7" PRId64"] Address %s, name '%s' (short '%s')\n", + td, ra_address[i].c_str(), ra_name_complete[i].c_str(), ra_name_short[i].c_str()); + fprintf(stderr, "[%7.7" PRId64"] RSSI %d\n", td, ra_rssi[i]); + + for(int j=0; j uuid = services[i].at(j); + fprintf(stderr, "[%7.7" PRId64"] UUID[%d] (%d bytes) %s\n", td, j, uuid->type, uuid->toUUID128String().c_str()); + } + + int idx = findDevice(ra_bdaddr[i]); + std::shared_ptr dev; + if( 0 > idx ) { + dev = std::shared_ptr(new HCIDevice(ra_bdaddr[i], use_name, ra_rssi[i])); + addDevice(dev); + } else { + dev = getDevice(idx); + if( ra_name_complete[i].length() > 0 ) { + dev->setName(ra_name_complete[i]); + } else if( !dev->name.length() && ra_name_short[i].length() > 0 ) { + dev->setName(ra_name_short[i]); + } + dev->setLastRSSI(ra_rssi[i]); + } + for(int j=0; j uuid = services[i].at(j); + dev->addService(uuid); + } + } + } + +done: + setsockopt(session.dd(), SOL_HCI, HCI_FILTER, &of, sizeof(of)); + return ok; +} + diff --git a/src/tinyb_hci/HCIScanner.cpp b/src/tinyb_hci/HCIScanner.cpp new file mode 100644 index 00000000..b7ecbe58 --- /dev/null +++ b/src/tinyb_hci/HCIScanner.cpp @@ -0,0 +1,77 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "HCITypes.hpp" + +int main(int argc, char *argv[]) +{ + int err = 0; + std::string sensormac; + + for(int i=1; i (i+1) ) { + sensormac = std::string(argv[++i]); + } + } + if( 17 != sensormac.length() ) { + fprintf(stderr, "Usage: %s -mac 00:00:00:00:00:00\n", argv[0]); + exit(1); + } + + tinyb_hci::HCIAdapter adapter; // default + if( !adapter.hasDevId() ) { + fprintf(stderr, "Default adapter not available.\n"); + exit(1); + } + if( !adapter.isValid() ) { + fprintf(stderr, "Adapter invalid.\n"); + exit(1); + } + fprintf(stderr, "Adapter: device %s, address %s\n", + adapter.getName().c_str(), adapter.getAddress().c_str()); + + while( !err ) { + std::shared_ptr session = adapter.startDiscovery(); + if( nullptr == session ) { + fprintf(stderr, "Adapter start discovery failed.\n"); + exit(1); + } + + // do something + if( !adapter.discoverDevices(*session, 10000) ) { + fprintf(stderr, "Adapter discovery failed.\n"); + err = 1; + } + + if( !adapter.stopDiscovery(*session) ) { + fprintf(stderr, "Adapter stop discovery failed.\n"); + err = 1; + } + } + +out: + return err; +} + diff --git a/src/tinyb_hci/HCITypes.cpp b/src/tinyb_hci/HCITypes.cpp new file mode 100644 index 00000000..c6870111 --- /dev/null +++ b/src/tinyb_hci/HCITypes.cpp @@ -0,0 +1,283 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "HCITypes.hpp" + +using namespace tinyb_hci; + +// ************************************************* +// ************************************************* +// ************************************************* + +HCIDevice::HCIDevice(const bdaddr_t &mac, const std::string &name, uint8_t rssi) +: mac(mac), rssi(rssi), name(name) +{ +} + +std::string HCIDevice::getAddress() const { + if( valid ) { + char sa[18]; + ba2str(&mac, sa); + return std::string(sa); + } else { + return std::string(); + } +} + +void HCIDevice::addService(std::shared_ptr const &uuid) +{ + if( 0 > findService(uuid) ) { + services.push_back(uuid); + } +} + +int HCIDevice::findService(std::shared_ptr const &uuid) const +{ + auto begin = services.begin(); + auto it = std::find_if(begin, services.end(), [&](std::shared_ptr const& p) { + return *p == *uuid; + }); + if ( it == std::end(services) ) { + return -1; + } else { + return std::distance(begin, it); + } +} + +std::string HCIDevice::toString() const { + std::string out("Device["+getAddress()+", "+getName()+", rssi "+std::to_string(getLastRSSI())+"]"); + if(services.size() > 0 ) { + out.append("\n"); + for(auto it = services.begin(); it != services.end(); it++) { + std::shared_ptr p = *it; + out.append(" ").append(p->toUUID128String()).append(", ").append(std::to_string(static_cast(p->type))).append(" bytes\n"); + } + } + return out; +} + +// ************************************************* +// ************************************************* +// ************************************************* + +int HCIAdapter::getDefaultDevId() { + return hci_get_route(NULL); +} +int HCIAdapter::getDevId(bdaddr_t &bdaddr) { + return hci_get_route(&bdaddr); +} +int HCIAdapter::getDevId(const std::string &hcidev) { + return hci_devid(hcidev.c_str()); +} + +bool HCIAdapter::validateDevInfo() { + memset(&dev_info, 0, sizeof(dev_info)); + if( 0 > dev_id ) { + return false; + } + if( 0 > hci_devinfo(dev_id, &dev_info) ) { + return false; + } + return true; +} + +void HCIAdapter::sessionClosed(HCISession& s) +{ + auto it = std::find_if(sessions.begin(), sessions.end(), [&](std::shared_ptr const& p) { + return *p == s; + }); + if ( it != std::end(sessions) ) { + sessions.erase(it); + } +} + +HCIAdapter::HCIAdapter() +: dev_id(getDefaultDevId()) +{ + valid = validateDevInfo(); +} + +HCIAdapter::HCIAdapter(bdaddr_t &mac) +: dev_id(getDevId(mac)) +{ + valid = validateDevInfo(); +} + +HCIAdapter::HCIAdapter(const std::string &hcidev) +: dev_id(getDevId(hcidev)) +{ + valid = validateDevInfo(); +} + +HCIAdapter::HCIAdapter(const int dev_id) +: dev_id(dev_id) +{ + valid = validateDevInfo(); +} + +HCIAdapter::~HCIAdapter() { + discoveredDevices.clear(); + sessions.clear(); +} + +std::string HCIAdapter::getAddress() const { + if( valid ) { + char sa[18]; + ba2str(&dev_info.bdaddr, sa); + return std::string(sa); + } else { + return std::string(); + } +} + +std::string HCIAdapter::getName() const { + if( valid ) { + return std::string(dev_info.name); + } else { + return std::string(); + } +} + +std::shared_ptr HCIAdapter::open() +{ + if( !valid ) { + return nullptr; + } + int dd = hci_open_dev(dev_id); + if( 0 > dd ) { + perror("Could not open device"); + return nullptr; + } + std::shared_ptr s(new HCISession(*this, dd)); + sessions.push_back(s); + return s; +} + +std::shared_ptr HCIAdapter::startDiscovery() { + const uint8_t own_type = LE_PUBLIC_ADDRESS; + const uint8_t scan_type = 0x01; + const uint8_t filter_type = 0; + const uint8_t filter_policy = 0x00; + const uint16_t interval = htobs(0x0010); + const uint16_t window = htobs(0x0010); + const uint8_t filter_dup = 0x01; + + std::shared_ptr session = open(); + if( nullptr == session ) { + return nullptr; + } + + if( !session->isOpen() ) { + fprintf(stderr, "New session not open\n"); + return nullptr; + } + int err = hci_le_set_scan_parameters(session->dd(), scan_type, interval, window, + own_type, filter_policy, to_send_req_poll_ms); + if (err < 0) { + perror("Set scan parameters failed"); + session->close(); + return nullptr; + } + + err = hci_le_set_scan_enable(session->dd(), 0x01, filter_dup, to_send_req_poll_ms); + if (err < 0) { + perror("Start scan failed"); + session->close(); + return nullptr; + } + return session; +} + +bool HCIAdapter::stopDiscovery(HCISession& session) { + const uint8_t filter_dup = 0x01; + + if( !session.isOpen() ) { + fprintf(stderr, "Session not open\n"); + return false; + } + bool res; + if( 0 > hci_le_set_scan_enable(session.dd(), 0x00, filter_dup, to_send_req_poll_ms) ) { + perror("Stop scan failed"); + res = false; + } else { + res = true; + } + session.close(); + return res; +} + +void HCIAdapter::addDevice(std::shared_ptr const &device) { + if( 0 > findDevice(device->mac) ) { + discoveredDevices.push_back(device); + } +} + +int HCIAdapter::findDevice(bdaddr_t const & mac) const { + auto begin = discoveredDevices.begin(); + auto it = std::find_if(begin, discoveredDevices.end(), [&](std::shared_ptr const& p) { + return !bacmp(&p->mac, &mac); + }); + if ( it == std::end(discoveredDevices) ) { + return -1; + } else { + return std::distance(begin, it); + } +} + +std::string HCIAdapter::toString() const { + std::string out("Adapter["+getAddress()+", "+getName()+", id="+std::to_string(dev_id)+"]"); + if(discoveredDevices.size() > 0 ) { + out.append("\n"); + for(auto it = discoveredDevices.begin(); it != discoveredDevices.end(); it++) { + std::shared_ptr p = *it; + out.append(" ").append(p->toString()).append("\n"); + } + } + return out; +} + +// ************************************************* +// ************************************************* +// ************************************************* + +std::atomic_int HCISession::name_counter(0); + +bool HCISession::close() +{ + if( 0 > _dd ) { + return false; + } + hci_close_dev(_dd); + _dd = -1; + adapter.sessionClosed(*this); + return true; +} + diff --git a/src/tinyb_hci/HCIUtil.cpp b/src/tinyb_hci/HCIUtil.cpp new file mode 100644 index 00000000..f03cb213 --- /dev/null +++ b/src/tinyb_hci/HCIUtil.cpp @@ -0,0 +1,143 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "HCIUtil.hpp" + +// #define _USE_BACKTRACE_ 1 + +#if _USE_BACKTRACE_ +extern "C" { + #include +} +#endif + +using namespace tinyb_hci; + +static const int64_t NanoPerMilli = 1000000L; +static const int64_t MilliPerOne = 1000L; + +/** + * See + *

+ * Regarding avoiding kernel via VDSO, + * see , + * clock_gettime seems to be well supported at least on kernel >= 4.4. + * Only bfin and sh are missing, while ia64 seems to be complicated. + */ +int64_t tinyb_hci::getCurrentMilliseconds() { + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + return t.tv_sec * MilliPerOne + t.tv_nsec / NanoPerMilli; +} + +const char* RuntimeException::what() const noexcept { +#if _USE_BACKTRACE_ + std::string out(msg); + void *buffers[10]; + size_t nptrs = backtrace(buffers, 10); + char **symbols = backtrace_symbols(buffers, nptrs); + if( NULL != symbols ) { + out.append("\nBacktrace:\n"); + for(int i=0; i uuid16_le_octet_index || uuid16_le_octet_index > 14 ) { + std::string msg("uuid16_le_octet_index "); + msg.append(std::to_string(uuid16_le_octet_index)); + msg.append(", not within [0..14]"); + throw IllegalArgumentException(msg); + } + uint128_t dest = base_uuid; + + // base_uuid: 00000000-0000-1000-8000-00805F9B34FB + // uuid16: DCBA + // uuid16_le_octet_index: 12 + // result: 0000DCBA-0000-1000-8000-00805F9B34FB + // + // LE: low-mem - FB349B5F8000-0080-0010-0000-ABCD0000 - high-mem + // ^ index 12 + // LE: uuid16 -> value.data[12+13] + // + // BE: low-mem - 0000DCBA-0000-1000-8000-00805F9B34FB - high-mem + // ^ index 2 + // BE: uuid16 -> value.data[2+3] + // +#if __BYTE_ORDER == __BIG_ENDIAN + int offset = 15 - 1 - uuid16_le_octet_index; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + int offset = uuid16_le_octet_index; +#else +#error "Unexpected __BYTE_ORDER" +#endif + uint16_t * destu16 = (uint16_t*)(dest.data + offset); + *destu16 += uuid16; + return dest; +} + +uint128_t tinyb_hci::merge_uint128(uint128_t const & base_uuid, uint32_t const uuid32, int const uuid32_le_octet_index) +{ + if( 0 > uuid32_le_octet_index || uuid32_le_octet_index > 12 ) { + std::string msg("uuid32_le_octet_index "); + msg.append(std::to_string(uuid32_le_octet_index)); + msg.append(", not within [0..12]"); + throw IllegalArgumentException(msg); + } + uint128_t dest = base_uuid; + + // base_uuid: 00000000-0000-1000-8000-00805F9B34FB + // uuid32: 87654321 + // uuid32_le_octet_index: 12 + // result: 87654321-0000-1000-8000-00805F9B34FB + // + // LE: low-mem - FB349B5F8000-0080-0010-0000-12345678 - high-mem + // ^ index 12 + // LE: uuid32 -> value.data[12..15] + // + // BE: low-mem - 87654321-0000-1000-8000-00805F9B34FB - high-mem + // ^ index 0 + // BE: uuid32 -> value.data[0..3] + // +#if __BYTE_ORDER == __BIG_ENDIAN + int offset = 15 - 3 - uuid32_le_octet_index; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + int offset = uuid32_le_octet_index; +#else +#error "Unexpected __BYTE_ORDER" +#endif + uint32_t * destu32 = (uint32_t*)(dest.data + offset); + *destu32 += uuid32; + return dest; +} + diff --git a/src/tinyb_hci/HCItemp.cpp b/src/tinyb_hci/HCItemp.cpp new file mode 100644 index 00000000..28c9a8a8 --- /dev/null +++ b/src/tinyb_hci/HCItemp.cpp @@ -0,0 +1,34 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "HCITypes.hpp" + +using namespace tinyb_hci; + + diff --git a/src/tinyb_hci/UUID.cpp b/src/tinyb_hci/UUID.cpp new file mode 100644 index 00000000..6f72f228 --- /dev/null +++ b/src/tinyb_hci/UUID.cpp @@ -0,0 +1,113 @@ +/* + * Author: Sven Gothel + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "UUID.hpp" + +using namespace tinyb_hci; + +// BASE_UUID '00000000-0000-1000-8000-00805F9B34FB' +static uint8_t bt_base_uuid_be[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }; +UUID128 tinyb_hci::BT_BASE_UUID = UUID128( bt_base_uuid_be ); + +UUID128::UUID128(UUID128 const & base_uuid, UUID16 const & uuid16, int const uuid16_le_octet_index) +: UUID(Type::UUID128), value(merge_uint128(base_uuid.value, uuid16.value, uuid16_le_octet_index)) {} + +UUID128::UUID128(UUID128 const & base_uuid, UUID32 const & uuid32, int const uuid32_le_octet_index) +: UUID(Type::UUID128), value(merge_uint128(base_uuid.value, uuid32.value, uuid32_le_octet_index)) {} + +std::string UUID16::toString() const { + char buffer[4+1]; + int count = snprintf(buffer, sizeof(buffer), "%.4X", value); + if( 4 != count ) { + std::string msg("UUID string not of length 4 but "); + msg.append(std::to_string(count)); + throw InternalError(msg); + } + return std::string(buffer); +} + +std::string UUID16::toUUID128String(UUID128 const & base_uuid, int const le_octet_index) const +{ + UUID128 u128(base_uuid, *this, le_octet_index); + return u128.toString(); +} + +std::string UUID32::toString() const { + char buffer[8+1]; + int count = snprintf(buffer, sizeof(buffer), "%.8X", value); + if( 8 != count ) { + std::string msg("UUID string not of length 8 but "); + msg.append(std::to_string(count)); + throw InternalError(msg); + } + return std::string(buffer); +} + +std::string UUID32::toUUID128String(UUID128 const & base_uuid, int const le_octet_index) const +{ + UUID128 u128(base_uuid, *this, le_octet_index); + return u128.toString(); +} + +std::string UUID128::toString() const { + // 87654321-0000-1000-8000-00805F9B34FB + // 0 1 2 3 4 5 + // LE: low-mem - FB349B5F0800-0080-0010-0000-12345678 - high-mem + // 5 4 3 2 1 0 + // + // BE: low-mem - 87654321-0000-1000-8000-00805F9B34FB - high-mem + // 0 1 2 3 4 5 + // + char buffer[36+1]; + uint32_t part0, part4; + uint16_t part1, part2, part3, part5; +#if __BYTE_ORDER == __BIG_ENDIAN + part0 = get_uint32(value.data, 0); + part1 = get_uint16(value.data, 4); + part2 = get_uint16(value.data, 6); + part3 = get_uint16(value.data, 8); + part4 = get_uint32(value.data, 10); + part5 = get_uint16(value.data, 14); +#elif __BYTE_ORDER == __LITTLE_ENDIAN + part5 = get_uint16(value.data, 0); + part4 = get_uint32(value.data, 2); + part3 = get_uint16(value.data, 6); + part2 = get_uint16(value.data, 8); + part1 = get_uint16(value.data, 10); + part0 = get_uint32(value.data, 12); +#else +#error "Unexpected __BYTE_ORDER" +#endif + int count = snprintf(buffer, sizeof(buffer), "%.8X-%.4X-%.4X-%.4X-%.8X%.4X", + part0, part1, part2, part3, part4, part5); + if( 36 != count ) { + std::string msg("UUID string not of length 36 but "); + msg.append(std::to_string(count)); + throw InternalError(msg, E_FILE_LINE); + } + return std::string(buffer); +} + diff --git a/src/tinyb_hci/tinyb_hci.pc.cmake b/src/tinyb_hci/tinyb_hci.pc.cmake new file mode 100644 index 00000000..8a18a64e --- /dev/null +++ b/src/tinyb_hci/tinyb_hci.pc.cmake @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib@LIB_SUFFIX@ +includedir=${prefix}/include/tinyb_hci + +Name: tinyb_hci +Description: Tiny BLE HCI library +Version: @tinyb_VERSION_STRING@ + +Libs: -L${libdir} -ltinyb +Cflags: -I${includedir} diff --git a/src/tinyb_utils.cpp b/src/tinyb_utils.cpp deleted file mode 100644 index 89c76b81..00000000 --- a/src/tinyb_utils.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Author: Andrei Vasiliu - * Copyright (c) 2015 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "tinyb_utils.hpp" -#include "BluetoothException.hpp" - -std::vector tinyb::from_chars_to_vector(const gchar *chars) -{ - std::vector::size_type chars_size = strlen((const char*)chars); - - if (chars_size == 0) - throw std::runtime_error("Trying to read empty value"); - - std::vector result(chars, chars + chars_size); - - return result; -} - -std::vector tinyb::from_gbytes_to_vector(const GBytes *bytes) -{ - gsize result_size; - const unsigned char *aux_array = (const unsigned char *)g_bytes_get_data(const_cast(bytes), &result_size); - - if (aux_array == nullptr || result_size == 0) - throw std::runtime_error("Trying to read empty value"); - - std::vector result(result_size); - std::copy(aux_array, aux_array + result_size, result.begin()); - - return result; -} - -/* it allocates memory - the result that is being returned is from heap */ -GBytes *tinyb::from_vector_to_gbytes(const std::vector& vector) -{ - unsigned int vector_size = vector.size(); - const unsigned char *vector_content = vector.data(); - - GBytes *result = g_bytes_new(vector_content, vector_size); - if (result == nullptr) - throw std::bad_alloc(); - - return result; -} - -std::vector 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 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) { - BluetoothException e(error->message); - g_error_free(error); - throw e; - } -} -- cgit v1.2.3