Files
MuditaOS/module-bluetooth/Bluetooth/BluetoothWorker.cpp
T
SP2FET 1929a38252 [EGD-5848] Fix bluetooth pairing key import
After BT refactor settings init for key storage has been moved,
thus in the initial phase settings were unavailable and btstack
couldn't import keys from storage
2021-02-23 09:18:24 +01:00

260 lines
7.9 KiB
C++

// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <service-bluetooth/ServiceBluetooth.hpp>
#include "BluetoothWorker.hpp"
#include "BtCommand.hpp"
#include "log/log.hpp"
#include "interface/BluetoothDriverImpl.hpp"
#include "interface/profiles/A2DP/A2DP.hpp"
#include "interface/profiles/HSP/HSP.hpp"
#include "BtKeysStorage.hpp"
#if DEBUG_BLUETOOTH_HCI_COMS == 1
#define logHciComs(...) LOG_DEBUG(__VA_ARGS__)
#else
#define logHciComs(...)
#endif
#if DEBUG_BLUETOOTH_HCI_BYTES == 1
#include <sstream>
#define logHciBytes(...) LOG_DEBUG(__VA_ARGS__)
#else
#define logHciBytes(...)
#endif
using namespace bsp;
namespace queues
{
constexpr inline auto io = "qBtIO";
constexpr inline auto cmd = "qBtCmds";
constexpr inline auto btstack = "qBtStack";
constexpr inline auto queueLength = 10;
constexpr inline auto triggerQueueLength = 3;
} // namespace queues
namespace
{
class DeviceRegistration
{
public:
using OnLinkKeyAddedCallback = std::function<void(const std::string &)>;
DeviceRegistration(std::shared_ptr<bluetooth::SettingsHolder> settings, OnLinkKeyAddedCallback &&onLinkKeyAdded)
: settings{std::move(settings)}, onLinkKeyAdded{std::move(onLinkKeyAdded)}
{}
[[nodiscard]] auto operator()()
{
bluetooth::GAP::registerScan();
auto settingsName = std::get<std::string>(settings->getValue(bluetooth::Settings::DeviceName));
if (settingsName.empty()) {
LOG_WARN("Settings name is empty!");
constexpr auto name = "PurePhone";
settings->setValue(bluetooth::Settings::DeviceName, name);
settingsName = name;
}
bluetooth::set_name(settingsName);
settings->onLinkKeyAdded = onLinkKeyAdded;
return bluetooth::Error::Success;
}
private:
std::shared_ptr<bluetooth::SettingsHolder> settings;
OnLinkKeyAddedCallback onLinkKeyAdded;
};
auto createStatefulController(sys::Service *service,
bluetooth::RunLoop *loop,
std::shared_ptr<bluetooth::SettingsHolder> settings,
std::shared_ptr<bluetooth::Profile> currentProfile,
DeviceRegistration::OnLinkKeyAddedCallback &&onLinkKeyAddedCallback)
{
auto driver = std::make_shared<bluetooth::Driver>(loop->getRunLoopInstance(), service);
auto commandHandler =
std::make_unique<bluetooth::CommandHandler>(service, settings, std::move(currentProfile), driver);
return std::make_unique<bluetooth::StatefulController>(
std::move(driver),
std::move(commandHandler),
DeviceRegistration{std::move(settings), std::move(onLinkKeyAddedCallback)});
}
} // namespace
BluetoothWorker::BluetoothWorker(sys::Service *service)
: Worker(service), service(service), currentProfile(std::make_shared<bluetooth::HSP>()),
settings(static_cast<ServiceBluetooth *>(service)->settingsHolder),
runLoop(std::make_unique<bluetooth::RunLoop>()),
controller{createStatefulController(
service, runLoop.get(), settings, currentProfile, [this](const std::string &addr) { onLinkKeyAdded(addr); })}
{
init({
{queues::io, sizeof(bluetooth::Message), queues::queueLength},
{queues::cmd, sizeof(bluetooth::Command), queues::queueLength},
{queues::btstack, sizeof(bool), queues::triggerQueueLength},
});
registerQueues();
}
void BluetoothWorker::registerQueues()
{
static_cast<ServiceBluetooth *>(service)->workerQueue = Worker::getQueueHandleByName(queues::cmd);
runLoop->setTriggerQueue(Worker::getQueueHandleByName(queues::btstack));
BlueKitchen::getInstance()->qHandle = queues[queueIO_handle]->GetQueueHandle();
}
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));
}
}
}
BluetoothWorker::~BluetoothWorker()
{
controller->shutdown();
}
auto BluetoothWorker::run() -> bool
{
LOG_INFO("-> BluetoothWorker run request");
if (isRunning) {
return true;
}
if (const auto status = Worker::run(); !status) {
return false;
}
isRunning = true;
return true;
}
auto BluetoothWorker::handleCommand(QueueHandle_t queue) -> bool
{
bluetooth::Command command(bluetooth::Command::Type::None);
if (xQueueReceive(queue, static_cast<void *>(&command), 0) != pdTRUE) {
LOG_ERROR("Queue receive failure!");
return false;
}
switch (command.getType()) {
case bluetooth::Command::PowerOn:
controller->turnOn();
break;
case bluetooth::Command::PowerOff:
controller->turnOff();
break;
default:
controller->processCommand(command);
break;
}
return true;
}
auto BluetoothWorker::handleBtStackTrigger(QueueHandle_t queue) -> bool
{
bool notification;
if (xQueueReceive(queue, &notification, 0) != pdTRUE) {
LOG_ERROR("Queue receive failure!");
return false;
}
if (notification) {
runLoop->process();
return true;
}
return false;
}
auto BluetoothWorker::handleMessage(uint32_t queueID) -> bool
{
QueueHandle_t queue = queues[queueID]->GetQueueHandle();
if (queueID == queueService) {
LOG_DEBUG("not interested");
return true;
}
if (queueID == queueCommands) {
handleCommand(queue);
return true;
}
if (queueID == queueRunloopTrigger) {
handleBtStackTrigger(queue);
return true;
}
if (queueID != queueIO_handle) {
LOG_ERROR("Wrong queue! %" PRIu32, queueID);
return false;
}
auto notification = bluetooth::Message::EvtErrorRec;
if (xQueueReceive(queue, &notification, 0) != pdTRUE) {
LOG_ERROR("Queue receive failure!");
return false;
}
auto bt = BlueKitchen::getInstance();
switch (notification) {
case bluetooth::Message::EvtSending:
logHciComs("[evt] sending");
break;
case bluetooth::Message::EvtSent:
logHciComs("[evt] sent");
if (bt->write_done_cb) {
bt->write_done_cb();
}
break;
case bluetooth::Message::EvtReceiving:
logHciComs("[evt] receiving");
break;
case bluetooth::Message::EvtReceived: {
logHciBytes("[evt] BT DMA received <-- [%ld]>%s<",
bt->read_len,
[&]() -> std::string {
std::stringstream ss;
for (int i = 0; i < bt->read_len; ++i) {
ss << " 0x" << std::hex << (int)*(bt->read_buff + i);
}
return ss.str();
}()
.c_str());
bt->read_len = 0;
if (bt->read_ready_cb) {
bt->read_ready_cb();
}
} break;
case bluetooth::Message::EvtSendingError:
[[fallthrough]];
case bluetooth::Message::EvtReceivingError:
[[fallthrough]];
case bluetooth::Message::EvtUartError:
[[fallthrough]];
case bluetooth::Message::EvtRecUnwanted:
LOG_ERROR("Uart error [%d]: %s", notification, bluetooth::MessageCstr(notification));
break;
default:
LOG_ERROR("ERROR");
}
return true;
}
void BluetoothWorker::setDeviceAddress(bd_addr_t addr)
{
currentProfile->setDeviceAddress(addr);
}
auto BluetoothWorker::deinit() -> bool
{
controller->turnOff();
return Worker::deinit();
}