~aleteoryx/muditaos

8df9b22ac9761e013ee5efa08439bc2227e17194 — Mateusz Grzywacz 5 years ago aff3b75
[EGD-4582] Bluetooth over DMA (#1115)

[EGD-4582] Bluetooth UART: replace polling with DMA
M changelog.md => changelog.md +3 -0
@@ 6,6 6,9 @@
### Added
* `[utils]` Dump logs to a file on RT1051 after reaching 80% of log buffer utilization.

### Changed
* `[bluetooth]` Underlying communication with the Bluetooth module over DMA (direct access)

[Current release]

### Added

M module-bluetooth/Bluetooth/BluetoothWorker.cpp => module-bluetooth/Bluetooth/BluetoothWorker.cpp +36 -29
@@ 11,6 11,19 @@ extern "C"
#include "module-bluetooth/lib/btstack/src/btstack_util.h"
};

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

#if DEBUG_BLUETOOTH_HCI_BYTES == 1
#include <sstream>
#define logHciBytes(...) LOG_DEBUG(__VA_ARGS__)
#else
#define logHciBytes(...)
#endif

using namespace bsp;

const char *c_str(Bt::Error::Code code)


@@ 110,8 123,6 @@ bool BluetoothWorker::start_pan()
    return false;
}

#include <sstream>

bool BluetoothWorker::handleMessage(uint32_t queueID)
{



@@ 127,51 138,47 @@ bool BluetoothWorker::handleMessage(uint32_t queueID)

    Bt::Message notification = Bt::Message::EvtErrorRec;
    if (xQueueReceive(queue, &notification, 0) != pdTRUE) {
        LOG_ERROR("Receive failure!");
        LOG_ERROR("Queue receive failure!");
        return false;
    }
    auto bt = BlueKitchen::getInstance();
    switch (notification) {
    case Bt::Message::EvtSending:
        logHciComs("[evt] sending");
        break;
    case Bt::Message::EvtSent:
#ifdef DO_DEBUG_HCI_COMS
        LOG_INFO("[evt] sent");
#endif
        logHciComs("[evt] sent");
        if (bt->write_done_cb) {
            bt->write_done_cb();
        }
        break;
    case Bt::Message::EvtReceiving:
        logHciComs("[evt] receiving");
        break;
    case Bt::Message::EvtReceived: {
        if (bt->to_read_req > bt->in.len) {
            // LOG_ERROR("%d vs %d", bt->to_read_req, bt->in.len);
            break;
        }
        for (int i = 0; i < bt->to_read_req; ++i) {
            // error in pop should never happen
            if (int ret = bt->in.pop((char *)bt->read_buff + i)) {
                LOG_ERROR("This shall never happen: %d", ret);
            }
        }
        // LOG_DEBUG(">> %d",bt->in.len);
#ifdef DO_DEBUG_HCI_COMS
        std::stringstream ss;
        for (int i = 0; i < bt->to_read_req; ++i) {
            ss << " 0x" << std::hex << (int)*(bt->read_buff + i);
        }
        LOG_DEBUG("[evt] recieved <-- [%d]>%s<", bt->to_read_req, ss.str().c_str());
#endif
        bt->to_read_req = 0;
        logHciBytes("[evt] BT DMA received <-- [%ld]>%s<",
                    bt->read_len,
                    [&]() -> std::string {
                        std::stringstream ss;
                        for (int i = 0; i < bt->read_len; ++i) {
                            ss << " 0x" << std::hex << (int)*(bt->read_buff + i);
                        }
                        return ss.str();
                    }()
                                 .c_str());

        bt->read_len = 0;

        if (bt->read_ready_cb) {
            bt->read_ready_cb();
        }
    } break;
    case Bt::Message::EvtSentError:
    case Bt::Message::EvtRecError:
    case Bt::Message::EvtSendingError:
    case Bt::Message::EvtReceivingError:
    case Bt::Message::EvtUartError:
    case Bt::Message::EvtRecUnwanted: {
    case Bt::Message::EvtRecUnwanted:
        LOG_ERROR("Uart error [%d]: %s", notification, Bt::MessageCstr(notification));
        break;
    } break;
    default:
        LOG_ERROR("ERROR");
    }

M module-bluetooth/Bluetooth/BluetoothWorker.hpp => module-bluetooth/Bluetooth/BluetoothWorker.hpp +13 -11
@@ 22,13 22,15 @@ namespace Bt
    enum Message : uint8_t
    {
        /// asynchronous messages to use on event from irq
        EvtSent,        /// trigger Bt stack wrote, enable writting in HCI in BluetoothWorker task
        EvtRecUnwanted, /// not requested recieve - probably receive came to fast from sent...
        EvtRecError,    /// bsp error on receive
        EvtSentError,   /// bsp error on send
        EvtUartError,   /// generic uart error
        EvtReceived,    /// trigger Bt stack received, start processing HCI in BluetoothWorker task
        EvtErrorRec,    /// there was error o queue receive
        EvtSending,        /// Bt stack ordered a write transaction and it is pending
        EvtSent,           /// trigger Bt stack wrote, enable writting in HCI in BluetoothWorker task
        EvtSendingError,   /// bsp error on send
        EvtReceiving,      /// Bt stack requested a receive transaction and it is pending
        EvtReceived,       /// trigger Bt stack received, start processing HCI in BluetoothWorker task
        EvtRecUnwanted,    /// not requested recieve - probably receive came to fast from sent...
        EvtReceivingError, /// bsp error on receive
        EvtUartError,      /// generic uart error
        EvtErrorRec,       /// there was error o queue receive
    };

    inline const char *MessageCstr(Message what)


@@ 40,10 42,10 @@ namespace Bt
            return "EvtSent";
        case EvtRecUnwanted:
            return "EvtRecUnwanted";
        case EvtRecError:
            return "EvtRecError";
        case EvtSentError:
            return "EvtSentError";
        case EvtReceivingError:
            return "EvtReceivingError";
        case EvtSendingError:
            return "EvtSendingError";
        case EvtUartError:
            return "EvtUartError";
        case EvtErrorRec:

M module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.cpp => module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.cpp +1 -1
@@ 83,7 83,7 @@ extern "C"
#ifdef DEBUG_UART
        LOG_INFO("--> write: %d", length);
#endif
        BlueKitchen::getInstance()->write_blocking((char *)buffer, length);
        BlueKitchen::getInstance()->write(buffer, length);
    }

    static const btstack_uart_block_t btstack_uart_posix = {

M module-bsp/board/linux/bluetooth/Bluetooth.cpp => module-bsp/board/linux/bluetooth/Bluetooth.cpp +13 -42
@@ 9,22 9,7 @@

using namespace bsp;

void BTdev::_circ::sem_take()
{}
void BTdev::_circ::sem_give()
{}

BTdev::_circ::_circ(unsigned int size, int threshold) : head(0), tail(0), threshold(threshold), size(size), len(0)
{
    buff = new char[size];
}
BTdev::_circ::~_circ()
{
    delete[] buff;
}

BlueKitchen::BlueKitchen(unsigned int in_size, unsigned int out_size) : BluetoothCommon(in_size, out_size)
{}
BlueKitchen::BlueKitchen() = default;

BlueKitchen *BlueKitchen::getInstance()
{


@@ 35,14 20,7 @@ BlueKitchen *BlueKitchen::getInstance()
    return k;
}

ssize_t BlueKitchen::write_blocking(char *buf, ssize_t len)
{
    return 0;
}

BluetoothCommon::BluetoothCommon(unsigned int in_size, unsigned int out_size, int threshold)
    : BTdev(in_size, out_size, threshold)
{}
BluetoothCommon::BluetoothCommon() = default;

BlueKitchen::~BlueKitchen()
{}


@@ 61,40 39,39 @@ void BluetoothCommon::sleep_ms(ssize_t ms)
    ulTaskNotifyTake(pdTRUE, ms);
}

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

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

