<commit_before>// Copyright Microsoft Corporation
// Copyright Oberon microsystems, Inc
// Copyright GHI Electronics, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include "STM32F4.h"

#define USART_EVENT_POST_DEBOUNCE_TICKS (10 * 10000) // 10ms between each events
// StopBits
#define USART_STOP_BITS_ONE           0
#define USART_STOP_BITS_HALF          1
#define USART_STOP_BITS_TWO           2
#define USART_STOP_BITS_ONEPOINTFIVE  3

//Bit data length
#define STM32F4_UART_DATA_BIT_LENGTH_8    8
#define STM32F4_UART_DATA_BIT_LENGTH_9    9

bool STM32F4_Uart_CanSend(int controllerIndex);
void STM32F4_Uart_TxBufferEmptyInterruptEnable(int controllerIndex, bool enable);
void STM32F4_Uart_RxBufferFullInterruptEnable(int controllerIndex, bool enable);
void STM32F4_Uart_Reset();
void STM32F4_Uart_EventCallback(const TinyCLR_Task_Manager* self, const TinyCLR_Api_Manager* apiManager, TinyCLR_Task_Reference task, void* arg);

typedef USART_TypeDef* USART_TypeDef_Ptr;

struct UartState {
    int32_t controllerIndex;

    uint8_t *txBuffer;
    uint8_t *rxBuffer;

    size_t txBufferCount;
    size_t txBufferIn;
    size_t txBufferOut;
    size_t txBufferSize;

    size_t rxBufferCount;
    size_t rxBufferIn;
    size_t rxBufferOut;
    size_t rxBufferSize;

    USART_TypeDef_Ptr portReg;

    bool handshaking;
    bool enable;

    TinyCLR_Uart_ErrorReceivedHandler errorEventHandler;
    TinyCLR_Uart_DataReceivedHandler dataReceivedEventHandler;
    TinyCLR_Uart_ClearToSendChangedHandler cleartosendEventHandler;

    TinyCLR_Task_Reference errorCallbackTaskReference;
    TinyCLR_Task_Reference dataReceivedCallbackTaskReference;

    const TinyCLR_Task_Manager* taskManager;

    const TinyCLR_Uart_Controller* controller;
    bool tableInitialized;
    uint16_t initializeCount;
    uint64_t lastEventTime;
    size_t lastReadRxBufferCount;
    size_t lastEventRxBufferCount;

    uint8_t error;
};

#define UART_TXD_PIN 0
#define UART_RXD_PIN 1
#define UART_RTS_PIN 2
#define UART_CTS_PIN 3

static const STM32F4_Gpio_Pin uartPins[][4] = STM32F4_UART_PINS;

static const uint32_t uartRxDefaultBuffersSize[] = STM32F4_UART_DEFAULT_RX_BUFFER_SIZE;
static const uint32_t uartTxDefaultBuffersSize[] = STM32F4_UART_DEFAULT_TX_BUFFER_SIZE;

static UartState uartStates[TOTAL_UART_CONTROLLERS];
static TinyCLR_Uart_Controller uartControllers[TOTAL_UART_CONTROLLERS];
static TinyCLR_Api_Info uartApi[TOTAL_UART_CONTROLLERS];

const char* uartApiNames[] = {
#if TOTAL_UART_CONTROLLERS > 0
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\0",
#if TOTAL_UART_CONTROLLERS > 1
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\1",
#if TOTAL_UART_CONTROLLERS > 2
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\2",
#if TOTAL_UART_CONTROLLERS > 3
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\3",
#if TOTAL_UART_CONTROLLERS > 4
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\4",
#if TOTAL_UART_CONTROLLERS > 5
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\5",
#if TOTAL_UART_CONTROLLERS > 6
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\6",
#if TOTAL_UART_CONTROLLERS > 7
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\7",
#if TOTAL_UART_CONTROLLERS > 8
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\8",
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
};

