/*对外通讯 modbus从机*/
#include "proto_modbus_slave_ex.h"
#include "string.h"
#include "stdio.h"

#include "app.h"
#include "app_timer.h"

#include "bsp_Uart.h"
#include "bsp_Flash.h"

#include "proto_print.h"
#include "proto_modbus_master_tdlas.h"

static modbus_analysis_data_t modbus_analysis_data;//指令解析结构体
static modbus_communication_send_buf_t send_struct;//发送结构体

static void proto_modbus_communication_data_analysis(u8 *pData, u16 len, void *data);
static void proto_modbus_communication_data_send(u8 *pData, u16 len);
static void proto_modbus_init(void);
static void proto_modbus_task(void);
static modbus_error_code_e proto_modbus_data_write(u16 Addr, u16 Value);
static u16 proto_modbus_data_read(u16 Addr);

proto_Modbus_t modbus_slave_ex=
{
    .id            = 0x01,
    .data_read     = proto_modbus_data_read,
    .data_write    = proto_modbus_data_write,
    .data_analysis = proto_modbus_communication_data_analysis,
    .init          = proto_modbus_init,
    .task          = proto_modbus_task,
};

static proto_Modbus_t  *p_modbus = &modbus_slave_ex;
static bsp_uart_t * p_rx_uart;

static void proto_modbus_communication_data_send(u8 *p_data, u16 len)
{
    if(p_rx_uart != NULL)
    {
        p_rx_uart->send(p_rx_uart,p_data,len);
    } 
}

static void proto_modbus_init(void)
{
    p_modbus->id = Usr_Flash.FlashData.modbus_id;
    com_uart1.rx_data_analysis = proto_modbus_communication_data_analysis;
    com_uart4.rx_data_analysis = proto_modbus_communication_data_analysis; 
}
static void proto_modbus_task(void)
{
    
}

