#include "ptz_header_file.h"
#include "agent_hyt.h"
#include "service_update.h"
#include "comm_cfginfo.h"
#include "includes.h"
#include "w25q128.h"
#include "rotate_plan.h"
#include "enet_to_udp.h"
#include "device_wdog.h"
#include "onchip_flash.h"


//void OnChip_Flash_read_in_add(uint32_t address,uint16_t cnt,uint8_t*bBuf);
//uint8_t OnChip_Flash_write_byte(uint32_t address,uint16_t cnt, uint8_t buf[]);
//uint8_t OnChip_Flash_erase_sector(uint16_t sectorNo);

/******************************************************************************
** 函数名称： ushort cmCRC_16(uchar *PuchMsg,ushort usDataLen)
** 功   能： 16位CRC校验
** 修改日志：
******************************************************************************/
extern system_cfg_info system_info;

static unsigned char auch_crc_h[]={   
                                        0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81, //DESCRIPTION:RTU CRC校验的高位字节表
                                        0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,
                                        0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,
                                        0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
                                        0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,
                                        0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,
                                        0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,
                                        0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
                                        0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,
                                        0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,
                                        0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,
                                        0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
                                        0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,
                                        0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,
                                        0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,
                                        0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
                                        0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40};

static unsigned char auch_crc_l[]={   
                                        0x00,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,0x07,0xC7,0x05,0xC5,0xC4, //DESCRIPTION:RTU CRC校验的低位字节表
                                        0x04,0xCC,0x0C,0x0D,0xCD,0x0F,0xCF,0xCE,0x0E,0x0A,0xCA,0xCB,0x0B,0xC9,0x09,
                                        0x08,0xC8,0xD8,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,0x1E,0xDE,0xDF,0x1F,0xDD,
                                        0x1D,0x1C,0xDC,0x14,0xD4,0xD5,0x15,0xD7,0x17,0x16,0xD6,0xD2,0x12,0x13,0xD3,
                                        0x11,0xD1,0xD0,0x10,0xF0,0x30,0x31,0xF1,0x33,0xF3,0xF2,0x32,0x36,0xF6,0xF7,
                                        0x37,0xF5,0x35,0x34,0xF4,0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,0xFA,0x3A,
                                        0x3B,0xFB,0x39,0xF9,0xF8,0x38,0x28,0xE8,0xE9,0x29,0xEB,0x2B,0x2A,0xEA,0xEE,
                                        0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C,0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,
                                        0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0,0xA0,0x60,0x61,0xA1,0x63,0xA3,0xA2,
                                        0x62,0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4,0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,
                                        0x6E,0xAE,0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68,0x78,0xB8,0xB9,0x79,0xBB,
                                        0x7B,0x7A,0xBA,0xBE,0x7E,0x7F,0xBF,0x7D,0xBD,0xBC,0x7C,0xB4,0x74,0x75,0xB5,
                                        0x77,0xB7,0xB6,0x76,0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0,0x50,0x90,0x91,
                                        0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,0x9C,0x5C,
                                        0x5D,0x9D,0x5F,0x9F,0x9E,0x5E,0x5A,0x9A,0x9B,0x5B,0x99,0x59,0x58,0x98,0x88,
                                        0x48,0x49,0x89,0x4B,0x8B,0x8A,0x4A,0x4E,0x8E,0x8F,0x4F,0x8D,0x4D,0x4C,0x8C,
                                        0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x40};


static struct sockaddr_in ptz_update_local;//本地IP和端口

static struct sockaddr_in ptz_update_from;//IP和端口
static socklen_t ptz_update_fromlen;//长度

static struct sockaddr_in ptz_update_serv_a;//指定的默认升级服务端
static socklen_t ptz_update_servlen_a;

static struct sockaddr_in ptz_update_serv_b;//指定的默认升级服务端
static socklen_t ptz_update_servlen_b;

static struct sockaddr_in ptz_update_serv_c;//指定的默认升级服务端
static socklen_t ptz_update_servlen_c;

static struct sockaddr_in ptz_update_serv_d;//指定的默认升级服务端
static socklen_t ptz_update_servlen_d;


static int ptz_update_fd;//升级通道句柄

static UpdateRecvFifoBuff udrb;//数据接收存储
static UpdateRecvFifoBuff udpb;//数据处理存储
static UpdateRecvFifoBuff udsb;//数据发送存储区

static UpdateRecvFifoBuff urfb[UPDATE_BUFF_FIFO_NUM];//循环缓冲区
static int ptz_update_communicaton = PTZ_CONNECT_STATE_DEAD;
static unsigned short int ptz_update_fifo_read_addr;//循环存储区读地址标记
static unsigned short int ptz_update_fifo_write_addr;//循环存储区写地址标记

//static UpdateFileHead ptz_update_file_head;//升级文件头
static UpdateFileHead ptz_update_file_head_inf;//升级文件头

//用以保存接收到的升级frame的状态，
//每一位对应一个frame，如果对应的帧已经接收成功，则把这一位设置起来
//用frame_bit_map的每一位保存每一帧升级数据的接收保存状态
static unsigned char update_frame_bit_map[256];//升级状态存储区
static int update_bit_map_count = 0; //总共有多少bit
static int update_byte_map_count = 0;//总共有多少个byte

static unsigned char update_state;//云台升级状态

//升级补包表
static u_int16_t update_retrans_table_buff[MAX_RETRANS_TABLE_LEN+1];
static UpdateRetransTable *update_retrans_table = (UpdateRetransTable *)update_retrans_table_buff;

//文件校验
static u_int8_t flash_read_buff[256]; //片外flash读取的buffer
static u_int8_t flash_read_buff2[256];
static u_int8_t flash_read_buff3[256];

static u_int16_t feeddog_num = 0;



//UDP环形缓冲区的地址编号计算函数，如果到达唤醒缓冲区的尾部，将绕回到头部            
static unsigned char ptz_update_fifo_addring(unsigned short int i)
{
  return ((i + 1) == UPDATE_BUFF_FIFO_NUM) ? 0 : i+1;
}

//UDP环形缓冲区写入数据
static void ptz_update_fifo_write_data()
{
  //把原来的数据清除
  memset(&urfb[ptz_update_fifo_write_addr], 0, sizeof(urfb[ptz_update_fifo_write_addr]));
  
  //保存数据,保存有效数据长度
  memcpy(&urfb[ptz_update_fifo_write_addr], &udrb, sizeof(udrb));
  ptz_update_fifo_write_addr = ptz_update_fifo_addring(ptz_update_fifo_write_addr);
}


//UDP环形缓冲区读出数据
static UpdateRecvFifoBuff ptz_update_fifo_read_data()
{
  UpdateRecvFifoBuff fifo_data;
  fifo_data = urfb[ptz_update_fifo_read_addr];
  ptz_update_fifo_read_addr = ptz_update_fifo_addring(ptz_update_fifo_read_addr);
  return fifo_data;
}

