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

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

#include "bsp_relay.h"
#include "bsp_Uart.h"
#include "bsp_Flash.h"
#include "bsp_W5500.h"

#include "proto_print.h"
#include "proto_modbus_master_leakage.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;
bsp_W5500_Class_t *p_W5500_Class = NULL;

static void proto_modbus_communication_data_send(u8 *p_data, u16 len)
{
    if(NULL != p_W5500_Class)
    {
        W5500.Socket_Send(p_W5500_Class,p_data,len);
    }
}

static void proto_modbus_init(void)
{
    u16 i;
    for(i=0;i<BSP_W5500_PORT_NUM;i++)
    {
        W5500.W5500_Class[i].Rx_DataAnalysis = 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;
    u16 send_buff_index_offset = 0;

    u16 transaction_type,proto_type,proto_len;

    /*mobuds_tcp校验*/
    transaction_type = pData[0] << 8 | pData[1];        /*事务类型*/
    proto_type = pData[2] << 8 | pData[3];              /*协议类型*/
    proto_len = pData[4] << 8 | pData[5];               /*协议长度*/
    
    /*协议类型 长度判断*/
    if(MODBUS_TCP_PROTO_TYPE != proto_type || proto_len != (len - 6))
    {
        return;
    }
    p_W5500_Class = (bsp_W5500_Class_t *)other_data;
    /*正常modbus协议解析*/
    modbus_analysis_data.id         = pData[6];
    modbus_analysis_data.func       = pData[7];
    modbus_analysis_data.start_addr = (pData[8] << 8) | pData[9];
    modbus_analysis_data.reg_number = (pData[10] << 8) | pData[11];

    send_buff_index_offset = 6;
    memcpy(send_struct.send_buffer,pData,4);
    
    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;
  }
  */  
    switch (modbus_analysis_data.func)
    {
        case 0x03:
        case 0x04:
        {
            TempAddr = modbus_analysis_data.start_addr;
            send_struct.send_buffer[send_buff_index_offset + 0] = modbus_analysis_data.id;
            send_struct.send_buffer[send_buff_index_offset + 1] = modbus_analysis_data.func;
            send_struct.send_buffer[send_buff_index_offset + 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[send_buff_index_offset + 3 + 2 * inx] = (TempData >> 8) & 0xff;
                send_struct.send_buffer[send_buff_index_offset + 4 + 2 * inx] = TempData & 0xff;
                TempAddr++;
            }
            send_struct.len =send_buff_index_offset + 3 + send_struct.send_buffer[send_buff_index_offset + 2]; 
        }break;
        /*特殊协议*/
        case 0x41:
        {
            TempAddr = modbus_analysis_data.start_addr;
            send_struct.send_buffer[send_buff_index_offset + 0] = modbus_analysis_data.id;
            send_struct.send_buffer[send_buff_index_offset + 1] = modbus_analysis_data.func;
            send_struct.send_buffer[send_buff_index_offset + 2] = modbus_analysis_data.start_addr >> 8;
            send_struct.send_buffer[send_buff_index_offset + 3] = modbus_analysis_data.start_addr & 0xff;
            send_struct.send_buffer[send_buff_index_offset + 4] = (2 * modbus_analysis_data.reg_number) >> 8;
            send_struct.send_buffer[send_buff_index_offset + 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[send_buff_index_offset + 6 + 2 * inx] = (TempData >> 8) & 0xff;
                send_struct.send_buffer[send_buff_index_offset + 7 + 2 * inx] = TempData & 0xff;
                TempAddr++;
            }
            send_struct.len = send_buff_index_offset + 6 + 2 * modbus_analysis_data.reg_number;
        }break;
        
        case 0x06:
        {
            modbus_analysis_data.write_data_addr = &pData[send_buff_index_offset + 4];
            
            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)
            {
                break;
            }    

            send_struct.len = send_buff_index_offset + 6;
            send_struct.send_buffer[send_buff_index_offset + 0] = modbus_analysis_data.id;
            send_struct.send_buffer[send_buff_index_offset + 1] = modbus_analysis_data.func;
            send_struct.send_buffer[send_buff_index_offset + 2] = modbus_analysis_data.start_addr >> 8;
            send_struct.send_buffer[send_buff_index_offset + 3] = modbus_analysis_data.start_addr & 0xff;
            send_struct.send_buffer[send_buff_index_offset + 4] = modbus_analysis_data.write_data_addr[0];
            send_struct.send_buffer[send_buff_index_offset + 5] = modbus_analysis_data.write_data_addr[1]; 
        }break;

        case 0x10:
        {
            modbus_analysis_data.write_data_addr = &pData[send_buff_index_offset + 7];
            
            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)
                {
                    break;
                }    
            }
            send_struct.len = send_buff_index_offset + 6;
            send_struct.send_buffer[send_buff_index_offset + 0] = modbus_analysis_data.id;
            send_struct.send_buffer[send_buff_index_offset + 1] = modbus_analysis_data.func;
            send_struct.send_buffer[send_buff_index_offset + 2] = modbus_analysis_data.start_addr >> 8;
            send_struct.send_buffer[send_buff_index_offset + 3] = modbus_analysis_data.start_addr & 0xff;
            send_struct.send_buffer[send_buff_index_offset + 4] = modbus_analysis_data.reg_number >> 8;
            send_struct.send_buffer[send_buff_index_offset + 5] = modbus_analysis_data.reg_number & 0xff;
        }
        break;
        default:
        {
            error_code = ModbusErrorCode_IllegalFunction;
        }
        break;
    }

        /*数据处理成功*/
    if(ModbusErrorCode_Success == error_code)
    {
        send_struct.send_buffer[4] = (send_struct.len - send_buff_index_offset) >> 8;
        send_struct.send_buffer[5] = (send_struct.len - send_buff_index_offset) & 0x00ff;
        proto_modbus_communication_data_send(send_struct.send_buffer, send_struct.len);
        return;
    }
    else
    {
        send_struct.len = send_buff_index_offset + 3;
        send_struct.send_buffer[4] = (send_struct.len - send_buff_index_offset) >> 8;
        send_struct.send_buffer[5] = (send_struct.len - send_buff_index_offset) & 0x00ff;
        send_struct.send_buffer[send_buff_index_offset + 0] = modbus_analysis_data.id;
        send_struct.send_buffer[send_buff_index_offset + 1] = modbus_analysis_data.func | 0x80;
        send_struct.send_buffer[send_buff_index_offset + 2] = error_code;
        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 1 ... 4:
//        {
//            relay.set(addr-1,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;
    }
    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;
    u16 sensor_index,sensor_ch,reg;
    u16 *p_string;
    
    

    switch(addr)
    {
        case 0 ... 607:
        {
            sensor_index = addr / 19; /*哪一个传光强*/
            reg = addr % 19;          /*哪一个数据*/
            switch(reg)
            {
                case 0:/*端口&ID*/
                {
//                    data = (leakage.sub_device_data[sensor_index].flash_data.com + 1)<< 8 | leakage.sub_device_data[sensor_index].flash_data.modbus_id;
                    u16 value = (leakage.sub_device_data[sensor_index].flash_data.com + 1) << 8;
                    value |= leakage.sub_device_data[sensor_index].flash_data.modbus_id;
                    if (leakage.sub_device_data[sensor_index].shield == BLOCKED) {
                        value |= 0x8000; /*最高位表示屏蔽*/
                    }
                    if (leakage.sub_device_data[sensor_index].flash_data.state == ENABLE) {
                        value |= 0x4000; /*次高位表示使能*/
                    }
                    data = value;
                }break;
                case 1 ... 5:/*区域名*/
                {
                    p_string = (u16 *)leakage.sub_device_data[sensor_index].flash_data.region_name;
                    data =  p_string[reg - 1]>> 8 | p_string[reg - 1] << 8;
                }break;
                case 6 ... 10:/*设备名*/
                {
                    p_string = (u16 *)leakage.sub_device_data[sensor_index].flash_data.device_name;
                    data =  p_string[reg - 6]>> 8 | p_string[reg - 6] << 8;
                }break;
                case 11 ... 18:/*通道数据*/
                {
                    if (leakage.sub_device_data[sensor_index].shield == BLOCKED)/*已屏蔽*/
                    {
                        data = 0;
                    }
                    else
                    {
                        sensor_ch = (reg - 11) / 2;
                        if( (reg - 11) & 0x0001) /*漏液位置*/
                        {
                            data = leakage.sub_device_data[sensor_index].ch_data[sensor_ch].distance;
                        }
                        else                      /*设备状态*/
                        {
                            data = leakage.sub_device_data[sensor_index].ch_data[sensor_ch].state;
                        }
                    }
                }break;
                default:data = 0;
            }
            
        }break;
        default:data = 0;
    }
    return data;
}
