


#include "base/define.h"
#include "basechecker.h"
#include "stdint.h"
#include "EWUpdata.h"
#include "driver/EWDriver.h"
#include "base/delay.h"
#include "hardware/adc_cfg.h"
#include "base/utility.h"
#include "hardware/power.h"
#include "hardware/timer_cfg.h"
#include "debug.h"
#include "commend.h"
#include "mystring.h"
#include "mystdlib.h"





#define UPDATA_PACK_LEN   128
#define UPDATA_BASE_ADDR  0x1000
#define UPDATA_DATA_LEN   (11*1024)
#define UPDATA_FLAG_ADDR  (0x7c)
#define BOOT_FLAG         ((uint8_t []){0x99,0x66,0xaa,0x55})
#define UPDATA_FLAG       ((uint8_t []){0xaa,0xbb,0xcc,0xdd})

#define UPDATA_CRC_ALL ((uint32_t *)(MC_CODE_ADDR+16*1024))[0]
#define UPDATA_CRC_APP ((uint32_t *)(MC_CODE_ADDR+16*1024))[1]



// 擦除
static uint8_t EW_bootErease(void)
{
  uint8_t data[3]={0xfe,0x00,0x00};
  uint8_t read[4]={0};
  uint8_t ret=0;
  DMod_SendBytesXor(data,2,1);
  delay_os_ms(50);
  ret=DMod_ReadBytesXor(read,4,100);
  DBG_LOG("ret=%d,dat=%02x,%02x,%02x,%02x,",ret,read[0],read[1],read[2],read[3]);
  return ret;
}
static int cmd_jwt_boot_erase(list_def *argv)
{
  int ret=0;
  ret=EW_bootErease();
  return ret;
}
commend_export(jwt_boot_erase,cmd_jwt_boot_erase,"jwt srase in boot")


// 跳转
static uint8_t EW_bootJump(void)
{
  uint8_t data[3]={0xf9,0x00,0x00};
  uint8_t read[4]={0};
  uint8_t ret=0;
  DMod_SendBytesXor(data,2,1);
  ret=DMod_ReadBytesXor(read,4,100);
  DBG_LOG("ret=%d,dat=%02x,%02x,%02x,%02x,",ret,read[0],read[1],read[2],read[3]);
  return ret;
}
static int cmd_jwt_boot_jump(list_def *argv)
{
  int ret=0;
  ret=EW_bootJump();
  return ret;
}
commend_export(jwt_boot_jump,cmd_jwt_boot_jump,"jwt jump in boot")


// 充电
static uint8_t EW_bootCharg(void)
{
  uint8_t data[4]={0xf8,0x01,0x01,0x00};
  uint8_t read[4]={0};
  uint8_t ret=0;
  DMod_SendBytesXor(data,3,1);
  delay_ms(2);
  ret=DMod_ReadBytesXor(read,4,100);
  DBG_LOG("ret=%d,dat=%02x,%02x,%02x,%02x,",ret,read[0],read[1],read[2],read[3]);
  return ret;
}
static int cmd_jwt_boot_charg(list_def *argv)
{
  int ret=0;
  ret=EW_bootCharg();
  return ret;
}
commend_export(jwt_boot_charg,cmd_jwt_boot_charg,"jwt charg in boot")



// 放电
static uint8_t EW_bootDisCharg(void)
{
  uint8_t data[4]={0xf8,0x01,0x00,0x00};
  uint8_t read[4]={0};
  uint8_t ret=0;
  DMod_SendBytesXor(data,3,1);
  ret=DMod_ReadBytesXor(read,4,100);
  DBG_LOG("ret=%d,dat=%02x,%02x,%02x,%02x,",ret,read[0],read[1],read[2],read[3]);
  return ret;
}
static int cmd_jwt_boot_discharg(list_def *argv)
{
  int ret=0;
  ret=EW_bootDisCharg();
  return ret;
}
commend_export(jwt_boot_discharg,cmd_jwt_boot_discharg,"jwt discharg in boot")



