#include "hart_xor.h"
#include "hart_serial.h"
#include "hart_lib.h"

//=========================== defines =========================================

#define CMD_EXPANSION_FLAG        31

#define DELIM_PHYLAYER_ASYNC    0x00
#define DELIM_FRAME_BACK        0x01
#define DELIM_FRAME_STX         0x02
#define DELIM_FRAME_ACK         0x06

//=========================== typedef =========================================

typedef struct
{
    // request callback to upper layer - commands that are not terminated in OEM MCU
    hart_serial_request_cbt  requestCb;

    // sending replies to Modem port
    uint8_t                  toModemBuf[HART_MAX_FRAME_LENGTH];
    // receiving cmds from Modem port
    uint8_t                  fromModemBuf[HART_MAX_FRAME_LENGTH];

    // mote address
    uint8_t                  broadcastAddr[UNIQUE_ADDR_LEN];
    uint8_t                  uniqueAddr[UNIQUE_ADDR_LEN];    // 38 LS bits
    uint8_t                  pollingAddr;                    // 6  LS bits

    // storing parameters; must reply with same parameters as received
    hart_lib_master_t        hartMaster;
    bool                     pollingAddrUsed;
    bool                     broadcastAddrUsed;
    bool                     token;
    uint16_t                 cmdId;
} hart_serial_vars_t;

//=========================== variables =======================================

hart_serial_vars_t hart_serial_vars;

//=========================== prototype =======================================

void hart_serial_rxHartFrame(uint8_t* rxAddr, bool pollingAddr, uint8_t rxCmd, uint8_t* rxData, uint8_t rxDataLen, uint8_t rxError);

//=========================== public ==========================================

void hart_serial_init(uint8_t* macAddr, uint8_t pollingAddr, hart_serial_request_cbt requestCb)
{
    // reset local variables
    memset(&hart_serial_vars, 0, sizeof(hart_serial_vars));

    // create unique address
    memcpy(hart_serial_vars.uniqueAddr, &macAddr[3], 5);
    hart_serial_vars.uniqueAddr[0] &= 0x3F;

    // store params
    hart_serial_vars.pollingAddr    = pollingAddr;
    hart_serial_vars.requestCb      = requestCb;

    // initialize the XOR module
    hart_xor_init(
        hart_serial_rxHartFrame,
        hart_serial_vars.fromModemBuf,
        sizeof(hart_serial_vars.fromModemBuf)
    );
}

void hart_serial_txHartFrame(uint16_t cmd, uint8_t* response, uint8_t response_len)
{
    
}

//=========================== private ==========================================

void hart_serial_rxHartFrame(uint8_t* rxAddr, bool pollingAddr, uint8_t rxCmd, uint8_t* rxData, uint8_t rxDataLen, uint8_t rxError)
{
    
}
//=========================== helpers ==========================================

// serial communication error handling
void hart_serial_errorReply(uint8_t cmdId, uint8_t errCode)
{
    uint8_t thisErr = HART_ERR_BUFF_OVF | HART_ERR_COMMUNICATION | HART_ERR_COM;

    if (errCode != 0)
        thisErr = errCode;

    // send error if it was not broadcasted
    if (!hart_serial_vars.broadcastAddrUsed)
        hart_serial_txHartFrame(cmdId, &thisErr, 1);
}
