#include "tran_for_coder2.h"
#include "debug.h"
#include "mymisc.h"
#include "mystdlib.h"
#include "board.h"
#include "dev_flash.h"
#include "tcp.h"
#include "prot_uc.h"
#include "handle_for_coder.h"
#include "handle_for_checker.h"
#include "coder_lib.h"
#include "PSDGenerate.h"
#include "mystring.h"
#include "coder_judge.h"

// 这个文件解析跟赋码仪相关的命令




typedef struct{
  int step;// 检测注码顺序
}self_def;

static self_def g_self;


// 从机地址偏移
static inline int slave_addr_off(void)
{
  if(sys_param()->slave_addr_start)
    return 1;
  else
    return 0;
}



typedef struct{
  ucport_def u;
  uint8_t addrs_num;
  char year[10];
  struct{
    char shell_code[20];
    char uid_code[20];
    char password[10];
    uint8_t uid_pw_hex[15];
  }item[10];
  uint8_t ack[390];
  uint8_t ack_num;
  void (*doexert)(ucport_def *u);
}write_uid_def;



// 上报注码结果
static void write_uid_upmit(write_uid_def *w)
{
  array_def *a=arr_creat();
  arr_append(a,w->addrs_num);
  // arr_appends(a,w->ack,390);
  for(int i=0;i<w->addrs_num;i++)
  {
    uint8_t *d=&w->ack[i*39];
    if(sys_param()->coder_ret_mode)
    {
      // 完整模式
      arr_appends(a,d,39);
    }
    else{
      // 精简模式
      arr_appends(a,d,2);
      d+=2+13+16;
      arr_appends(a,d,8);
    }
  }
  emit tran_send_signal(w->u.p,0x82,arr_temp(a));
  g_self.step=0;
  // 把命令字改为0x82用于接收主机应答
  tran_set_busy(w->u.p,0);
  w->u.cmd=0x82;
}



// 填充注码结果
static void write_uid_fillret(write_uid_def *w,int addr,int ack)
{
  addr-=1;
  uint8_t *d=&w->ack[(addr)*39];
  w->ack_num++;
  d[0]=addr+slave_addr_off();
  d[1]=((ack==0xff)||(ack==0x00))?ack:(ack+0xc0);
  memcpy(&d[2],w->item[addr].shell_code,13);
  memcpy(&d[2+13],w->item[addr].uid_code,16);
  memcpy(&d[2+13+16],w->item[addr].password,8);
  if(w->ack_num>=w->addrs_num)
  {
    write_uid_upmit(w);
  }
}



// 注码完成
static void write_uid_end(ucport_def *u,port_mcu *src,void *data,int ack,char *err_str)
{
  write_uid_def *w=(write_uid_def *)u;
  uint8_t addr=port_get_addr(src);
  if(addr<=0||addr>w->addrs_num){
    DBG_WARN("addr err:%d",addr);
    return;
  }
  write_uid_fillret(w,addr,ack);
}





static void write_uid_return_ok(void *p)
{
  write_uid_def *u=p;
  array_def *a=arr_creat();
  arr_append(a,u->addrs_num);
  for(int i=0;i<u->addrs_num;i++)
  {
    arr_append(a,i+slave_addr_off());
    arr_append(a,0);
    arr_append_num(a,37,'0');
  }
  emit tran_send_signal(u->u.p,0x82,arr_temp(a));
  tran_set_busy(u->u.p,0);
  g_self.step=0;
}


static void write_del(ucport_def *u)
{
  free(u);
}


static int write_uid_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  DBG_LOG("recv write_uid end signal.");
  tran_set_busy(u->p,0);
  return 0;
}



