From 76c924fd5ee9b3d99ba61d40bd5fa932e40715c0 Mon Sep 17 00:00:00 2001 From: Adam Dobrowolski Date: Thu, 2 Dec 2021 15:41:58 +0100 Subject: [PATCH] [EGD-8002] Added SSP, fixed some minor issues, removed obsolete code ssp seems working minor crash fixups copy lacks patched obsolete code removed Devicei tests added for added code and cleanup Added missing tests for new functions Code cleaned up a bit - mostly moved to cpp --- .gdbinit-1051 | 2 +- .../ApplicationSettings.cpp | 10 +- .../bluetooth/BluetoothSettingsModel.cpp | 3 +- .../bluetooth/BluetoothSettingsModel.hpp | 1 + .../bluetooth/BluetoothCheckPasskeyWindow.cpp | 8 +- .../bluetooth/BluetoothCheckPasskeyWindow.hpp | 5 +- module-bluetooth/Bluetooth/BtKeysStorage.cpp | 1 - module-bluetooth/Bluetooth/Device.cpp | 81 +++++ module-bluetooth/Bluetooth/Device.hpp | 56 ++-- .../Bluetooth/error_bluetooth.cpp | 142 +++++++++ .../Bluetooth/error_bluetooth.hpp | 8 + .../interface/BluetoothDriverImpl.cpp | 3 + .../interface/profiles/GAP/Devices.cpp | 64 ++++ .../interface/profiles/GAP/Devices.hpp | 30 ++ .../Bluetooth/interface/profiles/GAP/GAP.cpp | 279 ++++++++++++------ .../Bluetooth/interface/profiles/GAP/GAP.hpp | 31 +- .../interface/profiles/GAP/used_events.cpp | 57 ++++ .../interface/profiles/GAP/used_events.hpp | 9 + module-bluetooth/CMakeLists.txt | 4 + module-bluetooth/tests/CMakeLists.txt | 1 + module-bluetooth/tests/test-Devicei.cpp | 14 + .../tests/tests-BluetoothDevicesModel.cpp | 1 + module-bluetooth/tests/tests-Devicei.cpp | 62 ++++ .../service-bluetooth/ServiceBluetooth.cpp | 2 +- .../BluetoothDevicesModel.cpp | 6 + .../BluetoothSettingsModel.cpp | 172 ----------- .../BluetoothSettingsModel.hpp | 59 ---- .../service-bluetooth/messages/Passkey.hpp | 23 +- module-utils/log/Logger.cpp | 1 + 29 files changed, 755 insertions(+), 380 deletions(-) create mode 100644 module-bluetooth/Bluetooth/Device.cpp create mode 100644 module-bluetooth/Bluetooth/error_bluetooth.cpp create mode 100644 module-bluetooth/Bluetooth/error_bluetooth.hpp create mode 100644 module-bluetooth/Bluetooth/interface/profiles/GAP/Devices.cpp create mode 100644 module-bluetooth/Bluetooth/interface/profiles/GAP/Devices.hpp create mode 100644 module-bluetooth/Bluetooth/interface/profiles/GAP/used_events.cpp create mode 100644 module-bluetooth/Bluetooth/interface/profiles/GAP/used_events.hpp create mode 100644 module-bluetooth/tests/test-Devicei.cpp create mode 100644 module-bluetooth/tests/tests-Devicei.cpp delete mode 100644 module-services/service-bluetooth/service-bluetooth/BluetoothSettingsModel.cpp delete mode 100644 module-services/service-bluetooth/service-bluetooth/BluetoothSettingsModel.hpp diff --git a/.gdbinit-1051 b/.gdbinit-1051 index e2063c26b91350cc403260111b1be60032df9c87..67a4c7881b390451483631c2e0e70480ce998982 100644 --- a/.gdbinit-1051 +++ b/.gdbinit-1051 @@ -13,4 +13,4 @@ info threads thread 2 tb main b HardFault_Handler - +b _exit diff --git a/module-apps/application-settings/ApplicationSettings.cpp b/module-apps/application-settings/ApplicationSettings.cpp index 57cb2a366cf3bf4c518bf892887674c721a82bd7..411b08f6e9becce3c40f1da1d2204fb70d9db699 100644 --- a/module-apps/application-settings/ApplicationSettings.cpp +++ b/module-apps/application-settings/ApplicationSettings.cpp @@ -226,6 +226,8 @@ namespace app }); connect(typeid(::message::bluetooth::RequestPasskey), [&](sys::Message *msg) { + auto m = dynamic_cast<::message::bluetooth::RequestPasskey *>(msg); + bluetoothSettingsModel->pinRequestor = m->getDevice(); switchWindow(gui::window::name::bluetooth_check_passkey); return sys::MessageNone{}; }); @@ -396,10 +398,10 @@ namespace app windowsFactory.attach(gui::window::name::phone_name, [this](ApplicationCommon *app, const std::string &name) { return std::make_unique(app, bluetoothSettingsModel); }); - windowsFactory.attach(gui::window::name::bluetooth_check_passkey, - [](ApplicationCommon *app, const std::string &name) { - return std::make_unique(app); - }); + windowsFactory.attach( + gui::window::name::bluetooth_check_passkey, [this](ApplicationCommon *app, const std::string &name) { + return std::make_unique(app, bluetoothSettingsModel); + }); // Network windowsFactory.attach(gui::window::name::network, [](ApplicationCommon *app, const std::string &name) { diff --git a/module-apps/application-settings/models/bluetooth/BluetoothSettingsModel.cpp b/module-apps/application-settings/models/bluetooth/BluetoothSettingsModel.cpp index 96a36fcc39b3ba24cb3ff13ab645e46cbf51b733..9493a740f9f0734138f1c4ee86a426582d65021b 100644 --- a/module-apps/application-settings/models/bluetooth/BluetoothSettingsModel.cpp +++ b/module-apps/application-settings/models/bluetooth/BluetoothSettingsModel.cpp @@ -70,7 +70,8 @@ void BluetoothSettingsModel::requestDeviceUnpair(const Devicei &device) void BluetoothSettingsModel::responsePasskey(const std::string &passkey) { - service->bus.sendUnicast(std::make_shared(passkey), service::name::bluetooth); + service->bus.sendUnicast(std::make_shared(passkey, pinRequestor), + service::name::bluetooth); } void BluetoothSettingsModel::requestConnection(const Devicei &device) diff --git a/module-apps/application-settings/models/bluetooth/BluetoothSettingsModel.hpp b/module-apps/application-settings/models/bluetooth/BluetoothSettingsModel.hpp index 1c22f543a1ca7a5929c5b097f7071faef11dfc90..11f7ca0b5f1d9cb93a7c50453166edfc9b128ec6 100644 --- a/module-apps/application-settings/models/bluetooth/BluetoothSettingsModel.hpp +++ b/module-apps/application-settings/models/bluetooth/BluetoothSettingsModel.hpp @@ -40,6 +40,7 @@ class BluetoothSettingsModel auto isDeviceConnecting() -> bool; auto getStatus() const -> const BluetoothStatus; auto isDeviceListEmpty() const -> bool; + Devicei pinRequestor; private: std::vector devices{}; diff --git a/module-apps/application-settings/windows/bluetooth/BluetoothCheckPasskeyWindow.cpp b/module-apps/application-settings/windows/bluetooth/BluetoothCheckPasskeyWindow.cpp index 4b56e8c51f324ce9cc33ba4fac8bbb5edc009f70..89abe568579363a7d5390e5fc63f813d16eefbe8 100644 --- a/module-apps/application-settings/windows/bluetooth/BluetoothCheckPasskeyWindow.cpp +++ b/module-apps/application-settings/windows/bluetooth/BluetoothCheckPasskeyWindow.cpp @@ -6,6 +6,7 @@ #include #include +#include #include namespace gui @@ -17,10 +18,11 @@ namespace gui } // namespace namespace passkey_style = style::settings::window::bluetooth::passkey; - BluetoothCheckPasskeyWindow::BluetoothCheckPasskeyWindow(app::ApplicationCommon *app) - : AppWindow(app, window::name::bluetooth_check_passkey) + BluetoothCheckPasskeyWindow::BluetoothCheckPasskeyWindow( + app::ApplicationCommon *app, std::shared_ptr bluetoothSettingsModel) + : AppWindow(app, window::name::bluetooth_check_passkey), + bluetoothSettingsModel(std::move(bluetoothSettingsModel)) { - bluetoothSettingsModel = std::make_unique(application); buildInterface(); } diff --git a/module-apps/application-settings/windows/bluetooth/BluetoothCheckPasskeyWindow.hpp b/module-apps/application-settings/windows/bluetooth/BluetoothCheckPasskeyWindow.hpp index 35b623475aa2d5d5c1b43e8ce03666f4b4f7d411..0c79793774a12635380f97630ceb16f85a6c7a5d 100644 --- a/module-apps/application-settings/windows/bluetooth/BluetoothCheckPasskeyWindow.hpp +++ b/module-apps/application-settings/windows/bluetooth/BluetoothCheckPasskeyWindow.hpp @@ -13,7 +13,8 @@ namespace gui class BluetoothCheckPasskeyWindow : public AppWindow { public: - explicit BluetoothCheckPasskeyWindow(app::ApplicationCommon *app); + BluetoothCheckPasskeyWindow(app::ApplicationCommon *app, + std::shared_ptr bluetoothSettingsModel); private: void buildInterface() override; @@ -22,6 +23,6 @@ namespace gui Image *image = nullptr; Label *label = nullptr; Text *text = nullptr; - std::unique_ptr bluetoothSettingsModel; + std::shared_ptr bluetoothSettingsModel; }; } // namespace gui diff --git a/module-bluetooth/Bluetooth/BtKeysStorage.cpp b/module-bluetooth/Bluetooth/BtKeysStorage.cpp index d2c052af6e348b16ae249cb77e03935c11ec40c5..d7276d27272cb755360ddc795fdafbd4db5b581d 100644 --- a/module-bluetooth/Bluetooth/BtKeysStorage.cpp +++ b/module-bluetooth/Bluetooth/BtKeysStorage.cpp @@ -59,7 +59,6 @@ namespace bluetooth } keys = std::move(keysJson[strings::keys].array_items()); - LOG_INFO("Imported keys: %d", static_cast(keys.size())); } void KeyStorage::closeStorage() diff --git a/module-bluetooth/Bluetooth/Device.cpp b/module-bluetooth/Bluetooth/Device.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48b753ec928b5155209ad353da543c51926c952a --- /dev/null +++ b/module-bluetooth/Bluetooth/Device.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "Device.hpp" +#include + +Devicei::Devicei(std::string name) : Device(std::move(name)) +{ + pageScanRepetitionMode = {}; + clockOffset = {}; + classOfDevice = {}; + state = DEVICE_STATE::REMOTE_NAME_FAILURE; + deviceState = DeviceState::Unknown; + isPairingSSP = false; + + memset(address, 0, sizeof(address)); +} + +Devicei::Devicei(bd_addr_t &address) : Devicei() +{ + setAddress(&address); +} + +Devicei &Devicei::operator=(const Devicei &d) +{ + if (&d == this) { + return *this; + } + setAddress(&d.address); + setName(d.name.data()); + pageScanRepetitionMode = d.pageScanRepetitionMode; + clockOffset = d.clockOffset; + classOfDevice = d.classOfDevice; + state = d.state; + deviceState = d.deviceState; + isPairingSSP = d.isPairingSSP; + return *this; +} + +Devicei::Devicei(const Devicei &d) : Devicei(d.name.data()) +{ + operator=(d); +} + +Devicei &Devicei::operator=(Devicei &&d) noexcept +{ + setAddress(&d.address); + setName(d.name.data()); + pageScanRepetitionMode = d.pageScanRepetitionMode; + clockOffset = d.clockOffset; + classOfDevice = d.classOfDevice; + state = d.state; + deviceState = d.deviceState; + isPairingSSP = d.isPairingSSP; + return *this; +} + +Devicei::Devicei(Devicei &&d) noexcept : Devicei(d.name.data()) +{ + operator=(d); +} + +void Devicei::setAddress(bd_addr_t *addr) +{ + memcpy(&address, addr, sizeof address); +} + +bool Devicei::operator==(const Devicei &cmpDevice) const +{ + return (strcmp(cmpDevice.name.data(), name.data()) == 0) && (bd_addr_cmp(cmpDevice.address, address) == 0); +} + +bool Devicei::operator!=(const Devicei &cmpDevice) const +{ + return (strcmp(cmpDevice.name.data(), name.data()) != 0) || (bd_addr_cmp(cmpDevice.address, address) != 0); +} + +auto Devicei::address_str() const -> const char * +{ + return bd_addr_to_str(address); +} diff --git a/module-bluetooth/Bluetooth/Device.hpp b/module-bluetooth/Bluetooth/Device.hpp index 73143fdf94744a5e6147046d32ee3d0a4d0b9bf9..c64edb4623e5256c044cd55f709568c53a819cfb 100644 --- a/module-bluetooth/Bluetooth/Device.hpp +++ b/module-bluetooth/Bluetooth/Device.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -16,21 +15,26 @@ struct Device public: static constexpr auto NameBufferSize = 240; explicit Device(std::string name = "") + { + setName(name); + } + virtual ~Device() = default; + std::array name; + void setName(const std::string &name) { if (name.size() > NameBufferSize) { throw std::runtime_error("Requested name is bigger than buffer size"); } strcpy(this->name.data(), name.c_str()); } - virtual ~Device() = default; - std::array name; }; enum DEVICE_STATE { REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, - REMOTE_NAME_FETCHED + REMOTE_NAME_FETCHED, + REMOTE_NAME_FAILURE, }; namespace TYPE_OF_SERVICE @@ -96,37 +100,25 @@ enum class DeviceState struct Devicei : public Device { public: - bd_addr_t address; - uint8_t pageScanRepetitionMode; - uint16_t clockOffset; - uint32_t classOfDevice; ///> Class of Device/Service + mutable bd_addr_t address{}; + uint8_t pageScanRepetitionMode{}; + uint16_t clockOffset{}; + uint32_t classOfDevice{}; ///> Class of Device/Service DEVICE_STATE state; DeviceState deviceState; - - explicit Devicei(std::string name = "") : Device(std::move(name)) - { - memset(address, 0, sizeof(address)); - } + bool isPairingSSP = false; + + explicit Devicei(std::string name = ""); + explicit Devicei(bd_addr_t &address); + Devicei &operator=(const Devicei &d); + Devicei(const Devicei &d); + Devicei &operator=(Devicei &&d) noexcept; + Devicei(Devicei &&d) noexcept; ~Devicei() override = default; - void setAddress(bd_addr_t *addr) - { - memcpy(&address, addr, sizeof address); - } - - inline bool operator==(const Devicei &cmpDevice) const - { - return (strcmp(cmpDevice.name.data(), name.data()) == 0) && (bd_addr_cmp(cmpDevice.address, address) == 0); - } - - inline bool operator!=(const Devicei &cmpDevice) const - { - return (strcmp(cmpDevice.name.data(), name.data()) != 0) || (bd_addr_cmp(cmpDevice.address, address) != 0); - } - - auto address_str() const -> const char * - { - return bd_addr_to_str(address); - } + void setAddress(bd_addr_t *addr); + bool operator==(const Devicei &cmpDevice) const; + bool operator!=(const Devicei &cmpDevice) const; + auto address_str() const -> const char *; }; struct DeviceMetadata_t diff --git a/module-bluetooth/Bluetooth/error_bluetooth.cpp b/module-bluetooth/Bluetooth/error_bluetooth.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b5d9a5d46ef8790c425363bbdb0959a7190a7de --- /dev/null +++ b/module-bluetooth/Bluetooth/error_bluetooth.cpp @@ -0,0 +1,142 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "error_bluetooth.hpp" +#include + +namespace bluetooth +{ + const char *error_cstr(int err) + { + switch (err) { + case ERROR_CODE_SUCCESS: + return "ERROR_CODE_SUCCESS"; + case ERROR_CODE_UNKNOWN_HCI_COMMAND: + return "ERROR_CODE_UNKNOWN_HCI_COMMAND"; + case ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER: + return "ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER"; + case ERROR_CODE_HARDWARE_FAILURE: + return "ERROR_CODE_HARDWARE_FAILURE"; + case ERROR_CODE_PAGE_TIMEOUT: + return "ERROR_CODE_PAGE_TIMEOUT"; + case ERROR_CODE_AUTHENTICATION_FAILURE: + return "ERROR_CODE_AUTHENTICATION_FAILURE"; + case ERROR_CODE_PIN_OR_KEY_MISSING: + return "ERROR_CODE_PIN_OR_KEY_MISSING"; + case ERROR_CODE_MEMORY_CAPACITY_EXCEEDED: + return "ERROR_CODE_MEMORY_CAPACITY_EXCEEDED"; + case ERROR_CODE_CONNECTION_TIMEOUT: + return "ERROR_CODE_CONNECTION_TIMEOUT"; + case ERROR_CODE_CONNECTION_LIMIT_EXCEEDED: + return "ERROR_CODE_CONNECTION_LIMIT_EXCEEDED"; + case ERROR_CODE_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED: + return "ERROR_CODE_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED"; + case ERROR_CODE_ACL_CONNECTION_ALREADY_EXISTS: + return "ERROR_CODE_ACL_CONNECTION_ALREADY_EXISTS"; + case ERROR_CODE_COMMAND_DISALLOWED: + return "ERROR_CODE_COMMAND_DISALLOWED"; + case ERROR_CODE_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES: + return "ERROR_CODE_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES"; + case ERROR_CODE_CONNECTION_REJECTED_DUE_TO_SECURITY_REASONS: + return "ERROR_CODE_CONNECTION_REJECTED_DUE_TO_SECURITY_REASONS"; + case ERROR_CODE_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR: + return "ERROR_CODE_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR"; + case ERROR_CODE_CONNECTION_ACCEPT_TIMEOUT_EXCEEDED: + return "ERROR_CODE_CONNECTION_ACCEPT_TIMEOUT_EXCEEDED"; + case ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE: + return "ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE"; + case ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS: + return "ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS"; + case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION: + return "ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION"; + case ERROR_CODE_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES: + return "ERROR_CODE_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES"; + case ERROR_CODE_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_POWER_OFF: + return "ERROR_CODE_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_POWER_OFF"; + case ERROR_CODE_CONNECTION_TERMINATED_BY_LOCAL_HOST: + return "ERROR_CODE_CONNECTION_TERMINATED_BY_LOCAL_HOST"; + case ERROR_CODE_REPEATED_ATTEMPTS: + return "ERROR_CODE_REPEATED_ATTEMPTS"; + case ERROR_CODE_PAIRING_NOT_ALLOWED: + return "ERROR_CODE_PAIRING_NOT_ALLOWED"; + case ERROR_CODE_UNKNOWN_LMP_PDU: + return "ERROR_CODE_UNKNOWN_LMP_PDU"; + case ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE_UNSUPPORTED_LMP_FEATURE: + return "ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE_UNSUPPORTED_LMP_FEATURE"; + case ERROR_CODE_SCO_OFFSET_REJECTED: + return "ERROR_CODE_SCO_OFFSET_REJECTED"; + case ERROR_CODE_SCO_INTERVAL_REJECTED: + return "ERROR_CODE_SCO_INTERVAL_REJECTED"; + case ERROR_CODE_SCO_AIR_MODE_REJECTED: + return "ERROR_CODE_SCO_AIR_MODE_REJECTED"; + case ERROR_CODE_INVALID_LMP_PARAMETERS_INVALID_LL_PARAMETERS: + return "ERROR_CODE_INVALID_LMP_PARAMETERS_INVALID_LL_PARAMETERS"; + case ERROR_CODE_UNSPECIFIED_ERROR: + return "ERROR_CODE_UNSPECIFIED_ERROR"; + case ERROR_CODE_UNSUPPORTED_LMP_PARAMETER_VALUE_UNSUPPORTED_LL_PARAMETER_VALUE: + return "ERROR_CODE_UNSUPPORTED_LMP_PARAMETER_VALUE_UNSUPPORTED_LL_PARAMETER_VALUE"; + case ERROR_CODE_ROLE_CHANGE_NOT_ALLOWED: + return "ERROR_CODE_ROLE_CHANGE_NOT_ALLOWED"; + case ERROR_CODE_LMP_RESPONSE_TIMEOUT_LL_RESPONSE_TIMEOUT: + return "ERROR_CODE_LMP_RESPONSE_TIMEOUT_LL_RESPONSE_TIMEOUT"; + case ERROR_CODE_LMP_ERROR_TRANSACTION_COLLISION: + return "ERROR_CODE_LMP_ERROR_TRANSACTION_COLLISION"; + case ERROR_CODE_LMP_PDU_NOT_ALLOWED: + return "ERROR_CODE_LMP_PDU_NOT_ALLOWED"; + case ERROR_CODE_ENCRYPTION_MODE_NOT_ACCEPTABLE: + return "ERROR_CODE_ENCRYPTION_MODE_NOT_ACCEPTABLE"; + case ERROR_CODE_LINK_KEY_CANNOT_BE_CHANGED: + return "ERROR_CODE_LINK_KEY_CANNOT_BE_CHANGED"; + case ERROR_CODE_REQUESTED_QOS_NOT_SUPPORTED: + return "ERROR_CODE_REQUESTED_QOS_NOT_SUPPORTED"; + case ERROR_CODE_INSTANT_PASSED: + return "ERROR_CODE_INSTANT_PASSED"; + case ERROR_CODE_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED: + return "ERROR_CODE_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED"; + case ERROR_CODE_DIFFERENT_TRANSACTION_COLLISION: + return "ERROR_CODE_DIFFERENT_TRANSACTION_COLLISION"; + case ERROR_CODE_RESERVED: + return "ERROR_CODE_RESERVED"; + case ERROR_CODE_QOS_UNACCEPTABLE_PARAMETER: + return "ERROR_CODE_QOS_UNACCEPTABLE_PARAMETER"; + case ERROR_CODE_QOS_REJECTED: + return "ERROR_CODE_QOS_REJECTED"; + case ERROR_CODE_CHANNEL_CLASSIFICATION_NOT_SUPPORTED: + return "ERROR_CODE_CHANNEL_CLASSIFICATION_NOT_SUPPORTED"; + case ERROR_CODE_INSUFFICIENT_SECURITY: + return "ERROR_CODE_INSUFFICIENT_SECURITY"; + case ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE: + return "ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE"; + case ERROR_CODE_ROLE_SWITCH_PENDING: + return "ERROR_CODE_ROLE_SWITCH_PENDING"; + case ERROR_CODE_RESERVED_SLOT_VIOLATION: + return "ERROR_CODE_RESERVED_SLOT_VIOLATION"; + case ERROR_CODE_ROLE_SWITCH_FAILED: + return "ERROR_CODE_ROLE_SWITCH_FAILED"; + case ERROR_CODE_EXTENDED_INQUIRY_RESPONSE_TOO_LARGE: + return "ERROR_CODE_EXTENDED_INQUIRY_RESPONSE_TOO_LARGE"; + case ERROR_CODE_SECURE_SIMPLE_PAIRING_NOT_SUPPORTED_BY_HOST: + return "ERROR_CODE_SECURE_SIMPLE_PAIRING_NOT_SUPPORTED_BY_HOST"; + case ERROR_CODE_HOST_BUSY_PAIRING: + return "ERROR_CODE_HOST_BUSY_PAIRING"; + case ERROR_CODE_CONNECTION_REJECTED_DUE_TO_NO_SUITABLE_CHANNEL_FOUND: + return "ERROR_CODE_CONNECTION_REJECTED_DUE_TO_NO_SUITABLE_CHANNEL_FOUND"; + case ERROR_CODE_CONTROLLER_BUSY: + return "ERROR_CODE_CONTROLLER_BUSY"; + case ERROR_CODE_UNACCEPTABLE_CONNECTION_PARAMETERS: + return "ERROR_CODE_UNACCEPTABLE_CONNECTION_PARAMETERS"; + case ERROR_CODE_DIRECTED_ADVERTISING_TIMEOUT: + return "ERROR_CODE_DIRECTED_ADVERTISING_TIMEOUT"; + case ERROR_CODE_CONNECTION_TERMINATED_DUE_TO_MIC_FAILURE: + return "ERROR_CODE_CONNECTION_TERMINATED_DUE_TO_MIC_FAILURE"; + case ERROR_CODE_CONNECTION_FAILED_TO_BE_ESTABLISHED: + return "ERROR_CODE_CONNECTION_FAILED_TO_BE_ESTABLISHED"; + case ERROR_CODE_MAC_CONNECTION_FAILED: + return "ERROR_CODE_MAC_CONNECTION_FAILED"; + case ERROR_CODE_COARSE_CLOCK_ADJUSTMENT_REJECTED_BUT_WILL_TRY_TO_ADJUST_USING_CLOCK_DRAGGING: + return "ERROR_CODE_COARSE_CLOCK_ADJUSTMENT_REJECTED_BUT_WILL_TRY_TO_ADJUST_USING_CLOCK_DRAGGING"; + default: + return "ERROR_CODE_UNDEFINED"; + } + } +} // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/error_bluetooth.hpp b/module-bluetooth/Bluetooth/error_bluetooth.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9252ea6d248268a49e4ee4ca2a6e487b4b8fc768 --- /dev/null +++ b/module-bluetooth/Bluetooth/error_bluetooth.hpp @@ -0,0 +1,8 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +/// all these are taken from the defines to have textual representation +namespace bluetooth +{ + const char *error_cstr(int err); +} diff --git a/module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.cpp b/module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.cpp index 5440e4165a11c4d88ed308bb9e471f34af71039e..f79ac6ee29846b6575a7c0b19df02963c967d9d7 100644 --- a/module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.cpp +++ b/module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.cpp @@ -82,6 +82,9 @@ namespace bluetooth hci_set_link_key_db(bluetooth::KeyStorage::getKeyStorage()); hci_event_callback_registration.callback = &hci_packet_handler; hci_add_event_handler(&hci_event_callback_registration); + + gap_ssp_set_io_capability(SSP_IO_CAPABILITY_KEYBOARD_ONLY); + gap_ssp_set_auto_accept(false); LOG_DEBUG("BT worker run success"); return Error::Success; } diff --git a/module-bluetooth/Bluetooth/interface/profiles/GAP/Devices.cpp b/module-bluetooth/Bluetooth/interface/profiles/GAP/Devices.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65fe7804ead21870f135baef1eb0cf4b319b0fdf --- /dev/null +++ b/module-bluetooth/Bluetooth/interface/profiles/GAP/Devices.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "Devices.hpp" +#include + +namespace bluetooth::gap +{ + auto Devices::getList() -> std::vector + { + return {devices.begin(), devices.end()}; + } + + Devices::iter Devices::find(bd_addr_t &addr) + { + return std::find_if(std::begin(devices), std::end(devices), [addr](const Devicei &device) { + return bd_addr_cmp(addr, device.address) == 0; + }); + } + + Devices::iter Devices::find(DEVICE_STATE st) + { + return std::find_if( + std::begin(devices), std::end(devices), [st](const Devicei &device) { return st == device.state; }); + } + + void Devices::for_each(const std::function &f) + { + if (not f) { + return; + } + for (auto &el : devices) { + f(el); + } + } + + Devices::iter Devices::end() + { + return std::end(devices); + } + + Devices::iter Devices::put(Devicei &&dev) + { + if (const auto &it = find(dev.address); it != end()) { + devices.erase(it); + } + devices.emplace_back(dev); + return std::prev(devices.end()); + } + + Devices::iter Devices::put(bd_addr_t &addr) + { + if (const auto &it = find(addr); it != end()) { + devices.erase(it); + } + devices.emplace_back(Devicei(addr)); + return std::prev(devices.end()); + } + + void Devices::clear() + { + devices.clear(); + } +} // namespace bluetooth::gap diff --git a/module-bluetooth/Bluetooth/interface/profiles/GAP/Devices.hpp b/module-bluetooth/Bluetooth/interface/profiles/GAP/Devices.hpp new file mode 100644 index 0000000000000000000000000000000000000000..01db8c8560e7655f849737e003a163c7ec0bfc31 --- /dev/null +++ b/module-bluetooth/Bluetooth/interface/profiles/GAP/Devices.hpp @@ -0,0 +1,30 @@ +// 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 + +namespace bluetooth::gap +{ + /// class to store and get devices in GAP operations + class Devices + { + std::list devices; + + public: + using iter = decltype(devices)::iterator; + iter find(bd_addr_t &addr); + iter find(DEVICE_STATE st); + void for_each(const std::function &f); + iter end(); + // adds element, if element already on list - remove and add anew + iter put(Devicei &&dev); + // same as above + iter put(bd_addr_t &addr); + void clear(); + auto getList() -> std::vector; + }; +} // namespace bluetooth::gap diff --git a/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp b/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp index e4df6fffd86101b4b5a2b700cb42e0196683b146..fe3d8b619545744aefa0541635bc151ba1fea951 100644 --- a/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp +++ b/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp @@ -2,12 +2,17 @@ // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "GAP.hpp" +#include "Devices.hpp" +#include "GAP/used_events.hpp" -#include +#include #include #include #include #include +#include +#include +#include extern "C" { #include "btstack.h" @@ -15,11 +20,27 @@ extern "C" }; namespace bluetooth { - Devicei GAP::currentlyProccesedDevice; sys::Service *GAP::ownerService = nullptr; - std::vector GAP::devices; btstack_packet_callback_registration_t GAP::cb_handler; - ScanState GAP::state; + stack::state GAP::state; + + namespace gap + { + enum class state + { + scan_off = 0, + scan_on, + } static state; + } + + static gap::Devices &devices() + { + static std::unique_ptr dev; + if (not dev) { + dev = std::make_unique(); + } + return *dev; + }; auto GAP::registerScan() -> Error { @@ -34,11 +55,15 @@ namespace bluetooth auto GAP::scan() -> Error { if (hci_get_state() == HCI_STATE_WORKING) { - devices.clear(); + if (gap::state == gap::state::scan_on) { + stopScan(); + } + devices().clear(); if (auto ret = startScan(); ret != 0) { - LOG_ERROR("Start scan error!: 0x%X", ret); + LOG_ERROR("Start scan error!: 0x%02X - %s", ret, error_cstr(ret)); return Error(Error::LibraryError, ret); } + gap::state = gap::state::scan_on; } else { return Error(Error::NotReady); @@ -48,6 +73,7 @@ namespace bluetooth void GAP::stopScan() { + gap::state = gap::state::scan_off; gap_inquiry_force_stop(); LOG_INFO("Scan stopped!"); } @@ -61,30 +87,20 @@ namespace bluetooth auto GAP::pair(Devicei device, std::uint8_t protectionLevel) -> bool { if (hci_get_state() == HCI_STATE_WORKING) { - auto devIndex = getDeviceIndexForAddress(devices, device.address); - currentlyProccesedDevice = devices.at(devIndex); - + auto it = devices().find(device.address); + if (it == devices().end()) { + LOG_ERROR("device not found: %s", device.address_str()); + return false; + } return gap_dedicated_bonding(device.address, protectionLevel) == 0; } return false; } - auto GAP::getDeviceIndexForAddress(const std::vector &devs, const 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); + auto msg = std::make_shared(devices().getList()); ownerService->bus.sendMulticast(std::move(msg), sys::BusChannel::BluetoothNotifications); } @@ -94,48 +110,28 @@ namespace bluetooth 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..."); - gap_remote_name_request(device.address, device.pageScanRepetitionMode, device.clockOffset | 0x8000); - return; - } - } - } - void GAP::continueScanning() { - if (remoteNameToFetch()) { - fetchRemoteName(); + if (const auto &it = devices().find(REMOTE_NAME_REQUEST); it != devices().end()) { + LOG_INFO("Get remote name for %s", it->name.data()); + it->state = REMOTE_NAME_INQUIRED; + gap_remote_name_request(it->address, it->pageScanRepetitionMode, it->clockOffset | 0x8000); return; } - startScan(); + if (gap::state == gap::state::scan_on) { + 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) { - devices[index].state = REMOTE_NAME_FETCHED; - strcpy(devices[index].name.data(), reinterpret_cast(&packet[9])); - return true; - } - else { - LOG_INFO("Failed to get name: page timeout"); + if (auto it = devices().find(addr); it != devices().end()) { + it->state = packet[2] ? REMOTE_NAME_FAILURE : REMOTE_NAME_FETCHED; + if (it->state != REMOTE_NAME_FAILURE) { + strcpy(it->name.data(), reinterpret_cast(&packet[9])); } + return it->state == REMOTE_NAME_FETCHED; } return false; } @@ -148,6 +144,7 @@ namespace bluetooth device.clockOffset = gap_event_inquiry_result_get_clock_offset(packet); device.classOfDevice = gap_event_inquiry_result_get_class_of_device(packet); LOG_INFO("Device found "); + LOG_INFO("with address: %s, ", device.address_str()); LOG_INFO("with COD: 0x%06x, ", static_cast(device.classOfDevice)); LOG_INFO("pageScan %d, ", device.pageScanRepetitionMode); LOG_INFO("clock offset 0x%04x", device.clockOffset); @@ -171,14 +168,15 @@ namespace bluetooth strcpy(device.name.data(), bd_addr_to_str(devAddr)); } - devices.emplace_back(std::move(device)); + devices().put(std::move(device)); } - void GAP::processInquiryResult(std::uint8_t *packet, bd_addr_t &addr) + 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) { + auto it = devices().find(addr); + if (it != devices().end()) { return; // already in our list } uint32_t classOfDevice = gap_event_inquiry_result_get_class_of_device(packet); @@ -194,12 +192,11 @@ namespace bluetooth } void GAP::processInquiryComplete() { - for (auto &device : devices) { - // retry remote name request - if (device.state == REMOTE_NAME_INQUIRED) { - device.state = REMOTE_NAME_REQUEST; + devices().for_each([](Devicei &d) { + if (d.state == REMOTE_NAME_INQUIRED) { + d.state = REMOTE_NAME_REQUEST; } - } + }); continueScanning(); } void GAP::processNameRequestComplete(std::uint8_t *packet, bd_addr_t &addr) @@ -209,13 +206,15 @@ namespace bluetooth } continueScanning(); } + void GAP::processDedicatedBondingCompleted(std::uint8_t *packet, bd_addr_t &addr) { auto result = packet[2]; - - auto msg = std::make_shared(currentlyProccesedDevice, result == 0u); - ownerService->bus.sendUnicast(std::move(msg), "ServiceBluetooth"); + auto it = devices().find(addr); + auto msg = std::make_shared(it != devices().end() ? *it : Devicei(), result == 0u); + ownerService->bus.sendUnicast(std::move(msg), service::name::bluetooth); } + /* @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. @@ -225,71 +224,136 @@ namespace bluetooth * - 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) + void GAP::activeStateHandler(std::uint8_t eventType, std::uint8_t *packet, std::uint16_t size) { + if (not(eventType == HCI_EVENT_TRANSPORT_PACKET_SENT || eventType == HCI_EVENT_COMMAND_STATUS || + eventType == HCI_EVENT_INQUIRY_COMPLETE || eventType == HCI_EVENT_COMMAND_COMPLETE)) { + LOG_DEBUG("event: 0x%02X - %s - size: %" PRIu16, eventType, evt_cstr(eventType), size); + } switch (eventType) { + case HCI_EVENT_TRANSPORT_PACKET_SENT: + break; + case HCI_EVENT_EXTENDED_INQUIRY_RESPONSE: + break; + case GAP_EVENT_PAIRING_STARTED: + break; + + case HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE: + break; + + case HCI_EVENT_USER_CONFIRMATION_REQUEST: { + bd_addr_t addr; + hci_event_user_confirmation_request_get_bd_addr(packet, addr); + hci_connection_t *conn = hci_connection_for_bd_addr_and_type(addr, BD_ADDR_TYPE_ACL); + hci_send_cmd(&hci_user_confirmation_request_reply, &conn->address); + } break; + + case HCI_EVENT_PIN_CODE_REQUEST: { + bd_addr_t addr; + hci_event_pin_code_request_get_bd_addr(packet, addr); + auto it = devices().find(addr); + if (it == devices().end()) { + gap_remote_name_request(addr, PAGE_SCAN_MODE_STANDARD, 0); + it = devices().put(addr); + } + it->isPairingSSP = false; + + auto msg = std::make_shared<::message::bluetooth::RequestPasskey>(*it); + ownerService->bus.sendMulticast(std::move(msg), sys::BusChannel::BluetoothNotifications); + } break; + + case HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES_COMPLETE: { + uint16_t handle = little_endian_read_16(packet, 3); + hci_connection_t *conn = hci_connection_for_handle(handle); + auto yes = gap_ssp_supported_on_both_sides(conn->con_handle); + auto it = devices().find(conn->address); + if (it == devices().end()) { + return; + } + it->isPairingSSP = yes; + } break; case GAP_EVENT_INQUIRY_RESULT: - processInquiryResult(packet, addr); + processInquiryResult(packet); break; case GAP_EVENT_INQUIRY_COMPLETE: processInquiryComplete(); break; - - case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: + case HCI_EVENT_USER_PASSKEY_REQUEST: { + bd_addr_t addr; + hci_event_user_passkey_request_get_bd_addr(packet, addr); + auto it = devices().find(addr); + if (it == devices().end()) { + gap_remote_name_request(addr, PAGE_SCAN_MODE_STANDARD, 0); + it = devices().put(addr); + } + it->isPairingSSP = true; + ownerService->bus.sendMulticast(std::make_shared<::message::bluetooth::RequestPasskey>(*it), + sys::BusChannel::BluetoothNotifications); + } break; + case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: { + bd_addr_t addr; + hci_event_remote_name_request_complete_get_bd_addr(packet, addr); processNameRequestComplete(packet, addr); - break; + } break; case GAP_EVENT_DEDICATED_BONDING_COMPLETED: + bd_addr_t addr; + reverse_bd_addr(&packet[3], addr); processDedicatedBondingCompleted(packet, addr); break; + case HCI_EVENT_SIMPLE_PAIRING_COMPLETE: { + bd_addr_t addr; + hci_event_simple_pairing_complete_get_bd_addr(packet, addr); + processSimplePairingCompleted(packet, addr); + } break; + case GAP_EVENT_PAIRING_COMPLETE: + LOG_DEBUG("status: 0x%02X", packet[10]); + 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; + state = stack::state::working; } } } + 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; } - if (hci_event_packet_get_type(packet) == HCI_EVENT_PIN_CODE_REQUEST) { - bd_addr_t address; - LOG_DEBUG("PIN code request!"); - hci_event_pin_code_request_get_bd_addr(packet, address); - auto msg = std::make_shared<::message::bluetooth::RequestPasskey>(); - ownerService->bus.sendMulticast(std::move(msg), sys::BusChannel::BluetoothNotifications); - } const auto eventType = hci_event_packet_get_type(packet); switch (state) { - case ScanState::init: + case stack::state::init: initStateHandler(eventType, packet); break; - case ScanState::active: - activeStateHandler(eventType, packet, addr); + case stack::state::working: + activeStateHandler(eventType, packet, size); break; default: break; } } + GAP::GAP(sys::Service *owner) { ownerService = owner; - state = ScanState::init; + state = stack::state::init; } - auto GAP::getDevicesList() -> const std::vector & + + auto GAP::getDevicesList() -> std::vector { - return devices; + return devices().getList(); } + auto GAP::unpair(Devicei device) -> bool { LOG_INFO("Unpairing device"); @@ -300,8 +364,45 @@ namespace bluetooth sys::BusChannel::BluetoothNotifications); return true; } - void GAP::respondPinCode(const std::string &pin) + + void GAP::respondPinCode(const std::string &pin, Devicei d) + { + LOG_DEBUG("pairing response for device: %s pin: %s is SSP? %s", + d.address_str(), + pin.c_str(), + d.isPairingSSP ? "yes" : "no"); + if (!d.isPairingSSP) { + gap_pin_code_response(d.address, pin.c_str()); + return; + } + + unsigned int passkey = 0; + try { + passkey = stoi(pin); + LOG_DEBUG("Sending %06u as a passkey", passkey); + } + catch (const std::invalid_argument &e) { + LOG_ERROR("STOI error: %s", e.what()); + } + + gap_ssp_passkey_response(d.address, passkey); + } + + void GAP::processSimplePairingCompleted(std::uint8_t *packet, bd_addr_t &addr) { - gap_pin_code_response(currentlyProccesedDevice.address, pin.c_str()); + auto status = hci_event_simple_pairing_complete_get_status(packet); + auto it = devices().find(addr); + LOG_INFO("HCI_EVENT_SIMPLE_PAIRING_COMPLETE: 0x%02X - %s - device found: %s : address: %s", + status, + error_cstr(status), + it != devices().end() ? "found" : "fail", + bd_addr_to_str(addr)); + if (it == devices().end()) { + auto msg = std::make_shared(Devicei(), false); + ownerService->bus.sendUnicast(std::move(msg), service::name::bluetooth); + return; + } + auto msg = std::make_shared(*it, status == ERROR_CODE_SUCCESS); + ownerService->bus.sendUnicast(std::move(msg), service::name::bluetooth); } } // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp b/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp index 08ae9bf2d5f308a9a824153a420189af1f799020..e1517aa306f1275e7dba03479cc357ccd12f9f2f 100644 --- a/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp +++ b/module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp @@ -12,35 +12,40 @@ extern "C" } namespace bluetooth { - enum ScanState + namespace stack { - init, - active, - done - }; + enum state + { + off, + init, + working, + halting, + sleeping, + falling_asleep + }; + } + 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 stack::state 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 activeStateHandler(std::uint8_t eventType, std::uint8_t *packet, std::uint16_t size); 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 processInquiryResult(std::uint8_t *packet); static void processInquiryComplete(); static void processNameRequestComplete(std::uint8_t *packet, bd_addr_t &addr); static void processDedicatedBondingCompleted(std::uint8_t *packet, bd_addr_t &addr); + static void processSimplePairingCompleted(std::uint8_t *packet, bd_addr_t &addr); static void initStateHandler(std::uint8_t eventType, std::uint8_t *packet); static auto getDeviceIndexForAddress(const std::vector &devs, const bd_addr_t addr) -> int; @@ -52,8 +57,8 @@ namespace bluetooth void setVisibility(bool visibility); auto pair(Devicei device, std::uint8_t protectionLevel = 0) -> bool; auto unpair(Devicei device) -> bool; - static auto getDevicesList() -> const std::vector &; - static void respondPinCode(const std::string &pin); + static auto getDevicesList() -> std::vector; + static void respondPinCode(const std::string &pin, Devicei d); static Devicei currentlyProccesedDevice; explicit GAP(sys::Service *owner); diff --git a/module-bluetooth/Bluetooth/interface/profiles/GAP/used_events.cpp b/module-bluetooth/Bluetooth/interface/profiles/GAP/used_events.cpp new file mode 100644 index 0000000000000000000000000000000000000000..351aabd5e256efc622bd687cdb1d5a7f01b8fb69 --- /dev/null +++ b/module-bluetooth/Bluetooth/interface/profiles/GAP/used_events.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "used_events.hpp" +#include + +namespace bluetooth +{ + const char *evt_cstr(int evt) + { + switch (evt) { + // ---------- + // HCI EVENTS + // ---------- + case HCI_EVENT_TRANSPORT_PACKET_SENT: + return "HCI_EVENT_TRANSPORT_PACKET_SENT"; + case HCI_EVENT_COMMAND_COMPLETE: + return "HCI_EVENT_COMMAND_COMPLETE"; + case HCI_EVENT_COMMAND_STATUS: + return "HCI_EVENT_COMMAND_STATUS"; + case HCI_EVENT_INQUIRY_COMPLETE: + return "HCI_EVENT_INQUIRY_COMPLETE"; + case HCI_EVENT_EXTENDED_INQUIRY_RESPONSE: + return "HCI_EVENT_EXTENDED_INQUIRY_RESPONSE"; + case HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE: + return "HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE"; + case HCI_EVENT_USER_CONFIRMATION_REQUEST: + return "HCI_EVENT_USER_CONFIRMATION_REQUEST"; + case HCI_EVENT_PIN_CODE_REQUEST: + return "HCI_EVENT_PIN_CODE_REQUEST"; + case HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES_COMPLETE: + return "HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES_COMPLETE"; + case HCI_EVENT_USER_PASSKEY_REQUEST: + return "HCI_EVENT_USER_PASSKEY_REQUEST"; + case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: + return "HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE"; + case HCI_EVENT_SIMPLE_PAIRING_COMPLETE: + return "HCI_EVENT_SIMPLE_PAIRING_COMPLETE"; + + // ---------- + // GAP EVENTS + // ---------- + case GAP_EVENT_PAIRING_COMPLETE: + return "GAP_EVENT_PAIRING_COMPLETE"; + case GAP_EVENT_DEDICATED_BONDING_COMPLETED: + return "GAP_EVENT_DEDICATED_BONDING_COMPLETED"; + case GAP_EVENT_INQUIRY_RESULT: + return "GAP_EVENT_INQUIRY_RESULT"; + case GAP_EVENT_INQUIRY_COMPLETE: + return "GAP_EVENT_INQUIRY_COMPLETE"; + case GAP_EVENT_PAIRING_STARTED: + return "GAP_EVENT_PAIRING_STARTED"; + default: + return "EVENT_UNKNOWN"; + } + } +} // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/interface/profiles/GAP/used_events.hpp b/module-bluetooth/Bluetooth/interface/profiles/GAP/used_events.hpp new file mode 100644 index 0000000000000000000000000000000000000000..18c6b51974b97be0b15052e994ec784f773a8b9b --- /dev/null +++ b/module-bluetooth/Bluetooth/interface/profiles/GAP/used_events.hpp @@ -0,0 +1,9 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +namespace bluetooth +{ + const char *evt_cstr(int evt); +} diff --git a/module-bluetooth/CMakeLists.txt b/module-bluetooth/CMakeLists.txt index e489022f27296bcfea96c9e549a70b12acb5c532..704a63978912d182887846db2e508a9961e3042c 100644 --- a/module-bluetooth/CMakeLists.txt +++ b/module-bluetooth/CMakeLists.txt @@ -10,12 +10,16 @@ module_is_test_entity() set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/audio/BluetoothAudioDevice.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/BluetoothWorker.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/error_bluetooth.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/WorkerController.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/CommandHandler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/Device.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/glucode/BluetoothRunLoop.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/BluetoothDriverImpl.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/GAP/Devices.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/GAP/used_events.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/tests/CMakeLists.txt b/module-bluetooth/tests/CMakeLists.txt index a70a0626676abe537f30d5d8c7a13a94b8e6ec75..61578ab1c6f083443e9aa2f1d20f3d8857b3bc58 100644 --- a/module-bluetooth/tests/CMakeLists.txt +++ b/module-bluetooth/tests/CMakeLists.txt @@ -5,6 +5,7 @@ add_catch2_executable( tests-main.cpp tests-StatefulController.cpp tests-BluetoothDevicesModel.cpp + tests-Devicei.cpp LIBS module-sys module-bluetooth diff --git a/module-bluetooth/tests/test-Devicei.cpp b/module-bluetooth/tests/test-Devicei.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ddfdc80f299e80794e51c5d91d8f8f88bc8b4a99 --- /dev/null +++ b/module-bluetooth/tests/test-Devicei.cpp @@ -0,0 +1,14 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +TEST_CASE("Given StatefulController when process command successfully then turned on") +{ + auto driver = std::make_unique(); + auto processor = std::make_unique(); + StatefulController controller{std::move(driver), std::move(processor), InitializerMock}; + controller.turnOn(); + REQUIRE(controller.isOn()); + + controller.processCommand(bluetooth::Command(Command::Type::PowerOn)); + REQUIRE(controller.isOn()); +} diff --git a/module-bluetooth/tests/tests-BluetoothDevicesModel.cpp b/module-bluetooth/tests/tests-BluetoothDevicesModel.cpp index dfe806f3717a8a2b415656ca1df7dfe1ef643116..4a3a76c7096b0aedc8c0b96f7abb4aabcd5b4aff 100644 --- a/module-bluetooth/tests/tests-BluetoothDevicesModel.cpp +++ b/module-bluetooth/tests/tests-BluetoothDevicesModel.cpp @@ -4,6 +4,7 @@ #include #include "Device.hpp" #include "service-bluetooth/BluetoothDevicesModel.hpp" + TEST_CASE("Devicei comparison") { Devicei device1{"Dev1"}; diff --git a/module-bluetooth/tests/tests-Devicei.cpp b/module-bluetooth/tests/tests-Devicei.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f8f06f0dc29479f309fd51e75427579e78de0a62 --- /dev/null +++ b/module-bluetooth/tests/tests-Devicei.cpp @@ -0,0 +1,62 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include +#include "Device.hpp" +#include + +Devicei genDev() +{ + Devicei from("from"); + bd_addr_t addr{0, 1, 2, 3, 4, 5}; + from.setAddress(&addr); + from.pageScanRepetitionMode = 1; + from.clockOffset = 1; + from.classOfDevice = 1; + from.state = DEVICE_STATE::REMOTE_NAME_REQUEST; + from.deviceState = DeviceState::Paired; + from.isPairingSSP = true; + return from; +} + +TEST_CASE("Devicei - create copy and move") +{ + Devicei from = genDev(); + Devicei to; + + SECTION("create - by copy") + { + SECTION("ctor") + { + to = Devicei(from); + } + SECTION("operator") + { + to.operator=(from); + } + } + + SECTION("move") + { + // please see that that section depends on previous section working fine + Devicei base = from; + SECTION("ctor") + { + to = std::move(base); + } + SECTION("operator") + { + to.operator=(std::move(from)); + } + } + + REQUIRE(from == to); + REQUIRE(!(from != to)); + REQUIRE(bd_addr_cmp(from.address, to.address) == 0); + REQUIRE(from.pageScanRepetitionMode == to.pageScanRepetitionMode); + REQUIRE(from.clockOffset == to.clockOffset); + REQUIRE(from.classOfDevice == to.classOfDevice); + REQUIRE(from.state == to.state); + REQUIRE(from.deviceState == to.deviceState); + REQUIRE(from.isPairingSSP == to.isPairingSSP); +} diff --git a/module-services/service-bluetooth/ServiceBluetooth.cpp b/module-services/service-bluetooth/ServiceBluetooth.cpp index 2ec41a2ce16b819a1c03587f4749166fe25294bd..741f9e44817e6c360088dfd00a42af28f4f0d154 100644 --- a/module-services/service-bluetooth/ServiceBluetooth.cpp +++ b/module-services/service-bluetooth/ServiceBluetooth.cpp @@ -349,7 +349,7 @@ auto ServiceBluetooth::handle(message::bluetooth::DisconnectResult *msg) -> std: auto ServiceBluetooth::handle(message::bluetooth::ResponsePasskey *msg) -> std::shared_ptr { auto passKey = msg->getPasskey(); - bluetooth::GAP::respondPinCode(passKey); + bluetooth::GAP::respondPinCode(passKey, msg->getDevice()); return sys::MessageNone{}; } diff --git a/module-services/service-bluetooth/service-bluetooth/BluetoothDevicesModel.cpp b/module-services/service-bluetooth/service-bluetooth/BluetoothDevicesModel.cpp index 9fd9251d12b13123d1afba6f26f3d026e08ed602..7b4763ea1f16db2faed3f0fcc084fea752095fa4 100644 --- a/module-services/service-bluetooth/service-bluetooth/BluetoothDevicesModel.cpp +++ b/module-services/service-bluetooth/service-bluetooth/BluetoothDevicesModel.cpp @@ -70,11 +70,17 @@ void BluetoothDevicesModel::syncDevicesWithApp() sys::BusChannel::BluetoothNotifications); } } + void BluetoothDevicesModel::setInternalDeviceState(const Devicei &device, const DeviceState &state) { auto dev = getDeviceByAddress(device.address); + if (not dev) { + LOG_ERROR("no such device - ignored"); + return; + } dev.value().get().deviceState = state; } + void BluetoothDevicesModel::mergeInternalDeviceState(const Devicei &device) { try { diff --git a/module-services/service-bluetooth/service-bluetooth/BluetoothSettingsModel.cpp b/module-services/service-bluetooth/service-bluetooth/BluetoothSettingsModel.cpp deleted file mode 100644 index 5a17807ec2ca53ab08ff206fe1b1a41e8fbd1cfe..0000000000000000000000000000000000000000 --- a/module-services/service-bluetooth/service-bluetooth/BluetoothSettingsModel.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. -// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md - -#include "BluetoothSettingsModel.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -BluetoothSettingsModel::BluetoothSettingsModel(app::Application *application) : application{application} -{} - -void BluetoothSettingsModel::requestStatus() -{ - application->bus.sendUnicast(std::make_shared<::message::bluetooth::RequestStatus>(), service::name::bluetooth); -} - -void BluetoothSettingsModel::setStatus(const bool desiredBluetoothState, const bool desiredVisibility) -{ - BluetoothStatus status{.state = desiredBluetoothState ? BluetoothStatus::State::On : BluetoothStatus::State::Off, - .visibility = desiredVisibility}; - message::bluetooth::SetStatus setStatus(status); - application->bus.sendUnicast(std::make_shared<::message::bluetooth::SetStatus>(std::move(setStatus)), - service::name::bluetooth); -} - -void BluetoothSettingsModel::requestDeviceName() -{ - application->bus.sendUnicast(std::make_shared<::message::bluetooth::RequestDeviceName>(), service::name::bluetooth); -} - -void BluetoothSettingsModel::setDeviceName(const UTF8 &deviceName) -{ - application->bus.sendUnicast(std::make_shared(deviceName), - service::name::bluetooth); -} - -void BluetoothSettingsModel::requestBondedDevices() -{ - application->bus.sendUnicast(std::make_shared<::message::bluetooth::RequestBondedDevices>(), - service::name::bluetooth); -} - -void BluetoothSettingsModel::requestScan() -{ - application->bus.sendUnicast(std::make_shared(BluetoothMessage::Request::Scan), - service::name::bluetooth); -} - -void BluetoothSettingsModel::stopScan() -{ - application->bus.sendUnicast(std::make_shared(BluetoothMessage::Request::StopScan), - service::name::bluetooth); -} - -void BluetoothSettingsModel::requestDevicePair(const std::string &addr) -{ - application->bus.sendUnicast(std::make_shared(addr), service::name::bluetooth); -} - -void BluetoothSettingsModel::requestDeviceUnpair(const Devicei &device) -{ - application->bus.sendUnicast(std::make_shared(bd_addr_to_str(device.address)), - service::name::bluetooth); -} - -void BluetoothSettingsModel::responsePasskey(const std::string &passkey) -{ - application->bus.sendUnicast(std::make_shared(passkey), - service::name::bluetooth); -} - -void BluetoothSettingsModel::requestConnection(const std::string &addr) -{ - application->bus.sendUnicast(std::make_shared(addr), service::name::bluetooth); -} - -void BluetoothSettingsModel::requestDisconnection() -{ - application->bus.sendUnicast(std::make_shared(), service::name::bluetooth); -} -void BluetoothSettingsModel::mergeDevicesList(const std::vector &devicesList) -{ - devices.insert(std::end(devices), std::begin(devicesList), std::end(devicesList)); - - // remove duplicates - auto end = std::end(devices); - for (auto it = std::begin(devices); it != end; ++it) { - end = std::remove(it + 1, end, *it); - } - devices.erase(end, std::end(devices)); -} -void BluetoothSettingsModel::setActiveDeviceState(const DeviceState &state) -{ - auto activeDevice = getActiveDevice(); - if (activeDevice.has_value()) { - activeDevice.value().get().deviceState = state; - } -} -auto BluetoothSettingsModel::getActiveDevice() -> std::optional> -{ - try { - return devices.at(activeDeviceIndex); - } - catch (const std::out_of_range &oor) { - LOG_FATAL("NO DEVICE FOUND!"); - return std::nullopt; - } -} -auto BluetoothSettingsModel::getSelectedDevice() -> std::optional> -{ - try { - return devices.at(selectedDeviceIndex); - } - catch (const std::out_of_range &oor) { - LOG_FATAL("NO DEVICE FOUND!"); - return std::nullopt; - } -} -void BluetoothSettingsModel::setActiveDevice(const Devicei &device) -{ - auto itr = std::find(std::begin(devices), std::end(devices), device); - activeDeviceIndex = std::distance(std::begin(devices), itr); -} -void BluetoothSettingsModel::setSelectedDevice(const Devicei &device) -{ - auto itr = std::find(std::begin(devices), std::end(devices), device); - selectedDeviceIndex = std::distance(std::begin(devices), itr); -} -void BluetoothSettingsModel::insertDevice(const Devicei device) -{ - devices.emplace_back(device); -} -auto BluetoothSettingsModel::getDeviceByAddress(const std::string &address) - -> std::optional> -{ - auto deviceIt = std::find_if(std::begin(devices), std::end(devices), [address](const Devicei &device) { - return bd_addr_to_str(device.address) == address; - }); - - if (deviceIt == std::end(devices)) { - return std::nullopt; - } - return std::ref(*deviceIt); -} -void BluetoothSettingsModel::removeDevice(const Devicei &device) -{ - devices.erase(std::remove(std::begin(devices), std::end(devices), device), std::end(devices)); -} -auto BluetoothSettingsModel::getDevices() -> std::vector & -{ - return devices; -} -auto BluetoothSettingsModel::isDeviceConnecting() -> bool -{ - - auto deviceIt = std::find_if(std::begin(devices), std::end(devices), [](const Devicei &device) { - return device.deviceState == DeviceState::Connecting; - }); - - if (deviceIt != std::end(devices)) { - return true; - } - return false; -} diff --git a/module-services/service-bluetooth/service-bluetooth/BluetoothSettingsModel.hpp b/module-services/service-bluetooth/service-bluetooth/BluetoothSettingsModel.hpp deleted file mode 100644 index 3ecbda162839f489073e879083a03665724d294e..0000000000000000000000000000000000000000 --- a/module-services/service-bluetooth/service-bluetooth/BluetoothSettingsModel.hpp +++ /dev/null @@ -1,59 +0,0 @@ -// 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 "Application.hpp" -#include - -extern "C" -{ -#include -} - -class ActiveDevice -{ - public: - explicit ActiveDevice(std::string address) : address(std::move(address)) - {} - ActiveDevice() = default; - DeviceState state = DeviceState::Unknown; - std::string address; -}; - -class BluetoothSettingsModel -{ - public: - explicit BluetoothSettingsModel(app::Application *application); - - void requestStatus(); - void setStatus(bool desiredBluetoothState, bool desiredVisibility); - void requestDeviceName(); - void setDeviceName(const UTF8 &deviceName); - void requestBondedDevices(); - void requestScan(); - void stopScan(); - void requestDevicePair(const std::string &addr); - void requestDeviceUnpair(const Devicei &device); - void responsePasskey(const std::string &passkey); - void requestConnection(const std::string &addr); - void requestDisconnection(); - void replaceDevicesList(const std::vector &devicesList); - void setActiveDeviceState(const DeviceState &state); - auto getActiveDevice() -> std::optional>; - auto getSelectedDevice() -> std::optional>; - auto getDeviceByAddress(const std::string &address) -> std::optional>; - void setActiveDevice(const Devicei &device); - void setSelectedDevice(const Devicei &device); - void insertDevice(Devicei device); - void removeDevice(const Devicei &device); - auto getDevices() -> std::vector &; - auto isDeviceConnecting() -> bool; - - private: - std::vector devices{}; - std::uint16_t activeDeviceIndex = 0; - std::uint16_t selectedDeviceIndex = 0; - app::Application *application = nullptr; - Devicei dummyDevice{""}; -}; diff --git a/module-services/service-bluetooth/service-bluetooth/messages/Passkey.hpp b/module-services/service-bluetooth/service-bluetooth/messages/Passkey.hpp index 0e59569a2795e1d9ac2bd9ff1e54d9f55b4967a1..6f40bb068d3680d88131fad0b7d5028f48bdcce2 100644 --- a/module-services/service-bluetooth/service-bluetooth/messages/Passkey.hpp +++ b/module-services/service-bluetooth/service-bluetooth/messages/Passkey.hpp @@ -8,18 +8,37 @@ namespace message::bluetooth { class RequestPasskey : public BluetoothMessage - {}; + { + Devicei device; + + public: + explicit RequestPasskey(const Devicei &dev) : device(dev) + {} + + [[nodiscard]] auto getDevice() + { + return device; + } + }; class ResponsePasskey : public BluetoothMessage { + Devicei device; + public: - explicit ResponsePasskey(std::string passkey) : passkey(std::move(passkey)) + ResponsePasskey(std::string passkey, const Devicei &dev) : device(dev), passkey(std::move(passkey)) {} + [[nodiscard]] auto getPasskey() const -> std::string { return passkey; } + [[nodiscard]] auto getDevice() + { + return device; + } + private: std::string passkey; }; diff --git a/module-utils/log/Logger.cpp b/module-utils/log/Logger.cpp index e8b0befe526a878da0df85d6a55d800d0477d677..03b95f6cae2271db945a82faf3d699313c448d90 100644 --- a/module-utils/log/Logger.cpp +++ b/module-utils/log/Logger.cpp @@ -20,6 +20,7 @@ namespace Log {"ServiceAntenna", logger_level::LOGERROR}, {"ServiceAudio", logger_level::LOGINFO}, {"ServiceBluetooth", logger_level::LOGINFO}, + {"ServiceBluetooth_w1", logger_level::LOGINFO}, {"ServiceFota", logger_level::LOGINFO}, {"ServiceEink", logger_level::LOGINFO}, {"ServiceDB", logger_level::LOGINFO},