ssize_t BluetoothCommon::write_blocking(char *buf, ssize_t len)
BTdev::Error BlueKitchen::write(const uint8_t *buf, size_t nbytes)
{
    return 0;
    return Success;
}

BTdev::Error BluetoothCommon::set_baudrate(uint32_t bd)
BTdev::Error BluetoothCommon::write(const uint8_t *buf, size_t nbytes)
{
    return Success;
}

// set flow on -> true, set flow off -> false
BTdev::Error BluetoothCommon::set_rts(bool on)
ssize_t BluetoothCommon::write_blocking(const uint8_t *buf, ssize_t nbytes)
{
    return Success;
    return 0;
}

BTdev::Error BluetoothCommon::set_reset(bool on)
BTdev::Error BluetoothCommon::set_baudrate(uint32_t bd)
{
    return Success;
}

int BluetoothCommon::read_cts()
BTdev::Error BluetoothCommon::set_reset(bool on)
{
    return 0;
    return Success;
}

void BluetoothCommon::configure_uart_io()


@@ 108,9 85,3 @@ void BluetoothCommon::configure_cts_irq()

void BluetoothCommon::set_irq(bool enable)
{}

ssize_t BlueKitchen::read(void *buf, size_t nbytes)
{
    return 0;
}


M module-bsp/board/rt1051/bluetooth/BlueKitchen.cpp => module-bsp/board/rt1051/bluetooth/BlueKitchen.cpp +37 -80
@@ 8,15 8,19 @@
#include "fsl_lpuart.h"
#include "board.h"

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

using namespace bsp;

BlueKitchen::BlueKitchen(unsigned int in_size, unsigned int out_size) : BluetoothCommon(in_size, out_size)
BlueKitchen::BlueKitchen()
{
    to_read       = 0;
    read_buff     = NULL;
    read_ready_cb = NULL;
    write_done_cb = NULL;
    in.threshold  = 128;
}

BlueKitchen::~BlueKitchen()


