/**
************************************************************************************************
* @文件    : fly_modbus.c
* @作者    : 樊春春
* @版本    : V1.0
* @时间    : 2022/05/30 22:46:49
* @邮箱    : fanchcho@gmail.com
* @说明    :
************************************************************************************************
**/

#include "modbus.h"

INT16U misc_info_buf[BUF_LEN_128] = {0};
INT16U cell_temp_buf[BUF_LEN_512] = {0};
INT16U samkoon_txbuf[BUF_LEN_128] = {0};

/****************************************************
 * @函数    : crc_count
 * @作者    : 樊春春
 * @功能    : 计算CRC数据
 * @入参    : addr: 数据指针   num: 数量
 * @说明    : 无
 *****************************************************/
unsigned short crc_count(const INT8U *addr, int num)
{
    unsigned short crc = 0xFFFF;
    int            i;
    while (num--)
    {
        crc ^= *addr++;
        for (i = 0; i < 8; i++)
        {
            crc = (crc & 0x0001) ? ((crc >> 1) ^ 0xA001) : (crc >> 1);
        }
    }
    return crc;
}

/****************************************************
 * @函数    : crc_write
 * @作者    : 樊春春
 * @功能    : CRC写入
 * @入参    : p: 数据指针   data: crc值   count: 写入位置
 * @说明    : 无
 *****************************************************/
void crc_write(INT8U *p, INT16U data, INT8U count)
{
    p    = p + (2 * count + 3);
    *p++ = (INT8U)data;
    *p++ = (INT8U)(data >> 8);
}

/****************************************************
 * @函数    : little2big
 * @作者    : 樊春春
 * @功能    : 小端转大端
 * @入参    : buf: 数据指针   count: 个数
 * @说明    : 无
 *****************************************************/
void little2big(INT16U *buf, INT16U count)
{
    INT8U  i      = 0;
    INT8U *p      = (INT8U *)buf;
    INT8U *p_next = (INT8U *)buf + 1;
    char   tmp;
    for (i = 0; i < 2 * count; i++)
    {
        tmp     = *p;
        *p      = *p_next;
        *p_next = tmp;
        p       = p + 2;
        p_next  = p_next + 2;
    }
}

/****************************************************
 * @函数    : modbus_head
 * @作者    : 樊春春
 * @功能    : Mosbus头拷贝
 * @入参    : des_data: 目标数据指针   src_data: 源数据指针
 * @说明    : 无
 *****************************************************/
void modbus_head(INT8U *des_data, INT8U *src_data)
{
    INT8U i = 0;
    for (i = 0; i < 2; i++)
    {
        *des_data++ = *src_data++;
    }
    src_data  = src_data + 3;
    *des_data = (*src_data) * 2;
}

/*--------------------------------------------
** func ：ImportantData_TxGet
** brief：copy send data;
          soc 1th start from 0x4001;
** para : samkoon_txbuf\misc_info_buf for use
--------------------------------------------*/
void ImportantData_TxGet(INT16U pos, INT16U cnt, INT8U *des_data, INT8U *src_data)
{
    INT8U i  = 0;
    pos      = pos - 0x4001; // addr offset 4300 hex
    src_data = src_data + pos;
    des_data = des_data + 6; // cell txbuf offset:6

    for (i = pos; i < cnt; i++)
    {
        *des_data++ = *src_data++;
    }
}

/*---------------------------------------
** func ：Cell_Info_ReadOut
** brief：copy cell data
          1th start from 0x4301
** para ：none
---------------------------------------*/
void Cell_Info_ReadOut(INT16U *p)
{
    INT8U i, j;

    for (i = 0; i < 6; i++)
    {
        for (j = 0; j < 6; j++)
        {
            *p++ = 3300;
        }
    }

    //	for(i = 0;i < config_get_slave_num(); i++)   // without offset
    //  {
    //		 for(j = 0;j < bmu_get_cell_num(i); j++)
    //	   {
    //			 *p++ = 3300; //bmu_get_cell_vol(i,j);
    //		 }
    //	}
}
/*---------------------------------------
** func ：Cell_Info_TxGet
** brief: none
** para ：position \ cnt
---------------------------------------*/