//效验码计算
static unsigned  short int ptz_update_calc_frame_crc16( unsigned  char *PuchMsg,unsigned  int usDataLen)
{
   unsigned  char uch_crc_h;      //high byte of CRC initialized
   unsigned  char uch_crc_l;      //low byte of CRC initialized
   unsigned  short int uIndex;        //will index into CRC lookup table

   uch_crc_h=0xFF;
   uch_crc_l=0xFF;

   while(usDataLen--)
   {
       //calculate the CRC
       uIndex   = uch_crc_h^(unsigned  char)(*PuchMsg++);
       uch_crc_h = uch_crc_l^auch_crc_h[uIndex];
       uch_crc_l = auch_crc_l[uIndex];
   }
   return(uch_crc_h <<8|uch_crc_l);
}


//应用升级包数据片写入片外flash缓存空间，空间必须先被擦除
//request是升级包总描述信息，frame是要写入的分片
static BOOL ptz_update_write_frame_to_flash_buff(UpdateRequest *request, UpdateData *frame)
{
  u_int32_t offset = UPDATE_FLASH_BUFF_BEGIN_ADDR + request->frame_len * frame->index;
  if((offset + frame->data_len) > UPDATE_FLASH_BUFF_END_ADDR)
    return FALSE;
  
  Flash_Write_MorePage(frame->data, offset, frame->data_len);
  return TRUE;
}

//擦除片外flash应用升级包缓存空间，total_len是升级包的长度
static BOOL ptz_update_erase_flash_buff(unsigned int total_len)
{
  int i = 0;
  int block_count = total_len / Flash_BLOCKBYTE_LENGTH;
  
  if(total_len>UPDATE_FLASH_BUFF_SIZE)
    return FALSE;
  
  if(total_len % Flash_BLOCKBYTE_LENGTH)
    block_count++;
  
  feeddog_num = 0;
  for(i = 0; i<block_count; i++)
  {
    Flash_Erase_Block(UPDATE_FLASH_BUFF_BEGIN_BLOCK + i);
    feeddog_num = feeddog_num + 1;
    if(feeddog_num % 2 == 0)
    {
      OSTimeDlyHMSM(0u, 0u, 0u, 2u);
    }
  }
  feeddog_num = 0;
  return TRUE;
}

//初始化frame_bit_map，清空，同时设置总数
static int ptz_update_init_frame_bit_map(int frame_count)
{
  int byte_count = frame_count / BITS_PER_UNIT;
  if(frame_count % BITS_PER_UNIT)
    byte_count++;
  if(byte_count > sizeof(update_frame_bit_map))
  {
    return 0;
  }
  else
  {
    update_bit_map_count = frame_count;
    update_byte_map_count = byte_count;
    memset(update_frame_bit_map, 0, sizeof(update_frame_bit_map));
    return update_byte_map_count;
  }
}

//设置序号为index的帧对应的bit_map
static BOOL ptz_update_set_frame_bit_map(int index)
{
  if(index > update_bit_map_count)//index是从0开始的
    return FALSE;
  int byte_offset = index / BITS_PER_UNIT;
  int bit_offset = index % BITS_PER_UNIT;
  update_frame_bit_map[byte_offset] |= (0x01<<bit_offset);
  return TRUE;
}

//根据bit_map返回补包表，参数max_count传入表中能保存的最大记录数
static BOOL ptz_update_get_upgrade_retrans_table(UpdateRequest *request_info, UpdateRetransTable *table, int max_count)
{
  int byte_offset = 0;
  int bit_offset = 0;
  int index = 0;
  table->count = 0;
  memset(update_retrans_table_buff, 0, sizeof(update_retrans_table_buff));
  for(byte_offset= 0; byte_offset < update_byte_map_count; byte_offset++)
  {
    for(bit_offset = 0; bit_offset < BITS_PER_UNIT; bit_offset++)
    {
      if(((0x01 << bit_offset) & update_frame_bit_map[byte_offset]) == 0) //该帧未成功收到
      {
        if(table->count >= max_count) //超出返回容量
          return FALSE;
        table->index[table->count] = index;
        table->count++;
      }
      index++;
      if(index >= request_info->frame_count)
        return TRUE;
    }
  }
  return TRUE;
}


static void ptz_update_CRC16_init(CPU_INT16U *crc16)
{
        *crc16 = 0xFFFF;
}


static CPU_INT16U ptz_update_CRC16( CPU_INT08U *PuchMsg,CPU_INT32U usDataLen)
{
   CPU_INT08U uchCRCHi;      //high byte of CRC initialized
   CPU_INT08U uchCRCLo;      //low byte of CRC initialized
   CPU_INT16U uIndex;        //will index into CRC lookup table

   uchCRCHi=0xFF;
   uchCRCLo=0xFF;

   while(usDataLen--)
   {
       //calculate the CRC
       uIndex   = uchCRCHi^(CPU_INT08U)(*PuchMsg++);
       uchCRCHi = uchCRCLo^auch_crc_h[uIndex];
       uchCRCLo = auch_crc_l[uIndex];
   }
   return(uchCRCHi <<8|uchCRCLo);
}

static void ptz_update_CRC16_update(CPU_INT16U *crc16, CPU_INT08U *PuchMsg,CPU_INT32U usDataLen)
{
   CPU_INT08U uchCRCHi;      //high byte of CRC initialized
   CPU_INT08U uchCRCLo;      //low byte of CRC initialized
   CPU_INT16U uIndex;        //will index into CRC lookup table

   uchCRCHi = (*crc16) >> 8;
   uchCRCLo = (*crc16) & 0xFF;

   while(usDataLen--)
   {
       uIndex   = uchCRCHi^(CPU_INT08U)(*PuchMsg++);
       uchCRCHi = uchCRCLo^auch_crc_h[uIndex];
       uchCRCLo = auch_crc_l[uIndex];
   }

   *crc16 = (uchCRCHi <<8|uchCRCLo);
}

static u_int16_t _flash_buff_crc16(u_int32_t offset, u_int32_t len)
{
  u_int16_t ret;
  u_int32_t read_len;
  ptz_update_CRC16_init(&ret);
  feeddog_num = 0;
  while(len)
  {
    if(len > sizeof(flash_read_buff))
      read_len = sizeof(flash_read_buff);
    else
      read_len = len;
    
    Flash_Read(flash_read_buff, offset, read_len);
    ptz_update_CRC16_update(&ret, flash_read_buff, read_len);
    len -= read_len;
    offset += read_len;
    feeddog_num = feeddog_num + 1;
    if(feeddog_num % 20 == 0)
    {
      OSTimeDlyHMSM(0u, 0u, 0u, 5u);
    }
  }
  feeddog_num = 0;
  return ret;
}

//检验片外flash缓存空间中的应用升级包的CRC是否正确
//total_len是升级包的总长度，包括结尾的crc16
static BOOL ptz_update_flash_buff_file_crc_OK(u_int32_t total_len)
{
  u_int16_t crc_calc = 0;
  u_int16_t crc_read = 0;
  
  if(total_len < sizeof(crc_calc))
    return FALSE;
  
  crc_calc = flash_buff_crc16(total_len-2);
  
  Flash_Read((u_int8_t *)&crc_read, UPDATE_FLASH_BUFF_BEGIN_ADDR + total_len - sizeof(crc_calc), sizeof(crc_calc));
  return crc_calc == crc_read;
}



void ptz_update_complete_frame_packet(UpdateFrame *pack)
{
        pack->frame_type = UPDATE_FRAME_TYPE_SEND;
        *(u_int16_t *)(&pack->data[pack->data_len]) = ptz_update_CRC16((u_int8_t *)pack, UPDATE_FRAME_SIZE(pack) - sizeof(u_int16_t));
}


