#include "proto_modbus_master_tdlas.h"
#include "string.h"
#include "stdio.h"

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

#include "bsp_Uart.h"
#include "bsp_74HC4067.h"
#include "bsp_Flash.h"
#include "app_leakage.h"

#include "proto_print.h"
#include "proto_modbus_lib.h"

#define TDLAS_MODBUS_ID    (0xe8)
#define TDLAS_DATA_ENDIAN  (LITTLE_ENDIAN)          /*配置大小端序*/

#define PROTO_LEAKAGE_READ_DATA_NUM                           (14)                  /*读取一个设备寄存器数量*/
#define PROTO_TDLAS_GET_CURR_DATA_START_ADDR                  (0x0000)
#define PROTO_TDLAS_SET_ZERO_CALIB_START_ADDR                 (12)
#define PROTO_TDLAS_SET_SPAN_CALIB_START_ADDR                 (13)
#define PROTO_TDLAS_GET_RESET_START_ADDR                      (0x0000)
#define PROTO_TDLAS_GET_FAC_CALIB_START_ADDR                  (11010)
#define PROTO_TDLAS_GET_FAC_CALIB_PARA_SET_START_ADDR         (11000)
#define PROTO_TDLAS_GET_FAC_CALIB_DATA_START_ADDR             (250)


static void proto_tdlas_init(void);
static void proto_tdlas_control_zero_calib(u16 calib_value);

static void proto_tdlas_control_span_calib(u16 CalibValue);
static void proto_tdlas_control_reset(void);
static void proto_tdlas_control_fac_calib(u16 calib_value,u8 calib_point,u8 temp_point);
static void proto_tdlas_control_fac_calib_para_set(s16 temp,u16 press,u16 humidity);
static void proto_tdlas_tx_task(void);
static void proto_tdlas_rx_task(u8 *p_data,u16 len,void *other_data);
static void proto_tdlas_control_fac_calib_data_get(u8 ch);

/*是哪个串口接收的数据*/
static bsp_uart_t *rx_uart = NULL;

proto_tdlas_t tdlas=
{
    .modbus_id                  = TDLAS_MODBUS_ID,
      
    .init                       = proto_tdlas_init,
    .tx_task                    = proto_tdlas_tx_task,
    .rx_task                    = proto_tdlas_rx_task,
//    .print                      = proto_tdlas_print_debug_data,
                          
    .control.zero_calib         = proto_tdlas_control_zero_calib,        
    .control.span_calib         = proto_tdlas_control_span_calib,        
    .control.reset              = proto_tdlas_control_reset,             
    .control.fac_calib          = proto_tdlas_control_fac_calib,         
    .control.fac_calib_para_set = proto_tdlas_control_fac_calib_para_set,
    .control.fac_calib_data_get = proto_tdlas_control_fac_calib_data_get,
};

proto_tdlas_t *p_sensor = &tdlas;
bsp_uart_t *p_use_uart = &com_uart4;
    
static void proto_tdlas_init(void)
{
    com_uart4.rx_data_analysis = p_sensor->rx_task;
}

static void proto_tdlas_send(u8 *p_data,u16 len)
{
      com_uart4.send(&com_uart4,p_data,len);
}

static void proto_sensor_switch(u8 ch)
{     
   UartCH_Config.ch_set(ch);
}

/*零点校准*/
static void proto_tdlas_control_zero_calib(u16 calib_value)
{
    u8 i;
    for(i=0;i<Usr_Flash.FlashData.modbus_read_sensor_num;i++)
    {
        p_sensor->sys[i].sys_state = PROTO_TDLAS_SYS_STATE_ZERO_CALIB;
        p_sensor->set_data.calib_value = calib_value;
    }
}

/*量程校准         */
static void proto_tdlas_control_span_calib(u16 CalibValue)
{
    u8 i;
    for(i=0;i<Usr_Flash.FlashData.modbus_read_sensor_num;i++)
    {
        p_sensor->sys[i].sys_state = PROTO_TDLAS_SYS_STATE_SPAN_CALIB;
        p_sensor->set_data.calib_value = CalibValue;
    }

}