static ucport_def *write_uid(tran_def *t, uint8_t cmd,array_def *data)
{
  if(arr_length(data)<140+4+1){
    DBG_WARN("cmd format err.");
    return 0;
  }
  int ret=0;
  write_uid_def *u=calloc(1,sizeof(write_uid_def));
  u->u.p=t;
  u->u.del=write_del;
  u->u.doend=write_uid_end;
  u->u.dolater=write_uid_dolater;
  u->addrs_num=arr_get(data,0);
  memcpy(u->year,arr_data(data)+1,4);
  DBG_LOG("coder, year=%s",u->year);
  
  // 数据固定140字节，如果不检测某通道，则该通道填充占位符
  uint8_t *d_off=arr_data(data)+4+1;
  uint8_t *d_;
  tran_set_busy(t,1);
  for(int i=0;i<u->addrs_num;i++)
  {
    memcpy(u->item[i].shell_code,d_off+i*14+1,13);
    DBG_LOG("slave:%d, shell=%s",i,u->item[i].shell_code);
    // 生成uid码
    ret|=coder_shell_to_uid(u->year,u->item[i].shell_code,u->item[i].uid_code);
    DBG_LOG("slave:%d, uid=%s",i,u->item[i].uid_code);
    // 生成存储码
    ret|=coder_uid_to_save(u->item[i].uid_code,u->item[i].uid_pw_hex);
    // 生成密码
    GetPasswordByUidCode((uint8_t *)u->item[i].uid_code,&u->item[i].uid_pw_hex[8]);
    d_=u->item[i].uid_pw_hex;
    DBG_LOG("slave:%d, uid_pw=%02X %02X %02X %02X %02X %02X %02X %02X "
      "%02X %02X %02X %02X ",i,d_[0],d_[1],d_[2],d_[3],d_[4],d_[5],d_[6],d_[7],
      d_[8],d_[9],d_[10],d_[11]);
    // 生成密码字符串
    sprintf(u->item[i].password,"%02X%02X%02X%02X",u->item[i].uid_pw_hex[8],
      u->item[i].uid_pw_hex[9],u->item[i].uid_pw_hex[10],u->item[i].uid_pw_hex[11]);
    // 默认失败
    u->ack[i*39+0]=i+slave_addr_off();
    u->ack[i*39+1]=1;
    if(1){
      port_mcu *mcu=tran_get_portm(u->u.p,i);
      // 这里打开赋码操作
      if(mcu){
        if(check_shell_code(u->item[i].shell_code)){
          port_start(mcu,code_creat(8,4,u->item[i].uid_pw_hex));
        }else{
          // 管壳码无效,不注码,此时默认已ack
          // 管壳码无效不视为失败
          ret=0;
          write_uid_fillret(u,i+1,0xff);
        }
      }
    }
    
  }
  

  
  array_def *a=arr_creat();
  arr_append(a,u->addrs_num);
//  if(g_self.step==1){
    if(ret==0)
      arr_append(a,TRAN_ERR_NONE);
    else
      arr_append(a,TRAN_ERR_PARAM);
//  }else{
//    arr_append(a,TRAN_ERR_STEP);
//  }
  emit tran_reply_signal(u->u.p,arr_temp(a));

  // test:稍后返回成功
  //later_execute(write_uid_return_ok,u,500);
  
  return (ucport_def *)u;
}


//transmit_export(ym_checker,0x02,write_uid)



// 复检完成
static void write_uid2_end(ucport_def *u,port_mcu *src,void *data,int ack,char *err_str)
{
  write_uid_def *w=(write_uid_def *)u;
  uint8_t addr=port_get_addr(src);
  if(addr<=0||addr>10){
    DBG_WARN("addr err:%d",addr);
    return;
  }
  addr-=1;
  
  uint8_t *d=&w->ack[(addr)*39];
  w->ack_num++;
  d[0]=addr+slave_addr_off();
  d[1]=ack;
  memcpy(&d[2],w->item[addr].shell_code,13);
  memcpy(&d[2+13],w->item[addr].uid_code,16);
  memcpy(&d[2+13+16],w->item[addr].password,8);
  if(w->ack_num>=10)
  {
    array_def *a=arr_creat();
    arr_append(a,w->addrs_num);
    for(int i=0;i<10;i++)
    {
      uint8_t *d=&w->ack[i*39];
      arr_appends(a,d,2);
    }
    emit tran_send_signal(w->u.p,0x83,arr_temp(a));
    tran_set_busy(w->u.p,0);
  }
}