//计算chcksum
static u_int8_t ptz_check_sum(u_int8_t *p, int len)
{
        u_int8_t ret = 0;
        int i = 0;

        for(; i<len; i++)
        {  
                ret += p[i];
        }        
        return (~ret)+1;
}

//检查片内升级包头的checksum
static u_int8_t ptz_update_file_head_checksum_OK(UpdateFileHead *file_head)
{
   return ptz_check_sum((u_int8_t *)file_head, (u_int8_t *)(&file_head->head_checksum) - (u_int8_t *)file_head)
     == file_head->head_checksum;
}


//校验片外存储器中缓存的升级包的完整性
static BOOL ptz_update_file_head_verify(u_int32_t total_len, UpdateFileHead *file_head)
{
  Flash_Read((u_int8_t *)file_head, UPDATE_FLASH_BUFF_BEGIN_ADDR, sizeof(*file_head));
  
  //检查头的checksum
  if(!ptz_update_file_head_checksum_OK(file_head))
    return FALSE;

  //数据长度确认
  if(file_head->data_len != (total_len - sizeof(u_int16_t) - sizeof(*file_head)))
    return FALSE;
  
  //起始标志检查
  if(file_head->flag != UPDATE_RELEASE_FILE_FLAG)
    return FALSE;
  
  //头长度检验
  if(file_head->head_len != sizeof(*file_head))
    return FALSE;
  
  //文件类型检验 boot app cert key cfg_file
  if((file_head->file_type != UPDATE_FILE_TYPE_NW_INFO) && (file_head->file_type != UPDATE_FILE_TYPE_APP) && (file_head->file_type != UPDATE_FILE_TYPE_BOOT_LOADER) && (file_head->file_type != UPDATE_FILE_TYPE_CERT) && (file_head->file_type != UPDATE_FILE_TYPE_PUB_KEY)&& (file_head->file_type != UPDATE_FILE_TYPE_CFG_FILE) && ((file_head->file_type != UPDATE_FILE_TYPE_CFG_IP)))
    return FALSE;
  
  //文件格式版本
  if(file_head->file_format_ver != 1)
    return FALSE;  
  
  if(file_head->file_type == UPDATE_FILE_TYPE_APP){ //App
    //烧写地址检验
    if(file_head->addr < (UPDATE_APP_ADDR_BEGIN - APP_ADD_BEGIN_OFFEST))
      return FALSE;
    //空间检验
    if((file_head->addr + file_head->data_len) > (UPDATE_APP_ADDR_END - APP_ADD_BEGIN_OFFEST))
      return FALSE;
  }else if(file_head->file_type == UPDATE_FILE_TYPE_BOOT_LOADER){ //Bootloader
    //烧写地址检验
    if(file_head->addr != 0) //bootloader必须以0为起始地址
      return FALSE;
    //空间检验
    if((file_head->addr + file_head->data_len) > UPDATE_BOOTLOADER_ADDR_END)
      return FALSE;
  }else if(file_head->file_type == UPDATE_FILE_TYPE_CERT){//CERT
     //烧写地址
    if(file_head->addr < UPDATE_CERT_ADDR_BEGIN)
      return FALSE;
    //空间检验
    if((file_head->addr + file_head->data_len) > UPDATE_CERT_ADDR_END)
      return FALSE;    
  }else if(file_head->file_type == UPDATE_FILE_TYPE_PUB_KEY){//KEY
     //烧写地址
    if(file_head->addr < UPDATE_KEY_ADDR_BEGIN)
      return FALSE;
    //空间检验
    if((file_head->addr + file_head->data_len) > UPDATE_KEY_ADDR_END)
      return FALSE;   
  }else if(file_head->file_type == UPDATE_FILE_TYPE_CFG_FILE){//CFG FILE
     //烧写地址
    if(file_head->addr < UPDATE_CFG_FILE_ADDR_BEGIN)
      return FALSE;
    //空间检验
    if((file_head->addr + file_head->data_len) > UPDATE_CFG_FILE_ADDR_END)
      return FALSE;   
  }else if (file_head->file_type == UPDATE_FILE_TYPE_CFG_IP){//CFG IP
       //烧写地址
    if(file_head->addr < UPDATE_CFG_IP_ADDR_BEGIN)
      return FALSE;
    //空间检验
    if((file_head->addr + file_head->data_len) > UPDATE_CFG_IP_ADDR_END)
      return FALSE;   
  }else if (file_head->file_type == UPDATE_FILE_TYPE_NW_INFO){//NW INFO
       //烧写地址
    if(file_head->addr < UPDATE_CFG_NW_INFO_ADDR_BEGIN)
      return FALSE;
    //空间检验
    if((file_head->addr + file_head->data_len) > UPDATE_CFG_NW_INFO_ADDR_END)
      return FALSE;
  }
  return TRUE;
}

//擦除应用程序在片内rom中的存储空间
//如果是应用app/bootloader擦除片内flash. 
//如果是cert--/key/cfg片外flash
static BOOL ptz_update_program_flash_erase(UpdateFileHead *file_head)
{
  //int i = 0;
  u_int32_t total_len = file_head->data_len;
  //int sector_begin = file_head->addr / UPDATE_ON_CHIP_FLASH_SECTOR_SIZE;
  //int sector_count = total_len / UPDATE_ON_CHIP_FLASH_SECTOR_SIZE;
  
  if(file_head->file_type == UPDATE_FILE_TYPE_APP)
  {
    if((file_head->addr + total_len) > UPDATE_APP_ADDR_END)
    {
       return FALSE;
    }
//    return TRUE;
    if(1 == OnChip_Flash_erase_sector(APP_PKG_HEAD_SECTOR_BEGIN))
    {
      term_printf("\n 擦除片内rom失败，APP_PKG_HEAD_SECTOR_BEGIN \r\n");
      return FALSE;
    }
    if(1 == OnChip_Flash_erase_sector(CTL_SECTOR_NUMBER_4))
    {
      term_printf("\n 擦除片内rom失败，CTL_SECTOR_NUMBER_4  \r\n");
      return FALSE;
    }
    if(1 == OnChip_Flash_erase_sector(CTL_SECTOR_NUMBER_5))
    {
      term_printf("\n 擦除片内rom失败，CTL_SECTOR_NUMBER_5 \r\n");
      return FALSE;
    }
//    OnChip_Flash_erase_sector(UPDATE_APP_PKG_HEAD_SECTOR_BEGIN);//同时为升级包的头信息删除一个sector
//    if(total_len % UPDATE_ON_CHIP_FLASH_SECTOR_SIZE)
//    sector_count++;
//   
//    for(i = 0; i<sector_count; i++){
//        OnChip_Flash_erase_sector(sector_begin + i);
//    }
    
  }
  else if(file_head->file_type == UPDATE_FILE_TYPE_PUB_KEY)
  {
    if((file_head->addr + total_len) > UPDATE_KEY_ADDR_END)
       return FALSE;
       Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM,UPDATE_KEY_HEAD_SECTOR_BEGIN);
       Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM,UPDATE_KEY_SECTOR_BEGIN);       
  }
  else if(file_head->file_type == UPDATE_FILE_TYPE_CERT)
  {
    if((file_head->addr + total_len) > UPDATE_CERT_ADDR_END)
       return FALSE;
    Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM,UPDATE_CERT_HEAD_SECTOR_BEGIN);
    Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM,UPDATE_CERT_SECTOR_BEGIN);      
  }
  else if(file_head->file_type == UPDATE_FILE_TYPE_CFG_FILE)
  {
    if((file_head->addr + total_len) > UPDATE_CFG_FILE_ADDR_END)
       return FALSE;
     Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM,UPDATE_CFG_FILE_HEAD_SECTOR_BEGIN);
     Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM,UPDATE_CFG_FILE_SECTOR_BEGIN);  
  }
  else if(file_head->file_type == UPDATE_FILE_TYPE_CFG_IP)
  {//ip配置
     if((file_head->addr + total_len) > UPDATE_CFG_IP_ADDR_END)
       return FALSE;
     Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM16,UPDATE_CFG_IP_HEAD_SECTOR_BEGIN);
     Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM16,UPDATE_CFG_IP_SECTOR_BEGIN); 
  }
  else if(file_head->file_type == UPDATE_FILE_TYPE_NW_INFO)
  {//南网台帐信息
     if((file_head->addr + total_len) > UPDATE_CFG_NW_INFO_ADDR_END)
       return FALSE;
     Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM16,UPDATE_CFG_NW_INFO_HEAD_SECTOR_BEGIN);
     Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM16,UPDATE_CFG_NW_INFO_SECTOR_BEGIN);
     Flash_Erase_Sector(UPDATE_EXT_FLASH_BLOCK_NUM16,UPDATE_CFG_NW_INFO_SECTOR_BEGIN+1);
  }
  return TRUE;
}

