~aleteoryx/muditaos

09efb75ed5a6f53720f58f56e35a27a1f1c7b184 — Lefucjusz 1 year, 6 months ago 6e60078
[MOS-1068] Cleanup BTStack intergration

Code cleanup in various places of
BTStack integration.
M module-bluetooth/Bluetooth/BluetoothWorker.cpp => module-bluetooth/Bluetooth/BluetoothWorker.cpp +29 -30
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <service-bluetooth/ServiceBluetooth.hpp>


@@ 6,8 6,6 @@
#include "BtCommand.hpp"
#include <log/log.hpp>
#include "interface/BluetoothDriverImpl.hpp"
#include "interface/profiles/A2DP/A2DP.hpp"
#include "interface/profiles/HSP/HSP.hpp"
#include "audio/BluetoothAudioDevice.hpp"
#include "BtKeysStorage.hpp"



@@ 26,12 24,12 @@

namespace queues
{
    constexpr inline auto io      = "qBtIO";
    constexpr inline auto cmd     = "qBtCmds";
    constexpr inline auto btstack = "qBtStack";
    constexpr auto io      = "qBtIO";
    constexpr auto cmd     = "qBtCmds";
    constexpr auto btstack = "qBtStack";

    constexpr inline auto queueLength        = 10;
    constexpr inline auto triggerQueueLength = 3;
    constexpr auto queueLength        = 10;
    constexpr auto triggerQueueLength = 3;
} // namespace queues

namespace


@@ 120,7 118,7 @@ void BluetoothWorker::registerQueues()

    dynamic_cast<ServiceBluetooth *>(service)->workerQueue = workerQueue;
    runLoop->setTriggerQueue(Worker::getQueueHandleByName(queues::btstack));
    bsp::BlueKitchen::getInstance()->qHandle = queues[queueIO_handle]->GetQueueHandle();
    bsp::BlueKitchen::getInstance().qHandle = queues[queueIO_handle]->GetQueueHandle();
}

void BluetoothWorker::onLinkKeyAdded(const std::string &deviceAddress)


@@ 212,49 210,53 @@ auto BluetoothWorker::handleMessage(uint32_t queueID) -> bool
        LOG_ERROR("Queue receive failure!");
        return false;
    }
    auto bt = bsp::BlueKitchen::getInstance();

    auto &blueKitchen = bsp::BlueKitchen::getInstance();
    switch (notification) {
    case bluetooth::Message::EvtSending:
    case bluetooth::Message::EvtSending: {
        logHciComs("[evt] sending");
        break;
    case bluetooth::Message::EvtSent:
    } break;

    case bluetooth::Message::EvtSent: {
        logHciComs("[evt] sent");
        if (bt->write_done_cb) {
            bt->write_done_cb();
        if (blueKitchen.writeDoneCallback) {
            blueKitchen.writeDoneCallback();
        }
        break;
    case bluetooth::Message::EvtReceiving:
    } break;

    case bluetooth::Message::EvtReceiving: {
        logHciComs("[evt] receiving");
        break;
    } break;

    case bluetooth::Message::EvtReceived: {
        logHciBytes("[evt] BT DMA received <-- [%ld]>%s<",
                    bt->read_len,
                    blueKitchen.readLength,
                    [&]() -> std::string {
                        std::stringstream ss;
                        for (int i = 0; i < bt->read_len; ++i) {
                            ss << " 0x" << std::hex << (int)*(bt->read_buff + i);
                        for (auto i = 0; i < blueKitchen.readLength; ++i) {
                            ss << " 0x" << std::hex << static_cast<int>(blueKitchen.readBuffer[i]);
                        }
                        return ss.str();
                    }()
                                 .c_str());

        bt->read_len = 0;
        blueKitchen.readLength = 0;

        if (bt->read_ready_cb) {
            bt->read_ready_cb();
        if (blueKitchen.readReadyCallback) {
            blueKitchen.readReadyCallback();
        }
    } 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("Unknown message: %d", notification);
        break;
    }

    return true;


@@ 266,9 268,6 @@ void BluetoothWorker::closeWorker()
    this->close();
}

void BluetoothWorker::removeFromBoundDevices(uint8_t *addr)
{}

void BluetoothWorker::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> device)
{
    cpp_freertos::LockGuard lock(loopMutex);

M module-bluetooth/Bluetooth/BluetoothWorker.hpp => module-bluetooth/Bluetooth/BluetoothWorker.hpp +1 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 88,7 88,6 @@ class BluetoothWorker : private sys::Worker

    void registerQueues();
    void onLinkKeyAdded(const std::string &deviceAddress);
    void removeFromBoundDevices(uint8_t *addr);

    std::shared_ptr<Mailbox<bluetooth::Command, QueueHandle_t, WorkerLock>> workerQueue;


M module-bluetooth/Bluetooth/BtKeysStorage.cpp => module-bluetooth/Bluetooth/BtKeysStorage.cpp +5 -5
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <algorithm>


@@ 14,10 14,10 @@ namespace bluetooth
{
    namespace strings
    {
        constexpr inline auto keys     = "keys";
        constexpr inline auto link_key = "link_key";
        constexpr inline auto bd_addr  = "bd_addr";
        constexpr inline auto type     = "type";
        constexpr auto keys     = "keys";
        constexpr auto link_key = "link_key";
        constexpr auto bd_addr  = "bd_addr";
        constexpr auto type     = "type";
    } // namespace strings

    auto KeyStorage::getKeyStorage() -> btstack_link_key_db_t *

M module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.cpp => module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.cpp +70 -79
@@ 1,77 1,81 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, 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 <log/log.hpp>
#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::btstackRunLoopQueue;
    TaskHandle_t RunLoop::btstackRunLoopTask;
    QueueHandle_t RunLoop::triggerQueue;
    TimerHandle_t RunLoop::testTimer = nullptr;
    TimerHandle_t RunLoop::btstackTimer = nullptr;
    btstack_linked_list_t RunLoop::timers;
    btstack_linked_list_t RunLoop::dataSources;
    bool RunLoop::runLoopExitRequested;

    auto RunLoop::removeTimer(btstack_timer_source_t *ts) -> bool
    bool RunLoop::removeTimer(btstack_timer_source_t *timerSource)
    {
        return btstack_linked_list_remove(&timers, reinterpret_cast<btstack_linked_item_t *>(ts));
        return btstack_linked_list_remove(&timers, reinterpret_cast<btstack_linked_item_t *>(timerSource));
    }

    void RunLoop::setTriggerQueue(QueueHandle_t queue)
    {
        assert(queue != nullptr);
        triggerQueue = queue;
    }

    void RunLoop::deinit()
    {
        vQueueDelete(btstack_run_loop_queue);
        xTimerDelete(testTimer, 0);
        vQueueDelete(btstackRunLoopQueue);
        xTimerDelete(btstackTimer, 0);
    }

    void RunLoop::init()
    {
        timers                 = nullptr;
        btstack_run_loop_queue = xQueueCreate(RUN_LOOP_QUEUE_LENGTH, RUN_LOOP_QUEUE_ITEM_SIZE);
        btstackRunLoopQueue    = xQueueCreate(runLoopQueueLength, runLoopQueueItemSize);

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

        LOG_INFO("Run loop init, task %p, queue item size %u",
                 btstack_run_loop_task,
                 static_cast<int>(sizeof(function_call_t)));
        LOG_INFO("Run loop init, task %p, queue item size %zu", btstackRunLoopTask, sizeof(FunctionCallType));
    }
    void RunLoop::enableDataSourceCallbacks(btstack_data_source_t *ds, uint16_t callback_types)

    void RunLoop::enableDataSourceCallbacks(btstack_data_source_t *dataSource, std::uint16_t callbackTypes)
    {
        ds->flags |= callback_types;
        dataSource->flags |= callbackTypes;
    }

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

    void RunLoop::addDataSource(btstack_data_source_t *ds)
    void RunLoop::addDataSource(btstack_data_source_t *dataSource)
    {
        btstack_linked_list_add(&data_sources, (btstack_linked_item_t *)ds);
        btstack_linked_list_add(&dataSources, reinterpret_cast<btstack_linked_item_t *>(dataSource));
    }

    auto RunLoop::removeDataSource(btstack_data_source_t *ds) -> bool
    auto RunLoop::removeDataSource(btstack_data_source_t *dataSource) -> bool
    {
        return btstack_linked_list_remove(&data_sources, (btstack_linked_item_t *)ds);
        return btstack_linked_list_remove(&dataSources, reinterpret_cast<btstack_linked_item_t *>(dataSource));
    }

    void RunLoop::triggerExit()
    {
        run_loop_exit_requested = true;
        runLoopExitRequested = true;
    }

    auto RunLoop::getTimeMs() -> TickType_t
    {
        return xTaskGetTickCount();
    }

    void RunLoop::trigger()
    {

        bool trigger = true;
        if (triggerQueue != nullptr) {
            xQueueSend(triggerQueue, &trigger, 0);


@@ 80,67 84,55 @@ namespace bluetooth
            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)
    void RunLoop::addTimer(btstack_timer_source_t *timerSource)
    {
        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) {
            // Don't add timer that's already in there
            auto next = reinterpret_cast<btstack_timer_source_t *>(it->next);
            if (next == timerSource) {
                LOG_ERROR("Timer 'btstack_run_loop_timer' already in list!");
                return;
            }
            // exit if new timeout before list timeout
            int32_t delta = btstack_time_delta(ts->timeout, next->timeout);

            // Exit if new timeout before list timeout
            const auto delta = btstack_time_delta(timerSource->timeout, next->timeout);
            if (delta < 0) {
                break;
            }
        }
        ts->item.next = it->next;
        it->next      = reinterpret_cast<btstack_linked_item_t *>(ts);
        timerSource->item.next = it->next;
        it->next               = reinterpret_cast<btstack_linked_item_t *>(timerSource);
        trigger();
    }
    void RunLoop::setTimer(btstack_timer_source_t *ts, uint32_t timeout_in_ms)

    void RunLoop::setTimer(btstack_timer_source_t *timerSource, std::uint32_t timeoutMs)
    {
        ts->timeout = getTimeMs() + timeout_in_ms + 1;
        timerSource->timeout = getTimeMs() + timeoutMs + 1;
        trigger();
    }
    void RunLoop::triggerCallback(TimerHandle_t xTimer)

    void RunLoop::triggerCallback([[maybe_unused]] TimerHandle_t xTimer)
    {
        trigger();
    }

    void RunLoop::start()
    {
        if (testTimer == nullptr) {
            testTimer = xTimerCreate("TestTimer", pdMS_TO_TICKS(1000), pdTRUE, nullptr, triggerCallback);
            xTimerStart(testTimer, 0);
        if (btstackTimer == nullptr) {
            btstackTimer =
                xTimerCreate("BTStackTimer", pdMS_TO_TICKS(defaultTimerPeriodMs), pdTRUE, nullptr, triggerCallback);
            xTimerStart(btstackTimer, 0);
        }
    }

    auto RunLoop::process() -> bool
    {
        // process registered function calls on run loop thread
        // 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);
            FunctionCallType message = {nullptr, nullptr};
            const auto res           = xQueueReceive(btstackRunLoopQueue, &message, 0);
            if (res == pdFALSE) {
                break;
            }


@@ 149,33 141,33 @@ namespace bluetooth
            }
        }

        // process timers and get next timeout
        uint32_t timeout_ms = 1000;
        // Process timers and get next timeout
        std::uint32_t timeoutMs = defaultTimerPeriodMs;
        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;
            auto timerSource   = reinterpret_cast<btstack_timer_source_t *>(timers);
            const auto now     = getTimeMs();
            const auto deltaMs = btstack_time_delta(timerSource->timeout, now);
            if (deltaMs > 0) {
                timeoutMs = deltaMs;
                break;
            }
            // remove timer before processing it to allow handler to re-register with run loop
            removeTimer(ts);
            ts->process(ts);

            // Remove timer before processing it to allow handler to re-register with run loop
            removeTimer(timerSource);
            timerSource->process(timerSource);
        }

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

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

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

        runLoop = btstack_run_loop{
            &init,
            &addDataSource,


@@ 191,5 183,4 @@ namespace bluetooth
        };
        return &runLoop;
    }

} // namespace bluetooth

