#pragma once
#include <strings.h>

#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "queue.h"

typedef void (*callback_rxData)(void * args, char *data, size_t len);

class I_GobotRPC_CI_Hardware {
public:
    virtual void send(char *data, size_t len) = 0;
    virtual void registerCB_RxData(callback_rxData cb, void *args) = 0;
};


#include "hardware/uart.h"

void GobotRPC_CI_Hardware_RP2040_UART_isr();
void GobotRPC_CI_Hardware_RP2040_UART_Task_RXBuffering(void *args);
void GobotRPC_CI_Hardware_RP2040_UART_Task_RXProcessing(void *args);

#define NUM_INPUT_BUFFERS 16

enum inputBufferRXState_t {
    NEW,
    READ_SIZE,
    READ_DATA,
    FULL
};

struct inputBuffers_t {
    char data[256];
    size_t expected_length;
    size_t len;
    inputBufferRXState_t state;
};

class GobotRPC_CI_Hardware_RP2040_UART : public I_GobotRPC_CI_Hardware {
private:
    uart_inst_t *uart;

    inputBuffers_t inputBufferPool[NUM_INPUT_BUFFERS];

    TaskHandle_t rxProcessingTaskHandle;

    SemaphoreHandle_t rxSignalSemaphore;
    QueueHandle_t emptyInputBuffersQueue;
    QueueHandle_t filledInputBuffersQueue;

    callback_rxData cb_rxData;
    void * cb_rxData_args;

    SemaphoreHandle_t uartTxMutex;

    UBaseType_t core;

public:
    GobotRPC_CI_Hardware_RP2040_UART(uart_inst_t *uart, uint baudrate, UBaseType_t core);
    void send(char *data, size_t len) override;
    void registerCB_RxData(callback_rxData cb, void *args);
    
    void initRxTaskAndQueues();

    void onRx_ISR();
    void rxBufferingTaskFn();
    void rxProcessingTaskFn();
};

extern GobotRPC_CI_Hardware_RP2040_UART * g_GobotRPC_CI_Hardware_RP2040_UART;

