#pragma once

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

#include <stdint.h>
#include <strings.h>

#include "pico/stdlib.h"
#include "hardware/i2c.h"

#include "pinConfig.hpp"

#include "ci/instructions.hpp"

struct GoRPCPackage_Transport {
    uint32_t addr;
    uint32_t len;
    char data[256];
};

typedef void (*callback_pullPackage)(GoRPCPackage_Transport *src, void *args);
typedef void (*callback_pushPackage)(GoRPCPackage_Transport *dest, void *args);
typedef void (*callback_pushCIInstruction)(CI_Instruction_Transport *src, void *args);

class GobotRPC_TI_Hardware {
public:
    virtual void registerPullPackageCB(callback_pullPackage cb, void *args) = 0;
    virtual void registerPushPackageCB(callback_pushPackage cb, void *args) = 0;
    virtual void registerPushCIInstructionCB(callback_pushCIInstruction cb, void *args) = 0;
    virtual void setAddrMap(uint32_t addr, int intNum) = 0;

    void raiseTranmissionError(bool rx, uint32_t addr);
    void raiseTransmissionSuceess(uint32_t addr);
    void raiseInfoReset();
};

void i2cRxTaskFn(void * args);
void i2cTxTaskFn(void * args);

void intPin_ISR(uint gpio, uint32_t events);

class GobotRPC_TI_Hardware_RP2040_I2C : public GobotRPC_TI_Hardware {
private:
    callback_pullPackage pullPackageCB;
    void *pullPackageCBArgs;

    callback_pushPackage pushPackageCB;
    void *pushPackageCBArgs;

    callback_pushCIInstruction pushCIInstructionCB;
    void *pushCIInstructionCBArgs;

    SemaphoreHandle_t i2cMutex;
    SemaphoreHandle_t i2cRXSemaphore;


    TaskHandle_t i2cRxTaskHandle;
    TaskHandle_t i2cTxTaskHandle;
    TaskHandle_t i2cIntTaskHandle;
    TaskHandle_t revCIInstructionTaskHandle;

    QueueHandle_t revCIInstructionQueue;

    UBaseType_t core;

    i2c_inst_t * i2c;

    uint32_t intAddressMap[GOBOTRPC_TI_INT_NUM];

    void initTasks();
    bool readI2C(GoRPCPackage_Transport * pkg, uint32_t addr);

public:
    GobotRPC_TI_Hardware_RP2040_I2C(UBaseType_t core, i2c_inst_t *i2c, QueueHandle_t revCIInstructionQueue);

    void registerPullPackageCB(callback_pullPackage cb, void *args);
    void registerPushPackageCB(callback_pushPackage cb, void *args);
    void registerPushCIInstructionCB(callback_pushCIInstruction cb, void *args);
    
    void setAddrMap(uint32_t addr, int intNum);

    void i2cRxTask();
    void i2cTxTask();
    void manualTriggerIntTask();
    void intPinISR(BaseType_t * xHigherPriorityTaskWoken);
    uint32_t readIntPins();

    void raiseTranmissionError(bool rx, uint32_t addr);
    void raiseTransmissionSuceess(uint32_t addr);
    void raiseInfoReset();

    void revCIInstructionTask();
};


extern GobotRPC_TI_Hardware_RP2040_I2C * g_GobotRPC_TI_Hardware_RP2040_I2C;