#include "proto_modbus_lib.h"
#include "stdio.h"
#include "string.h"
#include "bsp_Uart.h"

/**************************************************
 *名称： modbus_lib_crc16
 *功能： modbus crc16校验
 *参数： p_data -- 校验数据指针
 *       len    -- 数据长度 
 *返回： 校验结果（小端序）
**************************************************/
u16 modbus_lib_crc16(u8 *p_data, u16 len)
{
    u16 crc16 = 0xFFFF;
    u16 i, j;
    for (i = 0; i < len; i++) {
        crc16 ^= p_data[i];
        for (j = 0; j < 8; j++) {
            if (crc16 & 0x0001) {
                crc16 >>= 1;
                crc16 ^= 0xA001;
            } else {
                crc16 >>= 1;
            }
        }
    }
    return crc16;
}

/************************************
 * 函数: Float2u16
 * 功能: 提取浮点数的高16或低16位
 * 参数: float_data : 要转换的浮点数
         h_l      : 返回高16位还是低16位
 * 返回: 返回对应的高16位还是低16位
 * 描述: 无
 ******************************************/
u16 float_to_u16(float float_data,unsigned char h_l)
{
  u16 temp = 0XFFFF;
  if(h_l == U16_DATA_L)
  {
    temp = *((u32 *)&float_data) & 0x0000ffff; 
  }
  else if(h_l == U16_DATA_H)
  {
    temp = ((*((u32 *)&float_data)) >> 16) & 0x0000ffff;
  }
  return temp;
}

/******************************************
 * 函数: u32TOu16
 * 功能: 提取u32的高16或低16位
 * 参数: u32_data   : 要转换的u32
         h_l      : 返回高16位还是低16位
 * 返回: 返回对应的高16位还是低16位
 * 描述: 无
 ******************************************/
u16 u32_to_u16(u32 u32_data,unsigned char h_l)
{
  u16 temp = 0XFFFF;
  if(h_l == U16_DATA_L)
  {
    temp = u32_data & 0x0000ffff; 
  }
  else if(h_l == U16_DATA_H)
  {
    temp = (u32_data >> 16) & 0x0000ffff;
  }
  return temp;
}

void u32_to_u8(u32 u32_data,u8 *p_data,u8 endian)
{
    if(BIG_ENDIAN == endian)
    {
        for(u8 i = 0;i < 4;i++)
        {
            p_data[i] = (u32_data >> (8 * (3 - i))) & 0xff;
        } 
    }
    else if(LITTLE_ENDIAN == endian)
    {
        for(u8 i = 0;i < 4;i++)
        {
            p_data[i] = (u32_data >> (8 * i)) & 0xff;
        } 
    }
}

void u16_to_u8(u16 u16_data,u8 *p_data,u8 endian)
{
    if(BIG_ENDIAN == endian)
    {
        for(u8 i = 0;i < 2;i++)
        {
            p_data[i] = (u16_data >> (8 * (1 - i))) & 0xff;
        } 
    }
    else if(LITTLE_ENDIAN == endian)
    {
        for(u8 i = 0;i < 2;i++)
        {
            p_data[i] = (u16_data >> (8 * i)) & 0xff;
        } 
    }
}

float u32_to_float(u32 u32_data,unsigned char h_l)
{
    float temp = 0;
    temp = *((float *)&u32_data); 
    return temp;
}

/*将u8_endian端序的p_u8data转换为单片机对应的小端序*/
u32 u8_to_u32(u8 *p_u8data,unsigned char u8_endian)
{
    u32 temp = 0;
    if(BIG_ENDIAN == u8_endian)
    {
        for(u8 i = 0;i < 4;i++)
        {
            temp |= p_u8data[i] << ((3 - i) * 8);  
        } 
    }
    else if(LITTLE_ENDIAN == u8_endian)
    {
        for(u8 i = 0;i < 4;i++)
        {
            temp |= p_u8data[i] << (i * 8);  
        }
    }
    return temp;
}

/*将u8_endian端序的p_u8data转换为单片机对应的小端序*/
u16 u8_to_u16(u8 *p_u8data,unsigned char u8_endian)
{
    u32 temp = 0;
    if(BIG_ENDIAN == u8_endian)
    {
        for(u8 i = 0;i < 2;i++)
        {
            temp |= p_u8data[i] << ((1 - i) * 8);  
        } 
    }
    else if(LITTLE_ENDIAN == u8_endian)
    {
        for(u8 i = 0;i < 2;i++)
        {
            temp |= p_u8data[i] << (i * 8);  
        }
    }
    return temp;
}