static void proto_modbus_communication_data_analysis(u8 *pData, u16 len,void *other_data)
{
  modbus_error_code_e error_code;
  u16 inx;
  u16 TempAddr, TempData, crc_16;

    
  if (0 == modbus_lib_analysis(&modbus_analysis_data, pData, len))//检查数据长度 校验是否正确
    return;
  if (p_modbus->id != modbus_analysis_data.id && modbus_analysis_data.id != 0xe8)//判断ID是否正确
    return; 

  error_code = ModbusErrorCode_Success;
  

/*  //检查地址是否超出范围
  if ((modbus_analysis_data.start_addr >= MODBUS_REG_LEN) || (modbus_analysis_data.reg_number >= MODBUS_REG_LEN) ||
      (modbus_analysis_data.start_addr + modbus_analysis_data.reg_number >= MODBUS_REG_LEN))
  {
    ErrorCode = ModbusErrorCode_IllegalAddr;
    goto Error;
  }
  */
    p_rx_uart = (bsp_uart_t*)other_data;
    switch (modbus_analysis_data.func)
    {
        case 0x03:
        case 0x04:
        {
            TempAddr = modbus_analysis_data.start_addr;
            send_struct.send_buffer[0] = modbus_analysis_data.id;
            send_struct.send_buffer[1] = modbus_analysis_data.func;
            send_struct.send_buffer[2] = 2 * modbus_analysis_data.reg_number;
            for (inx = 0; inx < modbus_analysis_data.reg_number; inx++)
            {
                TempData = proto_modbus_data_read(TempAddr);
                send_struct.send_buffer[3 + 2 * inx] = (TempData >> 8) & 0xff;
                send_struct.send_buffer[4 + 2 * inx] = TempData & 0xff;
                TempAddr++;
            }
            crc_16 = modbus_lib_crc16(send_struct.send_buffer, 3 + send_struct.send_buffer[2]);
            send_struct.send_buffer[3 + send_struct.send_buffer[2]] = crc_16 & 0xff;
            send_struct.send_buffer[4 + send_struct.send_buffer[2]] = (crc_16 >> 8) & 0xff;
            send_struct.len = 5 + send_struct.send_buffer[2];
        }goto Success;
        /*特殊协议*/
        case 0x41:
        {
            TempAddr = modbus_analysis_data.start_addr;
            send_struct.send_buffer[0] = modbus_analysis_data.id;
            send_struct.send_buffer[1] = modbus_analysis_data.func;
            send_struct.send_buffer[2] = modbus_analysis_data.start_addr >> 8;
            send_struct.send_buffer[3] = modbus_analysis_data.start_addr & 0xff;
            send_struct.send_buffer[4] = (2 * modbus_analysis_data.reg_number) >> 8;
            send_struct.send_buffer[5] = (2 * modbus_analysis_data.reg_number) & 0xff;
            for (inx = 0; inx < modbus_analysis_data.reg_number; inx++)
            {
                TempData = proto_modbus_data_read(TempAddr);
                send_struct.send_buffer[6 + 2 * inx] = (TempData >> 8) & 0xff;
                send_struct.send_buffer[7 + 2 * inx] = TempData & 0xff;
                TempAddr++;
            }
            crc_16 = modbus_lib_crc16(send_struct.send_buffer, 6 + 2 * modbus_analysis_data.reg_number);
            send_struct.send_buffer[6 + 2 * modbus_analysis_data.reg_number] = crc_16 & 0xff;
            send_struct.send_buffer[7 + 2 * modbus_analysis_data.reg_number] = (crc_16 >> 8) & 0xff;
            send_struct.len = 8 + 2 * modbus_analysis_data.reg_number;
        }goto Success;
        
        case 0x06:
        {
            TempAddr = modbus_analysis_data.start_addr;
            TempData = (modbus_analysis_data.write_data_addr[0] << 8) | modbus_analysis_data.write_data_addr[1];
            error_code = proto_modbus_data_write(TempAddr, TempData);
            if (error_code)
            {
                goto Error;
            }    

            send_struct.len = 8;
            send_struct.send_buffer[0] = modbus_analysis_data.id;
            send_struct.send_buffer[1] = modbus_analysis_data.func;
            send_struct.send_buffer[2] = modbus_analysis_data.start_addr >> 8;
            send_struct.send_buffer[3] = modbus_analysis_data.start_addr & 0xff;
            send_struct.send_buffer[4] = modbus_analysis_data.write_data_addr[0];
            send_struct.send_buffer[5] = modbus_analysis_data.write_data_addr[1];
            crc_16 = modbus_lib_crc16(send_struct.send_buffer, 6);
            send_struct.send_buffer[6] = crc_16 & 0xff;
            send_struct.send_buffer[7] = (crc_16 >> 8) & 0xff;    
        }break;

        case 0x10:
        {
            TempAddr = modbus_analysis_data.start_addr;
            for (inx = 0; inx < modbus_analysis_data.reg_number; inx++)
            {
                TempData = modbus_analysis_data.write_data_addr[2 * inx];
                TempData = (TempData << 8) | modbus_analysis_data.write_data_addr[2 * inx + 1];
                error_code = proto_modbus_data_write(TempAddr, TempData);
                TempAddr++;
                if (error_code)
                {
                    goto Error;
                }    
            }
            send_struct.len = 8;
            send_struct.send_buffer[0] = modbus_analysis_data.id;
            send_struct.send_buffer[1] = modbus_analysis_data.func;
            send_struct.send_buffer[2] = modbus_analysis_data.start_addr >> 8;
            send_struct.send_buffer[3] = modbus_analysis_data.start_addr & 0xff;
            send_struct.send_buffer[4] = modbus_analysis_data.reg_number >> 8;
            send_struct.send_buffer[5] = modbus_analysis_data.reg_number & 0xff;
            crc_16 = modbus_lib_crc16(send_struct.send_buffer, 6);
            send_struct.send_buffer[6] = crc_16 & 0xff;
            send_struct.send_buffer[7] = (crc_16 >> 8) & 0xff;
        }
        break;
        default:
        {
            error_code = ModbusErrorCode_IllegalFunction;
        }
        goto Error;
    }

Success:
    proto_modbus_communication_data_send(send_struct.send_buffer, send_struct.len);
    return;

Error:
    send_struct.len = 5;
    send_struct.send_buffer[0] = modbus_analysis_data.id;
    send_struct.send_buffer[1] = modbus_analysis_data.func | 0x80;
    send_struct.send_buffer[2] = error_code;
    crc_16 = modbus_lib_crc16(send_struct.send_buffer, 3);
    send_struct.send_buffer[3] = crc_16 & 0xff;
    send_struct.send_buffer[4] = (crc_16 >> 8) & 0xff;
    proto_modbus_communication_data_send(send_struct.send_buffer, send_struct.len);
}