void STM32F4_Uart_EnsureTableInitialized() {
    for (int32_t i = 0; i < TOTAL_UART_CONTROLLERS; i++) {
        if (uartStates[i].tableInitialized)
            continue;

        uartControllers[i].ApiInfo = &uartApi[i];
        uartControllers[i].Acquire = &STM32F4_Uart_Acquire;
        uartControllers[i].Release = &STM32F4_Uart_Release;
        uartControllers[i].Enable = &STM32F4_Uart_Enable;
        uartControllers[i].Disable = &STM32F4_Uart_Disable;
        uartControllers[i].SetActiveSettings = &STM32F4_Uart_SetActiveSettings;
        uartControllers[i].Flush = &STM32F4_Uart_Flush;
        uartControllers[i].Read = &STM32F4_Uart_Read;
        uartControllers[i].Write = &STM32F4_Uart_Write;
        uartControllers[i].SetErrorReceivedHandler = &STM32F4_Uart_SetErrorReceivedHandler;
        uartControllers[i].SetDataReceivedHandler = &STM32F4_Uart_SetDataReceivedHandler;
        uartControllers[i].GetClearToSendState = &STM32F4_Uart_GetClearToSendState;
        uartControllers[i].SetClearToSendChangedHandler = &STM32F4_Uart_SetClearToSendChangedHandler;
        uartControllers[i].GetIsRequestToSendEnabled = &STM32F4_Uart_GetIsRequestToSendEnabled;
        uartControllers[i].SetIsRequestToSendEnabled = &STM32F4_Uart_SetIsRequestToSendEnabled;
        uartControllers[i].GetReadBufferSize = &STM32F4_Uart_GetReadBufferSize;
        uartControllers[i].SetReadBufferSize = &STM32F4_Uart_SetReadBufferSize;
        uartControllers[i].GetWriteBufferSize = &STM32F4_Uart_GetWriteBufferSize;
        uartControllers[i].SetWriteBufferSize = &STM32F4_Uart_SetWriteBufferSize;
        uartControllers[i].GetBytesToRead = &STM32F4_Uart_GetBytesToRead;
        uartControllers[i].GetBytesToWrite = &STM32F4_Uart_GetBytesToWrite;
        uartControllers[i].ClearReadBuffer = &STM32F4_Uart_ClearReadBuffer;
        uartControllers[i].ClearWriteBuffer = &STM32F4_Uart_ClearWriteBuffer;

        uartApi[i].Author = "GHI Electronics, LLC";
        uartApi[i].Name = uartApiNames[i];
        uartApi[i].Type = TinyCLR_Api_Type::UartController;
        uartApi[i].Version = 0;
        uartApi[i].Implementation = &uartControllers[i];
        uartApi[i].State = &uartStates[i];

        uartStates[i].controllerIndex = i;
        uartStates[i].initializeCount = 0;
        uartStates[i].txBuffer = nullptr;
        uartStates[i].txBuffer = nullptr;

        uartStates[i].tableInitialized = true;
    }

    if (TOTAL_UART_CONTROLLERS > 0) uartStates[0].portReg = USART1;
    if (TOTAL_UART_CONTROLLERS > 1) uartStates[1].portReg = USART2;
#if !defined(STM32F401xE) && !defined(STM32F411xE)
    if (TOTAL_UART_CONTROLLERS > 2) uartStates[2].portReg = USART3;
    if (TOTAL_UART_CONTROLLERS > 3) uartStates[3].portReg = UART4;
    if (TOTAL_UART_CONTROLLERS > 4) uartStates[4].portReg = UART5;
    if (TOTAL_UART_CONTROLLERS > 5) uartStates[5].portReg = USART6;
#ifdef UART7
    if (TOTAL_UART_CONTROLLERS > 6) uartStates[6].portReg = UART7;
#ifdef UART8
    if (TOTAL_UART_CONTROLLERS > 7) uartStates[7].portReg = UART8;
#ifdef UART9
    if (TOTAL_UART_CONTROLLERS > 8) uartStates[8].portReg = UART9;
#endif
#endif
#endif
#endif
}

const TinyCLR_Api_Info* STM32F4_Uart_GetRequiredApi() {
    STM32F4_Uart_EnsureTableInitialized();

    return &uartApi[UART_DEBUGGER_INDEX];
}


void STM32F4_Uart_AddApi(const TinyCLR_Api_Manager* apiManager) {
    STM32F4_Uart_EnsureTableInitialized();

    for (int32_t i = 0; i < TOTAL_UART_CONTROLLERS; i++) {
        apiManager->Add(apiManager, &uartApi[i]);
    }
}

size_t STM32F4_Uart_GetReadBufferSize(const TinyCLR_Uart_Controller* self) {
    auto state = reinterpret_cast<UartState*>(self->ApiInfo->State);

    return state->rxBufferSize;
}

TinyCLR_Result STM32F4_Uart_SetReadBufferSize(const TinyCLR_Uart_Controller* self, size_t size) {
    auto memoryProvider = (const TinyCLR_Memory_Manager*)apiManager->FindDefault(apiManager, TinyCLR_Api_Type::MemoryManager);

    auto state = reinterpret_cast<UartState*>(self->ApiInfo->State);

    if (size <= 0)
        return TinyCLR_Result::ArgumentInvalid;

    if (state->rxBuffer) {
        memoryProvider->Free(memoryProvider, state->rxBuffer);
    }

    state->rxBufferSize = 0;

    state->rxBuffer = (uint8_t*)memoryProvider->Allocate(memoryProvider, size);

    if (state->rxBuffer == nullptr) {
        return TinyCLR_Result::OutOfMemory;
    }

    state->rxBufferSize = size;

    return TinyCLR_Result::Success;
}