/*字节端序转换*/
u32 u32_endian_conv(u32 data)
{
    u32 temp = 0;
    temp =   (((data >> 0 ) & 0xff) << 24)
               | (((data >> 8 ) & 0xff) << 16)
               | (((data >> 16) & 0xff) << 8 )
               | (((data >> 24) & 0xff) << 0 );
     return temp;
}

/*字节端序转换*/
u16 u16_endian_conv(u16 data)
{
    u16 temp = 0;
    temp =    (((data >> 0) & 0xff) << 8)
               | (((data >> 8) & 0xff) << 0);
     return temp;
}


/******************************************
* 函数: ModbusReaddata
* 功能: MODBUS读数据
* 参数: Id   :MODBUS从机地址
*       addr :写数据的起始地址
*       Num  :写的寄存器数量
*       send  :串口发送函数
* 返回: 无
* 描述: 无
******************************************/
void modbus_lib_data_read(u8 id,u16 addr,u16 num,void (*send)(u8 *,u16 ))
{
  u8 tx[8];
  u16 crc16;
  tx[0] = id;
  tx[1] = 0x03;//0x03;
  tx[2] = (addr >> 8) & 0xff;
  tx[3] = addr & 0xff;
  tx[4] = (num >> 8) & 0xff;
  tx[5] = num & 0xff;
  crc16 = modbus_lib_crc16(tx,6);
  tx[6] = crc16 & 0xff;
  tx[7] = (crc16 >> 8) & 0xff;  
  send(tx,8);
}

/******************************************
* 函数: modbus_multiple_data_write
* 功能: MODBUS写数据
* 参数: Id   :MODBUS从机地址
*       addr :写数据的起始地址
*       Num  :写的寄存器数量
*       data :写的数据
*       send  :串口发送函数
* 返回: 无
* 描述: 无
******************************************/
void modbus_lib_multiple_data_write(u8 id,u16 addr,u16 Num,u16 *data,void (*send)(u8 *,u16 ))
{
  u8 tx[50];
  u16 crc16,i;
  tx[0] = id;
  tx[1] = 0x10;
  tx[2] = (addr >> 8) & 0xff;
  tx[3] = addr & 0xff;
  tx[4] = (Num >> 8) & 0xff;
  tx[5] = Num & 0xff;
  tx[6] = Num * 2;
  for(i = 0;i < tx[6]/2;i++)
  {
    tx[7 + 2 * i] = (data[i] >> 8) & 0xff;
    tx[8 + 2 * i] = data[i] & 0xff;  
  }
  crc16 = modbus_lib_crc16(tx,7 + 2 * i);
  tx[7 + 2 * i] = crc16 & 0xff;
  tx[8 + 2 * i] = (crc16 >> 8) & 0xff;  
  send(tx,9 + 2 * i);
}

void modbus_lib_only_data_write(u8 id,u16 addr,u16 value,void (*send)(u8 *,u16 ))
{
  u8 tx[8];
  u16 crc16;
  tx[0] = id;
  tx[1] = 0x06;
  tx[2] = (addr >> 8) & 0xff;
  tx[3] = addr & 0xff;
  tx[4] = (value >> 8) & 0xff;
  tx[5] = value & 0xff;  
  crc16 = modbus_lib_crc16(tx,6);
  tx[6] = crc16 & 0xff;
  tx[7] = (crc16 >> 8) & 0xff;  
  send(tx,8);
}


//01    10      00 02           00 01        02               12 34          CRC
//id    Func    Startaddress    RegNumber    wdataaddress    
u8 modbus_lib_analysis(modbus_analysis_data_t *p_modbus, u8 *p_data, u16 len)
{
    u16 crc16;
    u16 u16_temp;

    if(NULL == p_modbus) return 0;
    if(len < 8) return 0;

    crc16 = modbus_lib_crc16(p_data, len-2);
    u16_temp = *(p_data+len-1);
    u16_temp <<= 8;
    u16_temp |= *(p_data+len-2);
    if(u16_temp != crc16) return 0;

    p_modbus->id = *p_data;
    p_modbus->func = *(p_data+1);

    p_modbus->start_addr = (*(p_data+2))<<8;
    p_modbus->start_addr |= *(p_data+3);

    /*单独写一个寄存器*/
    if(0x06 == p_modbus->func)
    {
        p_modbus->write_data_addr = p_data+4;
    } 
    else if(0x10 == p_modbus->func) /*写多个寄存器*/
    {
        p_modbus->reg_number = (*(p_data+4))<<8;
        p_modbus->reg_number |= *(p_data+5);
        p_modbus->write_data_addr = p_data+7;
    }
    else
    {
        p_modbus->reg_number = (*(p_data+4))<<8;
        p_modbus->reg_number |= *(p_data+5);
    } 
    return 1;
}