// 发送数据
// len 最长为128字节
static uint8_t EW_bootWrite(uint16_t addr,uint8_t *d,uint16_t len)
{
  uint8_t ret=0;
  uint8_t read[4]={0};
  uint8_t *buf=rt_malloc(len+2+2+1);
  if(buf==RT_NULL) return 1;
  buf[0]=0xfc;
  buf[1]=2+len;
  buf[2]=addr&0xff;
  buf[3]=addr>>8;
  rt_memcpy(&buf[4],d,len);
  LED2_Out=0;
  DMod_SendBytesXor(buf,len+2+2,1);
  LED2_Out=1;
  ret=DMod_ReadBytesXor(read,4,100);
  rt_free(buf);
  if(ret){
    DBG_LOG("ret=%d,dat=%02x,%02x,%02x,%02x,",ret,read[0],read[1],read[2],read[3]);
  }
  return ret;
}



// 校验
static uint8_t EW_bootCheckCrc(uint16_t adr_start,uint16_t adr_end,uint32_t *crc)
{
  uint8_t ret=0;
  uint8_t cmd[7]={0xfb,0x04,adr_start&0xff,adr_start>>8,adr_end&0xff,adr_end>>8};
  uint8_t read[4+4]={0};
  DMod_SendBytesXor(cmd,6,1);
  delay_ms(10);
  ret=DMod_ReadBytesXor(read,8,100);
  if(ret==0){
    if(crc){
      *crc=(read[3]<<24)|(read[4]<<16)|(read[5]<<8)|(read[6]<<0);
    }
  }
  DBG_LOG("addr_start=0x%04x,addr_end=0x%04x.",adr_start,adr_end);
  DBG_LOG("ret=%d,dat=%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,",
    ret,read[0],read[1],read[2],read[3],read[4],read[5],read[6],read[7]);
  return ret;
}
static int cmd_jwt_boot_checkcrc(list_def *argv)
{
  int ret=0;
  uint32_t crc=0;
  ret=EW_bootCheckCrc(UPDATA_BASE_ADDR,UPDATA_BASE_ADDR+UPDATA_DATA_LEN,&crc);
  cmd_print("jwt crc32=0x%04x.",crc);
  //crc=Crc32Calu((uint32_t *)(MC_CODE_ADDR+UPDATA_BASE_ADDR),UPDATA_DATA_LEN);
  crc=UPDATA_CRC_APP;
  cmd_print("local crc32=0x%04x.",crc);
  return ret;
}
commend_export(jwt_boot_checkcrc,cmd_jwt_boot_checkcrc,"jwt checkcrc in boot")



// 读取
static uint8_t EW_bootRead(uint16_t adr,uint8_t *buf,uint16_t len)
{
  uint8_t ret=0;
  uint8_t cmd[7]={0xfa,0x03,adr&0xff,adr>>8,len};
  uint16_t read_len=2+len+1+1;
  uint8_t *read=rt_malloc(read_len);
  if(read==RT_NULL) return 1;
  DMod_SendBytesXor(cmd,6,1);
  ret=DMod_ReadBytesXor(read,read_len,100);
  rt_memset(buf,0,len);
  if(ret==0)
  {
    rt_memcpy(buf,&read[3],len);
  }
  DBG_LOG("ret=%d,dat=%02x,%02x,%02x,%02x,",ret,read[0],read[1],read[2],read[3]);
  rt_free(read);
  return ret;
}



// app:读取数据
static int EW_appRead(void)
{
  uint8_t read_buf[4]={0};
  int ret=0;
  uint8_t addr=(uint8_t)(UPDATA_FLAG_ADDR/4);
  DBG_LOG("addr=0x%02x.",addr);
  ret=EW_ReadMTP(1,addr,read_buf,4);
  DBG_LOG("ret=%d,dat=%02x,%02x,%02x,%02x,",ret,read_buf[0],read_buf[1],read_buf[2],read_buf[3]);
  return ret;
}
static int cmd_jwt_app_read(list_def *argv)
{
  int ret=0;
  ret=EW_appRead();
  return ret;
}
commend_export(jwt_app_read,cmd_jwt_app_read,"jwt read in app")