size_t STM32F4_Uart_GetWriteBufferSize(const TinyCLR_Uart_Controller* self) {
    auto state = reinterpret_cast<UartState*>(self->ApiInfo->State);

    return state->txBufferSize;
}

TinyCLR_Result STM32F4_Uart_SetWriteBufferSize(const TinyCLR_Uart_Controller* self, size_t size) {
    auto memoryProvider = (const TinyCLR_Memory_Manager*)apiManager->FindDefault(apiManager, TinyCLR_Api_Type::MemoryManager);

    auto state = reinterpret_cast<UartState*>(self->ApiInfo->State);

    if (size <= 0)
        return TinyCLR_Result::ArgumentInvalid;

    if (state->txBuffer) {
        memoryProvider->Free(memoryProvider, state->txBuffer);
    }

    state->txBufferSize = 0;

    state->txBuffer = (uint8_t*)memoryProvider->Allocate(memoryProvider, size);

    if (state->txBuffer == nullptr) {
        return TinyCLR_Result::OutOfMemory;
    }

    state->txBufferSize = size;

    return TinyCLR_Result::Success;
}

bool STM32F4_Uart_CanPostEvent(int8_t controllerIndex) {
    auto state = reinterpret_cast<UartState*>(&uartStates[controllerIndex]);
    auto currentTime = STM32F4_Time_GetCurrentProcessorTime();
    bool canPost = (currentTime - state->lastEventTime) > USART_EVENT_POST_DEBOUNCE_TICKS;

    if (canPost) // only update when debounce is over
        state->lastEventTime = currentTime;

    return canPost;
}

void STM32F4_Uart_InterruptHandler(int8_t controllerIndex) {
    DISABLE_INTERRUPTS_SCOPED(irq);

    auto state = reinterpret_cast<UartState*>(&uartStates[controllerIndex]);
    auto sr = (uint16_t)(state->portReg->SR);
    bool error = ((sr & USART_SR_ORE) || (sr & USART_SR_FE) || (sr & USART_SR_PE)) != 0 ? true : false;

    if (error || (sr & USART_SR_RXNE)) {
        // Still read latest data
        // Read data also clear error status
        auto data = (uint8_t)(state->portReg->DR);

        if (sr & USART_SR_RXNE) {
            state->rxBuffer[state->rxBufferIn++] = data;

            if (state->rxBufferCount < state->rxBufferSize) {
                state->rxBufferCount++;
            }

            if (state->rxBufferIn == state->rxBufferSize)
                state->rxBufferIn = 0;
        }

        if (state->rxBufferCount == state->rxBufferSize) {
            state->error = 1 << (uint8_t)TinyCLR_Uart_Error::BufferFull;

            error = true;
        }

        if (!error && (sr & USART_SR_RXNE)) {
            // Task callback will decide post the event immediately or delay
            // If Data Rx and Error happen at same time, Error event has higher priority.
            STM32F4_Uart_EventCallback(state->taskManager, apiManager, state->dataReceivedCallbackTaskReference, (void*)state);
        }

        if (error) {
            if (sr & USART_SR_ORE) {
                state->error = 1 << (uint8_t)TinyCLR_Uart_Error::Overrun;
            }

            else if (sr & USART_SR_FE) {
                state->error = 1 << (uint8_t)TinyCLR_Uart_Error::Frame;
            }

            else if (sr & USART_SR_PE) {
                state->error = 1 << (uint8_t)TinyCLR_Uart_Error::ReceiveParity;
            }

            // Task callback will decide post the event immediately or delay
            STM32F4_Uart_EventCallback(state->taskManager, apiManager, state->errorCallbackTaskReference, (void*)state);
        }
    }

    if (sr & USART_SR_TXE) {
        if (STM32F4_Uart_CanSend(controllerIndex)) {
            if (state->txBufferCount > 0) {
                uint8_t data = state->txBuffer[state->txBufferOut++];

                state->txBufferCount--;

                if (state->txBufferOut == state->txBufferSize)
                    state->txBufferOut = 0;

                state->portReg->DR = data; // write TX data
            }
            else {
                STM32F4_Uart_TxBufferEmptyInterruptEnable(controllerIndex, false); // Disable interrupt when no more data to send.
            }
        }
        else {
            // Temporary disable tx during cts is high to avoild device lockup
            STM32F4_Uart_TxBufferEmptyInterruptEnable(controllerIndex, false);
        }
    }

    if (state->handshaking && (sr & USART_SR_CTS)) {
        bool ctsState = true;

        // STM32F4 write 0 to clear CTS interrupt
        (state->portReg->SR) &= ~USART_SR_CTS;

        STM32F4_Uart_GetClearToSendState(state->controller, ctsState);

        if (state->cleartosendEventHandler != nullptr)
            state->cleartosendEventHandler(state->controller, ctsState, STM32F4_Time_GetSystemTime(nullptr));

        // If tx was disable to avoid locked up
        // Need Enable back if detected OK to send
        if (ctsState)
            STM32F4_Uart_TxBufferEmptyInterruptEnable(controllerIndex, true);
    }
}