static ucport_def *write_uid2(tran_def *t, uint8_t cmd,array_def *data)
{
  write_uid_def *u=(write_uid_def *)write_uid(t,cmd,data);
  if(u)
  {
    u->u.doend=write_uid2_end;
  }
  return (ucport_def *)u;
}

// 复检，与注码动作相同，但返回值不同
transmit_export(ym_checker,0x03,write_uid2)












// 判断检测数据错误码
// 返回 errcode,1=param/0=execute,taskindex,paramindex
static uint32_t in_range_err(const uint8_t *src_data,const uint8_t *errbit)
{
  const scheme_def *s=check_scheme();
  const scheme_task_def *t;
  int temp;
  int index=0;
  uint32_t ret=0;
  for(int i=0;i<s->task_num;i++)
  {
    t=&s->task[i];
    if((errbit[i/8]&(1<<(i%8)))!=0)
    {
      ret=(t->err&0xff)|(i<<16);
      return ret;
    }
    for(int j=0;j<t->item_num;j++)
    {
      temp=src_data[index*2]|(src_data[index*2+1]<<8);
      if(temp>=t->range[j].min&&temp<=t->range[j].max){
        // 正常
      }else{
        ret=(t->range[j].err&0xff)|(1<<8)|(i<<16)|(j<<24);
        return ret;
      }
      index++;
    }
  }
  return ret;
}





typedef struct{
  ucport_def u;
  uint8_t addrs_num;
  uint8_t type;
  uint8_t ack[(6)*10];
  uint8_t ack_num;
  void (*doexert)(ucport_def *u);
}check_def;



// 检测完成
static void check_end(ucport_def *u,port_mcu *src,void *data,int ack,char *err_str)
{
  check_def *w=(check_def *)u;
  uint8_t addr=port_get_addr(src);
  if(addr<=0||addr>w->addrs_num){
    DBG_WARN("addr err:%d",addr);
    return;
  }
  addr-=1;
  
  uint32_t errcode=0;
  uint8_t *ack_d=&w->ack[(addr)*6];
  ack_d[0]=addr+slave_addr_off();
  if(ack==-1) ack_d[1]=208; // 208表示通信超时
  else ack_d[1]=ack==0?0:209;// 209表示小板返回了命令失败
  // TODO: 还有4字节数据
  if(data)
  {
    errcode=in_range_err(arr_data(data)+8+8,arr_data(data));
    ack_d[2]=errcode&0xff;
    ack_d[3]=(errcode>>8)&0xff;
    ack_d[4]=(errcode>>16)&0xff;
    ack_d[5]=(errcode>>24)&0xff;
    if(ack_d[1]==0){
      // 先判断主要错误，如果没有主要错误，则填充为子错误
      ack_d[1]=coder_judge(arr_data(data));
      if(ack_d[1]==0){
        ack_d[1]=ack_d[2];
      }
    }
  }else{
  }
  
  w->ack_num++;
  if(w->ack_num>=w->addrs_num)
  {
    array_def *a=arr_creat();
    arr_append(a,w->addrs_num);
    arr_append(a,w->type);
    arr_appends(a,w->ack,(6)*10);
    emit tran_send_signal(w->u.p,0x81,arr_temp(a));
    tran_set_busy(w->u.p,0);
    // 把命令字改为0x81用于接收主机应答
    w->u.cmd=0x81;
    g_self.step=1;
  }
}



static void check_return_ok(void *p)
{
  check_def *u=p;
  array_def *a=arr_creat();
  arr_append(a,u->addrs_num);
  arr_append(a,u->type);
  // 固定返回6*10个字节，如果不检测某通道，则该通道填充占位符
  for(int i=0;i<u->addrs_num;i++){
    arr_append(a,i+slave_addr_off());
    arr_append(a,0);// 成功
    arr_append(a,i+1);// 返回真是序号
    arr_append_num(a,3,0);
  }
  emit tran_send_signal(u->u.p,0x81,arr_temp(a));
  tran_set_busy(u->u.p,0);
  g_self.step=1;
}


static void check_del(ucport_def *u)
{
  free(u);
}

static int check_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  DBG_LOG("recv check end signal.");
  tran_set_busy(u->p,0);
  return 0;
}


