/*
数据通信任务
*/
#include "bsp.h"

#include "ringbuffer.h"
#include "protocol.h"
#include "update_protocol.h"

#include "app_comm.h"
#include "app_tp_collect.h"
#include "app_ad_collect.h"

#define  USING_SIMULATOR ( 0 )

#define  COMM_RECV_OUTTIME (20)

static struct {
    ring_buf_t rb;
    uint8_t    rb_pool[128];
} g_comm;

static struct {
    uint8_t    rxbuf[256];
    int        rxbytes;
} g_frame;

static void rs485_rx_cb(uint8_t data)
{
    ring_buf_put(&g_comm.rb, &data, 1);
}

/**
返回值:成功:len,失败: 0
***/
static int recive_frame(void)
{
    uint8_t data = 0;

    int len = ring_buf_len(&g_comm.rb);

    if (len == 0)
        return 0;

    for (int i = 0; i < len; i++) {

        if (g_frame.rxbytes < sizeof(g_frame.rxbuf)) {

            int byte = ring_buf_get(&g_comm.rb, &data, 1);

            if (byte > 0) {

                g_frame.rxbuf[ g_frame.rxbytes] = data;

                g_frame.rxbytes++;
            }
        }
    }

    return len;
}

static void update_on_start(uint8_t* frame, int len, uint8_t* pload, int size)
{
    update_protocol_req_t* pReq = (void*)&frame[sizeof(update_protocol_hd_t)];

    boot_para_t cfg = {0};

    cfg.AppFlag = 0;
    cfg.UpdateFlag = APP_UPDATE_FLAG;
    cfg.Crc32Check = pReq->AppCrc32;
    cfg.PackageNum = pReq->PackageNum;
    cfg.AppSize    = pReq->AppSize;

    dev_boot_write_param(cfg);

    update_send_cmd(0x01, 1, pReq->PackageNum);

    //重启进入BOOT
    NVIC_SystemReset();
}

static int update_cmd_process(uint8_t cmd, void* frame, int len, void* pload, int size)
{
    int res = -1;

    switch (cmd) {
        case 0x81: {
            update_on_start(frame, len, pload,  size);

            res = 0;
        }
        break;

        default:
            break;

    }

    return res;
}

static int update_process(void* frame, int len)
{
    uint8_t  cmd = 0;

    uint8_t  slave_addr = 0;

    uint8_t  user_data[256] = {0};

    int      user_data_len = 0;

    int res = update_unpack(frame, len, &cmd, &slave_addr, user_data, &user_data_len);

    if (res != 0)
        return -1;

    if (slave_addr != 0x01)
        return -2;

    res = update_cmd_process(cmd, frame, len, user_data, user_data_len);

    if (res != 0)
        return -3;

    return 0;
}

static void comm_rsp(uint8_t slave_addr,uint8_t frame_cmd,void *pay, int len)
{
    uint8_t frame_ack[128] = {0};

    uint16_t frame_ack_len = 0;

    protocol_pack_frame(slave_addr, frame_cmd - 0x80, pay, len, frame_ack, sizeof(frame_ack), &frame_ack_len);

    dev_rs485_send(frame_ack, frame_ack_len);      
}