/*恢复出厂设置    */
static void proto_tdlas_control_reset(void)
{
    u8 i;
    for(i=0;i<Usr_Flash.FlashData.modbus_read_sensor_num;i++)
    {
        p_sensor->sys[i].sys_state = PROTO_TDLAS_SYS_STATE_RESET;
    }
}

/*厂家标定*/
static void proto_tdlas_control_fac_calib(u16 calib_value,u8 calib_point,u8 temp_point)
{
    u8 i;
    for(i=0;i<Usr_Flash.FlashData.modbus_read_sensor_num;i++)
    {
        p_sensor->sys[i].sys_state = PROTO_TDLAS_SYS_STATE_FAC_CALIB;
        p_sensor->set_data.calib_value                  = calib_value;
        p_sensor->set_data.calib_point                  = calib_point;
        p_sensor->set_data.temp_point                   = temp_point;
    }
}

/*环境参数设置*/
static void proto_tdlas_control_fac_calib_para_set(s16 temp,u16 press,u16 humidity)
{
    u8 i;
    for(i=0;i<Usr_Flash.FlashData.modbus_read_sensor_num;i++)
    {
        p_sensor->sys[i].sys_state = PROTO_TDLAS_SYS_STATE_FAC_CALIB_PARA_SET;
        p_sensor->set_data.temp                         = (-1 == temp) ? p_sensor->set_data.temp : temp;
        p_sensor->set_data.humidity                     = (0xffff == humidity) ? p_sensor->set_data.humidity : humidity;
        p_sensor->set_data.press                        = (0xffff == press) ? p_sensor->set_data.press : press;
    }        
}

/*获取标定数据*/
static void proto_tdlas_control_fac_calib_data_get(u8 ch)
{
    if(Usr_Flash.FlashData.modbus_read_sensor_num > ch)
    {
        p_sensor->sensor_index = ch;
        p_sensor->sys[ch].sys_state = PROTO_TDLAS_SYS_STATE_FAC_CALIB_DATA_GET;
        proto_sensor_switch(ch);
    }
}

/********发送***********/
static void proto_tdlas_tx_curr_data_get(void)
{
    u16 addr = PROTO_TDLAS_GET_CURR_DATA_START_ADDR;
    u8 len = PROTO_LEAKAGE_READ_DATA_NUM;
    modbus_lib_data_read(p_sensor->modbus_id,addr,len,proto_tdlas_send);
}

static void proto_tdlas_tx_zero_calib(void)
{
    u16 addr = PROTO_TDLAS_SET_ZERO_CALIB_START_ADDR;
    u8 len = 1;
    u16 data[1];
    data[0] = 0;

    modbus_lib_multiple_data_write(p_sensor->modbus_id,addr,len,data,proto_tdlas_send);
}

static void proto_tdlas_tx_span_calib(void)
{
    u16 addr = PROTO_TDLAS_SET_SPAN_CALIB_START_ADDR;
    u8 len = 1;
    u16 data[1];
    data[0] = p_sensor->set_data.calib_value;
    modbus_lib_multiple_data_write(p_sensor->modbus_id,addr,len,data,proto_tdlas_send);
}

static void proto_tdlas_tx_Reset(void)
{
    u16 addr = PROTO_TDLAS_GET_RESET_START_ADDR;
    u8 len = 1;
    u16 data[1];
    data[0] = 0x00FE;
    //modbus_lib_multiple_data_write(p_sensor->modbus_id,addr,len,data,proto_tdlas_send);
}

static void proto_tdlas_tx_fac_calib(void)
{
    u16 addr = PROTO_TDLAS_GET_FAC_CALIB_START_ADDR;
    u8 len = 1;
    u16 data[1];
    data[0] = p_sensor->set_data.calib_value;
    addr = addr + p_sensor->set_data.temp_point * 10 + p_sensor->set_data.calib_point;
    modbus_lib_multiple_data_write(p_sensor->modbus_id,addr,len,data,proto_tdlas_send);
}

