From e1918179530e87b040b8c52f525ff3b66b4e26ba Mon Sep 17 00:00:00 2001 From: SP2FET Date: Wed, 3 Feb 2021 11:56:26 +0100 Subject: [PATCH] [EGD-5480] Bluetooth scan refactor There was a need for Bluetooth scan code refactor. Here it is --- .../windows/AddDeviceWindow.cpp | 2 +- .../windows/AllDevicesWindow.cpp | 4 +- .../Bluetooth/BluetoothWorker.cpp | 14 +- .../Bluetooth/BluetoothWorker.hpp | 1 - module-bluetooth/Bluetooth/BtCommand.hpp | 16 +- module-bluetooth/Bluetooth/CommandHandler.cpp | 20 +- module-bluetooth/Bluetooth/CommandHandler.hpp | 5 +- module-bluetooth/Bluetooth/Device.hpp | 4 +- .../Bluetooth/WorkerController.cpp | 1 + .../Bluetooth/interface/BluetoothDriver.cpp | 19 +- .../Bluetooth/interface/BluetoothDriver.hpp | 8 +- .../Bluetooth/interface/profiles/GAP.cpp | 267 ----------------- .../Bluetooth/interface/profiles/GAP/GAP.cpp | 271 ++++++++++++++++++ .../Bluetooth/interface/profiles/GAP/GAP.hpp | 56 ++++ module-bluetooth/CMakeLists.txt | 1 + module-bluetooth/lib/btstack.cmake | 1 - module-bsp/board/rt1051/common/macros.h | 2 - 17 files changed, 385 insertions(+), 307 deletions(-) delete mode 100644 module-bluetooth/Bluetooth/interface/profiles/GAP.cpp create mode 100644 module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp create mode 100644 module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp diff --git a/module-apps/application-settings-new/windows/AddDeviceWindow.cpp b/module-apps/application-settings-new/windows/AddDeviceWindow.cpp index 18b60374af3995009c592187a3c65fa37aa6521c..b81afca520a0139f54ece79478b89fe715e0a485 100644 --- a/module-apps/application-settings-new/windows/AddDeviceWindow.cpp +++ b/module-apps/application-settings-new/windows/AddDeviceWindow.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "AddDeviceWindow.hpp" diff --git a/module-apps/application-settings-new/windows/AllDevicesWindow.cpp b/module-apps/application-settings-new/windows/AllDevicesWindow.cpp index 85aaf325732b249edb572822d56f39440500a331..57662163d4c99d1ad666708cbf527cfd27adf6e0 100644 --- a/module-apps/application-settings-new/windows/AllDevicesWindow.cpp +++ b/module-apps/application-settings-new/windows/AllDevicesWindow.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "AllDevicesWindow.hpp" @@ -28,6 +28,8 @@ namespace gui void AllDevicesWindow::onBeforeShow(ShowMode mode, SwitchData *data) { clearOptions(); + application->bus.sendUnicast(std::make_shared(BluetoothMessage::Request::StopScan), + "ServiceBluetooth"); if (const auto newData = dynamic_cast(data); newData != nullptr) { addOptions(allDevicesOptionsList(newData->getDevices())); } diff --git a/module-bluetooth/Bluetooth/BluetoothWorker.cpp b/module-bluetooth/Bluetooth/BluetoothWorker.cpp index 46ce5d6441d8e7a6cc93a4e036dab236290814c7..5e31fe46db14ce162843374f87805710cd5d953d 100644 --- a/module-bluetooth/Bluetooth/BluetoothWorker.cpp +++ b/module-bluetooth/Bluetooth/BluetoothWorker.cpp @@ -48,7 +48,7 @@ namespace [[nodiscard]] auto operator()() { bluetooth::KeyStorage::settings = settings; - bluetooth::GAP::register_scan(); + bluetooth::GAP::registerScan(); auto settingsName = std::get(settings->getValue(bluetooth::Settings::DeviceName)); if (settingsName.empty()) { @@ -58,8 +58,6 @@ namespace settingsName = name; } bluetooth::set_name(settingsName); - bluetooth::GAP::set_visibility( - std::visit(bluetooth::BoolVisitor{}, settings->getValue(bluetooth::Settings::Visibility))); settings->onLinkKeyAdded = onLinkKeyAdded; return bluetooth::Error::Success; @@ -76,8 +74,9 @@ namespace std::shared_ptr currentProfile, DeviceRegistration::OnLinkKeyAddedCallback &&onLinkKeyAddedCallback) { - auto driver = std::make_unique(loop->getRunLoopInstance()); - auto commandHandler = std::make_unique(service, settings, std::move(currentProfile)); + auto driver = std::make_shared(loop->getRunLoopInstance(), service); + auto commandHandler = + std::make_unique(service, settings, std::move(currentProfile), driver); return std::make_unique( std::move(driver), std::move(commandHandler), @@ -109,7 +108,8 @@ void BluetoothWorker::registerQueues() void BluetoothWorker::onLinkKeyAdded(const std::string &deviceAddress) { - for (auto &device : bluetooth::GAP::devices) { + auto devices = bluetooth::GAP::getDevicesList(); + for (auto &device : devices) { if (bd_addr_to_str(device.address) == deviceAddress) { pairedDevices.emplace_back(device); settings->setValue(bluetooth::Settings::BondedDevices, SettingsSerializer::toString(pairedDevices)); @@ -249,7 +249,7 @@ auto BluetoothWorker::handleMessage(uint32_t queueID) -> bool void BluetoothWorker::setDeviceAddress(bd_addr_t addr) { - bluetooth::GAP::do_pairing(addr); + currentProfile->setDeviceAddress(addr); } diff --git a/module-bluetooth/Bluetooth/BluetoothWorker.hpp b/module-bluetooth/Bluetooth/BluetoothWorker.hpp index 6e59483595c2a63295fd399360523819a31ac02b..31af5902240ba3bf732d3408c2d913687b6e3820 100644 --- a/module-bluetooth/Bluetooth/BluetoothWorker.hpp +++ b/module-bluetooth/Bluetooth/BluetoothWorker.hpp @@ -13,7 +13,6 @@ #include #include "service-bluetooth/SettingsHolder.hpp" #include "glucode/BluetoothRunLoop.hpp" -#include "interface/BluetoothDriver.hpp" #include "WorkerController.hpp" struct HCI; diff --git a/module-bluetooth/Bluetooth/BtCommand.hpp b/module-bluetooth/Bluetooth/BtCommand.hpp index 67945d45b431b6e22f714a55181bd1d8b06c3958..93c7218654b72118e7ab9af1f208aeff30dcefed 100644 --- a/module-bluetooth/Bluetooth/BtCommand.hpp +++ b/module-bluetooth/Bluetooth/BtCommand.hpp @@ -1,31 +1,19 @@ -// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once #include #include -#include "BluetoothWorker.hpp" #include "Error.hpp" #include #include +#include namespace bluetooth { auto set_name(std::string &name) -> Error; - namespace GAP - { - extern std::vector devices; - /// THIS have to be called prior to Bt system start! - auto register_scan() -> Error; - auto scan() -> Error; - void stop_scan(); - auto set_visibility(bool visibility) -> Error; - auto do_pairing(uint8_t *addr) -> bool; - - void setOwnerService(sys::Service *service); - }; // namespace GAP namespace PAN { auto bnep_start() -> Error; diff --git a/module-bluetooth/Bluetooth/CommandHandler.cpp b/module-bluetooth/Bluetooth/CommandHandler.cpp index 46df2921ef97551d1ec44b8cc01f4ac399ea04a7..2d16df72d82de180efcce4698aadf3d5564b8894 100644 --- a/module-bluetooth/Bluetooth/CommandHandler.cpp +++ b/module-bluetooth/Bluetooth/CommandHandler.cpp @@ -3,8 +3,10 @@ #include "CommandHandler.hpp" -#include "BtCommand.hpp" +#include + #include "Device.hpp" +#include "BtCommand.hpp" namespace bluetooth { @@ -18,8 +20,10 @@ namespace bluetooth CommandHandler::CommandHandler(sys::Service *service, std::shared_ptr settings, - std::shared_ptr currentProfile) - : service{service}, settings{std::move(settings)}, currentProfile{std::move(currentProfile)} + std::shared_ptr currentProfile, + std::shared_ptr driver) + : service{service}, settings{std::move(settings)}, currentProfile{std::move(currentProfile)}, driver{std::move( + driver)} {} Error::Code CommandHandler::handle(Command command) @@ -49,8 +53,8 @@ namespace bluetooth Error::Code CommandHandler::scan() { - bluetooth::GAP::setOwnerService(service); - if (const auto ret = bluetooth::GAP::scan(); ret.err != bluetooth::Error::Success) { + + if (const auto ret = driver->scan(); ret.err != bluetooth::Error::Success) { LOG_ERROR("Cant start scan!: %s %" PRIu32 "", toString(ret.err).c_str(), ret.lib_code); return ret.err; } @@ -62,7 +66,7 @@ namespace bluetooth Error::Code CommandHandler::stopScan() { - bluetooth::GAP::stop_scan(); + driver->stopScan(); return Error::Success; } @@ -78,9 +82,9 @@ namespace bluetooth Error::Code CommandHandler::setVisibility(bool visibility) { - const auto status = bluetooth::GAP::set_visibility(visibility); + driver->setVisibility(visibility); settings->setValue(bluetooth::Settings::Visibility, static_cast(visibility)); - return status.err; + return Error::Success; } Error::Code CommandHandler::establishAudioConnection() diff --git a/module-bluetooth/Bluetooth/CommandHandler.hpp b/module-bluetooth/Bluetooth/CommandHandler.hpp index 3b962512b2798e7e8f15bb2058a75e6c684b4b4e..2744a46302c4d217235a4017907467e0f1d274e1 100644 --- a/module-bluetooth/Bluetooth/CommandHandler.hpp +++ b/module-bluetooth/Bluetooth/CommandHandler.hpp @@ -5,6 +5,7 @@ #include "Error.hpp" #include "interface/profiles/Profile.hpp" +#include "interface/BluetoothDriver.hpp" #include #include @@ -39,7 +40,8 @@ namespace bluetooth public: explicit CommandHandler(sys::Service *service, std::shared_ptr settings, - std::shared_ptr currentProfile); + std::shared_ptr currentProfile, + std::shared_ptr driver); auto handle(Command command) -> Error::Code override; @@ -54,5 +56,6 @@ namespace bluetooth sys::Service *service; std::shared_ptr settings; std::shared_ptr currentProfile; + std::shared_ptr driver; }; } // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/Device.hpp b/module-bluetooth/Bluetooth/Device.hpp index 8ad322d68b0088c64db6b02c6fde456a31ca2a60..e2ebee232ed7302ae1169b331cd0b167650352ee 100644 --- a/module-bluetooth/Bluetooth/Device.hpp +++ b/module-bluetooth/Bluetooth/Device.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -35,7 +35,7 @@ struct Devicei : public Device Devicei(std::string name = "") : Device(std::move(name)) {} ~Devicei() override = default; - void address_set(bd_addr_t *addr) + void setAddress(bd_addr_t *addr) { memcpy(&address, addr, sizeof address); } diff --git a/module-bluetooth/Bluetooth/WorkerController.cpp b/module-bluetooth/Bluetooth/WorkerController.cpp index da4770f5ca7e7b0161fd040aa41c4d18f4e062cd..3c4984d528c400d822419853506d20fc0ad524a7 100644 --- a/module-bluetooth/Bluetooth/WorkerController.cpp +++ b/module-bluetooth/Bluetooth/WorkerController.cpp @@ -7,6 +7,7 @@ #include "interface/profiles/Profile.hpp" #include +#define BOOST_SML_CFG_DISABLE_MIN_SIZE // GCC10 fix #include #include diff --git a/module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp b/module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp index ded8f4ec99ced7a7b83805cb7919d0e832cf663d..1125fa80420a5fa6d1c6d92edc0f502f2c2d937c 100644 --- a/module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp +++ b/module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp @@ -53,7 +53,8 @@ namespace bluetooth } #endif - Driver::Driver(const btstack_run_loop *runLoop) : runLoop{runLoop} + Driver::Driver(const btstack_run_loop *runLoop, sys::Service *ownerService) + : runLoop{runLoop}, gap{std::make_unique(ownerService)} {} auto Driver::init() -> Error::Code @@ -187,4 +188,20 @@ namespace bluetooth hci_close(); return ret != 0 ? Error::LibraryError : Error::Success; } + auto Driver::scan() -> Error + { + return gap->scan(); + } + void Driver::stopScan() + { + gap->stopScan(); + } + void Driver::setVisibility(bool visibility) + { + gap->setVisibility(visibility); + } + auto Driver::pair(uint8_t *addr, std::uint8_t protectionLevel) -> bool + { + return gap->pair(addr, protectionLevel); + } } // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp b/module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp index ca15f71330f7c8e7dad5d6673a6d884a94bedfb7..46be4317789fbb26623a819d2586067f5b3b8a31 100644 --- a/module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp +++ b/module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp @@ -5,6 +5,7 @@ #include #include +#include "GAP/GAP.hpp" #include "Error.hpp" namespace bluetooth @@ -27,6 +28,7 @@ namespace bluetooth static hci_transport_config_uart_t config; const btstack_run_loop *runLoop; btstack_packet_callback_registration_t hci_event_callback_registration; + std::unique_ptr gap; static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); static void local_version_information_handler(uint8_t *packet); #ifdef TARGET_RT1051 @@ -36,11 +38,15 @@ namespace bluetooth #endif public: - explicit Driver(const btstack_run_loop *runLoop); + Driver(const btstack_run_loop *runLoop, sys::Service *ownerService); [[nodiscard]] auto init() -> Error::Code override; [[nodiscard]] auto run() -> Error::Code override; [[nodiscard]] auto stop() -> Error::Code override; void registerErrorCallback(const ErrorCallback &newCallback) override; + auto scan() -> Error; + void stopScan(); + void setVisibility(bool visibility); + auto pair(uint8_t *addr, std::uint8_t protectionLevel = 0) -> bool; }; } // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/interface/profiles/GAP.cpp b/module-bluetooth/Bluetooth/interface/profiles/GAP.cpp deleted file mode 100644 index 21b2d97184bf3f72cc5decd5c6de5c0439530528..0000000000000000000000000000000000000000 --- a/module-bluetooth/Bluetooth/interface/profiles/GAP.cpp +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. -// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md - -#include "BluetoothWorker.hpp" -#include "Device.hpp" -#include -#include -#include -#include -#include -#include - -extern "C" -{ -#include "btstack.h" -#include "hci.h" -}; - -btstack_packet_callback_registration_t cb_handler; - -std::vector bluetooth::GAP::devices; -static auto start_scan() -> int; -static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); - -static auto getDeviceIndexForAddress(std::vector &devs, bd_addr_t addr) -> int -{ - int j; - for (j = 0; j < devs.size(); j++) { - if (bd_addr_cmp(addr, devs[j].address) == 0) { - return j; - } - } - return -1; -} - -enum STATE -{ - INIT, - ACTIVE, - DONE -}; -enum STATE state = INIT; - -namespace bluetooth::GAP -{ - - static sys::Service *ownerService = nullptr; - - void setOwnerService(sys::Service *service) - { - ownerService = service; - } - - auto register_scan() -> Error - { - LOG_INFO("GAP register scan!"); - /// -> this have to be called prior to power on! - hci_set_inquiry_mode(INQUIRY_MODE_RSSI_AND_EIR); - cb_handler.callback = &packet_handler; - hci_add_event_handler(&cb_handler); - return Error(); - } - - auto scan() -> Error - { - LOG_INFO("Start scan if active: %d: %d", hci_get_state(), state); - if (hci_get_state() == HCI_STATE_WORKING) { - if (int ret = start_scan(); ret != 0) { - LOG_ERROR("Start scan error!: 0x%X", ret); - return Error(Error::LibraryError, ret); - } - } - else { - return Error(Error::NotReady); - } - return Error(); - } - - void stop_scan() - { - gap_inquiry_force_stop(); - LOG_INFO("Scan stopped!"); - } - - auto set_visibility(bool visibility) -> Error - { - gap_discoverable_control(static_cast(visibility)); - LOG_INFO("Visibility: %s", visibility ? "true" : "false"); - return Error(); - } - - auto do_pairing(uint8_t *addr) -> bool - { - if (hci_get_state() == HCI_STATE_WORKING) { - gap_dedicated_bonding(addr, 0); - return true; - } - return false; - } - -} // namespace bluetooth::GAP - -#define INQUIRY_INTERVAL 5 -static auto start_scan() -> int -{ - LOG_INFO("Starting inquiry scan.."); - return gap_inquiry_start(INQUIRY_INTERVAL); -} - -static auto has_more_remote_name_requests() -> int -{ - for (int i = 0; i < bluetooth::GAP::devices.size(); i++) { - if (bluetooth::GAP::devices[i].state == REMOTE_NAME_REQUEST) { - return 1; - } - } - return 0; -} - -static void do_next_remote_name_request() -{ - - for (auto &device : bluetooth::GAP::devices) { - // remote name request - if (device.state == REMOTE_NAME_REQUEST) { - device.state = REMOTE_NAME_INQUIRED; - LOG_INFO("Get remote name of %s...", bd_addr_to_str(device.address)); - gap_remote_name_request(device.address, device.pageScanRepetitionMode, device.clockOffset | 0x8000); - return; - } - } -} - -static void continue_remote_names() -{ - if (has_more_remote_name_requests() != 0) { - do_next_remote_name_request(); - return; - } - start_scan(); -} - -static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) -{ - UNUSED(channel); - UNUSED(size); - - bd_addr_t addr; - int i; - int index; - - if (packet_type != HCI_EVENT_PACKET) { - return; - } - - uint8_t event = hci_event_packet_get_type(packet); - - switch (state) { - /* @text In INIT, an inquiry scan is started, and the application transits to - * ACTIVE state. - */ - case INIT: - switch (event) { - case BTSTACK_EVENT_STATE: - if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) { - state = ACTIVE; - } - break; - default: - break; - } - break; - - /* @text In ACTIVE, the following events are processed: - * - GAP Inquiry result event: BTstack provides a unified inquiry result that contain - * Class of Device (CoD), page scan mode, clock offset. RSSI and name (from EIR) are optional. - * - Inquiry complete event: the remote name is requested for devices without a fetched - * name. The state of a remote name can be one of the following: - * REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, or REMOTE_NAME_FETCHED. - * - Remote name request complete event: the remote name is stored in the table and the - * state is updated to REMOTE_NAME_FETCHED. The query of remote names is continued. - */ - case ACTIVE: - switch (event) { - - case GAP_EVENT_INQUIRY_RESULT: { - gap_event_inquiry_result_get_bd_addr(packet, addr); - index = getDeviceIndexForAddress(bluetooth::GAP::devices, addr); - if (index >= 0) { - break; // already in our list - } - - Devicei dev; - dev.address_set(&addr); - dev.pageScanRepetitionMode = gap_event_inquiry_result_get_page_scan_repetition_mode(packet); - dev.clockOffset = gap_event_inquiry_result_get_clock_offset(packet); - // print info - LOG_INFO("Device found: %s ", bd_addr_to_str(addr)); - LOG_INFO("with COD: 0x%06x, ", (unsigned int)gap_event_inquiry_result_get_class_of_device(packet)); - LOG_INFO("pageScan %d, ", dev.pageScanRepetitionMode); - LOG_INFO("clock offset 0x%04x", dev.clockOffset); - if (gap_event_inquiry_result_get_rssi_available(packet) != 0u) { - LOG_INFO(", rssi %d dBm", (int8_t)gap_event_inquiry_result_get_rssi(packet)); - } - if (gap_event_inquiry_result_get_name_available(packet) != 0u) { - char name_buffer[240]; - int name_len = gap_event_inquiry_result_get_name_len(packet); - memcpy(name_buffer, gap_event_inquiry_result_get_name(packet), name_len); - name_buffer[name_len] = 0; - LOG_INFO(", name '%s'", name_buffer); - dev.name = std::string{name_buffer}; - dev.state = REMOTE_NAME_FETCHED; - } - else { - dev.state = REMOTE_NAME_REQUEST; - } - bluetooth::GAP::devices.push_back(dev); - auto msg = std::make_shared(bluetooth::GAP::devices); - bluetooth::GAP::ownerService->bus.sendUnicast(msg, "ApplicationSettings"); - bluetooth::GAP::ownerService->bus.sendUnicast(msg, "ApplicationSettingsNew"); - } break; - - case GAP_EVENT_INQUIRY_COMPLETE: - for (i = 0; i < bluetooth::GAP::devices.size(); i++) { - // retry remote name request - if (bluetooth::GAP::devices[i].state == REMOTE_NAME_INQUIRED) - bluetooth::GAP::devices[i].state = REMOTE_NAME_REQUEST; - } - continue_remote_names(); - break; - - case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: { - reverse_bd_addr(&packet[3], addr); - index = getDeviceIndexForAddress(bluetooth::GAP::devices, addr); - if (index >= 0) { - if (packet[2] == 0) { - LOG_INFO("Name: '%s'", &packet[9]); - bluetooth::GAP::devices[index].state = REMOTE_NAME_FETCHED; - bluetooth::GAP::devices[index].name = reinterpret_cast(&packet[9]); - } - else { - LOG_INFO("Failed to get name: page timeout"); - } - } - if (index + 1 == bluetooth::GAP::devices.size()) { - LOG_INFO("Scanned all"); - state = DONE; - gap_inquiry_stop(); - break; - } - continue_remote_names(); - } break; - case GAP_EVENT_DEDICATED_BONDING_COMPLETED: { - auto result = packet[2]; - auto msg = std::make_shared(result == 0u); - bluetooth::GAP::ownerService->bus.sendUnicast(msg, "ApplicationSettings"); - bluetooth::GAP::ownerService->bus.sendUnicast(msg, "ApplicationSettingsNew"); - } break; - default: - break; - } - break; - - default: - break; - } -} diff --git a/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp b/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4fb325fb1b8c29ee70181f8a6bc080cf9728b897 --- /dev/null +++ b/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp @@ -0,0 +1,271 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "GAP.hpp" + +#include +#include + +extern "C" +{ +#include "btstack.h" +#include "hci.h" +}; +namespace bluetooth +{ + sys::Service *GAP::ownerService = nullptr; + std::vector GAP::devices; + btstack_packet_callback_registration_t GAP::cb_handler; + ScanState GAP::state; + + auto GAP::registerScan() -> Error + { + LOG_INFO("GAP register scan!"); + /// -> this have to be called prior to power on! + hci_set_inquiry_mode(INQUIRY_MODE_RSSI_AND_EIR); + cb_handler.callback = &packetHandler; + hci_add_event_handler(&cb_handler); + return Error(); + } + + auto GAP::scan() -> Error + { + if (hci_get_state() == HCI_STATE_WORKING) { + if (auto ret = startScan(); ret != 0) { + LOG_ERROR("Start scan error!: 0x%X", ret); + return Error(Error::LibraryError, ret); + } + } + else { + return Error(Error::NotReady); + } + return Error(); + } + + void GAP::stopScan() + { + gap_inquiry_force_stop(); + devices.clear(); + LOG_INFO("Scan stopped!"); + } + + void GAP::setVisibility(bool visibility) + { + gap_discoverable_control(static_cast(visibility)); + LOG_INFO("Visibility: %s", visibility ? "true" : "false"); + } + + auto GAP::pair(std::uint8_t *addr, std::uint8_t protectionLevel) -> bool + { + if (hci_get_state() == HCI_STATE_WORKING) { + return gap_dedicated_bonding(addr, protectionLevel) == 0; + } + return false; + } + + auto getDeviceIndexForAddress(const std::vector &devs, bd_addr_t addr) -> int + { + auto result = std::find_if(std::begin(devs), std::end(devs), [addr](const Devicei &device) { + return bd_addr_cmp(addr, device.address) == 0; + }); + + if (result == std::end(devs)) { + return -1; + } + + return std::distance(std::begin(devs), result); + } + + void GAP::sendDevices() + { + auto msg = std::make_shared(devices); + ownerService->bus.sendUnicast(msg, "ApplicationSettings"); + ownerService->bus.sendUnicast(std::move(msg), "ApplicationSettingsNew"); + } + + auto GAP::startScan() -> int + { + LOG_INFO("Starting inquiry scan.."); + return gap_inquiry_start(inquiryIntervalSeconds); + } + + auto GAP::remoteNameToFetch() -> bool + { + auto result = std::find_if(std::begin(devices), std::end(devices), [](Devicei &device) { + return device.state == REMOTE_NAME_REQUEST; + }); + + return result != std::end(devices); + } + + void GAP::fetchRemoteName() + { + for (auto &device : bluetooth::GAP::devices) { + if (device.state == REMOTE_NAME_REQUEST) { + device.state = REMOTE_NAME_INQUIRED; + LOG_INFO("Get remote name of %s...", bd_addr_to_str(device.address)); + gap_remote_name_request(device.address, device.pageScanRepetitionMode, device.clockOffset | 0x8000); + return; + } + } + } + + void GAP::continueScanning() + { + if (remoteNameToFetch()) { + fetchRemoteName(); + return; + } + startScan(); + } + auto GAP::updateDeviceName(std::uint8_t *packet, bd_addr_t &addr) -> bool + { + reverse_bd_addr(&packet[3], addr); + auto index = getDeviceIndexForAddress(devices, addr); + if (index >= 0) { + if (packet[2] == 0) { + LOG_INFO("Name: '%s'", &packet[9]); + devices[index].state = REMOTE_NAME_FETCHED; + devices[index].name = std::string{reinterpret_cast(&packet[9])}; + return true; + } + else { + LOG_INFO("Failed to get name: page timeout"); + } + } + return false; + } + + void GAP::addNewDevice(std::uint8_t *packet, bd_addr_t &addr) + { + Devicei device; + device.setAddress(&addr); + device.pageScanRepetitionMode = gap_event_inquiry_result_get_page_scan_repetition_mode(packet); + device.clockOffset = gap_event_inquiry_result_get_clock_offset(packet); + + LOG_INFO("Device found: %s ", bd_addr_to_str(addr)); + LOG_INFO("with COD: 0x%06x, ", static_cast(gap_event_inquiry_result_get_class_of_device(packet))); + LOG_INFO("pageScan %d, ", device.pageScanRepetitionMode); + LOG_INFO("clock offset 0x%04x", device.clockOffset); + if (gap_event_inquiry_result_get_rssi_available(packet) != 0u) { + LOG_INFO(", rssi %d dBm", static_cast(gap_event_inquiry_result_get_rssi(packet))); + } + if (gap_event_inquiry_result_get_name_available(packet) != 0u) { + auto name = gap_event_inquiry_result_get_name(packet); + device.name = std::string{reinterpret_cast(name)}; + + LOG_INFO(", name '%s'", device.name.c_str()); + device.state = REMOTE_NAME_FETCHED; + } + else { + device.state = REMOTE_NAME_REQUEST; + device.name = std::string{}; + } + + devices.emplace_back(std::move(device)); + } + + void GAP::processInquiryResult(std::uint8_t *packet, bd_addr_t &addr) + { + gap_event_inquiry_result_get_bd_addr(packet, addr); + auto index = getDeviceIndexForAddress(devices, addr); + if (index >= 0) { + return; // already in our list + } + addNewDevice(packet, addr); + sendDevices(); + } + void GAP::processInquiryComplete() + { + for (auto &device : devices) { + // retry remote name request + if (device.state == REMOTE_NAME_INQUIRED) { + device.state = REMOTE_NAME_REQUEST; + } + } + continueScanning(); + } + void GAP::processNameRequestComplete(std::uint8_t *packet, bd_addr_t &addr) + { + if (updateDeviceName(packet, addr)) { + sendDevices(); + } + continueScanning(); + } + void GAP::processDedicatedBondingCompleted(std::uint8_t *packet) + { + auto result = packet[2]; + auto msg = std::make_shared(result == 0u); + ownerService->bus.sendUnicast(msg, "ApplicationSettings"); + ownerService->bus.sendUnicast(std::move(msg), "ApplicationSettingsNew"); + } + /* @text In ACTIVE, the following events are processed: + * - GAP Inquiry result event: BTstack provides a unified inquiry result that contain + * Class of Device (CoD), page scan mode, clock offset. RSSI and name (from EIR) are optional. + * - Inquiry complete event: the remote name is requested for devices without a fetched + * name. The state of a remote name can be one of the following: + * REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, or REMOTE_NAME_FETCHED. + * - Remote name request complete event: the remote name is stored in the table and the + * state is updated to REMOTE_NAME_FETCHED. The query of remote names is continued. + */ + void GAP::activeStateHandler(std::uint8_t eventType, std::uint8_t *packet, bd_addr_t &addr) + { + switch (eventType) { + + case GAP_EVENT_INQUIRY_RESULT: + processInquiryResult(packet, addr); + break; + + case GAP_EVENT_INQUIRY_COMPLETE: + processInquiryComplete(); + break; + + case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: + processNameRequestComplete(packet, addr); + break; + case GAP_EVENT_DEDICATED_BONDING_COMPLETED: + processDedicatedBondingCompleted(packet); + break; + default: + break; + } + } + void GAP::initStateHandler(std::uint8_t eventType, std::uint8_t *packet) + { + if (eventType == BTSTACK_EVENT_STATE) { + if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) { + state = ScanState::active; + } + } + } + void GAP::packetHandler(std::uint8_t packet_type, std::uint16_t channel, std::uint8_t *packet, std::uint16_t size) + { + bd_addr_t addr; + + if (packet_type != HCI_EVENT_PACKET) { + return; + } + + const auto eventType = hci_event_packet_get_type(packet); + switch (state) { + case ScanState::init: + initStateHandler(eventType, packet); + break; + case ScanState::active: + activeStateHandler(eventType, packet, addr); + break; + default: + break; + } + } + GAP::GAP(sys::Service *owner) + { + ownerService = owner; + state = ScanState::init; + } + auto GAP::getDevicesList() -> const std::vector & + { + return devices; + } + +} // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp b/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e6f3b6fa42bbb20cbbec0cf77c7637d1fdcaafef --- /dev/null +++ b/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp @@ -0,0 +1,56 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once +#include +#include +#include +#include +extern "C" +{ +#include "btstack_defines.h" +} +namespace bluetooth +{ + enum ScanState + { + init, + active, + done + }; + class GAP + { + static std::vector devices; + static sys::Service *ownerService; + static btstack_packet_callback_registration_t cb_handler; + static constexpr auto inquiryIntervalSeconds = 5; + static ScanState state; + static void sendDevices(); + static auto startScan() -> int; + static auto remoteNameToFetch() -> bool; + static void fetchRemoteName(); + static void continueScanning(); + static auto updateDeviceName(std::uint8_t *packet, bd_addr_t &addr) -> bool; + static void addNewDevice(std::uint8_t *packet, bd_addr_t &addr); + static void activeStateHandler(std::uint8_t eventType, std::uint8_t *packet, bd_addr_t &addr); + static void packetHandler(std::uint8_t packet_type, + std::uint16_t channel, + std::uint8_t *packet, + std::uint16_t size); + static void processInquiryResult(std::uint8_t *packet, bd_addr_t &addr); + static void processInquiryComplete(); + static void processNameRequestComplete(std::uint8_t *packet, bd_addr_t &addr); + static void processDedicatedBondingCompleted(std::uint8_t *packet); + static void initStateHandler(std::uint8_t eventType, std::uint8_t *packet); + + public: + /// THIS have to be called prior to Bt system start! + static auto registerScan() -> Error; + auto scan() -> Error; + void stopScan(); + void setVisibility(bool visibility); + auto pair(uint8_t *addr, std::uint8_t protectionLevel = 0) -> bool; + static auto getDevicesList() -> const std::vector &; + explicit GAP(sys::Service *owner); + }; +} // namespace bluetooth diff --git a/module-bluetooth/CMakeLists.txt b/module-bluetooth/CMakeLists.txt index fb62dd7ea926ed339502e3db17582540219674f0..afb242f91cf09cbc30096ac960022173f946a2ef 100644 --- a/module-bluetooth/CMakeLists.txt +++ b/module-bluetooth/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/glucode/BluetoothRunLoop.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/BluetoothDriver.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/BtKeysStorage.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/GAP/GAP.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/A2DP/A2DP.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/A2DP/AVRCP.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/A2DP/AVDTP.cpp diff --git a/module-bluetooth/lib/btstack.cmake b/module-bluetooth/lib/btstack.cmake index af5c6d6fab755c53066c833f3e8d10ba4d09e6d7..98f26de9d391add64e8762ff42cda291d700f38d 100644 --- a/module-bluetooth/lib/btstack.cmake +++ b/module-bluetooth/lib/btstack.cmake @@ -140,7 +140,6 @@ list(APPEND TARGET_LIBRARIES_INCLUDES ${BT_STACK_ROOT}/platform/lwip ) set(BOARD_DIR_SOURCES - ${BT_INT}/GAP.cpp ${BT_INT}/PAN.cpp ${BT_GLU}/bluetooth_init_cc2564C_1.0.c diff --git a/module-bsp/board/rt1051/common/macros.h b/module-bsp/board/rt1051/common/macros.h index 5a17eb4851c61755baf348ac84590579745d1bf8..2c08ad12d03411dbd4ead89b963bad6a2fd6819f 100644 --- a/module-bsp/board/rt1051/common/macros.h +++ b/module-bsp/board/rt1051/common/macros.h @@ -10,8 +10,6 @@ #define _STRINGIFY(s) #s #define STRINGIFY(s) _STRINGIFY(s) -#define UNUSED(x) ((void)(x)) - #define ALIGN_(n) __attribute__((aligned(n))) #define CACHEABLE_SECTION_SDRAM(var) __attribute__((section(".sdram"))) var