void Cell_Info_TxGet(INT16U pos, INT16U cnt, INT8U *des_data, INT8U *src_data)
{
    INT8U i  = 0;
    pos      = pos - 0x4300; // addr offset 4300 hex
    src_data = src_data + pos;
    des_data = des_data + 6; // cell txbuf offset:6

    for (i = pos; i < cnt; i++)
    {
        *des_data++ = *src_data++;
    }
}

/*---------------------------------------
** func ：Temperature_ReadOut
** brief：copy temperature data,
          1th start from 0x55C1
          offset -40
** para ：none
---------------------------------------*/
void Temperature_ReadOut(INT16U *p)
{
    INT8U i, j;
    for (i = 0; i < 6; i++)
    {
        for (j = 0; j < 6; j++)
        {
            *p++ = 20;
        }
    }

    //	for(i = 0;i < config_get_slave_num(); i++)   // without offset     //PackNum = (total + (singleNum - 1))/singleNum
    //  {
    //		 for(j = 0;j < bmu_get_temp_num(i); j++)
    //	   {
    //		    *p++ = bmu_get_cell_temp(i,j);
    //		 }
    //	}
}

/*---------------------------------------
** func ：Cell_Info_TxGet
** brief: none
** para ：position \ cnt
---------------------------------------*/
void Temperature_TxGet(INT16U pos, INT16U cnt, INT8U *des_data, INT8U *src_data)
{
    INT8U i  = 0;
    pos      = pos - 0x55c0; // addr offset 55c0 hex
    src_data = src_data + pos;
    des_data = des_data + 6; // tmp txbuf offset:6

    for (i = pos; i < cnt; i++)
    {
        *des_data++ = *src_data++;
    }
}
/*---------------------------------------
** func ：Rtu_TxData_Get()
** brief: none
** para ：position \ cnt
---------------------------------------*/
void Rtu_TxData_Get(INT16U pos,
                    INT16U cnt,
                    INT16U addr_start,
                    INT8U  fotmat_offset, // fotmat_offset:3
                    INT8U *des_data,
                    INT8U *src_data)
{
    INT8U i = 0;
    if (pos < addr_start)
        return;

    pos      = pos - addr_start; // addr offset 55c0 hex
    src_data = src_data + pos * 2;
    //	des_data = des_data + fotmat_offset;
    des_data = (INT8U *)des_data + fotmat_offset;
    for (i = 2 * pos; i < 2 * cnt; i++)
    {
        *des_data++ = *src_data++;
    }
}