static void proto_tdlas_tx_fac_calib_para_set(void)
{
    u16 addr = PROTO_TDLAS_GET_FAC_CALIB_PARA_SET_START_ADDR;
    u8 len = 3;
    u16 data[3];
    
    data[0] = *((u16 *)(&p_sensor->set_data.temp));         /*温度*/
    data[1] = p_sensor->set_data.press;                     /*压力*/
    data[2] = p_sensor->set_data.humidity;                  /*湿度*/
    
    modbus_lib_multiple_data_write(p_sensor->modbus_id,addr,len,data,proto_tdlas_send);
}

static void  proto_tdlas_tx_fac_calib_data_get(void)
{
    u16 addr = PROTO_TDLAS_GET_FAC_CALIB_DATA_START_ADDR;
    u8 len = 1;
    u16 data[1];
    
    data[0] = 3;         /*温度*/
    modbus_lib_multiple_data_write(p_sensor->modbus_id,addr,len,data,proto_tdlas_send);
}

static void proto_tdlas_tx_task(void)
{
    u8 SendFlag = 0;
    proto_tdlas_sys_t *p_sensor_sys;
    p_sensor_sys = &p_sensor->sys[p_sensor->sensor_index];
   
    if(0 == (p_sensor_sys->state_error_flag & (0x00000001 << PROTO_TDLAS_ERROR_FLAG_TIME_OUT)))
    {
        if((++p_sensor_sys->tx_time_out_count) > 8)/*通讯超时*/
        {
            p_sensor_sys->state_error_flag |= (0x00000001 << PROTO_TDLAS_ERROR_FLAG_TIME_OUT);
            /*清除数据*/
            memset(&gas_data[p_sensor->sensor_index],0,sizeof(gas_data_t));
        }
    }
 
    switch(p_sensor_sys->sys_state)
    {
        case PROTO_TDLAS_SYS_STATE_INIT:
        {
            
        }break;
        case PROTO_TDLAS_SYS_STATE_CURR_DATA_GET:
        {
            proto_tdlas_tx_curr_data_get();
        }break;            
        case PROTO_TDLAS_SYS_STATE_ZERO_CALIB:
        {
            proto_tdlas_tx_zero_calib();
        }break;            
        case PROTO_TDLAS_SYS_STATE_SPAN_CALIB:
        {
            proto_tdlas_tx_span_calib();
        }break;
        case PROTO_TDLAS_SYS_STATE_RESET:
        {
            proto_tdlas_tx_Reset();
        }break;
        case PROTO_TDLAS_SYS_STATE_FAC_CALIB:
        {
            proto_tdlas_tx_fac_calib();
        }break;
        case PROTO_TDLAS_SYS_STATE_FAC_CALIB_PARA_SET:
        {
            proto_tdlas_tx_fac_calib_para_set();
        }break;
        case PROTO_TDLAS_SYS_STATE_FAC_CALIB_DATA_GET:
        {
            if(0 == p_sensor_sys->send_time)
            {
                p_use_uart->relay.flag = 1;
                proto_tdlas_tx_fac_calib_data_get();
            }
            p_sensor_sys->send_time++;
            if(p_sensor_sys->send_time > 50)
            {
                p_use_uart->relay.flag = 0;
                p_sensor_sys->send_time = 0;
                p_sensor_sys->sys_state = PROTO_TDLAS_SYS_STATE_CURR_DATA_GET;
                p_sensor->sensor_index++;
                if(p_sensor->sensor_index >= Usr_Flash.FlashData.modbus_read_sensor_num)
                {
                    p_sensor->sensor_index = 0;
                }
                proto_sensor_switch(p_sensor->sensor_index);
            }
            SendFlag = 1;
        }break;
        default:
        {
        
        }break;
    } 
    if(SendFlag)
    {
        return ;
    }
    else
    {

        
        p_sensor_sys->send_time++;
        if(p_sensor_sys->send_time >= 3)    /*进入异常*/
        {
            p_sensor_sys->state_error_flag |= (0x00000001 << p_sensor_sys->sys_state);/*记录异常状态*/
            p_sensor_sys->send_time = 0;
            p_sensor_sys->sys_state = PROTO_TDLAS_SYS_STATE_CURR_DATA_GET;
            p_sensor->sensor_index++;
            if(p_sensor->sensor_index >= Usr_Flash.FlashData.modbus_read_sensor_num)
            {
                p_sensor->sensor_index = 0;
            }
            proto_sensor_switch(p_sensor->sensor_index);
        }
        
   }
}

