#include "tran_for_slave.h"
#include "debug.h"
#include "mymisc.h"
#include "mystdlib.h"
#include "board.h"
#include "dev_flash.h"
#include "prot_uc.h"
#include "coder_lib.h"
#include "JQ_PSDGenerate.h"
#include "mystring.h"
#include "coder_judge.h"
#include "JQ_UIDGenerate.h"
#include "transmit.h"
#include "elec_det.h"
#include "crc.h"
#include "dev_backup.h"


typedef struct{
  ucport_def u;
  rt_timer_t timer;
//  int *host_type;// 主机接口类型0串口，1can
}slave_def;



static slave_def *slave_creat(void)
{
  slave_def *u=calloc(1,sizeof(slave_def));
  //u->host_type=app_variable("host_if",0,0);
  return u;
}



static void slave_del(ucport_def *u)
{
  slave_def *s=(slave_def *)u;
  CHECK_DO(s->timer,rt_timer_delete);
  free(u);
}



// 获取检测结果
static int check_result_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  slave_def *s=(slave_def *)u;
  array_def *r=elec_check_result();
  if(r){
    emit tran_reply_signal(u->p,arr_temp(r));
  }
  return 0;
}
static ucport_def *check_result(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=check_result_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0x02,check_result)
transmit_export(ym_slave,0x18,check_result)



// 设置硬件版本号
static int write_hw_version_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  int value=arr_get(data,0)|(arr_get(data,1)<<8);
  emit tran_reply_signal(u->p,arr_temp(elec_write_hardversion(value)));
  return 0;
}
static ucport_def *write_hw_version(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=write_hw_version_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0x03,write_hw_version)





// 设置电阻校准值
static int write_resistor_cbv_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  int value=arr_get(data,0)|(arr_get(data,1)<<8);
  emit tran_reply_signal(u->p,arr_temp(elec_write_resistor_cbv(value)));
  return 0;
}
static ucport_def *write_resistor_cbv(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  int value=arr_get(data,0)|(arr_get(data,1)<<8);
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=write_resistor_cbv_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0x04,write_resistor_cbv)




// 测量桥丝阻值
static int check_resistor_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  uint8_t index=0;
  if(data){
    index=arr_get(data,0);
  }
  emit tran_reply_signal(u->p,arr_temp(elec_check_resistor(index)));
  return 0;
}
static ucport_def *check_resistor(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=check_resistor_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0x05,check_resistor)






// 根据方案检测
typedef struct{
  int submit_running;
  int submit_delay;// 自动上报间隔
  int submit_times;// 自动上报次数
  tran_def *tran;
  uint8_t cmd;
  int host_type;
  array_def *data;
  array_def *(*check_fun)(array_def *uid);
}check_def;
static check_def g_check;
static void check_set_data(check_def *u,array_def *data)
{
  CHECK_DO(u->data,arr_delete);
  u->data=arr_duplicate(data);
}
static void check_submit_later(void *t)
{
  check_def *s=(check_def *)t;
  
  s->submit_times--;
  if(s->submit_running&&(s->submit_times>0)){
    array_def *ret=elec_check_result();
    if(ret!=0){
      emit tran_send_signal(s->tran,s->cmd,ret);
      // s->submit_delay=150;
      s->submit_delay+=elec_local_addr()*3;
    }else{
      //while(1);
    }
    later_execute(check_submit_later,s,s->submit_delay);
  }else{
    s->submit_running=0;
    s->submit_times=0;
    s->cmd=0;
  }
}
static void check_later(void *t)
{
  check_def *s=(check_def *)t;
  if(s->check_fun){
    s->check_fun(s->data);
  }
  if(s->host_type==1)
  {
    s->submit_times=10;
    s->submit_running=1;
    s->submit_delay=elec_local_addr()*10+200;
    later_execute(check_submit_later,s,s->submit_delay);
  }else{
    s->cmd=0;
  }
}
static int check_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  slave_def *s=(slave_def *)u;
  check_def *c=&g_check;
  array_def *r=arr_creat();
  if(c->cmd==0){
    c->cmd=cmd;
    c->tran=s->u.p;
    check_set_data(c,data);
    later_execute(check_later,c,10);
    elec_check_result_clear();
  }
  if(c->cmd==cmd){
    arr_append(r,0);
  }else{
    arr_append(r,2);
  }
  if(c->cmd==cmd){
    emit tran_reply_signal(u->p,arr_temp(r));
  }else{
    arr_delete(r);
  }
  return 0;
}