//app/booter从片外存储器将升级数据复制到片内rom
//cert/key/cfg_file 从片外缓冲区复制到片外另外区域
static BOOL ptz_update_program_flash_copy(UpdateFileHead *file_head)
{
  u_int32_t read_len;
  u_int32_t read_addr = UPDATE_FLASH_BUFF_BEGIN_ADDR + file_head->head_len;
  u_int32_t len = file_head->data_len + sizeof(u_int16_t); //复制内容包括结尾的crc16
//  u_int32_t write_addr = file_head->addr;
  
  u_int32_t write_addr = APP_ADDR_BEGIN;
  char erase_state=0;

  if (file_head->file_type == UPDATE_FILE_TYPE_APP)
  {//应用程序
//    return TRUE;
    while(len)
      {//写程序
        if(erase_state == 0)
        {
          erase_state++;
          if(1 == OnChip_Flash_erase_sector(CTL_SECTOR_NUMBER_4))
          {
            term_printf("\n 擦除片内rom失败，CTL_SECTOR_NUMBER_4  \r\n");
            return FALSE;
          }
        }
        if(len > sizeof(flash_read_buff))
        {
          read_len = sizeof(flash_read_buff);
        }else{
          read_len = len;
        }
        memset(flash_read_buff,0,sizeof(flash_read_buff));
        Flash_Read(flash_read_buff, read_addr, read_len);
//        FeedDog();
//        term_printf("\n 程序写入成功,地址write_addr = %d \r\n",flash_read_buff);
        if(OnChip_Flash_write_byte(write_addr, read_len, flash_read_buff) != 0)
        {
          term_printf("\n 程序写入失败,地址write_addr = \r\n",write_addr);
          return FALSE;
          
        }
        
        OnChip_Flash_read_in_add(write_addr, read_len, (uint8_t*)&flash_read_buff3);
        
        if (memcmp(flash_read_buff, flash_read_buff3, read_len) != 0)
         {
           term_printf("\n write rom error to different  \r\n");
           return FALSE;
         }
        len -= read_len;
        read_addr += read_len;
        write_addr += read_len;
        if(erase_state == 1 && write_addr >= 0x801FFFF)
        {
          erase_state++;
          if(1 == OnChip_Flash_erase_sector(CTL_SECTOR_NUMBER_5))
          {
            term_printf("\n 擦除片内rom失败，CTL_SECTOR_NUMBER_5  \r\n");
            return FALSE;
          }
        }
      }
      term_printf("\n 程序写入成功,地址write_addr = %d \r\n",write_addr);
//      if(write_addr >= 0x8040c00)
//      {
//        term_printf("\n write_addr == 0x8040c00  \r\n");
//      }
//      OnChip_Flash_erase_sector(APP_PKG_HEAD_SECTOR_BEGIN);
      if (OnChip_Flash_write_byte(APP_PKG_HEAD_BEGIN, sizeof(*file_head), (u_int8_t *)file_head) != 0)//写头
      {
        term_printf("\n 文件头写入失败,地址write_addr = \r\n",APP_PKG_HEAD_BEGIN);
        return FALSE;
      }
  }
  else
  {
      feeddog_num = 0;
      while(len)
      {
        if(len > sizeof(flash_read_buff))
          read_len = sizeof(flash_read_buff);
        else
          read_len = len;
        Flash_Read(flash_read_buff, read_addr, read_len);
        Flash_Write_Page(flash_read_buff,write_addr,read_len);
        len -= read_len;
        read_addr += read_len;
        write_addr += read_len;
        feeddog_num = feeddog_num + 1;
        if(feeddog_num % 20 == 0)
        {
          OSTimeDlyHMSM(0u, 0u, 0u, 5u);
        }
      }
      feeddog_num = 0;
      if (file_head->file_type == UPDATE_FILE_TYPE_PUB_KEY)
      {//公钥
          Flash_Write_Page((u_int8_t *)file_head,UPDATE_KEY_HEAD_BEGIN,sizeof(*file_head));
      }
      else if(file_head->file_type == UPDATE_FILE_TYPE_CERT)
      {//证书
          Flash_Write_Page((u_int8_t *)file_head,UPDATE_CERT_HEAD_BEGIN,sizeof(*file_head)); 
      }
      else if(file_head->file_type == UPDATE_FILE_TYPE_CFG_FILE)
      {//配置文件
          Flash_Write_Page((u_int8_t *)file_head,UPDATE_CFG_FILE_HEAD_BEGIN,sizeof(*file_head));
      }
      else if(file_head->file_type == UPDATE_FILE_TYPE_CFG_IP)
      {//IP配置文件
          Flash_Write_Page((u_int8_t *)file_head,UPDATE_CFG_IP_HEAD_BEGIN,sizeof(*file_head));
      }
      else if(file_head->file_type == UPDATE_FILE_TYPE_NW_INFO)
      {//南网台帐
          Flash_Write_Page((u_int8_t *)file_head,UPDATE_CFG_NW_INFO_HEAD_BEGIN,sizeof(*file_head));
      }  
  }  
  return TRUE;
}
  
