#pragma once
#include "ci/hardware.hpp"
#include <strings.h>

enum GobotRPC_CI_CMD {
    TX_CI_PACKET = 0x01,
    RX_CI_PACKET = 0x02,
    SET_ADDR_PORT_MAP = 0x03,

    SUCESS_TRANMISSION = 0xfc,
    ERROR_TRANMISSION = 0xfd,
    HEARTBEAT = 0xff,

    RESET_CI_PACKET = 0xcc,
    RESET_INFO_CI_PACKET = 0xcd
};

#define CI_TX_PACKAGE_DATA_OFFSET 6
#define CI_TX_PACKAGE_SIZE(data_len) (data_len + CI_TX_PACKAGE_SIZE)

#define CI_RX_PACKAGE_DATA_OFFSET 6
#define CI_RX_PACKAGE_SIZE(data_len) (data_len + CI_RX_PACKAGE_DATA_OFFSET)

typedef void (*callback_TxPacket)(void * args, char *data, size_t len, uint32_t addr);
typedef void (*callback_SetAddress)(void * args, uint32_t addr, uint8_t port);

void GobotRPC_CI_rxData_cb(void * args, char *data, size_t len);
void GobotRPC_CI_heartBeatTaskFn(void *args);
void GobotRPC_CI_txCIInstructionTaskFn(void *args);

class GobotRPC_CI {
private:
    I_GobotRPC_CI_Hardware *hardware;

    callback_TxPacket cb_TxPacket;
    void * cb_TxPacket_args;

    callback_SetAddress cb_SetAddressMap;
    void * cb_SetAddressMap_args;

    TaskHandle_t heartBeatTaskHandle;
    TaskHandle_t txCIInstructionTaskHandle;

    QueueHandle_t ciInstructionQueue;
    QueueHandle_t ciInstructionReverseQueue;
public:
    GobotRPC_CI(I_GobotRPC_CI_Hardware *hardware, UBaseType_t core, QueueHandle_t ciInstructionQueue, QueueHandle_t ciInstructionReverseQueue);

    void registerCB_TxPacket(callback_TxPacket cb, void *args);
    void registerCB_SetAddress(callback_SetAddress cb, void *args);

    void send_RxPacket(char *data, size_t len, uint32_t addr);

    void onRxData(char *data, size_t len);

    void heartBeartTaskFn();

    // CI Instruction Stuff
    void send_rev_SetAddrMap(uint32_t addr, uint8_t port);
    void txCIInstructionTask();
    void send_ErrorTransmission(bool rx, uint64_t addr);
    void send_SuccessTransmission(uint64_t addr);
    void send_InfoReset();
};