static void comm_process(uint8_t* frame, int len)
{
    uint16_t slave_addr = 0;
    uint8_t  frame_cmd = 0;
    uint8_t  frame_data[64] = {0};
    uint16_t frame_data_len = 0;

    /***数据解码***/
    int err = -1;
    
    err= protocol_unpack_frame(frame, len, &slave_addr, &frame_cmd, frame_data, &frame_data_len);

    if (err != PROTOCOL_SUCCESS)
        return ;

    //TODO:获取本机地址
    uint8_t local_addr = 0;
    dev_cfg_get_devid(&local_addr);


    uint8_t rsp_data[64] = {0};
    void*  payload = rsp_data;
    uint16_t payload_len = 0;
    
    uint8_t is_match =1;
    
    switch (frame_cmd) {
        
        case PROTOCOL_CMD_SET_ID: {
            
             //
            if (slave_addr != local_addr)
             return ;
            
            id_data_t data = {0};

            memcpy(&data, &frame_data, sizeof(data));

            dev_cfg_set_devid(data.id);
            
            BSP_LOG("set: device id =[%d] =[0x%x] \n", data.id,data.id);
        }
        break;
        
        case PROTOCOL_CMD_GET_ID:{
        
             id_data_t     id_data =  {0};

             id_data.id = local_addr;
            
             payload_len = sizeof(id_data);
                     
             memcpy(payload ,&id_data,payload_len);
            
             BSP_LOG("get: device id =[%d] =[0x%x] \n", id_data.id,id_data.id);
            
        }break;


        case PROTOCOL_CMD_GET_TP: {
            //TODO: get tp datas
           if (slave_addr != local_addr)
           return ;

           tp_datas_t    tp_data =  {0};
                      
           collect_tp_info_t tp_info={0};
           
           app_collect_tp_get(&tp_info);
           
           memcpy( &tp_data,&tp_info.tp_datas,sizeof(tp_data));

           //兼容旧协议,没有用到的通道，填充无效数据
           for(int i=0; i <8-TP_SENSOR_NUM; i++){
           
               tp_data.channels[i+TP_SENSOR_NUM].status =1;
               tp_data.channels[i+TP_SENSOR_NUM].value  =0;
           }
           
            for (int i = 0; i < TP_SENSOR_NUM ; i++) {

                char strbuf[128]={0};
           
                snprintf(strbuf,sizeof(strbuf)," comm ad ch[%d] %08.4f \r\n", i, tp_data.channels[i].value);
                
                BSP_LOG("%s",strbuf);
            }

            BSP_LOG("\r\n");

            payload_len = sizeof(tp_data);
            
            memcpy(payload, &tp_data, payload_len);

        }break; 
        
        case PROTOCOL_CMD_GET_AD: {

            //
            if (slave_addr != local_addr)
             return ;

            //TODO: get ad datas
            ad_datas_t ad_data = {0};
            
            app_collect_ad_get(&ad_data);

           //兼容旧协议,没有用到的通道，填充无效数据
            for(int i=0; i <8-YB_SENSOR_NUM; i++){
           
               ad_data.channels[i+5].status =1;
            }
            
            BSP_LOG("\r\n");

            for (int i = 0; i < YB_SENSOR_NUM ; i++) {

                char strbuf[128] = {0};

                snprintf(strbuf, sizeof(strbuf), " comm ad ch[%d] %08.4f \r\n", i, ad_data.channels[i].value);

                BSP_LOG("%s", strbuf);
            }

            BSP_LOG("\r\n");

            payload_len = sizeof(ad_data);
            
            memcpy(payload, &ad_data, payload_len);

        }
        break;
        
        case PROTOCOL_CMD_SET_TP_OFFSET:{
        
             if (slave_addr != local_addr)
             return ;
                   
             offset_set_data_t  offset_data={0};
             
             memcpy( &offset_data,frame_data,sizeof(offset_data));

             dev_cfg_set_temp_offset(offset_data.id, offset_data.prams.value);
             
             char strbuf[128]={0};

             snprintf(strbuf,sizeof(strbuf)," set[%d] offset %.2f \r\n", offset_data.id , offset_data.prams.value);

             BSP_LOG("%s",strbuf);
              
        }break;
        
        
        case PROTOCOL_CMD_GET_TP_OFFSET:{
        
                       //
            if (slave_addr != local_addr)
             return ;
            
            offset_get_param_t *param = (void *)frame_data;
                       
            offset_get_data_t offset_data={0};
            
            float val = 200;
            
            dev_cfg_get_temp_offset( param->id,&val);

            offset_data.id = param->id;
            
            offset_data.prams.value = val;
            
            payload_len = sizeof(offset_data);
            
            memcpy(payload,&offset_data,payload_len);
            
            char strbuf[128]={0};

            snprintf(strbuf,sizeof(strbuf)," get[%d] offset %.2f \r\n", offset_data.id , offset_data.prams.value);

            BSP_LOG("%s",strbuf);
                    

        }break;
        
        case PROTOCOL_CMD_RESET_CHANNEL: {
            //
            if (slave_addr != local_addr)
            return ;

            app_collect_ad_reset_offset();

            BSP_LOG("reset offset start");

        }
        break;
        
        default:
            is_match =0;
        break;
    }
     
    if(is_match ==0)
    return;
        
    comm_rsp(slave_addr,frame_cmd, payload, payload_len);
}


void app_comm_entry(void *param)
{
    int len = 0;

    dev_rs485_init();

    dev_rs485_rx_register(rs485_rx_cb);

    ring_buf_init(&g_comm.rb, g_comm.rb_pool, sizeof(g_comm.rb_pool));

    /***/
    update_init(dev_rs485_send);
    
    while (1) {
       
        rt_thread_mdelay(1);
        
        len = recive_frame();

        if (len == 0) {
           
            rt_thread_mdelay(5);
            
            len = recive_frame();

            if (len == 0) {
                
                if (g_frame.rxbytes > 0) {
                    
                    update_process(g_frame.rxbuf, g_frame.rxbytes);

                    comm_process(g_frame.rxbuf, g_frame.rxbytes);

                    g_frame.rxbytes = 0;
                }
            }
        }
    }
}


ALIGN(RT_ALIGN_SIZE)
static uint8_t comm_thd_stack[4096];
static struct rt_thread comm_thd;

int app_comm_init(void)
{

#if USING_SIMULATOR
    BSP_LOG("comm data using simulator \n");
#endif

    int ret = rt_thread_init(&comm_thd,
                   "app_comm",
                   app_comm_entry,
                   RT_NULL,
                   comm_thd_stack,
                   sizeof(comm_thd_stack),
                   10,
                   20
                  );


    if(ret == RT_EOK){
    
        rt_thread_startup(&comm_thd);
    }
    
   return 0; 
}
INIT_APP_EXPORT(app_comm_init);