//校验已写入片内rom的应用程序包
//通过读出片外flash内容与片内内容完全比较的方式校验
static BOOL ptz_update_program_app_verify(u_int8_t file_type)
{
  u_int32_t read_len, len;
  u_int32_t read_addr = UPDATE_FLASH_BUFF_BEGIN_ADDR + sizeof(UpdateFileHead);
  
  static UpdateFileHead file_head;
  static UpdateFileHead file_head2;  
  u_int32_t app_addr = 0;
   
  memset(&file_head, 0, sizeof(file_head));
  
  //首先校验头信息
  if (file_type == UPDATE_FILE_TYPE_APP)
  {//APP 
      app_addr = UPDATE_APP_ADDR_BEGIN;
      Flash_Read((u_int8_t *)&file_head, UPDATE_FLASH_BUFF_BEGIN_ADDR, sizeof(file_head));
      if(memcmp(&file_head, (u_int8_t *)UPDATE_APP_PKG_HEAD_BEGIN, sizeof(file_head)) != 0)
         return FALSE;
      len = file_head.data_len + sizeof(u_int16_t); //校验包括crc16内容
      while(len){
          if(len > sizeof(flash_read_buff))
            read_len = sizeof(flash_read_buff);
          else
            read_len = len;
          Flash_Read(flash_read_buff, read_addr, read_len);
          
          if(memcmp(flash_read_buff, (u_int8_t *)app_addr, read_len) != 0)
            return FALSE;
          
          len -= read_len;
          read_addr += read_len;
          app_addr += read_len;
       }
    return TRUE;
  }
  else
  { 
    if (file_type == UPDATE_FILE_TYPE_CERT)
    {//CERT    
         app_addr = UPDATE_CERT_ADDR_BEGIN;
         Flash_Read((u_int8_t *)&file_head,  UPDATE_FLASH_BUFF_BEGIN_ADDR, sizeof(file_head));
         Flash_Read((u_int8_t *)&file_head2, UPDATE_CERT_HEAD_BEGIN, sizeof(file_head2));
         if(memcmp(&file_head,&file_head2, sizeof(file_head)) != 0)
            return FALSE;
     }
    else if(file_type == UPDATE_FILE_TYPE_PUB_KEY)
    {
         app_addr = UPDATE_KEY_ADDR_BEGIN;
         Flash_Read((u_int8_t *)&file_head,  UPDATE_FLASH_BUFF_BEGIN_ADDR, sizeof(file_head));
         Flash_Read((u_int8_t *)&file_head2, UPDATE_KEY_HEAD_BEGIN, sizeof(file_head2));
         if (memcmp(&file_head,&file_head2, sizeof(file_head)) != 0)
            return FALSE;
     }
    else if(file_type ==UPDATE_FILE_TYPE_CFG_FILE)
    {
         app_addr = UPDATE_CFG_FILE_ADDR_BEGIN;
         Flash_Read((u_int8_t *)&file_head,  UPDATE_FLASH_BUFF_BEGIN_ADDR, sizeof(file_head));
         Flash_Read((u_int8_t *)&file_head2, UPDATE_CFG_FILE_HEAD_BEGIN, sizeof(file_head2));
         if (memcmp(&file_head,&file_head2, sizeof(file_head)) != 0)
             return FALSE;
     }
    else if(file_type ==UPDATE_FILE_TYPE_CFG_IP)
    {
         app_addr = UPDATE_CFG_IP_ADDR_BEGIN;
         Flash_Read((u_int8_t *)&file_head,  UPDATE_FLASH_BUFF_BEGIN_ADDR, sizeof(file_head));
         Flash_Read((u_int8_t *)&file_head2, UPDATE_CFG_IP_HEAD_BEGIN, sizeof(file_head2));
         if (memcmp(&file_head,&file_head2, sizeof(file_head)) != 0)
             return FALSE;
     }
    else if(file_type ==UPDATE_FILE_TYPE_NW_INFO)
    {
         app_addr = UPDATE_CFG_NW_INFO_ADDR_BEGIN;
         Flash_Read((u_int8_t *)&file_head,  UPDATE_FLASH_BUFF_BEGIN_ADDR, sizeof(file_head));
         Flash_Read((u_int8_t *)&file_head2, UPDATE_CFG_NW_INFO_HEAD_BEGIN, sizeof(file_head2));
         if (memcmp(&file_head,&file_head2, sizeof(file_head)) != 0)
             return FALSE;
     }
    
      len = file_head.data_len + sizeof(u_int16_t); //校验包括crc16内容
      feeddog_num = 0;
      while(len)
      {
          if(len > sizeof(flash_read_buff))
            read_len = sizeof(flash_read_buff);
          else
            read_len = len;
          Flash_Read(flash_read_buff, read_addr, read_len);
          Flash_Read(flash_read_buff2,app_addr,read_len);
          if(memcmp(flash_read_buff,flash_read_buff2, read_len) != 0)
             return FALSE;
          len -= read_len;
          read_addr += read_len;
          app_addr += read_len;
          feeddog_num = feeddog_num + 1;
          if(feeddog_num % 20 == 0)
          {
            OSTimeDlyHMSM(0u, 0u, 0u, 5u);
          }
       }
       feeddog_num = 0;
  }
  return TRUE;
}

//校验并把片外flash中缓存的App升级包烧写进片内rom，然后再校验
static BOOL ptz_update_program_file(u_int32_t total_len)
{
  static UpdateFileHead file_head;

  memset(&file_head, 0, sizeof(file_head));
  Flash_Read((u_int8_t *)&file_head, UPDATE_FLASH_BUFF_BEGIN_ADDR, sizeof(file_head));
  
  if(!ptz_update_file_head_verify(total_len, &file_head))
    return FALSE;
  
  if((file_head.file_type == UPDATE_FILE_TYPE_NW_INFO)  || 
     (file_head.file_type == UPDATE_FILE_TYPE_APP)      || 
     (file_head.file_type == UPDATE_FILE_TYPE_PUB_KEY)  || 
     (file_head.file_type == UPDATE_FILE_TYPE_CERT)     || 
     (file_head.file_type == UPDATE_FILE_TYPE_CFG_FILE) || 
     (file_head.file_type == UPDATE_FILE_TYPE_CFG_IP))
  {
    if(!ptz_update_program_flash_erase(&file_head))
      return FALSE;
  
    if(!ptz_update_program_flash_copy(&file_head))
        return FALSE;
      
    if(!ptz_update_program_app_verify(file_head.file_type))
           return FALSE;
    
  }else //不认识的文件类型
       return FALSE;
  return TRUE;
}



static BOOL ptz_update_burn_bootloader(u_int32_t total_len)
{
  static UpdateFileHead file_head;
  
  memset(&file_head, 0, sizeof(file_head));
  Flash_Read((u_int8_t *)&file_head, UPDATE_FLASH_BUFF_BEGIN_ADDR, sizeof(file_head));
  
  if(file_head.file_type == UPDATE_FILE_TYPE_BOOT_LOADER)
  {
     if(!ptz_update_file_head_verify(total_len, &file_head))
       return FALSE;
  
//    if(!ptz_update_bootloader_flash_erase(&file_head))
//       return FALSE;
//   
//    if(!ptz_update_bootloader_flash_copy(&file_head))
//        return FALSE;
//    
//    if(!ptz_update_bootloader_verify())
//        return FALSE;
     
     
  }else  
      //不认识的文件类型
    return FALSE;
  
  return TRUE;
}