@@ 28,96 32,49 @@ BlueKitchen *BlueKitchen::getInstance()
    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(2048, 8000);
        k = new BlueKitchen();
    }
    return k;
}

// request... from circ buffer
ssize_t BlueKitchen::read(void *buf, size_t nbytes)
{
    set_rts(false);
    to_read     = nbytes;
    to_read_req = nbytes;
    read_buff   = reinterpret_cast<char *>(buf);
    // set bt ptr to 0, len to 0, to read to nbytes
    // bt->to_read
    BaseType_t taskwoken = 0;
    uint8_t val          = Bt::Message::EvtReceived;
    if ((to_read != 0) && (in.len >= to_read)) {
        to_read = 0;
        if (qHandle) {
            xQueueSendFromISR(qHandle, &val, &taskwoken);
            portEND_SWITCHING_ISR(taskwoken);
        }
    }
    set_rts(true);
    return 0;
}

void BlueKitchen::set_flowcontrol(int on)
BTdev::Error BlueKitchen::read(uint8_t *buf, size_t nbytes)
{
    // TODO
}
    logHciStack("BlueKitchen requested to read %d bytes", nbytes);

#include <sstream>
    uint8_t val;

ssize_t BlueKitchen::write_blocking(char *buf, ssize_t size)
{
    ssize_t i            = 0;
    BaseType_t taskwoken = 0;
    uint8_t val          = Bt::Message::EvtSent;
    read_buff = buf; // point at the Bt stack read buffer
    read_len  = nbytes;

#ifdef DO_DEBUG_HCI_COMS
    std::stringstream ss;
    for (int i = 0; i < size; ++i) {
        ss << " 0x" << std::hex << (int)buf[i];
    }
    LOG_DEBUG("--> [%d]>%s<", size, ss.str().c_str());
#endif
    if (BluetoothCommon::write_blocking(buf, size) == size) {
        xQueueSendFromISR(qHandle, &val, &taskwoken);
        portEND_SWITCHING_ISR(taskwoken);
    if (BluetoothCommon::read(buf, nbytes) == Success) {
        val = Bt::Message::EvtReceiving;
        xQueueSend(qHandle, &val, portMAX_DELAY);
        return BTdev::Success;
    }
    else {
        val = Bt::Message::EvtSentError;
        xQueueSendFromISR(qHandle, &val, &taskwoken);
        val = Bt::Message::EvtReceivingError;
        xQueueSend(qHandle, &val, portMAX_DELAY);
        return BTdev::ErrorBSP;
    }

    return i;
}

extern "C"
BTdev::Error BlueKitchen::write(const uint8_t *buf, size_t size)
{
    void LPUART2_IRQHandler(void)
    {
        uint32_t isrReg               = LPUART_GetStatusFlags(BSP_BLUETOOTH_UART_BASE);
        static char characterReceived = 0;
        BaseType_t taskwoken          = 0;
        uint8_t val                   = Bt::Message::EvtReceived;
        bsp::BlueKitchen *bt          = bsp::BlueKitchen::getInstance();
    uint8_t val;

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

        if (isrReg & kLPUART_RxDataRegFullFlag) {
            characterReceived = LPUART_ReadByte(BSP_BLUETOOTH_UART_BASE);
            if (bt->in.push(characterReceived)) {
                val = Bt::Message::EvtRecUnwanted;
                xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
            }
            if (bt->to_read != 0 && (bt->in.len >= bt->to_read)) {
                bt->to_read = 0;
                assert(bt->qHandle);
                val = Bt::Message::EvtReceived;
                xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
                portEND_SWITCHING_ISR(taskwoken);
            }
            if (bt->in.threshold_guard()) {
                bt->set_rts(false);
            }
        }
        if (isrReg & kLPUART_RxOverrunFlag) {
            val = Bt::Message::EvtUartError;
            xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
        }
        LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, isrReg);
    if (BluetoothCommon::write(buf, size) == Success) {
        val = Bt::Message::EvtSending;
        xQueueSend(qHandle, &val, portMAX_DELAY);
        return BTdev::Success;
    }
    else {
        val = Bt::Message::EvtSendingError;
        xQueueSend(qHandle, &val, portMAX_DELAY);
        return BTdev::ErrorBSP;
    }
};
}

void BlueKitchen::set_flowcontrol(int on)
{}

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

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

using namespace bsp;

// TODO it's plain copy same as in cellular - this is kind of wrong
uint32_t UartGetPeripheralClock();
#if DEBUG_BLUETOOTH_HCI_COMS == 1
#define logHciComs(...) LOG_DEBUG(__VA_ARGS__)
#else
#define logHciComs(...)
#endif

void BTdev::_circ::sem_take()
{
    if (!(SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)) {
        xSemaphoreTake(sem, 0);
    }
    else {
        BaseType_t px;
        xSemaphoreTakeFromISR(sem, &px);
    }
}
#if DEBUG_BLUETOOTH_HCI_BYTES == 1
#include <sstream>
#define logHciBytes(...) LOG_DEBUG(__VA_ARGS__)
#else
#define logHciBytes(...)
#endif