M module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.hpp => module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.hpp +35 -27
@@ 1,55 1,63 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, 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 <queue.hpp>
#include <timer.hpp>

namespace bluetooth
{

    using function_call_t = struct function_call
    using FunctionCallType = struct FunctionCall
    {
        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);
    inline constexpr auto runLoopQueueLength   = 20;
    inline constexpr auto runLoopQueueItemSize = sizeof(FunctionCallType);

    class RunLoop
    {
      public:
        static void trigger();
        static bool process();
        static void deinit();
        static void setTriggerQueue(QueueHandle_t queue);
        auto getRunLoopInstance() -> btstack_run_loop *;

      private:
        static auto removeTimer(btstack_timer_source_t *ts) -> bool;
        static bool removeTimer(btstack_timer_source_t *timerSource);

        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 enableDataSourceCallbacks(btstack_data_source_t *dataSource, std::uint16_t callbackTypes);
        static void disableDataSourceCallbacks(btstack_data_source_t *dataSource, std::uint16_t callbackTypes);

        static void addDataSource(btstack_data_source_t *dataSource);
        static bool removeDataSource(btstack_data_source_t *dataSource);

        static void triggerExit();

        static auto getTimeMs() -> TickType_t;
        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 setTimer(btstack_timer_source_t *ts, uint32_t timeoutMs);

        static void start();
        static void triggerCallback(TimerHandle_t xTimer);
        static QueueHandle_t btstack_run_loop_queue;
        static TaskHandle_t btstack_run_loop_task;

        static constexpr auto defaultTimerPeriodMs = 1000;

        static QueueHandle_t btstackRunLoopQueue;
        static TaskHandle_t btstackRunLoopTask;
        static QueueHandle_t triggerQueue;
        static TimerHandle_t testTimer;
        static TimerHandle_t btstackTimer;
        static btstack_linked_list_t timers;
        static btstack_linked_list_t data_sources;
        static bool run_loop_exit_requested;
        btstack_run_loop runLoop;
        static btstack_linked_list_t dataSources;
        static bool runLoopExitRequested;

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

} // namespace bluetooth

M module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.cpp => module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.cpp +37 -43
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <bsp/bluetooth/Bluetooth.hpp>


@@ 8,96 8,90 @@ using namespace bsp;

extern "C"
{

#include "btstack_uart_block_rt1051.h"
#include <hci_transport.h>
#include <btstack_run_loop.h>
#include <btstack_uart_block.h>
#include <stddef.h> // for null
#include <btstack_run_loop_freertos.h>
}

    // #define DEBUG_UART
// #define DEBUG_UART

namespace
{
    // and it's hci_transport_config_uart_t which is a bit different...
    static int uart_rt1051_init(const btstack_uart_config_t *config)
    int uart_rt1051_init([[maybe_unused]] const btstack_uart_config_t *config)
    {
        LOG_INFO("Create BlueKitchen interface");
        BlueKitchen::getInstance();
        return 0;
    }

    static int uart_rt1051_open()
    int uart_rt1051_open()
    {
        LOG_INFO("BlueKitchen uart open");
        BlueKitchen::getInstance()->open();
        LOG_INFO("BlueKitchen UART open");
        BlueKitchen::getInstance().open();
        return 0;
    }