void STM32F4_Uart_Interrupt0(void* param) {
    STM32F4_Uart_InterruptHandler(0);
}

void STM32F4_Uart_Interrupt1(void* param) {
    STM32F4_Uart_InterruptHandler(1);
}

#if !defined(STM32F401xE) && !defined(STM32F411xE)
void STM32F4_Uart_Interrupt2(void* param) {
    STM32F4_Uart_InterruptHandler(2);
}

void STM32F4_Uart_Interrupt3(void* param) {
    STM32F4_Uart_InterruptHandler(3);
}

void STM32F4_Uart_Interrupt4(void* param) {
    STM32F4_Uart_InterruptHandler(4);
}

void STM32F4_Uart_Interrupt5(void* param) {
    STM32F4_Uart_InterruptHandler(5);
}
#ifdef UART7
void STM32F4_Uart_Interrupt6(void* param) {
    STM32F4_Uart_InterruptHandler(6);
}
#ifdef UART8
void STM32F4_Uart_Interrupt7(void* param) {
    STM32F4_Uart_InterruptHandler(7);
}
#ifdef UART9
void STM32F4_Uart_Interrupt8(void* param) {
    STM32F4_Uart_InterruptHandler(8);
}
#endif
#endif
#endif
#endif

TinyCLR_Result STM32F4_Uart_Acquire(const TinyCLR_Uart_Controller* self) {
    auto state = reinterpret_cast<UartState*>(self->ApiInfo->State);

    if (state->initializeCount == 0) {
        int32_t controllerIndex = state->controllerIndex;

        if (controllerIndex >= TOTAL_UART_CONTROLLERS)
            return TinyCLR_Result::ArgumentInvalid;

        if (!STM32F4_GpioInternal_OpenMultiPins(uartPins[controllerIndex], 2))
            return TinyCLR_Result::SharingViolation;

        state->txBufferCount = 0;
        state->txBufferIn = 0;
        state->txBufferOut = 0;

        state->rxBufferCount = 0;
        state->rxBufferIn = 0;
        state->rxBufferOut = 0;

        state->controller = self;
        state->handshaking = false;
        state->enable = false;

        state->lastReadRxBufferCount = 0;
        state->lastEventRxBufferCount = 0;
        state->error = 0;
        state->lastEventTime = STM32F4_Time_GetCurrentProcessorTime();

        state->txBuffer = nullptr;
        state->rxBuffer = nullptr;

        if (STM32F4_Uart_SetWriteBufferSize(self, uartTxDefaultBuffersSize[controllerIndex]) != TinyCLR_Result::Success)
            return TinyCLR_Result::OutOfMemory;

        if (STM32F4_Uart_SetReadBufferSize(self, uartRxDefaultBuffersSize[controllerIndex]) != TinyCLR_Result::Success)
            return TinyCLR_Result::OutOfMemory;
    }

    state->initializeCount++;

    return TinyCLR_Result::Success;
}