void BTdev::_circ::sem_give()
{
    if (!(SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)) {
        xSemaphoreGive(sem);
    }
    else {
        BaseType_t px;
        xSemaphoreGiveFromISR(sem, &px);
    }
}
using namespace bsp;

BTdev::_circ::_circ(unsigned int size, int threshold) : head(0), tail(0), threshold(threshold), size(size), len(0)
{
    buff = new char[size];
    sem  = xSemaphoreCreateBinary();
}
lpuart_edma_handle_t BluetoothCommon::uartDmaHandle = {};

BTdev::_circ::~_circ()
{
    vSemaphoreDelete(sem);
    delete[] buff;
}
uint32_t UartGetPeripheralClock();

BluetoothCommon::BluetoothCommon(unsigned int in_size, unsigned int out_size, int threshold)
    : BTdev(in_size, out_size, threshold)
BluetoothCommon::BluetoothCommon()
{
    configure_uart_io();
    configure_lpuart();


@@ 61,17 42,14 @@ BluetoothCommon::~BluetoothCommon()
void BluetoothCommon::open()
{
    LOG_INFO("Bluetooth HW open!");
    set_reset(true);
    set_irq(true);
    set_reset(true);
    is_open = true;
    set_rts(true);
}

void BluetoothCommon::close()
{
    LOG_INFO("close!");
    // TODO destroy semaphore
    set_rts(false);
    LOG_INFO("Bluetooth HW close!");
    set_irq(false);
    is_open = false;
    set_reset(false);


@@ 82,59 60,103 @@ void BluetoothCommon::sleep_ms(ssize_t ms)
    ulTaskNotifyTake(pdTRUE, ms);
}

BTdev::Error BluetoothCommon::flush()
BTdev::Error BluetoothCommon::read(uint8_t *buf, size_t nbytes)
{
    // LOG_INFO("flush [%d] %s", out.len, out.tail<out.head?"reverse":"normal");
    Error err  = Success;
    int len    = out.len;
    char *from = new char[out.len];
    for (int i = 0; i < len; ++i) {
        out.pop(from + i);
    }
    int to_write = len;
    char *fromp  = from;
    while (to_write) {
        while (1) {
            if (read_cts() == 0) {
                break;
            }
            else {
                sleep_ms(1);
            }
        }
        LPUART_WriteBlocking(BSP_BLUETOOTH_UART_BASE, reinterpret_cast<uint8_t *>(fromp), 1);
        --to_write;
        ++fromp;
    auto ret = ErrorUndefined;

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

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

    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");
        break;
    case kStatus_InvalidArgument:
        LOG_WARN("BT UART RX DMA invalid argument");
        ret = ErrorBSP;
        break;
    }
    delete[] from;
    return err;
    return ret;
}

ssize_t BluetoothCommon::write(char *buf, size_t nbytes)
BTdev::Error BluetoothCommon::write(const uint8_t *buf, size_t size)
{
    // LOG_INFO( "write -> [%.*s]",nbytes, buf);
    ssize_t i = 0;
    // if CTS set -> ignore return 0, can use threshold_guard here too
    for (i = 0; i < nbytes; ++i) {
        if (out.push(*(buf + i)) != 0) {
            LOG_ERROR("Cant push!");
            break;
        }
    logHciBytes("BT DMA to write --> [%d]>%s<",
                size,
                [&]() -> std::string {
                    std::stringstream ss;
                    for (int i = 0; i < size; ++i) {
                        ss << " 0x" << std::hex << (int)buf[i];
                    }
                    return ss.str();
                }()
                             .c_str());
    auto ret = ErrorUndefined;

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

    uartDmaHandle.userData = xTaskGetCurrentTaskHandle();

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

    auto sent = LPUART_SendEDMA(BSP_BLUETOOTH_UART_BASE, &uartDmaHandle, &sendXfer);
    switch (sent) {
    case kStatus_Success:
        // orchestrate a DMA Tx
        logHciComs("DMA Tx started (%d)", size);
        ret = Success;
        break;
    case kStatus_LPUART_TxBusy:
        // could've checked beforehand
        LOG_WARN("Previous DMA Tx is still pending");
        ret = ErrorBSP;
        break;
    case kStatus_InvalidArgument:
        LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, false);
        LOG_ERROR("DMA Tx invalid arg");
        ret = ErrorBSP;
        break;
    }
    return i;
    return ret;
}

ssize_t BluetoothCommon::write_blocking(char *buf, ssize_t len)
ssize_t BluetoothCommon::write_blocking(const uint8_t *buf, ssize_t nbytes)
{
    int yet_to_write = len;
    if (len > out.size) {
        LOG_WARN("WRITE: %d vs %d", len, out.size);
    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;
        }
    }
    while (yet_to_write != 0) {
        yet_to_write -= write(buf + len - yet_to_write, yet_to_write < out.size ? yet_to_write : (out.size - 1));
        flush();
    else {
        LOG_WARN("DMA Tx not wrote (%d/%d)", wrote, nbytes);
    }
    return len;
    return ret;
}

BTdev::Error BluetoothCommon::set_baudrate(uint32_t bd)


@@ 149,25 171,18 @@ BTdev::Error BluetoothCommon::set_baudrate(uint32_t bd)
    return ret;
}