/*----------------------------------------------
** @func  : samkoon_com_work
** @brief : BMS with samkoon communication
** format :  xx     xx   xx xx   xx xx    xx xx
             addr  func  -reg-  -count-   -crc-
      ans:   xx     xx   xx xx   xx....xx    xx xx
             addr  func  count-  --data--    -crc-

crc:small  other:big
-----------------------------------------------*/
void samkoon_com_work(INT8U *rec_data, void (*tx_p)(const INT8U *buf, INT16U len))
{
    INT16U          register_addr_hmi;
    INT16U          tmp_crc;
    volatile INT16U register_count;
    volatile INT8U  illegal_flag  = 0;
    INT8U           function_code = 0;

    register_addr_hmi = (rec_data[REGISTER_ADDR_H] << 8) + rec_data[REGISTER_ADDR_L];
    register_count    = (rec_data[COUNT_INDEX_H] << 8) + rec_data[COUNT_INDEX_L];
    function_code     = rec_data[FUNCTION_CODE_INDEX];

    switch (function_code)
    {
    case FUNC_03:
        if ((register_addr_hmi >= MODBUS_ADDR_RACK_REMOTE) && (register_addr_hmi < MODBUS_ADDR_RACK_REMOTE_END))
        {
            modbus_head((INT8U *)samkoon_txbuf, rec_data);
            // Important_Bin_ReadOut(misc_info_buf);
            little2big(misc_info_buf, register_count);
            Rtu_TxData_Get(register_addr_hmi, register_count, 0xc9, 3, (INT8U *)samkoon_txbuf, (INT8U *)misc_info_buf);
            tmp_crc = crc_count((INT8U *)samkoon_txbuf, 2 * register_count + 3);
            crc_write((INT8U *)samkoon_txbuf, tmp_crc, register_count);
            //				samkoon_txbuf[register_count + 2] = tmp_crc;
            tx_p((INT8U *)samkoon_txbuf, (2 * register_count + 5));
        }
        else if ((register_addr_hmi >= MODBUS_ADDR_SOC) && (register_addr_hmi < MODBUS_RACK_END))
        {
            modbus_head((INT8U *)samkoon_txbuf, rec_data);
            // ImportantData_Readout(misc_info_buf);
            little2big(misc_info_buf, register_count);
            Rtu_TxData_Get(register_addr_hmi, register_count, 0x4101, 3, (INT8U *)samkoon_txbuf, (INT8U *)misc_info_buf);
            tmp_crc = crc_count((INT8U *)samkoon_txbuf, 2 * register_count + 3);
            crc_write((INT8U *)samkoon_txbuf, tmp_crc, register_count);
            //			   	samkoon_txbuf[register_count + 2] = tmp_crc;
            tx_p((INT8U *)samkoon_txbuf, (2 * register_count + 5));
        }
        else if ((register_addr_hmi >= MODBUS_ADDR_CELL) && (register_addr_hmi < MODBUS_CELL_END))
        {
            modbus_head((INT8U *)samkoon_txbuf, rec_data);
            Cell_Info_ReadOut(cell_temp_buf); // read all cell data
            little2big(cell_temp_buf, register_count);
            Rtu_TxData_Get(register_addr_hmi, register_count, 0x4301, 3, (INT8U *)samkoon_txbuf, (INT8U *)cell_temp_buf);
            tmp_crc = crc_count((INT8U *)samkoon_txbuf, 2 * register_count + 3);
            crc_write((INT8U *)samkoon_txbuf, tmp_crc, register_count);
            //			     samkoon_txbuf[register_count + 2] = tmp_crc;
            tx_p((INT8U *)samkoon_txbuf, (2 * register_count + 5));
        }
        else if ((register_addr_hmi >= MODBUS_ADDR_TEMP) && (register_addr_hmi < MODBUS_TEMP_END))
        {
            modbus_head((INT8U *)samkoon_txbuf, rec_data);
            Temperature_ReadOut(cell_temp_buf); // read all temp data
            little2big(cell_temp_buf, register_count);
            Rtu_TxData_Get(register_addr_hmi, register_count, 0x55c1, 3, (INT8U *)samkoon_txbuf, (INT8U *)cell_temp_buf);
            tmp_crc = crc_count((INT8U *)samkoon_txbuf, 2 * register_count + 3);
            crc_write((INT8U *)samkoon_txbuf, tmp_crc, register_count);
            //			     samkoon_txbuf[register_count + 2] = tmp_crc;
            tx_p((INT8U *)samkoon_txbuf, (2 * register_count + 5));
        }
        else if ((register_addr_hmi >= MODBUS_ADDR_READ_KA) && (register_addr_hmi < MODBUS_KA_END))
        {
            modbus_head((INT8U *)samkoon_txbuf, rec_data);
            // Relay_Bin_Readout(misc_info_buf);
            little2big(misc_info_buf, register_count);
            Rtu_TxData_Get(register_addr_hmi, register_count, 0x1001, 3, (INT8U *)samkoon_txbuf, (INT8U *)misc_info_buf);
            tmp_crc = crc_count((INT8U *)samkoon_txbuf, 2 * register_count + 3);
            crc_write((INT8U *)samkoon_txbuf, tmp_crc, register_count);
            //			   	 samkoon_txbuf[register_count + 2] = tmp_crc;
            tx_p((INT8U *)samkoon_txbuf, (2 * register_count + 5));
        }
        break;
    /* do other work... */
    case FUNC_05:
        break;

    default:
        illegal_flag = 1;
        break;
    }
}

void modbus_slave_task(void)
{
    INT8U              err          = 0;
    INT8U              test_buf[20] = {0};
    UartFrame_TypeDef *msg;
    while (1)
    {
        OSTimeDly(200);
        iwdg_feed(UART3_DOG);
        msg = (UartFrame_TypeDef *)OSMboxPend(uart3_mbox, 50, &err);
        if ((err == OS_ERR_NONE) && (msg->len >= 2))
        {
            if ((msg->buf[0] == 0x00) && (msg->buf[1] == 0xAA) && (msg->buf[2] == 0xBB))
            {
                test_buf[0] = 0x00;
                test_buf[1] = 0xBB;
                test_buf[2] = 0xAA;
                uart3_dma_send(test_buf, 3);
            }
        }
    }
}