TinyCLR_Result STM32F4_Uart_SetActiveSettings(const TinyCLR_Uart_Controller* self, const TinyCLR_Uart_Settings* settings) {
    uint32_t baudRate = settings->BaudRate;
    uint32_t dataBits = settings->DataBits;
    TinyCLR_Uart_Parity parity = settings->Parity;
    TinyCLR_Uart_StopBitCount stopBits = settings->StopBits;
    TinyCLR_Uart_Handshake handshaking = settings->Handshaking;
    uint32_t clk;
<commit_msg>Ensure event variables are in proper state when Acquire<commit_after>// Copyright Microsoft Corporation
// Copyright Oberon microsystems, Inc
// Copyright GHI Electronics, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include "STM32F4.h"

#define USART_EVENT_POST_DEBOUNCE_TICKS (10 * 10000) // 10ms between each events
// StopBits
#define USART_STOP_BITS_ONE           0
#define USART_STOP_BITS_HALF          1
#define USART_STOP_BITS_TWO           2
#define USART_STOP_BITS_ONEPOINTFIVE  3

//Bit data length
#define STM32F4_UART_DATA_BIT_LENGTH_8    8
#define STM32F4_UART_DATA_BIT_LENGTH_9    9

bool STM32F4_Uart_CanSend(int controllerIndex);
void STM32F4_Uart_TxBufferEmptyInterruptEnable(int controllerIndex, bool enable);
void STM32F4_Uart_RxBufferFullInterruptEnable(int controllerIndex, bool enable);
void STM32F4_Uart_Reset();
void STM32F4_Uart_EventCallback(const TinyCLR_Task_Manager* self, const TinyCLR_Api_Manager* apiManager, TinyCLR_Task_Reference task, void* arg);

typedef USART_TypeDef* USART_TypeDef_Ptr;

struct UartState {
    int32_t controllerIndex;

    uint8_t *txBuffer;
    uint8_t *rxBuffer;

    size_t txBufferCount;
    size_t txBufferIn;
    size_t txBufferOut;
    size_t txBufferSize;

    size_t rxBufferCount;
    size_t rxBufferIn;
    size_t rxBufferOut;
    size_t rxBufferSize;

    USART_TypeDef_Ptr portReg;

    bool handshaking;
    bool enable;

    TinyCLR_Uart_ErrorReceivedHandler errorEventHandler;
    TinyCLR_Uart_DataReceivedHandler dataReceivedEventHandler;
    TinyCLR_Uart_ClearToSendChangedHandler cleartosendEventHandler;

    TinyCLR_Task_Reference errorCallbackTaskReference;
    TinyCLR_Task_Reference dataReceivedCallbackTaskReference;

    const TinyCLR_Task_Manager* taskManager;

    const TinyCLR_Uart_Controller* controller;
    bool tableInitialized;
    uint16_t initializeCount;
    uint64_t lastEventTime;
    size_t lastReadRxBufferCount;
    size_t lastEventRxBufferCount;

    uint8_t error;
};

#define UART_TXD_PIN 0
#define UART_RXD_PIN 1
#define UART_RTS_PIN 2
#define UART_CTS_PIN 3

static const STM32F4_Gpio_Pin uartPins[][4] = STM32F4_UART_PINS;

static const uint32_t uartRxDefaultBuffersSize[] = STM32F4_UART_DEFAULT_RX_BUFFER_SIZE;
static const uint32_t uartTxDefaultBuffersSize[] = STM32F4_UART_DEFAULT_TX_BUFFER_SIZE;

static UartState uartStates[TOTAL_UART_CONTROLLERS];
static TinyCLR_Uart_Controller uartControllers[TOTAL_UART_CONTROLLERS];
static TinyCLR_Api_Info uartApi[TOTAL_UART_CONTROLLERS];

const char* uartApiNames[] = {
#if TOTAL_UART_CONTROLLERS > 0
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\0",
#if TOTAL_UART_CONTROLLERS > 1
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\1",
#if TOTAL_UART_CONTROLLERS > 2
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\2",
#if TOTAL_UART_CONTROLLERS > 3
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\3",
#if TOTAL_UART_CONTROLLERS > 4
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\4",
#if TOTAL_UART_CONTROLLERS > 5
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\5",
#if TOTAL_UART_CONTROLLERS > 6
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\6",
#if TOTAL_UART_CONTROLLERS > 7
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\7",
#if TOTAL_UART_CONTROLLERS > 8
"GHIElectronics.TinyCLR.NativeApis.STM32F4.UartController\\8",
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
};

void STM32F4_Uart_EnsureTableInitialized() {
    for (int32_t i = 0; i < TOTAL_UART_CONTROLLERS; i++) {
        if (uartStates[i].tableInitialized)
            continue;

        uartControllers[i].ApiInfo = &uartApi[i];
        uartControllers[i].Acquire = &STM32F4_Uart_Acquire;
        uartControllers[i].Release = &STM32F4_Uart_Release;
        uartControllers[i].Enable = &STM32F4_Uart_Enable;
        uartControllers[i].Disable = &STM32F4_Uart_Disable;
        uartControllers[i].SetActiveSettings = &STM32F4_Uart_SetActiveSettings;
        uartControllers[i].Flush = &STM32F4_Uart_Flush;
        uartControllers[i].Read = &STM32F4_Uart_Read;
        uartControllers[i].Write = &STM32F4_Uart_Write;
        uartControllers[i].SetErrorReceivedHandler = &STM32F4_Uart_SetErrorReceivedHandler;
        uartControllers[i].SetDataReceivedHandler = &STM32F4_Uart_SetDataReceivedHandler;
        uartControllers[i].GetClearToSendState = &STM32F4_Uart_GetClearToSendState;
        uartControllers[i].SetClearToSendChangedHandler = &STM32F4_Uart_SetClearToSendChangedHandler;
        uartControllers[i].GetIsRequestToSendEnabled = &STM32F4_Uart_GetIsRequestToSendEnabled;
        uartControllers[i].SetIsRequestToSendEnabled = &STM32F4_Uart_SetIsRequestToSendEnabled;
        uartControllers[i].GetReadBufferSize = &STM32F4_Uart_GetReadBufferSize;
        uartControllers[i].SetReadBufferSize = &STM32F4_Uart_SetReadBufferSize;
        uartControllers[i].GetWriteBufferSize = &STM32F4_Uart_GetWriteBufferSize;
        uartControllers[i].SetWriteBufferSize = &STM32F4_Uart_SetWriteBufferSize;
        uartControllers[i].GetBytesToRead = &STM32F4_Uart_GetBytesToRead;
        uartControllers[i].GetBytesToWrite = &STM32F4_Uart_GetBytesToWrite;
        uartControllers[i].ClearReadBuffer = &STM32F4_Uart_ClearReadBuffer;
        uartControllers[i].ClearWriteBuffer = &STM32F4_Uart_ClearWriteBuffer;

        uartApi[i].Author = "GHI Electronics, LLC";
        uartApi[i].Name = uartApiNames[i];
        uartApi[i].Type = TinyCLR_Api_Type::UartController;
        uartApi[i].Version = 0;
        uartApi[i].Implementation = &uartControllers[i];
        uartApi[i].State = &uartStates[i];

        uartStates[i].controllerIndex = i;
        uartStates[i].initializeCount = 0;
        uartStates[i].txBuffer = nullptr;
        uartStates[i].txBuffer = nullptr;

        uartStates[i].tableInitialized = true;
    }

    if (TOTAL_UART_CONTROLLERS > 0) uartStates[0].portReg = USART1;
    if (TOTAL_UART_CONTROLLERS > 1) uartStates[1].portReg = USART2;
#if !defined(STM32F401xE) && !defined(STM32F411xE)
    if (TOTAL_UART_CONTROLLERS > 2) uartStates[2].portReg = USART3;
    if (TOTAL_UART_CONTROLLERS > 3) uartStates[3].portReg = UART4;
    if (TOTAL_UART_CONTROLLERS > 4) uartStates[4].portReg = UART5;
    if (TOTAL_UART_CONTROLLERS > 5) uartStates[5].portReg = USART6;
#ifdef UART7
    if (TOTAL_UART_CONTROLLERS > 6) uartStates[6].portReg = UART7;
#ifdef UART8
    if (TOTAL_UART_CONTROLLERS > 7) uartStates[7].portReg = UART8;
#ifdef UART9
    if (TOTAL_UART_CONTROLLERS > 8) uartStates[8].portReg = UART9;
#endif
#endif
#endif
#endif
}

const TinyCLR_Api_Info* STM32F4_Uart_GetRequiredApi() {
    STM32F4_Uart_EnsureTableInitialized();

    return &uartApi[UART_DEBUGGER_INDEX];
}


void STM32F4_Uart_AddApi(const TinyCLR_Api_Manager* apiManager) {
    STM32F4_Uart_EnsureTableInitialized();

    for (int32_t i = 0; i < TOTAL_UART_CONTROLLERS; i++) {
        apiManager->Add(apiManager, &uartApi[i]);
    }
}

size_t STM32F4_Uart_GetReadBufferSize(const TinyCLR_Uart_Controller* self) {
    auto state = reinterpret_cast<UartState*>(self->ApiInfo->State);

    return state->rxBufferSize;
}

TinyCLR_Result STM32F4_Uart_SetReadBufferSize(const TinyCLR_Uart_Controller* self, size_t size) {
    auto memoryProvider = (const TinyCLR_Memory_Manager*)apiManager->FindDefault(apiManager, TinyCLR_Api_Type::MemoryManager);

    auto state = reinterpret_cast<UartState*>(self->ApiInfo->State);

    if (size <= 0)
        return TinyCLR_Result::ArgumentInvalid;

    if (state->rxBuffer) {
        memoryProvider->Free(memoryProvider, state->rxBuffer);
    }

    state->rxBufferSize = 0;

    state->rxBuffer = (uint8_t*)memoryProvider->Allocate(memoryProvider, size);

    if (state->rxBuffer == nullptr) {
        return TinyCLR_Result::OutOfMemory;
    }

    state->rxBufferSize = size;

    return TinyCLR_Result::Success;
}

size_t STM32F4_Uart_GetWriteBufferSize(const TinyCLR_Uart_Controller* self) {
    auto state = reinterpret_cast<UartState*>(self->ApiInfo->State);

    return state->txBufferSize;
}

TinyCLR_Result STM32F4_Uart_SetWriteBufferSize(const TinyCLR_Uart_Controller* self, size_t size) {
    auto memoryProvider = (const TinyCLR_Memory_Manager*)apiManager->FindDefault(apiManager, TinyCLR_Api_Type::MemoryManager);

    auto state = reinterpret_cast<UartState*>(self->ApiInfo->State);

    if (size <= 0)
        return TinyCLR_Result::ArgumentInvalid;

    if (state->txBuffer) {
        memoryProvider->Free(memoryProvider, state->txBuffer);
    }

    state->txBufferSize = 0;

    state->txBuffer = (uint8_t*)memoryProvider->Allocate(memoryProvider, size);

    if (state->txBuffer == nullptr) {
        return TinyCLR_Result::OutOfMemory;
    }

    state->txBufferSize = size;

    return TinyCLR_Result::Success;
}

bool STM32F4_Uart_CanPostEvent(int8_t controllerIndex) {
    auto state = reinterpret_cast<UartState*>(&uartStates[controllerIndex]);
    auto currentTime = STM32F4_Time_GetCurrentProcessorTime();
    bool canPost = (currentTime - state->lastEventTime) > USART_EVENT_POST_DEBOUNCE_TICKS;

    if (canPost) // only update when debounce is over
        state->lastEventTime = currentTime;

    return canPost;
}

void STM32F4_Uart_InterruptHandler(int8_t controllerIndex) {
    DISABLE_INTERRUPTS_SCOPED(irq);

    auto state = reinterpret_cast<UartState*>(&uartStates[controllerIndex]);
    auto sr = (uint16_t)(state->portReg->SR);
    bool error = ((sr & USART_SR_ORE) || (sr & USART_SR_FE) || (sr & USART_SR_PE)) != 0 ? true : false;

    if (error || (sr & USART_SR_RXNE)) {
        // Still read latest data
        // Read data also clear error status
        auto data = (uint8_t)(state->portReg->DR);

        if (sr & USART_SR_RXNE) {
            state->rxBuffer[state->rxBufferIn++] = data;

            if (state->rxBufferCount < state->rxBufferSize) {
                state->rxBufferCount++;
            }

            if (state->rxBufferIn == state->rxBufferSize)
                state->rxBufferIn = 0;
        }

        if (state->rxBufferCount == state->rxBufferSize) {
            state->error = 1 << (uint8_t)TinyCLR_Uart_Error::BufferFull;

            error = true;
        }

        if (!error && (sr & USART_SR_RXNE)) {
            // Task callback will decide post the event immediately or delay
            // If Data Rx and Error happen at same time, Error event has higher priority.
            STM32F4_Uart_EventCallback(state->taskManager, apiManager, state->dataReceivedCallbackTaskReference, (void*)state);
        }

        if (error) {
            if (sr & USART_SR_ORE) {
                state->error = 1 << (uint8_t)TinyCLR_Uart_Error::Overrun;
            }

            else if (sr & USART_SR_FE) {
                state->error = 1 << (uint8_t)TinyCLR_Uart_Error::Frame;
            }

            else if (sr & USART_SR_PE) {
                state->error = 1 << (uint8_t)TinyCLR_Uart_Error::ReceiveParity;
            }

            // Task callback will decide post the event immediately or delay
            STM32F4_Uart_EventCallback(state->taskManager, apiManager, state->errorCallbackTaskReference, (void*)state);
        }
    }

    if (sr & USART_SR_TXE) {
        if (STM32F4_Uart_CanSend(controllerIndex)) {
            if (state->txBufferCount > 0) {
                uint8_t data = state->txBuffer[state->txBufferOut++];

                state->txBufferCount--;

                if (state->txBufferOut == state->txBufferSize)
                    state->txBufferOut = 0;

                state->portReg->DR = data; // write TX data
            }
            else {
                STM32F4_Uart_TxBufferEmptyInterruptEnable(controllerIndex, false); // Disable interrupt when no more data to send.
            }
        }
        else {
            // Temporary disable tx during cts is high to avoild device lockup
            STM32F4_Uart_TxBufferEmptyInterruptEnable(controllerIndex, false);
        }
    }

    if (state->handshaking && (sr & USART_SR_CTS)) {
        bool ctsState = true;

        // STM32F4 write 0 to clear CTS interrupt
        (state->portReg->SR) &= ~USART_SR_CTS;

        STM32F4_Uart_GetClearToSendState(state->controller, ctsState);

        if (state->cleartosendEventHandler != nullptr)
            state->cleartosendEventHandler(state->controller, ctsState, STM32F4_Time_GetSystemTime(nullptr));

        // If tx was disable to avoid locked up
        // Need Enable back if detected OK to send
        if (ctsState)
            STM32F4_Uart_TxBufferEmptyInterruptEnable(controllerIndex, true);
    }
}

void STM32F4_Uart_Interrupt0(void* param) {
    STM32F4_Uart_InterruptHandler(0);
}

void STM32F4_Uart_Interrupt1(void* param) {
    STM32F4_Uart_InterruptHandler(1);
}

#if !defined(STM32F401xE) && !defined(STM32F411xE)
void STM32F4_Uart_Interrupt2(void* param) {
    STM32F4_Uart_InterruptHandler(2);
}

void STM32F4_Uart_Interrupt3(void* param) {
    STM32F4_Uart_InterruptHandler(3);
}

void STM32F4_Uart_Interrupt4(void* param) {
    STM32F4_Uart_InterruptHandler(4);
}

void STM32F4_Uart_Interrupt5(void* param) {
    STM32F4_Uart_InterruptHandler(5);
}
#ifdef UART7
void STM32F4_Uart_Interrupt6(void* param) {
    STM32F4_Uart_InterruptHandler(6);
}
#ifdef UART8
void STM32F4_Uart_Interrupt7(void* param) {
    STM32F4_Uart_InterruptHandler(7);
}
#ifdef UART9
void STM32F4_Uart_Interrupt8(void* param) {
    STM32F4_Uart_InterruptHandler(8);
}
#endif
#endif
#endif
#endif

TinyCLR_Result STM32F4_Uart_Acquire(const TinyCLR_Uart_Controller* self) {
    auto state = reinterpret_cast<UartState*>(self->ApiInfo->State);

    if (state->initializeCount == 0) {
        int32_t controllerIndex = state->controllerIndex;

        if (controllerIndex >= TOTAL_UART_CONTROLLERS)
            return TinyCLR_Result::ArgumentInvalid;

        if (!STM32F4_GpioInternal_OpenMultiPins(uartPins[controllerIndex], 2))
            return TinyCLR_Result::SharingViolation;

        state->txBufferCount = 0;
        state->txBufferIn = 0;
        state->txBufferOut = 0;

        state->rxBufferCount = 0;
        state->rxBufferIn = 0;
        state->rxBufferOut = 0;

        state->controller = self;
        state->handshaking = false;
        state->enable = false;

        state->lastReadRxBufferCount = 0;
        state->lastEventRxBufferCount = 0;
        state->error = 0;
        state->lastEventTime = STM32F4_Time_GetCurrentProcessorTime();

        state->txBuffer = nullptr;
        state->rxBuffer = nullptr;
        state->errorEventHandler = nullptr;
        state->dataReceivedEventHandler = nullptr;
        state->cleartosendEventHandler = nullptr;

        if (STM32F4_Uart_SetWriteBufferSize(self, uartTxDefaultBuffersSize[controllerIndex]) != TinyCLR_Result::Success)
            return TinyCLR_Result::OutOfMemory;

        if (STM32F4_Uart_SetReadBufferSize(self, uartRxDefaultBuffersSize[controllerIndex]) != TinyCLR_Result::Success)
            return TinyCLR_Result::OutOfMemory;
    }

    state->initializeCount++;

    return TinyCLR_Result::Success;
}

TinyCLR_Result STM32F4_Uart_SetActiveSettings(const TinyCLR_Uart_Controller* self, const TinyCLR_Uart_Settings* settings) {
    uint32_t baudRate = settings->BaudRate;
    uint32_t dataBits = settings->DataBits;
    TinyCLR_Uart_Parity parity = settings->Parity;
    TinyCLR_Uart_StopBitCount stopBits = settings->StopBits;
    TinyCLR_Uart_Handshake handshaking = settings->Handshaking;
    uint32_t clk;

{'fraction_non_alphanumeric': 0.09433902891846817, 'fraction_numerical': 0.02794298121400925, 'mean_word_length': 3.8319902691196592, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 252, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '345049', 'n_tokens_mistral': 11598, 'n_tokens_neox': 10775, 'n_words': 1880}