// set flow on -> true, set flow off -> false
BTdev::Error BluetoothCommon::set_rts(bool on)
{
    GPIO_PinWrite(BSP_BLUETOOTH_UART_RTS_PORT, BSP_BLUETOOTH_UART_RTS_PIN, on ? 0U : 1U);
    return Success;
}

BTdev::Error BluetoothCommon::set_reset(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);
    }
    LOG_INFO("reset %s", on ? "on" : "off");
    GPIO_PinWrite(BSP_BLUETOOTH_SHUTDOWN_PORT, BSP_BLUETOOTH_SHUTDOWN_PIN, on ? 1U : 0U);
    return Success;
}

int BluetoothCommon::read_cts()
{
    return GPIO_PinRead(BSP_BLUETOOTH_UART_CTS_PORT, BSP_BLUETOOTH_UART_CTS_PIN);
}

uint32_t UartGetPeripheralClock()
{
    const int UART_PERIPHERAL_PLL_DIVIDER = 6;


@@ 198,9 213,7 @@ void BluetoothCommon::configure_uart_io()
    GPIO_PinInit(BSP_BLUETOOTH_UART_CTS_PORT, BSP_BLUETOOTH_UART_CTS_PIN, &gpio_init_structure);
    gpio_init_structure.direction     = kGPIO_DigitalOutput;
    gpio_init_structure.interruptMode = kGPIO_NoIntmode;
    GPIO_PinInit(BSP_BLUETOOTH_OSC_EN_PORT, BSP_BLUETOOTH_OSC_EN_PIN, &gpio_init_structure);
    GPIO_PinWrite(BSP_BLUETOOTH_OSC_EN_PORT, BSP_BLUETOOTH_OSC_EN_PIN, 1U);
    gpio_init_structure.direction = kGPIO_DigitalOutput;
    gpio_init_structure.outputLogic   = 0;
    GPIO_PinInit(BSP_BLUETOOTH_SHUTDOWN_PORT, BSP_BLUETOOTH_SHUTDOWN_PIN, &gpio_init_structure);
}



@@ 216,16 229,63 @@ void BluetoothCommon::configure_lpuart()
    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!");
        return;
    }
    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);
    NVIC_SetPriority(LPUART2_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
    NVIC_EnableIRQ(LPUART2_IRQn);

    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));

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

    LPUART_TransferCreateHandleEDMA(BSP_BLUETOOTH_UART_BASE,
                                    &uartDmaHandle,
                                    uartDmaCallback,
                                    nullptr,
                                    reinterpret_cast<edma_handle_t *>(uartTxDmaHandle->GetHandle()),
                                    reinterpret_cast<edma_handle_t *>(uartRxDmaHandle->GetHandle()));
}

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();

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

void BluetoothCommon::configure_cts_irq()


@@ 236,7 296,6 @@ void BluetoothCommon::configure_cts_irq()
    EnableIRQ(GPIO1_Combined_16_31_IRQn);
    NVIC_SetPriority(GPIO1_Combined_16_31_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY);
}

void BluetoothCommon::set_irq(bool enable)
{
    // printf("%s\n", __FUNCTION__);


@@ 244,16 303,30 @@ void BluetoothCommon::set_irq(bool enable)
    LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, false);
    LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, 0xFFFFFFFF);
    if (enable) {
        LPUART_EnableInterrupts(BSP_BLUETOOTH_UART_BASE,
                                kLPUART_RxDataRegFullInterruptEnable | kLPUART_IdleLineInterruptEnable);
        LPUART_EnableInterrupts(BSP_BLUETOOTH_UART_BASE, kLPUART_RxOverrunInterruptEnable);
    }
    else {
        LPUART_DisableInterrupts(BSP_BLUETOOTH_UART_BASE,
                                 kLPUART_RxDataRegFullInterruptEnable | kLPUART_IdleLineInterruptEnable);
        LPUART_DisableInterrupts(BSP_BLUETOOTH_UART_BASE, kLPUART_RxOverrunInterruptEnable);
    }
}

