/*-------------------------------------------------------------------------------------------------
--
-- File Name    : coaxpressHost.c



-- Description  : This module replicates the CoaXPress Host Driver modules.




-- Targeted device : Microchip FPGAs
-- Author          : India Solutions Team




--
-- COPYRIGHT 2023 BY MICROCHIP
-- THE INFORMATION CONTAINED IN THIS DOCUMENT IS SUBJECT TO LICENSING RESTRICTIONS
-- FROM MICROCHIP CORP.  IF YOU ARE NOT IN POSSESSION OF WRITTEN AUTHORIZATION FROM
-- MICROCHIP FOR USE OF THIS FILE, THEN THE FILE SHOULD BE IMMEDIATELY DESTROYED AND
-- NO BACK-UP OF THE FILE SHOULD BE MADE.
--



-------------------------------------------------------------------------------------------------*/

#include "hal/hal.h"

#include "coaxpressBootstrapReg.h"
#include "coaxpressCrc.h"
#include "coaxpressHost.h"

extern volatile uint8_t irq_flag_device;

void msdelay1(uint32_t tms)
{
    int i = 0;
    for(i = 0; i < 50000; i++);
}

uint32_t swap_msb_lsb_8bit(uint32_t input_32bit)
{
    unsigned char data_char[FOUR_BYTES];
    unsigned char swap_data_char[FOUR_BYTES];

    for (unsigned char i = 0; i < 4; i++)
    {
        data_char[i] = (input_32bit >> i * 8) & 0xff;
        swap_data_char[i] = ((data_char[i] & 1) << 7) | ((data_char[i] & 2) << 5) | ((data_char[i] & 4) << 3) | ((data_char[i] & 8) << 1) | ((data_char[i] & 16) >> 1) | ((data_char[i] & 32) >> 3) | ((data_char[i] & 64) >> 5) | ((data_char[i] & 128) >> 7);
    }

    input_32bit = (swap_data_char[3] << 24) | (swap_data_char[2] << 16) | (swap_data_char[1] << 8) | swap_data_char[0];

    return input_32bit;
}

//Coaxpress Crc Calculation
uint32_t calculate_coaxpress_crc32(uint32_t crc_buffer[], uint8_t crc_count)
{
    uint32_t crc_in, crc_out = 0xffffffff;
    uint32_t len, index,i;
    unsigned char buf[FOUR_BYTES];


    for (i = 0; i < crc_count; i++)
    {
        index = 4;

        crc_in = swap_msb_lsb_8bit(crc_buffer[i]);

        buf[0] = crc_in & 0xff;
        buf[1] = (crc_in >> 8) & 0xff;
        buf[2] = (crc_in >> 16) & 0xff;
        buf[3] = (crc_in >> 24) & 0xff;

        while (index--)
        {
            crc_out = (crc_out << 8) ^ crc32_table[((crc_out >> 24) ^ buf[index]) & 255];

        }
    }

    crc_out = swap_msb_lsb_8bit(crc_out);

    return crc_out;
}

uint8_t wait_for_deviceirq()
{
    uint32_t i;
    //i = 0;
    do {
        if (irq_flag_device == 1)
        {
            irq_flag_device = 0;

            break;
        }
        else
        {
            i++;
            if (i == 10*50000)
            {
                return 0;
            }
        }
    } while (1);

    return 1;
}

void send_cmd(uint32_t tx_command[], uint8_t tag, uint8_t size)
{
    *(volatile int*) CMD_WR_ADDRESS = START_OF_THE_PACKET;
    if (tag == 0)
        *(volatile int*) CMD_WR_ADDRESS = CONTROL_CMD_WITHOUT_TAG;
    else
        *(volatile int*) CMD_WR_ADDRESS = CONTROL_CMD_WITH_TAG;

    for(uint32_t i=0; i<size; i++)
    {
        *(volatile int*) CMD_WR_ADDRESS = tx_command[i];
    }

    *(volatile int*) CMD_WR_ADDRESS = calculate_coaxpress_crc32(tx_command, size);
    *(volatile int*) CMD_WR_ADDRESS = END_OF_THE_PACKET;
}


void read_resp(uint32_t rd_pkt[])
{
    uint32_t i;

    for(i=0; i<10; i++)
    {
        rd_pkt[i] = 0;
    }

    rd_pkt[0] = *(volatile int*) RD_ACK_ADDRESS;  //length of read
    if(rd_pkt[0] > 128)
    {
        rd_pkt[0] = 0;   //if size is more than 128, exception will come
    }
    for(i=1; i<=rd_pkt[0]; i++)
    {
        rd_pkt[i] = *(volatile int*) RD_ACK_ADDRESS;
    }
}

uint8_t receive_resp_cmd(uint32_t rd_pkt[])
{
    uint8_t status;
    status = wait_for_deviceirq();
    read_resp(rd_pkt);
    msdelay1(10);
    return status;
}

void send_read_cmd(uint32_t crc_buffer[], uint32_t host_cmd_address, uint8_t tag, uint16_t size)
{
    uint8_t count = 0;
    crc_buffer[count++] = CONTROL_CMD_READ | size;
    crc_buffer[count++] = host_cmd_address;
    send_cmd(crc_buffer, tag, count);
    msdelay1(10);
}

void send_write_cmd(uint32_t crc_buffer[], uint32_t host_cmd_address, uint32_t host_cmd_wdata, uint8_t tag, uint16_t size)
{
    uint8_t count = 0;
    crc_buffer[count++] = CONTROL_CMD_WRITE | size;
    crc_buffer[count++] = host_cmd_address;
    crc_buffer[count++] = host_cmd_wdata;
    send_cmd(crc_buffer, tag, count);
    msdelay1(10);
}