//云台向升级端发送升级回复
static void ptz_send_update_reply(unsigned char pack_type, const void *data, int len)
{
  //建立一个指针指向发送数据缓冲区
  UpdateFrame *pack = (UpdateFrame *)udsb.data_buff;
  //对发送缓冲区数据清0
  memset(&udsb, 0, sizeof(udsb));
  //数据封包
  pack->flag = UPDATE_FRAME_HEAD_FLAG;//帧头
  pack->data_len = len;//数据长度
  if(data && (len > 0))//判断有无数据
          memcpy(pack->data, data, len);//有数据则装载数据
  memcpy(pack->id, system_info.cmd_id, sizeof(pack->id));//复制设备ID
  pack->frame_type = UPDATE_FRAME_TYPE_SEND;
  pack->pack_type = pack_type;
  //计算数据包总长度
  udsb.data_len = UPDATE_FRAME_SIZE(pack);
  ptz_update_complete_frame_packet(pack);
  //发送数据
  BSP_OS_SemWait(&udp_send_data_mutex, 0u);
  if(ptz_update_communicaton == PTZ_CONNECT_STATE_SUCCESS){
	int ret = sendto(ptz_update_fd, pack,  udsb.data_len, 0, (struct sockaddr*)&ptz_update_from, ptz_update_fromlen);
	if(ret == -1){
		ptz_update_communicaton = PTZ_CONNECT_STATE_FAILED;
		close(ptz_update_fd);
	}
  }
  BSP_OS_SemPost(&udp_send_data_mutex);
}


//云台向指定的升级端发送心跳包ptz_send_update_reply(UPDATE_FRAME_TYPE_KEEP_ALIVE, NULL, 0);
static void ptz_send_update_heartbeat()
{
  int ret;
  //建立一个指针指向发送数据缓冲区
  UpdateFrame *pack = (UpdateFrame *)udsb.data_buff;
  //对发送缓冲区数据清0
  memset(&udsb, 0, sizeof(udsb));
  //数据封包
  pack->flag = UPDATE_FRAME_HEAD_FLAG;//帧头
  pack->data_len = 0;//数据长度
  memcpy(pack->id, system_info.cmd_id, sizeof(pack->id));//复制设备ID
  pack->frame_type = UPDATE_FRAME_TYPE_SEND;
  pack->pack_type = UPDATE_FRAME_TYPE_KEEP_ALIVE;
  //计算数据包总长度
  udsb.data_len = UPDATE_FRAME_SIZE(pack);
  ptz_update_complete_frame_packet(pack);
  //发送数据
  BSP_OS_SemWait(&udp_send_data_mutex, 0u);
  if(ptz_update_communicaton == PTZ_CONNECT_STATE_SUCCESS)
  {
      ret = sendto(ptz_update_fd, pack,  udsb.data_len, 0, (struct sockaddr*)&ptz_update_serv_a, ptz_update_servlen_a);
      if(ret == -1){
              ptz_update_communicaton = PTZ_CONNECT_STATE_FAILED;
              close(ptz_update_fd);
              BSP_OS_SemPost(&udp_send_data_mutex);
              return;
      }
      
      ret = sendto(ptz_update_fd, pack,  udsb.data_len, 0, (struct sockaddr*)&ptz_update_serv_b, ptz_update_servlen_b);
      if(ret == -1){
              ptz_update_communicaton = PTZ_CONNECT_STATE_FAILED;
              close(ptz_update_fd);
              BSP_OS_SemPost(&udp_send_data_mutex);
              return;
      }
      
      ret = sendto(ptz_update_fd, pack,  udsb.data_len, 0, (struct sockaddr*)&ptz_update_serv_c, ptz_update_servlen_c);
      if(ret == -1){
              ptz_update_communicaton = PTZ_CONNECT_STATE_FAILED;
              close(ptz_update_fd);
              BSP_OS_SemPost(&udp_send_data_mutex);
              return;
      }
      
      ret = sendto(ptz_update_fd, pack,  udsb.data_len, 0, (struct sockaddr*)&ptz_update_serv_d, ptz_update_servlen_d);
      if(ret == -1){
              ptz_update_communicaton = PTZ_CONNECT_STATE_FAILED;
              close(ptz_update_fd);
              BSP_OS_SemPost(&udp_send_data_mutex);
              return;
      }
  }
  BSP_OS_SemPost(&udp_send_data_mutex);
}



//升级数据接收
static void ptz_update_rece_data_task()
{
  while(1) 
  {
    //建立本地连接通道
    if(ptz_update_communicaton != PTZ_CONNECT_STATE_SUCCESS)
    {
      ptz_update_fd = CreateUDPClientSock();
      if(ptz_update_fd != -1) 
      {
        // 设置服务器端ip和端口号
        memset(&ptz_update_from, 0, sizeof(struct sockaddr_in));
        ptz_update_local.sin_family = PF_INET;
        // 监听端口
        ptz_update_local.sin_port = htons(PTZ_UPDATE_PORT);
        ptz_update_local.sin_addr.s_addr = INADDR_ANY;
        ptz_update_fromlen = sizeof(ptz_update_from);
        if(0!=bind(ptz_update_fd,(struct sockaddr*)&ptz_update_local,sizeof(ptz_update_local)))
        {
          close(ptz_update_fd);
        }
        else
        {
          ptz_update_communicaton = PTZ_CONNECT_STATE_SUCCESS;
        }
      }
      else
      {
        ptz_update_communicaton = PTZ_CONNECT_STATE_FAILED;
        close(ptz_update_fd);
      }
    }
    
    if(ptz_update_communicaton == PTZ_CONNECT_STATE_SUCCESS) 
    {
      memset(&udrb, 0, sizeof(udrb));//'\0'
      udrb.data_len = 
        recvfrom(ptz_update_fd, udrb.data_buff, sizeof(udrb.data_buff), 0, (struct sockaddr*)&ptz_update_from, &ptz_update_fromlen);
        if (udrb.data_len >0)
        {
          //将数据保存到环形缓冲区
          ptz_update_fifo_write_data(); 
        }
        else
        {     
          ptz_update_communicaton = PTZ_CONNECT_STATE_FAILED;
          close(ptz_update_fd);
        }
    }
    OSTimeDlyHMSM(0u, 0u, 0u, 2u);
  }
}