extern "C"
{
    void LPUART2_IRQHandler(void)
    {
        uint32_t isrReg      = LPUART_GetStatusFlags(BSP_BLUETOOTH_UART_BASE);
        BaseType_t taskwoken = 0;
        uint8_t val          = Bt::Message::EvtReceived;
        bsp::BlueKitchen *bt = bsp::BlueKitchen::getInstance();

        if (isrReg & kLPUART_RxDataRegFullFlag) {
            LOG_WARN("LPUART IRQ RX full");
        }
        if (isrReg & kLPUART_RxOverrunFlag) {
            LOG_WARN("LPUART IRQ RX overrun");
            val = Bt::Message::EvtUartError;
            xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
        }
        LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, isrReg);
    }
    //     LPUART_EnableInterrupts(BSP_BLUETOOTH_UART_BASE,
    //     kLPUART_RxDataRegFullInterruptEnable|kLPUART_TxDataRegEmptyInterruptEnable|kLPUART_TransmissionCompleteInterruptEnable|kLPUART_RxOverrunInterruptEnable
    //     );
    LPUART_EnableRx(BSP_BLUETOOTH_UART_BASE, true);
    LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, true);
}

M module-bsp/board/rt1051/common/board.h => module-bsp/board/rt1051/common/board.h +2 -6
@@ 238,13 238,9 @@
#define BSP_BLUETOOTH_UART_CTS_PIN  16
#define BSP_BLUETOOTH_UART_CTS_PAD  GPIO_AD_B1_00

#define BSP_BLUETOOTH_OSC_EN_PIN  0
#define BSP_BLUETOOTH_OSC_EN_PORT GPIO2
#define BSP_BLUETOOTH_OSC_EN_PAD  GPIO_B0_00

#define BSP_BLUETOOTH_SHUTDOWN_PIN  1
#define BSP_BLUETOOTH_SHUTDOWN_PORT GPIO2
#define BSP_BLUETOOTH_SHUTDOWN_PAD  GPIO_B0_01
#define BSP_BLUETOOTH_SHUTDOWN_PIN  1
#define BSP_BLUETOOTH_SHUTDOWN_PAD  GPIO_B0_01 // active low

/**
 * BOARD KEYBOARD DEFINITIONS

M module-bsp/board/rt1051/common/pin_mux.c => module-bsp/board/rt1051/common/pin_mux.c +2 -3
@@ 1359,9 1359,8 @@ void PINMUX_InitBluetoothPins(void)

    IOMUXC_SetPinConfig(PINMUX_BLUETOOTH_UART_CTS,

                        PAD_CONFIG_SLEW_RATE_SLOW | PAD_CONFIG_DRIVER_STRENGTH_LVL_1 | PAD_CONFIG_SPEED_SLOW_50MHz |
                            PAD_CONFIG_PULL_KEEPER_ENABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_DOWN_100kOhm |
                            PAD_CONFIG_HYSTERESIS_DISABLED);
                        PAD_CONFIG_SLEW_RATE_SLOW | PAD_CONFIG_DRIVER_DISABLED | PAD_CONFIG_SPEED_SLOW_50MHz |
                            PAD_CONFIG_PULL_KEEPER_ENABLED | PAD_CONFIG_SELECT_PULL | PAD_CONFIG_PULL_DOWN_100kOhm);

    IOMUXC_SetPinConfig(PINMUX_BLUETOOTH_UART_RTS,


M module-bsp/board/rt1051/common/pin_mux.h => module-bsp/board/rt1051/common/pin_mux.h +2 -2
@@ 159,8 159,8 @@ extern "C"
 */
#define PINMUX_BLUETOOTH_UART_TX   IOMUXC_GPIO_AD_B1_02_LPUART2_TX
#define PINMUX_BLUETOOTH_UART_RX   IOMUXC_GPIO_AD_B1_03_LPUART2_RX
#define PINMUX_BLUETOOTH_UART_CTS  IOMUXC_GPIO_AD_B1_00_GPIO1_IO16
#define PINMUX_BLUETOOTH_UART_RTS  IOMUXC_GPIO_AD_B1_01_GPIO1_IO17
#define PINMUX_BLUETOOTH_UART_CTS  IOMUXC_GPIO_AD_B1_00_LPUART2_CTS_B
#define PINMUX_BLUETOOTH_UART_RTS  IOMUXC_GPIO_AD_B1_01_LPUART2_RTS_B
#define PINMUX_BLUETOOTH_OSC_EN    IOMUXC_GPIO_B0_00_GPIO2_IO00
#define PINMUX_BLUETOOTH_NSHUTDOWN IOMUXC_GPIO_B0_01_GPIO2_IO01