    static int uart_rt1051_close()
    int uart_rt1051_close()
    {
        LOG_INFO("BlueKitchen uart close");
        BlueKitchen::getInstance()->close();
        LOG_INFO("BlueKitchen UART close");
        BlueKitchen::getInstance().close();
        return 0;
    }

    static void uart_rt1051_set_block_received(void (*handler)(void))
    void uart_rt1051_set_block_received(void (*handler)())
    {
        BlueKitchen::getInstance()->read_ready_cb = handler;
        BlueKitchen::getInstance().readReadyCallback = handler;
    }

    static void uart_rt1051_set_block_sent(void (*handler)(void))
    void uart_rt1051_set_block_sent(void (*handler)())
    {
        BlueKitchen::getInstance()->write_done_cb = handler;
        BlueKitchen::getInstance().writeDoneCallback = handler;
    }

    static int uart_rt1051_set_baudrate(uint32_t baudrate)
    int uart_rt1051_set_baudrate(std::uint32_t baudrate)
    {
        BlueKitchen::getInstance()->set_baudrate(baudrate);
        BlueKitchen::getInstance().setBaudrate(baudrate);
        return 0;
    }

    static int uart_rt1051_set_parity(int pairity)
    int uart_rt1051_set_parity(int parity)
    {
        // Not implemented
        LOG_INFO("BlueKitchen set pairity: %d", pairity);
        LOG_INFO("BlueKitchen set pairity: %d", parity);
        return 0;
    }

    static int uart_rt1051_set_flowcontrol(int flowcontrol)
    {
        LOG_INFO("BlueKitchen set flowcontrol: %d", flowcontrol);
        // BlueKitchen::getInstance()->set_rts(); ??
        return 0;
    }

    static void uart_rt1051_receive_block(uint8_t *buffer, uint16_t len)
    void uart_rt1051_receive_block(std::uint8_t *buffer, std::uint16_t len)
    {
#ifdef DEBUG_UART
        LOG_DEBUG("<-- read: %d", len);
#endif
        BlueKitchen::getInstance()->read(buffer, len);
        BlueKitchen::getInstance().read(buffer, len);
    }

    static void uart_rt1051_send_block(const uint8_t *buffer, uint16_t length)
    void uart_rt1051_send_block(const uint8_t *buffer, uint16_t length)
    {
#ifdef DEBUG_UART
        LOG_DEBUG("--> write: %d", length);
#endif
        BlueKitchen::getInstance()->write(buffer, length);
        BlueKitchen::getInstance().write(buffer, length);
    }

    static int btstack_uart_rt1051_get_supported_sleep_modes(void)
    int btstack_uart_rt1051_get_supported_sleep_modes()
    {
        return BTSTACK_UART_SLEEP_MASK_RTS_HIGH_WAKE_ON_CTS_PULSE;
    }

    static void btstack_uart_rt1051_set_sleep(btstack_uart_sleep_mode_t sleep_mode)
    void btstack_uart_rt1051_set_sleep([[maybe_unused]] btstack_uart_sleep_mode_t sleep_mode)
    {}

    static void btstack_uart_rt1051_set_wakeup_handler(void (*the_wakeup_handler)(void))
    void btstack_uart_rt1051_set_wakeup_handler([[maybe_unused]] void (*wakeup_handler)())
    {}

    static const btstack_uart_block_t btstack_uart_posix = {
    const btstack_uart_block_t btstack_uart_posix = {
        /* int  (*init)(hci_transport_config_uart_t * config); */ uart_rt1051_init,
        /* int  (*open)(void); */ uart_rt1051_open,
        /* int  (*close)(void); */ uart_rt1051_close,


@@ 105,16 99,16 @@ extern "C"
        /* void (*set_block_sent)(void (*handler)(void)); */ uart_rt1051_set_block_sent,
        /* int  (*set_baudrate)(uint32_t baudrate); */ uart_rt1051_set_baudrate,
        /* int  (*set_parity)(int parity); */ uart_rt1051_set_parity,
        /* int  (*set_flowcontrol)(int flowcontrol); */ NULL, // uart_rt1051_set_flowcontrol,
        /* int  (*set_flowcontrol)(int flowcontrol); */ nullptr,
        /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ uart_rt1051_receive_block,
        /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ uart_rt1051_send_block,
        /* int (*get_supported_sleep_modes); */ &btstack_uart_rt1051_get_supported_sleep_modes,
        /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ &btstack_uart_rt1051_set_sleep,
        /* void (*set_wakeup_handler)(void (*handler)(void)); */ &btstack_uart_rt1051_set_wakeup_handler,
        /* int (*get_supported_sleep_modes)(); */ btstack_uart_rt1051_get_supported_sleep_modes,
        /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ btstack_uart_rt1051_set_sleep,
        /* void (*set_wakeup_handler)(void (*handler)(void)); */ btstack_uart_rt1051_set_wakeup_handler,
    };
} // namespace

    const btstack_uart_block_t *btstack_uart_block_rt1051_instance()
    {
        return &btstack_uart_posix;
    }
};
const btstack_uart_block_t *btstack_uart_block_rt1051_instance()
{
    return &btstack_uart_posix;
}

M module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.h => module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.h +3 -2
@@ 4,10 4,11 @@
extern "C"
{
#endif

#include <btstack_uart_block.h>

    const btstack_uart_block_t *btstack_uart_block_rt1051_instance();
const btstack_uart_block_t *btstack_uart_block_rt1051_instance();

#ifdef __cplusplus
}; // __cplusplus
} // __cplusplus
#endif

M module-bluetooth/Bluetooth/glucode/hal_time_ms.c => module-bluetooth/Bluetooth/glucode/hal_time_ms.c +0 -1
@@ 1,4 1,3 @@
#include "btstack_debug.h"
#include <FreeRTOS.h>
#include <stdint.h>
#include <task.h>

M module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.cpp => module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.cpp +27 -23
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BluetoothDriverImpl.hpp"


@@ 26,7 26,6 @@ extern "C"
extern "C"
{
#include <btstack_uart.h>

#include <btstack_run_loop_posix.h>
#include <btstack_tlv_posix.h>
}


@@ 38,21 37,18 @@ namespace bluetooth
    PowerOnCallback Driver::powerOnCallback = nullptr;

#ifdef TARGET_RT1051
    [[maybe_unused]] auto Driver::runLoopInitTarget(const btstack_run_loop *loop) -> const btstack_uart_block_t *
    auto Driver::runLoopInitTarget(const btstack_run_loop *loop) -> const btstack_uart_block_t *
    {
        btstack_run_loop_init(loop);
        const btstack_uart_block_t *uartDriver = btstack_uart_block_rt1051_instance();
        return uartDriver;
        return btstack_uart_block_rt1051_instance();
    }
#else

    [[maybe_unused]] auto Driver::runLoopInitLinux(const btstack_run_loop *) -> const btstack_uart_block_t *
    auto Driver::runLoopInitLinux([[maybe_unused]] const btstack_run_loop *loop) -> const btstack_uart_block_t *
    {
        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;
        return btstack_uart_block_posix_instance();
    }
#endif



@@ 76,22 72,26 @@ namespace bluetooth
        auto uartDriver = runLoopInitLinux(runLoop);
