~aleteoryx/muditaos

6befeb5073f3ea8e2c99a9a5f1bf26d34b86715d — SP2FET 5 years ago 9ff0894
[EGD-5316] Add Bluetooth run loop integration into worker

To be able to handle properly the Bluetooth stack we need to
get rid of doubled FreeRTOS task and do refactor of
the whole BT section. This is first part of refactor and it
includes integrating run loop into our worker and unifying
namespaces
32 files changed, 604 insertions(+), 358 deletions(-)

M module-bluetooth/Bluetooth/BluetoothWorker.cpp
M module-bluetooth/Bluetooth/BluetoothWorker.hpp
M module-bluetooth/Bluetooth/BtCommand.hpp
M module-bluetooth/Bluetooth/BtKeysStorage.cpp
M module-bluetooth/Bluetooth/BtKeysStorage.hpp
M module-bluetooth/Bluetooth/Error.hpp
A module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.cpp
A module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.hpp
R module-bluetooth/Bluetooth/{BtstackWorker => interface/BluetoothDriver}.cpp
A module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DPImpl.hpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVDTP.cpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVDTP.hpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.cpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.hpp
M module-bluetooth/Bluetooth/interface/profiles/GAP.cpp
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSPImpl.hpp
M module-bluetooth/Bluetooth/interface/profiles/HSP/SCO.cpp
M module-bluetooth/Bluetooth/interface/profiles/HSP/SCO.hpp
M module-bluetooth/Bluetooth/interface/profiles/PAN.cpp
M module-bluetooth/Bluetooth/interface/profiles/Profile.hpp
M module-bluetooth/CMakeLists.txt
M module-bsp/board/rt1051/bluetooth/BlueKitchen.cpp
M module-bsp/board/rt1051/bluetooth/BluetoothCommon.cpp
M module-services/service-bluetooth/ServiceBluetooth.cpp
M module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp
M module-services/service-bluetooth/service-bluetooth/SettingsHolder.cpp
M module-services/service-bluetooth/service-bluetooth/SettingsHolder.hpp
M module-bluetooth/Bluetooth/BluetoothWorker.cpp => module-bluetooth/Bluetooth/BluetoothWorker.cpp +96 -79
@@ 1,18 1,13 @@
// Copyright (c) 2017-2020, 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/profiles/A2DP/A2DP.hpp"
#include "interface/profiles/HSP/HSP.hpp"
#include "BtKeysStorage.hpp"
extern "C"
{
#include "module-bluetooth/lib/btstack/src/btstack_util.h"
}
#include <btstack_run_loop_freertos.h>
#include <service-bluetooth/ServiceBluetooth.hpp>

#if DEBUG_BLUETOOTH_HCI_COMS == 1
#define logHciComs(...) LOG_DEBUG(__VA_ARGS__)


@@ 29,36 24,34 @@ extern "C"

using namespace bsp;

const char *c_str(Bt::Error::Code code)
[[nodiscard]] auto to_string(bluetooth::Error::Code code) -> std::string
{
    switch (code) {
    case Bt::Error::Code::Success:
        return "Success";
    case Bt::Error::Code::NotReady:
        return "NotReady";
    case Bt::Error::Code::SystemError:
        return "SystemError";
    case Bt::Error::Code::LibraryError:
        return "LibraryError";
    }
    return "";
    return utils::enumToString(code);
}
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

BluetoothWorker::BluetoothWorker(sys::Service *service)
    : Worker(service), service(service), currentProfile(std::make_shared<Bt::HSP>()),
      settings(static_cast<ServiceBluetooth *>(service)->settingsHolder)
    : Worker(service), service(service), currentProfile(std::make_shared<bluetooth::HSP>()),
      settings(static_cast<ServiceBluetooth *>(service)->settingsHolder),
      runLoop(std::make_unique<bluetooth::RunLoop>()), driver(std::make_unique<bluetooth::Driver>())
{
    init({
        {queues::io, sizeof(Bt::Message), 10},
        {queues::cmd, sizeof(Bt::Command), 10},
        {queues::io, sizeof(bluetooth::Message), queues::queueLength},
        {queues::cmd, sizeof(bluetooth::Command), queues::queueLength},
        {queues::btstack, sizeof(bool), queues::triggerQueueLength},
    });
    static_cast<ServiceBluetooth *>(service)->workerQueue = Worker::getQueueHandleByName(queues::cmd);
    runLoop->setTriggerQueue(Worker::getQueueHandleByName(queues::btstack));
    driver->init(runLoop->getRunLoopInstance());
}

BluetoothWorker::~BluetoothWorker()


@@ 69,7 62,7 @@ BluetoothWorker::~BluetoothWorker()
    LOG_INFO("Worker removed");
}