//云台升级数据处理
static void ptz_update_data_process_task()
{
  static char info_str[256];
  static char kh = 0;
  int count = 0;
  static UpdateFrame* update_frame = (UpdateFrame *)udpb.data_buff;//升级帧
  static UpdateRequest request_info;//升级请求
  static UpdateData* update_data = NULL;//升级具体数据
  
  static unsigned char update_active_connect_switch = 0;//主动连接指定升级服务端开关
  static unsigned int  update_active_connect_timer = 0;//主动连接指定升级服务端计时
  
  while(1)
  {
#if 1
    //判断循环buff里面是否有未处理的数据
    if(ptz_update_fifo_read_addr != ptz_update_fifo_write_addr)
    {

      memset(&udpb, 0, sizeof(udpb));
      //从循环buff读取数据

//      udpb = ptz_update_fifo_read_data();
      udpb = urfb[ptz_update_fifo_read_addr];
      ptz_update_fifo_read_addr = ptz_update_fifo_addring(ptz_update_fifo_read_addr);
      //开始处理数据
    
      if(ptz_update_calc_frame_crc16(udpb.data_buff, udpb.data_len - 2) == 
         UPDATE_FRAME_GET_CRC16(update_frame)) //首先判断每一帧的校验码是否正确
      {

        if(update_frame->frame_type == UPDATE_FRAME_TYPE_RECE &&//判断帧类型是不是接收数据
           update_frame->flag == UPDATE_FRAME_HEAD_FLAG)//判断帧头是否正确
        {
          switch(update_frame->pack_type)
          {
            case UPDATE_FRAME_TYPE_KEEP_ALIVE:         //0X01 用以保持连接
              ptz_send_update_reply(UPDATE_FRAME_TYPE_KEEP_ALIVE, NULL, 0);
              break; 
              
            case UPDATE_FRAME_TYPE_GET_DEVICE_INFO:    //0X02 用于获取设备信息，包括软硬件版本等
              memset((u_int8_t *)&ptz_update_file_head_inf, 0, sizeof(ptz_update_file_head_inf));
              memcpy((u_int8_t *)&ptz_update_file_head_inf, (u_int8_t *)UPDATE_APP_PKG_HEAD, sizeof(ptz_update_file_head_inf));
              //校验包头，若干片内没有头信息，则为出厂程序，头信息赋初始值
              
              //检查头的checksum
              if(!ptz_update_file_head_checksum_OK(&ptz_update_file_head_inf))
              {
                ptz_update_file_head_inf.hardware_type[0] = HARD_WARE_TYPE_DEFAULT_K;
                ptz_update_file_head_inf.hardware_type[1] = HARD_WARE_TYPE_DEFAULT_6;
                ptz_update_file_head_inf.hardware_ver = 1;
                ptz_update_file_head_inf.software_ver = 1;
                ptz_update_file_head_inf.addr = 0x00010000;
              }
              
              
              ptz_send_update_reply(UPDATE_FRAME_TYPE_GET_DEVICE_INFO, (u_int8_t *)&ptz_update_file_head_inf, sizeof(ptz_update_file_head_inf));
              break;
              
            case UPDATE_FRAME_TYPE_RESET_DEVICE:       //0X03 设备复位
              ptz_hori_stop(0);
              ptz_vert_stop(0);
              count = sprintf(info_str, "OK");
              ptz_send_update_reply(UPDATE_FRAME_TYPE_RESET_DEVICE, info_str, count);
              OSTimeDlyHMSM(0u, 0u, 0u, 10u);
              GD32_RESET();
              break;
              
            case UPDATE_FRAME_TYPE_BOOT_APP:           //0X04 要求设备载入应用（直接复位）
              ptz_hori_stop(0);
              ptz_vert_stop(0);
              count = sprintf(info_str, "OK");
              ptz_send_update_reply(UPDATE_FRAME_TYPE_BOOT_APP, info_str, count);
              OSTimeDlyHMSM(0u, 0u, 0u, 10u);
              GD32_RESET();
              break;
              
            case UPDATE_FRAME_TYPE_UPGRADE_REQ:        //0X05 升级设备请求，数据内容是一个upgrade_request结构
              memset(&request_info, 0, sizeof(request_info));
              update_bit_map_count = 0; //总共有多少bit,每一位bit存储每一帧接收的状态
              update_byte_map_count = 0;//总共有多少个byte，存储所有帧接收的状态要用多少个字节
              //提取升级文件头
              memcpy(&request_info, update_frame->data, sizeof(request_info));
              //判断存储每一个帧的状态需要多少位BIT，多少个字节BYTE
              if(!ptz_update_init_frame_bit_map(request_info.frame_count))
              {
                count = sprintf(info_str, "准备接收数据出错(init_frame_bit_map)！");
                ptz_send_update_reply(UPDATE_FRAME_TYPE_ERROR, info_str, count);
                break;
              }
              //判断升级数据包是否超出设定的片外FLASH存储的大小
              if(!ptz_update_erase_flash_buff(request_info.total_len))
              {
                count = sprintf(info_str, "准备接收数据出错(erase_upgrad_flash_buff)！");
                ptz_send_update_reply(UPDATE_FRAME_TYPE_ERROR, info_str, count);
                break;
              }
              update_state = UPDATE_STATE_UPGRADE_DATA_TRANS;
              ptz_send_update_reply(UPDATE_FRAME_TYPE_UPGRADE_REQ, &request_info, sizeof(request_info));
              break;
              
            case UPDATE_FRAME_TYPE_UPGRADE_DATE:       //0X06 升级设备数据，数据内容是一个upgrade_frame结构
              update_data = (UpdateData*)update_frame->data;
              if(update_state != UPDATE_STATE_UPGRADE_DATA_TRANS)
              {
                count = sprintf(info_str, "设备未进入接收状态，请先发送升级请求包！");
                ptz_send_update_reply(UPDATE_FRAME_TYPE_ERROR, info_str, count);
                break;
              }
              if(!ptz_update_write_frame_to_flash_buff(&request_info, update_data))
              {
                count = sprintf(info_str, "升级数据写入失败！");
                ptz_send_update_reply(UPDATE_FRAME_TYPE_ERROR, info_str, count);
                break;
              }
              if(!ptz_update_set_frame_bit_map(update_data->index))
              {
                count = sprintf(info_str, "升级帧状态保存总数溢出");
                ptz_send_update_reply(UPDATE_FRAME_TYPE_ERROR, info_str, count);
                break;
              }
              break;
              
            case UPDATE_FRAME_TYPE_UPGRADE_FINISH:     //0X07 升级设备结束，SRV->Device数据内容空
              if(update_state != UPDATE_STATE_UPGRADE_DATA_TRANS)
              {
                count = sprintf(info_str, "设备未进入接收状态，请先发送升级请求包！");
                ptz_send_update_reply(UPDATE_FRAME_TYPE_ERROR, info_str, count);
                break;
              }
              //判断哪些帧接收失败
              if(!ptz_update_get_upgrade_retrans_table(&request_info, update_retrans_table, MAX_RETRANS_TABLE_LEN))
              {
                count = sprintf(info_str, "准备重传数据出错！");
                ptz_send_update_reply(UPDATE_FRAME_TYPE_ERROR, info_str, count);
                update_state = UPDATE_STATE_IDEL;
                break;
              }
              //判断是否需要重传
              if(update_retrans_table->count > 0)
              {
                ptz_send_update_reply(UPDATE_FRAME_TYPE_UPGRADE_FINISH, update_retrans_table, UPDATE_RETRANS_TABLE_SIZE(update_retrans_table));
                update_state = UPDATE_STATE_UPGRADE_DATA_TRANS;
                break;
              }
              //校验升级包文件 
              if(!ptz_update_flash_buff_file_crc_OK(request_info.total_len))
              {
                count = sprintf(info_str, "升级包CRC校验失败！");
                ptz_send_update_reply(UPDATE_FRAME_TYPE_ERROR, info_str, count);
                update_state = UPDATE_STATE_IDEL;
                break;
              }
              //将bootloader存入单片机内部的RAM
              if(request_info.file_head.file_type == UPDATE_FILE_TYPE_BOOT_LOADER)
              {
//                if(!ptz_update_burn_bootloader(request_info.total_len))
//                {
//                   count = sprintf(info_str, "升级失败!!!！");
//                   ptz_send_update_reply(UPDATE_FRAME_TYPE_ERROR, info_str, count);
//                   update_state = UPDATE_STATE_IDEL;
//                   break;
//                }
                ptz_send_update_reply(UPDATE_FRAME_TYPE_UPGRADE_FINISH, update_retrans_table, UPDATE_RETRANS_TABLE_SIZE(update_retrans_table));
                update_state = UPDATE_STATE_IDEL;
                break;
              }
              //其他文件升级，包含应用程序，配置文件等
              if(request_info.file_head.file_type != UPDATE_FILE_TYPE_BOOT_LOADER)
              {
//                if(!ptz_update_program_file(request_info.total_len))
//                {
//                   count = sprintf(info_str, "升级包失败!!!！");
//                   ptz_send_update_reply(UPDATE_FRAME_TYPE_ERROR, info_str, count);
//                   update_state = UPDATE_STATE_IDEL;
//                   break;
//                }
                ptz_send_update_reply(UPDATE_FRAME_TYPE_UPGRADE_FINISH, update_retrans_table, UPDATE_RETRANS_TABLE_SIZE(update_retrans_table));
                update_state = UPDATE_STATE_IDEL;
              }
              break;
          }
        }

      }

    }
#endif
   
    //初始化指定升级服务端的IP和端口
    if(ptz_update_communicaton == PTZ_CONNECT_STATE_SUCCESS) 
    {
      if(update_active_connect_switch == 0)
      {
        //初始化指定升级服务端的IP和端口
        ptz_update_serv_a.sin_family = PF_INET;
        ptz_update_serv_a.sin_port = htons(PTZ_UPDATE_SERV_PORT_A);
        ptz_update_serv_a.sin_addr.s_addr = inet_addr(PTZ_UPDATE_SERV_IP_A);
        ptz_update_servlen_a = sizeof(ptz_update_serv_a);

        ptz_update_serv_b.sin_family = PF_INET;
        ptz_update_serv_b.sin_port = htons(PTZ_UPDATE_SERV_PORT_A);
        ptz_update_serv_b.sin_addr.s_addr = inet_addr(PTZ_UPDATE_SERV_IP_B);
        ptz_update_servlen_b = sizeof(ptz_update_serv_b);

        ptz_update_serv_c.sin_family = PF_INET;
        ptz_update_serv_c.sin_port = htons(PTZ_UPDATE_SERV_PORT_B);
        ptz_update_serv_c.sin_addr.s_addr = inet_addr(PTZ_UPDATE_SERV_IP_A);
        ptz_update_servlen_c = sizeof(ptz_update_serv_c);

        ptz_update_serv_d.sin_family = PF_INET;
        ptz_update_serv_d.sin_port = htons(PTZ_UPDATE_SERV_PORT_B);
        ptz_update_serv_d.sin_addr.s_addr = inet_addr(PTZ_UPDATE_SERV_IP_B);
        ptz_update_servlen_d = sizeof(ptz_update_serv_d);
        update_active_connect_timer = 0;//发送间隔时间清0
        update_active_connect_switch = 1;//初始化完成后默认打开发送心跳包
      }
    }
    
    //判断是否需要发送心跳包
    if(update_active_connect_switch != 0)
    {//首先发送的端口和通道要完成初始化
      if(update_state == UPDATE_STATE_UPGRADE_DATA_TRANS)
      {
        update_active_connect_switch = 2;//关闭心跳包发送
      }
      else//update_state == UPDATE_STATE_IDEL || update_state == UPDATE_STATE_DEAD
      {
        update_active_connect_switch = 1;//打开心跳包发送
      }
    }
     //主动发送升级心跳包
    if(ptz_update_communicaton == PTZ_CONNECT_STATE_SUCCESS) 
    {  
      if(update_active_connect_switch == 1)
      {
        if(kh == 0)
        {//一旦进入应用程序先发送2包升级心跳包
          kh = 1;
          ptz_send_update_heartbeat();//发送升级心跳包
          OSTimeDlyHMSM(0u, 0u, 1u, 0u);
          ptz_send_update_heartbeat();//发送升级心跳包
        }
        
        
        update_active_connect_timer = update_active_connect_timer + 2;//改时间根据任务挂起时间计算
        if(update_active_connect_timer >= 30000)//30S发一次
        {
          update_active_connect_timer = 0;
          ptz_send_update_heartbeat();//发送升级心跳包
        }
      }
    }
    OSTimeDlyHMSM(0u, 0u, 0u, 2u);
  }
}