#endif

        const hci_transport_t *transport = hci_transport_h4_instance_for_uart(uartDriver);
        const auto transport = hci_transport_h4_instance_for_uart(uartDriver);
        hci_init(transport, (void *)&config);

        hci_set_link_key_db(bluetooth::KeyStorage::getKeyStorage());
        hci_event_callback_registration.callback = &hci_packet_handler;
        hci_add_event_handler(&hci_event_callback_registration);
        hciEventCallbackRegistration.callback = &hciPacketHandler;
        hci_add_event_handler(&hciEventCallbackRegistration);

        gap_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO);
        gap_ssp_set_auto_accept(false);

        gap_set_class_of_device(0x64020C);

        LOG_DEBUG("BT worker run success");
        return Result::Code::Success;
    }

    void Driver::hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
    void Driver::hciPacketHandler(std::uint8_t packet_type,
                                  std::uint16_t channel,
                                  std::uint8_t *packet,
                                  std::uint16_t size)
    {
        bd_addr_t addr;
        if (packet_type != HCI_EVENT_PACKET) {


@@ 103,7 103,7 @@ namespace bluetooth
                break;
            }
            gap_local_bd_addr(addr);
            LOG_INFO("BTstack up and running");
            LOG_INFO("BTStack up and running");
            bluetooth::KeyStorage::settings->setValue(bluetooth::Settings::State,
                                                      static_cast<int>(BluetoothStatus::State::On));
            if (powerOnCallback) {


@@ 115,24 115,24 @@ namespace bluetooth
                if (hci_event_command_complete_get_return_parameters(packet)[0] != 0u) {
                    break;
                }
                // terminate, name 248 chars
                // Terminate, name 248 chars
                packet[6 + 248] = 0;
            }
            if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_version_information)) {
                local_version_information_handler(packet);
                localVersionInformationHandler(packet);
            }
            break;
        default:
            break;
        }
    }
    void Driver::local_version_information_handler(uint8_t *packet)
    void Driver::localVersionInformationHandler(uint8_t *packet)
    {
        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);
        const std::uint16_t hci_version    = packet[6];
        const std::uint16_t hci_revision   = little_endian_read_16(packet, 7);
        const std::uint16_t lmp_version    = packet[9];
        const std::uint16_t manufacturer   = little_endian_read_16(packet, 10);
        const std::uint16_t lmp_subversion = little_endian_read_16(packet, 12);
        LOG_INFO("Local version information: HCI Version: 0x%04x, HCI Revision: 0x%04x, LMP Version: 0x%04x, LMP "
                 "Subversion: 0x%04x, Manufacturer: 0x%04x",
                 hci_version,


@@ 169,6 169,7 @@ namespace bluetooth
            break;
        }
    }

    auto Driver::run() -> Result::Code
    {
        auto ret = hci_power_control(HCI_POWER_ON);


@@ 208,18 209,22 @@ namespace bluetooth
                                                  static_cast<int>(BluetoothStatus::State::Off));
        return ret != 0 ? Result::Code::LibraryError : Result::Code::Success;
    }

    auto Driver::scan() -> Result
    {
        return gap->scan();
    }

    void Driver::stopScan()
    {
        gap->stopScan();
    }

    void Driver::setVisibility(bool visibility)
    {
        gap->setVisibility(visibility);
    }

    void Driver::pair(Devicei device, std::uint8_t protectionLevel)
    {
        LOG_INFO("Device: %s, addr: %s", device.name.data(), device.address_str());


@@ 230,5 235,4 @@ namespace bluetooth
    {
        gap->unpair(device);
    }

} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.hpp => module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.hpp +7 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 20,12 20,15 @@ namespace bluetooth
      private:
        static hci_transport_config_uart_t config;
        const btstack_run_loop *runLoop;
        btstack_packet_callback_registration_t hci_event_callback_registration;
        btstack_packet_callback_registration_t hciEventCallbackRegistration;
        std::unique_ptr<bluetooth::GAP> gap;
        static PowerOnCallback powerOnCallback;

        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);
        static void hciPacketHandler(std::uint8_t packet_type,
                                     std::uint16_t channel,
                                     std::uint8_t *packet,
                                     std::uint16_t size);
        static void localVersionInformationHandler(std::uint8_t *packet);