static ucport_def *check_self(tran_def *t, uint8_t cmd,array_def *data,
  array_def *(*fun)(array_def *))
{
  int ret=0;
  check_def *c=&g_check;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=check_dolater;
  c->check_fun=fun;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}

static ucport_def *check_with_scheme(tran_def *t, uint8_t cmd,array_def *data)
{
  check_def *c=&g_check;
  c->host_type=*(int *)app_variable("host_if",0,0);
  return check_self(t,cmd,data,elec_check_with_scheme);
}
transmit_export(ym_slave,0x0b,check_with_scheme)
transmit_export(ym_slave,0x0c,check_with_scheme)
static ucport_def *check_code(tran_def *t, uint8_t cmd,array_def *data)
{
  check_def *c=&g_check;
  c->host_type=0;
  return check_self(t,cmd,data,elec_code);
}
transmit_export(ym_slave,0x17,check_code)





// 停止上报
static int stop_submit_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  g_check.submit_running=0;
  g_check.cmd=0;
  array_def *r=arr_creat();
  arr_append(r,0);
  emit tran_reply_signal(u->p,arr_temp(r));
  return 0;
}
static ucport_def *stop_submit(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=stop_submit_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0x14,stop_submit)







// 定义地址宏
// 本程序中程序下载地址不是这个地址，在此用来计算偏移量
#define MCU_APP_ADDR_BASE       0x8004000
#define MCU_TASKID_ADDR_BASE    0x803f000
#define MCU_JWT_ADDR_BASE       0x803B000

// 定义升级结构体
typedef struct{
  uint8_t device_state;
  uint32_t flash_addr;
  uint32_t flash_addr_base;
  int erased;
}updata_def;
static updata_def g_updata;


// 查询设备状态，第一次返回在app，如果设置了跳转指令则返回在bootloader
// 1:app;2:bootleader
static int device_state_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  array_def *r=arr_creat();
  arr_append(r,g_updata.device_state+1);
  emit tran_reply_signal(u->p,arr_temp(r));
  return 0;
}
static ucport_def *device_state(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=device_state_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0xf9,device_state)

// 跳转至bootloader，这里只是改变标志，实际还是在app中
static int turn_to_bootloader_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  g_updata.device_state=1;
  array_def *r=arr_creat();
  arr_append(r,0);
  emit tran_reply_signal(u->p,arr_temp(r));
  return 0;
}
static ucport_def *turn_to_bootloader(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=turn_to_bootloader_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0xf8,turn_to_bootloader)




// 生成文件头
static uint32_t creat_file_head(uint32_t addr,const char *name)
{
  uint8_t *td=calloc(FLASH_FILE_HEAD_SIZE,sizeof(uint8_t));
  // 文件大小和文件名
  memcpy(td,name,strlen(name));
  // used字段
  ((flash_file *)td)->used=0xffffffff;
  flash_write((uint8_t *)addr,td,FLASH_FILE_HEAD_SIZE);
  free(td);
  return addr+FLASH_FILE_HEAD_SIZE;
}


// 擦除app空间
static int erase_app_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  flash_erase_app2();
  g_updata.flash_addr=creat_file_head((uint32_t)flash_get_app2(),"slave_app.pkt");
  array_def *r=arr_creat();
  arr_append(r,0);
  emit tran_reply_signal(u->p,arr_temp(r));
  return 0;
}
static ucport_def *erase_app(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=erase_app_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0xfe,erase_app)




// 写入数据
// 因为添加了文件头，实际写入地址应该偏移一个文件头的长度
static int write_data_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  uint32_t addr=(arr_get(data,0))|(arr_get(data,1)<<8)|(arr_get(data,2)<<16)|(arr_get(data,3)<<24);
  int len=arr_length(data)-4;
  int ret=0;
  uint32_t offset=addr-MCU_APP_ADDR_BASE;
  addr=g_updata.flash_addr+offset;
  ret=flash_write((uint8_t *)addr,&arr_data(data)[4],len);
  array_def *r=arr_creat();
  arr_append(r,(ret!=0));
  emit tran_reply_signal(u->p,arr_temp(r));
  return 0;
}
static ucport_def *write_data(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=write_data_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0xfc,write_data)