static ucport_def *check(tran_def *t, uint8_t cmd,array_def *data)
{
  if(arr_length(data)<2){
    DBG_WARN("cmd format err.");
    return 0;
  }
  check_def *u=calloc(1,sizeof(check_def));
  u->u.p=t;
  u->u.del=check_del;
  u->u.doend=check_end;
  u->u.dolater=check_dolater;
  u->addrs_num=arr_get(data,0);
  u->type=arr_get(data,0);
  // 默认失败
  for(int i=0;i<u->addrs_num;i++)
  {
    u->ack[i*6+0]=i+slave_addr_off();
    u->ack[i*6+1]=1;
  }
  tran_set_busy(t,1);
  for(int i=0;i<u->addrs_num;i++)
  {
    if(1){
      port_mcu *mcu=tran_get_portm(u->u.p,i);
      // 这里打开检测
      if(mcu){
        port_start(mcu,check_creat(check_scheme()));
      }
    }
  }
  
  array_def *a=arr_creat();
  arr_append(a,u->addrs_num);
  arr_append(a,u->type);
  arr_append(a,TRAN_ERR_NONE);
  emit tran_reply_signal(u->u.p,arr_temp(a));

  // test:稍后返回成功
  //later_execute(check_return_ok,u,500);
  
  return (ucport_def *)u;
}


transmit_export(ym_checker,0x01,check)








typedef struct{
  rt_timer_t timer;
}live_keeper_def;


static void live_connect(live_keeper_def *t)
{
  rt_tick_t tick=0;
  tick=rt_tick_from_millisecond(1000);
  rt_timer_control(t->timer,RT_TIMER_CTRL_SET_TIME,&tick);
  rt_timer_start(t->timer);
}
static void live_recv(live_keeper_def *t)
{
  rt_tick_t tick=0;
  tick=rt_tick_from_millisecond(5000);
  rt_timer_control(t->timer,RT_TIMER_CTRL_SET_TIME,&tick);
  rt_timer_start(t->timer);
}


// cmd=0x8a
static void live_send(void *p)
{
  const sys_param_def *par=sys_param();
  tran_def *t=app_variable("tran",0,0);
  uint16_t slave_online=0;
  if(t)
    slave_online=tran_get_slave_online(t);
  array_def *d=arr_creat();
  arr_append(d,0);// 改为模块类型
  arr_append(d,0xff);
  arr_append(d,0x03);
  arr_append(d,par->local_id&0xff);
  arr_append(d,slave_online&0xff);// 在线的小板
  arr_append(d,(slave_online>>8)&0xff);
  emit coder2_live_send_signal(p,0x8a,arr_temp(d));
  //DBG_LOG("tcp liver:%s",str_temp(arr_string(d)));
}


static void init_for_tcp(void *t)
{
  void *tcp=app_variable("tcp",0,0);
  void *protu=app_variable("protu",0,0);
  if(tcp&&protu){
    live_keeper_def *live=calloc(1,sizeof(live_keeper_def));
    live->timer=rt_timer_create("live_t",live_send,live,
      rt_tick_from_millisecond(1000),
      RT_TIMER_FLAG_PERIODIC|RT_TIMER_FLAG_SOFT_TIMER);
    protu_codec_set(protu,protu_find_codec("ym_checker"));
    connect(tcp,tcp_connect_signal,0,live,live_connect);
    connect(tcp,tcp_recv_signal,0,live,live_recv);
    connect(live,coder2_live_send_signal,0,protu,protu_send_call);
    DBG_LOG("tcp liver created");
  }else{
    DBG_WARN("can not fond variable \"tcp\" or/and \"protu\"");
  }
}




// 如果本机为赋码仪并且连接类型为tcp
// 初始化心跳
static int init_live_keeper(void)
{
  const sys_param_def *par=sys_param();
  if((strcmp(par->device_type,"coder")==0)&&(strcmp(par->host_if,"utcp")==0))
  {
    app_valid_call("protu",init_for_tcp,0);
  }else{
    DBG_LOG("tcp liver not created");
  }
  return 0;
}
//app_init_export(init_live_keeper);