/******************************************
 * 函数: proto_modbus_data_write
 * 功能: Modbus写寄存器
 * 参数: Addr: 地址
         Value:数据
 * 返回: 无
 * 描述: 无
 ******************************************/
static modbus_error_code_e proto_modbus_data_write(u16 addr, u16 data)
{
    modbus_error_code_e error_code;
    u8 temp_point,cali_point;
    
    error_code = ModbusErrorCode_Success;

    switch(addr)
    {
        /*温度 压力 湿度*/
        case 11000:
        {
            tdlas.control.fac_calib_para_set(*((u16 *)(&data)),0xffff,0xffff);
        }break;
        case 11001:
        {
            tdlas.control.fac_calib_para_set(0xffff,data,0xffff);
        }break;
        case 11002:
        {
            tdlas.control.fac_calib_para_set(0xffff,0xffff,data);
        }break;
        
        /*零点校准*/
        case 11003:
        {
            tdlas.control.zero_calib(0);
        }break;
        /*量程点校准*/
        case 11004:
        {
            tdlas.control.span_calib(data);
        }break;
         
        /*厂家标定*/
        case 11010 ... 11109:
        {
            temp_point = (addr - 11010) / 10;
            cali_point = (addr - 11010) % 10;
            tdlas.control.fac_calib(data,cali_point,temp_point);
        }break;
        
        /*转发传感器标定信息*/
        case 11200:
        {
            tdlas.control.fac_calib_data_get(data);
        }break;
        
        
        /*sn*/
        case 20000 ... 20004:
        {
            Usr_Flash.FlashData.sn[addr - 20000] = data;
            Usr_Flash.Write();
        }break;
        /*modbus_id*/
        case 20005:
        {
            Usr_Flash.FlashData.modbus_id = data;
            modbus_slave_ex.id = Usr_Flash.FlashData.modbus_id;
            Usr_Flash.Write();
        }break;
        /*modbus_read_reg_num*/
        case 20006:
        {
            if(data > 1000)
            {
                error_code = ModbusErrorCode_IllegalData;
            }
            else
            {
                Usr_Flash.FlashData.modbus_read_reg_num = data;
                Usr_Flash.Write();
            }
        }break;
        case 20007:
        {
            if(data > 16)
            {
                error_code = ModbusErrorCode_IllegalData;
            }
            else
            {
                Usr_Flash.FlashData.modbus_read_sensor_num = data;
                Usr_Flash.Write();
            }
        }break;
        /*FC打印相关数据*/
        case 252:
        {
            print.set(data);
        }break;
    }
    return error_code;
}

/******************************************
 * 函数: proto_modbus_data_read
 * 功能: Modbus读寄存器数据
 * 参数: Addr: 地址
 * 返回: 地址对应的数据
 * 描述: 无
 ******************************************/
static u16 proto_modbus_data_read(u16 addr)
{
    u16 data = 0;
    u16 *p_data;
    u16 num,offset;

    switch(addr)
    {
        /*实时数据*/
        case 0 ... 639:
        {
            u16 size;
            size = sizeof(gas_data_t);
            /* TDLAS默认读取*/
           if( size== (2 * Usr_Flash.FlashData.modbus_read_reg_num))
           {
               p_data = (u16 *)&gas_data; 
               data = p_data[addr];
           }
           else if((2 * Usr_Flash.FlashData.modbus_read_reg_num )< sizeof(gas_data_t))/*其他传感器*/
           {
               num = addr / Usr_Flash.FlashData.modbus_read_reg_num;
               offset = addr % Usr_Flash.FlashData.modbus_read_reg_num;
               p_data = (u16 *)&gas_data[num];
               data = p_data[offset];
           }    
           
        }break;
        
        /*sn*/
        case 20000 ... 20004:
        {
            data = Usr_Flash.FlashData.sn[addr - 20000];
        }break;
        /*modbus_id*/
        case 20005:
        {
            data = Usr_Flash.FlashData.modbus_id;
        }break;
        /*modbus_read_reg_num*/
        case 20006:
        {
            data = Usr_Flash.FlashData.modbus_read_reg_num;
        }break;
        case 20007:
        {
            data = Usr_Flash.FlashData.modbus_read_sensor_num;
        }break;
        default:data = 0;
    }
    return data;
}