// 校验并跳转
static int ceck_crc_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  uint32_t addr_start=(arr_get(data,0))|(arr_get(data,1)<<8)|(arr_get(data,2)<<16)|(arr_get(data,3)<<24);
  uint32_t addr_end=(arr_get(data,4))|(arr_get(data,5)<<8)|(arr_get(data,6)<<16)|(arr_get(data,7)<<24);
  uint32_t crc32=(arr_get(data,8))|(arr_get(data,9)<<8)|(arr_get(data,10)<<16)|(arr_get(data,11)<<24);
  uint32_t crc32_local=0;
  int len=addr_end-addr_start;
  addr_start=g_updata.flash_addr;
  crc32_local=crc_crc32((uint8_t *)addr_start,len);
  int ret=(crc32!=crc32_local);
  if(ret){
    DBG_WARN("crc32 not equal,crc=0x%04x,crc_local=0x%04x",crc32,crc32_local);
  }
  array_def *r=arr_creat();
  arr_append(r,ret);
  emit tran_reply_signal(u->p,arr_temp(r));
  if(ret==0){
    later_execute((void (*)(void *))bk_reboot_updata,0,100);
  }
  return 0;
}
static ucport_def *ceck_crc(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=ceck_crc_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0xfb,ceck_crc)





// 写入数据,这个命令会自动擦除
// 因为添加了文件头，实际写入地址应该偏移一个文件头的长度
static int write_data2_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  uint32_t addr=(arr_get(data,0))|(arr_get(data,1)<<8)|(arr_get(data,2)<<16)|(arr_get(data,3)<<24);
  int len=arr_length(data)-4;
  int ret=0;
  if(strcmp(err_str,"ok")!=0){
    return -1;
  }
  if((addr)==MCU_TASKID_ADDR_BASE){
    if(g_updata.erased==0){
      flash_erase_scheme();
      g_updata.flash_addr=creat_file_head((uint32_t)flash_get_scheme(),"scheme.bin");
      g_updata.flash_addr_base=MCU_TASKID_ADDR_BASE;
      elec_scheme_deinit();
      g_updata.erased=1;
    }
  }else if((addr)==MCU_JWT_ADDR_BASE){
    if(g_updata.erased==0){
      flash_erase_jwtcode();
      g_updata.flash_addr=creat_file_head((uint32_t)flash_get_jwtcode(),"jwtcode.jwt");
      g_updata.flash_addr_base=MCU_JWT_ADDR_BASE;
      g_updata.erased=1;
    }
  }
  uint32_t offset=addr-g_updata.flash_addr_base;
  addr=g_updata.flash_addr+offset;
  ret=flash_write((uint8_t *)addr,&arr_data(data)[4],len);
  array_def *r=arr_creat();
  arr_append(r,ret);
  emit tran_reply_signal(u->p,arr_temp(r));
  if(ret){
    g_updata.erased=0;
  }
  return 0;
}
static ucport_def *write_data2(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=write_data2_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0x11,write_data2)



// 重新加载方案
static int load_scheme_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  int ret=0;
  array_def *r=arr_creat();
  arr_append(r,ret);
  emit tran_reply_signal(u->p,arr_temp(r));
  // 此处如果重启的话会丢失缓存
//  later_execute((void (*)(void *))bk_reboot_app,0,100);
  g_updata.erased=0;
  ret=elec_scheme_init();
  return 0;
}
static ucport_def *load_scheme(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=load_scheme_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0x15,load_scheme)




// 获取自检参数
static int bootinfo_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  emit tran_reply_signal(u->p,arr_temp(elec_bootinfo()));
  return 0;
}
static ucport_def *bootinfo(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=bootinfo_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0x13,bootinfo)



// 写缓存
static int write_fatbuf_dolater(ucport_def *u,uint8_t cmd,array_def *data,char *err_str)
{
  emit tran_reply_signal(u->p,arr_temp(elec_write_fat_buff(data)));
  return 0;
}
static ucport_def *write_fatbuf(tran_def *t, uint8_t cmd,array_def *data)
{
  int ret=0;
  slave_def *u=slave_creat();
  u->u.p=t;
  u->u.del=slave_del;
  u->u.dolater=write_fatbuf_dolater;
  u->u.dolater(&u->u,cmd,data,"ok");
  return (ucport_def *)u;
}
transmit_export(ym_slave,0x19,write_fatbuf)










