From 1db3f192052d9290387a35e5880d5fd311cbc49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ta=C5=84ski?= Date: Fri, 29 Jan 2021 16:11:19 +0100 Subject: [PATCH] [EGD-5472] Bluetooth worker state machine State machine POC implemented using SML library. --- .../ApplicationSettings.cpp | 24 +- .../windows/BluetoothWindow.cpp | 48 ++-- .../windows/BluetoothWindow.hpp | 31 ++- .../application-settings/windows/BtWindow.cpp | 4 +- .../Bluetooth/BluetoothWorker.cpp | 206 +++++++--------- .../Bluetooth/BluetoothWorker.hpp | 38 +-- module-bluetooth/Bluetooth/CommandHandler.cpp | 102 ++++++++ module-bluetooth/Bluetooth/CommandHandler.hpp | 58 +++++ .../Bluetooth/WorkerController.cpp | 219 ++++++++++++++++++ .../Bluetooth/WorkerController.hpp | 50 ++++ .../Bluetooth/interface/BluetoothDriver.cpp | 17 +- .../Bluetooth/interface/BluetoothDriver.hpp | 27 ++- module-bluetooth/CMakeLists.txt | 6 + module-bluetooth/tests/CMakeLists.txt | 9 + .../tests/tests-StatefulController.cpp | 171 ++++++++++++++ module-bluetooth/tests/tests-main.cpp | 5 + .../service-bluetooth/ServiceBluetooth.cpp | 32 ++- .../service-bluetooth/BluetoothMessage.hpp | 4 +- .../service-bluetooth/SettingsHolder.cpp | 5 +- .../service-bluetooth/SettingsHolder.hpp | 4 +- .../developerMode/DeveloperModeHelper.cpp | 2 +- 21 files changed, 848 insertions(+), 214 deletions(-) create mode 100644 module-bluetooth/Bluetooth/CommandHandler.cpp create mode 100644 module-bluetooth/Bluetooth/CommandHandler.hpp create mode 100644 module-bluetooth/Bluetooth/WorkerController.cpp create mode 100644 module-bluetooth/Bluetooth/WorkerController.hpp create mode 100644 module-bluetooth/tests/tests-StatefulController.cpp create mode 100644 module-bluetooth/tests/tests-main.cpp diff --git a/module-apps/application-settings-new/ApplicationSettings.cpp b/module-apps/application-settings-new/ApplicationSettings.cpp index 77d8173022a4157e452eaa94d46137ce4801484c..48b51ae898bd0a2a9781cec537f0ebf5a78c61bd 100644 --- a/module-apps/application-settings-new/ApplicationSettings.cpp +++ b/module-apps/application-settings-new/ApplicationSettings.cpp @@ -116,7 +116,8 @@ namespace app else if (auto responseStatusMsg = dynamic_cast<::message::bluetooth::ResponseStatus *>(msgl); nullptr != responseStatusMsg) { if (gui::window::name::bluetooth == getCurrentWindow()->getName()) { - auto btStatusData = std::make_unique(responseStatusMsg->getStatus()); + const auto status = responseStatusMsg->getStatus(); + auto btStatusData = std::make_unique(status.state, status.visibility); switchWindow(gui::window::name::bluetooth, std::move(btStatusData)); } } @@ -189,6 +190,27 @@ namespace app ::settings::SystemProperties::lockPassHash, [this](std::string value) { lockPassHash = utils::getNumericValue(value); }, ::settings::SettingsScope::Global); + settings->registerValueChange( + ::settings::Bluetooth::state, + [this](std::string value) { + if (gui::window::name::bluetooth == getCurrentWindow()->getName()) { + const auto isBtOn = utils::getNumericValue(value); + auto btStatusData = std::make_unique( + isBtOn ? BluetoothStatus::State::On : BluetoothStatus::State::Off); + switchWindow(gui::window::name::bluetooth, std::move(btStatusData)); + } + }, + ::settings::SettingsScope::Global); + settings->registerValueChange( + ::settings::Bluetooth::deviceVisibility, + [this](std::string value) { + if (gui::window::name::bluetooth == getCurrentWindow()->getName()) { + const auto isVisible = utils::getNumericValue(value); + auto btStatusData = std::make_unique(isVisible); + switchWindow(gui::window::name::bluetooth, std::move(btStatusData)); + } + }, + ::settings::SettingsScope::Global); return ret; } diff --git a/module-apps/application-settings-new/windows/BluetoothWindow.cpp b/module-apps/application-settings-new/windows/BluetoothWindow.cpp index c3d62cc5046402a8a7d6b3fe69195eff0db261c6..a1d4e4e211330d6438f2041191dcc1571b17900c 100644 --- a/module-apps/application-settings-new/windows/BluetoothWindow.cpp +++ b/module-apps/application-settings-new/windows/BluetoothWindow.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 "BluetoothWindow.hpp" @@ -22,9 +22,13 @@ namespace gui void BluetoothWindow::onBeforeShow(ShowMode mode, SwitchData *data) { if (data != nullptr) { - const auto newData = static_cast(data); - isBluetoothSwitchOn = newData->getState(); - isPhoneVisibilitySwitchOn = newData->getVisibility(); + const auto newData = static_cast(data); + if (const auto btState = newData->getState(); btState.has_value()) { + isBluetoothSwitchOn = btState.value(); + } + if (const auto visibility = newData->getVisibility(); visibility.has_value()) { + isPhoneVisibilitySwitchOn = visibility.value(); + } } rebuildOptionList(); } @@ -36,7 +40,7 @@ namespace gui optionsList.emplace_back(std::make_unique( utils::translateI18("app_settings_bluetooth_main"), [=](gui::Item &item) { - switchHandler(isBluetoothSwitchOn); + changeBluetoothState(isBluetoothSwitchOn); return true; }, [=](gui::Item &item) { @@ -69,7 +73,7 @@ namespace gui optionsList.emplace_back(std::make_unique( utils::translateI18("app_settings_bluetooth_phone_visibility"), [=](gui::Item &item) { - switchHandler(isPhoneVisibilitySwitchOn); + changeVisibility(isPhoneVisibilitySwitchOn); return true; }, [=](gui::Item &item) { @@ -104,22 +108,28 @@ namespace gui return optionsList; } - void BluetoothWindow::switchHandler(bool &switchState) + void BluetoothWindow::changeBluetoothState(bool currentState) { - switchState = !switchState; - BluetoothStatus btStatus; + ::message::bluetooth::SetStatus setStatus(makeDesiredStatus(!currentState, isPhoneVisibilitySwitchOn)); + sys::Bus::SendUnicast(std::make_shared<::message::bluetooth::SetStatus>(std::move(setStatus)), + service::name::bluetooth, + application); + } - if (isBluetoothSwitchOn) { - btStatus.state = BluetoothStatus::State::On; - } - else { - btStatus.state = BluetoothStatus::State::Off; - } - btStatus.visibility = isPhoneVisibilitySwitchOn; - ::message::bluetooth::SetStatus setStatus(btStatus); + void BluetoothWindow::changeVisibility(bool currentVisibility) + { + ::message::bluetooth::SetStatus setStatus(makeDesiredStatus(isBluetoothSwitchOn, !currentVisibility)); + sys::Bus::SendUnicast(std::make_shared<::message::bluetooth::SetStatus>(std::move(setStatus)), + service::name::bluetooth, + application); + } - sys::Bus::SendUnicast( - std::make_shared<::message::bluetooth::SetStatus>(setStatus), service::name::bluetooth, application); + BluetoothStatus BluetoothWindow::makeDesiredStatus(bool desiredBluetoothState, bool desiredVisibility) noexcept + { + BluetoothStatus status; + status.state = desiredBluetoothState ? BluetoothStatus::State::On : BluetoothStatus::State::Off; + status.visibility = desiredVisibility; + return status; } void BluetoothWindow::rebuildOptionList() diff --git a/module-apps/application-settings-new/windows/BluetoothWindow.hpp b/module-apps/application-settings-new/windows/BluetoothWindow.hpp index 0db03d6a3b84b88c996c627ea223541d14301ad4..ea9f1e1ac02851dff032bb42065ad127c17d131f 100644 --- a/module-apps/application-settings-new/windows/BluetoothWindow.hpp +++ b/module-apps/application-settings-new/windows/BluetoothWindow.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 @@ -18,28 +18,43 @@ namespace gui bool isBluetoothSwitchOn = false; bool isPhoneVisibilitySwitchOn = false; auto bluetoothOptionsList() -> std::list; - void switchHandler(bool &switchState); + void changeBluetoothState(bool currentState); + void changeVisibility(bool currentVisibility); void rebuildOptionList(); + + static BluetoothStatus makeDesiredStatus(bool desiredBluetoothState, bool desiredVisibility) noexcept; }; class BluetoothStatusData : public SwitchData { public: - explicit BluetoothStatusData(BluetoothStatus status) : SwitchData(), status(std::move(status)) + explicit BluetoothStatusData(BluetoothStatus::State state) : state{state} + {} + explicit BluetoothStatusData(bool visibility) : visibility{visibility} + {} + BluetoothStatusData(BluetoothStatus::State state, bool visibility) : state{state}, visibility{visibility} {} - [[nodiscard]] auto getState() const noexcept -> bool + + [[nodiscard]] auto getState() const noexcept -> std::optional { - if (status.state == BluetoothStatus::State::On) { + if (!state.has_value()) { + return std::nullopt; + } + if (state == BluetoothStatus::State::On) { return true; } return false; } - [[nodiscard]] auto getVisibility() const noexcept -> bool + [[nodiscard]] auto getVisibility() const noexcept -> std::optional { - return status.visibility; + if (!visibility.has_value()) { + return std::nullopt; + } + return visibility; } private: - BluetoothStatus status; + std::optional state; + std::optional visibility; }; } // namespace gui diff --git a/module-apps/application-settings/windows/BtWindow.cpp b/module-apps/application-settings/windows/BtWindow.cpp index 105b1c6549fafc97428f91df5212baab8f377573..71552f1146a35afcc644aeb8d73e886305bdc19d 100644 --- a/module-apps/application-settings/windows/BtWindow.cpp +++ b/module-apps/application-settings/windows/BtWindow.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 @@ -106,7 +106,7 @@ namespace gui add_box_label(box, " -> Stop", [=](Item &) { LOG_DEBUG("Stop playback"); - message_bt(application, BluetoothMessage::Request::Stop); + message_bt(application, BluetoothMessage::Request::StopPlayback); return true; }); diff --git a/module-bluetooth/Bluetooth/BluetoothWorker.cpp b/module-bluetooth/Bluetooth/BluetoothWorker.cpp index bcae4ba3062b4242c8a36455bfc2770e68dad6a6..46ce5d6441d8e7a6cc93a4e036dab236290814c7 100644 --- a/module-bluetooth/Bluetooth/BluetoothWorker.cpp +++ b/module-bluetooth/Bluetooth/BluetoothWorker.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 @@ -24,10 +24,6 @@ using namespace bsp; -[[nodiscard]] auto to_string(bluetooth::Error::Code code) -> std::string -{ - return utils::enumToString(code); -} namespace queues { constexpr inline auto io = "qBtIO"; @@ -36,112 +32,110 @@ namespace queues constexpr inline auto queueLength = 10; constexpr inline auto triggerQueueLength = 3; - } // namespace queues +namespace +{ + class DeviceRegistration + { + public: + using OnLinkKeyAddedCallback = std::function; + + DeviceRegistration(std::shared_ptr settings, OnLinkKeyAddedCallback &&onLinkKeyAdded) + : settings{std::move(settings)}, onLinkKeyAdded{std::move(onLinkKeyAdded)} + {} + + [[nodiscard]] auto operator()() + { + bluetooth::KeyStorage::settings = settings; + bluetooth::GAP::register_scan(); + + auto settingsName = std::get(settings->getValue(bluetooth::Settings::DeviceName)); + if (settingsName.empty()) { + LOG_WARN("Settings name is empty!"); + constexpr auto name = "PurePhone"; + settings->setValue(bluetooth::Settings::DeviceName, name); + 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; + } + + private: + std::shared_ptr settings; + OnLinkKeyAddedCallback onLinkKeyAdded; + }; + + auto createStatefulController(sys::Service *service, + bluetooth::RunLoop *loop, + std::shared_ptr settings, + std::shared_ptr currentProfile, + DeviceRegistration::OnLinkKeyAddedCallback &&onLinkKeyAddedCallback) + { + auto driver = std::make_unique(loop->getRunLoopInstance()); + auto commandHandler = std::make_unique(service, settings, std::move(currentProfile)); + return std::make_unique( + std::move(driver), + std::move(commandHandler), + DeviceRegistration{std::move(settings), std::move(onLinkKeyAddedCallback)}); + } +} // namespace + BluetoothWorker::BluetoothWorker(sys::Service *service) : Worker(service), service(service), currentProfile(std::make_shared()), settings(static_cast(service)->settingsHolder), - runLoop(std::make_unique()), driver(std::make_unique()) + runLoop(std::make_unique()), + controller{createStatefulController( + service, runLoop.get(), settings, currentProfile, [this](const std::string &addr) { onLinkKeyAdded(addr); })} { init({ {queues::io, sizeof(bluetooth::Message), queues::queueLength}, {queues::cmd, sizeof(bluetooth::Command), queues::queueLength}, {queues::btstack, sizeof(bool), queues::triggerQueueLength}, }); + registerQueues(); +} + +void BluetoothWorker::registerQueues() +{ static_cast(service)->workerQueue = Worker::getQueueHandleByName(queues::cmd); runLoop->setTriggerQueue(Worker::getQueueHandleByName(queues::btstack)); - driver->init(runLoop->getRunLoopInstance()); + BlueKitchen::getInstance()->qHandle = queues[queueIO_handle]->GetQueueHandle(); } -BluetoothWorker::~BluetoothWorker() +void BluetoothWorker::onLinkKeyAdded(const std::string &deviceAddress) { - if (this->bt_worker_task != nullptr) { - vTaskDelete(this->bt_worker_task); + for (auto &device : bluetooth::GAP::devices) { + if (bd_addr_to_str(device.address) == deviceAddress) { + pairedDevices.emplace_back(device); + settings->setValue(bluetooth::Settings::BondedDevices, SettingsSerializer::toString(pairedDevices)); + } } - LOG_INFO("Worker removed"); +} + +BluetoothWorker::~BluetoothWorker() +{ + controller->shutdown(); } auto BluetoothWorker::run() -> bool { LOG_INFO("-> BluetoothWorker run request"); - if (is_running) { + if (isRunning) { return true; } - if (Worker::run()) { - is_running = true; - auto el = queues[queueIO_handle]; - BlueKitchen::getInstance()->qHandle = el->GetQueueHandle(); - bluetooth::KeyStorage::settings = settings; - - driver->registerHardwareErrorCallback(nullptr); - bluetooth::GAP::register_scan(); - - std::string name = "PurePhone"; - auto settingsName = std::get(settings->getValue(bluetooth::Settings::DeviceName)); - if (settingsName.empty()) { - LOG_ERROR("settings name empty!"); - settings->setValue(bluetooth::Settings::DeviceName, name); - settingsName = name; - } - - bluetooth::set_name(settingsName); - bluetooth::GAP::set_visibility( - std::visit(bluetooth::BoolVisitor(), settings->getValue(bluetooth::Settings::Visibility))); - settings->onLinkKeyAdded = [this](std::string addr) { - for (auto &device : bluetooth::GAP::devices) { - if (bd_addr_to_str(device.address) == addr) { - // found paired device - pairedDevices.emplace_back(device); - settings->setValue(bluetooth::Settings::BondedDevices, SettingsSerializer::toString(pairedDevices)); - } - } - }; - - return driver->run() == bluetooth::Error::Success; - } - else { - return false; - } -} - -auto BluetoothWorker::scan() -> bool -{ - std::vector empty; - bluetooth::GAP::setOwnerService(service); - auto ret = bluetooth::GAP::scan(); - if (ret.err != bluetooth::Error::Success) { - LOG_ERROR("Cant start scan!: %s %" PRIu32 "", to_string(ret.err).c_str(), ret.lib_code); + if (const auto status = Worker::run(); !status) { return false; } - else { - LOG_INFO("Scan started!"); - // open new scan window - return true; - } -} - -void BluetoothWorker::stopScan() -{ - bluetooth::GAP::stop_scan(); -} - -void BluetoothWorker::setVisibility(bool visibility) -{ - bluetooth::GAP::set_visibility(visibility); - settings->setValue(bluetooth::Settings::Visibility, visibility); + isRunning = true; + return true; } -auto BluetoothWorker::start_pan() -> bool -{ - bluetooth::PAN::bnep_setup(); - auto err = bluetooth::PAN::bnep_start(); - if (err.err != bluetooth::Error::Success) { - LOG_ERROR("PAN setup error: %s %" PRIu32, to_string(err.err).c_str(), err.lib_code); - } - return false; -} auto BluetoothWorker::handleCommand(QueueHandle_t queue) -> bool { bluetooth::Command command; @@ -149,29 +143,16 @@ auto BluetoothWorker::handleCommand(QueueHandle_t queue) -> bool LOG_ERROR("Queue receive failure!"); return false; } - switch (command) { - case bluetooth::PowerOn: + switch (command) { + case bluetooth::Command::PowerOn: + controller->turnOn(); break; - case bluetooth::StartScan: - scan(); - break; - case bluetooth::StopScan: - stopScan(); - break; - case bluetooth::VisibilityOn: - setVisibility(true); - break; - case bluetooth::VisibilityOff: - setVisibility(false); - break; - case bluetooth::ConnectAudio: - establishAudioConnection(); - break; - case bluetooth::DisconnectAudio: - disconnectAudioConnection(); + case bluetooth::Command::PowerOff: + controller->turnOff(); break; - case bluetooth::PowerOff: + default: + controller->processCommand(command); break; } return true; @@ -186,12 +167,9 @@ auto BluetoothWorker::handleBtStackTrigger(QueueHandle_t queue) -> bool } if (notification) { runLoop->process(); - return true; } - else { - return false; - } + return false; } auto BluetoothWorker::handleMessage(uint32_t queueID) -> bool @@ -269,26 +247,14 @@ auto BluetoothWorker::handleMessage(uint32_t queueID) -> bool return true; } -auto BluetoothWorker::establishAudioConnection() -> bool -{ - currentProfile->setOwnerService(service); - if (currentProfile->init() != bluetooth::Error::Success) { - return false; - } - currentProfile->connect(); - return true; -} -auto BluetoothWorker::disconnectAudioConnection() -> bool -{ - currentProfile->disconnect(); - return true; -} void BluetoothWorker::setDeviceAddress(bd_addr_t addr) { bluetooth::GAP::do_pairing(addr); currentProfile->setDeviceAddress(addr); } + auto BluetoothWorker::deinit() -> bool { + controller->turnOff(); return Worker::deinit(); } diff --git a/module-bluetooth/Bluetooth/BluetoothWorker.hpp b/module-bluetooth/Bluetooth/BluetoothWorker.hpp index 3ff2af048aa65c781fe6162953a454e16d3a81e7..6e59483595c2a63295fd399360523819a31ac02b 100644 --- a/module-bluetooth/Bluetooth/BluetoothWorker.hpp +++ b/module-bluetooth/Bluetooth/BluetoothWorker.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 @@ -14,6 +14,7 @@ #include "service-bluetooth/SettingsHolder.hpp" #include "glucode/BluetoothRunLoop.hpp" #include "interface/BluetoothDriver.hpp" +#include "WorkerController.hpp" struct HCI; /// debug option for HCI (uart) commands debugging @@ -35,18 +36,6 @@ namespace bluetooth EvtErrorRec, /// there was error o queue receive }; - enum Command : std::uint8_t - { - StartScan, - StopScan, - VisibilityOn, - VisibilityOff, - ConnectAudio, - DisconnectAudio, - PowerOn, - PowerOff, - }; - inline const char *MessageCstr(Message what) { switch (what) { @@ -88,9 +77,11 @@ class BluetoothWorker : private sys::Worker queueRunloopTrigger // btstack run_loop queue }; - TaskHandle_t bt_worker_task = nullptr; - int is_running = false; sys::Service *service = nullptr; + bool isRunning = false; + + void registerQueues(); + void onLinkKeyAdded(const std::string &deviceAddress); public: enum Error @@ -104,23 +95,18 @@ class BluetoothWorker : private sys::Worker ~BluetoothWorker() override; auto handleMessage(uint32_t queueID) -> bool override; - auto handleCommand(QueueHandle_t queue) -> bool; auto handleBtStackTrigger(QueueHandle_t queue) -> bool; - bool run(); - auto scan() -> bool; - void setVisibility(bool visibility); - auto start_pan() -> bool; - auto establishAudioConnection() -> bool; - auto disconnectAudioConnection() -> bool; - /// bluetooth stack id in use - unsigned long active_features; - void stopScan(); + + bool run() override; void setDeviceAddress(bd_addr_t addr); auto deinit() -> bool override; + + /// bluetooth stack id in use + unsigned long active_features; std::shared_ptr currentProfile; std::shared_ptr settings; std::vector pairedDevices; std::unique_ptr runLoop; - std::unique_ptr driver; + std::unique_ptr controller; }; diff --git a/module-bluetooth/Bluetooth/CommandHandler.cpp b/module-bluetooth/Bluetooth/CommandHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46df2921ef97551d1ec44b8cc01f4ac399ea04a7 --- /dev/null +++ b/module-bluetooth/Bluetooth/CommandHandler.cpp @@ -0,0 +1,102 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "CommandHandler.hpp" + +#include "BtCommand.hpp" +#include "Device.hpp" + +namespace bluetooth +{ + namespace + { + [[nodiscard]] auto toString(bluetooth::Error::Code code) -> std::string + { + return utils::enumToString(code); + } + } // namespace + + CommandHandler::CommandHandler(sys::Service *service, + std::shared_ptr settings, + std::shared_ptr currentProfile) + : service{service}, settings{std::move(settings)}, currentProfile{std::move(currentProfile)} + {} + + Error::Code CommandHandler::handle(Command command) + { + switch (command) { + case bluetooth::PowerOn: + return Error::Success; + case bluetooth::StartScan: + return scan(); + case bluetooth::StopScan: + return stopScan(); + case bluetooth::StartPan: + return startPan(); + case bluetooth::VisibilityOn: + return setVisibility(true); + case bluetooth::VisibilityOff: + return setVisibility(false); + case bluetooth::ConnectAudio: + return establishAudioConnection(); + case bluetooth::DisconnectAudio: + return disconnectAudioConnection(); + case bluetooth::PowerOff: + return Error::Success; + } + return Error::LibraryError; + } + + Error::Code CommandHandler::scan() + { + bluetooth::GAP::setOwnerService(service); + if (const auto ret = bluetooth::GAP::scan(); ret.err != bluetooth::Error::Success) { + LOG_ERROR("Cant start scan!: %s %" PRIu32 "", toString(ret.err).c_str(), ret.lib_code); + return ret.err; + } + + LOG_INFO("Scan started!"); + // open new scan window + return Error::Success; + } + + Error::Code CommandHandler::stopScan() + { + bluetooth::GAP::stop_scan(); + return Error::Success; + } + + Error::Code CommandHandler::startPan() + { + bluetooth::PAN::bnep_setup(); + if (const auto err = bluetooth::PAN::bnep_start(); err.err != bluetooth::Error::Success) { + LOG_ERROR("PAN setup error: %s %" PRIu32, toString(err.err).c_str(), err.lib_code); + return err.err; + } + return bluetooth::Error::Success; + } + + Error::Code CommandHandler::setVisibility(bool visibility) + { + const auto status = bluetooth::GAP::set_visibility(visibility); + settings->setValue(bluetooth::Settings::Visibility, static_cast(visibility)); + return status.err; + } + + Error::Code CommandHandler::establishAudioConnection() + { + currentProfile->setOwnerService(service); + if (const auto status = currentProfile->init(); status != bluetooth::Error::Success) { + return status; + } + + currentProfile->connect(); + return Error::Success; + } + + Error::Code CommandHandler::disconnectAudioConnection() + { + currentProfile->disconnect(); + return Error::Success; + } +} // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/CommandHandler.hpp b/module-bluetooth/Bluetooth/CommandHandler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3b962512b2798e7e8f15bb2058a75e6c684b4b4e --- /dev/null +++ b/module-bluetooth/Bluetooth/CommandHandler.hpp @@ -0,0 +1,58 @@ +// 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 "Error.hpp" +#include "interface/profiles/Profile.hpp" + +#include +#include + +#include + +namespace bluetooth +{ + enum Command : std::uint8_t + { + StartScan, + StopScan, + StartPan, + VisibilityOn, + VisibilityOff, + ConnectAudio, + DisconnectAudio, + PowerOn, + PowerOff, + }; + + class AbstractCommandHandler + { + public: + virtual ~AbstractCommandHandler() noexcept = default; + + virtual auto handle(Command command) -> Error::Code = 0; + }; + + class CommandHandler : public AbstractCommandHandler + { + public: + explicit CommandHandler(sys::Service *service, + std::shared_ptr settings, + std::shared_ptr currentProfile); + + auto handle(Command command) -> Error::Code override; + + private: + Error::Code scan(); + Error::Code stopScan(); + Error::Code startPan(); + Error::Code setVisibility(bool visibility); + Error::Code establishAudioConnection(); + Error::Code disconnectAudioConnection(); + + sys::Service *service; + std::shared_ptr settings; + std::shared_ptr currentProfile; + }; +} // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/WorkerController.cpp b/module-bluetooth/Bluetooth/WorkerController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7438890c1f3b070a97dd0ae34ef7c13b138840a9 --- /dev/null +++ b/module-bluetooth/Bluetooth/WorkerController.cpp @@ -0,0 +1,219 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "WorkerController.hpp" + +#include "Device.hpp" +#include "interface/profiles/Profile.hpp" + +#include +#include +#include + +#include +#include + +namespace bluetooth +{ + namespace sml = boost::sml; + + namespace + { + struct Logger + { + template void log_process_event(const TEvent &) + { + LOG_INFO("[%s][process_event] %s", sml::aux::get_type_name(), sml::aux::get_type_name()); + } + + template void log_guard(const TGuard &, const TEvent &, bool result) + { + LOG_INFO("[%s][guard] %s %s %s", + sml::aux::get_type_name(), + sml::aux::get_type_name(), + sml::aux::get_type_name(), + (result ? "[OK]" : "[Reject]")); + } + + template void log_action(const TAction &, const TEvent &) + { + LOG_INFO("[%s][action] %s %s", + sml::aux::get_type_name(), + sml::aux::get_type_name(), + sml::aux::get_type_name()); + } + + template + void log_state_change(const TSrcState &src, const TDstState &dst) + { + LOG_INFO("[%s][transition] %s -> %s", sml::aux::get_type_name(), src.c_str(), dst.c_str()); + } + }; + + struct TurnOn + {}; + struct TurnOff + {}; + struct ShutDown + {}; + struct ProcessCommand + { + Command command; + }; + + class InitializationError : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + class ProcessingError : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + struct InitializationState + { + bool isInitDone = false; + }; + + struct Setup + { + public: + auto operator()() const + { + auto isInit = [](InitializationState &data) { return data.isInitDone; }; + auto init = [](std::shared_ptr &driver) { + if (const auto status = driver->init(); status != Error::Success) { + throw InitializationError{"Unable to initialize a bluetooth driver."}; + } + }; + auto setup = [](DeviceRegistrationFunction ®isterDevice, InitializationState &data) { + if (const auto status = registerDevice(); status != Error::Success) { + throw InitializationError{"Unable to initialize bluetooth"}; + } + data.isInitDone = true; + }; + auto startDriver = [](std::shared_ptr &driver) { + if (const auto status = driver->run(); status != Error::Success) { + throw InitializationError{"Unable to run the bluetooth driver"}; + } + }; + + using namespace sml; + // clang-format off + return make_transition_table(*"Setup"_s / startDriver = "StartingDriver"_s, + "Setup"_s + on_entry<_> [ !isInit ] / ( init, setup ), + "StartingDriver"_s = X); + // clang-format on + } + }; + + struct On + { + auto operator()() const + { + auto isInit = [](InitializationState &data) { return data.isInitDone; }; + auto handleCommand = [](std::shared_ptr &processor, + const ProcessCommand &processCommand) { + if (const auto status = processor->handle(processCommand.command); status != Error::Success) { + throw ProcessingError{"Failed to process command"}; + } + }; + + using namespace sml; + // clang-format off + return make_transition_table(*"Idle"_s + event [ isInit ] / handleCommand = "Processing"_s, + "Processing"_s = "Idle"_s); + // clang-format on + } + }; + + class StateMachine + { + public: + auto operator()() const + { + auto turnOff = [](std::shared_ptr &driver) { driver->stop(); }; + auto printInitError = [](const InitializationError &error) { LOG_ERROR("%s", error.what()); }; + auto printProcessingError = [](const ProcessingError &error) { LOG_ERROR("%s", error.what()); }; + + using namespace sml; + // clang-format off + return make_transition_table(*"Off"_s + event = state, + state = state, + state + exception / printInitError = "Off"_s, + state + event / turnOff = "Off"_s, + state + exception / ( printProcessingError, turnOff ) = "Restart"_s, + "Restart"_s = state, + "Off"_s + event = X); + // clang-format on + } + }; + } // namespace + + class StatefulController::Impl + { + public: + Impl(Logger logger, + std::shared_ptr &&driver, + std::shared_ptr &&handler, + DeviceRegistrationFunction &®isterDevice); + + using SM = + sml::sm, sml::defer_queue, sml::process_queue>; + SM sm; + }; + + StatefulController::Impl::Impl(Logger logger, + std::shared_ptr &&driver, + std::shared_ptr &&handler, + DeviceRegistrationFunction &®isterDevice) + : sm{std::move(logger), std::move(driver), std::move(handler), std::move(registerDevice), InitializationState{}} + {} + + StatefulController::StatefulController(std::shared_ptr &&driver, + std::shared_ptr &&handler, + DeviceRegistrationFunction &®isterDevice) + : pimpl(std::make_unique(Logger{}, std::move(driver), std::move(handler), std::move(registerDevice))) + {} + + StatefulController::~StatefulController() noexcept = default; + + void StatefulController::turnOn() + { + pimpl->sm.process_event(TurnOn{}); + } + + void StatefulController::turnOff() + { + pimpl->sm.process_event(TurnOff{}); + } + + void StatefulController::shutdown() + { + if (isOn()) { + turnOff(); + } + pimpl->sm.process_event(ShutDown{}); + } + + auto StatefulController::isOn() const -> bool + { + using namespace sml; + return !pimpl->sm.is("Off"_s) && !isTerminated(); + } + + auto StatefulController::isTerminated() const -> bool + { + using namespace sml; + return pimpl->sm.is(X); + } + + void StatefulController::processCommand(Command command) + { + LOG_INFO("Process command: %s", magic_enum::enum_name(command).data()); + pimpl->sm.process_event(ProcessCommand{command}); + } +} // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/WorkerController.hpp b/module-bluetooth/Bluetooth/WorkerController.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a23d7bd0a1662d68a002cd651146814218882d7f --- /dev/null +++ b/module-bluetooth/Bluetooth/WorkerController.hpp @@ -0,0 +1,50 @@ +// 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 "CommandHandler.hpp" +#include "interface/BluetoothDriver.hpp" + +#include +#include + +namespace bluetooth +{ + using DeviceRegistrationFunction = std::function; + + class AbstractController + { + public: + virtual ~AbstractController() noexcept = default; + + virtual void turnOn() = 0; + virtual void turnOff() = 0; + virtual void shutdown() = 0; + virtual auto isOn() const -> bool = 0; + virtual auto isTerminated() const -> bool = 0; + + virtual void processCommand(Command command) = 0; + }; + + class StatefulController : public AbstractController + { + public: + StatefulController(std::shared_ptr &&driver, + std::shared_ptr &&handler, + DeviceRegistrationFunction &®isterDevice); + ~StatefulController() noexcept override; + + void turnOn() override; + void turnOff() override; + void shutdown() override; + [[nodiscard]] auto isOn() const -> bool override; + [[nodiscard]] auto isTerminated() const -> bool override; + + void processCommand(Command command) override; + + private: + class Impl; + std::unique_ptr pimpl; + }; +} // namespace bluetooth diff --git a/module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp b/module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp index 7d9c0f800372f823e7f8ce796c148a6040f7de87..ded8f4ec99ced7a7b83805cb7919d0e832cf663d 100644 --- a/module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp +++ b/module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp @@ -35,15 +35,15 @@ namespace bluetooth hci_transport_config_uart_t Driver::config; #ifdef TARGET_RT1051 - [[maybe_unused]] auto Driver::runLoopInitTarget(const btstack_run_loop *runLoop) -> const btstack_uart_block_t * + [[maybe_unused]] auto Driver::runLoopInitTarget(const btstack_run_loop *loop) -> const btstack_uart_block_t * { - btstack_run_loop_init(runLoop); + btstack_run_loop_init(loop); const btstack_uart_block_t *uartDriver = btstack_uart_block_rt1051_instance(); return uartDriver; } #else - [[maybe_unused]] auto Driver::runLoopInitLinux(const btstack_run_loop *runLoop) -> const btstack_uart_block_t * + [[maybe_unused]] auto Driver::runLoopInitLinux(const btstack_run_loop *) -> const btstack_uart_block_t * { btstack_run_loop_init(btstack_run_loop_posix_get_instance()); config.device_name = "/dev/telit"; @@ -53,7 +53,10 @@ namespace bluetooth } #endif - auto Driver::init(const btstack_run_loop *runLoop) -> Error::Code + Driver::Driver(const btstack_run_loop *runLoop) : runLoop{runLoop} + {} + + auto Driver::init() -> Error::Code { btstack_memory_init(); config = { @@ -164,10 +167,10 @@ namespace bluetooth return Error::Success; } - void Driver::registerHardwareErrorCallback(std::function new_callback) + void Driver::registerErrorCallback(const ErrorCallback &newCallback) { - static std::function callback = nullptr; - callback = new_callback; + static ErrorCallback callback; + callback = newCallback; hci_set_hardware_error_callback([](uint8_t val) -> void { LOG_ERROR("Bluetooth HW ERROR! %d", val); if (callback) { diff --git a/module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp b/module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp index 1d5d4874243673f308a856f4c1fe78462568e89b..ca15f71330f7c8e7dad5d6673a6d884a94bedfb7 100644 --- a/module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp +++ b/module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp @@ -9,21 +9,38 @@ namespace bluetooth { + class AbstractDriver + { + public: + using ErrorCallback = std::function; + virtual ~AbstractDriver() noexcept = default; - class Driver + [[nodiscard]] virtual auto init() -> Error::Code = 0; + [[nodiscard]] virtual auto run() -> Error::Code = 0; + [[nodiscard]] virtual auto stop() -> Error::Code = 0; + virtual void registerErrorCallback(const ErrorCallback &newCallback) = 0; + }; + + class Driver : public AbstractDriver { private: static hci_transport_config_uart_t config; + const btstack_run_loop *runLoop; btstack_packet_callback_registration_t hci_event_callback_registration; 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 [[maybe_unused]] auto runLoopInitTarget(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *; +#else [[maybe_unused]] auto runLoopInitLinux(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *; +#endif public: - auto init(const btstack_run_loop *runLoop) -> Error::Code; - auto run() -> Error::Code; - auto stop() -> Error::Code; - void registerHardwareErrorCallback(std::function new_callback); + explicit Driver(const btstack_run_loop *runLoop); + + [[nodiscard]] auto init() -> Error::Code override; + [[nodiscard]] auto run() -> Error::Code override; + [[nodiscard]] auto stop() -> Error::Code override; + void registerErrorCallback(const ErrorCallback &newCallback) override; }; } // namespace bluetooth diff --git a/module-bluetooth/CMakeLists.txt b/module-bluetooth/CMakeLists.txt index 1826b51bae79c3ff2abe3d652af6114f38e46ba5..fb62dd7ea926ed339502e3db17582540219674f0 100644 --- a/module-bluetooth/CMakeLists.txt +++ b/module-bluetooth/CMakeLists.txt @@ -6,6 +6,8 @@ set(CMAKE_CXX_STANDARD 17) set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/BluetoothWorker.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/WorkerController.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/CommandHandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/glucode/BluetoothRunLoop.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/BluetoothDriver.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/BtKeysStorage.cpp @@ -68,3 +70,7 @@ target_link_libraries(${PROJECT_NAME} service-audio ${BOARD_DIR_LIBRARIES} ) + +if (${ENABLE_TESTS}) + add_subdirectory(tests) +endif() diff --git a/module-bluetooth/tests/CMakeLists.txt b/module-bluetooth/tests/CMakeLists.txt index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..80036cae8a1bedb7802874024efc1a05f74ac000 100644 --- a/module-bluetooth/tests/CMakeLists.txt +++ b/module-bluetooth/tests/CMakeLists.txt @@ -0,0 +1,9 @@ +add_catch2_executable( + NAME + StatefulController-tests + SRCS + tests-main.cpp + tests-StatefulController.cpp + LIBS + module-bluetooth +) diff --git a/module-bluetooth/tests/tests-StatefulController.cpp b/module-bluetooth/tests/tests-StatefulController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eff9172a812f5e874741b1c72014e01e3d78cf5d --- /dev/null +++ b/module-bluetooth/tests/tests-StatefulController.cpp @@ -0,0 +1,171 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include + +#include "WorkerController.hpp" +#include "interface/BluetoothDriver.hpp" + +#include + +using namespace bluetooth; + +class DriverMock : public AbstractDriver +{ + public: + Error::Code init() override + { + return initReturnCode; + } + Error::Code run() override + { + return runReturnCode; + } + Error::Code stop() override + { + return stopReturnCode; + } + void registerErrorCallback(const ErrorCallback &) override + {} + + Error::Code initReturnCode = Error::Success; + Error::Code runReturnCode = Error::Success; + Error::Code stopReturnCode = Error::Success; +}; + +auto InitializerMock = []() { return Error::Success; }; + +class HandlerMock : public AbstractCommandHandler +{ + public: + Error::Code handle(Command command) override + { + return returnCode; + } + + Error::Code returnCode = Error::Success; +}; + +TEST_CASE("Given StatefulController when turn on 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()); +} + +TEST_CASE("Given StatefulController when error during device registration then turned off") +{ + auto driver = std::make_unique(); + auto processor = std::make_unique(); + StatefulController controller{std::move(driver), std::move(processor), []() { return Error::SystemError; }}; + controller.turnOn(); + REQUIRE(!controller.isOn()); +} + +TEST_CASE("Given StatefulController when error during driver init then turned off") +{ + auto driver = std::make_unique(); + driver->initReturnCode = Error::SystemError; + + auto processor = std::make_unique(); + StatefulController controller{std::move(driver), std::move(processor), InitializerMock}; + controller.turnOn(); + REQUIRE(!controller.isOn()); +} + +TEST_CASE("Given StatefulController when error during driver run then turned off") +{ + auto driver = std::make_unique(); + driver->runReturnCode = Error::SystemError; + + auto processor = std::make_unique(); + StatefulController controller{std::move(driver), std::move(processor), InitializerMock}; + controller.turnOn(); + REQUIRE(!controller.isOn()); +} + +TEST_CASE("Given StatefulController when restart then don't init twice") +{ + auto driver = std::make_shared(); + auto processor = std::make_unique(); + StatefulController controller{driver, std::move(processor), InitializerMock}; + controller.turnOn(); + REQUIRE(controller.isOn()); + + controller.turnOff(); + REQUIRE(!controller.isOn()); + + driver->initReturnCode = Error::SystemError; + controller.turnOn(); + REQUIRE(controller.isOn()); +} + +TEST_CASE("Given StatefulController when turn off in off state then turned off") +{ + auto driver = std::make_unique(); + auto processor = std::make_unique(); + StatefulController controller{std::move(driver), std::move(processor), InitializerMock}; + controller.turnOff(); + REQUIRE(!controller.isOn()); +} + +TEST_CASE("Given StatefulController when turn off in on state then turned off") +{ + 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.turnOff(); + REQUIRE(!controller.isOn()); +} + +TEST_CASE("Given StatefulController when shutdown in off state then terminated") +{ + auto driver = std::make_unique(); + auto processor = std::make_unique(); + StatefulController controller{std::move(driver), std::move(processor), InitializerMock}; + controller.shutdown(); + REQUIRE(controller.isTerminated()); +} + +TEST_CASE("Given StatefulController when shutdown in on state then terminated") +{ + 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.shutdown(); + REQUIRE(controller.isTerminated()); +} + +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(Command::PowerOn); + REQUIRE(controller.isOn()); +} + +TEST_CASE("Given StatefulController when processing command failed then restarted and turned on") +{ + auto driver = std::make_unique(); + auto processor = std::make_unique(); + processor->returnCode = Error::SystemError; + StatefulController controller{std::move(driver), std::move(processor), InitializerMock}; + controller.turnOn(); + REQUIRE(controller.isOn()); + + controller.processCommand(Command::PowerOn); + controller.processCommand(Command::PowerOn); + REQUIRE(controller.isOn()); +} diff --git a/module-bluetooth/tests/tests-main.cpp b/module-bluetooth/tests/tests-main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a6ad34dd8ce49475f75635a46116fd419dafda9 --- /dev/null +++ b/module-bluetooth/tests/tests-main.cpp @@ -0,0 +1,5 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include diff --git a/module-services/service-bluetooth/ServiceBluetooth.cpp b/module-services/service-bluetooth/ServiceBluetooth.cpp index f246d52f3d66fe1ec59df964a5b35c18d5ad1b50..6daf7abd1eaa55140855ab17770983fd1dbcedab 100644 --- a/module-services/service-bluetooth/ServiceBluetooth.cpp +++ b/module-services/service-bluetooth/ServiceBluetooth.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 "Constants.hpp" @@ -42,6 +42,7 @@ sys::ReturnCodes ServiceBluetooth::InitHandler() { LOG_ERROR("Bluetooth experimental!"); worker = std::make_unique(this); + worker->run(); connect(message::bluetooth::RequestBondedDevices(), [&](sys::Message *msg) { auto bondedDevicesStr = @@ -65,21 +66,20 @@ sys::ReturnCodes ServiceBluetooth::InitHandler() connect(typeid(message::bluetooth::SetStatus), [&](sys::Message *msg) { auto setStatusMsg = static_cast(msg); - auto btStatus = setStatusMsg->getStatus(); - worker->setVisibility(btStatus.visibility); + auto newBtStatus = setStatusMsg->getStatus(); - switch (btStatus.state) { + switch (newBtStatus.state) { case BluetoothStatus::State::On: - worker->run(); + sendWorkerCommand(bluetooth::Command::PowerOn); break; case BluetoothStatus::State::Off: - // TODO + sendWorkerCommand(bluetooth::Command::PowerOff); break; default: break; } - - return std::make_shared(btStatus); + sendWorkerCommand(newBtStatus.visibility ? bluetooth::VisibilityOn : bluetooth::VisibilityOff); + return sys::MessageNone{}; }); connect(sdesktop::developerMode::DeveloperModeRequest(), [&](sys::Message *msg) { @@ -99,7 +99,6 @@ sys::ReturnCodes ServiceBluetooth::InitHandler() auto initialState = std::visit(bluetooth::IntVisitor(), settingsHolder->getValue(bluetooth::Settings::State)); if (static_cast(initialState) == BluetoothStatus::State::On) { settingsHolder->setValue(bluetooth::Settings::State, static_cast(BluetoothStatus::State::Off)); - worker->run(); } }; @@ -122,15 +121,10 @@ sys::MessagePointer ServiceBluetooth::DataReceivedHandler(sys::DataMessage *msg, switch (lmsg->req) { case BluetoothMessage::Start: worker->run(); - break; case BluetoothMessage::Scan: - if (worker->scan()) { - return std::make_shared(sys::ReturnCodes::Success); - } - else { - return std::make_shared(sys::ReturnCodes::Failure); - } + sendWorkerCommand(bluetooth::StartScan); + break; case BluetoothMessage::StopScan: sendWorkerCommand(bluetooth::StopScan); break; @@ -145,19 +139,19 @@ sys::MessagePointer ServiceBluetooth::DataReceivedHandler(sys::DataMessage *msg, // else { /// TODO request PPP LOG_INFO("Start PAN"); - worker->start_pan(); + sendWorkerCommand(bluetooth::StartPan); // } } break; case BluetoothMessage::Visible: { static bool visibility = true; - worker->setVisibility(visibility); + sendWorkerCommand(visibility ? bluetooth::VisibilityOn : bluetooth::VisibilityOff); visibility = !visibility; } break; case BluetoothMessage::Play: sendWorkerCommand(bluetooth::ConnectAudio); break; - case BluetoothMessage::Stop: + case BluetoothMessage::StopPlayback: sendWorkerCommand(bluetooth::DisconnectAudio); break; diff --git a/module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp b/module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp index 9ffbe1927552c116c18082df602752aa0ebc6d79..d54c73c3287fa78d23f6c393f876d296224daec4 100644 --- a/module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp +++ b/module-services/service-bluetooth/service-bluetooth/BluetoothMessage.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 @@ -43,7 +43,7 @@ class BluetoothMessage : public sys::DataMessage PAN, Visible, Play, - Stop + StopPlayback }; enum Request req = Request::None; BluetoothMessage(enum Request req = None) : sys::DataMessage(MessageType::BluetoothRequest), req(req){}; diff --git a/module-services/service-bluetooth/service-bluetooth/SettingsHolder.cpp b/module-services/service-bluetooth/service-bluetooth/SettingsHolder.cpp index cd13b9682978191b888373f7721b2055aa08460e..e7edd50180abb959516b6f66959beb215154c0f6 100644 --- a/module-services/service-bluetooth/service-bluetooth/SettingsHolder.cpp +++ b/module-services/service-bluetooth/service-bluetooth/SettingsHolder.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 "SettingsHolder.hpp" @@ -20,7 +20,8 @@ namespace bluetooth { settingsMap[newSetting] = value; - settingsProvider->setValue(settingString[newSetting], std::visit(StringVisitor(), value)); + settingsProvider->setValue( + settingString[newSetting], std::visit(StringVisitor(), value), ::settings::SettingsScope::Global); LOG_INFO("setting %s set: %s", settingString[newSetting].c_str(), std::visit(StringVisitor(), value).c_str()); } SettingsHolder::SettingsHolder(std::unique_ptr settingsPtr) diff --git a/module-services/service-bluetooth/service-bluetooth/SettingsHolder.hpp b/module-services/service-bluetooth/service-bluetooth/SettingsHolder.hpp index 0c8832f897565d28ea79fa331b5274545e83c121..15f5465502e1482816b668d8ed00848cc704e7d3 100644 --- a/module-services/service-bluetooth/service-bluetooth/SettingsHolder.hpp +++ b/module-services/service-bluetooth/service-bluetooth/SettingsHolder.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 #include @@ -82,7 +82,7 @@ namespace bluetooth auto getValue(const Settings setting) -> SettingEntry; void setValue(const Settings &newSetting, const SettingEntry &value); std::function onStateChange; - std::function onLinkKeyAdded; + std::function onLinkKeyAdded; private: static std::map settingString; diff --git a/module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp b/module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp index e0e41c4c52c054df2cc653830a128d5e57706925..5e2f998e8102be385607e11c2c405c4f0f8a98cc 100644 --- a/module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp +++ b/module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp @@ -62,7 +62,7 @@ auto DeveloperModeHelper::processPutRequest(Context &context) -> sys::ReturnCode LOG_INFO("turning on BT from harness!"); } else { - request = BluetoothMessage::Request::Stop; + request = BluetoothMessage::Request::StopPlayback; LOG_INFO("turning off BT from harness!"); } std::shared_ptr msg = std::make_shared(request);