bool BluetoothWorker::run()
auto BluetoothWorker::run() -> bool
{
    LOG_INFO("-> BluetoothWorker run request");
    if (is_running) {


@@ 79,48 72,49 @@ bool BluetoothWorker::run()
        is_running                          = true;
        auto el                             = queues[queueIO_handle];
        BlueKitchen::getInstance()->qHandle = el->GetQueueHandle();
        Bt::KeyStorage::settings            = settings;
        Bt::initialize_stack();
        Bt::register_hw_error_callback();
        Bt::GAP::register_scan();
        bluetooth::KeyStorage::settings     = settings;

        driver->registerHardwareErrorCallback(nullptr);
        bluetooth::GAP::register_scan();

        std::string name = "PurePhone";
        auto settingsName = std::get<std::string>(settings->getValue(Bluetooth::Settings::DeviceName));
        auto settingsName = std::get<std::string>(settings->getValue(bluetooth::Settings::DeviceName));
        if (settingsName.empty()) {
            LOG_ERROR("settings name empty!");
            settings->setValue(Bluetooth::Settings::DeviceName, name);
            settings->setValue(bluetooth::Settings::DeviceName, name);
            settingsName = name;
        }
        Bt::set_name(settingsName);
        Bt::GAP::set_visibility(
            std::visit(Bluetooth::BoolVisitor(), settings->getValue(Bluetooth::Settings::Visibility)));

        settings->setValue(Bluetooth::Settings::State, static_cast<int>(BluetoothStatus::State::On));
        bluetooth::set_name(settingsName);
        bluetooth::GAP::set_visibility(
            std::visit(bluetooth::BoolVisitor(), settings->getValue(bluetooth::Settings::Visibility)));

        settings->setValue(bluetooth::Settings::State, static_cast<int>(BluetoothStatus::State::On));

        settings->onLinkKeyAdded = [this](std::string addr) {
            for (auto &device : Bt::GAP::devices) {
            for (auto &device : bluetooth::GAP::devices) {
                if (bd_addr_to_str(device.address) == addr) {
                    // found paired device
                    pairedDevices.emplace_back(device);
                    settings->setValue(Bluetooth::Settings::BondedDevices, SettingsSerializer::toString(pairedDevices));
                    settings->setValue(bluetooth::Settings::BondedDevices, SettingsSerializer::toString(pairedDevices));
                }
            }
        };

        Bt::run_stack(&this->bt_worker_task);
        return true;
        return driver->run() == bluetooth::Error::Success;
    }
    else {
        return false;
    }
}

bool BluetoothWorker::scan()
auto BluetoothWorker::scan() -> bool
{
    std::vector<Device> empty;
    Bt::GAP::setOwnerService(service);
    auto ret = Bt::GAP::scan();
    if (ret.err != Bt::Error::Success) {
        LOG_ERROR("Cant start scan!: %s %" PRIu32 "", c_str(ret.err), ret.lib_code);
    bluetooth::GAP::setOwnerService(service);
    auto ret = bluetooth::GAP::scan();
    if (ret.err != bluetooth::Error::Success) {
        LOG_ERROR("Cant start scan!: %s %" PRIu32 "", to_string(ret.err).c_str(), ret.lib_code);
        return false;
    }
    else {


@@ 132,59 126,77 @@ bool BluetoothWorker::scan()

void BluetoothWorker::stopScan()
{
    Bt::GAP::stop_scan();
    bluetooth::GAP::stop_scan();
}

void BluetoothWorker::setVisibility(bool visibility)
{
    Bt::GAP::set_visibility(visibility);
    settings->setValue(Bluetooth::Settings::Visibility, visibility);
    bluetooth::GAP::set_visibility(visibility);
    settings->setValue(bluetooth::Settings::Visibility, visibility);
}

bool BluetoothWorker::start_pan()
auto BluetoothWorker::start_pan() -> bool
{
    Bt::PAN::bnep_setup();
    auto err = Bt::PAN::bnep_start();
    if (err.err != Bt::Error::Success) {
        LOG_ERROR("PAN setup error: %s %" PRIu32, c_str(err.err), err.lib_code);
    bluetooth::PAN::bnep_setup();
    auto err = bluetooth::PAN::bnep_start();
    if (err.err != bluetooth::Error::Success) {
        LOG_ERROR("PAN setup error: %s %" PRIu32, to_string(err.err).c_str(), err.lib_code);
    }
    return false;
}
bool BluetoothWorker::handleCommand(QueueHandle_t queue)
auto BluetoothWorker::handleCommand(QueueHandle_t queue) -> bool
{
    Bt::Command command;
    bluetooth::Command command;
    if (xQueueReceive(queue, &command, 0) != pdTRUE) {
        LOG_ERROR("Queue receive failure!");
        return false;
    }
    switch (command) {
    case Bt::PowerOn:
    case bluetooth::PowerOn:

        break;
    case Bt::StartScan:
    case bluetooth::StartScan:
        scan();
        break;
    case Bt::StopScan:
    case bluetooth::StopScan:
        stopScan();
        break;
    case Bt::VisibilityOn:
    case bluetooth::VisibilityOn:
        setVisibility(true);
        break;
    case Bt::VisibilityOff:
    case bluetooth::VisibilityOff:
        setVisibility(false);
        break;
    case Bt::ConnectAudio:
    case bluetooth::ConnectAudio:
        establishAudioConnection();
        break;
    case Bt::DisconnectAudio:
    case bluetooth::DisconnectAudio:
        disconnectAudioConnection();
        break;
    case Bt::PowerOff:
    case bluetooth::PowerOff:
        break;
    }
    return true;
}
bool BluetoothWorker::handleMessage(uint32_t queueID)

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;
    }
    else {
        return false;
    }
}

auto BluetoothWorker::handleMessage(uint32_t queueID) -> bool
{
    QueueHandle_t queue = queues[queueID]->GetQueueHandle();
    if (queueID == queueService) {


@@ 196,33 208,36 @@ bool BluetoothWorker::handleMessage(uint32_t queueID)
        handleCommand(queue);
        return true;
    }
    if (queueID == queueRunloopTrigger) {
        handleBtStackTrigger(queue);
        return true;
    }

    if (queueID != queueIO_handle) {
        LOG_ERROR("Wrong queue! %" PRIu32, queueID);
        return false;
    }

    Bt::Message notification = Bt::Message::EvtErrorRec;
    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 Bt::Message::EvtSending:
    case bluetooth::Message::EvtSending:
        logHciComs("[evt] sending");
        break;
    case Bt::Message::EvtSent:
    case bluetooth::Message::EvtSent:
        logHciComs("[evt] sent");
        if (bt->write_done_cb) {
            btstack_run_loop_freertos_execute_code_on_main_thread(reinterpret_cast<void (*)(void *)>(bt->write_done_cb),
                                                                  nullptr);
            bt->write_done_cb();
        }
        break;
    case Bt::Message::EvtReceiving:
    case bluetooth::Message::EvtReceiving:
        logHciComs("[evt] receiving");
        break;
    case Bt::Message::EvtReceived: {
    case bluetooth::Message::EvtReceived: {
        logHciBytes("[evt] BT DMA received <-- [%ld]>%s<",
                    bt->read_len,
                    [&]() -> std::string {


@@ 237,15 252,17 @@ bool BluetoothWorker::handleMessage(uint32_t queueID)
        bt->read_len = 0;

        if (bt->read_ready_cb) {
            btstack_run_loop_freertos_execute_code_on_main_thread(reinterpret_cast<void (*)(void *)>(bt->read_ready_cb),
                                                                  nullptr);
            bt->read_ready_cb();
        }
    } break;
    case Bt::Message::EvtSendingError:
    case Bt::Message::EvtReceivingError:
    case Bt::Message::EvtUartError:
    case Bt::Message::EvtRecUnwanted:
        LOG_ERROR("Uart error [%d]: %s", notification, Bt::MessageCstr(notification));
    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");


@@ 254,22 271,22 @@ bool BluetoothWorker::handleMessage(uint32_t queueID)
    return true;
}

bool BluetoothWorker::establishAudioConnection()
auto BluetoothWorker::establishAudioConnection() -> bool
{
    currentProfile->setOwnerService(service);
    if (currentProfile->init() != Bt::Error::Success) {
    if (currentProfile->init() != bluetooth::Error::Success) {
        return false;
    }
    currentProfile->connect();
    return true;
}
bool BluetoothWorker::disconnectAudioConnection()
auto BluetoothWorker::disconnectAudioConnection() -> bool
{
    currentProfile->disconnect();
    return true;
}
void BluetoothWorker::setDeviceAddress(bd_addr_t addr)
{
    Bt::GAP::do_pairing(addr);
    bluetooth::GAP::do_pairing(addr);
    currentProfile->setDeviceAddress(addr);
}

M module-bluetooth/Bluetooth/BluetoothWorker.hpp => module-bluetooth/Bluetooth/BluetoothWorker.hpp +16 -22
@@ 12,13 12,14 @@
#include <task.h>
#include <vector>
#include "service-bluetooth/SettingsHolder.hpp"

#include "glucode/BluetoothRunLoop.hpp"
#include "interface/BluetoothDriver.hpp"
struct HCI;

/// debug option for HCI (uart) commands debugging
// #define DO_DEBUG_HCI_COMS

namespace Bt
namespace bluetooth
{
    enum Message : std::uint8_t
    {


@@ 83,9 84,8 @@ class BluetoothWorker : private sys::Worker
        queueService = 0,
        queueControl = 1,
        queueIO_handle, /// bsp support queue
                        //        queue_profiles, /// queue for communication between profile workers,
                        //                        /// main bt_worker_task should dispatch these in events
        queueCommands,
        queueRunloopTrigger // btstack run_loop queue
    };

    TaskHandle_t bt_worker_task = nullptr;


@@ 101,32 101,26 @@ class BluetoothWorker : private sys::Worker
    };

    BluetoothWorker(sys::Service *service);
    virtual ~BluetoothWorker();

    virtual bool handleMessage(uint32_t queueID);
    ~BluetoothWorker() override;

    bool handleCommand(QueueHandle_t queue);
    auto handleMessage(uint32_t queueID) -> bool override;

    auto handleCommand(QueueHandle_t queue) -> bool;
    auto handleBtStackTrigger(QueueHandle_t queue) -> bool;
    bool run();

    bool scan();

    auto scan() -> bool;
    void setVisibility(bool visibility);

    bool start_pan();

    bool establishAudioConnection();

    bool disconnectAudioConnection();

    Error aud_init();
    auto start_pan() -> bool;
    auto establishAudioConnection() -> bool;
    auto disconnectAudioConnection() -> bool;
    /// bluetooth stack id in use
    unsigned long active_features;
    void stopScan();
    void setDeviceAddress(bd_addr_t addr);
    void initAudioBT();

    std::shared_ptr<Bt::Profile> currentProfile;
    std::shared_ptr<Bluetooth::SettingsHolder> settings;
    std::shared_ptr<bluetooth::Profile> currentProfile;
    std::shared_ptr<bluetooth::SettingsHolder> settings;
    std::vector<Devicei> pairedDevices;
    std::unique_ptr<bluetooth::RunLoop> runLoop;
    std::unique_ptr<bluetooth::Driver> driver;
};

M module-bluetooth/Bluetooth/BtCommand.hpp => module-bluetooth/Bluetooth/BtCommand.hpp +3 -4
@@ 8,13 8,12 @@
#include "BluetoothWorker.hpp"
#include "Error.hpp"
#include <functional>
#include <btstack_run_loop.h>

namespace Bt
namespace bluetooth
{
    auto initialize_stack() -> Error;
    auto register_hw_error_callback(std::function<void(uint8_t)> new_callback = nullptr) -> Error;

    auto set_name(std::string &name) -> Error;
    auto run_stack(TaskHandle_t *handle) -> Error;
    namespace GAP
    {
        extern std::vector<Devicei> devices;

M module-bluetooth/Bluetooth/BtKeysStorage.cpp => module-bluetooth/Bluetooth/BtKeysStorage.cpp +8 -8
@@ 4,13 4,13 @@
#include <algorithm>
#include "BtKeysStorage.hpp"

json11::Json Bt::KeyStorage::keysJson = json11::Json();
btstack_link_key_db_t Bt::KeyStorage::keyStorage;
json11::Json::array Bt::KeyStorage::keys;
std::string Bt::KeyStorage::keysEntry;
std::shared_ptr<Bluetooth::SettingsHolder> Bt::KeyStorage::settings = nullptr;
json11::Json bluetooth::KeyStorage::keysJson = json11::Json();
btstack_link_key_db_t bluetooth::KeyStorage::keyStorage;
json11::Json::array bluetooth::KeyStorage::keys;
std::string bluetooth::KeyStorage::keysEntry;
std::shared_ptr<bluetooth::SettingsHolder> bluetooth::KeyStorage::settings = nullptr;

namespace Bt
namespace bluetooth
{
    namespace strings
    {


@@ 39,7 39,7 @@ namespace Bt
    {
        LOG_INFO("opening storage from API");
        if (settings) {
            keysEntry = std::visit(Bluetooth::StringVisitor(), settings->getValue(Bluetooth::Settings::BtKeys));
            keysEntry = std::visit(bluetooth::StringVisitor(), settings->getValue(bluetooth::Settings::BtKeys));
        }
        else {
            LOG_ERROR("failed opening settings for BT!");


@@ 140,7 140,7 @@ namespace Bt
        json11::Json finalJson = json11::Json::object{{strings::keys, keys}};
        keysEntry              = finalJson.dump();
        if (settings) {
            settings->setValue(Bluetooth::Settings::BtKeys, keysEntry);
            settings->setValue(bluetooth::Settings::BtKeys, keysEntry);
        }
        else {
            LOG_ERROR("failed to open settings to write!");

M module-bluetooth/Bluetooth/BtKeysStorage.hpp => module-bluetooth/Bluetooth/BtKeysStorage.hpp +2 -2
@@ 9,14 9,14 @@
#include <json/json11.hpp>
#include <service-bluetooth/SettingsHolder.hpp>

namespace Bt
namespace bluetooth
{

    class KeyStorage
    {
      public:
        static auto getKeyStorage() -> btstack_link_key_db_t *;
        static std::shared_ptr<Bluetooth::SettingsHolder> settings;
        static std::shared_ptr<bluetooth::SettingsHolder> settings;

      private:
        static void openStorage();

M module-bluetooth/Bluetooth/Error.hpp => module-bluetooth/Bluetooth/Error.hpp +3 -3
@@ 7,7 7,7 @@
#include <variant>
#include <optional>

namespace Bt
namespace bluetooth
{

    struct Error


@@ 20,9 20,9 @@ namespace Bt
            LibraryError,
        } err             = Success;
        uint32_t lib_code = 0;
        Error(enum Code err = Success, int lib_code = Success) : err(err), lib_code(0)
        Error(enum Code err = Success, int lib_code = Success) : err(err)
        {}
    };

} // namespace Bt
const char *c_str(Bt::Error::Code code);
const char *c_str(bluetooth::Error::Code code);

A module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.cpp => module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.cpp +198 -0
@@ 0,0 1,198 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BluetoothRunLoop.hpp"
#include "btstack_util.h"
#include <cassert>
namespace bluetooth
{

    btstack_linked_list_t RunLoop::timers;
    btstack_linked_list_t RunLoop::data_sources;
    bool RunLoop::run_loop_exit_requested;

    QueueHandle_t RunLoop::btstack_run_loop_queue;
    TaskHandle_t RunLoop::btstack_run_loop_task;
    QueueHandle_t RunLoop::triggerQueue;
    TimerHandle_t RunLoop::testTimer;

    auto RunLoop::removeTimer(btstack_timer_source_t *ts) -> bool
    {
        return btstack_linked_list_remove(&timers, reinterpret_cast<btstack_linked_item_t *>(ts));
    }
    void RunLoop::setTriggerQueue(QueueHandle_t queue)
    {
        assert(queue != nullptr);
        triggerQueue = queue;
    }
    void RunLoop::init()
    {
        timers                 = nullptr;
        btstack_run_loop_queue = xQueueCreate(RUN_LOOP_QUEUE_LENGTH, RUN_LOOP_QUEUE_ITEM_SIZE);

        // task to handle to optimize 'run on main thread'
        btstack_run_loop_task = xTaskGetCurrentTaskHandle();

        LOG_INFO("run loop init, task %p, queue item size %u",
                 btstack_run_loop_task,
                 static_cast<int>(sizeof(function_call_t)));
    }
    void RunLoop::enableDataSourceCallbacks(btstack_data_source_t *ds, uint16_t callback_types)
    {
        ds->flags |= callback_types;
    }

    void RunLoop::disableDataSourceCallbacks(btstack_data_source_t *ds, uint16_t callback_types)
    {
        ds->flags &= ~callback_types;
    }

    void RunLoop::addDataSource(btstack_data_source_t *ds)
    {
        btstack_linked_list_add(&data_sources, (btstack_linked_item_t *)ds);
    }

    auto RunLoop::removeDataSource(btstack_data_source_t *ds) -> bool
    {
        return btstack_linked_list_remove(&data_sources, (btstack_linked_item_t *)ds);
    }
    void RunLoop::triggerExit()
    {
        run_loop_exit_requested = true;
    }
    auto RunLoop::getTimeMs() -> TickType_t
    {
        return xTaskGetTickCount();
    }
    void RunLoop::trigger()
    {

        bool trigger = true;
        if (triggerQueue != nullptr) {
            xQueueSend(triggerQueue, &trigger, 0);
        }
        else {
            LOG_FATAL("Trigger queue does not exist!");
        }
    }
    void RunLoop::executeCodeOnMainThread(void (*fn)(void *arg), void *arg)
    {

        // directly call function if already on btstack task
        if (xTaskGetCurrentTaskHandle() == btstack_run_loop_task) {
            (*fn)(arg);
            return;
        }

        function_call_t message;
        message.fn     = fn;
        message.arg    = arg;
        BaseType_t res = xQueueSendToBack(btstack_run_loop_queue, &message, 0); // portMAX_DELAY);
        if (res != pdTRUE) {
            LOG_ERROR("Failed to post fn %p", fn);
        }
        trigger();
    }

    void RunLoop::addTimer(btstack_timer_source_t *ts)
    {
        btstack_linked_item_t *it = nullptr;
        for (it = reinterpret_cast<btstack_linked_item_t *>(&timers); it->next != nullptr; it = it->next) {
            // don't add timer that's already in there
            auto *next = reinterpret_cast<btstack_timer_source_t *>(it->next);
            if (next == ts) {
                LOG_ERROR("btstack_run_loop_timer_add error: timer to add already in list!");
                return;
            }
            // exit if new timeout before list timeout
            int32_t delta = btstack_time_delta(ts->timeout, next->timeout);
            if (delta < 0) {
                break;
            }
        }
        ts->item.next = it->next;
        it->next      = reinterpret_cast<btstack_linked_item_t *>(ts);
        trigger();
    }
    void RunLoop::setTimer(btstack_timer_source_t *ts, uint32_t timeout_in_ms)
    {
        ts->timeout = getTimeMs() + timeout_in_ms + 1;
        trigger();
    }
    void RunLoop::triggerCallback(TimerHandle_t xTimer)
    {
        trigger();
    }
    void RunLoop::start()
    {
        testTimer = xTimerCreate("TestTimer", pdMS_TO_TICKS(1000), pdTRUE, nullptr, triggerCallback);
        xTimerStart(testTimer, 0);
    }
    auto RunLoop::process() -> bool
    {

        btstack_data_source_t *ds;
        btstack_data_source_t *next;
        for (ds = reinterpret_cast<btstack_data_source_t *>(data_sources); ds != nullptr; ds = next) {
            next = reinterpret_cast<btstack_data_source_t *>(
                ds->item.next); // cache pointer to next data_source to allow data source to remove itself
            if ((ds->flags & DATA_SOURCE_CALLBACK_POLL) != 0) {
                ds->process(ds, DATA_SOURCE_CALLBACK_POLL);
            }
        }
        // process registered function calls on run loop thread
        while (true) {
            function_call_t message = {nullptr, nullptr};
            BaseType_t res          = xQueueReceive(btstack_run_loop_queue, &message, 0);
            if (res == pdFALSE) {
                break;
            }
            if (message.fn != nullptr) {
                message.fn(message.arg);
            }
        }

        // process timers and get next timeout
        uint32_t timeout_ms = 1000;
        while (timers != nullptr) {
            auto *ts         = reinterpret_cast<btstack_timer_source_t *>(timers);
            uint32_t now     = getTimeMs();
            int32_t delta_ms = btstack_time_delta(ts->timeout, now);
            if (delta_ms > 0) {
                timeout_ms = delta_ms;
                break;
            }
            // remove timer before processing it to allow handler to re-register with run loop
            removeTimer(ts);
            ts->process(ts);
        }

        // exit triggered by btstack_run_loop_freertos_trigger_exit (from data source, timer, run on main thread)
        if (run_loop_exit_requested) {
            return true;
        }

        xTimerChangePeriod(testTimer, pdMS_TO_TICKS(timeout_ms), 0);
        return false;
    }

    auto RunLoop::getRunLoopInstance() -> btstack_run_loop *
    {

        runLoop = btstack_run_loop{
            &init,
            &addDataSource,
            &removeDataSource,
            &enableDataSourceCallbacks,
            &disableDataSourceCallbacks,
            &setTimer,
            &addTimer,
            &removeTimer,
            &start,
            nullptr,
            &getTimeMs,
        };
        return &runLoop;
    }

} // namespace bluetooth

A module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.hpp => module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.hpp +54 -0
@@ 0,0 1,54 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include <log/log.hpp>
#include "queue.hpp"
#include <btstack_run_loop.h>
#include <timer.hpp>

namespace bluetooth
{

    using function_call_t = struct function_call
    {
        void (*fn)(void *arg);
        void *arg;
    };

    constexpr inline auto RUN_LOOP_QUEUE_LENGTH    = 20;
    constexpr inline auto RUN_LOOP_QUEUE_ITEM_SIZE = sizeof(function_call_t);

    class RunLoop
    {
      private:
        static auto removeTimer(btstack_timer_source_t *ts) -> bool;
        static void init();
        static void enableDataSourceCallbacks(btstack_data_source_t *ds, uint16_t callback_types);
        static void disableDataSourceCallbacks(btstack_data_source_t *ds, uint16_t callback_types);
        static void addDataSource(btstack_data_source_t *ds);
        static auto removeDataSource(btstack_data_source_t *ds) -> bool;
        static void triggerExit();
        static auto getTimeMs() -> TickType_t;
        static void trigger();
        static void executeCodeOnMainThread(void (*fn)(void *arg), void *arg);
        static void addTimer(btstack_timer_source_t *ts);
        static void setTimer(btstack_timer_source_t *ts, uint32_t timeout_in_ms);
        static void start();
        static void triggerCallback(TimerHandle_t xTimer);
        static QueueHandle_t btstack_run_loop_queue;
        static TaskHandle_t btstack_run_loop_task;
        static QueueHandle_t triggerQueue;
        static TimerHandle_t testTimer;
        static btstack_linked_list_t timers;
        static btstack_linked_list_t data_sources;
        static bool run_loop_exit_requested;
        btstack_run_loop runLoop;

      public:
        auto process() -> bool;
        void setTriggerQueue(QueueHandle_t queue);
        auto getRunLoopInstance() -> btstack_run_loop *;
    };

} // namespace bluetooth

R module-bluetooth/Bluetooth/BtstackWorker.cpp => module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp +128 -171
@@ 1,27 1,27 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <cstdlib>
#include <log/log.hpp>
#include "BluetoothDriver.hpp"

extern "C"
{
#include <btstack_event.h>

#include <btstack_util.h>
#include <bluetooth_company_id.h>
#include <btstack_memory.h>
#include <btstack_run_loop.h>
#include <btstack_stdin.h>
#include <hci.h>
#include <hci_dump.h>

#include <btstack_chipset_cc256x.h>
#include <btstack_link_key_db_memory.h>
};
}

#include <service-bluetooth/ServiceBluetooth.hpp>
#include <BtKeysStorage.hpp>

#ifdef TARGET_RT1051
#include <Bluetooth/glucode/btstack_uart_block_rt1051.h>
#include <btstack_run_loop_freertos.h>
#else
extern "C"
{


@@ 30,178 30,139 @@ extern "C"
}
#endif

#include "BtKeysStorage.hpp"
#include <Error.hpp>
#include <functional>

// #define TLV_DB_PATH_PREFIX "/tmp/btstack_"
// #define TLV_DB_PATH_POSTFIX ".tlv"
// static char tlv_db_path[100];
// static const btstack_tlv_t * tlv_impl;
// static btstack_tlv_posix_t   tlv_context;

static void local_version_information_handler(uint8_t *packet);

static hci_transport_config_uart_t config = {
    .type          = HCI_TRANSPORT_CONFIG_UART,
    .baudrate_init = 115200,
    .baudrate_main = 0, // main baudrate
    .flowcontrol   = 1, // flow control
    .device_name   = nullptr,
};

static btstack_packet_callback_registration_t hci_event_callback_registration;

static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
    bd_addr_t addr;
    if (packet_type != HCI_EVENT_PACKET) {
        return;
    }
    switch (hci_event_packet_get_type(packet)) {
    case BTSTACK_EVENT_STATE:
        if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) {
            break;
        }
        gap_local_bd_addr(addr);
        LOG_INFO("BTstack up and running at %s", bd_addr_to_str(addr));
        // setup TLV
        //            strcpy(tlv_db_path, TLV_DB_PATH_PREFIX);
        //            strcat(tlv_db_path, bd_addr_to_str(addr));
        //            strcat(tlv_db_path, TLV_DB_PATH_POSTFIX);
        //            tlv_impl = btstack_tlv_posix_init_instance(&tlv_context, tlv_db_path);
        //            btstack_tlv_set_instance(tlv_impl, &tlv_context);
        break;
    case HCI_EVENT_COMMAND_COMPLETE:
        if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_name)) {
            if (hci_event_command_complete_get_return_parameters(packet)[0] != 0u)
                break;
            // terminate, name 248 chars
            packet[6 + 248] = 0;
            LOG_INFO("Local name: %s", &packet[6]);
        }
        if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_version_information)) {
            local_version_information_handler(packet);
        }
        break;
    default:
        break;
    }
}

static void sigint_handler(int param)
{
    UNUSED(param);

    LOG_INFO("CTRL-C - SIGINT received, shutting down..");

    // reset anyway
    btstack_stdin_reset();

    // power down
    hci_power_control(HCI_POWER_OFF);
    hci_close();
    exit(0);
}

static int led_state = 0;
void hal_led_toggle()
{
    led_state = 1 - led_state;
    LOG_INFO("LED State %u", led_state);
}
static void use_fast_uart()
{
#if defined(HAVE_POSIX_B240000_MAPPED_TO_3000000) || defined(HAVE_POSIX_B600_MAPPED_TO_3000000)
    LOG_INFO("Using 3000000 baud.");
    config.baudrate_main = 3000000;
#elif defined(HAVE_POSIX_B1200_MAPPED_TO_2000000) || defined(HAVE_POSIX_B300_MAPPED_TO_2000000)
    LOG_INFO("Using 2000000 baud.");
    config.baudrate_main = 2000000;
#else
    LOG_INFO("Using 921600 baud");
    config.baudrate_main = 921600;
#endif
}

static void local_version_information_handler(uint8_t *packet)
namespace bluetooth
{
    LOG_INFO("Local version information:");
    uint16_t hci_version    = packet[6];
    uint16_t hci_revision   = little_endian_read_16(packet, 7);
    uint16_t lmp_version    = packet[9];
    uint16_t manufacturer   = little_endian_read_16(packet, 10);
    uint16_t lmp_subversion = little_endian_read_16(packet, 12);
    LOG_INFO("- HCI Version    0x%04x", hci_version);
    LOG_INFO("- HCI Revision   0x%04x", hci_revision);
    LOG_INFO("- LMP Version    0x%04x", lmp_version);
    LOG_INFO("- LMP Subversion 0x%04x", lmp_subversion);
    LOG_INFO("- Manufacturer 0x%04x", manufacturer);
    switch (manufacturer) {
    case BLUETOOTH_COMPANY_ID_TEXAS_INSTRUMENTS_INC:
        LOG_INFO("Texas Instruments - CC256x compatible chipset.");
        if (lmp_subversion != btstack_chipset_cc256x_lmp_subversion()) {
            LOG_INFO("Error: LMP Subversion does not match initscript! ");
            LOG_INFO("Your initscripts is for %s chipset",
                     btstack_chipset_cc256x_lmp_subversion() < lmp_subversion ? "an older" : "a newer");
            LOG_INFO("Please update Makefile to include the appropriate bluetooth_init_cc256???.c file");
            exit(10);
        }
        use_fast_uart();
        hci_set_chipset(btstack_chipset_cc256x_instance());
#ifdef ENABLE_EHCILL
        LOG_INFO("eHCILL enabled.");
#else
        LOG_INFO("eHCILL disable.");
#endif
    hci_transport_config_uart_t Driver::config;

        break;
    case BLUETOOTH_COMPANY_ID_NORDIC_SEMICONDUCTOR_ASA:
        LOG_INFO("Nordic Semiconductor nRF5 chipset.");
        break;
    default:
        LOG_INFO("Unknown manufacturer / manufacturer not supported yet.\n");
        break;
#ifdef TARGET_RT1051
    [[maybe_unused]] auto Driver::runLoopInitTarget(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *
    {
        btstack_run_loop_init(runLoop);
        const btstack_uart_block_t *uartDriver = btstack_uart_block_rt1051_instance();
        return uartDriver;
    }
}

extern "C"
{
#include <FreeRTOS.h>
#include <task.h>
};
#else

namespace Bt
{
    void run_btstack(void *)
    [[maybe_unused]] auto Driver::runLoopInitLinux(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *
    {
        LOG_INFO("- run BtStack loop\n");
        btstack_run_loop_execute();
        btstack_run_loop_init(btstack_run_loop_posix_get_instance());
        config.device_name = "/dev/telit";
        LOG_INFO("H4 device: %s", config.device_name);
        const btstack_uart_block_t *uartDriver = btstack_uart_block_posix_instance();
        return uartDriver;
    }
#endif

    auto initialize_stack() -> Error
    auto Driver::init(const btstack_run_loop *runLoop) -> Error::Code
    {
        btstack_memory_init();
        config = {
            .type          = HCI_TRANSPORT_CONFIG_UART,
            .baudrate_init = 115200,
            .baudrate_main = 0,
            .flowcontrol   = 1,
            .device_name   = nullptr,
        };
#ifdef TARGET_RT1051
        btstack_run_loop_init(btstack_run_loop_freertos_get_instance());
        const btstack_uart_block_t *uart_driver = btstack_uart_block_rt1051_instance();
        auto uartDriver = runLoopInitTarget(runLoop);
#else
        btstack_run_loop_init(btstack_run_loop_posix_get_instance());
        config.device_name = "/dev/telit";
        LOG_INFO("H4 device: %s", config.device_name);
        const btstack_uart_block_t *uart_driver = btstack_uart_block_posix_instance();
        auto uartDriver = runLoopInitLinux(runLoop);
#endif
        const hci_transport_t *transport = hci_transport_h4_instance(uart_driver);
        const hci_transport_t *transport = hci_transport_h4_instance(uartDriver);

        hci_init(transport, (void *)&config);
        hci_set_link_key_db(KeyStorage::getKeyStorage());
        hci_set_link_key_db(bluetooth::KeyStorage::getKeyStorage());
        hci_event_callback_registration.callback = &hci_packet_handler;
        hci_add_event_handler(&hci_event_callback_registration);
        LOG_DEBUG("BT worker run success");
        return Error();
        return Error::Success;
    }

    auto register_hw_error_callback(std::function<void(uint8_t)> new_callback) -> Error
    void Driver::hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
    {
        bd_addr_t addr;
        if (packet_type != HCI_EVENT_PACKET) {
            return;
        }
        switch (hci_event_packet_get_type(packet)) {
        case BTSTACK_EVENT_STATE:
            if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) {
                break;
            }
            gap_local_bd_addr(addr);
            LOG_INFO("BTstack up and running at %s", bd_addr_to_str(addr));
            break;
        case HCI_EVENT_COMMAND_COMPLETE:
            if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_name)) {
                if (hci_event_command_complete_get_return_parameters(packet)[0] != 0u) {
                    break;
                }
                // terminate, name 248 chars
                packet[6 + 248] = 0;
                LOG_INFO("Local name: %s", &packet[6]);
            }
            if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_version_information)) {
                local_version_information_handler(packet);
            }
            break;
        default:
            break;
        }
    }
    void Driver::local_version_information_handler(uint8_t *packet)
    {
        LOG_INFO("Local version information:");
        uint16_t hci_version    = packet[6];
        uint16_t hci_revision   = little_endian_read_16(packet, 7);
        uint16_t lmp_version    = packet[9];
        uint16_t manufacturer   = little_endian_read_16(packet, 10);
        uint16_t lmp_subversion = little_endian_read_16(packet, 12);
        LOG_INFO("- HCI Version    0x%04x", hci_version);
        LOG_INFO("- HCI Revision   0x%04x", hci_revision);
        LOG_INFO("- LMP Version    0x%04x", lmp_version);
        LOG_INFO("- LMP Subversion 0x%04x", lmp_subversion);
        LOG_INFO("- Manufacturer 0x%04x", manufacturer);
        switch (manufacturer) {
        case BLUETOOTH_COMPANY_ID_TEXAS_INSTRUMENTS_INC:
            LOG_INFO("Texas Instruments - CC256x compatible chipset.");
            if (lmp_subversion != btstack_chipset_cc256x_lmp_subversion()) {
                LOG_INFO("Error: LMP Subversion does not match initscript! ");
                LOG_INFO("Your initscripts is for %s chipset",
                         btstack_chipset_cc256x_lmp_subversion() < lmp_subversion ? "an older" : "a newer");
                LOG_INFO("Please update Makefile to include the appropriate bluetooth_init_cc256???.c file");
                exit(10);
            }
            LOG_INFO("Using 921600 baud");
            config.baudrate_main = 921600;
            hci_set_chipset(btstack_chipset_cc256x_instance());
#ifdef ENABLE_EHCILL
            LOG_INFO("eHCILL enabled.");
#else
            LOG_INFO("eHCILL disable.");
#endif

            break;
        case BLUETOOTH_COMPANY_ID_NORDIC_SEMICONDUCTOR_ASA:
            LOG_INFO("Nordic Semiconductor nRF5 chipset.");
            break;
        default:
            LOG_INFO("Unknown manufacturer / manufacturer not supported yet.\n");
            break;
        }
    }
    auto Driver::run() -> Error::Code
    {
        auto ret = hci_power_control(HCI_POWER_ON);
        if (ret != 0) {
            LOG_ERROR("HCI power on failed, can't start Bluetooth!");
            return Error::LibraryError;
        }
        LOG_INFO("HCI turned on - run BtStack loop\n");
        btstack_run_loop_execute();
        return Error::Success;
    }

    void Driver::registerHardwareErrorCallback(std::function<void(uint8_t)> new_callback)
    {
        static std::function<void(uint8_t)> callback = nullptr;
        callback                                     = new_callback;


@@ 211,18 172,14 @@ namespace Bt
                callback(val);
            }
        });
        return Error();
    }

    auto run_stack(TaskHandle_t *handle) -> Error
    auto Driver::stop() -> Error::Code
    {
        BaseType_t taskerr = 0;
        LOG_INFO("Past last moment for Bt registration prior to RUN state");
        hci_power_control(HCI_POWER_ON);
        if ((taskerr = xTaskCreate(run_btstack, "BtStack", 1024, NULL, tskIDLE_PRIORITY, handle)) != pdPASS) {
            LOG_ERROR("BT Service failure! %lu", taskerr);
            return Error(Error::SystemError, taskerr);
        auto ret = hci_power_control(HCI_POWER_OFF);
        if (ret != 0) {
            LOG_ERROR("Can't turn off Bluetooth Stack!");
        }
        return Error();
        hci_close();
        return ret != 0 ? Error::LibraryError : Error::Success;
    }
} // namespace Bt
} // namespace bluetooth

A module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp => module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp +29 -0
@@ 0,0 1,29 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <btstack.h>
#include <functional>
#include "Error.hpp"

namespace bluetooth
{

    class Driver
    {
      private:
        static hci_transport_config_uart_t config;
        btstack_packet_callback_registration_t hci_event_callback_registration;
        static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
        static void local_version_information_handler(uint8_t *packet);
        [[maybe_unused]] auto runLoopInitTarget(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *;
        [[maybe_unused]] auto runLoopInitLinux(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *;

      public:
        auto init(const btstack_run_loop *runLoop) -> Error::Code;
        auto run() -> Error::Code;
        auto stop() -> Error::Code;
        void registerHardwareErrorCallback(std::function<void(uint8_t)> new_callback);
    };
} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp +3 -3
@@ 23,7 23,7 @@ extern "C"
#include <btstack_defines.h>
}

namespace Bt
namespace bluetooth
{
    A2DP::A2DP() : pimpl(std::make_unique<A2DPImpl>(A2DPImpl()))
    {}


@@ 120,7 120,7 @@ namespace Bt
                                               AVDTP::sbcCodecConfiguration.size());
        if (local_stream_endpoint == nullptr) {
            LOG_INFO("A2DP Source: not enough memory to create local stream endpoint\n");
            return Bt::Error::SystemError;
            return bluetooth::Error::SystemError;
        }
        AVRCP::mediaTracker.local_seid = avdtp_local_seid(local_stream_endpoint);
        avdtp_source_register_delay_reporting_category(AVRCP::mediaTracker.local_seid);


@@ 165,7 165,7 @@ namespace Bt

        LOG_INFO("Init done!");

        return Bt::Error::Success;
        return bluetooth::Error::Success;
    }

    void A2DP::A2DPImpl::sendMediaPacket()

M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp +1 -1
@@ 9,7 9,7 @@
#include "queue.h"
#include <memory>
#include <service-bluetooth/ServiceBluetoothCommon.hpp>
namespace Bt
namespace bluetooth
{
    class A2DP : public Profile
    {

M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DPImpl.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DPImpl.hpp +1 -1
@@ 15,7 15,7 @@ extern "C"
#include <btstack_defines.h>
}

namespace Bt
namespace bluetooth
{
    static constexpr int SBC_STORAGE_SIZE = 1030;
    struct MediaContext

M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVDTP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/AVDTP.cpp +1 -1
@@ 3,7 3,7 @@

#include "AVDTP.hpp"

namespace Bt
namespace bluetooth
{
    AVDTP::SbcConfiguration AVDTP::sbcConfig;
    btstack_sbc_encoder_state_t AVDTP::sbcEncoderState;

M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVDTP.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/AVDTP.hpp +1 -1
@@ 10,7 10,7 @@ extern "C"
#include <btstack_defines.h>
#include <classic/avdtp.h>
}
namespace Bt
namespace bluetooth
{

    class AVDTP

M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.cpp +1 -1
@@ 3,7 3,7 @@

#include "AVRCP.hpp"

namespace Bt
namespace bluetooth
{

    AVRCP::PlaybackStatusInfo AVRCP::playInfo;

M module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/AVRCP.hpp +1 -1
@@ 15,7 15,7 @@ extern "C"
#include <btstack_defines.h>
}

namespace Bt
namespace bluetooth
{
    class AVRCP
    {

M module-bluetooth/Bluetooth/interface/profiles/GAP.cpp => module-bluetooth/Bluetooth/interface/profiles/GAP.cpp +25 -28
@@ 19,7 19,7 @@ extern "C"

btstack_packet_callback_registration_t cb_handler;

std::vector<Devicei> Bt::GAP::devices;
std::vector<Devicei> bluetooth::GAP::devices;
static auto start_scan() -> int;
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);



@@ 42,7 42,7 @@ enum STATE
};
enum STATE state = INIT;

namespace Bt::GAP
namespace bluetooth::GAP
{

    static sys::Service *ownerService = nullptr;


@@ 99,7 99,7 @@ namespace Bt::GAP
        return false;
    }

} // namespace Bt::GAP
} // namespace bluetooth::GAP

#define INQUIRY_INTERVAL 5
static auto start_scan() -> int


@@ 110,9 110,8 @@ static auto start_scan() -> int

static auto has_more_remote_name_requests() -> int
{
    int i;
    for (i = 0; i < Bt::GAP::devices.size(); i++) {
        if (Bt::GAP::devices[i].state == REMOTE_NAME_REQUEST) {
    for (int i = 0; i < bluetooth::GAP::devices.size(); i++) {
        if (bluetooth::GAP::devices[i].state == REMOTE_NAME_REQUEST) {
            return 1;
        }
    }


@@ 121,15 120,13 @@ static auto has_more_remote_name_requests() -> int

static void do_next_remote_name_request()
{
    int i;
    for (i = 0; i < Bt::GAP::devices.size(); i++) {

    for (auto &device : bluetooth::GAP::devices) {
        // remote name request
        if (Bt::GAP::devices[i].state == REMOTE_NAME_REQUEST) {
            Bt::GAP::devices[i].state = REMOTE_NAME_INQUIRED;
            LOG_INFO("Get remote name of %s...", bd_addr_to_str(Bt::GAP::devices[i].address));
            gap_remote_name_request(Bt::GAP::devices[i].address,
                                    Bt::GAP::devices[i].pageScanRepetitionMode,
                                    Bt::GAP::devices[i].clockOffset | 0x8000);
        if (device.state == REMOTE_NAME_REQUEST) {
            device.state = REMOTE_NAME_INQUIRED;
            LOG_INFO("Get remote name of %s...", bd_addr_to_str(device.address));
            gap_remote_name_request(device.address, device.pageScanRepetitionMode, device.clockOffset | 0x8000);
            return;
        }
    }


@@ 189,7 186,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe

        case GAP_EVENT_INQUIRY_RESULT: {
            gap_event_inquiry_result_get_bd_addr(packet, addr);
            index = getDeviceIndexForAddress(Bt::GAP::devices, addr);
            index = getDeviceIndexForAddress(bluetooth::GAP::devices, addr);
            if (index >= 0) {
                break; // already in our list
            }


@@ 218,36 215,36 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
            else {
                dev.state = REMOTE_NAME_REQUEST;
            }
            Bt::GAP::devices.push_back(dev);
            auto msg = std::make_shared<BluetoothScanResultMessage>(Bt::GAP::devices);
            sys::Bus::SendUnicast(msg, "ApplicationSettings", Bt::GAP::ownerService);
            sys::Bus::SendUnicast(msg, "ApplicationSettingsNew", Bt::GAP::ownerService);
            bluetooth::GAP::devices.push_back(dev);
            auto msg = std::make_shared<BluetoothScanResultMessage>(bluetooth::GAP::devices);
            sys::Bus::SendUnicast(msg, "ApplicationSettings", bluetooth::GAP::ownerService);
            sys::Bus::SendUnicast(msg, "ApplicationSettingsNew", bluetooth::GAP::ownerService);

        } break;

        case GAP_EVENT_INQUIRY_COMPLETE:
            for (i = 0; i < Bt::GAP::devices.size(); i++) {
            for (i = 0; i < bluetooth::GAP::devices.size(); i++) {
                // retry remote name request
                if (Bt::GAP::devices[i].state == REMOTE_NAME_INQUIRED)
                    Bt::GAP::devices[i].state = REMOTE_NAME_REQUEST;
                if (bluetooth::GAP::devices[i].state == REMOTE_NAME_INQUIRED)
                    bluetooth::GAP::devices[i].state = REMOTE_NAME_REQUEST;
            }
            continue_remote_names();
            break;

        case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: {
            reverse_bd_addr(&packet[3], addr);
            index = getDeviceIndexForAddress(Bt::GAP::devices, addr);
            index = getDeviceIndexForAddress(bluetooth::GAP::devices, addr);
            if (index >= 0) {
                if (packet[2] == 0) {
                    LOG_INFO("Name: '%s'", &packet[9]);
                    Bt::GAP::devices[index].state = REMOTE_NAME_FETCHED;
                    Bt::GAP::devices[index].name  = reinterpret_cast<char *>(&packet[9]);
                    bluetooth::GAP::devices[index].state = REMOTE_NAME_FETCHED;
                    bluetooth::GAP::devices[index].name  = reinterpret_cast<char *>(&packet[9]);
                }
                else {
                    LOG_INFO("Failed to get name: page timeout");
                }
            }
            if (index + 1 == Bt::GAP::devices.size()) {
            if (index + 1 == bluetooth::GAP::devices.size()) {
                LOG_INFO("Scanned all");
                state = DONE;
                gap_inquiry_stop();


@@ 258,8 255,8 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
        case GAP_EVENT_DEDICATED_BONDING_COMPLETED: {
            auto result = packet[2];
            auto msg    = std::make_shared<BluetoothPairResultMessage>(result == 0u);
            sys::Bus::SendUnicast(msg, "ApplicationSettings", Bt::GAP::ownerService);
            sys::Bus::SendUnicast(msg, "ApplicationSettingsNew", Bt::GAP::ownerService);
            sys::Bus::SendUnicast(msg, "ApplicationSettings", bluetooth::GAP::ownerService);
            sys::Bus::SendUnicast(msg, "ApplicationSettingsNew", bluetooth::GAP::ownerService);
        } break;
        default:
            break;

M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp +2 -2
@@ 17,7 17,7 @@ extern "C"
#include <btstack_defines.h>
}

namespace Bt
namespace bluetooth
{
    HSP::HSP() : pimpl(std::make_unique<HSPImpl>(HSPImpl()))
    {}


@@ 204,7 204,7 @@ namespace Bt

        LOG_INFO("HSP init done!");

        return Bt::Error::Success;
        return bluetooth::Error::Success;
    }

    void HSP::HSPImpl::start()

M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp +1 -1
@@ 6,7 6,7 @@
#include "Profile.hpp"
#include <service-bluetooth/BluetoothMessage.hpp>

namespace Bt
namespace bluetooth
{

    class HSP : public Profile

M module-bluetooth/Bluetooth/interface/profiles/HSP/HSPImpl.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSPImpl.hpp +1 -1
@@ 7,7 7,7 @@
#include "SCO.hpp"
#include <Audio/AudioCommon.hpp>

namespace Bt
namespace bluetooth
{
    static constexpr int serviceBufferLength = 150;
    static constexpr int commandBufferLength = 150;

M module-bluetooth/Bluetooth/interface/profiles/HSP/SCO.cpp => module-bluetooth/Bluetooth/interface/profiles/HSP/SCO.cpp +2 -2
@@ 19,7 19,7 @@ extern "C"
#include "hci.h"
}

namespace Bt
namespace bluetooth
{

    class SCO::SCOImpl


@@ 94,7 94,7 @@ namespace Bt
    SCO::~SCO() = default;
} // namespace Bt

using namespace Bt;
using namespace bluetooth;

btstack_cvsd_plc_state_t SCO::SCOImpl::cvsdPlcState;
QueueHandle_t SCO::SCOImpl::sinkQueue;

M module-bluetooth/Bluetooth/interface/profiles/HSP/SCO.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/SCO.hpp +1 -1
@@ 11,7 11,7 @@ extern "C"
{
#include <module-bluetooth/lib/btstack/src/bluetooth.h>
};
namespace Bt
namespace bluetooth
{

    class SCO

M module-bluetooth/Bluetooth/interface/profiles/PAN.cpp => module-bluetooth/Bluetooth/interface/profiles/PAN.cpp +1 -1
@@ 106,7 106,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
    }
}

namespace Bt
namespace bluetooth
{

    // Set local name with a template Bluetooth address, that will be automatically

M module-bluetooth/Bluetooth/interface/profiles/Profile.hpp => module-bluetooth/Bluetooth/interface/profiles/Profile.hpp +1 -1
@@ 7,7 7,7 @@
#include <Service/Message.hpp>
#include <service-bluetooth/ServiceBluetoothCommon.hpp>
#include <memory>
namespace Bt
namespace bluetooth
{
    class Profile
    {

M module-bluetooth/CMakeLists.txt => module-bluetooth/CMakeLists.txt +3 -2
@@ 6,14 6,15 @@ set(CMAKE_CXX_STANDARD 17)

set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/BluetoothWorker.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/BtstackWorker.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/glucode/BluetoothRunLoop.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/BluetoothDriver.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/BtKeysStorage.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/A2DP/A2DP.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/A2DP/AVRCP.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/A2DP/AVDTP.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/HSP/HSP.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/HSP/SCO.cpp
    )
)

message("Build with BlueKitchen")
include(lib/btstack.cmake)

M module-bsp/board/rt1051/bluetooth/BlueKitchen.cpp => module-bsp/board/rt1051/bluetooth/BlueKitchen.cpp +4 -4
@@ 47,12 47,12 @@ BTdev::Error BlueKitchen::read(uint8_t *buf, size_t nbytes)
    read_len  = nbytes;

    if (BluetoothCommon::read(buf, nbytes) == Success) {
        val = Bt::Message::EvtReceiving;
        val = bluetooth::Message::EvtReceiving;
        xQueueSend(qHandle, &val, portMAX_DELAY);
        return BTdev::Success;
    }
    else {
        val = Bt::Message::EvtReceivingError;
        val = bluetooth::Message::EvtReceivingError;
        xQueueSend(qHandle, &val, portMAX_DELAY);
        return BTdev::ErrorBSP;
    }


@@ 65,12 65,12 @@ BTdev::Error BlueKitchen::write(const uint8_t *buf, size_t size)
    logHciStack("BlueKitchen sends %d bytes", size);

    if (BluetoothCommon::write(buf, size) == Success) {
        val = Bt::Message::EvtSending;
        val = bluetooth::Message::EvtSending;
        xQueueSend(qHandle, &val, portMAX_DELAY);
        return BTdev::Success;
    }
    else {
        val = Bt::Message::EvtSendingError;
        val = bluetooth::Message::EvtSendingError;
        xQueueSend(qHandle, &val, portMAX_DELAY);
        return BTdev::ErrorBSP;
    }

M module-bsp/board/rt1051/bluetooth/BluetoothCommon.cpp => module-bsp/board/rt1051/bluetooth/BluetoothCommon.cpp +4 -4
@@ 273,7 273,7 @@ void BluetoothCommon::uartDmaCallback(LPUART_Type *base, lpuart_edma_handle_t *h
    case kStatus_LPUART_TxIdle: {
        logHciComs("DMA irq: TX done");
        LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, false);
        val = Bt::Message::EvtSent;
        val = bluetooth::Message::EvtSent;
        xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
        portEND_SWITCHING_ISR(taskwoken);
        break;


@@ 281,7 281,7 @@ void BluetoothCommon::uartDmaCallback(LPUART_Type *base, lpuart_edma_handle_t *h
    case kStatus_LPUART_RxIdle:
        logHciComs("DMA irq: RX done");
        LPUART_EnableRx(BSP_BLUETOOTH_UART_BASE, false);
        val = Bt::Message::EvtReceived;
        val = bluetooth::Message::EvtReceived;
        xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
        portEND_SWITCHING_ISR(taskwoken);
        break;


@@ 316,7 316,7 @@ extern "C"
    {
        uint32_t isrReg      = LPUART_GetStatusFlags(BSP_BLUETOOTH_UART_BASE);
        BaseType_t taskwoken = 0;
        uint8_t val          = Bt::Message::EvtReceived;
        uint8_t val          = bluetooth::Message::EvtReceived;
        bsp::BlueKitchen *bt = bsp::BlueKitchen::getInstance();

        if (isrReg & kLPUART_RxDataRegFullFlag) {


@@ 324,7 324,7 @@ extern "C"
        }
        if (isrReg & kLPUART_RxOverrunFlag) {
            LOG_WARN("LPUART IRQ RX overrun");
            val = Bt::Message::EvtUartError;
            val = bluetooth::Message::EvtUartError;
            xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
        }
        LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, isrReg);

M module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +9 -9
@@ 25,7 25,7 @@
ServiceBluetooth::ServiceBluetooth() : sys::Service(service::name::bluetooth)
{
    auto settings  = std::make_unique<settings::Settings>(this);
    settingsHolder = std::make_shared<Bluetooth::SettingsHolder>(std::move(settings));
    settingsHolder = std::make_shared<bluetooth::SettingsHolder>(std::move(settings));
    LOG_INFO("[ServiceBluetooth] Initializing");
}



@@ 43,7 43,7 @@ sys::ReturnCodes ServiceBluetooth::InitHandler()

    connect(message::bluetooth::RequestBondedDevices(), [&](sys::Message *msg) {
        auto bondedDevicesStr =
            std::visit(Bluetooth::StringVisitor(), this->settingsHolder->getValue(Bluetooth::Settings::BondedDevices));
            std::visit(bluetooth::StringVisitor(), this->settingsHolder->getValue(bluetooth::Settings::BondedDevices));

        return std::make_shared<message::bluetooth::ResponseBondedDevices>(
            SettingsSerializer::fromString(bondedDevicesStr));


@@ 52,9 52,9 @@ sys::ReturnCodes ServiceBluetooth::InitHandler()
    connect(message::bluetooth::RequestStatus(), [&](sys::Message *msg) {
        BluetoothStatus status;

        auto state = std::visit(Bluetooth::IntVisitor(), settingsHolder->getValue(Bluetooth::Settings::State));
        auto state = std::visit(bluetooth::IntVisitor(), settingsHolder->getValue(bluetooth::Settings::State));
        auto visibility =
            std::visit(Bluetooth::BoolVisitor(), settingsHolder->getValue(Bluetooth::Settings::Visibility));
            std::visit(bluetooth::BoolVisitor(), settingsHolder->getValue(bluetooth::Settings::Visibility));
        status.state      = static_cast<BluetoothStatus::State>(state);
        status.visibility = visibility;



@@ 82,7 82,7 @@ sys::ReturnCodes ServiceBluetooth::InitHandler()

    settingsHolder->onStateChange = [this]() {
        auto initialState =
            std::visit(Bluetooth::IntVisitor(), this->settingsHolder->getValue(Bluetooth::Settings::State));
            std::visit(bluetooth::IntVisitor(), this->settingsHolder->getValue(bluetooth::Settings::State));
        if (static_cast<BluetoothStatus::State>(initialState) == BluetoothStatus::State::On) {
            this->worker->run();
        }


@@ 117,7 117,7 @@ sys::MessagePointer ServiceBluetooth::DataReceivedHandler(sys::DataMessage *msg,
                    return std::make_shared<sys::ResponseMessage>(sys::ReturnCodes::Failure);
                }
            case BluetoothMessage::StopScan:
                sendWorkerCommand(Bt::StopScan);
                sendWorkerCommand(bluetooth::StopScan);
                break;
            case BluetoothMessage::PAN: {
                /// TODO request lwip first...


@@ 140,10 140,10 @@ sys::MessagePointer ServiceBluetooth::DataReceivedHandler(sys::DataMessage *msg,
            } break;

            case BluetoothMessage::Play:
                sendWorkerCommand(Bt::ConnectAudio);
                sendWorkerCommand(bluetooth::ConnectAudio);
                break;
            case BluetoothMessage::Stop:
                sendWorkerCommand(Bt::DisconnectAudio);
                sendWorkerCommand(bluetooth::DisconnectAudio);
                break;

            default:


@@ 177,7 177,7 @@ sys::ReturnCodes ServiceBluetooth::SwitchPowerModeHandler(const sys::ServicePowe
    LOG_ERROR("TODO");
    return sys::ReturnCodes::Success;
}
void ServiceBluetooth::sendWorkerCommand(Bt::Command command)
void ServiceBluetooth::sendWorkerCommand(bluetooth::Command command)
{
    xQueueSend(workerQueue, &command, portMAX_DELAY);
}

M module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp => module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp +2 -2
@@ 29,9 29,9 @@ class ServiceBluetooth : public sys::Service
    sys::ReturnCodes InitHandler() override;
    sys::ReturnCodes DeinitHandler() override;
    virtual sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override;
    void sendWorkerCommand(Bt::Command command);
    void sendWorkerCommand(bluetooth::Command command);
    QueueHandle_t workerQueue = nullptr;
    std::shared_ptr<Bluetooth::SettingsHolder> settingsHolder;
    std::shared_ptr<bluetooth::SettingsHolder> settingsHolder;

  private:
    std::unique_ptr<BluetoothWorker> worker;

M module-services/service-bluetooth/service-bluetooth/SettingsHolder.cpp => module-services/service-bluetooth/service-bluetooth/SettingsHolder.cpp +1 -1
@@ 2,7 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SettingsHolder.hpp"
namespace Bluetooth
namespace bluetooth
{
    std::map<Settings, std::string> SettingsHolder::settingString{
        {Settings::DeviceName, settings::Bluetooth::deviceName},

M module-services/service-bluetooth/service-bluetooth/SettingsHolder.hpp => module-services/service-bluetooth/service-bluetooth/SettingsHolder.hpp +1 -1
@@ 9,7 9,7 @@
#include <module-utils/Utils.hpp>
#include "SettingsSerializer.hpp"

namespace Bluetooth
namespace bluetooth
{

    enum class Settings