static OS_STK  task_update_rece_data_stk[TASK_PTZ_UPDATE_RECE_DATA_STK_SIZE];
static  void  creat_task_update_rece_data(void)
{ 
   CPU_INT08U  task_err;   
   CPU_INT08U  name_err;
   
   task_err = OSTaskCreateExt((void (*)(void *)) ptz_update_rece_data_task,           
		   (void           *) 0,
		   (OS_STK         *)&task_update_rece_data_stk[TASK_PTZ_UPDATE_RECE_DATA_STK_SIZE - 1],
		   (INT8U           ) TASK_PTZ_UPDATE_RECE_DATA_PRIO,                   
		   (INT16U          ) TASK_PTZ_UPDATE_RECE_DATA_PRIO,
		   (OS_STK         *)&task_update_rece_data_stk[0],
		   (INT32U          ) TASK_PTZ_UPDATE_RECE_DATA_STK_SIZE,
		   (void           *) 0,
		   (INT16U          )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));     
    #if (OS_TASK_NAME_EN > 0)
    OSTaskNameSet(TASK_PTZ_UPDATE_RECE_DATA_PRIO, "ptz_update_rece_data_task", &name_err);
    #endif
       
    if ((task_err == OS_ERR_NONE) && (name_err == OS_ERR_NONE)) {
        pdebug(DEBUG_LEVEL_INFO,"create ptz_update_rece_data_task  success...\n\r");
	} else { 
        pdebug(DEBUG_LEVEL_FATAL,"create ptz_update_rece_data_task  failed...\n\r");
	}
}



static OS_STK  task_update_data_process_stk[TASK_PTZ_UPDATE_DATA_PROCESS_STK_SIZE];
static  void  creat_task_update_data_process(void)
{ 
   CPU_INT08U  task_err;   
   CPU_INT08U  name_err;
   
   task_err = OSTaskCreateExt((void (*)(void *)) ptz_update_data_process_task,           
		   (void           *) 0,
		   (OS_STK         *)&task_update_data_process_stk[TASK_PTZ_UPDATE_DATA_PROCESS_STK_SIZE - 1],
		   (INT8U           ) TASK_PTZ_UPDATE_DATA_PROCESS_PRIO,                   
		   (INT16U          ) TASK_PTZ_UPDATE_DATA_PROCESS_PRIO,
		   (OS_STK         *)&task_update_data_process_stk[0],
		   (INT32U          ) TASK_PTZ_UPDATE_DATA_PROCESS_STK_SIZE,
		   (void           *) 0,
		   (INT16U          )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));     
    #if (OS_TASK_NAME_EN > 0)
    OSTaskNameSet(TASK_PTZ_UPDATE_DATA_PROCESS_PRIO, "ptz_update_data_process_task", &name_err);
    #endif
       
    if ((task_err == OS_ERR_NONE) && (name_err == OS_ERR_NONE)) {
        pdebug(DEBUG_LEVEL_INFO,"create ptz_update_data_process_task  success...\n\r");
	} else { 
        pdebug(DEBUG_LEVEL_FATAL,"create ptz_update_data_process_task  failed...\n\r");
	}
}


void init_update_module()
{
  creat_task_update_rece_data();
  creat_task_update_data_process();
}

/*****************************/