M module-bsp/board/rt1051/drivers/RT1051DriverDMA.cpp => module-bsp/board/rt1051/drivers/RT1051DriverDMA.cpp +5 -2
@@ 40,8 40,11 @@ namespace drivers

    RT1051DriverDMA::~RT1051DriverDMA()
    {
        EDMA_Deinit(base);
        LOG_DEBUG("Deinit: DMA_0");
        switch (instance) {
        case DMAInstances::DMA_0:
            EDMA_Deinit(base);
            LOG_DEBUG("Deinit: DMA_0");
        }
    }

    std::unique_ptr<DriverDMAHandle> RT1051DriverDMA::CreateHandle(const uint32_t channel,

M module-bsp/bsp/BoardDefinitions.hpp => module-bsp/bsp/BoardDefinitions.hpp +11 -6
@@ 20,8 20,8 @@ enum class BoardDefinitions
    AUDIOCODEC_I2C            = static_cast<int>(drivers::I2CInstances ::I2C2),
    AUDIOCODEC_DMAMUX         = static_cast<int>(drivers::DMAMuxInstances ::DMAMUX0),
    AUDIOCODEC_DMA            = static_cast<int>(drivers::DMAInstances ::DMA_0),
    AUDIOCODEC_TX_DMA_CHANNEL = 6,
    AUDIOCODEC_RX_DMA_CHANNEL = 7,
    AUDIOCODEC_TX_DMA_CHANNEL = 5,
    AUDIOCODEC_RX_DMA_CHANNEL = 6,
    AUDIOCODEC_IRQ            = 31, // GPIO_B1_15  requires pull-up 10kΩ
    AUDIOCODEC_IRQ_GPIO       = static_cast<int>(drivers::GPIOInstances ::GPIO_2),



@@ 30,8 30,8 @@ enum class BoardDefinitions

    CELLULAR_AUDIO_DMAMUX         = AUDIOCODEC_DMAMUX,
    CELLULAR_AUDIO_DMA            = AUDIOCODEC_DMA,
    CELLULAR_AUDIO_TX_DMA_CHANNEL = 3,
    CELLULAR_AUDIO_RX_DMA_CHANNEL = 4,
    CELLULAR_AUDIO_TX_DMA_CHANNEL = 2,
    CELLULAR_AUDIO_RX_DMA_CHANNEL = 3,

    KEYBOARD_I2C_BAUDRATE = AUDIOCODEC_I2C_BAUDRATE,
    KEYBOARD_I2C          = AUDIOCODEC_I2C,


@@ 54,7 54,7 @@ enum class BoardDefinitions

    CELLULAR_DMA = static_cast<int >(drivers::DMAInstances ::DMA_0),
    CELLULAR_DMAMUX = static_cast<int >(drivers::DMAMuxInstances ::DMAMUX0),
    CELLULAR_TX_DMA_CHANNEL = 5,
    CELLULAR_TX_DMA_CHANNEL = 4,
    CELLULAR_GPIO_1 = static_cast<int >(drivers::GPIOInstances ::GPIO_1),
    CELLULAR_GPIO_2 = static_cast<int >(drivers::GPIOInstances ::GPIO_2),
    CELLULAR_GPIO_3 = static_cast<int >(drivers::GPIOInstances ::GPIO_3),


@@ 84,6 84,11 @@ enum class BoardDefinitions
    EINK_BUSY_PIN=17,
    EINK_PLL = static_cast<int >(drivers::PLLInstances::PLL2_PFD2),

    BLUETOOTH_DMA = static_cast<int >(drivers::DMAInstances ::DMA_0),
    BLUETOOTH_DMAMUX = static_cast<int >(drivers::DMAMuxInstances ::DMAMUX0),
    BLUETOOTH_TX_DMA_CHANNEL = 7,
    BLUETOOTH_RX_DMA_CHANNEL = 8,

    EMMC_PLL = static_cast<int >(drivers::PLLInstances::PLL2_PFD2),

    AUDIO_PLL = static_cast<int >(drivers::PLLInstances::PLL4_Audio),


@@ 107,7 112,7 @@ enum class BoardDefinitions
    KEYPAD_BACKLIGHT_DRIVER_I2C_BAUDRATE = AUDIOCODEC_I2C_BAUDRATE,
    KEYPAD_BACKLIGHT_DRIVER_I2C = AUDIOCODEC_I2C,
    KEYPAD_BACKLIGHT_DRIVER_GPIO = static_cast<int>(drivers::GPIOInstances::GPIO_1),
    KEYPAD_BACKLIGHT_DRIVER_NRST = 3, // GPIO_AD_B0_03 Active LOW. External pulldown resistor of 10Ω between NRST and GND.
    KEYPAD_BACKLIGHT_DRIVER_NRST = 3, // GPIO_AD_B0_03 Active LOW. External pulldown resistor of 10kΩ between NRST and GND.

    EINK_FRONTLIGHT_PWM_INSTANCE = 2, // GPIO_AD_B0_01 = FLEXPWM2_PWM3_B
    EINK_FRONTLIGHT_PWM_MODULE = 3,

M module-bsp/bsp/bluetooth/Bluetooth.cpp => module-bsp/bsp/bluetooth/Bluetooth.cpp +1 -1
@@ 3,7 3,7 @@


namespace bsp {
    BTdev::BTdev(unsigned int in_size, unsigned int out_size, int threshold) : flog(nullptr), in(in_size, threshold), out(out_size, threshold)
    BTdev::BTdev() : flog(nullptr)
    {
        is_open = false;
    }

M module-bsp/bsp/bluetooth/Bluetooth.hpp => module-bsp/bsp/bluetooth/Bluetooth.hpp +29 -75
@@ 7,6 7,12 @@
#include <thread.hpp>
#include <board.h>

#if defined(TARGET_RT1051)
#include "board/rt1051/common/fsl_drivers/fsl_lpuart_edma.h"
#include "drivers/dmamux/DriverDMAMux.hpp"
#include "drivers/dma/DriverDMA.hpp"
#endif

/// c++ low level driver overlay

namespace bsp {


@@ 34,116 40,64 @@ namespace bsp {
            static const unsigned int default_timeout_ms = 1000;
            static const unsigned int default_buff_size = 1024;
            static const unsigned int default_baudrate = 115200;
            struct _circ {
                SemaphoreHandle_t sem = 0;
                void sem_take();
                void sem_give();
                char* buff;
                volatile unsigned int head, tail, threshold;
                const unsigned int size;
                volatile unsigned int len;
                _circ(unsigned int size, int threshold=0);
                ~_circ();
                inline int push(char val) {
                    sem_take();
                    int ret=0;
                    if(len<size) {
                        buff[tail]=val;
                        ++tail;
                        ++len;
                        if(tail==size) tail=0;
                    } else {
                        ret=-1;
                    }
                    sem_give();
                    return ret;
                }
                inline int pop(char* val) {
                    sem_take();
                    int ret=0;
                    if(val!=nullptr) {
                        if(len) {
                            *val = buff[head];
                            --len;
                            ++head;
                            if(head == size) head=0;
                        } else {
                            ret =-1;
                        }
                    } else {
                        ret=-2;
                    }
                    sem_give();
                    return ret;
                }
                // reached => 1, safe => 0
                inline bool threshold_guard() {
                    return len+threshold > size;
                }
                inline void flush() {
                    sem_take();
                    len=0;
                    head=0;
                    tail=0;
                    sem_give();
                }
            } in, out;

            BTdev(unsigned int in_size=default_buff_size, unsigned int out_size=default_buff_size, int threshold=0);
            BTdev();
            virtual ~BTdev();

            // generall
            // general
            virtual void open() = 0;    // enable device -> irq enable
            virtual void close() = 0;   // disable device -> irq disable
            virtual ssize_t read(void *buf, size_t nbytes) = 0; // read from internal in buffor
            virtual BTdev::Error read(uint8_t *buf, size_t nbytes) = 0;
            void log(LogLvl lvl,const char* val, ...);
            // uart specyfic
            // uart specific
    };

    // Common stuff for Bluetopia and profiles +clean listing for overrrides
    class BluetoothCommon : public BTdev
    {
        public:
            static const ssize_t baudrate =115200;
            static const ssize_t off_threshold =16;
            static const ssize_t on_threshold =32;
        public:
            BluetoothCommon(unsigned int in_size=default_buff_size, unsigned int out_size=default_buff_size, int threshold=0);

            BluetoothCommon();
            virtual ~BluetoothCommon();
            // uart specyfic Common part
            // uart specific Common part
            virtual void open() override;
            virtual void close() override;
            virtual ssize_t write(char *buf, size_t nbytes);
            virtual ssize_t write_blocking(char *buf, ssize_t len);
            Error flush();
            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_rts(bool on);
            Error set_reset(bool on);
            int read_cts();
            void sleep_ms(ssize_t ms);
            void set_irq(bool enable);
            // Part to override
            virtual ssize_t read(void *buf, size_t nbytes) override = 0;

        private:
            void configure_uart_io();
            void configure_lpuart();
            void configure_cts_irq();
#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);
#endif
    };

    /// definitions needed by BT stack

    class BlueKitchen : public BluetoothCommon {
        public:
            BlueKitchen(unsigned int in_size=default_buff_size, unsigned int out_size=default_buff_size);
            BlueKitchen();
            virtual ~BlueKitchen();
            static BlueKitchen *getInstance();

            virtual ssize_t read(void *buf, size_t nbytes) override;
            virtual ssize_t write_blocking(char *buf, ssize_t len) override;
            volatile uint32_t to_read_req = 0;
            volatile uint32_t to_read =0;
            volatile char* read_buff;
            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;

            void set_flowcontrol(int on);


M module-utils/log/debug.hpp => module-utils/log/debug.hpp +2 -0
@@ 6,6 6,8 @@
#define DEBUG_APPLICATION_MANAGEMENT 0 /// show verbose logs in ApplicationManager
#define DEBUG_SCOPED_TIMINGS         0 /// show timings in measured functions
#define _RT1051_UART_DEBUG           0 /// show full modem uart communication
#define DEBUG_BLUETOOTH_HCI_COMS     0 /// show communication with BT module - transactions
#define DEBUG_BLUETOOTH_HCI_BYTES    0 /// show communication with BT module - all the HCI bytes
#define DEBUG_MODEM_OUTPUT_RESPONSE  0 /// show full modem output
#define DEBUG_SERVICE_MESSAGES       0 /// show messages prior to handling in service
#define DEBUG_DB_MODEL_DATA          0 /// show messages prior to handling in service