/**
 * @file seasky_protocol.c
 * @author Liu Wei
 * @author modified by Neozng
 * @brief 湖南大学RoBoMatster串口通信协议
 * @version 0.1
 * @date 2022-11-03
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#include "seasky_protocol.h"
#include "crc8.h"
#include "crc16.h"

/*获取CRC8校验码*/
uint8_t Get_CRC8_Check(uint8_t *pchMessage, uint16_t dwLength)
{
    return crc_8(pchMessage, dwLength);
}
/*检验CRC8数据段*/
uint8_t CRC8_Check_Sum(uint8_t *pchMessage, uint16_t dwLength)
{
    uint8_t ucExpected = 0;
    if ((pchMessage == 0) || (dwLength <= 2))
        return 0;
    ucExpected = Get_CRC8_Check(pchMessage, dwLength - 1);
    return (ucExpected == pchMessage[dwLength - 1]);
}
/*获取CRC16校验码*/
uint16_t Get_CRC16_Check(uint8_t *pchMessage, uint32_t dwLength)
{
    return crc_16(pchMessage, dwLength);
}
/*检验CRC16数据段*/
uint16_t CRC16_Check_Sum(uint8_t *pchMessage, uint32_t dwLength)
{
    uint16_t wExpected = 0;
    if ((pchMessage == 0) || (dwLength <= 2))
    {
        return 0;
    }
    wExpected = Get_CRC16_Check(pchMessage, dwLength - 2);
    return (((wExpected & 0xff) == pchMessage[dwLength - 2]) && (((wExpected >> 8) & 0xff) == pchMessage[dwLength - 1]));
}
/*检验数据帧头*/
uint8_t protocol_heade_Check(protocol_rm_struct *pro,uint8_t *rx_buf)
{
    if (rx_buf[0] == PROTOCOL_CMD_ID)
    {
        pro->header.sof = rx_buf[0];
        if (CRC8_Check_Sum(&rx_buf[0], 4))
        {
            pro->header.data_length = (rx_buf[2] << 8) | rx_buf[1];
            pro->header.crc_check = rx_buf[3];
            pro->cmd_id = (rx_buf[5] << 8) | rx_buf[4];
            return 1;
        }
    }
    return 0;
}

float float_protocol(uint8_t *dat_t)
{
    uint8_t f_data[4];
    f_data[0] = *(dat_t + 0);
    f_data[1] = *(dat_t + 1);
    f_data[2] = *(dat_t + 2);
    f_data[3] = *(dat_t + 3);
    return *(float *)f_data;
}
/*
    此函数根据待发送的数据更新数据帧格式以及内容，实现数据的打包操作
    后续调用通信接口的发送函数发送tx_buf中的对应数据
*/
void get_protocol_send_data(uint16_t send_id,        //信号id
                            uint16_t flags_register, // 16位寄存器
                            float *tx_data,          //待发送的float数据
                            uint8_t float_length,    // float的数据长度
                            uint8_t *tx_buf,         //待发送的数据帧
                            uint16_t *tx_buf_len)    //待发送的数据帧长度
{
    static uint16_t crc16;
    static uint16_t data_len;

    data_len = float_length * 4 + 2;
    /*帧头部分*/
    tx_buf[0] = PROTOCOL_CMD_ID;
    tx_buf[1] = data_len & 0xff;               //低位在前
    tx_buf[2] = (data_len >> 8) & 0xff;        //低位在前
    tx_buf[3] = Get_CRC8_Check(&tx_buf[0], 3); //获取CRC8校验位

    /*数据的信号id*/
    tx_buf[4] = send_id & 0xff;
    tx_buf[5] = (send_id >> 8) & 0xff;

    /*建立16位寄存器*/
    tx_buf[6] = flags_register & 0xff;
    tx_buf[7] = (flags_register >> 8) & 0xff;

    /*float数据段*/
    for (int i = 0; i < 4 * float_length; i++)
    {
        tx_buf[i + 8] = ((uint8_t *)(&tx_data[i / 4]))[i % 4];
    }

    /*整包校验*/
    crc16 = Get_CRC16_Check(&tx_buf[0], data_len + 6);
    tx_buf[data_len + 6] = crc16 & 0xff;
    tx_buf[data_len + 7] = (crc16 >> 8) & 0xff;

    *tx_buf_len = data_len + 8;
}
/*
    此函数用于处理接收数据，
    返回数据内容的id
*/
uint16_t get_protocol_info(uint8_t *rx_buf,          //接收到的原始数据
                           uint16_t *flags_register, //接收数据的16位寄存器地址
                           float *rx_data)           //接收的float数据存储地址
{
    static protocol_rm_struct pro;
    static uint16_t date_length;
    if (protocol_heade_Check(&pro, rx_buf))
    {
        date_length = OFFSET_BYTE + pro.header.data_length;
        while (CRC16_Check_Sum(&rx_buf[0], date_length))
        {
            *flags_register = (rx_buf[7] << 8) | rx_buf[6];
            for (int i = 0; i < (pro.header.data_length - 2) / 4; i++)
            {
                rx_data[i] = float_protocol(&rx_buf[8 + 4 * i]);
            }
            for (int i = 0; i < date_length; i++)
            {
                rx_buf[i] = 0;
            }
            return pro.cmd_id;
        }
    }
    return 0;
}
