M module-apps/application-settings/models/bluetooth/BluetoothSettingsModel.cpp => module-apps/application-settings/models/bluetooth/BluetoothSettingsModel.cpp +1 -0
@@ 48,6 48,7 @@ void BluetoothSettingsModel::requestBondedDevices()
void BluetoothSettingsModel::requestScan()
{
+ /// TODO send event Scan{}
service->bus.sendUnicast(std::make_shared<BluetoothMessage>(BluetoothMessage::Request::Scan),
service::name::bluetooth);
}
A module-bluetooth/Bluetooth/AbstractController.hpp => module-bluetooth/Bluetooth/AbstractController.hpp +71 -0
@@ 0,0 1,71 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+namespace bt::evt
+{
+ struct Base;
+ struct StartScan;
+ struct StopScan;
+ struct GetDevicesAvailable;
+ struct VisibilityOn;
+ struct VisibilityOff;
+ struct ConnectAudio;
+ struct DisconnectAudio;
+ struct PowerOn;
+ struct PowerOff;
+ struct ShutDown;
+ struct Pair;
+ struct Unpair;
+ struct StartRinging;
+ struct StopRinging;
+ struct StartRouting;
+ struct StartStream;
+ struct StopStream;
+ struct CallAnswered;
+ struct CallTerminated;
+ struct CallStarted;
+ struct IncomingCallNumber;
+ struct SignalStrengthData;
+ struct OperatorNameData;
+ struct BatteryLevelData;
+ struct NetworkStatusData;
+} // namespace bt::evt
+
+namespace bluetooth
+{
+
+ class AbstractController
+ {
+ public:
+ virtual ~AbstractController() noexcept = default;
+
+ virtual void handle(const bt::evt::Base &evt) = 0;
+ virtual void handle(const bt::evt::StartScan &evt) = 0;
+ virtual void handle(const bt::evt::StopScan &evt) = 0;
+ virtual void handle(const bt::evt::GetDevicesAvailable &evt) = 0;
+ virtual void handle(const bt::evt::VisibilityOn &evt) = 0;
+ virtual void handle(const bt::evt::VisibilityOff &evt) = 0;
+ virtual void handle(const bt::evt::ConnectAudio &evt) = 0;
+ virtual void handle(const bt::evt::DisconnectAudio &evt) = 0;
+ virtual void handle(const bt::evt::PowerOn &evt) = 0;
+ virtual void handle(const bt::evt::PowerOff &evt) = 0;
+ virtual void handle(const bt::evt::ShutDown &evt) = 0;
+ virtual void handle(const bt::evt::Pair &evt) = 0;
+ virtual void handle(const bt::evt::Unpair &evt) = 0;
+ virtual void handle(const bt::evt::StartRinging &evt) = 0;
+ virtual void handle(const bt::evt::StopRinging &evt) = 0;
+ virtual void handle(const bt::evt::StartRouting &evt) = 0;
+ virtual void handle(const bt::evt::StartStream &evt) = 0;
+ virtual void handle(const bt::evt::StopStream &evt) = 0;
+ virtual void handle(const bt::evt::CallAnswered &evt) = 0;
+ virtual void handle(const bt::evt::CallTerminated &evt) = 0;
+ virtual void handle(const bt::evt::CallStarted &evt) = 0;
+ virtual void handle(const bt::evt::IncomingCallNumber &evt) = 0;
+ virtual void handle(const bt::evt::SignalStrengthData &evt) = 0;
+ virtual void handle(const bt::evt::OperatorNameData &evt) = 0;
+ virtual void handle(const bt::evt::BatteryLevelData &evt) = 0;
+ virtual void handle(const bt::evt::NetworkStatusData &evt) = 0;
+ };
+}; // namespace bluetooth
A module-bluetooth/Bluetooth/BluetoothStateMachine.hpp => module-bluetooth/Bluetooth/BluetoothStateMachine.hpp +412 -0
@@ 0,0 1,412 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#define BOOST_SML_CFG_DISABLE_MIN_SIZE // GCC10 fix
+#include <boost/sml.hpp>
+#include <sml-utils/Logger.hpp>
+#include <stdexcept>
+#include "command/event/Events.hpp"
+#include "service-bluetooth/SettingsHolder.hpp"
+#include "interface/profiles/ProfileManager.hpp"
+#include "WorkerController.hpp"
+#include "Device.hpp"
+#include <log/log.hpp>
+
+namespace bluetooth
+{
+ namespace sml = boost::sml;
+
+ 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 InitDriver
+ {
+ void operator()(std::shared_ptr<AbstractDriver> driver)
+ {
+ if (driver == nullptr) {
+ throw std::runtime_error("shouldn't happen");
+ }
+ // printf("driver: 0x%X %d\n", driver.get(), int(driver.use_count()));
+ if (const auto status = driver->init(); status != Error::Success) {
+ throw InitializationError{"Unable to initialize a bluetooth driver."};
+ }
+ }
+ } constexpr InitDriver;
+
+ struct InitDevicesList
+ {
+ void operator()(const std::shared_ptr<bluetooth::SettingsHolder> settings,
+ const std::shared_ptr<std::vector<Devicei>> pairedDevices)
+ {
+ auto bondedDevicesStr =
+ std::visit(bluetooth::StringVisitor(), settings->getValue(bluetooth::Settings::BondedDevices));
+ pairedDevices->clear();
+ auto devices = SettingsSerializer::fromString(bondedDevicesStr);
+ pairedDevices->assign(devices.begin(), devices.end());
+ LOG_INFO("Loaded: %d devices", int(pairedDevices->size()));
+ }
+ } constexpr InitDevicesList;
+
+ struct IsInit
+ {
+ bool operator()(InitializationState &data)
+ {
+ return data.isInitDone;
+ };
+ } constexpr isInit;
+
+ struct PostInit
+ {
+ // TODO shoundn't this be in driver?
+ void operator()(DeviceRegistrationFunction registerDevice, InitializationState &data)
+ {
+ if (const auto status = registerDevice(); status != Error::Success) {
+ throw InitializationError{"Unable to initialize bluetooth"};
+ }
+ data.isInitDone = true;
+ }
+ } constexpr PostInit;
+
+ struct StartDriver
+ {
+ void operator()(std::shared_ptr<AbstractDriver> driver)
+ {
+ if (const auto status = driver->run(); status != Error::Success) {
+ throw InitializationError{"Unable to run the bluetooth driver"};
+ }
+ }
+ } static StartDriver;
+
+ struct Setup
+ {
+ public:
+ auto operator()() const
+ {
+ using namespace sml;
+ return make_transition_table(*"Setup"_s + on_entry<_>[!isInit] / (InitDevicesList, InitDriver, PostInit),
+ "Setup"_s / StartDriver = X);
+ }
+ };
+
+ struct HandleOn
+ {
+ void operator()(std::shared_ptr<AbstractCommandHandler> handler)
+ {
+ handler->scan();
+ }
+ } constexpr HandleOn;
+
+ struct HandleOff
+ {
+ void operator()(std::shared_ptr<AbstractCommandHandler> handler)
+ {
+ handler->stopScan();
+ }
+ } constexpr HandleOff;
+
+ struct HandlePair
+ {
+ void operator()(std::shared_ptr<AbstractCommandHandler> handler, const bt::evt::Pair &event)
+ {
+ handler->pair(event.device);
+ }
+ } constexpr HandlePair;
+
+ struct Connected
+ {
+ bool operator()(std::shared_ptr<bluetooth::SettingsHolder> settings, bt::evt::Unpair evt)
+ {
+ auto deviceAddr =
+ std::visit(bluetooth::StringVisitor(), settings->getValue(bluetooth::Settings::ConnectedDevice));
+ return static_cast<bool>(deviceAddr == bd_addr_to_str(evt.device.address));
+ }
+ } constexpr Connected;
+
+ struct HandleUnpair
+ {
+ void operator()(std::shared_ptr<AbstractDriver> driver, const bt::evt::Unpair &event)
+ {
+ driver->unpair(event.device);
+ }
+ } constexpr HandleUnpair;
+
+ struct HandleDrop
+ {
+ void operator()(const bt::evt::Unpair &event,
+ std::shared_ptr<bluetooth::SettingsHolder> settings,
+ std::shared_ptr<std::vector<Devicei>> pairedDevices)
+ {
+ auto position = std::find_if(pairedDevices->begin(), pairedDevices->end(), [&](const Devicei &device) {
+ return !bd_addr_cmp(event.device.address, device.address);
+ });
+ if (position != pairedDevices->end()) {
+ pairedDevices->erase(position);
+ settings->setValue(bluetooth::Settings::BondedDevices, SettingsSerializer::toString(*pairedDevices));
+ LOG_INFO("Device removed from paired devices list");
+ }
+ }
+ } constexpr HandleDrop;
+
+ struct HandleDisconnect
+ {
+ void operator()(std::shared_ptr<AbstractCommandHandler> handler)
+ {
+ handler->disconnectAudioConnection();
+ }
+
+ } constexpr HandleDisconnect;
+
+ struct HandleSetVisibility
+ {
+ void operator()(std::shared_ptr<AbstractCommandHandler> handler)
+ {
+ handler->setVisibility(true);
+ }
+
+ } constexpr HandleSetVisibility;
+
+ struct HandleUnsetVisibility
+ {
+ void operator()(std::shared_ptr<AbstractCommandHandler> handler)
+ {
+ handler->setVisibility(false);
+ }
+
+ } constexpr HandleUnsetVisibility;
+
+ struct EstablishAudioConnection
+ {
+ void operator()(std::shared_ptr<AbstractCommandHandler> handler, bt::evt::ConnectAudio evt)
+ {
+ handler->establishAudioConnection(evt.device);
+ }
+
+ } constexpr EstablishAudioConnection;
+
+ struct StartRinging
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager)
+ {
+ profileManager->startRinging();
+ }
+ } constexpr StartRinging;
+
+ struct StopRinging
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager)
+ {
+ profileManager->stopRinging();
+ }
+ } constexpr StopRinging;
+
+ struct InitializeCall
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager)
+ {
+ profileManager->initializeCall();
+ }
+ } constexpr InitializeCall;
+
+ struct CallAnswered
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager)
+ {
+ profileManager->callAnswered();
+ }
+ } constexpr CallAnswered;
+
+ struct TerminateCall
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager)
+ {
+ profileManager->terminateCall();
+ }
+ } constexpr TerminateCall;
+
+ struct CallStarted
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager, bt::evt::CallStarted evt)
+ {
+ profileManager->callStarted(evt.number);
+ }
+ } constexpr CallStarted;
+
+ struct IncomingCall
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager, bt::evt::IncomingCallNumber evt)
+ {
+ profileManager->setIncomingCallNumber(evt.number);
+ }
+ } constexpr IncomingCall;
+
+ struct SignalStrength
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager, bt::evt::SignalStrengthData evt)
+ {
+ profileManager->setSignalStrengthData(evt.strength);
+ }
+ } constexpr SignalStrength;
+
+ struct SetOperatorName
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager, bt::evt::OperatorNameData evt)
+ {
+ profileManager->setOperatorNameData(bluetooth::OperatorName(evt.name));
+ }
+ } constexpr SetOperatorName;
+
+ struct SetBatteryLevel
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager, bt::evt::BatteryLevelData evt)
+ {
+ profileManager->setBatteryLevelData(evt.level);
+ }
+ } constexpr SetBatteryLevel;
+
+ struct SetNetworkStatus
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager, bt::evt::NetworkStatusData evt)
+ {
+ profileManager->setNetworkStatusData(evt.status);
+ }
+ } constexpr SetNetworkStatus;
+
+ struct StartAudio
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager)
+ {
+ profileManager->start();
+ }
+ } constexpr StartAudio;
+
+ struct StopAudio
+ {
+ void operator()(std::shared_ptr<bluetooth::BaseProfileManager> profileManager)
+ {
+ profileManager->stop();
+ }
+ } constexpr StopAudio;
+
+ struct On
+ {
+ auto operator()() const
+ {
+ auto isInit = [](InitializationState &data) { return data.isInitDone; };
+
+ using namespace sml;
+ // clang-format off
+ return make_transition_table(
+ *"Idle"_s + event<bt::evt::StartScan>[isInit] / HandleOn = "Idle"_s,
+ "Idle"_s + event<bt::evt::StopScan>[isInit] / HandleOff = "Idle"_s,
+ "Idle"_s + event<bt::evt::Pair>[isInit] / HandlePair = "Idle"_s,
+ "Idle"_s + event<bt::evt::Unpair>[isInit and Connected] / (HandleDisconnect, HandleUnpair) = "Idle"_s,
+ "Idle"_s + event<bt::evt::Unpair>[isInit] / (HandleUnpair, HandleDrop) = "Idle"_s,
+
+ "Idle"_s + event<bt::evt::VisibilityOn> / HandleSetVisibility = "Idle"_s,
+ "Idle"_s + event<bt::evt::VisibilityOff> / HandleUnsetVisibility = "Idle"_s,
+ "Idle"_s + event<bt::evt::ConnectAudio> / EstablishAudioConnection = "Idle"_s,
+
+ "Idle"_s + event<bt::evt::StartRinging> / StartRinging = "Idle"_s,
+ "Idle"_s + event<bt::evt::StopRinging> / StopRinging = "Idle"_s,
+ "Idle"_s + event<bt::evt::StartRouting> /InitializeCall = "Idle"_s,
+ "Idle"_s + event<bt::evt::CallAnswered> / CallAnswered = "Idle"_s,
+ "Idle"_s + event<bt::evt::CallTerminated> / TerminateCall = "Idle"_s,
+ "Idle"_s + event<bt::evt::CallStarted>/ CallStarted = "Idle"_s,
+ "Idle"_s + event<bt::evt::IncomingCallNumber> / IncomingCall= "Idle"_s,
+ "Idle"_s + event<bt::evt::SignalStrengthData> / SignalStrength = "Idle"_s,
+ "Idle"_s + event<bt::evt::OperatorNameData>/ SetOperatorName = "Idle"_s,
+ "Idle"_s + event<bt::evt::BatteryLevelData>/ SetBatteryLevel = "Idle"_s,
+ "Idle"_s + event<bt::evt::NetworkStatusData> / SetNetworkStatus = "Idle"_s,
+ "Idle"_s + event<bt::evt::StartStream>/ StartAudio = "Idle"_s,
+ "Idle"_s + event<bt::evt::StopStream>/ StopAudio = "Idle"_s
+ );
+ // clang-format on
+ }
+ };
+
+ struct ExceptionHandler
+ {
+ void operator()(const std::runtime_error &err)
+ {
+ LOG_FATAL("EXCEPTION %s", err.what());
+ }
+ } constexpr ExceptionHandler;
+
+ struct TurnOff
+ {
+ void operator()(std::shared_ptr<AbstractDriver> driver,
+ std::shared_ptr<bluetooth::BaseProfileManager> profileManager)
+ {
+ profileManager->deInit();
+ driver->stop();
+ };
+ } constexpr TurnOff;
+
+ class StateMachine
+ {
+ public:
+ auto operator()() const
+ {
+ 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<bt::evt::PowerOn> = state<Setup>,
+ state<Setup> = state<On>,
+ state<Setup> + exception<InitializationError> / printInitError = "Off"_s,
+
+ state<On> + event<bt::evt::PowerOff> / TurnOff = "Off"_s,
+ state<On> + exception<ProcessingError> / ( printProcessingError, TurnOff ) = "Restart"_s,
+ state<On> + event<bt::evt::ShutDown> / TurnOff = X,
+
+ "Restart"_s = state<Setup>,
+ "Restart"_s + event<bt::evt::ShutDown> /TurnOff = X,
+
+ *("ExceptionsHandling"_s) + exception<std::runtime_error> / ExceptionHandler = "Off"_s,
+ "ExceptionsHandling"_s + exception<std::runtime_error> / ExceptionHandler = "Off"_s,
+
+ "Off"_s + event<bt::evt::ShutDown> = X);
+ // clang-format on
+ }
+ };
+
+ class StatefulController::Impl
+ {
+ public:
+ Impl() = delete;
+ Impl(std::shared_ptr<AbstractDriver> driver,
+ std::shared_ptr<AbstractCommandHandler> handler,
+ DeviceRegistrationFunction registerDevice,
+ std::shared_ptr<bluetooth::SettingsHolder> settings,
+ std::shared_ptr<std::vector<Devicei>> pairedDevices,
+ std::shared_ptr<bluetooth::BaseProfileManager> profileManager);
+ using SM = sml::sm<StateMachine, boost::sml::logger<Logger>>;
+ SM sm;
+ };
+
+ StatefulController::Impl::Impl(std::shared_ptr<AbstractDriver> driver,
+ std::shared_ptr<AbstractCommandHandler> handler,
+ DeviceRegistrationFunction registerDevice,
+ std::shared_ptr<bluetooth::SettingsHolder> settings,
+ std::shared_ptr<std::vector<Devicei>> pairedDevices,
+ std::shared_ptr<bluetooth::BaseProfileManager> profileManager)
+ : sm{Logger{}, driver, handler, registerDevice, InitializationState{}, settings, pairedDevices, profileManager}
+ {}
+} // namespace bluetooth
M module-bluetooth/Bluetooth/BluetoothWorker.cpp => module-bluetooth/Bluetooth/BluetoothWorker.cpp +46 -74
@@ 10,7 10,6 @@
#include "interface/profiles/HSP/HSP.hpp"
#include "audio/BluetoothAudioDevice.hpp"
#include "BtKeysStorage.hpp"
-#include "command/DeviceData.hpp"
#if DEBUG_BLUETOOTH_HCI_COMS == 1
#define logHciComs(...) LOG_DEBUG(__VA_ARGS__)
@@ 71,32 70,44 @@ namespace
};
auto createStatefulController(sys::Service *service,
- bluetooth::RunLoop *loop,
- std::shared_ptr<bluetooth::SettingsHolder> settings,
- std::shared_ptr<bluetooth::ProfileManager> profileManager,
- DeviceRegistration::OnLinkKeyAddedCallback &&onLinkKeyAddedCallback)
+ std::shared_ptr<bluetooth::Driver> driver,
+ std::shared_ptr<bluetooth::CommandHandler> commandHandler,
+ const std::shared_ptr<bluetooth::SettingsHolder> &settings,
+ std::shared_ptr<bluetooth::BaseProfileManager> profileManager,
+ DeviceRegistration::OnLinkKeyAddedCallback &&onLinkKeyAddedCallback,
+ std::shared_ptr<std::vector<Devicei>> pairedDevices)
{
- auto driver = std::make_shared<bluetooth::Driver>(loop->getRunLoopInstance(), service);
- auto commandHandler =
- std::make_unique<bluetooth::CommandHandler>(service, settings, std::move(profileManager), driver);
+ ;
+
return std::make_unique<bluetooth::StatefulController>(
- std::move(driver),
- std::move(commandHandler),
- DeviceRegistration{std::move(settings), std::move(onLinkKeyAddedCallback)});
+ driver,
+ commandHandler,
+ DeviceRegistration{settings, std::move(onLinkKeyAddedCallback)},
+ settings,
+ pairedDevices,
+ profileManager);
}
} // namespace
BluetoothWorker::BluetoothWorker(sys::Service *service)
: Worker(service, BluetoothWorkerStackDepth), service(service),
profileManager(std::make_shared<bluetooth::ProfileManager>(service)),
- settings(static_cast<ServiceBluetooth *>(service)->settingsHolder),
+ settings(dynamic_cast<ServiceBluetooth *>(service)->settingsHolder),
runLoop(std::make_unique<bluetooth::RunLoop>()),
+ driver(std::make_shared<bluetooth::Driver>(runLoop->getRunLoopInstance(), service)),
+ handler(std::make_shared<bluetooth::CommandHandler>(service, settings, profileManager, driver)),
controller{createStatefulController(
- service, runLoop.get(), settings, profileManager, [this](const std::string &addr) { onLinkKeyAdded(addr); })}
+ service,
+ driver,
+ handler,
+ settings,
+ profileManager,
+ [this](const std::string &addr) { onLinkKeyAdded(addr); },
+ pairedDevices)}
{
init({
{queues::io, sizeof(bluetooth::Message), queues::queueLength},
- {queues::cmd, sizeof(bluetooth::Command::CommandPack), queues::queueLength},
+ {queues::cmd, 0, queues::queueLength},
{queues::btstack, sizeof(bool), queues::triggerQueueLength},
});
registerQueues();
@@ 104,7 115,10 @@ BluetoothWorker::BluetoothWorker(sys::Service *service)
void BluetoothWorker::registerQueues()
{
- static_cast<ServiceBluetooth *>(service)->workerQueue = Worker::getQueueHandleByName(queues::cmd);
+ workerQueue = std::make_shared<Mailbox<bluetooth::Command, QueueHandle_t, WorkerLock>>(
+ Worker::getQueueHandleByName(queues::cmd));
+
+ dynamic_cast<ServiceBluetooth *>(service)->workerQueue = workerQueue;
runLoop->setTriggerQueue(Worker::getQueueHandleByName(queues::btstack));
bsp::BlueKitchen::getInstance()->qHandle = queues[queueIO_handle]->GetQueueHandle();
}
@@ 114,15 128,15 @@ void BluetoothWorker::onLinkKeyAdded(const std::string &deviceAddress)
auto devices = bluetooth::GAP::getDevicesList();
for (auto &device : devices) {
if (bd_addr_to_str(device.address) == deviceAddress) {
- pairedDevices.emplace_back(device);
- settings->setValue(bluetooth::Settings::BondedDevices, SettingsSerializer::toString(pairedDevices));
+ pairedDevices->emplace_back(device);
+ settings->setValue(bluetooth::Settings::BondedDevices, SettingsSerializer::toString(*pairedDevices));
}
}
}
BluetoothWorker::~BluetoothWorker()
{
- controller->shutdown();
+ controller->handle(bt::evt::ShutDown{});
}
auto BluetoothWorker::run() -> bool
@@ 141,33 155,18 @@ auto BluetoothWorker::run() -> bool
auto BluetoothWorker::handleCommand(QueueHandle_t queue) -> bool
{
- bluetooth::Command::CommandPack pack{};
- if (xQueueReceive(queue, static_cast<void *>(&pack), 0) != pdTRUE) {
- LOG_ERROR("Queue receive failure!");
- return false;
- }
- auto command = bluetooth::Command(std::move(pack));
-
- switch (command.getType()) {
- case bluetooth::Command::PowerOn:
- initDevicesList();
- controller->turnOn();
- break;
- case bluetooth::Command::Unpair: {
- controller->processCommand(command);
- auto device = std::get<Devicei>(command.getData());
- removeFromBoundDevices(device.address);
- handleUnpairDisconnect(device);
- } break;
- case bluetooth::Command::None:
- break;
- case bluetooth::Command::PowerOff:
- controller->processCommand(command);
- controller->turnOff();
- break;
- default:
- controller->processCommand(command);
- break;
+ LOG_INFO("handle bluetooth command(s)");
+ xQueueReceive(queue, nullptr, 0);
+ while (not workerQueue->empty()) {
+ auto cmd = workerQueue->peek();
+ if (cmd == std::nullopt) {
+ LOG_ERROR("There was no data even with notification");
+ break;
+ }
+ if ((*cmd).evt != nullptr) {
+ controller->handle(*cmd->evt);
+ delete cmd->evt;
+ }
}
return true;
}
@@ 264,24 263,12 @@ auto BluetoothWorker::handleMessage(uint32_t queueID) -> bool
void BluetoothWorker::closeWorker()
{
- controller->turnOff();
+ controller->handle(bt::evt::PowerOff{});
this->close();
}
-void BluetoothWorker::initDevicesList()
-{
- auto bondedDevicesStr =
- std::visit(bluetooth::StringVisitor(), settings->getValue(bluetooth::Settings::BondedDevices));
- pairedDevices = SettingsSerializer::fromString(bondedDevicesStr);
-}
+
void BluetoothWorker::removeFromBoundDevices(uint8_t *addr)
{
- auto position = std::find_if(
- pairedDevices.begin(), pairedDevices.end(), [&](Devicei device) { return !bd_addr_cmp(addr, device.address); });
- if (position != pairedDevices.end()) {
- pairedDevices.erase(position);
- settings->setValue(bluetooth::Settings::BondedDevices, SettingsSerializer::toString(pairedDevices));
- LOG_INFO("Device removed from paired devices list");
- }
}
void BluetoothWorker::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> device)
@@ 289,18 276,3 @@ void BluetoothWorker::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDe
cpp_freertos::LockGuard lock(loopMutex);
profileManager->setAudioDevice(std::move(device));
}
-auto BluetoothWorker::isAddressConnected(const uint8_t *addr) -> bool
-{
- auto deviceAddr =
- std::visit(bluetooth::StringVisitor(), this->settings->getValue(bluetooth::Settings::ConnectedDevice));
- return static_cast<bool>(deviceAddr == bd_addr_to_str(addr));
-}
-void BluetoothWorker::handleUnpairDisconnect(const Devicei &device)
-{
- if (isAddressConnected(device.address)) {
- auto commandData = std::make_unique<bluetooth::DeviceData>(device);
- auto disconnectCmd = bluetooth::Command(
- bluetooth::Command::CommandPack{bluetooth::Command::DisconnectAudio, std::move(commandData)});
- controller->processCommand(disconnectCmd);
- }
-}
M module-bluetooth/Bluetooth/BluetoothWorker.hpp => module-bluetooth/Bluetooth/BluetoothWorker.hpp +16 -5
@@ 7,6 7,7 @@
#include "glucode/BluetoothRunLoop.hpp"
#include "interface/profiles/Profile.hpp"
#include "service-bluetooth/SettingsHolder.hpp"
+#include "service-bluetooth/WorkerLock.hpp"
#include "Service/Worker.hpp"
#include "Device.hpp"
@@ 61,6 62,15 @@ namespace bluetooth
};
}; // namespace bluetooth
+struct DeviceStore
+{};
+
+namespace bluetooth
+{
+ class Driver;
+ class CommandHandler;
+}; // namespace bluetooth
+
class BluetoothWorker : private sys::Worker
{
enum WorkerEventQueues
@@ 78,10 88,9 @@ class BluetoothWorker : private sys::Worker
void registerQueues();
void onLinkKeyAdded(const std::string &deviceAddress);
- void initDevicesList();
void removeFromBoundDevices(uint8_t *addr);
- auto isAddressConnected(const bd_addr_t addr) -> bool;
- void handleUnpairDisconnect(const Devicei &device);
+
+ std::shared_ptr<Mailbox<bluetooth::Command, QueueHandle_t, WorkerLock>> workerQueue;
public:
enum Error
@@ 91,7 100,7 @@ class BluetoothWorker : private sys::Worker
ErrorBtAPI,
};
- BluetoothWorker(sys::Service *service);
+ explicit BluetoothWorker(sys::Service *service);
~BluetoothWorker() override;
auto handleMessage(uint32_t queueID) -> bool override;
@@ 107,7 116,9 @@ class BluetoothWorker : private sys::Worker
unsigned long active_features;
std::shared_ptr<bluetooth::ProfileManager> profileManager;
std::shared_ptr<bluetooth::SettingsHolder> settings;
- std::vector<Devicei> pairedDevices;
+ std::shared_ptr<std::vector<Devicei>> pairedDevices = std::make_shared<std::vector<Devicei>>();
std::unique_ptr<bluetooth::RunLoop> runLoop;
+ std::shared_ptr<bluetooth::Driver> driver;
+ std::shared_ptr<bluetooth::CommandHandler> handler;
std::unique_ptr<bluetooth::AbstractController> controller;
};
M module-bluetooth/Bluetooth/CommandHandler.cpp => module-bluetooth/Bluetooth/CommandHandler.cpp +5 -63
@@ 31,7 31,7 @@ namespace bluetooth
CommandHandler::CommandHandler(sys::Service *service,
std::shared_ptr<bluetooth::SettingsHolder> settings,
- std::shared_ptr<bluetooth::ProfileManager> profileManager,
+ std::shared_ptr<bluetooth::BaseProfileManager> profileManager,
std::shared_ptr<bluetooth::AbstractDriver> driver)
: service{service}, settings{std::move(settings)}, profileManager{std::move(profileManager)}, driver{std::move(
driver)}
@@ 39,66 39,6 @@ namespace bluetooth
this->driver->registerPowerOnCallback([profilePtr = this->profileManager]() { profilePtr->init(); });
}
- Error::Code CommandHandler::handle(Command &command)
- {
- switch (command.getType()) {
- case bluetooth::Command::PowerOn:
- return Error::Success;
- case bluetooth::Command::StartScan:
- return scan();
- case bluetooth::Command::getDevicesAvailable:
- return availableDevices();
- case bluetooth::Command::StopScan:
- return stopScan();
- case bluetooth::Command::Pair:
- return pair(command.getData());
- case bluetooth::Command::Unpair:
- return unpair(command.getData());
- case bluetooth::Command::VisibilityOn:
- return setVisibility(true);
- case bluetooth::Command::VisibilityOff:
- return setVisibility(false);
- case bluetooth::Command::ConnectAudio:
- return establishAudioConnection(command.getData());
- case bluetooth::Command::DisconnectAudio:
- return disconnectAudioConnection();
- case bluetooth::Command::PowerOff:
- profileManager->deInit();
- return Error::Success;
- case bluetooth::Command::None:
- return Error::Success;
- case Command::StartRinging:
- return profileManager->startRinging();
- case Command::StopRinging:
- return profileManager->stopRinging();
- case Command::StartRouting:
- return profileManager->initializeCall();
- case Command::CallAnswered:
- return profileManager->callAnswered();
- case Command::CallTerminated:
- return profileManager->terminateCall();
- case Command::CallStarted:
- return profileManager->callStarted(command.getData());
- case Command::IncomingCallNumber:
- return profileManager->setIncomingCallNumber(command.getData());
- case Command::SignalStrengthData:
- return profileManager->setSignalStrengthData(command.getData());
- case Command::OperatorNameData:
- return profileManager->setOperatorNameData(command.getData());
- case Command::BatteryLevelData:
- return profileManager->setBatteryLevelData(command.getData());
- case Command::NetworkStatusData:
- return profileManager->setNetworkStatusData(command.getData());
- case Command::StartStream:
- profileManager->start();
- return Error::Success;
- case Command::StopStream:
- profileManager->stop();
- return Error::Success;
- }
- return Error::LibraryError;
- }
-
Error::Code CommandHandler::scan()
{
@@ 144,7 84,8 @@ namespace bluetooth
{
auto device = std::get<Devicei>(data);
LOG_INFO("Pairing...");
- const auto errorCode = driver->pair(device) ? Error::Success : Error::LibraryError;
+ auto errorCode = Error::Code::Success;
+ driver->pair(device);
LOG_INFO("Pairing result: %s", magic_enum::enum_name(errorCode).data());
return errorCode;
}
@@ 152,7 93,8 @@ namespace bluetooth
{
auto device = std::get<Devicei>(data);
LOG_INFO("Unpairing...");
- const auto errorCode = driver->unpair(device) ? Error::Success : Error::LibraryError;
+ const auto errorCode = Error::Code::Success;
+ driver->unpair(device);
LOG_INFO("Unpairing result: %s", magic_enum::enum_name(errorCode).data());
return errorCode;
}
M module-bluetooth/Bluetooth/CommandHandler.hpp => module-bluetooth/Bluetooth/CommandHandler.hpp +22 -12
@@ 27,7 27,14 @@ namespace bluetooth
public:
virtual ~AbstractCommandHandler() noexcept = default;
- virtual auto handle(Command &command) -> Error::Code = 0;
+ virtual Error::Code scan() = 0;
+ virtual Error::Code stopScan() = 0;
+ virtual Error::Code setVisibility(bool visibility) = 0;
+ virtual Error::Code establishAudioConnection(const DataVariant &data) = 0;
+ virtual Error::Code disconnectAudioConnection() = 0;
+ virtual Error::Code pair(const DataVariant &data) = 0;
+ virtual Error::Code unpair(const DataVariant &data) = 0;
+ virtual Error::Code availableDevices() = 0;
};
class CommandHandler : public AbstractCommandHandler
@@ 35,23 42,26 @@ namespace bluetooth
public:
explicit CommandHandler(sys::Service *service,
std::shared_ptr<bluetooth::SettingsHolder> settings,
- std::shared_ptr<bluetooth::ProfileManager> profileManager,
+ std::shared_ptr<bluetooth::BaseProfileManager> profileManager,
std::shared_ptr<bluetooth::AbstractDriver> driver);
- auto handle(Command &command) -> Error::Code override;
+ Error::Code scan() override;
+ Error::Code stopScan() override;
+ Error::Code setVisibility(bool visibility) override;
+ Error::Code establishAudioConnection(const DataVariant &data) override;
+ Error::Code disconnectAudioConnection() override;
+ Error::Code pair(const DataVariant &data) override;
+ Error::Code unpair(const DataVariant &data) override;
+ Error::Code availableDevices() override;
private:
- Error::Code scan();
- Error::Code stopScan();
- Error::Code setVisibility(bool visibility);
- Error::Code establishAudioConnection(const DataVariant &data);
- Error::Code disconnectAudioConnection();
- Error::Code pair(const DataVariant &data);
- Error::Code unpair(const DataVariant &data);
- Error::Code availableDevices();
sys::Service *service;
std::shared_ptr<bluetooth::SettingsHolder> settings;
- std::shared_ptr<bluetooth::ProfileManager> profileManager;
+
+ public:
+ std::shared_ptr<bluetooth::BaseProfileManager> profileManager;
+
+ private:
std::shared_ptr<AbstractDriver> driver;
};
} // namespace bluetooth
M module-bluetooth/Bluetooth/WorkerController.cpp => module-bluetooth/Bluetooth/WorkerController.cpp +122 -170
@@ 1,191 1,143 @@
// Copyright (c) 2017-2022, 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/ProfileManager.hpp"
-
-#include <log/log.hpp>
-#define BOOST_SML_CFG_DISABLE_MIN_SIZE // GCC10 fix
-#include <boost/sml.hpp>
-#include <magic_enum.hpp>
-#include <stdexcept>
+#include "BluetoothStateMachine.hpp"
namespace bluetooth
{
- namespace sml = boost::sml;
-
- namespace
- {
- 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<AbstractDriver> &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<AbstractDriver> &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<AbstractCommandHandler> &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<ProcessCommand> [ isInit ] / handleCommand = "Processing"_s,
- "Processing"_s = "Idle"_s);
- // clang-format on
- }
- };
-
- class StateMachine
- {
- public:
- auto operator()() const
- {
- auto turnOff = [](std::shared_ptr<AbstractDriver> &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<TurnOn> = state<Setup>,
- state<Setup> = state<On>,
- state<Setup> + exception<InitializationError> / printInitError = "Off"_s,
- state<On> + event<TurnOff> / turnOff = "Off"_s,
- state<On> + exception<ProcessingError> / ( printProcessingError, turnOff ) = "Restart"_s,
- "Restart"_s = state<Setup>,
- "Off"_s + event<ShutDown> = X);
- // clang-format on
- }
- };
- } // namespace
-
- class StatefulController::Impl
- {
- public:
- Impl(std::shared_ptr<AbstractDriver> &&driver,
- std::shared_ptr<AbstractCommandHandler> &&handler,
- DeviceRegistrationFunction &®isterDevice);
-
- using SM = sml::sm<StateMachine>;
- SM sm;
- };
-
- StatefulController::Impl::Impl(std::shared_ptr<AbstractDriver> &&driver,
- std::shared_ptr<AbstractCommandHandler> &&handler,
- DeviceRegistrationFunction &®isterDevice)
- : sm{std::move(driver), std::move(handler), std::move(registerDevice), InitializationState{}}
- {}
-
- StatefulController::StatefulController(std::shared_ptr<AbstractDriver> &&driver,
- std::shared_ptr<AbstractCommandHandler> &&handler,
- DeviceRegistrationFunction &®isterDevice)
- : pimpl(std::make_unique<Impl>(std::move(driver), std::move(handler), std::move(registerDevice)))
- {}
-
- StatefulController::~StatefulController() noexcept = default;
- void StatefulController::turnOn()
+ StatefulController::StatefulController(std::shared_ptr<AbstractDriver> driver,
+ std::shared_ptr<AbstractCommandHandler> handler,
+ DeviceRegistrationFunction registerDevice,
+ std::shared_ptr<bluetooth::SettingsHolder> settings,
+ std::shared_ptr<std::vector<Devicei>> pairedDevices,
+ std::shared_ptr<bluetooth::BaseProfileManager> profileManager)
+ : pimpl(std::make_unique<Impl>(driver, handler, registerDevice, settings, pairedDevices, profileManager))
{
- pimpl->sm.process_event(TurnOn{});
}
- void StatefulController::turnOff()
+ StatefulController::StatefulController(StatefulController &&other) noexcept
{
- pimpl->sm.process_event(TurnOff{});
+ this->pimpl = std::move(other.pimpl);
}
- void StatefulController::shutdown()
+ StatefulController &StatefulController::operator=(StatefulController &&other) noexcept
{
- if (isOn()) {
- turnOff();
- }
- pimpl->sm.process_event(ShutDown{});
+ this->pimpl = std::move(other.pimpl);
+ return *this;
}
- auto StatefulController::isOn() const -> bool
- {
- using namespace sml;
- return !pimpl->sm.is("Off"_s) && !isTerminated();
- }
+ StatefulController::~StatefulController() noexcept = default;
- auto StatefulController::isTerminated() const -> bool
+ //--------------------------------------------------------------------
+ // entry to dispatch to call handle (double visitor -> double dispatch)
+ void StatefulController::handle(const bt::evt::Base &evt)
{
- using namespace sml;
- return pimpl->sm.is(X);
+ evt.dispatch(this);
}
- void StatefulController::processCommand(Command &command)
- {
- try {
- LOG_INFO("Process command: %s", magic_enum::enum_name(command.getType()).data());
- pimpl->sm.process_event(ProcessCommand{command});
- LOG_DEBUG("Command processed");
- }
- catch (std::bad_variant_access &e) {
- LOG_ERROR(
- "Failed to parse command %s, error: %s", magic_enum::enum_name(command.getType()).data(), e.what());
- }
- }
+ //-----------------------------------------
+ // all `handle` code below is casual visitor
+
+ void StatefulController::handle(const bt::evt::StartScan &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::StopScan &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::GetDevicesAvailable &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::VisibilityOn &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::VisibilityOff &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::ConnectAudio &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::DisconnectAudio &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ // TODO split TurnOn and PowerOn?
+ void StatefulController::handle(const bt::evt::PowerOn &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::PowerOff &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::ShutDown &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::Pair &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::Unpair &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::StartRinging &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::StopRinging &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::StartRouting &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::StartStream &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::StopStream &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::CallAnswered &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::CallTerminated &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::CallStarted &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::IncomingCallNumber &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::SignalStrengthData &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::OperatorNameData &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::BatteryLevelData &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
+ void StatefulController::handle(const bt::evt::NetworkStatusData &evt)
+ {
+ pimpl->sm.process_event(evt);
+ };
} // namespace bluetooth
M module-bluetooth/Bluetooth/WorkerController.hpp => module-bluetooth/Bluetooth/WorkerController.hpp +41 -24
@@ 3,8 3,10 @@
#pragma once
+#include "AbstractController.hpp"
#include "CommandHandler.hpp"
#include "interface/BluetoothDriver.hpp"
+#include <command/event/Events.hpp>
#include <functional>
#include <memory>
@@ 13,38 15,53 @@ namespace bluetooth
{
using DeviceRegistrationFunction = std::function<Error::Code()>;
- 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<AbstractDriver> &&driver,
- std::shared_ptr<AbstractCommandHandler> &&handler,
- DeviceRegistrationFunction &®isterDevice);
+ StatefulController(std::shared_ptr<AbstractDriver> driver,
+ std::shared_ptr<AbstractCommandHandler> handler,
+ DeviceRegistrationFunction registerDevice,
+ std::shared_ptr<bluetooth::SettingsHolder> settings,
+ std::shared_ptr<std::vector<Devicei>> pairedDevices,
+ std::shared_ptr<bluetooth::BaseProfileManager> profileManager);
+ StatefulController() = delete;
+ StatefulController(const StatefulController &other) = delete;
+ StatefulController(StatefulController &&other) noexcept;
+ StatefulController &operator=(const StatefulController &other) = delete;
+ StatefulController &operator =(StatefulController &&other) noexcept;
+
~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 handle(const bt::evt::Base &evt) override;
+ void handle(const bt::evt::StartScan &evt) override;
+ void handle(const bt::evt::StopScan &evt) override;
+ void handle(const bt::evt::GetDevicesAvailable &evt) override;
+ void handle(const bt::evt::VisibilityOn &evt) override;
+ void handle(const bt::evt::VisibilityOff &evt) override;
+ void handle(const bt::evt::ConnectAudio &evt) override;
+ void handle(const bt::evt::DisconnectAudio &evt) override;
+ void handle(const bt::evt::PowerOn &evt) override;
+ void handle(const bt::evt::PowerOff &evt) override;
+ void handle(const bt::evt::ShutDown &evt) override;
+ void handle(const bt::evt::Pair &evt) override;
+ void handle(const bt::evt::Unpair &evt) override;
+ void handle(const bt::evt::StartRinging &evt) override;
+ void handle(const bt::evt::StopRinging &evt) override;
+ void handle(const bt::evt::StartRouting &evt) override;
+ void handle(const bt::evt::StartStream &evt) override;
+ void handle(const bt::evt::StopStream &evt) override;
+ void handle(const bt::evt::CallAnswered &evt) override;
+ void handle(const bt::evt::CallTerminated &evt) override;
+ void handle(const bt::evt::CallStarted &evt) override;
+ void handle(const bt::evt::IncomingCallNumber &evt) override;
+ void handle(const bt::evt::SignalStrengthData &evt) override;
+ void handle(const bt::evt::OperatorNameData &evt) override;
+ void handle(const bt::evt::BatteryLevelData &evt) override;
+ void handle(const bt::evt::NetworkStatusData &evt) override;
- void processCommand(Command &command) override;
+ class Impl;
private:
- class Impl;
std::unique_ptr<Impl> pimpl;
};
} // namespace bluetooth
M module-bluetooth/Bluetooth/command/BatteryLevelData.hpp => module-bluetooth/Bluetooth/command/BatteryLevelData.hpp +1 -1
@@ 7,7 7,7 @@
namespace bluetooth
{
- class BatteryLevelData : public CommandData
+ class BatteryLevelData : public Action
{
public:
explicit BatteryLevelData(const BatteryLevel &level);
M module-bluetooth/Bluetooth/command/Command.cpp => module-bluetooth/Bluetooth/command/Command.cpp +0 -17
@@ 6,21 6,4 @@
namespace bluetooth
{
-
- Command::Command(CommandPack &&pack) : pack(std::move(pack))
- {}
-
- auto Command::getType() const noexcept -> Command::Type
- {
- return pack.commandType;
- }
-
- auto Command::getData() -> DataVariant
- {
- if (pack.data == nullptr) {
- LOG_ERROR("Terrible,terrible damage!");
- return DataVariant{};
- }
- return pack.data->getData();
- }
} // namespace bluetooth
M module-bluetooth/Bluetooth/command/Command.hpp => module-bluetooth/Bluetooth/command/Command.hpp +3 -47
@@ 3,58 3,14 @@
#pragma once
#include "CommandData.hpp"
+#include "event/Events.hpp"
namespace bluetooth
{
- class Command
+ struct Command
{
- public:
- enum Type
- {
- StartScan,
- StopScan,
- getDevicesAvailable,
- VisibilityOn,
- VisibilityOff,
- ConnectAudio,
- DisconnectAudio,
- PowerOn,
- PowerOff,
- Pair,
- Unpair,
- StartRinging,
- StopRinging,
- StartRouting,
- StartStream,
- StopStream,
- CallAnswered,
- CallTerminated,
- CallStarted,
- IncomingCallNumber,
- SignalStrengthData,
- OperatorNameData,
- BatteryLevelData,
- NetworkStatusData,
- None,
- };
-
- struct CommandPack
- {
- Command::Type commandType = Command::None;
- std::unique_ptr<CommandData> data = nullptr;
- };
-
- explicit Command(CommandPack &&);
- explicit Command(Command::Type type)
- {
- pack.commandType = type;
- }
- auto getType() const noexcept -> Command::Type;
- auto getData() -> DataVariant;
-
- private:
- CommandPack pack;
+ bt::evt::Base *evt = nullptr;
};
} // namespace bluetooth
M module-bluetooth/Bluetooth/command/CommandData.hpp => module-bluetooth/Bluetooth/command/CommandData.hpp +0 -7
@@ 18,11 18,4 @@ namespace bluetooth
Devicei,
utils::PhoneNumber::View,
Store::Network::Status>;
-
- class CommandData
- {
- public:
- virtual auto getData() -> DataVariant = 0;
- virtual ~CommandData() = default;
- };
} // namespace bluetooth
D module-bluetooth/Bluetooth/command/DeviceData.cpp => module-bluetooth/Bluetooth/command/DeviceData.cpp +0 -16
@@ 1,16 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include "DeviceData.hpp"
-
-namespace bluetooth
-{
- DeviceData::DeviceData(const Devicei &device) : device(device)
- {}
-
- auto DeviceData::getData() -> DataVariant
- {
- return device;
- }
-
-} // namespace bluetooth
D module-bluetooth/Bluetooth/command/DeviceData.hpp => module-bluetooth/Bluetooth/command/DeviceData.hpp +0 -21
@@ 1,21 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#pragma once
-#include "CommandData.hpp"
-#include "Device.hpp"
-
-namespace bluetooth
-{
-
- class DeviceData : public CommandData
- {
- public:
- explicit DeviceData(const Devicei &device);
- auto getData() -> DataVariant override;
-
- private:
- Devicei device;
- };
-
-} // namespace bluetooth
D module-bluetooth/Bluetooth/command/NetworkStatusData.cpp => module-bluetooth/Bluetooth/command/NetworkStatusData.cpp +0 -14
@@ 1,14 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include "NetworkStatusData.hpp"
-
-namespace bluetooth
-{
- NetworkStatusData::NetworkStatusData(const Store::Network::Status &status) : status(status)
- {}
- auto NetworkStatusData::getData() -> DataVariant
- {
- return status;
- }
-} // namespace bluetooth
D module-bluetooth/Bluetooth/command/NetworkStatusData.hpp => module-bluetooth/Bluetooth/command/NetworkStatusData.hpp +0 -20
@@ 1,20 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#pragma once
-#include "CommandData.hpp"
-
-namespace bluetooth
-{
-
- class NetworkStatusData : public CommandData
- {
- public:
- explicit NetworkStatusData(const Store::Network::Status &status);
- auto getData() -> DataVariant override;
-
- private:
- Store::Network::Status status;
- };
-
-} // namespace bluetooth
D module-bluetooth/Bluetooth/command/OperatorNameData.cpp => module-bluetooth/Bluetooth/command/OperatorNameData.cpp +0 -16
@@ 1,16 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include "OperatorNameData.hpp"
-
-#include <utility>
-
-namespace bluetooth
-{
- OperatorNameData::OperatorNameData(OperatorName operatorName) : operatorName(std::move(operatorName))
- {}
- auto OperatorNameData::getData() -> DataVariant
- {
- return operatorName;
- }
-} // namespace bluetooth
D module-bluetooth/Bluetooth/command/OperatorNameData.hpp => module-bluetooth/Bluetooth/command/OperatorNameData.hpp +0 -20
@@ 1,20 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#pragma once
-#include "CommandData.hpp"
-
-namespace bluetooth
-{
-
- class OperatorNameData : public CommandData
- {
- public:
- explicit OperatorNameData(OperatorName operatorName);
- auto getData() -> DataVariant override;
-
- private:
- OperatorName operatorName;
- };
-
-} // namespace bluetooth
D module-bluetooth/Bluetooth/command/PhoneNumberData.cpp => module-bluetooth/Bluetooth/command/PhoneNumberData.cpp +0 -16
@@ 1,16 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include "PhoneNumberData.hpp"
-
-namespace bluetooth
-{
- PhoneNumberData::PhoneNumberData(const utils::PhoneNumber::View &view) : view(view)
- {}
- PhoneNumberData::PhoneNumberData(const utils::PhoneNumber &number) : view(number.getView())
- {}
- auto PhoneNumberData::getData() -> DataVariant
- {
- return view;
- }
-} // namespace bluetooth
D module-bluetooth/Bluetooth/command/PhoneNumberData.hpp => module-bluetooth/Bluetooth/command/PhoneNumberData.hpp +0 -21
@@ 1,21 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#pragma once
-#include "CommandData.hpp"
-
-namespace bluetooth
-{
-
- class PhoneNumberData : public CommandData
- {
- public:
- explicit PhoneNumberData(const utils::PhoneNumber::View &view);
- explicit PhoneNumberData(const utils::PhoneNumber &number);
- auto getData() -> DataVariant override;
-
- private:
- utils::PhoneNumber::View view;
- };
-
-} // namespace bluetooth
D module-bluetooth/Bluetooth/command/SignalStrengthData.cpp => module-bluetooth/Bluetooth/command/SignalStrengthData.cpp +0 -14
@@ 1,14 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include "SignalStrengthData.hpp"
-
-namespace bluetooth
-{
- SignalStrengthData::SignalStrengthData(const Store::SignalStrength &signalStrength) : signalStrength(signalStrength)
- {}
- auto SignalStrengthData::getData() -> DataVariant
- {
- return signalStrength;
- }
-} // namespace bluetooth
D module-bluetooth/Bluetooth/command/SignalStrengthData.hpp => module-bluetooth/Bluetooth/command/SignalStrengthData.hpp +0 -20
@@ 1,20 0,0 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#pragma once
-#include "CommandData.hpp"
-
-namespace bluetooth
-{
-
- class SignalStrengthData : public CommandData
- {
- public:
- explicit SignalStrengthData(const Store::SignalStrength &signalStrength);
- auto getData() -> DataVariant override;
-
- private:
- Store::SignalStrength signalStrength;
- };
-
-} // namespace bluetooth
A module-bluetooth/Bluetooth/command/event/Events.hpp => module-bluetooth/Bluetooth/command/event/Events.hpp +231 -0
@@ 0,0 1,231 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "Device.hpp"
+#include "EventStore.hpp"
+#include "module-utils/phonenumber/PhoneNumber.hpp"
+#include "AbstractController.hpp"
+#include "log/log.hpp"
+
+namespace bt::evt
+{
+ struct Base
+ {
+ virtual void dispatch(bluetooth::AbstractController *controler) const = 0;
+ virtual ~Base() = default;
+
+ protected:
+ Base() = default;
+ };
+
+ struct StartScan : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+
+ struct StopScan : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct GetDevicesAvailable : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct VisibilityOn : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct VisibilityOff : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct ConnectAudio : public Base
+ {
+ explicit ConnectAudio(const Devicei &dev) : device(dev)
+ {}
+ const Devicei device;
+
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct DisconnectAudio : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct PowerOn : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct PowerOff : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct ShutDown : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct Pair : public Base
+ {
+ Pair(const Devicei &device) : device(device)
+ {}
+ const Devicei device;
+
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct Unpair : public Base
+ {
+ explicit Unpair(const Devicei &device) : device(device)
+ {}
+ const Devicei device;
+
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+
+ struct StartRinging : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct StopRinging : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct StartRouting : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct StartStream : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct StopStream : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct CallAnswered : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct CallTerminated : public Base
+ {
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct CallStarted : public Base
+ {
+ explicit CallStarted(const utils::PhoneNumber &number) : number(number)
+ {}
+ const utils::PhoneNumber number;
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct IncomingCallNumber : public Base
+ {
+ explicit IncomingCallNumber(utils::PhoneNumber::View &number) : number(number)
+ {}
+ const utils::PhoneNumber::View number;
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct SignalStrengthData : public Base
+ {
+ explicit SignalStrengthData(const Store::SignalStrength &strength) : strength(strength)
+ {}
+ Store::SignalStrength strength;
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct OperatorNameData : public Base
+ {
+ explicit OperatorNameData(const std::string &name) : name(name)
+ {}
+ const std::string name;
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct BatteryLevelData : public Base
+ {
+ explicit BatteryLevelData(unsigned int level) : level(level)
+ {}
+ const unsigned int level;
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+ struct NetworkStatusData : public Base
+ {
+ explicit NetworkStatusData(Store::Network::Status status) : status(status)
+ {}
+ const Store::Network::Status status;
+
+ void dispatch(bluetooth::AbstractController *controler) const override
+ {
+ controler->handle(*this);
+ }
+ };
+} // namespace bt::evt
A module-bluetooth/Bluetooth/doc/README.md => module-bluetooth/Bluetooth/doc/README.md +35 -0
@@ 0,0 1,35 @@
+How to add new command handling in bluetooth
+============================================
+
+**remember**
+Blutetooth Worker command handling uses [double dispatch](https://www.wikiwand.com/en/Double_dispatch) (if you are not familiar with the technique, see: [double dispatch example](https://dzone.com/articles/double-dispatch-in-c))
+
+# To add a new event:
+
+1. In `event/Events.hpp`
+ - Add new event
+ - remember to
+ - inherit from base event
+ - add override on `dispatch` function
+ - Events may have const data inside, in such case please:
+ - set const data in constructor
+ - set data as const in structure
+ - do not add needless getter/setter
+1. In `AbstractController.hpp`:
+ - Add new event to forward declaration
+ - Add new event handler in the class below
+2. In `WorkerController.{hpp,cpp}`
+ - Add new event handler to worker controller implementation
+ - Add event handling in the desired state
+ - When adding new Handler or Event in the sml state machine please:
+ - define structure per each event handler
+ - **this way we have it's name in the logs wich** is super helpful
+3. In `test` catalog
+ - add unit tests regarding the state added
+ - **please add tests for both: success and failure** scenarions, not only the green path
+
+# Bluetooth command handling state diagram
+
+# To generate state machine diagram
+
+`make bluetooth_uml` then `./bluetooth_uml > bluetooth_uml.puml` and generate diagram via plantuml from that
A module-bluetooth/Bluetooth/doc/uml/CMakeLists.txt => module-bluetooth/Bluetooth/doc/uml/CMakeLists.txt +8 -0
@@ 0,0 1,8 @@
+project(call_uml)
+add_executable(${PROJECT_NAME} uml_printer.cpp)
+target_link_libraries(${PROJECT_NAME} PRIVATE
+ module-bluetooth
+ log
+ sml::sml
+ sml::utils::logger
+)
A module-bluetooth/Bluetooth/doc/uml/uml_printer.cpp => module-bluetooth/Bluetooth/doc/uml/uml_printer.cpp +10 -0
@@ 0,0 1,10 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <BluetoothMachine.hpp>
+#include <sml-utils/PlantUML.hpp>
+
+int main()
+{
+ dump<bluetooth::SM>();
+}
M module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp => module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp +10 -9
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 17,14 17,15 @@ namespace bluetooth
virtual ~AbstractDriver() noexcept = default;
using ErrorCallback = std::function<void(uint8_t)>;
- [[nodiscard]] virtual auto init() -> Error::Code = 0;
- [[nodiscard]] virtual auto run() -> Error::Code = 0;
- [[nodiscard]] virtual auto stop() -> Error::Code = 0;
- [[nodiscard]] virtual auto scan() -> Error = 0;
- virtual void stopScan() = 0;
- virtual void setVisibility(bool visibility) = 0;
- [[nodiscard]] virtual auto pair(Devicei device, std::uint8_t protectionLevel = 0) -> bool = 0;
- [[nodiscard]] virtual auto unpair(Devicei device) -> bool = 0;
+ [[nodiscard]] virtual auto init() -> Error::Code = 0;
+ [[nodiscard]] virtual auto run() -> Error::Code = 0;
+ [[nodiscard]] virtual auto stop() -> Error::Code = 0;
+ [[nodiscard]] virtual auto scan() -> Error = 0;
+ // TODO make bool again
+ virtual void stopScan() = 0;
+ virtual void setVisibility(bool visibility) = 0;
+ virtual void pair(Devicei device, std::uint8_t protectionLevel = 0) = 0;
+ virtual void unpair(Devicei device) = 0;
virtual void registerErrorCallback(const ErrorCallback &newCallback) = 0;
virtual void registerPowerOnCallback(const PowerOnCallback &newCallback) = 0;
M module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.cpp => module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.cpp +7 -4
@@ 106,6 106,7 @@ namespace bluetooth
LOG_INFO("BTstack up and running");
bluetooth::KeyStorage::settings->setValue(bluetooth::Settings::State,
static_cast<int>(BluetoothStatus::State::On));
+ // TODO inform SM and process ON?
if (powerOnCallback) {
powerOnCallback();
}
@@ 218,13 219,15 @@ namespace bluetooth
{
gap->setVisibility(visibility);
}
- auto Driver::pair(Devicei device, std::uint8_t protectionLevel) -> bool
+ void Driver::pair(Devicei device, std::uint8_t protectionLevel)
{
LOG_INFO("Device: %s, addr: %s", device.name.data(), device.address_str());
- return gap->pair(device, protectionLevel);
+ gap->pair(device, protectionLevel);
}
- auto Driver::unpair(Devicei device) -> bool
+
+ void Driver::unpair(Devicei device)
{
- return gap->unpair(device);
+ gap->unpair(device);
}
+
} // namespace bluetooth
M module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.hpp => module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.hpp +3 -3
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 44,7 44,7 @@ namespace bluetooth
auto scan() -> Error override;
void stopScan() override;
void setVisibility(bool visibility) override;
- auto pair(Devicei device, std::uint8_t protectionLevel = 0) -> bool override;
- auto unpair(Devicei device) -> bool override;
+ void pair(Devicei device, std::uint8_t protectionLevel = 0) override;
+ void unpair(Devicei device) override;
};
} // namespace bluetooth
M module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp => module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp +4 -6
@@ 84,17 84,16 @@ namespace bluetooth
LOG_INFO("Visibility: %s", visibility ? "true" : "false");
}
- auto GAP::pair(Devicei device, std::uint8_t protectionLevel) -> bool
+ void GAP::pair(Devicei device, std::uint8_t protectionLevel)
{
if (hci_get_state() == HCI_STATE_WORKING) {
auto it = devices().find(device.address);
if (it == devices().end()) {
LOG_ERROR("device not found: %s", device.address_str());
- return false;
+ return;
}
- return gap_dedicated_bonding(device.address, protectionLevel) == 0;
+ gap_dedicated_bonding(device.address, protectionLevel);
}
- return false;
}
void GAP::sendDevices()
@@ 378,7 377,7 @@ namespace bluetooth
return devices().getList();
}
- auto GAP::unpair(Devicei device) -> bool
+ void GAP::unpair(Devicei device)
{
LOG_INFO("Unpairing device");
gap_drop_link_key_for_bd_addr(device.address);
@@ 386,7 385,6 @@ namespace bluetooth
LOG_INFO("Device unpaired");
ownerService->bus.sendMulticast(std::make_shared<message::bluetooth::UnpairResult>(device, true),
sys::BusChannel::BluetoothNotifications);
- return true;
}
void GAP::respondPinCode(const std::string &pin, Devicei d)
M module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp => module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp +2 -2
@@ 55,8 55,8 @@ namespace bluetooth
auto scan() -> Error;
void stopScan();
void setVisibility(bool visibility);
- auto pair(Devicei device, std::uint8_t protectionLevel = 0) -> bool;
- auto unpair(Devicei device) -> bool;
+ void pair(Devicei device, std::uint8_t protectionLevel = 0);
+ void unpair(Devicei device);
static auto getDevicesList() -> std::vector<Devicei>;
static void respondPinCode(const std::string &pin, Devicei d);
static void finishCodeComparison(bool accepted, Devicei d);
M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp +6 -8
@@ 105,11 105,10 @@ namespace bluetooth
{
return callProfilePtr->callActive();
}
- auto ProfileManager::setIncomingCallNumber(const DataVariant &data) -> Error::Code
+ auto ProfileManager::setIncomingCallNumber(const utils::PhoneNumber &nr) -> Error::Code
{
- auto number = std::get<utils::PhoneNumber::View>(data);
if (callProfilePtr) {
- return callProfilePtr->setIncomingCallNumber(number.getE164());
+ return callProfilePtr->setIncomingCallNumber(nr.getView().getE164());
}
LOG_ERROR("No profile, returning!");
return Error::NotReady;
@@ 132,9 131,9 @@ namespace bluetooth
LOG_ERROR("No profile, returning!");
return Error::NotReady;
}
- auto ProfileManager::setBatteryLevelData(const DataVariant &data) -> Error::Code
+ auto ProfileManager::setBatteryLevelData(unsigned int level) -> Error::Code
{
- auto batteryLevel = std::get<BatteryLevel>(data);
+ auto batteryLevel = BatteryLevel(level);
if (callProfilePtr) {
return callProfilePtr->setBatteryLevel(batteryLevel);
}
@@ 158,11 157,10 @@ namespace bluetooth
LOG_ERROR("No profile, returning!");
return Error::NotReady;
}
- auto ProfileManager::callStarted(const DataVariant &data) -> Error::Code
+ auto ProfileManager::callStarted(const utils::PhoneNumber &nr) -> Error::Code
{
if (callProfilePtr) {
- auto number = std::get<utils::PhoneNumber::View>(data);
- return callProfilePtr->callStarted(number.getE164());
+ return callProfilePtr->callStarted(nr.getView().getE164());
}
LOG_ERROR("No profile, returning!");
return Error::NotReady;
M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp +45 -20
@@ 26,30 26,55 @@ namespace bluetooth
using ProfileList = std::map<AudioProfile, std::shared_ptr<bluetooth::Profile>>;
- class ProfileManager
+ class BaseProfileManager
+ {
+ public:
+ virtual ~BaseProfileManager() = default;
+ virtual auto init() -> Error::Code = 0;
+ virtual void deInit() = 0;
+ virtual auto connect(const Devicei &device) -> Error::Code = 0;
+ virtual auto disconnect() -> Error::Code = 0;
+ virtual auto start() -> Error::Code = 0;
+ virtual auto stop() -> Error::Code = 0;
+ virtual auto startRinging() -> Error::Code = 0;
+ virtual auto stopRinging() -> Error::Code = 0;
+ virtual auto initializeCall() -> Error::Code = 0;
+ virtual auto terminateCall() -> Error::Code = 0;
+ virtual auto callAnswered() -> Error::Code = 0;
+ virtual auto callStarted(const utils::PhoneNumber &) -> Error::Code = 0;
+ virtual auto setIncomingCallNumber(const utils::PhoneNumber &nr) -> Error::Code = 0;
+ virtual auto setSignalStrengthData(const DataVariant &data) -> Error::Code = 0;
+ virtual auto setOperatorNameData(const DataVariant &data) -> Error::Code = 0;
+ virtual auto setBatteryLevelData(unsigned int) -> Error::Code = 0;
+ virtual auto setNetworkStatusData(const DataVariant &data) -> Error::Code = 0;
+ virtual auto setAudioDevice(std::shared_ptr<BluetoothAudioDevice> device) -> Error::Code = 0;
+ };
+
+ class ProfileManager : public BaseProfileManager
{
public:
explicit ProfileManager(sys::Service *ownerService);
+ ProfileManager() = delete;
+
+ auto init() -> Error::Code override;
+ void deInit() override;
+ auto connect(const Devicei &device) -> Error::Code override;
+ auto disconnect() -> Error::Code override;
+ auto start() -> Error::Code override;
+ auto stop() -> Error::Code override;
+ auto startRinging() -> Error::Code override;
+ auto stopRinging() -> Error::Code override;
+ auto initializeCall() -> Error::Code override;
+ auto terminateCall() -> Error::Code override;
+ auto callAnswered() -> Error::Code override;
+ auto callStarted(const utils::PhoneNumber &) -> Error::Code override;
+ auto setIncomingCallNumber(const utils::PhoneNumber &nr) -> Error::Code override;
+ auto setSignalStrengthData(const DataVariant &data) -> Error::Code override;
+ auto setOperatorNameData(const DataVariant &data) -> Error::Code override;
+ auto setBatteryLevelData(unsigned int) -> Error::Code override;
+ auto setNetworkStatusData(const DataVariant &data) -> Error::Code override;
- auto init() -> Error::Code;
- void deInit();
- auto connect(const Devicei &device) -> Error::Code;
- auto disconnect() -> Error::Code;
- auto start() -> Error::Code;
- auto stop() -> Error::Code;
- auto startRinging() -> Error::Code;
- auto stopRinging() -> Error::Code;
- auto initializeCall() -> Error::Code;
- auto terminateCall() -> Error::Code;
- auto callAnswered() -> Error::Code;
- auto callStarted(const DataVariant &data) -> Error::Code;
- auto setIncomingCallNumber(const DataVariant &data) -> Error::Code;
- auto setSignalStrengthData(const DataVariant &data) -> Error::Code;
- auto setOperatorNameData(const DataVariant &data) -> Error::Code;
- auto setBatteryLevelData(const DataVariant &data) -> Error::Code;
- auto setNetworkStatusData(const DataVariant &data) -> Error::Code;
-
- auto setAudioDevice(std::shared_ptr<BluetoothAudioDevice> device) -> Error::Code;
+ auto setAudioDevice(std::shared_ptr<BluetoothAudioDevice> device) -> Error::Code override;
private:
sys::Service *ownerService;
M module-bluetooth/CMakeLists.txt => module-bluetooth/CMakeLists.txt +1 -7
@@ 32,13 32,6 @@ set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/PhoneInterface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/Command.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/DeviceData.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/PhoneNumberData.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/SignalStrengthData.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/OperatorNameData.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/BatteryLevelData.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/NetworkStatusData.cpp
-
)
include(lib/btstack.cmake)
@@ 82,6 75,7 @@ target_link_libraries(${PROJECT_NAME}
service-bluetooth
service-evtmgr
sml::sml
+ sml::utils::logger
json::json
)
M module-bluetooth/tests/CMakeLists.txt => module-bluetooth/tests/CMakeLists.txt +1 -1
@@ 5,12 5,12 @@ add_catch2_executable(
tests-StatefulController.cpp
tests-BluetoothDevicesModel.cpp
tests-Devicei.cpp
- tests-command.cpp
tests-BTKeysStorage.cpp
LIBS
module-sys
module-bluetooth
service-bluetooth
+ test::fakeit
)
M module-bluetooth/tests/tests-StatefulController.cpp => module-bluetooth/tests/tests-StatefulController.cpp +230 -157
@@ 2,188 2,261 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <catch2/catch.hpp>
-
-#include "WorkerController.hpp"
+#include <catch/fakeit.hpp>
+#include "service-bluetooth/SettingsHolder.hpp"
+#include "BluetoothStateMachine.hpp"
using namespace bluetooth;
-class DriverMock : public AbstractDriver
+auto driver()
{
- public:
- Error::Code init() override
- {
- return initReturnCode;
- }
- Error::Code run() override
- {
- return runReturnCode;
- }
- Error::Code stop() override
- {
- return stopReturnCode;
- }
- Error scan() override
- {
- return Error::Success;
- }
- void stopScan() override
- {}
- void setVisibility(bool visibility) override
- {}
- bool pair(Devicei device, std::uint8_t protectionLevel = 0) override
- {
- return true;
- }
- bool unpair(Devicei device) override
- {
- return true;
- }
- void registerErrorCallback(const ErrorCallback &) override
- {}
- void registerPowerOnCallback(const PowerOnCallback &) override
- {}
-
- Error::Code initReturnCode = Error::Success;
- Error::Code runReturnCode = Error::Success;
- Error::Code stopReturnCode = Error::Success;
+ fakeit::Mock<AbstractDriver> mock;
+ fakeit::When(Method(mock, init)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, init)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, run)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, stop)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, scan)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, stopScan)).AlwaysReturn();
+ fakeit::When(Method(mock, setVisibility)).AlwaysReturn();
+ fakeit::When(Method(mock, pair)).AlwaysReturn();
+ fakeit::When(Method(mock, unpair)).AlwaysReturn();
+ fakeit::When(Method(mock, registerErrorCallback)).AlwaysReturn();
+ fakeit::When(Method(mock, registerPowerOnCallback)).AlwaysReturn();
+ return mock;
};
auto InitializerMock = []() { return Error::Success; };
-class HandlerMock : public AbstractCommandHandler
+auto handler()
{
- public:
- Error::Code handle(Command &command) override
- {
- return returnCode;
- }
-
- Error::Code returnCode = Error::Success;
+ fakeit::Mock<AbstractCommandHandler> mock;
+ fakeit::When(Method(mock, scan)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, stopScan)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, setVisibility)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, establishAudioConnection)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, disconnectAudioConnection)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, pair)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, unpair)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, availableDevices)).AlwaysReturn(Error::Code::Success);
+ return mock;
};
-TEST_CASE("Given StatefulController when turn on then turned on")
+template <typename T> auto mock_to_shared(T *val)
{
- auto driver = std::make_unique<DriverMock>();
- auto processor = std::make_unique<HandlerMock>();
- StatefulController controller{std::move(driver), std::move(processor), InitializerMock};
- controller.turnOn();
- REQUIRE(controller.isOn());
+ auto t = std::shared_ptr<T>(val, [](...) {});
+ return t;
}
-TEST_CASE("Given StatefulController when error during device registration then turned off")
+/// TODO nei wiem czemu to nie działą (double free)
+template <typename T> class Mock
{
- auto driver = std::make_unique<DriverMock>();
- auto processor = std::make_unique<HandlerMock>();
- StatefulController controller{std::move(driver), std::move(processor), []() { return Error::SystemError; }};
- controller.turnOn();
- REQUIRE(!controller.isOn());
-}
+ T t;
+ std::shared_ptr<std::remove_reference_t<decltype(t.get())>> shared_;
-TEST_CASE("Given StatefulController when error during driver init then turned off")
-{
- auto driver = std::make_unique<DriverMock>();
- driver->initReturnCode = Error::SystemError;
+ public:
+ explicit Mock(T t) : t(t)
+ {}
- auto processor = std::make_unique<HandlerMock>();
- StatefulController controller{std::move(driver), std::move(processor), InitializerMock};
- controller.turnOn();
- REQUIRE(!controller.isOn());
-}
+ auto shared()
+ {
+ return shared_;
+ }
+};
-TEST_CASE("Given StatefulController when error during driver run then turned off")
+namespace mock
{
- auto driver = std::make_unique<DriverMock>();
- driver->runReturnCode = Error::SystemError;
-
- auto processor = std::make_unique<HandlerMock>();
- StatefulController controller{std::move(driver), std::move(processor), InitializerMock};
- controller.turnOn();
- REQUIRE(!controller.isOn());
-}
+ auto settings()
+ {
+ fakeit::Mock<bluetooth::SettingsHolder> mock;
+ fakeit::When(Method(mock, getValue)).AlwaysReturn({});
+ fakeit::When(Method(mock, setValue)).AlwaysReturn();
+ return mock;
+ }
-TEST_CASE("Given StatefulController when restart then don't init twice")
-{
- auto driver = std::make_shared<DriverMock>();
- auto processor = std::make_unique<HandlerMock>();
- 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());
-}
+ auto devices()
+ {
+ return std::make_shared<std::vector<Devicei>>();
+ }
-TEST_CASE("Given StatefulController when turn off in off state then turned off")
-{
- auto driver = std::make_unique<DriverMock>();
- auto processor = std::make_unique<HandlerMock>();
- StatefulController controller{std::move(driver), std::move(processor), InitializerMock};
- controller.turnOff();
- REQUIRE(!controller.isOn());
-}
+ auto profile()
+ {
+ fakeit::Mock<bluetooth::BaseProfileManager> mock;
+ fakeit::When(Method(mock, init)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, deInit)).AlwaysReturn();
+ fakeit::When(Method(mock, connect)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, disconnect)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, start)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, stop)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, startRinging)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, stopRinging)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, initializeCall)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, terminateCall)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, callAnswered)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, callStarted)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, setIncomingCallNumber)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, setSignalStrengthData)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, setOperatorNameData)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, setBatteryLevelData)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, setNetworkStatusData)).AlwaysReturn(Error::Code::Success);
+ fakeit::When(Method(mock, setAudioDevice)).AlwaysReturn(Error::Code::Success);
+ return mock;
+ };
-TEST_CASE("Given StatefulController when turn off in on state then turned off")
-{
- auto driver = std::make_unique<DriverMock>();
- auto processor = std::make_unique<HandlerMock>();
- StatefulController controller{std::move(driver), std::move(processor), InitializerMock};
- controller.turnOn();
- REQUIRE(controller.isOn());
-
- controller.turnOff();
- REQUIRE(!controller.isOn());
-}
+} // namespace mock
-TEST_CASE("Given StatefulController when shutdown in off state then terminated")
+TEST_CASE("Given StatefulController when turn on then turned on")
{
- auto driver = std::make_unique<DriverMock>();
- auto processor = std::make_unique<HandlerMock>();
- StatefulController controller{std::move(driver), std::move(processor), InitializerMock};
- controller.shutdown();
- REQUIRE(controller.isTerminated());
-}
+ auto d = driver();
+ auto drive = mock_to_shared(&d.get());
+ auto h = handler();
+ auto processor = mock_to_shared(&h.get());
+ auto s = mock::settings();
+ auto sett = mock_to_shared(&s.get());
+ auto devs = mock::devices();
+ auto p = mock::profile();
+ auto profile = mock_to_shared(&p.get());
+ // auto profile = Mock(mock::profile());
-TEST_CASE("Given StatefulController when shutdown in on state then terminated")
-{
- auto driver = std::make_unique<DriverMock>();
- auto processor = std::make_unique<HandlerMock>();
- StatefulController controller{std::move(driver), std::move(processor), InitializerMock};
- controller.turnOn();
- REQUIRE(controller.isOn());
-
- controller.shutdown();
- REQUIRE(controller.isTerminated());
-}
+ StatefulController::Impl controller(drive, processor, InitializerMock, sett, devs, profile);
-TEST_CASE("Given StatefulController when process command successfully then turned on")
-{
- auto driver = std::make_unique<DriverMock>();
- auto processor = std::make_unique<HandlerMock>();
- StatefulController controller{std::move(driver), std::move(processor), InitializerMock};
- controller.turnOn();
- REQUIRE(controller.isOn());
-
- auto command = bluetooth::Command(Command::Type::PowerOn);
- controller.processCommand(command);
- REQUIRE(controller.isOn());
+ controller.sm.process_event(bt::evt::PowerOn{});
+ controller.sm.process_event(bt::evt::PowerOff{});
+ // TODO assert driver initialized
+ // TODO test for some loaded devices with some other mockup
+ // TODO move machine to Impl and assert for next states
+ // using namespace boost::sml; REQUIRE(controller->impl.is("Shutdown"_s));
}
-TEST_CASE("Given StatefulController when processing command failed then restarted and turned on")
-{
- auto driver = std::make_unique<DriverMock>();
- auto processor = std::make_unique<HandlerMock>();
- processor->returnCode = Error::SystemError;
- StatefulController controller{std::move(driver), std::move(processor), InitializerMock};
- controller.turnOn();
- REQUIRE(controller.isOn());
-
- auto command = bluetooth::Command(Command::Type::PowerOn);
- controller.processCommand(command);
- controller.processCommand(command);
-
- REQUIRE(controller.isOn());
-}
+// TEST_CASE("pair")
+// {
+// auto d = driver();
+// auto drive = mock_to_shared(&d.get());
+// auto h = handler();
+// auto processor = mock_to_shared(&h.get());
+// auto s = mock::settings();
+// auto sett = mock_to_shared(&s.get());
+// auto devs = mock::devices();
+// auto profile = Mock(mock::profile());
+//
+// StatefulController controller(drive, processor, InitializerMock, sett, devs, profile.shared());
+// controller.handle(bt::evt::PowerOn{});
+// controller.handle(bt::evt::Pair{Devicei{"lol"}});
+// // TODO test - no pair device in settings
+// }
+//
+// TEST_CASE("unpair")
+// {
+// auto d = driver();
+// auto drive = mock_to_shared(&d.get());
+// auto h = handler();
+// auto processor = mock_to_shared(&h.get());
+// auto s = mock::settings();
+// auto sett = mock_to_shared(&s.get());
+// auto devs = mock::devices();
+// auto profile = Mock(mock::profile());
+// StatefulController controller(drive, processor, InitializerMock, sett, devs, profile.shared());
+//
+// controller.handle(bt::evt::PowerOn{});
+// // TODO here nothing happens
+// controller.handle(bt::evt::Unpair{Devicei{"lol"}});
+// // TODO here - device added
+// controller.handle(bt::evt::Pair{Devicei{"lol"}});
+// // TODO here device removed
+// controller.handle(bt::evt::Pair{Devicei{"lol"}});
+// }
+//
+//
+//
+// // TEST_CASE("Given StatefulController when error during device registration then turned off")
+// // {
+// // auto h = handler();
+// // auto processor = mock_to_shared(&h);
+// //
+// // auto d = driver(); auto drive = mock_to_shared(&d);
+// // StatefulController controller{drive, processor, []() { return Error::SystemError; }};
+// // controller.handle(bt::evt::PowerOn{});
+// // }
+// //
+// // TEST_CASE("Given StatefulController when error during driver init then turned off")
+// // {
+// // driver->initReturnCode = Error::SystemError;
+// // auto h = handler(); auto processor = mock_to_shared(&h);
+// // auto d = driver(); auto drive = mock_to_shared(&d);
+// // StatefulController controller{drive, processor, InitializerMock};
+// // controller.handle(bt::evt::PowerOn{});
+// // }
+// //
+// // TEST_CASE("Given StatefulController when error during driver run then turned off")
+// // {
+// // driver->runReturnCode = Error::SystemError;
+// // auto h = handler(); auto processor = mock_to_shared(&h);
+// // auto d = driver(); auto drive = mock_to_shared(&d);
+// // StatefulController controller{drive, processor, InitializerMock};
+// // controller.handle(bt::evt::PowerOn{});
+// // }
+// //
+// // TEST_CASE("Given StatefulController when restart then don't init twice")
+// // {
+// // auto h = handler(); auto processor = mock_to_shared(&h);
+// // auto d = driver(); auto drive = mock_to_shared(&d);
+// // StatefulController controller{driver, processor, InitializerMock};
+// //
+// // controller.handle(bt::evt::PowerOn{});
+// // controller.handle(bt::evt::PowerOff{});
+// // driver->initReturnCode = Error::SystemError;
+// // controller.handle(bt::evt::PowerOn{});
+// // }
+// //
+// // TEST_CASE("Given StatefulController when turn off in off state then turned off")
+// // {
+// // auto h = handler(); auto processor = mock_to_shared(&h);
+// // auto d = driver(); auto drive = mock_to_shared(&d);
+// // StatefulController controller{drive, processor, InitializerMock};
+// // controller.handle(bt::evt::PowerOff{});
+// // }
+// //
+// // TEST_CASE("Given StatefulController when turn off in on state then turned off")
+// // {
+// // auto h = handler(); auto processor = mock_to_shared(&h);
+// // auto d = driver(); auto drive = mock_to_shared(&d);
+// // StatefulController controller{drive, processor, InitializerMock};
+// // controller.handle(bt::evt::PowerOn{});
+// // controller.handle(bt::evt::PowerOff{});
+// // }
+// //
+// // TEST_CASE("Given StatefulController when shutdown in off state then terminated")
+// // {
+// // auto h = handler(); auto processor = mock_to_shared(&h);
+// // auto d = driver(); auto drive = mock_to_shared(&d);
+// // StatefulController controller{drive, processor, InitializerMock};
+// // controller.handle(bt::evt::PowerOff{});
+// // REQUIRE(controller.isTerminated());
+// // }
+// //
+// // TEST_CASE("Given StatefulController when shutdown in on state then terminated")
+// // {
+// // auto h = handler(); auto processor = mock_to_shared(&h);
+// // auto d = driver(); auto drive = mock_to_shared(&d);
+// // StatefulController controller{drive, processor, InitializerMock};
+// // controller.handle(bt::evt::PowerOn{});
+// // controller.handle(bt::evt::PowerOff{});
+// // REQUIRE(controller.isTerminated());
+// // }
+// //
+// // TEST_CASE("Given StatefulController when process command successfully then turned on")
+// // {
+// // auto h = handler(); auto processor = mock_to_shared(&h);
+// // auto d = driver(); auto drive = mock_to_shared(&d);
+// // StatefulController controller{drive, processor, InitializerMock};
+// // controller.handle(bt::evt::PowerOn{});
+// // }
+// //
+// // // TODO
+// // TEST_CASE("Given StatefulController when processing command failed then restarted and turned on")
+// // {
+// // auto h = handler(); auto processor = mock_to_shared(&h);
+// // auto d = driver(); auto drive = mock_to_shared(&d);
+// // StatefulController controller{drive, processor, InitializerMock};
+// //
+// // controller.handle(bt::evt::PowerOn{});
+// // }
M module-bluetooth/tests/tests-command.cpp => module-bluetooth/tests/tests-command.cpp +0 -1
@@ 4,7 4,6 @@
#include <catch2/catch.hpp>
#include "btstack_util.h"
#include <command/Command.hpp>
-#include <command/DeviceData.hpp>
#include <command/PhoneNumberData.hpp>
#include <command/BatteryLevelData.hpp>
M module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +50 -65
@@ 40,12 40,6 @@
#include <service-bluetooth/messages/Authenticate.hpp>
#include <GAP/GAP.hpp>
#include <service-cellular/CellularMessage.hpp>
-#include <command/PhoneNumberData.hpp>
-#include <command/DeviceData.hpp>
-#include <command/SignalStrengthData.hpp>
-#include <command/OperatorNameData.hpp>
-#include <command/BatteryLevelData.hpp>
-#include <command/NetworkStatusData.hpp>
#include <service-evtmgr/BatteryMessages.hpp>
namespace
@@ 145,8 139,8 @@ sys::ReturnCodes ServiceBluetooth::DeinitHandler()
void ServiceBluetooth::ProcessCloseReason(sys::CloseReason closeReason)
{
- sendWorkerCommand(bluetooth::Command::Type::DisconnectAudio);
- sendWorkerCommand(bluetooth::Command::Type::PowerOff);
+ sendWorkerCommand(new bt::evt::DisconnectAudio());
+ sendWorkerCommand(new bt::evt::PowerOff());
}
sys::MessagePointer ServiceBluetooth::DataReceivedHandler([[maybe_unused]] sys::DataMessage *msg,
@@ 161,16 155,6 @@ sys::ReturnCodes ServiceBluetooth::SwitchPowerModeHandler(const sys::ServicePowe
return sys::ReturnCodes::Success;
}
-void ServiceBluetooth::sendWorkerCommand(bluetooth::Command::Type commandType,
- std::unique_ptr<bluetooth::CommandData> data)
-{
- bluetooth::Command::CommandPack pack;
- pack.data = std::move(data);
- pack.commandType = commandType;
- xQueueSend(workerQueue, &pack, portMAX_DELAY);
- pack.data.release();
-}
-
auto ServiceBluetooth::handle(BluetoothAudioStartMessage *msg) -> std::shared_ptr<sys::Message>
{
worker->setAudioDevice(msg->getAudioDevice());
@@ 209,7 193,7 @@ auto ServiceBluetooth::handle(message::bluetooth::SetStatus *msg) -> std::shared
case BluetoothStatus::State::On:
cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyMHz::Level_3);
- sendWorkerCommand(bluetooth::Command::Type::PowerOn);
+ sendWorkerCommand(new bt::evt::PowerOn());
bus.sendMulticast(
std::make_shared<sys::bluetooth::BluetoothModeChanged>(sys::bluetooth::BluetoothMode::Enabled),
sys::BusChannel::BluetoothModeChanges);
@@ 228,8 212,12 @@ auto ServiceBluetooth::handle(message::bluetooth::SetStatus *msg) -> std::shared
default:
break;
}
- sendWorkerCommand(newBtStatus.visibility ? bluetooth::Command::Type::VisibilityOn
- : bluetooth::Command::Type::VisibilityOff);
+ if (newBtStatus.visibility) {
+ sendWorkerCommand(new bt::evt::VisibilityOn());
+ }
+ else {
+ sendWorkerCommand(new bt::evt::VisibilityOff());
+ }
return sys::MessageNone{};
}
@@ 237,9 225,8 @@ auto ServiceBluetooth::handle(BluetoothPairMessage *msg) -> std::shared_ptr<sys:
{
auto device = msg->getDevice();
bluetoothDevicesModel->removeDevice(device);
- auto commandData = std::make_unique<bluetooth::DeviceData>(device);
- sendWorkerCommand(bluetooth::Command::Type::Pair, std::move(commandData));
+ sendWorkerCommand(new bt::evt::Pair(device));
device.deviceState = DeviceState::Pairing;
bluetoothDevicesModel->insertDevice(device);
@@ 268,12 255,17 @@ auto ServiceBluetooth::handle(BluetoothPairResultMessage *msg) -> std::shared_pt
return sys::MessageNone{};
}
+void ServiceBluetooth::sendWorkerCommand(bt::evt::Base *command)
+{
+ if (workerQueue != nullptr) {
+ workerQueue->push(bluetooth::Command{command});
+ }
+}
+
auto ServiceBluetooth::handle(message::bluetooth::Unpair *msg) -> std::shared_ptr<sys::Message>
{
- auto commandData = std::make_unique<bluetooth::DeviceData>(msg->getDevice());
- sendWorkerCommand(bluetooth::Command::Type::Unpair, std::move(commandData));
+ sendWorkerCommand(new bt::evt::Unpair(msg->getDevice()));
bluetoothDevicesModel->removeDevice(msg->getDevice());
-
return sys::MessageNone{};
}
@@ 293,12 285,10 @@ auto ServiceBluetooth::handle(message::bluetooth::SetDeviceName *msg) -> std::sh
auto newName = msg->getName();
bluetooth::set_name(newName);
settingsHolder->setValue(bluetooth::Settings::DeviceName, newName);
- sendWorkerCommand(bluetooth::Command::Type::PowerOff);
+ sendWorkerCommand(new bt::evt::PowerOff());
- btRestartTimer =
- sys::TimerFactory::createSingleShotTimer(this, "btRestartTimer", btRestartDelay, [this](sys::Timer &_) {
- sendWorkerCommand(bluetooth::Command::Type::PowerOn);
- });
+ btRestartTimer = sys::TimerFactory::createSingleShotTimer(
+ this, "btRestartTimer", btRestartDelay, [this](sys::Timer &_) { sendWorkerCommand(new bt::evt::PowerOn()); });
btRestartTimer.start();
return sys::MessageNone{};
@@ 307,9 297,7 @@ auto ServiceBluetooth::handle(message::bluetooth::SetDeviceName *msg) -> std::sh
auto ServiceBluetooth::handle(message::bluetooth::Connect *msg) -> std::shared_ptr<sys::Message>
{
auto device = msg->getDevice();
- auto commandData = std::make_unique<bluetooth::DeviceData>(msg->getDevice());
- sendWorkerCommand(bluetooth::Command::Type::ConnectAudio, std::move(commandData));
-
+ sendWorkerCommand(new bt::evt::ConnectAudio(device));
bluetoothDevicesModel->setInternalDeviceState(device, DeviceState::Connecting);
bluetoothDevicesModel->syncDevicesWithApp();
return sys::MessageNone{};
@@ 359,7 347,7 @@ auto ServiceBluetooth::handle(message::bluetooth::ConnectResult *msg) -> std::sh
auto ServiceBluetooth::handle([[maybe_unused]] message::bluetooth::Disconnect *msg) -> std::shared_ptr<sys::Message>
{
- sendWorkerCommand(bluetooth::Command::Type::DisconnectAudio);
+ sendWorkerCommand(new bt::evt::DisconnectAudio());
return sys::MessageNone{};
}
@@ 417,31 405,33 @@ auto ServiceBluetooth::handle(BluetoothMessage *msg) -> std::shared_ptr<sys::Mes
resetTimeoutTimer();
switch (msg->req) {
- case BluetoothMessage::Start:
- break;
case BluetoothMessage::Scan:
- sendWorkerCommand(bluetooth::Command::Type::StartScan);
+ sendWorkerCommand(new bt::evt::StartScan());
break;
case BluetoothMessage::StopScan:
- sendWorkerCommand(bluetooth::Command::Type::StopScan);
+ sendWorkerCommand(new bt::evt::StopScan());
break;
case BluetoothMessage::getDevicesAvailable:
- sendWorkerCommand(bluetooth::Command::Type::getDevicesAvailable);
+ sendWorkerCommand(new bt::evt::GetDevicesAvailable());
break;
case BluetoothMessage::Visible: {
auto visibility =
not std::visit(bluetooth::BoolVisitor(), settingsHolder->getValue(bluetooth::Settings::Visibility));
- sendWorkerCommand(visibility ? bluetooth::Command::Type::VisibilityOn
- : bluetooth::Command::Type::VisibilityOff);
+ if (visibility) {
+ sendWorkerCommand(new bt::evt::VisibilityOn());
+ }
+ else {
+ sendWorkerCommand(new bt::evt::VisibilityOff());
+ }
} break;
case BluetoothMessage::Play:
- sendWorkerCommand(bluetooth::Command::Type::StartStream);
+ sendWorkerCommand(new bt::evt::StartStream());
break;
case BluetoothMessage::Disconnect:
- sendWorkerCommand(bluetooth::Command::Type::DisconnectAudio);
+ sendWorkerCommand(new bt::evt::DisconnectAudio());
break;
case BluetoothMessage::Stop:
- sendWorkerCommand(bluetooth::Command::Type::StopStream);
+ sendWorkerCommand(new bt::evt::StopStream());
break;
default:
break;
@@ 452,15 442,14 @@ auto ServiceBluetooth::handle(BluetoothMessage *msg) -> std::shared_ptr<sys::Mes
auto ServiceBluetooth::handle(BluetoothAddrMessage *msg) -> std::shared_ptr<sys::Message>
{
- auto commandData = std::make_unique<bluetooth::DeviceData>(msg->device);
- sendWorkerCommand(bluetooth::Command::Type::ConnectAudio, std::move(commandData));
+ sendWorkerCommand(new bt::evt::ConnectAudio(msg->device));
return std::make_shared<sys::ResponseMessage>();
}
auto ServiceBluetooth::handle(sdesktop::developerMode::DeveloperModeRequest *msg) -> std::shared_ptr<sys::Message>
{
if (typeid(*msg->event) == typeid(sdesktop::bluetooth::GetAvailableDevicesEvent)) {
- sendWorkerCommand(bluetooth::Command::Type::getDevicesAvailable);
+ sendWorkerCommand(new bt::evt::GetDevicesAvailable());
}
return sys::MessageNone{};
}
@@ 487,7 476,7 @@ auto ServiceBluetooth::handle(message::bluetooth::HFPVolume *msg) -> std::shared
auto ServiceBluetooth::handle(message::bluetooth::StartAudioRouting *msg) -> std::shared_ptr<sys::Message>
{
- sendWorkerCommand(bluetooth::Command::Type::StartRouting);
+ sendWorkerCommand(new bt::evt::StartRouting());
return std::make_shared<sys::ResponseMessage>();
}
@@ 499,8 488,7 @@ auto ServiceBluetooth::handle(CellularCallerIdMessage *msg) -> std::shared_ptr<s
if (btOn) {
LOG_DEBUG("Sending to profile!");
- auto commandData = std::make_unique<bluetooth::PhoneNumberData>(number);
- sendWorkerCommand(bluetooth::Command::Type::IncomingCallNumber, std::move(commandData));
+ sendWorkerCommand(new bt::evt::IncomingCallNumber(number));
}
return sys::MessageNone{};
@@ 508,7 496,7 @@ auto ServiceBluetooth::handle(CellularCallerIdMessage *msg) -> std::shared_ptr<s
auto ServiceBluetooth::handle(CellularCallActiveNotification *msg) -> std::shared_ptr<sys::Message>
{
- sendWorkerCommand(bluetooth::Command::Type::CallAnswered);
+ sendWorkerCommand(new bt::evt::CallAnswered());
return std::make_shared<sys::ResponseMessage>();
}
@@ 516,8 504,7 @@ auto ServiceBluetooth::handle(CellularSignalStrengthUpdateNotification *msg) ->
{
auto signalStrength = Store::GSM::get()->getSignalStrength();
LOG_DEBUG("Bluetooth: RSSI %d/5", static_cast<int>(signalStrength.rssiBar));
- auto commandData = std::make_unique<bluetooth::SignalStrengthData>(signalStrength);
- sendWorkerCommand(bluetooth::Command::Type::SignalStrengthData, std::move(commandData));
+ sendWorkerCommand(new bt::evt::SignalStrengthData(signalStrength));
return std::make_shared<sys::ResponseMessage>();
}
@@ 525,8 512,7 @@ auto ServiceBluetooth::handle(CellularCurrentOperatorNameNotification *msg) -> s
{
auto opName = msg->getCurrentOperatorName();
LOG_DEBUG("Bluetooth: Operator name: %s", opName.c_str());
- auto commandData = std::make_unique<bluetooth::OperatorNameData>(bluetooth::OperatorName(opName));
- sendWorkerCommand(bluetooth::Command::Type::OperatorNameData, std::move(commandData));
+ sendWorkerCommand(new bt::evt::OperatorNameData(opName));
return std::make_shared<sys::ResponseMessage>();
}
@@ 554,7 540,8 @@ void ServiceBluetooth::resetTimeoutTimer()
void ServiceBluetooth::handleTurnOff()
{
- sendWorkerCommand(bluetooth::Command::Type::PowerOff);
+ sendWorkerCommand(new bt::evt::PowerOff());
+ // NOTE: This should be in bluetooth state machine
cpuSentinel->ReleaseMinimumFrequency();
bus.sendMulticast(std::make_shared<sys::bluetooth::BluetoothModeChanged>(sys::bluetooth::BluetoothMode::Disabled),
sys::BusChannel::BluetoothModeChanges);
@@ 574,33 561,31 @@ auto ServiceBluetooth::handle(sevm::BatteryStatusChangeMessage *msg) -> std::sha
{
auto batteryLevel = Store::Battery::get().level;
LOG_DEBUG("Bluetooth: Battery level %d", batteryLevel);
- auto commandData = std::make_unique<bluetooth::BatteryLevelData>(bluetooth::BatteryLevel(batteryLevel));
- sendWorkerCommand(bluetooth::Command::Type::BatteryLevelData, std::move(commandData));
+ sendWorkerCommand(new bt::evt::BatteryLevelData(batteryLevel));
return sys::MessageNone{};
}
auto ServiceBluetooth::handle(cellular::CallEndedNotification *msg) -> std::shared_ptr<sys::Message>
{
- sendWorkerCommand(bluetooth::Command::Type::CallTerminated);
+ sendWorkerCommand(new bt::evt::CallTerminated());
return sys::MessageNone{};
}
auto ServiceBluetooth::handle(CellularNetworkStatusUpdateNotification *msg) -> std::shared_ptr<sys::Message>
{
auto status = Store::GSM::get()->getNetwork().status;
LOG_DEBUG("Bluetooth: Network status %s", magic_enum::enum_name(status).data());
- auto commandData = std::make_unique<bluetooth::NetworkStatusData>(status);
- sendWorkerCommand(bluetooth::Command::Type::NetworkStatusData, std::move(commandData));
+ sendWorkerCommand(new bt::evt::NetworkStatusData(status));
return sys::MessageNone{};
}
auto ServiceBluetooth::handle(cellular::CallStartedNotification *msg) -> std::shared_ptr<sys::Message>
{
if (!msg->isCallIncoming()) {
- auto commandData = std::make_unique<bluetooth::PhoneNumberData>(msg->getNumber());
- sendWorkerCommand(bluetooth::Command::Type::CallStarted, std::move(commandData));
+ auto evt = new bt::evt::CallStarted(msg->getNumber());
+ sendWorkerCommand(std::move(evt));
}
return sys::MessageNone{};
}
auto ServiceBluetooth::handle(CellularIncominCallMessage *msg) -> std::shared_ptr<sys::Message>
{
- sendWorkerCommand(bluetooth::Command::Type::StartRinging);
+ sendWorkerCommand(new bt::evt::StartRinging());
return sys::MessageNone{};
}
M module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp => module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp +0 -1
@@ 29,7 29,6 @@ class BluetoothMessage : public sys::DataMessage
enum Request
{
None,
- Start,
Scan,
StopScan,
getDevicesAvailable,
M module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp => module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp +9 -4
@@ 7,7 7,9 @@
#include <system/Common.hpp>
#include <Service/Message.hpp>
#include <Service/Service.hpp>
+#include "Service/Mailbox.hpp"
#include "service-bluetooth/SettingsHolder.hpp"
+#include "service-bluetooth/WorkerLock.hpp"
#include <service-db/DBServiceName.hpp>
#include <service-audio/ServiceAudio.hpp>
#include <module-bluetooth/Bluetooth/CommandHandler.hpp>
@@ 87,12 89,14 @@ class ServiceBluetooth : public sys::Service
sys::ReturnCodes DeinitHandler() override;
void ProcessCloseReason(sys::CloseReason closeReason) override;
virtual sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override;
- void sendWorkerCommand(bluetooth::Command::Type commandType,
- std::unique_ptr<bluetooth::CommandData> data = nullptr);
+
+ void sendWorkerCommand(bt::evt::Base *command);
+
void handleTurnOff();
- QueueHandle_t workerQueue = nullptr;
+
+ std::shared_ptr<Mailbox<bluetooth::Command, QueueHandle_t, WorkerLock>> workerQueue;
std::shared_ptr<bluetooth::SettingsHolder> settingsHolder;
- bluetooth::ProfileManager *profileManagerPtr = nullptr;
+ bluetooth::BaseProfileManager *profileManagerPtr = nullptr;
private:
std::unique_ptr<BluetoothWorker> worker;
@@ 114,6 118,7 @@ class ServiceBluetooth : public sys::Service
[[nodiscard]] auto handle(message::bluetooth::SetStatus *msg) -> std::shared_ptr<sys::Message>;
[[nodiscard]] auto handle(BluetoothPairMessage *msg) -> std::shared_ptr<sys::Message>;
[[nodiscard]] auto handle(BluetoothPairResultMessage *msg) -> std::shared_ptr<sys::Message>;
+
[[nodiscard]] auto handle(message::bluetooth::Unpair *msg) -> std::shared_ptr<sys::Message>;
[[nodiscard]] auto handle(message::bluetooth::RequestDeviceName *msg) -> std::shared_ptr<sys::Message>;
[[nodiscard]] auto handle(message::bluetooth::SetDeviceName *msg) -> std::shared_ptr<sys::Message>;
A module-services/service-bluetooth/service-bluetooth/WorkerLock.hpp => module-services/service-bluetooth/service-bluetooth/WorkerLock.hpp +40 -0
@@ 0,0 1,40 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "log/log.hpp"
+#include <FreeRTOS.h>
+#include <queue.h>
+#include <mutex.hpp>
+
+class WorkerLock
+{
+ QueueHandle_t queue;
+ cpp_freertos::MutexStandard &mutex;
+
+ public:
+ WorkerLock(QueueHandle_t queue, cpp_freertos::MutexStandard &mutex) : queue(queue), mutex(mutex)
+ {}
+
+ bool wait()
+ {
+ mutex.Unlock();
+ auto ret = xQueueReceive(queue, nullptr, portMAX_DELAY) != pdTRUE;
+ mutex.Lock();
+ return ret;
+ }
+
+ bool wait(TickType_t ticks)
+ {
+ mutex.Unlock();
+ auto ret = xQueueReceive(queue, nullptr, ticks) != pdTRUE;
+ mutex.Lock();
+ return ret;
+ }
+
+ bool signal()
+ {
+ return xQueueSend(queue, nullptr, portMAX_DELAY);
+ }
+};
M module-sys/Service/include/Service/Mailbox.hpp => module-sys/Service/include/Service/Mailbox.hpp +46 -23
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 7,22 7,49 @@
#include "thread.hpp"
#include <mutex.hpp>
#include <condition_variable.hpp>
+#include <optional>
-template <typename T> class Mailbox
+class ServiceLock
{
+ cpp_freertos::Thread *thread;
+ cpp_freertos::MutexStandard &mutex_;
+ cpp_freertos::ConditionVariable cond_;
+
public:
- Mailbox(cpp_freertos::Thread *thread) : thread_(thread)
+ ServiceLock(cpp_freertos::Thread *thread, cpp_freertos::MutexStandard &mutex_) : thread(thread), mutex_(mutex_)
{}
- T peek()
+ bool wait()
{
+ return thread->Wait(cond_, mutex_);
+ }
+ bool wait(TickType_t ticks)
+ {
+ return thread->Wait(cond_, mutex_, ticks);
+ }
+ bool signal()
+ {
+ cond_.Signal();
+ return true;
+ }
+};
+
+template <typename T, typename Base = cpp_freertos::Thread *, typename Lock = ServiceLock> class Mailbox
+{
+ public:
+ Mailbox(Base thread) : thread_(thread)
+ {}
+
+ std::optional<T> peek()
+ {
cpp_freertos::LockGuard mlock(mutex_);
- while (queue_.empty()) {
- thread_->Wait(cond_, mutex_);
+ if (queue_.empty()) {
+ return {};
}
- auto item = queue_.front();
- return item;
+ auto el = queue_.front();
+ queue_.pop_front();
+ return {el};
}
T pop(uint32_t timeout = portMAX_DELAY)
@@ 30,7 57,7 @@ template <typename T> class Mailbox
cpp_freertos::LockGuard mlock(mutex_);
while (queue_.empty()) {
- if (thread_->Wait(cond_, mutex_, timeout) == false) {
+ if (lock.wait(timeout) == false) {
return nullptr;
}
}
@@ 39,16 66,6 @@ template <typename T> class Mailbox
return item;
}
- void pop(T &item)
- {
- cpp_freertos::LockGuard mlock(mutex_);
- while (queue_.empty()) {
- thread_->Wait(cond_, mutex_);
- }
- item = queue_.front();
- queue_.pop_front();
- }
-
void push_front(const T &item)
{
mutex_.Lock();
@@ 61,7 78,7 @@ template <typename T> class Mailbox
mutex_.Lock();
queue_.push_back(item);
mutex_.Unlock();
- cond_.Signal();
+ lock.signal();
}
void push(T &&item)
@@ 69,12 86,18 @@ template <typename T> class Mailbox
mutex_.Lock();
queue_.push_back(std::move(item));
mutex_.Unlock();
- cond_.Signal();
+ lock.signal();
+ }
+
+ bool empty()
+ {
+ return queue_.empty();
}
private:
- cpp_freertos::Thread *thread_;
+ Base thread_;
std::deque<T> queue_;
cpp_freertos::MutexStandard mutex_;
- cpp_freertos::ConditionVariable cond_;
+
+ Lock lock{thread_, mutex_};
};
M module-utils/log/Logger.cpp => module-utils/log/Logger.cpp +1 -1
@@ 33,7 33,7 @@ namespace Log
{"ServiceAntenna", logger_level::LOGERROR},
{"ServiceAudio", logger_level::LOGINFO},
{"ServiceBluetooth", logger_level::LOGINFO},
- {"ServiceBluetooth_w1", logger_level::LOGINFO},
+ {"ServiceBluetooth_w1", logger_level::LOGDEBUG},
{"ServiceFota", logger_level::LOGINFO},
{"ServiceEink", logger_level::LOGINFO},
{"ServiceDB", logger_level::LOGINFO},