From 441cd0b11186d66493798551e1102eb246f1af9f Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Tue, 30 Jun 2015 14:37:06 +0200 Subject: Getting started on a port to OSX. --- CMakeLists.txt | 18 ++++ apps/CMakeLists.txt | 12 +++ apps/apps.cpp | 13 +++ apps/apps.h | 6 ++ apps/ble-inspect-device.h | 2 +- apps/ble-scan.h | 11 +-- apps/generate.cpp | 1 + apps/launcher.cpp | 1 + apps/sm-get-value.h | 6 +- ble/Bluetooth.cpp | 25 ++++-- ble/BluetoothImpl.h | 14 ++-- ble/CMakeLists.txt | 21 ++++- ble/LinuxBluetooth.cpp | 6 +- ble/OsxBluetooth.h | 39 +++++++++ ble/OsxBluetooth.mm | 181 ++++++++++++++++++++++++++++++++++++++++ include/ble/Bluetooth.h | 14 ++-- sensor/CMakeLists.txt | 8 +- sensor/include/trygvis/sensor.h | 1 + test/ByteBufferTest.cpp | 1 + 19 files changed, 341 insertions(+), 39 deletions(-) create mode 100644 ble/OsxBluetooth.h create mode 100644 ble/OsxBluetooth.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 9da7eb6..e4530c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,24 @@ cmake_minimum_required(VERSION 2.8.4) project(ble_toys C CXX) + +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(IS_APPLE "YES") +else() + set(IS_APPLE "NO") +endif() + +if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(IS_LINUX "YES") +else() + set(IS_LINUX "NO") +endif() + +message(STATUS "IS_LINUX ${IS_LINUX}") +message(STATUS "IS_APPLE ${IS_APPLE}") + +if(IS_LINUX) find_package(PkgConfig) +endif() # Use Clang by default: http://stackoverflow.com/a/7031553/245614 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 01252cf..a7defa2 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -3,8 +3,10 @@ list(APPEND APPS ble-scan) list(APPEND APPS sample-add-timestamp) list(APPEND APPS sample-convert) list(APPEND APPS sample-select) +if(IS_LINUX) list(APPEND APPS sm-db-insert) list(APPEND APPS sm-db-select) +endif() list(APPEND APPS sm-get-value) list(APPEND APPS sm-serial-read) list(APPEND APPS sm-serial-read-all) @@ -12,6 +14,7 @@ list(APPEND APPS sm-serial-read-all) # Boost find_package(Boost COMPONENTS regex system program_options REQUIRED) +if(IS_LINUX) # Bluez pkg_check_modules(BLUEZ bluez REQUIRED) @@ -19,6 +22,8 @@ pkg_check_modules(BLUEZ bluez REQUIRED) find_package(Threads REQUIRED) pkg_check_modules(PQXX libpqxx REQUIRED) +elseif() +endif() find_path(LOG4CPLUS_INCLUDE_DIRECTORIES log4cplus/logger.h) if(LOG4CPLUS_INCLUDE_DIRECTORIES MATCHES NOTFOUND) @@ -47,6 +52,12 @@ list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/generated/apps-list.gen.h) list(APPEND SOURCES SoilMoisture.cpp SoilMoisture.h) list(APPEND SOURCES apps.cpp apps.h) +if(IS_LINUX) + list(APPEND COMPILE_OPTIONS -DIS_LINUX) +elseif(IS_APPLE) + list(APPEND COMPILE_OPTIONS -DIS_APPLE) +endif() + add_executable(launcher launcher.cpp ${SOURCES} ${APPS_SOURCES}) @@ -65,6 +76,7 @@ target_link_libraries(launcher ${BLUEZ_LIBRARIES}) target_link_libraries(launcher ${PQXX_LIBRARIES}) target_link_libraries(launcher ${LOG4CPLUS_LIBRARIES}) target_link_libraries(launcher ${CMAKE_THREAD_LIBS_INIT}) +target_compile_options(launcher PRIVATE -Wno-deprecated-register ${COMPILE_OPTIONS}) foreach(app ${APPS}) add_custom_command( diff --git a/apps/apps.cpp b/apps/apps.cpp index e0bb631..0034ba9 100644 --- a/apps/apps.cpp +++ b/apps/apps.cpp @@ -8,6 +8,19 @@ using namespace log4cplus; using namespace std; namespace po = boost::program_options; +static string adapter_name; + +void add_ble_options(po::options_description &options) { + po::options_description bluetooth("Bluetooth"); + + bluetooth.add_options() + ("adapter", po::value(&adapter_name), "Which local adapter to use"); +} + +std::string ble_adapter_name() { + return adapter_name; +} + std::string get_hostname() { static string s = ""; diff --git a/apps/apps.h b/apps/apps.h index 7569a9f..b4de0a0 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -4,7 +4,9 @@ #include #include #include "json.hpp" +#include "ble/Bluetooth.h" #include +#include namespace trygvis { namespace apps { @@ -63,6 +65,10 @@ public: const std::string app_name; }; +void add_ble_options(po::options_description &options); + +std::string ble_adapter_name(); + std::string get_hostname(); template diff --git a/apps/ble-inspect-device.h b/apps/ble-inspect-device.h index 346f9be..d6f7255 100644 --- a/apps/ble-inspect-device.h +++ b/apps/ble-inspect-device.h @@ -56,7 +56,7 @@ public: try { Mac mac = Mac::parseMac(mac_str); - shared_ptr adapter = getAdapter(0); + shared_ptr adapter = bluetoothSystem.getAdapter(ble_adapter_name()); BluetoothDevice &device = adapter->getDevice(mac); diff --git a/apps/ble-scan.h b/apps/ble-scan.h index 9a72388..cd1d979 100644 --- a/apps/ble-scan.h +++ b/apps/ble-scan.h @@ -28,9 +28,8 @@ public: ~ble_scan() = default; - void add_options(po::options_description_easy_init &options) override { - options - ("adapter", po::value()->default_value(0), "Which adapter to use."); + void add_extra_options(po::options_description & options) { + add_ble_options(options); } int main(app_execution &execution) override { @@ -50,13 +49,11 @@ public: sigaction(SIGINT, &sigIntHandler, NULL); try { - auto adapter_index = execution.vm["adapter"].as(); - - adapter = getAdapter(adapter_index); + adapter = bluetoothSystem.getAdapter(ble_adapter_name()); set seen_devices; - cout << "Scanning with adapter #" << adapter_index << ", mac=" << adapter->getMac().str() << endl; + cout << "Scanning with adapter " << adapter->getName() << ", mac=" << adapter->getMac().str() << endl; adapter->runScan([&](BluetoothDevice &device) { auto mac = device.getMac(); diff --git a/apps/generate.cpp b/apps/generate.cpp index 9dcc271..89272d4 100644 --- a/apps/generate.cpp +++ b/apps/generate.cpp @@ -2,6 +2,7 @@ #include #include #include +#include using namespace std; diff --git a/apps/launcher.cpp b/apps/launcher.cpp index 2a1e039..e20a6db 100644 --- a/apps/launcher.cpp +++ b/apps/launcher.cpp @@ -2,6 +2,7 @@ #include "apps-list.gen.h" #include #include +#include namespace trygvis { namespace apps { diff --git a/apps/sm-get-value.h b/apps/sm-get-value.h index 0535f68..58e7005 100644 --- a/apps/sm-get-value.h +++ b/apps/sm-get-value.h @@ -53,6 +53,10 @@ public: ("format", default_format, "Output format"); } + void add_extra_options(po::options_description & options) override { + add_ble_options(options); + } + int main(app_execution &execution) override { __attribute__((unused)) BluetoothSystem bluetoothSystem; @@ -71,7 +75,7 @@ public: Mac mac = Mac::parseMac(MAC); - auto adapter = getAdapter(0); + auto adapter = bluetoothSystem.getAdapter(ble_adapter_name()); auto &device = adapter->getDevice(mac); diff --git a/ble/Bluetooth.cpp b/ble/Bluetooth.cpp index 14a8cda..48fc87c 100644 --- a/ble/Bluetooth.cpp +++ b/ble/Bluetooth.cpp @@ -4,6 +4,12 @@ #include #include +#if defined(IS_LINUX) +#include "LinuxBluetooth.h" +#elif defined(IS_APPLE) +#include "OsxBluetooth.h" +#endif + namespace trygvis { namespace bluetooth { using namespace std; @@ -201,19 +207,26 @@ BluetoothAdapter::BluetoothAdapter() { BluetoothAdapter::~BluetoothAdapter() { } +// ----------------------------------------------------------------------- +// BluetoothSystem +// ----------------------------------------------------------------------- + BluetoothSystem::BluetoothSystem() { } BluetoothSystem::~BluetoothSystem() { - shutdown(); } -shared_ptr getAdapter(int hciDevice) { - return getAdapterImpl(hciDevice); -} +shared_ptr BluetoothSystem::getAdapter(string adapter_name) { +#if defined(IS_LINUX) + typedef linux::LinuxBluetoothAdapter Impl; +#elif defined(IS_APPLE) + typedef osx::OsxBluetoothAdapter Impl; + + shared_ptr adapter = osx::getAdapterImpl(); +#endif -void shutdown() { - shutdownImpl(); + return std::static_pointer_cast(std::move(adapter)); } uuid_t makeUuid(const uuid_t base, uint8_t a, uint8_t b) { diff --git a/ble/BluetoothImpl.h b/ble/BluetoothImpl.h index 3f4615e..648961f 100644 --- a/ble/BluetoothImpl.h +++ b/ble/BluetoothImpl.h @@ -221,9 +221,14 @@ protected: class DefaultBluetoothAdapter : protected LogSetup, public BluetoothAdapter { public: + + string getName() override { + return _name; + }; + protected: - DefaultBluetoothAdapter(Mac &mac) : - LogSetup("BluetoothAdapter"), mac(mac) { + DefaultBluetoothAdapter(const string name, Mac &mac) : + LogSetup("BluetoothAdapter"), _name(name), mac(mac) { } Mac const &getMac() override { @@ -231,12 +236,9 @@ protected: }; Mac &mac; + const string _name; }; -shared_ptr getAdapterImpl(int hciDevice); - -void shutdownImpl(); - } }; diff --git a/ble/CMakeLists.txt b/ble/CMakeLists.txt index 543e85d..5f20a21 100644 --- a/ble/CMakeLists.txt +++ b/ble/CMakeLists.txt @@ -1,4 +1,21 @@ -file(GLOB SOURCE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp *.h) +list(APPEND SOURCE_FILES Bluetooth.cpp) +list(APPEND SOURCE_FILES BluetoothImpl.h) +list(APPEND SOURCE_FILES ByteBuffer.cpp) +list(APPEND SOURCE_FILES log.h) +list(APPEND SOURCE_FILES "${PROJECT_SOURCE_DIR}/include/ble/Bluetooth.h") +list(APPEND SOURCE_FILES "${PROJECT_SOURCE_DIR}/include/ble/ByteBuffer.h") + +if(IS_LINUX) + list(APPEND SOURCE_FILES LinuxBluetooth.cpp LinuxBluetooth.h) + list(APPEND COMPILE_OPTIONS -DIS_LINUX) +elseif(IS_APPLE) + list(APPEND SOURCE_FILES OsxBluetooth.mm OsxBluetooth.h) + list(APPEND COMPILE_OPTIONS -DIS_APPLE) +endif() + +find_package(Boost COMPONENTS regex system program_options REQUIRED) add_library(ble ${SOURCE_FILES}) -include_directories("${PROJECT_SOURCE_DIR}/include") +target_include_directories(ble PUBLIC "${PROJECT_SOURCE_DIR}/include") +target_include_directories(ble PUBLIC "${Boost_INCLUDE_DIRS}") +target_compile_options(ble PRIVATE -Wno-deprecated-register ${COMPILE_OPTIONS}) diff --git a/ble/LinuxBluetooth.cpp b/ble/LinuxBluetooth.cpp index d48bfcd..4450d4d 100644 --- a/ble/LinuxBluetooth.cpp +++ b/ble/LinuxBluetooth.cpp @@ -22,8 +22,6 @@ class LinuxBluetoothGatt; class LinuxBluetoothDevice; -class LinuxBluetoothAdapter; - class LinuxBluetoothManager; class LinuxBluetoothAdapter : public DefaultBluetoothAdapter { @@ -207,7 +205,7 @@ void LinuxBluetoothGatt::disconnect() { close(l2cap); } -uuid_t readUuid(BluetoothDevice *device, const ByteBuffer &bytes) { +static uuid_t readUuid(BluetoothDevice *device, const ByteBuffer &bytes) { size_t bytesLeft = bytes.getBytesLeft(); uuid_t u; @@ -437,7 +435,7 @@ LinuxBluetoothAdapter::LinuxBluetoothAdapter(int hciDeviceId, Mac &mac) : Defaul } LinuxBluetoothAdapter::~LinuxBluetoothAdapter() { - LOG_DEBUG("Stopping scan on device #" << hciDeviceId); + LOG_DEBUG("Closing adapter"); stopScan(); diff --git a/ble/OsxBluetooth.h b/ble/OsxBluetooth.h new file mode 100644 index 0000000..8fa06a9 --- /dev/null +++ b/ble/OsxBluetooth.h @@ -0,0 +1,39 @@ +#ifndef OSX_BLUETOOTH_H +#define OSX_BLUETOOTH_H + +#include + +namespace trygvis { +namespace bluetooth { +namespace osx { + +class OsxBluetoothDevice; + +class OsxBluetoothAdapter : public DefaultBluetoothAdapter { +public: + OsxBluetoothAdapter(const string name, Mac &mac); + + ~OsxBluetoothAdapter(); + + void startScan() override; + + void stopScan() override; + + void runScan(std::function) override; + + BluetoothDevice &getDevice(Mac &mac) override; + +private: + bool scanning; + + map devices; +}; + +shared_ptr&& getAdapterImpl(); +void shutdownImpl(); + +} +} +} + +#endif diff --git a/ble/OsxBluetooth.mm b/ble/OsxBluetooth.mm new file mode 100644 index 0000000..e94edaf --- /dev/null +++ b/ble/OsxBluetooth.mm @@ -0,0 +1,181 @@ +#import +#import +#import +#import + +#import "BluetoothImpl.h" +#import "OsxBluetooth.h" + +#include +using namespace std; + +namespace trygvis { +namespace bluetooth { +namespace osx { + +class OsxBluetoothDevice; +class OsxBluetoothGatt; + +class OsxBluetoothDevice : public DefaultBluetoothDevice { +public: + OsxBluetoothDevice(OsxBluetoothAdapter &adapter, Mac &mac); + + ~OsxBluetoothDevice(); + + shared_ptr connectGatt() override; + +private: + weak_ptr gatt; +}; + +class OsxBluetoothGatt : public DefaultBluetoothGatt { +public: + OsxBluetoothGatt(OsxBluetoothDevice &device); + + ~OsxBluetoothGatt(); + + OsxBluetoothGatt(const OsxBluetoothGatt&) = delete; + + OsxBluetoothGatt& operator=(const OsxBluetoothGatt&) = delete; + + bool isConnected() const override; + + void discoverServices() override; + + void writeValue(const BluetoothGattCharacteristic &c, const ByteBuffer &bytes) override; + + ByteBuffer readValue(const BluetoothGattCharacteristic &c) override; + +private: + void connect(); + + void disconnect(); + + vector discoverServices(uint16_t startHandle); + + vector discoverCharacteristics(uint16_t startHandle, uint16_t endHandle); + + ByteBuffer writeAndRead(ByteBuffer &out, shared_ptr buffer, size_t size); + + int l2cap; + + bool connected; +}; + +OsxBluetoothAdapter::OsxBluetoothAdapter(const string name, Mac &mac) : DefaultBluetoothAdapter(name, mac) { +} + +OsxBluetoothAdapter::~OsxBluetoothAdapter() { +} + +void OsxBluetoothAdapter::startScan() { +} + +void OsxBluetoothAdapter::stopScan() { +} + +void OsxBluetoothAdapter::runScan(std::function) { +} + +BluetoothDevice &OsxBluetoothAdapter::getDevice(Mac &mac) { + map::iterator it = devices.find(mac); + + if (it == devices.end()) { + OsxBluetoothDevice *device = new OsxBluetoothDevice(*this, mac); + devices[mac] = device; + return *device; + } + + return *it->second; +} + +OsxBluetoothDevice::OsxBluetoothDevice(OsxBluetoothAdapter &adapter, Mac &mac) : DefaultBluetoothDevice(adapter, mac) { +} + +OsxBluetoothDevice::~OsxBluetoothDevice() { +} + +shared_ptr OsxBluetoothDevice::connectGatt() { + if (auto p = gatt.lock()) { + return p; + } + auto ref = make_shared(*this); + + gatt = ref; + + return ref; +} + +// ----------------------------------------------------------------------- +// Gatt +// ----------------------------------------------------------------------- + +OsxBluetoothGatt::OsxBluetoothGatt(OsxBluetoothDevice &device) : + DefaultBluetoothGatt(device) { + connect(); +} + +OsxBluetoothGatt::~OsxBluetoothGatt() { + disconnect(); +} + +bool OsxBluetoothGatt::isConnected() const { + return connected; +} + +void OsxBluetoothGatt::connect() { +} + +void OsxBluetoothGatt::disconnect() { + if (!connected) { + return; + } +} + +void OsxBluetoothGatt::writeValue(const BluetoothGattCharacteristic &c, const ByteBuffer &bytes) { +} + +ByteBuffer OsxBluetoothGatt::readValue(const BluetoothGattCharacteristic &c) { + shared_ptr buffer(new uint8_t[0]); + + return ByteBuffer(buffer, 0); +} + +void OsxBluetoothGatt::discoverServices() { +} + +/* +ByteBuffer OsxBluetoothGatt::writeAndRead(ByteBuffer &out, shared_ptr buffer, size_t size) { +} + +vector OsxBluetoothGatt::discoverServices(uint16_t startHandle) { +} + +vector OsxBluetoothGatt::discoverCharacteristics(uint16_t startHandle, uint16_t endHandle) { +} +*/ + +// ----------------------------------------------------------------------- +// OsxBluetoothSystem +// ----------------------------------------------------------------------- + + +// We only have a single adapter on OSX. +shared_ptr adapter; + +shared_ptr&& getAdapterImpl() { + if(!adapter) { + auto mac = Mac::parseMac("00:00:00:00:00:00"); + adapter = make_shared("system", mac); + } + + return std::move(adapter); +} + +void shutdownImpl() { + adapter.reset(); +} + +} +} +} diff --git a/include/ble/Bluetooth.h b/include/ble/Bluetooth.h index 6a974d5..b035223 100644 --- a/include/ble/Bluetooth.h +++ b/include/ble/Bluetooth.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -167,21 +168,20 @@ public: virtual BluetoothDevice &getDevice(Mac &mac) = 0; + virtual string getName() = 0; + protected: BluetoothAdapter(); virtual ~BluetoothAdapter(); }; -/** -* Right this is only RAII support to properly call shutdown(). -* -* TODO: move getAdapter() here. Make this control all shutdowns. -*/ class BluetoothSystem { public: BluetoothSystem(); + shared_ptr getAdapter(string adapter_name); + ~BluetoothSystem(); }; @@ -245,10 +245,6 @@ private: AttributeData(uint16_t handle, ByteBuffer value); }; -shared_ptr getAdapter(int hciDevice); - -void shutdown(); - boost::uuids::uuid makeUuid(const boost::uuids::uuid base, uint8_t a, uint8_t b); } diff --git a/sensor/CMakeLists.txt b/sensor/CMakeLists.txt index d571e38..fb118d1 100644 --- a/sensor/CMakeLists.txt +++ b/sensor/CMakeLists.txt @@ -5,10 +5,12 @@ add_library(trygvis-sensor main/io.cpp ${INCLUDES}) -include_directories("${PROJECT_SOURCE_DIR}/json/src") -include_directories(include) - # Boost find_package(Boost COMPONENTS regex system REQUIRED) +target_include_directories(trygvis-sensor + PUBLIC "${PROJECT_SOURCE_DIR}/json/src" + PUBLIC "${PROJECT_SOURCE_DIR}/sensor/include" + PUBLIC "${Boost_INCLUDE_DIRS}") + add_subdirectory(test) diff --git a/sensor/include/trygvis/sensor.h b/sensor/include/trygvis/sensor.h index b5199e2..e78d845 100644 --- a/sensor/include/trygvis/sensor.h +++ b/sensor/include/trygvis/sensor.h @@ -4,6 +4,7 @@ #include #include #include +#include #include namespace trygvis { diff --git a/test/ByteBufferTest.cpp b/test/ByteBufferTest.cpp index 5aad376..d7b1736 100644 --- a/test/ByteBufferTest.cpp +++ b/test/ByteBufferTest.cpp @@ -1,4 +1,5 @@ #include "ble/ByteBuffer.h" +#include #define BOOST_TEST_MODULE "ByteBuffer" -- cgit v1.2.3