// app:通信测试
static int EW_appCommTest(void)
{
//  uint8_t data[4]={0x11,0x22};
//  uint8_t ret;
//  DBG_LOG("send:%02x,%02x.",data[0],data[1]);
//  ret=EW_CommTest(data,2,300);
//  DBG_LOG("ret=%d,dat=%02x,%02x,%02x,%02x,",ret,data[0],data[1],data[2],data[3]);
//  return ret;
  return EW_appRead();
}
static int cmd_jwt_app_commtest(list_def *argv)
{
  int ret=0;
  ret=EW_appCommTest();
  return ret;
}
commend_export(jwt_app_commtest,cmd_jwt_app_commtest,"jwt commtest in app")





// app:runbootloader
static void EW_appRunBoot(void)
{
  EW_Charge(1,0,0);
  delay_os_ms(6000);
  EW_RunBootLoader(1,1);
  DBG_LOG("run boot");
}
static int cmd_jwt_app_runboot(list_def *argv)
{
  int ret=0;
  EW_appRunBoot();
  return ret;
}
commend_export(jwt_app_runboot,cmd_jwt_app_runboot,"jwt turn to bootloader")




typedef struct{
  // 充电时间 6000
  int time_charg;
  // 加载app时间 6000
  int time_loadapp;
  // 总线关断时间 1000
  int time_poweroff;
  // 升级模式，0，无app时升级；1，无条件升级
  int updata_mode;
  // 模块状态
  int state;
}ew_updata_def;



// 硬复位
int EW_HardReset(ew_updata_def *e)
{
  EW_BUS_OFF;
  delay_os_ms(e->time_poweroff);
  EW_BUS_ON;
  return 0;
}


// 判断模块在何种工作状态 1:boot 2:app
// 3:boot失败且app也失败
int EW_CheckState(ew_updata_def *e)
{
  uint16_t ret=0;
  delay_os_ms(100);
  ret=EW_bootCharg();
  if(ret==0){
    delay_os_ms(e->time_charg);
    e->state=1;
  }else{
    EW_HardReset(e);
    delay_os_ms(e->time_loadapp);
    ret=EW_appCommTest();
    delay_ms(5);
    if(ret==0){
      e->state=2;
    }else{
      e->state=3;
    }
  }
  return e->state;
}



// 跳转到app的方式
static int EW_TurnToBoot1(ew_updata_def *e)
{
  DBG_LOG("turn to boot1");
  delay_ms(5);
  EW_EnWriteMTP(0,1);  
  delay_ms(5);
  EW_RunBootLoader(0,0);
  delay_os_ms(500);
  if(EW_bootCharg()==0)
    return 0;
  else
    return 1;
}
static int EW_TurnToBoot2(ew_updata_def *e)
{
  DBG_LOG("turn to boot2");
  delay_ms(5);
  EW_EnWriteMTP(0,1);  
  delay_ms(5);
  EW_WriteMTP(0,(uint8_t)(UPDATA_FLAG_ADDR/4),BOOT_FLAG,4);
  delay_ms(5);
  return 1;
}

// 跳转到bootloader
int EW_TurnToBoot(ew_updata_def *e)
{
  typedef int (*turnfun)(ew_updata_def *e);
  turnfun func_table[]={EW_TurnToBoot1,EW_TurnToBoot2};
  int ret=0;
  for(int i=0;i<2;i++){
    if(e->state!=1){
      ret=func_table[i](e);
      if(ret){
        EW_HardReset(e);
      }
      EW_CheckState(e);
    }else{
      break;
    }
  }
  return e->state;
}



static void EW_ParamPrint(ew_updata_def *e)
{
  DBG_LOG("time_charg=%d",e->time_charg);
  DBG_LOG("time_loadapp=%d",e->time_loadapp);
  DBG_LOG("time_poweroff=%d",e->time_poweroff);
  DBG_LOG("updata_mode=%d",e->updata_mode);
}