#ifdef TARGET_RT1051
        [[maybe_unused]] auto runLoopInitTarget(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *;
#else

M module-bsp/board/linux/bluetooth/Bluetooth.cpp => module-bsp/board/linux/bluetooth/Bluetooth.cpp +29 -40
@@ 1,31 1,35 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "bsp/bluetooth/Bluetooth.hpp"
#include <log/log.hpp>

/// stubs
#include <memory>

using namespace bsp;

BlueKitchen::BlueKitchen() = default;
BlueKitchen::~BlueKitchen() = default;

BlueKitchen *BlueKitchen::getInstance()
BlueKitchen &BlueKitchen::getInstance()
{
    static BlueKitchen *k = NULL;
    if (k == NULL) {
        k = new BlueKitchen();
    static std::unique_ptr<BlueKitchen> instance;
    if (instance == nullptr) {
        instance = std::make_unique<BlueKitchen>();
    }
    return k;
    return *instance;
}

BluetoothCommon::BluetoothCommon() = default;
BTDevice::Error BlueKitchen::read(std::uint8_t *buf, std::size_t size)
{
    return BTDevice::Error::Success;
}

BlueKitchen::~BlueKitchen()
{}
BTDevice::Error BlueKitchen::write(const std::uint8_t *buf, std::size_t size)
{
    return BTDevice::Error::Success;
}

BluetoothCommon::~BluetoothCommon()
{}
BluetoothCommon::BluetoothCommon()  = default;
BluetoothCommon::~BluetoothCommon() = default;

void BluetoothCommon::open()
{}


@@ 33,48 37,33 @@ void BluetoothCommon::open()
void BluetoothCommon::close()
{}

void BluetoothCommon::sleep_ms(ssize_t ms)
void BluetoothCommon::sleepMs(std::size_t ms)
{
    ulTaskNotifyTake(pdTRUE, ms);
}

BTdev::Error BlueKitchen::read(uint8_t *buf, size_t nbytes)
{
    return Success;
}

BTdev::Error BluetoothCommon::read(uint8_t *buf, size_t nbytes)
{
    return Success;
}

BTdev::Error BlueKitchen::write(const uint8_t *buf, size_t nbytes)
{
    return Success;
}

BTdev::Error BluetoothCommon::write(const uint8_t *buf, size_t nbytes)
BTDevice::Error BluetoothCommon::read(std::uint8_t *buf, std::size_t size)
{
    return Success;
    return BTDevice::Error::Success;
}

ssize_t BluetoothCommon::write_blocking(const uint8_t *buf, ssize_t nbytes)
BTDevice::Error BluetoothCommon::write(const std::uint8_t *buf, std::size_t size)
{
    return 0;
    return BTDevice::Error::Success;
}

BTdev::Error BluetoothCommon::set_baudrate(uint32_t bd)
BTDevice::Error BluetoothCommon::setBaudrate([[maybe_unused]] std::uint32_t baud)
{
    return Success;
    return BTDevice::Error::Success;
}

BTdev::Error BluetoothCommon::set_reset(bool on)
BTDevice::Error BluetoothCommon::setReset([[maybe_unused]] bool on)
{
    return Success;
    return BTDevice::Error::Success;
}

void BluetoothCommon::init_uart()
void BluetoothCommon::uartInit()
{}

void BluetoothCommon::set_irq(bool enable)
void BluetoothCommon::setIrq([[maybe_unused]] bool enable)
{}

M module-bsp/board/rt1051/bluetooth/BlueKitchen.cpp => module-bsp/board/rt1051/bluetooth/BlueKitchen.cpp +22 -29
@@ 1,11 1,9 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "bsp/bluetooth/Bluetooth.hpp"
#include <log/log.hpp>
#include "FreeRTOS.h"
#include "fsl_lpuart.h"
#include "board.h"

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


@@ 17,62 15,57 @@ using namespace bsp;

BlueKitchen::BlueKitchen()
{
    read_buff     = NULL;
    read_ready_cb = NULL;
    write_done_cb = NULL;
    readBuffer        = nullptr;
    readReadyCallback = nullptr;
    writeDoneCallback = nullptr;
}

BlueKitchen::~BlueKitchen() = default;

BlueKitchen *BlueKitchen::getInstance()
BlueKitchen &BlueKitchen::getInstance()
{
    static BlueKitchen *k = NULL;
    if (k == NULL) {
        /// outcomming & incomming heap allocated buffers sizes
        /// packet on IP network cna have MTU 1500, so big enough buffers were added to not throttle comms
        k = new BlueKitchen();
    static std::unique_ptr<BlueKitchen> instance;
    if (instance == nullptr) {
        instance = std::make_unique<BlueKitchen>();
    }
    return k;
    return *instance;
}

BTdev::Error BlueKitchen::read(uint8_t *buf, size_t nbytes)
BTDevice::Error BlueKitchen::read(uint8_t *buf, size_t nbytes)
{
    logHciStack("BlueKitchen requested to read %d bytes", nbytes);

    uint8_t val;
    std::uint8_t val;

    read_buff = buf; // point at the Bt stack read buffer
    read_len  = nbytes;
    readBuffer = buf;
    readLength = nbytes;

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

BTdev::Error BlueKitchen::write(const uint8_t *buf, size_t size)
BTDevice::Error BlueKitchen::write(const uint8_t *buf, size_t size)
{
    uint8_t val;

    logHciStack("BlueKitchen sends %d bytes", size);

    if (BluetoothCommon::write(buf, size) == Success) {
    std::uint8_t val;

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

void BlueKitchen::set_flowcontrol(int on)
{}

M module-bsp/board/rt1051/bluetooth/BluetoothCommon.cpp => module-bsp/board/rt1051/bluetooth/BluetoothCommon.cpp +118 -129
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "bsp/bluetooth/Bluetooth.hpp"


@@ 23,78 23,103 @@

using namespace bsp;

lpuart_edma_handle_t BluetoothCommon::uartDmaHandle = {};
namespace
{
    std::uint32_t uartGetPeripheralClock()
    {
        constexpr auto UART_PERIPHERAL_PLL_DIVIDER = 6;
        std::uint32_t freq;

        /* To make it simple, we assume default PLL and divider settings, and the
         * only variable from application is use PLL3 source or OSC source */
        if (CLOCK_GetMux(kCLOCK_UartMux) == 0) /* PLL3 div6 80M */
        {
            freq =
                (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / UART_PERIPHERAL_PLL_DIVIDER) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
        }
        else {
            freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
        }

        return freq;
    }
} // namespace

uint32_t UartGetPeripheralClock();
lpuart_edma_handle_t BluetoothCommon::uartDmaHandle = {};

BluetoothCommon::BluetoothCommon()
{
    gpio_pin_config_t gpio_init_structure;
    gpio_init_structure.direction     = kGPIO_DigitalOutput;
    gpio_init_structure.interruptMode = kGPIO_NoIntmode;
    gpio_init_structure.outputLogic   = 0;
    GPIO_PinInit(BSP_BLUETOOTH_SHUTDOWN_PORT, BSP_BLUETOOTH_SHUTDOWN_PIN, &gpio_init_structure);
    gpio_pin_config_t gpioConfig;
    gpioConfig.direction     = kGPIO_DigitalOutput;
    gpioConfig.interruptMode = kGPIO_NoIntmode;
    gpioConfig.outputLogic   = 0;
    GPIO_PinInit(BSP_BLUETOOTH_SHUTDOWN_PORT, BSP_BLUETOOTH_SHUTDOWN_PIN, &gpioConfig);
}

BluetoothCommon::~BluetoothCommon() = default;

void BluetoothCommon::open()
{
    init_uart();
    init_uart_dma();
    uartInit();
    uartDmaInit();
    LOG_INFO("Bluetooth HW init done from open!");
    set_irq(true);
    set_reset(true);
    is_open = true;

    setIrq(true);
    setReset(true);
    isOpen = true;
    LOG_INFO("Bluetooth HW open!");
}

void BluetoothCommon::close()
{
    set_irq(false);
    is_open = false;
    set_reset(false);
    deinit_uart_dma();
    deinit_uart();
    setReset(false);
    setIrq(false);
    isOpen = false;

    uartDmaDeinit();
    uartDeinit();
    LOG_INFO("Bluetooth HW close!");
}

void BluetoothCommon::sleep_ms(ssize_t ms)
void BluetoothCommon::sleepMs(std::size_t ms)
{
    ulTaskNotifyTake(pdTRUE, ms);
}

BTdev::Error BluetoothCommon::read(uint8_t *buf, size_t nbytes)
BTDevice::Error BluetoothCommon::read(std::uint8_t *buf, std::size_t size)
{
    auto ret = ErrorUndefined;

    // start RXfer if there is a byte incoming and no pending RXfer
    // Start RXfer if there is a byte incoming and no pending RXfer
    lpuart_transfer_t receiveXfer;
    receiveXfer.data     = buf;
    receiveXfer.dataSize = nbytes;
    receiveXfer.dataSize = size;

    // rx config
    // Rx config
    SCB_CleanInvalidateDCache();
    LPUART_EnableRx(BSP_BLUETOOTH_UART_BASE, true);

    auto status = LPUART_ReceiveEDMA(BSP_BLUETOOTH_UART_BASE, &uartDmaHandle, &receiveXfer);
    const auto status = LPUART_ReceiveEDMA(BSP_BLUETOOTH_UART_BASE, &uartDmaHandle, &receiveXfer);
    switch (status) {
    case kStatus_Success:
        ret = Success;
        break;
    case kStatus_LPUART_RxBusy:
        ret = ErrorBSP;
        LOG_WARN("BT UART RX DMA already busy");
        LOG_WARN("BT UART Rx DMA already busy");
        break;
    case kStatus_InvalidArgument:
        LOG_WARN("BT UART RX DMA invalid argument");
        LOG_WARN("BT UART Rx DMA invalid argument");
        ret = ErrorBSP;
        break;
    default:
        LOG_WARN("Unhandled case, status %ld", status);
        break;
    }
    return ret;
}

BTdev::Error BluetoothCommon::write(const uint8_t *buf, size_t size)
BTDevice::Error BluetoothCommon::write(const std::uint8_t *buf, std::size_t size)
{
    logHciBytes("BT DMA to write --> [%d]>%s<",
                size,


@@ 106,27 131,28 @@ BTdev::Error BluetoothCommon::write(const uint8_t *buf, size_t size)
                    return ss.str();
                }()
                             .c_str());

    auto ret = ErrorUndefined;

    lpuart_transfer_t sendXfer;
    sendXfer.data     = const_cast<uint8_t *>(buf);
    sendXfer.data     = const_cast<std::uint8_t *>(buf);
    sendXfer.dataSize = size;

    uartDmaHandle.userData = xTaskGetCurrentTaskHandle();

    // tx config
    // Tx config
    SCB_CleanInvalidateDCache();
    LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, true);

    auto sent = LPUART_SendEDMA(BSP_BLUETOOTH_UART_BASE, &uartDmaHandle, &sendXfer);
    switch (sent) {
    const auto status = LPUART_SendEDMA(BSP_BLUETOOTH_UART_BASE, &uartDmaHandle, &sendXfer);
    switch (status) {
    case kStatus_Success:
        // orchestrate a DMA Tx
        // Orchestrate a DMA Tx
        logHciComs("DMA Tx started (%d)", size);
        ret = Success;
        break;
    case kStatus_LPUART_TxBusy:
        // could've checked beforehand
        // Could've checked beforehand
        LOG_WARN("Previous DMA Tx is still pending");
        ret = ErrorBSP;
        break;


@@ 135,98 161,59 @@ BTdev::Error BluetoothCommon::write(const uint8_t *buf, size_t size)
        LOG_ERROR("DMA Tx invalid arg");
        ret = ErrorBSP;
        break;
    default:
        LOG_WARN("Unhandled case, status %ld", status);
        break;
    }
    return ret;
}

ssize_t BluetoothCommon::write_blocking(const uint8_t *buf, ssize_t nbytes)
{
    ssize_t ret = -1;

    auto wrote = write(const_cast<uint8_t *>(buf), nbytes);

    if (wrote == nbytes) { // success orchestrating a transfer
        constexpr auto writeBlockingTimeout = pdMS_TO_TICKS(100);
        auto ulNotificationValue            = ulTaskNotifyTake(pdFALSE, writeBlockingTimeout);
        if (ulNotificationValue != 0) { // success completing a transfer
            logHciComs("DMA Tx wrote");
            ret = nbytes;
        }
        else {
            LOG_ERROR("DMA Tx timeout");
            ret = -1;
        }
    }
    else {
        LOG_WARN("DMA Tx not wrote (%d/%d)", wrote, nbytes);
    }
    return ret;
}

BTdev::Error BluetoothCommon::set_baudrate(uint32_t bd)
BTDevice::Error BluetoothCommon::setBaudrate(std::uint32_t baud)
{
    LOG_INFO("Set baudrate: %" PRIu32, bd);
    LOG_INFO("Set baudrate: %" PRIu32, baud);
    Error ret = Success;
    int err   = 0;
    if ((err = LPUART_SetBaudRate(BSP_BLUETOOTH_UART_BASE, bd, UartGetPeripheralClock())) != 0) {
        LOG_ERROR("BT error: baudrate [%lu] set err: %d", bd, err);
    const auto err = LPUART_SetBaudRate(BSP_BLUETOOTH_UART_BASE, baud, uartGetPeripheralClock());
    if (err) {
        LOG_ERROR("BT: baudrate %lu, error %ld", baud, err);
        ret = ErrorBSP;
    }
    BSP_BLUETOOTH_UART_BASE->FIFO |= LPUART_FIFO_RXFLUSH_MASK; // flush fifo
    BSP_BLUETOOTH_UART_BASE->FIFO &= ~LPUART_FIFO_RXFE_MASK;   // disable fifo
    BSP_BLUETOOTH_UART_BASE->FIFO |= LPUART_FIFO_RXFLUSH_MASK; // Flush fifo
    BSP_BLUETOOTH_UART_BASE->FIFO &= ~LPUART_FIFO_RXFE_MASK;   // Disable fifo
    return ret;
}

BTdev::Error BluetoothCommon::set_reset(bool on)
BTDevice::Error BluetoothCommon::setReset(bool on)
{
    if (on) {
        GPIO_PinWrite(BSP_BLUETOOTH_SHUTDOWN_PORT, BSP_BLUETOOTH_SHUTDOWN_PIN, 0);
        // docs: "nSHUTD must be low for a minimum of 5 ms."
        sleep_ms(5 + 2);
        sleepMs(5 + 2); // docs: "nSHUTD must be low for a minimum of 5 ms."
    }
    LOG_INFO("reset %s", on ? "on" : "off");
    LOG_INFO("reset: %s", on ? "on" : "off");
    GPIO_PinWrite(BSP_BLUETOOTH_SHUTDOWN_PORT, BSP_BLUETOOTH_SHUTDOWN_PIN, on ? 1U : 0U);
    return Success;
}

uint32_t UartGetPeripheralClock()
void BluetoothCommon::uartInit()
{
    const int UART_PERIPHERAL_PLL_DIVIDER = 6;
    uint32_t freq                         = 0;
    /* To make it simple, we assume default PLL and divider settings, and the only variable
       from application is use PLL3 source or OSC source */
    if (CLOCK_GetMux(kCLOCK_UartMux) == 0) /* PLL3 div6 80M */
    {
        freq = (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / UART_PERIPHERAL_PLL_DIVIDER) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
    }
    else {
        freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
    }

    return freq;
}

void BluetoothCommon::init_uart()
{
    lpuart_config_t bt_c;
    LPUART_GetDefaultConfig(&bt_c);
    bt_c.baudRate_Bps  = baudrate;
    bt_c.dataBitsCount = kLPUART_EightDataBits;
    bt_c.parityMode    = kLPUART_ParityDisabled;
    bt_c.isMsb         = false;
    bt_c.rxIdleType    = kLPUART_IdleTypeStartBit;
    bt_c.rxIdleConfig  = kLPUART_IdleCharacter1;
    bt_c.enableTx      = false;
    bt_c.enableRx      = false;
    bt_c.enableTxCTS   = true;
    bt_c.txCtsConfig   = kLPUART_CtsSampleAtStart; // to be able to stop TX mid-transfer
    bt_c.enableRxRTS   = true;                     // == BSP_BLUETOOTH_UART_BASE->MODIR |= LPUART_MODIR_RXRTSE_MASK;

    if (LPUART_Init(BSP_BLUETOOTH_UART_BASE, &bt_c, UartGetPeripheralClock()) != kStatus_Success) {
        LOG_ERROR("BT: UART config error Could not initialize the uart!");
    lpuart_config_t uartConfig;
    LPUART_GetDefaultConfig(&uartConfig);
    uartConfig.baudRate_Bps  = defaultBaudRate;
    uartConfig.dataBitsCount = kLPUART_EightDataBits;
    uartConfig.parityMode    = kLPUART_ParityDisabled;
    uartConfig.isMsb         = false;
    uartConfig.rxIdleType    = kLPUART_IdleTypeStartBit;
    uartConfig.rxIdleConfig  = kLPUART_IdleCharacter1;
    uartConfig.enableTx      = false;
    uartConfig.enableRx      = false;
    uartConfig.enableTxCTS   = true;
    uartConfig.txCtsConfig   = kLPUART_CtsSampleAtStart; // To be able to stop TX mid-transfer
    uartConfig.enableRxRTS   = true; // == BSP_BLUETOOTH_UART_BASE->MODIR |= LPUART_MODIR_RXRTSE_MASK;

    if (LPUART_Init(BSP_BLUETOOTH_UART_BASE, &uartConfig, uartGetPeripheralClock()) != kStatus_Success) {
        LOG_ERROR("BT: UART config error, could not initialize!");
        return;
    }
    BSP_BLUETOOTH_UART_BASE->MODIR |= LPUART_MODIR_TXRTSPOL_MASK; // apparently docs are not clear here. HIGH during TX
    BSP_BLUETOOTH_UART_BASE->MODIR |= LPUART_MODIR_TXRTSPOL_MASK; // Apparently docs are not clear here. HIGH during Tx

    LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, 0xFFFFFFFF);
    NVIC_ClearPendingIRQ(LPUART2_IRQn);


@@ 234,18 221,18 @@ void BluetoothCommon::init_uart()
    NVIC_EnableIRQ(LPUART2_IRQn);
}

void BluetoothCommon::init_uart_dma()
void BluetoothCommon::uartDmaInit()
{
    dmamux = drivers::DriverDMAMux::Create(static_cast<drivers::DMAMuxInstances>(BoardDefinitions::BLUETOOTH_DMAMUX),
                                           drivers::DriverDMAMuxParams{});
    dma    = drivers::DriverDMA::Create(static_cast<drivers::DMAInstances>(BoardDefinitions::BLUETOOTH_DMA),
                                     drivers::DriverDMAParams{});

    uartTxDmaHandle = dma->CreateHandle(static_cast<uint32_t>(BoardDefinitions::BLUETOOTH_TX_DMA_CHANNEL));
    uartRxDmaHandle = dma->CreateHandle(static_cast<uint32_t>(BoardDefinitions::BLUETOOTH_RX_DMA_CHANNEL));
    uartTxDmaHandle = dma->CreateHandle(static_cast<std::uint32_t>(BoardDefinitions::BLUETOOTH_TX_DMA_CHANNEL));
    uartRxDmaHandle = dma->CreateHandle(static_cast<std::uint32_t>(BoardDefinitions::BLUETOOTH_RX_DMA_CHANNEL));

    dmamux->Enable(static_cast<uint32_t>(BoardDefinitions::BLUETOOTH_TX_DMA_CHANNEL), kDmaRequestMuxLPUART2Tx);
    dmamux->Enable(static_cast<uint32_t>(BoardDefinitions::BLUETOOTH_RX_DMA_CHANNEL), kDmaRequestMuxLPUART2Rx);
    dmamux->Enable(static_cast<std::uint32_t>(BoardDefinitions::BLUETOOTH_TX_DMA_CHANNEL), kDmaRequestMuxLPUART2Tx);
    dmamux->Enable(static_cast<std::uint32_t>(BoardDefinitions::BLUETOOTH_RX_DMA_CHANNEL), kDmaRequestMuxLPUART2Rx);

    LPUART_TransferCreateHandleEDMA(BSP_BLUETOOTH_UART_BASE,
                                    &uartDmaHandle,


@@ 255,7 242,7 @@ void BluetoothCommon::init_uart_dma()
                                    reinterpret_cast<edma_handle_t *>(uartRxDmaHandle->GetHandle()));
}

void BluetoothCommon::deinit_uart()
void BluetoothCommon::uartDeinit()
{
    LPUART_EnableRx(BSP_BLUETOOTH_UART_BASE, false);
    LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, false);


@@ 268,40 255,42 @@ void BluetoothCommon::deinit_uart()
    LPUART_Deinit(BSP_BLUETOOTH_UART_BASE);
}

void BluetoothCommon::deinit_uart_dma()
void BluetoothCommon::uartDmaDeinit()
{
    dmamux->Disable(static_cast<uint32_t>(BoardDefinitions::BLUETOOTH_RX_DMA_CHANNEL));
    dmamux->Disable(static_cast<uint32_t>(BoardDefinitions::BLUETOOTH_TX_DMA_CHANNEL));
    dmamux->Disable(static_cast<std::uint32_t>(BoardDefinitions::BLUETOOTH_RX_DMA_CHANNEL));
    dmamux->Disable(static_cast<std::uint32_t>(BoardDefinitions::BLUETOOTH_TX_DMA_CHANNEL));
}

void BluetoothCommon::uartDmaCallback(LPUART_Type *base, lpuart_edma_handle_t *handle, status_t status, void *userData)
{
    BaseType_t taskwoken = 0;
    uint8_t val;
    bsp::BlueKitchen *bt = bsp::BlueKitchen::getInstance();
    std::uint8_t val;
    BaseType_t xHigherPriorityTaskWoken = 0;
    auto &blueKitchen                   = bsp::BlueKitchen::getInstance();

    switch (status) {
    case kStatus_LPUART_TxIdle: {
        logHciComs("DMA irq: TX done");
        logHciComs("DMA IRQ: TX done");
        LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, false);
        val = bluetooth::Message::EvtSent;
        xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
        portEND_SWITCHING_ISR(taskwoken);
        xQueueSendFromISR(blueKitchen.qHandle, &val, &xHigherPriorityTaskWoken);
        portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
        break;
    }
    case kStatus_LPUART_RxIdle:
        logHciComs("DMA irq: RX done");
        logHciComs("DMA IRQ: RX done");
        LPUART_EnableRx(BSP_BLUETOOTH_UART_BASE, false);
        val = bluetooth::Message::EvtReceived;
        xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
        portEND_SWITCHING_ISR(taskwoken);
        xQueueSendFromISR(blueKitchen.qHandle, &val, &xHigherPriorityTaskWoken);
        portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
        break;
    default:
        logHciComs("DMA IRQ: unhandled case");
        break;
    }
}

void BluetoothCommon::set_irq(bool enable)
void BluetoothCommon::setIrq(bool enable)
{
    // printf("%s\n", __FUNCTION__);
    LPUART_EnableRx(BSP_BLUETOOTH_UART_BASE, false);
    LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, false);
    LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, 0xFFFFFFFF);


@@ 317,18 306,18 @@ extern "C"
{
    void LPUART2_IRQHandler(void)
    {
        uint32_t isrReg      = LPUART_GetStatusFlags(BSP_BLUETOOTH_UART_BASE);
        BaseType_t taskwoken = 0;
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        uint8_t val          = bluetooth::Message::EvtReceived;
        bsp::BlueKitchen *bt = bsp::BlueKitchen::getInstance();
        uint32_t isrReg                     = LPUART_GetStatusFlags(BSP_BLUETOOTH_UART_BASE);
        bsp::BlueKitchen &blueKitchen       = bsp::BlueKitchen::getInstance();

        if (isrReg & kLPUART_RxDataRegFullFlag) {
            LOG_WARN("Bluetooth IRQ RX full");
            LOG_WARN("Bluetooth IRQ Rx full");
        }
        if (isrReg & kLPUART_RxOverrunFlag) {
            LOG_WARN("Bluetooth IRQ RX overrun");
            LOG_WARN("Bluetooth IRQ Rx overrun");
            val = bluetooth::Message::EvtUartError;
            xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
            xQueueSendFromISR(blueKitchen.qHandle, &val, &xHigherPriorityTaskWoken);
        }
        LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, isrReg);
    }

D module-bsp/board/rt1051/bluetooth/Bluetopia.cpp => module-bsp/board/rt1051/bluetooth/Bluetopia.cpp +0 -57
@@ 1,57 0,0 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "bluetooth/Bluetooth.hpp"
#include <log/log.hpp>
#include "fsl_lpuart.h"
#include "board.h"

namespace bsp
{

    Bluetopia::Bluetopia(unsigned int in_size, unsigned int out_size, int threshold)
        : BluetoothCommon(default_buff_size, default_buff_size, 32)
    {}

    Bluetopia::~Bluetopia()
    {}

    Bluetopia *Bluetopia::getInstance()
    {
        static Bluetopia *inst = NULL;
        if (inst == NULL) {
            inst = new Bluetopia();
        }
        return inst;
    }

    ssize_t Bluetopia::read(void *, size_t nbytes)
    {
        LOG_INFO("not implemented");
        return 0;
    }

    extern "C"
    {
        void LPUART2_IRQHandler(void)
        {
            uint32_t isrReg               = LPUART_GetStatusFlags(BSP_BLUETOOTH_UART_BASE);
            static char characterReceived = 0;

            if (isrReg & kLPUART_RxDataRegFullFlag) {
                characterReceived  = LPUART_ReadByte(BSP_BLUETOOTH_UART_BASE);
                bsp::Bluetopia *bt = bsp::Bluetopia::getInstance();
                if (bt->in.push(characterReceived) == 0) {
                    bt->set_data();
                }
                if (bt->in.threshold_guard()) {
                    bt->set_rts(false);
                }
            }
            // TODO ths should be handled - othervise uart might be `nicelly` blocked
            if (isrReg & kLPUART_RxOverrunFlag) {
                printf("Overrun\n");
            }
            LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, isrReg);
        }
    };

M module-bsp/bsp/bluetooth/Bluetooth.cpp => module-bsp/bsp/bluetooth/Bluetooth.cpp +8 -15
@@ 1,25 1,18 @@
#include "Bluetooth.hpp"
#include <cstdarg>

namespace bsp
{
    BTDevice::BTDevice() : logLevel{LogNone}, isOpen{false}, logFunction{nullptr}
    {}

namespace bsp {
    BTdev::BTdev() : flog(nullptr)
    void BTDevice::log(LogLevel level, const char *val, ...)
    {
        is_open = false;
    }

    BTdev::~BTdev()
    {
    }

    void BTdev::log(LogLvl lvl,const char* val, ...)
    {
        if(loglvl>=lvl && flog) {
        if ((logLevel >= level) && (logFunction != nullptr)) {
            va_list args;
            va_start(args, val);
            flog(val,args);
            logFunction(val, args);
            va_end(args);
        }
    }

};
}

M module-bsp/bsp/bluetooth/Bluetooth.hpp => module-bsp/bsp/bluetooth/Bluetooth.hpp +90 -84
@@ 1,7 1,7 @@
#pragma once

#include <cstdint>      // uint32
#include <sys/types.h>  // ssize_t
#include <cstdint>
#include <sys/types.h>
#include <cstdarg>
#include <FreeRTOS.h>
#include <thread.hpp>


@@ 13,10 13,10 @@
#include "drivers/dma/DriverDMA.hpp"
#endif

/// c++ low level driver overlay

namespace bsp {
/// C++ low level driver overlay

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


@@ 34,95 34,101 @@ namespace bsp {
        };
    }

    class BTdev {
        public:
            enum Error {
                Success,
                ErrorUndefined,
                ErrorTimeout,
                ErrorBSP,
            };
            enum LogLvl {
                LogNone,
                LogError,
                LogWarning,
                LogDebug,
            };
            typedef int(*LogFoo)(const char*,va_list args);
        private:
            LogFoo flog;
        public:
            LogLvl loglvl;
            bool is_open;
            static const unsigned int default_timeout_ms = 1000;
            static const unsigned int default_buff_size = 1024;
            static const unsigned int default_baudrate = 115200;

            BTdev();
            virtual ~BTdev();

            // general
            virtual void open() = 0;    // enable device -> irq enable
            virtual void close() = 0;   // disable device -> irq disable
            virtual BTdev::Error read(uint8_t *buf, size_t nbytes) = 0;
            void log(LogLvl lvl,const char* val, ...);
            // uart specific
    class BTDevice
    {
      public:
        enum Error
        {
            Success,
            ErrorUndefined,
            ErrorTimeout,
            ErrorBSP,
        };

        enum LogLevel
        {
            LogNone,
            LogError,
            LogWarning,
            LogDebug,
        };

        using LogFunction = int (*)(const char *msg, va_list args);

        BTDevice();
        virtual ~BTDevice() = default;

        virtual void open() = 0;    // enable device -> irq enable
        virtual void close() = 0;   // disable device -> irq disable

        virtual Error read(std::uint8_t *buf, std::size_t size) = 0;

        void log(LogLevel level, const char *msg, ...);

        LogLevel logLevel;
        bool isOpen;

      private:
        LogFunction logFunction;
    };

    class BluetoothCommon : public BTdev
    class BluetoothCommon : public BTDevice
    {
        public:
            static const ssize_t baudrate =115200;
            static const ssize_t off_threshold =16;
            static const ssize_t on_threshold =32;

            BluetoothCommon();
            virtual ~BluetoothCommon();
            // uart specific Common part
            virtual void open() override;
            virtual void close() override;
            virtual BTdev::Error read(uint8_t *buf, size_t nbytes) override;
            virtual BTdev::Error write(const uint8_t *buf, size_t nbytes);
            virtual ssize_t write_blocking(const uint8_t *buf, ssize_t nbytes);
            Error set_baudrate(uint32_t bd);
            Error set_reset(bool on);
            void sleep_ms(ssize_t ms);
            void set_irq(bool enable);

        private:
            void init_uart();
            void deinit_uart();
            void init_uart_dma();
            void deinit_uart_dma();
      public:
        static constexpr std::uint32_t defaultBaudRate = 115200;

        BluetoothCommon();
        virtual ~BluetoothCommon();

        // uart specific Common part
        virtual void open() override;
        virtual void close() override;

        virtual Error read(std::uint8_t *buf, std::size_t size) override;
        virtual Error write(const std::uint8_t *buf, std::size_t size);

        Error setBaudrate(std::uint32_t baud);
        Error setReset(bool on);
        void setIrq(bool enable);

        void sleepMs(std::size_t ms);

      private:
        void uartInit();
        void uartDeinit();

        void uartDmaInit();
        void uartDmaDeinit();

#if defined(TARGET_RT1051)
            std::shared_ptr<drivers::DriverDMAMux> dmamux;
            std::shared_ptr<drivers::DriverDMA> dma;
            std::unique_ptr<drivers::DriverDMAHandle> uartRxDmaHandle;
            std::unique_ptr<drivers::DriverDMAHandle> uartTxDmaHandle;
            static AT_NONCACHEABLE_SECTION_INIT(lpuart_edma_handle_t uartDmaHandle);
            static void uartDmaCallback(LPUART_Type *base, lpuart_edma_handle_t *handle, status_t status, void *userData);
        std::shared_ptr<drivers::DriverDMAMux> dmamux;
        std::shared_ptr<drivers::DriverDMA> dma;
        std::unique_ptr<drivers::DriverDMAHandle> uartRxDmaHandle;
        std::unique_ptr<drivers::DriverDMAHandle> uartTxDmaHandle;
        static AT_NONCACHEABLE_SECTION_INIT(lpuart_edma_handle_t uartDmaHandle);

        static void uartDmaCallback(LPUART_Type *base, lpuart_edma_handle_t *handle, status_t status, void *userData);
#endif
    };

    /// definitions needed by BT stack
    /// Definitions needed by BT stack
    class BlueKitchen : public BluetoothCommon
    {
      public:
        BlueKitchen();
        virtual ~BlueKitchen();
        static BlueKitchen &getInstance();

    class BlueKitchen : public BluetoothCommon {
        public:
            BlueKitchen();
            virtual ~BlueKitchen();
            static BlueKitchen *getInstance();
        virtual Error read(uint8_t *buf, size_t size) override;
        virtual Error write(const uint8_t *buf, size_t size) override;

            virtual BTdev::Error read(uint8_t *buf, size_t nbytes) override;
            virtual BTdev::Error write(const uint8_t *buf, size_t size) override;
            uint32_t read_len = 0;
            uint8_t* read_buff;
        std::uint32_t readLength = 0;
        std::uint8_t *readBuffer;

            void set_flowcontrol(int on);
        void (*readReadyCallback)();
        void (*writeDoneCallback)();

            void (*read_ready_cb)(void);
            void (*write_done_cb)(void);
            /// to be able to trigger events on thread
            xQueueHandle qHandle = nullptr;
        /// to be able to trigger events on thread
        xQueueHandle qHandle = nullptr;
    };
};
}

M module-bsp/drivers/dma/DriverDMA.hpp => module-bsp/drivers/dma/DriverDMA.hpp +3 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef PUREPHONE_DRIVERDMA_HPP


@@ 9,7 9,6 @@

namespace drivers
{

    enum class DMAInstances
    {
        DMA_0,


@@ 22,6 21,8 @@ namespace drivers
    class DriverDMAHandle
    {
      public:
        virtual ~DriverDMAHandle() = default;

        virtual void *GetHandle() = 0;
    };


M module-utils/log/api/log/debug.hpp => module-utils/log/api/log/debug.hpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 13,7 13,7 @@
#define DEBUG_GUI_TEXT               0 /// show basic debug messages for gui::Text - warning this can be hard on cpu
#define DEBUG_GUI_TEXT_LINES         0 /// show extended debug messages for gui::Text - lines building
#define DEBUG_GUI_TEXT_CURSOR        0 /// show extended debug messages for gui::Text - cursor handling
#define DEBUG_HEAP_ALLOCATIONS       0 /// gather heap allocations statictics
#define DEBUG_HEAP_ALLOCATIONS       0 /// gather heap allocations statistics
#define DEBUG_INPUT_EVENTS           0 /// show input events prints in system
#define DEBUG_MISSING_ASSETS         0 /// show debug concerning missing assets
#define DEBUG_SCOPED_TIMINGS         0 /// show timings in measured functions