static void proto_tdlas_rx_task(u8 *p_data,u16 len,void *other_data)
{
    u8 send_time_flag = 0;
    u8 modbus_id,cmd;
    u16 check_crc16,modbus_crc16;
    u16 *p_u16_temp;
    u16 i,ch;
    u8 *p_rx_valid,temp_value;
    
    proto_tdlas_sys_t *p_sensor_sys;
    p_sensor_sys = &p_sensor->sys[p_sensor->sensor_index];
    
    if( p_use_uart->relay.flag == 1)
    {
        p_use_uart->relay.uart->send(p_use_uart->relay.uart,p_data,len);
    }
       
    if(p_sensor->modbus_id != p_data[0])
    {
        p_data = &p_data[1];
        len -= 1; 
    }
    modbus_id = *p_data;
    cmd = *(p_data+1);
    check_crc16 = p_data[len-2] << 8 | p_data[len-1];
    
    if(modbus_id != p_sensor->modbus_id) return ;
    if(cmd != 0x03 && cmd != 0x06 && cmd != 0x10 && cmd != 0x41) return ;

    modbus_crc16 = modbus_lib_crc16(p_data,len-2);
    modbus_crc16 = (modbus_crc16 >> 8) | (modbus_crc16 << 8);
    
    if(check_crc16 != modbus_crc16) return ;
    
    if(cmd == 0x41)
    {
       p_rx_valid = &p_data[6]; 
    }
    
    u8 byte_count = p_data[3];
    p_rx_valid = &p_data[3];
    
    rx_uart = (bsp_uart_t *)other_data;
    
    p_sensor_sys->tx_time_out_count = 0;
    p_sensor_sys->state_error_flag &= (~(0x00000001 << PROTO_TDLAS_ERROR_FLAG_TIME_OUT));
    
    switch(p_sensor_sys->sys_state)
    {
        case PROTO_TDLAS_SYS_STATE_INIT:
        {

        }break;
        case PROTO_TDLAS_SYS_STATE_CURR_DATA_GET:
        {
           /*计算当前设备索引*/
           u8 device_global_idx = p_sensor->sensor_index;
            
           if(device_global_idx >= APP_LEAKAGE_SUB_DEVICE_NUM)
           {
                break;
           }
           
           /*通道数据重置*/
           for(ch = 0;ch < APP_LEAKAGE_SUB_DEVICE_CH_NUM;ch++)
           {
                p_leakage->sub_device_data[device_global_idx].ch_data[ch].state = 0;
                p_leakage->sub_device_data[device_global_idx].ch_data[ch].state = 0;
           }
           
           if(byte_count >=28)
           {
                ch = 0;
                temp_value = (p_rx_valid[0] << 8) | p_rx_valid[1];  
                if(temp_value == 1) {
                    p_leakage->sub_device_data[device_global_idx].ch_data[ch].state |= 
                        APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE;                       
                }
                
                temp_value = (p_rx_valid[2] << 8) | p_rx_valid[3];  
                if(temp_value == 1) {
                    p_leakage->sub_device_data[device_global_idx].ch_data[ch].state |= 
                        APP_LEAKAGE_SUB_DEVICE_STATE_OPEN;
                }
                
                temp_value = (p_rx_valid[4] << 8) | p_rx_valid[5];  
                p_leakage->sub_device_data[device_global_idx].ch_data[ch].distance = temp_value *0.01;
                
                /* 心跳包：0x0003*/
                temp_value = (p_rx_valid[6] << 8) | p_rx_valid[7];
                p_leakage->sub_device_data[device_global_idx].heartbeat = temp_value & 0xFF;  
                
                /*通道2：0x0004-0x0006*/
                ch = 1;
                temp_value = (p_rx_valid[8] << 8) | p_rx_valid[9];  
                if(temp_value == 1) {
                    p_leakage->sub_device_data[device_global_idx].ch_data[ch].state |= 
                        APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE;
                }
                
                temp_value = (p_rx_valid[10] << 8) | p_rx_valid[11];  
                if(temp_value == 1) {
                    p_leakage->sub_device_data[device_global_idx].ch_data[ch].state |= 
                        APP_LEAKAGE_SUB_DEVICE_STATE_OPEN;
                }
                
                temp_value = (p_rx_valid[12] << 8) | p_rx_valid[13];  
                p_leakage->sub_device_data[device_global_idx].ch_data[ch].distance = temp_value *0.01;
                
                /*测试模式：0x0007*/
                temp_value = (p_rx_valid[14] << 8) | p_rx_valid[15];
                p_leakage->sub_device_data[device_global_idx].test_mode = temp_value & 0xFF;  
                
                /*通道3：0x0008-0x000A*/
                ch = 2;
                temp_value = (p_rx_valid[16] << 8) | p_rx_valid[17];  
                if(temp_value == 1) {
                    p_leakage->sub_device_data[device_global_idx].ch_data[ch].state |= 
                        APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE;
                }
                
                temp_value = (p_rx_valid[18] << 8) | p_rx_valid[19];  
                if(temp_value == 1) {
                    p_leakage->sub_device_data[device_global_idx].ch_data[ch].state |= 
                        APP_LEAKAGE_SUB_DEVICE_STATE_OPEN;
                }
                
                temp_value = (p_rx_valid[20] << 8) | p_rx_valid[21];  
                p_leakage->sub_device_data[device_global_idx].ch_data[ch].distance = temp_value *0.01;
                
                /* 通道4：0x000B-0x000D*/
                ch = 3;
                temp_value = (p_rx_valid[22] << 8) | p_rx_valid[23];  
                if(temp_value == 1) {
                    p_leakage->sub_device_data[device_global_idx].ch_data[ch].state |= 
                        APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE;
                }
                
                temp_value = (p_rx_valid[24] << 8) | p_rx_valid[25]; 
                if(temp_value == 1) {
                    p_leakage->sub_device_data[device_global_idx].ch_data[ch].state |= 
                        APP_LEAKAGE_SUB_DEVICE_STATE_OPEN;
                }
                
                temp_value = (p_rx_valid[26] << 8) | p_rx_valid[27];  
                p_leakage->sub_device_data[device_global_idx].ch_data[ch].distance = temp_value *0.01;
           }
        }break;            
        case PROTO_TDLAS_SYS_STATE_ZERO_CALIB:
        {

        }break;            
        case PROTO_TDLAS_SYS_STATE_SPAN_CALIB:
        {

        }break;
        case PROTO_TDLAS_SYS_STATE_RESET:
        {
            
        }break;
        case PROTO_TDLAS_SYS_STATE_FAC_CALIB:
        {
            
        }break;
        case PROTO_TDLAS_SYS_STATE_FAC_CALIB_PARA_SET:
        {
            
        }break;   
        case PROTO_TDLAS_SYS_STATE_FAC_CALIB_DATA_GET:
        {
        
        }break;
    }
    if(send_time_flag)
    {
        return;
    }
    else
    {
        p_sensor_sys->sys_state = PROTO_TDLAS_SYS_STATE_CURR_DATA_GET;
        p_sensor_sys->state_error_flag &= (~(0x00000001 << p_sensor_sys->sys_state));/*消除异常状态*/  
        p_sensor_sys->send_time = 0; 
        p_sensor->sensor_index++;
        if(p_sensor->sensor_index >= Usr_Flash.FlashData.modbus_read_sensor_num)
        {
            p_sensor->sensor_index = 0;
        }
        proto_sensor_switch(p_sensor->sensor_index);
        return;
    }
}