// 升级
void EW_Updata(void)
{
  Checker_RunCfg_st *cfg=&checker_runcfg;
  uint16_t ret=0;
  uint8_t read_buf[4]={0};
  uint8_t *data=(uint8_t *)MC_CODE_ADDR+UPDATA_BASE_ADDR;
  uint16_t len=UPDATA_DATA_LEN;
  uint16_t addr=UPDATA_BASE_ADDR;
  uint8_t pack_len=UPDATA_PACK_LEN;
  uint32_t crc=0;
  uint32_t crc_module=0;
  
  ew_updata_def ew_updata={0};
  // 充电时间 6000
  ew_updata.time_charg=checker_runcfg.params[0];
  // 加载app时间 6000
  ew_updata.time_loadapp=checker_runcfg.params[1];
  // 总线关断时间 1000
  ew_updata.time_poweroff=checker_runcfg.params[2];
  // 升级模式，0，无app时升级；1，无条件升级
  ew_updata.updata_mode=checker_runcfg.params[3];
  EW_ParamPrint(&ew_updata);
  PowerCalibration_set(200,120);
  ret=EW_CheckState(&ew_updata);
  if(ret==2){
    // 在app中
    if(ew_updata.updata_mode==0){
      DBG_LOG("no need updata.");
      ret=0;
      goto err;
    }
  }
  ret=EW_TurnToBoot(&ew_updata);
  // ret!=1 跳转到bootloader失败
  if(ret!=1) {
    DBG_WARN("turn to boot failed.ret=%d",ret);
    ret=1;
    goto err;
  }
  DBG_LOG("erase app");
  ret=EW_bootErease();
  if(ret) {ret=2;goto err;}
  delay_os_ms(600);
  while(len>0){
    pack_len=len>UPDATA_PACK_LEN?UPDATA_PACK_LEN:len;
    LED1_Out=!LED1_Out;
    ret=EW_bootWrite(addr,data,pack_len);
    addr+=pack_len;
    data+=pack_len;
    len-=pack_len;
    if(ret) {ret=3;goto err;}
    delay_ms(1);
  }
  //crc=Crc32Calu((uint32_t *)(MC_CODE_ADDR+UPDATA_BASE_ADDR),UPDATA_DATA_LEN);
  crc=UPDATA_CRC_APP;
  DBG_LOG("local crc:0x%04x.",crc);
  ret=EW_bootCheckCrc(UPDATA_BASE_ADDR,UPDATA_BASE_ADDR+UPDATA_DATA_LEN,&crc_module);
  DBG_LOG("module crc:0x%04x.",crc_module);
  if(ret) {ret=4;goto err;}
  if(crc!=crc_module){ret=5;goto err;}
  delay_os_ms(50);
  ret=EW_bootJump();
  if(ret) {ret=6;goto err;}
  delay_os_ms(ew_updata.time_loadapp);
  ret=EW_EnWriteMTP(0,1);
  if(ret) {ret=7;goto err;}
  DBG_LOG("EW_EnWriteMTP success.");
  delay_ms(5);

  ret=EW_WriteMTP(1,(uint8_t)(UPDATA_FLAG_ADDR/4),UPDATA_FLAG,4);
  if(ret) {ret=8;goto err;}
  DBG_LOG("EW_WriteMTP success.");
  delay_os_ms(20);
  ret=EW_ReadMTP(1,(uint8_t)(UPDATA_FLAG_ADDR/4),read_buf,4);
  if(ret) {ret=9;goto err;}
  if(memcmp(read_buf,UPDATA_FLAG,4)!=0){
    DBG_LOG("read_buf=0x%02d,0x%02d,0x%02d,0x%02d.",read_buf[0],read_buf[1],read_buf[2],read_buf[3]);
    ret=10;goto err;
  }
  DBG_LOG("EW_ReadMTP check success.");
  delay_ms(5);
  XTBUS_OFF;
  delay_os_ms(ew_updata.time_poweroff);
  XTBUS_ON;
  delay_os_ms(ew_updata.time_loadapp);
  ret=EW_appCommTest();
  if(ret) {ret=11;goto err;}
  DBG_LOG("EW_appCommTest success.");
  
  err:
  DBG_LOG("ret=%d",ret);
  Checker_SetRtv(&ret,checker_runcfg.rtv_count);
  Checker_MaskResult(ret,checker_runcfg.task_info.runindex);
}
static int cmd_jwt_updata(list_def *argv)
{
  int ret=0;
  checker_runcfg.params[0]=6000;
  checker_runcfg.params[1]=6000;
  checker_runcfg.params[2]=1000;
  checker_runcfg.params[3]=0;
  checker_runcfg.rtv_count=0;
  EW_Updata();
  return ret;
}
commend_export(jwt_updata,cmd_jwt_updata,"jwt updata")




