/******************************************************************
** Copyright (c) 2009  Wuhan Mozit Technology Co., Ltd .
** FileName:	core.c
** Author:	 	BigHead
** Mail:		jsrenyw@icloud.com
** Editor:		bighead
** Date:		2020-11-10 13:34
** Version: 	2020-11-10
** File Description:  业务逻辑核心代码实现部分
******************************************************************/
#include "core.h"

#include "cmd.h"

//指令发送表device_command:
#define CTR_RRS 1 //远程重启
#define CTR_SFR 2 //设备恢复出厂设置
#define CTR_RS  3 //服务器跳转
#define CTR_OTA 4 //ota升级
#define CTR_RDC 5 //远程手动调光
#define CTR_RSC 6 //远程开关控制 需回复
#define CTR_RCN 7 //删除子节点指令 需回复
#define CFG_BKS 8 //备份服务器配置 需回复
#define CFG_ULI 9 //设备数据上传间隔配置 需回复
#define CFG_STS 10 //开关时间段设置 需回复
#define CFG_SRV 11 //额定电压设置 需回复
#define CFG_SRC 12 //额定电流设置 需回复
#define CFG_NAT 13 //下发节点信息表配置
#define CFG_GNV 14 //获取子节点版本号
#define CFG_SCM 15 //开关控制模式(拉合闸)设置 需回复
#define CFG_DGS 16 //调光节点分组设置
#define CFG_DGM 17 //调光节点分组数据修改
#define CFG_MGM 18 //电表节点分组设置 需回复
#define CFG_SAT 19 //传感器报警阀值设置 需回复
#define CTR_RGC 20 //远程开关编组控制 需回复

//继电器状态:
#define SW_ON                           0     //0x0000：继电器合闸
#define SW_MANUAL_CONTROL               32    //0x0020：继电器远程拉闸
#define SW_TIMER_CONTROL                16    //0x0010: 继电器自动时间段拉闸
#define SW_TEMPERATURE_HUMIDITY_ALARM   513   //0x0201:继电器温湿度报警拉闸 需报警
#define SW_FIRE_ALARM                   514   //0x0202:继电器烟感报警拉闸 需报警
#define SW_TILT_ALARM                   515   //0x0203:继电器倾斜报警拉闸 需报警
#define SW_LOCK_ALARM                   516   //0x0204:继电器锁具报警拉闸 需报警
#define SW_LINE_TEMPERATURE_ALARM       517   //0x0205:继电器线温报警拉闸 需报警
#define SW_OVERVOLTAGE                  1     //0x0001：过压拉闸 需报警
#define SW_UNDERVOLTAGE                 2     //0x0002：欠压拉闸 需报警
#define SW_OVERLOAD_ALARM               4     //0x0004: 过载拉闸 需报警
#define SW_ELECTRIC_EXCESS              8     //0x0008：用电超额拉闸
#define SW_OVER_SWITCH_OUT_COUNT        64    //0x0040：超自动合闸次数
#define SW_FAST_CURRENT                 128   //0x0080：快速电流拉闸

int sw[] = {513,514,515,516,517,1,2,4};

typedef enum {false = 0,true =1} bool;
static pthread_t threads[32];

#define CRC32_POLYNOMIAL 0xEDB88320
list_node* file_list = NULL; //文件链表
list_node* user_list = NULL; //设备链表
int have_table = 0;
static uint32_t crc_table32[256];        //CRC查询表
unsigned short ota_file_packet_len = 1024;//ota文件每包的数据长度
//按照大端模式解析数据
//将1个整型数据填充到缓存中
#define INT_TO_BUFF(buff, pos, val)             \
    buff[(pos)] = (val)&0x000000FF;             \
    buff[(pos) + 1] = ((val)&0x0000FF00) >> 8;  \
    buff[(pos) + 2] = ((val)&0x00FF0000) >> 16; \
    buff[(pos) + 3] = ((val)&0xFF000000) >> 24
//从缓存中提取1个整型数据
#define INT_FROM_BUFF(buff, pos) ((buff[(pos) + 3] << 24) + (buff[(pos) + 2] << 16) + (buff[(pos) + 1] << 8) + buff[(pos)])

//从缓存中提取1个整型数据
#define SHORT_FROM_BUFF(buff, pos) ((buff[(pos) + 1] << 8) + buff[(pos)])


/******************************************************************
 *	Function Name:	db_init
 *	Arguments:
 *	Return Value:	void
 *	Date: 			2020-11-10
 *	Editor:			bighead
 *	Description:	程序启动时刻,调用该初始化函数多次,初始化不同mysql 连接
 ******************************************************************/
int db_init(MYSQL *db)
{
  int ret = 1;

  if (db)
  {
    MYSQL *_db = db;
    ret = mysqlConnetInit(_db) ? 1 : 0;
  }
  else
  {
    elog("MYSQL.var is NULL \n  ");
    exit(0);
  }

  return ret;
}

/******************************************************************
 *	Function Name:	core_init
 *	Arguments:
 *	Return Value:	void
 *	Date: 			2020-11-10
 *	Editor:			bighead
 *	Description:	程序启动时刻,调用该初始化函数仅 一次,该函数不允许重复调用
 ******************************************************************/
int core_init(void)
{
  int ret = 0;

  // 加载Topic服务配置
  initTopicConf();

  //创建队列
  //m_pque = CreateQueue(1000);

  // init mqtt.client
  init_mqtt_client();
  sleep(1);
  
  // 注册Topic
  regTopicFromTable();

  //创建处理任务队列线程
  //if(NUM_THREADS_UPLOAD_g>0)
  //  CreateDbHandThread();

  return ret;
}

/******************************************************************
 *	Function Name:	core_heart
 *	Arguments:
 *	Return Value:	void
 *	Date: 			2020-11-10
 *	Editor:			bighead
 *	Description:  每次主线程心跳调用, 约200ms一次, 可以调整频率在decode.c
 ******************************************************************/
int core_heart(unsigned int nowTime)
{
	int ret=0;
	ret=nowTime;
  return ret;
}

/******************************************************************
 *	Function Name:	core_heart_1s
 *	Arguments:
 *	Return Value:	void
 *	Date: 			2020-11-10
 *	Editor:			bighead
 *	Description:	每次主线程心跳调用, 约1s一次,不超过2s, 在core_heart心跳函数之后调用
 *               可以调整频率在decode.c
 ******************************************************************/
int core_heart_1s(unsigned int nowTime)
{
  int ret = 0;
	ret = nowTime;

  //时间同步广播
  ret = TimeSyncBroadcast();

  //从数据库取指令
  SendCmdFromDb();

  return ret;
}

//初始化时候进行部分测试,可以随意添加
int core_do_test(void)
{
  //decode_msg_handle("TEST", NULL, NULL);
  print_stats();
  return 0;
}

//定期调用会话统计信息, 分钟级别
int core_stats(void)
{
  print_stats();
  return 0;
}

/******************************************************************
 *	Function Name:	core_alarm_gateway
 *	Arguments:
 *	Return Value:	void
 *	Date: 			2023-12-5
 *	Editor:			cc
 *	Description:	扫描网关设备数据
 ******************************************************************/
int CoreAlarmGateway()
{
  static MYSQL *conn = NULL;
  MYSQL_RES* res = NULL;
  MYSQL_ROW row;
  char query[1024] = {0};
  int row_count;

  if (!conn)
  {
      // 先申请内存再初始化
      conn = malloc(sizeof(MYSQL));
      db_init(conn);
  }

  sprintf(query,"SELECT t1.device_mac,t1.gateway_mac,t2.device_name,t2.control_mode,t1.update_time,"
                "t1.current_on_off,t1.current_electric,t1.original_relay,t2.swith_time1,t2.swith_time2,t2.swith_time3,t2.swith_time4,"
                "t2.electric_wave_set,t2.electric_wave_min,t2.electric_wave_max,t1.command_update_time "
                "FROM dev_status AS t1 "
                "INNER JOIN dev_info_gateway AS t2 "
                "ON t1.device_mac = t2.device_mac "
                "WHERE TIMESTAMPDIFF(MINUTE, t1.update_time, NOW()) < 10 "
                "AND t1.current_online=1 "
                "AND t1.original_relay IS NOT NULL "
                "AND t1.current_electric IS NOT NULL "
                "AND t1.electric_update_flag=1 ");
  excuteSql(conn,query);
  res = mysql_store_result(conn);
  if (NULL == res)
  {
      debug("NULL == res \n");
      return 1;
  }
  //获取行数
  row_count = mysql_num_rows(res);
  if(row_count<1)
  {
      mysql_free_result(res);
      debug("row_count<1 \n");
      return 1;
  }
  debug("CoreAlarmGateway row_count:%d \r\n",row_count);

  //循环取出
  while((row = mysql_fetch_row(res)))
  {
    char device_mac[30] = {0};          //0节点
    char gateway_mac[30] = {0};         //1网关
    char device_name[256] = {0};        //2设备名称
    int  control_mode = 0;              //3控制模式
    char update_time[20];               //4更新时间
    int  current_on_off = 0;            //5开关状态
    int  current_electric = 0;          //6电流
    int  original_relay = 0;            //7原始开关值
    char switch_time1[10] = {0};        //8开关时间1
    char switch_time2[10] = {0};        //9开关时间2
    char switch_time3[10] = {0};        //10开关时间3
    char switch_time4[10] = {0};        //11开关时间4
    int  electric_wave_set = 0;         //12电流波峰值
    double  electric_wave_min = 0.0;    //13电流波峰值
    double  electric_wave_max = 0.0;    //14电流波峰值
    char command_update_time[20];       //15指令更新时间

    struct tm tm_time;
    struct tm tm_time2;
    char timeString[20];
    int result,result1,result2,result3,result4;
    char update_sql[100]={0};
    char strTemp[256] ={0};

    //取出数据
    strcpy(device_mac,row[0]);
    strcpy(gateway_mac,row[1]);
    strcpy(device_name,row[2]);
    control_mode = atoi(row[3]);
    strptime(row[4], "%Y-%m-%d %H:%M:%S", &tm_time);
    strftime(update_time, sizeof(update_time), "%Y-%m-%d %H:%M:%S", &tm_time);
    current_on_off = atoi(row[5]);
    current_electric = atoi(row[6]);
    original_relay = atoi(row[7]);
    if(row[8]) strcpy(switch_time1,row[8]);
    if(row[9]) strcpy(switch_time2,row[9]);
    if(row[10]) strcpy(switch_time3,row[10]);
    if(row[11]) strcpy(switch_time4,row[11]);
    if(row[12]) electric_wave_set = atoi(row[12]);
    if(row[13]) electric_wave_min = atof(row[13]);
    if(row[14]) electric_wave_max = atof(row[14]);
    if(row[15]) strptime(row[15], "%Y-%m-%d %H:%M:%S", &tm_time2);
    strftime(command_update_time, sizeof(command_update_time), "%Y-%m-%d %H:%M:%S", &tm_time2);
    
    // log("CoreAlarmGateway : device_mac:'%s',gateway_mac:'%s',device_name:%s,control_mode:%d,update_time:%s,current_on_off:%d,"
    //       "current_electric:%d,original_relay:%d,switch_time1:%s,switch_time2:%s,switch_time3:%s,switch_time4:%s,"
    //       "electric_wave_set:%d,electric_wave_min:%f,electric_wave_max:%f \n",
    //       device_mac,gateway_mac,device_name,control_mode,update_time,current_on_off,current_electric,original_relay,
    //       switch_time1,switch_time2,switch_time3,switch_time4,electric_wave_set,electric_wave_min,electric_wave_max);

    //更新数据取出标记
    sprintf(update_sql,"update dev_status set electric_update_flag=2 where device_mac='%s' and gateway_mac='%s' ",device_mac,gateway_mac);
    excuteSql(conn,update_sql);

     //判断继电器数据
     result = RelayAlarm(gateway_mac,"0F0000000001",original_relay,conn);
     if(result==0) continue;

     //判断更新的数据是否在指令下发的2minute内
     if(row[15])
     {
        tm_time2.tm_min +=2; //将指令更新时间加2分钟
        mktime(&tm_time2);//重新计算时间
        int result = compareModifiedTimes(tm_time2,tm_time);
        if(result>=0)//指令更新时间在2分钟内跳过后续判断
        {
          debug("网关:%s,compareModifiedTimes tm_time2>=tm_time\n",device_name);
          continue;
        }
     }

     if(!row[8] && !row[9]) continue;
     strftime(timeString, sizeof(timeString), "%H:%M", &tm_time);
     debug("timeString:%s \n",timeString);
     //判断自动模式
     if(control_mode==0)
     {
        if(compareTimes(switch_time1,switch_time2)<=0)//switch_time1<switch_time2
        {
          debug("网关:%s,compareTimes switch_time1<switch_time2\n",device_name);
          result1 = compareTimes(switch_time1,timeString);
          result2 = compareTimes(timeString,switch_time2);
          debug("result1:%d,result2:%d \n",result1,result1);
          //合闸时间段继电器拉闸
          if (result1<=0 && result2<=0)
          {
            if(current_on_off==0)
            {
              debug("网关:%s,合闸时间段继电器拉闸 \n",device_name);
              int ret=ElectricAlarm(gateway_mac,"0F0000000001",device_name,device_name,1101,"合闸时间段继电器拉闸",conn);
              if(ret==0) continue;
            }
          }
          //拉闸时间段继电器合闸
          else
          {
            if(current_on_off==1)
            {
              debug("网关:%s,拉闸时间段继电器合闸 \n",device_name);
              int ret=ElectricAlarm(gateway_mac,"0F0000000001",device_name,device_name,1102,"拉闸时间段继电器合闸",conn);
              if(ret==0) continue;
            }
          }
        }
        else
        {
          debug("网关:%s,compareTimes switch_time1>switch_time2\n",device_name);
          result1 = compareTimes(switch_time1,timeString);
          result2 = compareTimes(timeString,switch_time2);
          debug("result1:%d,result2:%d \n",result1,result1);
          //合闸时间段
          if (result1<=0 || result2<=0)
          {
            debug("网关:%s,在合闸时间段 \n",device_name);
            if(current_on_off==0)
            {
              debug("网关:%s,合闸时间段继电器拉闸 \n",device_name);
              int ret=ElectricAlarm(gateway_mac,"0F0000000001",device_name,device_name,1101,"合闸时间段继电器拉闸",conn);
              if(ret==0) continue;
            }
          }
          //拉闸时间段
          else
          {
            debug("网关:%s,在拉闸时间段\n",device_name);
            if(current_on_off==1)
            {
              debug("网关:%s,拉闸时间段继电器合闸 \n",device_name);
              int ret=ElectricAlarm(gateway_mac,"0F0000000001",device_name,device_name,1102,"拉闸时间段继电器合闸",conn);
              if(ret==0) continue;
            }
          }
        }
        
     }

     //判断继电器拉闸状态有电流
     if(current_on_off==0 && current_electric>100)
     {
       debug("网关:%s,继电器拉闸状态有电流 \n",device_name);
       int ret=ElectricAlarm(gateway_mac,"0F0000000001",device_name,device_name,1103,"继电器拉闸状态有电流",conn);
       if(ret==0) continue;
     }

     //判断继电器合闸状态无电流
     if(current_on_off==1 && current_electric<100)
     {
       debug("网关:%s,继电器合闸状态无电流 \n",device_name);
       int ret=ElectricAlarm(gateway_mac,"0F0000000001",device_name,device_name,1104,"继电器合闸状态无电流",conn);
       if(ret==0) continue;
     }

     //判断继电器合闸状态电流偏离正常阈值
     if(current_on_off==1 && electric_wave_set==3)
     {
        double fcurrent_electric = current_electric/10000.0;
        if(fcurrent_electric<(electric_wave_min*0.9)|| fcurrent_electric>(electric_wave_max*1.1))
        {
          debug("网关:%s,继电器合闸状态电流偏离正常值 \n",device_name);
          sprintf(strTemp,"继电器合闸状态电流偏离正常值,当前值:%.3f,阈值:%.3f-%.3f",fcurrent_electric,electric_wave_min,electric_wave_max);
          int ret=ElectricAlarm(gateway_mac,"0F0000000001",device_name,device_name,1105,strTemp,conn);
          if(ret==0) continue;
        }
     }
  }
     mysql_free_result(res);
  
  return 0;
}

/******************************************************************
 *	Function Name:	core_alarm_gateway
 *	Arguments:
 *	Return Value:	void
 *	Date: 			2023-12-8
 *	Editor:			cc
 *	Description:	扫描节点设备数据
 ******************************************************************/
int CoreAlarmNode()
{
  static MYSQL *conn2 = NULL;
  MYSQL_RES* res = NULL;
  MYSQL_ROW row;
  char query[1024] = {0};
  int row_count;

  if (!conn2)
  {
      // 先申请内存再初始化
      conn2 = malloc(sizeof(MYSQL));
      db_init(conn2);
  }

  sprintf(query,"SELECT t1.device_mac,t1.gateway_mac,t3.device_name,t2.device_name,t2.control_mode,t1.update_time,t1.current_on_off,t1.current_electric,"
                "t1.original_relay,t2.swith_time1,t2.swith_time2,t2.swith_time3,t2.swith_time4,t2.electric_wave_set,t2.electric_wave_min,t2.electric_wave_max,t1.command_update_time "
                "FROM dev_status AS t1 "
                "INNER JOIN dev_info_node AS t2 "
                "ON t1.device_mac = t2.device_mac "
                "AND t1.gateway_mac=t2.gateway_mac "
                "INNER JOIN dev_info_gateway AS t3 "
                "ON t2.gateway_mac = t3.device_mac "
                "WHERE TIMESTAMPDIFF(MINUTE, t1.update_time, NOW()) < 10 "
                "AND t1.current_online=1 "
                "AND t1.original_relay IS NOT NULL "
                "AND t1.current_electric IS NOT NULL "
                "AND t1.electric_update_flag=1 ");
  excuteSql(conn2,query);
  res = mysql_store_result(conn2);
  if (NULL == res)
  {
      debug("NULL == res \n");
      return 1;
  }
  //获取行数
  row_count = mysql_num_rows(res);
  if(row_count<1)
  {
      mysql_free_result(res);
      debug("row_count<1 \n");
      return 1;
  }
  debug("CoreAlarmNode row_count:%d \r\n",row_count);

  //循环取出
  while((row = mysql_fetch_row(res)))
  {
    char device_mac[30] = {0};           //0节点
    char gateway_mac[30] = {0};          //1网关
    char gateway_name[256] = {0};        //2设备名称
    char node_name[256] = {0};           //3节点名称
    int  control_mode = 0;              //4控制模式
    char update_time[20];               //5更新时间
    int  current_on_off = 0;            //6开关状态
    int  current_electric = 0;          //7电流
    int  original_relay = 0;            //8原始开关值
    char switch_time1[10] = {0};        //9开关时间1
    char switch_time2[10] = {0};        //10开关时间2
    char switch_time3[10] = {0};        //11开关时间3
    char switch_time4[10] = {0};        //12开关时间4
    int  electric_wave_set = 0;         //13电流波峰值
    double  electric_wave_min = 0.0;    //14电流波峰值
    double  electric_wave_max = 0.0;    //15电流波峰值

    struct tm tm_time;
    struct tm tm_time2;
    char timeString[20];
    int result,result1,result2,result3,result4;
    char update_sql[100]={0};
    char strTemp[256] ={0};

    //取出数据
    strcpy(device_mac,row[0]);
    strcpy(gateway_mac,row[1]);
    strcpy(gateway_name,row[2]);
    strcpy(node_name,row[3]);
    control_mode = atoi(row[4]);
    strptime(row[5], "%Y-%m-%d %H:%M:%S", &tm_time);
    strftime(update_time, sizeof(update_time), "%Y-%m-%d %H:%M:%S", &tm_time);
    current_on_off = atoi(row[6]);
    current_electric = atoi(row[7]);
    original_relay = atoi(row[8]);
    if(row[9]) strcpy(switch_time1,row[9]);
    if(row[10]) strcpy(switch_time2,row[10]);
    if(row[11]) strcpy(switch_time3,row[11]);
    if(row[12]) strcpy(switch_time4,row[12]);
    if(row[13]) electric_wave_set = atoi(row[13]);
    if(row[14]) electric_wave_min = atof(row[14]);
    if(row[15]) electric_wave_max = atof(row[15]);
    if(row[16]) strptime(row[15], "%Y-%m-%d %H:%M:%S", &tm_time2);
    
    // log("CoreAlarmNode : device_mac:'%s',gateway_mac:'%s',gateway_name:%s,node_name:%s,control_mode:%d,update_time:%s,current_on_off:%d,"
    //       "current_electric:%d,original_relay:%d,switch_time1:%s,switch_time2:%s,switch_time3:%s,switch_time4:%s,"
    //       "electric_wave_set:%d,electric_wave_min:%f,electric_wave_max:%f \n",
    //       device_mac,gateway_mac,gateway_name,node_name,control_mode,update_time,current_on_off,current_electric,original_relay,
    //       switch_time1,switch_time2,switch_time3,switch_time4,electric_wave_set,electric_wave_min,electric_wave_max);

    //更新数据取出标记
    sprintf(update_sql,"update dev_status set electric_update_flag=2 where device_mac='%s' and gateway_mac='%s' ",device_mac,gateway_mac);
    excuteSql(conn2,update_sql);

     //判断继电器数据
     result = RelayAlarm(gateway_mac,device_mac,original_relay,conn2);
     if(result==0) continue;

     //判断更新的数据是否在指令下发的2minute内
     if(row[16])
     {
        tm_time2.tm_min +=2; //将指令更新时间加2分钟
        mktime(&tm_time2);//重新计算时间
        int result = compareModifiedTimes(tm_time2,tm_time);
        if(result>=0)//指令更新时间在2分钟内跳过后续判断
        {
          debug("网关:%s,节点:%s,compareModifiedTimes tm_time2>=tm_time\n",gateway_name,node_name);
          continue;
        }
     }

     if(!row[9] || !row[10] || !row[11] || !row[12]) continue;
     strftime(timeString, sizeof(timeString), "%H:%M", &tm_time);
     debug("timeString:%s \n",timeString);
     //判断自动模式
     if(control_mode==0)
     {
        int isInTime1 = 0;
        int isInTime2 = 0;

        if(row[9]&&row[10]&&(strlen(switch_time1)>4)&&(strlen(switch_time2)>4))//第1个时间段不为空
        {
          debug("网关:%s,节点:%s,strlen(switch_time1)=%d,strlen(switch_time2)=%d\n",gateway_name,node_name,strlen(switch_time1),strlen(switch_time2));
          result1 = compareTimes(switch_time1,timeString);
          result2 = compareTimes(timeString,switch_time2);
          //时间正常顺序
          if(compareTimes(switch_time1,switch_time2)<=0)
          {
            debug("网关:%s,节点:%s,compareTimes switch_time1<=switch_time2\n",gateway_name,node_name);
            //合闸时间段
            if (result1<=0 && result2<=0) isInTime1=1;
          }
          //时间非正常顺序
          else
          {
            debug("网关:%s,节点:%s,compareTimes switch_time1>=switch_time2\n",gateway_name,node_name);
            //合闸时间段
            if (result1<=0 || result2<=0) isInTime1=1;
          }
        }
        else //第1个时间段为空
        {
          isInTime1=2;
        }

        if(row[11]&&row[12]&&(strlen(switch_time3)>4)&&(strlen(switch_time4)>4))//第2个时间段不为空
        {
          debug("网关:%s,节点:%s,strlen(switch_time3)=%d,strlen(switch_time4)=%d\n",gateway_name,node_name,strlen(switch_time3),strlen(switch_time4));
          result3 = compareTimes(switch_time3,timeString);
          result4 = compareTimes(timeString,switch_time4);
          //时间正常顺序
          if(compareTimes(switch_time3,switch_time4)<=0)
          {
            debug("网关:%s,节点:%s,compareTimes switch_time3<=switch_time4\n",gateway_name,node_name);
            //合闸时间段
            if (result3<=0 && result4<=0) isInTime2=1;
          }
          //时间非正常顺序
          else
          {
            debug("网关:%s,节点:%s,compareTimes switch_time3>=switch_time4\n",gateway_name,node_name);
            //合闸时间段
            if (result3<=0 || result4<=0) isInTime2=1;
          }
        }
        else //第1个时间段为空
        {
          isInTime2=2;
        }

        if((isInTime1==1||isInTime2==1) && current_on_off==0)
        {
          debug("网关:%s,节点:%s,合闸时间段继电器拉闸 \n",gateway_name,node_name);
          int ret=ElectricAlarm(gateway_mac,device_mac,gateway_name,node_name,1101,"合闸时间段继电器拉闸",conn2);
          if(ret==0) continue;
        }
        else if((isInTime1==0||isInTime2==0) && current_on_off==1)
        {
          debug("网关:%s,节点:%s,拉闸时间段继电器合闸 \n",gateway_name,node_name);
          int ret=ElectricAlarm(gateway_mac,device_mac,gateway_name,node_name,1102,"拉闸时间段继电器合闸",conn2);
          if(ret==0) continue;
        }
        
     }

     //判断继电器拉闸状态有电流
     if(current_on_off==0 && current_electric>100)
     {
       debug("网关:%s,节点:%s,继电器拉闸状态有电流 \n",gateway_name,node_name);
       int ret=ElectricAlarm(gateway_mac,device_mac,gateway_name,node_name,1103,"继电器拉闸状态有电流",conn2);
       if(ret==0) continue;
     }

     //判断继电器合闸状态无电流
     if(current_on_off==1 && current_electric<100)
     {
       debug("网关:%s,节点:%s,继电器合闸状态无电流 \n",gateway_name,node_name);
       int ret=ElectricAlarm(gateway_mac,device_mac,gateway_name,node_name,1104,"继电器合闸状态无电流",conn2);
       if(ret==0) continue;
     }

     //判断继电器合闸状态电流偏离正常阈值
     if(current_on_off==1 && electric_wave_set==3)
     {
        double fcurrent_electric = current_electric/10000.0;
        if(fcurrent_electric<(electric_wave_min*0.9)|| fcurrent_electric>(electric_wave_max*1.1))
        {
          debug("网关:%s,节点:%s,继电器合闸状态电流偏离正常值 \n",gateway_name,node_name);
          sprintf(strTemp,"继电器合闸状态电流偏离正常值,当前值:%.3f,阈值:%.3f-%.3f",fcurrent_electric,electric_wave_min,electric_wave_max);
          int ret=ElectricAlarm(gateway_mac,device_mac,gateway_name,node_name,1105,strTemp,conn2);
          if(ret==0) continue;
        }
     }
  }
  mysql_free_result(res);
  
  return 0;
}

/******************************************************************
 *	Function Name:	ElectricAlarm
 *	Arguments:
 *	Return Value:	void
 *	Date: 			2023-12-7
 *	Editor:			cc
 *	Description:	电流数据告警判断
 ******************************************************************/
int ElectricAlarm(char* mac,char* subMac,char* gatewayName,char* nodeName,int alarmCode,char* alarmStr,MYSQL* _db)
{
  //判断是否需要报警
  MYSQL_RES* res = NULL;
  MYSQL_ROW row;
  char querySql[256] = {0};
  char strName[256] = {0};
  char strAlarm[512] = {0};
  char updateSql[1024] = {0};
  char insertSql[512] = {0};
  int affectedRows = 0;
  int queryRow = 0;
  int fault_state=0;
  int fault_count=0;
  struct tm tm_time;

  //网关或节点名称
  if (strcmp(subMac,"0F0000000001") == 0)//网关
  {
    sprintf(strName,"设备名称:%s",gatewayName);
  }
  else
  {
    sprintf(strName,"设备名称:%s,节点:%s",gatewayName,nodeName);
  }
  //格式化报警内容
  sprintf(strAlarm,"%s,%s,时间:%s \r\n",strName,alarmStr,GetCurrentTime());
  

  //查询当前报警类型是否正在报警 fault_state 1: 未处理  2: 故障正在处理中  3: 处理完成
  sprintf(querySql,"select fault_state,fault_count,fault_time from dev_fault where device_mac = '%s' and device_mac_node = '%s' and relay_code = %d ",mac,subMac,alarmCode);
  excuteSql(_db,querySql);
  res = mysql_store_result(_db);
  queryRow = mysql_num_rows(res);
  if (res && queryRow>0)//有记录
  {
    debug("res && queryRow>0 querySql:%s\n",querySql);
    row = mysql_fetch_row(res);
    fault_state = atoi(row[0]);
    fault_count = atoi(row[1]);
    if(row[2]) strptime(row[2], "%Y-%m-%d %H:%M:%S", &tm_time);
    debug("fault_state:%d fault_count:%d\n",fault_state,fault_count);

    if(fault_state ==  1 || fault_state == 2)//正在报警
    {
      log("查询到当前报警类型正在报警,不再重复报警,alarmStr:%s\n",strAlarm);
      mysql_free_result(res);
      return 1;
    }

    if(alarmCode>1100)//电流报警进行3次判断
    {
      //在更新次数前检查是否是连续的告警次数,否则重新计数，通过检查上一次告警时间是否在5min以内
      if(row[2])
      {
        tm_time.tm_min +=5; //将指令更新时间加5分钟
        mktime(&tm_time);//重新计算时间
        int result=compareWithCurrentTime(tm_time);
        if(result>=0)//如果在5min以内
        {
          if(fault_count >= 2)//加上本次报警次数达到3次
          {
            //更新到报警故障表
            sprintf(updateSql,"update dev_fault set fault_details = '%s',fault_state = 1,fault_time = now(),fault_count=0 where "
                              "device_mac = '%s' and device_mac_node = '%s' and relay_code = %d",strAlarm,mac,subMac,alarmCode);
            log("触发告警(电流): %s\n",strAlarm);
          }
          else
          {
            fault_count = fault_count + 1;
            //更新报警次数，并不报警
            sprintf(updateSql,"update dev_fault set fault_details = '%s',fault_state = 3,fault_time = now(),fault_count=%d where "
                              "device_mac = '%s' and device_mac_node = '%s' and relay_code = %d",strAlarm,fault_count,mac,subMac,alarmCode);
            debug("网关:%s,节点:%s,电流告警更新次数(不报警)\n",gatewayName,nodeName);
          }
        }
        else//不在5min以内 计数重新开始
        {
          //更新到报警故障表
          sprintf(updateSql,"update dev_fault set fault_details = '%s',fault_state = 3,fault_time = now(),fault_count=1 where "
                            "device_mac = '%s' and device_mac_node = '%s' and relay_code = %d",strAlarm,mac,subMac,alarmCode);
          debug("不在5min以内 计数重新开始(电流): %s\n",strAlarm);
        }
        
      }
      else //没有时间字段 计数重新开始
      {
        //更新到报警故障表
        sprintf(updateSql,"update dev_fault set fault_details = '%s',fault_state = 3,fault_time = now(),fault_count=1 where "
                          "device_mac = '%s' and device_mac_node = '%s' and relay_code = %d",strAlarm,mac,subMac,alarmCode);
        debug("没有时间字段 计数重新开始(电流): %s\n",strAlarm);
      }  
      
    }
    else
    {
      //更新到报警故障表
      sprintf(updateSql,"update dev_fault set fault_details = '%s',fault_state = 1,fault_time = now() where "
                        "device_mac = '%s' and device_mac_node = '%s' and relay_code = %d",strAlarm,mac,subMac,alarmCode);
      log("触发告警: %s\n",strAlarm);
    }
    debug("updateSql: %s\n",updateSql);
    excuteSql(_db,updateSql);
  }
  else//没有查询到记录
  {
    debug("没有记录 querySql:%s",querySql);
    sprintf(insertSql,"insert into dev_fault(device_mac,device_mac_node,fault_details,relay_code,fault_state,fault_time)values('%s','%s','%s',%d,1,now())",
            mac,subMac,strAlarm,alarmCode);
    log("触发告警(插入): %s\n",strAlarm);
    excuteSql(_db,insertSql);
  }
  mysql_free_result(res);

  // //更新到报警故障表
  // sprintf(updateSql,"update dev_fault set fault_details = '%s',fault_state = 1,fault_time = now() where "
  //                   "device_mac = '%s' and device_mac_node = '%s' and relay_code = %d",strAlarm,mac,subMac,alarmCode);
  // excuteSql(_db,updateSql);
  // affectedRows = mysql_affected_rows(_db);
  // if (affectedRows < 1)
  // {
  //   sprintf(insertSql,"insert into dev_fault(device_mac,device_mac_node,fault_details,relay_code,fault_state,fault_time)values('%s','%s','%s',%d,1,now())",
  //           mac,subMac,strAlarm,alarmCode);
  //   //log("strAlarm:%s\n",strAlarm);
  //   excuteSql(_db,insertSql);
  // }

  return 0;
}

//扫描数据库发送指令
int SendCmdFromDb(void)
{
  static MYSQL *_db = NULL;
  MYSQL_RES* res = NULL;
  MYSQL_ROW row;
  char query[1024] = {0};
  char deleteSql[256] = {0};
  char updateSql[256] = {0};
  int row_count;

  if (!_db)
  {
      // 先申请内存再初始化
      _db = malloc(sizeof(MYSQL));
      db_init(_db);
  }

  sprintf(query,"select id,device_mac,device_mac_node,device_command,device_group,device_on_off,"
                "device_luminance,dimming_mode,node_type,control_mode from dev_cmd_send where device_mac is not null and current_online = 1 and device_type < 10");
  excuteSql(_db,query);
  res = mysql_store_result(_db);
  if (NULL == res)
  {
      return 1;
  }
  //获取行数
  row_count = mysql_num_rows(res);
  if(row_count<1)
  {
      //debug("%s 没有查询到指令 \n",mac);
      mysql_free_result(res);
      return 1;
  }
  //循环取出
  while((row = mysql_fetch_row(res)))
  {
    int  id = 0;
    char device_mac[30] = {0};         //网关mac 1
    char device_mac_node[30] = {0};    //节点mac 2
    int  device_command = 0;           //指令类型 3
    int  device_group = 0;             //组号 4
    int  device_on_off = 0;            //开关 5
    int  device_luminance = 0;         //亮度 6
    int  dimming_mode = 0;             //调光类型 7
    int  node_type = 0;                //节点类型 8
    int  control_mode = 0;             //开关控制模式 9

    int ret = 0;

    if(row[0])
      id = atoi(row[0]);

    if(!row[1] ||  strlen((char*)row[1])!=24)
    {
      //删除指令
      sprintf(deleteSql,"delete from dev_cmd_send where id = %d",id);
      excuteSql(_db,deleteSql);
      debug("网关mac不正确!");
      continue;
    }
    strcpy(device_mac,row[1]);

    if(row[2])
      strcpy(device_mac_node,row[2]);

    if(row[3])
      device_command = atoi(row[3]);

    if(row[4])
      device_group = atoi(row[4]);

    if(row[5])
      device_on_off = atoi(row[5]);
      
    if(row[6])
      device_luminance = atoi(row[6]);

    if(row[7])
      dimming_mode = atoi(row[7]);

    if(row[8])
      node_type = atoi(row[8]);

    if(row[9])
      control_mode = atoi(row[9]);
    
    debug("SendCmdFromDb 行数:%d ,device_mac:'%s',device_mac_node:'%s',device_command:%d,device_group:%d,device_on_off:%d,"
            "device_luminance:%d,dimming_mode:%d,node_type:'%d',control_mode:%d  \n",
          row_count,device_mac,device_mac_node,device_command,device_group,device_on_off,device_luminance,dimming_mode,node_type,control_mode);

    //删除指令
    sprintf(deleteSql,"delete from dev_cmd_send where id = %d",id);
    excuteSql(_db,deleteSql);
      

    switch (device_command)
    {
    case CTR_RRS: //远程重启
      {
        ret = SendRestart(device_mac);
      }
      break;
    case CTR_SFR: //设备恢复出厂设置
      {
        ret = SendFactoryReset(device_mac);
      }
      break;
    case CTR_RS: //服务器跳转
      {
        ret = SendServerJump(device_mac,_db);
      }
      break;
    case CTR_OTA: //ota升级
      {
        ret = SendRemoteUpgrade(device_mac,_db);
      }
      break;
    case CTR_RDC: //远程手动调光
      {
        if(row[4] && row[6]) //row[7] 调光类型判断暂去掉
        {
          ret = SendManualDimming(device_mac,device_group,device_luminance,dimming_mode);
        } 
      }
      break;
    case CTR_RSC: //远程开关控制 需回复
      {
        if (row[2] && (strlen(device_mac_node) == 12) && row[5] && row[8]) //节点
        {
          ret = SendSwitchControl(device_mac,device_mac_node,node_type,device_on_off);
          sprintf(updateSql,"update dev_status set command_update_time = now() where gateway_mac = '%s' and device_mac='%s'",device_mac,device_mac_node);
        }
        else if(!row[2] && row[5] && row[8])  //网关
        {
          ret = SendSwitchControl(device_mac,"",node_type,device_on_off);
          sprintf(updateSql,"update dev_status set command_update_time = now() where gateway_mac = '%s' and device_mac='%s'",device_mac,device_mac);
        }
        if(ret == 0)
        {
          excuteSql(_db,updateSql);
        }
      }
      break;
    case CTR_RCN: //删除子节点指令 需回复
      {
        if(row[2] && (strlen(device_mac_node) == 12) && row[8])
        {
          ret = SendDeleteNode(device_mac,device_mac_node,node_type);
        }
      }
      break;
    case CFG_BKS: //备份服务器配置 需回复
      {
        ret = SendBakIP(device_mac,_db);
      }
      break;
    case CFG_ULI: //设备数据上传间隔配置 需回复
      {
        ret = SendDataInterval(device_mac,_db);
      }
      break;
    case CFG_STS: //开关时间段设置 需回复
      {
        if (row[2] && (strlen(device_mac_node) == 12)) //节点
        {
          ret = SendOnOffTimeMuilt(device_mac,device_mac_node,_db);
          sprintf(updateSql,"update dev_status set command_update_time = now() where gateway_mac = '%s' and device_mac='%s'",device_mac,device_mac_node);
        }
        else if(!row[2])  //网关
        {
          ret = SendOnOffTimeMuilt(device_mac,"",_db);
          sprintf(updateSql,"update dev_status set command_update_time = now() where gateway_mac = '%s' and device_mac='%s'",device_mac,device_mac);
        }
        if(ret == 0)
        {
          excuteSql(_db,updateSql);
        }
      }
      break;
    case CFG_SRV: //额定电压设置 需回复
      {
        if (row[2] && (strlen(device_mac_node) == 12)) //节点
        {
          ret = SendRatedVoltage(device_mac,device_mac_node,_db);
        }
        else if(!row[2])  //网关
        {
          ret = SendRatedVoltage(device_mac,"",_db);
        }
      }
      break;
    case CFG_SRC: //额定电流设置 需回复
      {
        if (row[2] && (strlen(device_mac_node) == 12)) //节点
        {
          ret = SendRatedCurrent(device_mac,device_mac_node,_db);
        }
        else if(!row[2])  //网关
        {
          ret = SendRatedCurrent(device_mac,"",_db);
        }
      }
      break;
    case CFG_NAT: //下发节点信息表配置
      {
        ret = SendSubInfo(device_mac,_db);
      }
      break;
    case CFG_GNV: //获取子节点版本号
      {
        if (row[2] && (strlen(device_mac_node) == 12)) //节点
        {
          ret = SendGetSubVersion(device_mac,device_mac_node);
        }
      }
      break;
    case CFG_SCM: //开关控制模式(拉合闸)设置 需回复
      {
        if (row[2] && (strlen(device_mac_node) == 12)) //节点
        {
          ret = SendSwitchModeFromDB(device_mac,device_mac_node,_db);
        }
        else if(!row[2])  //网关
        {
          ret = SendSwitchModeFromDB(device_mac,"",_db);
        }
      }
      break;
    case CFG_DGS: //调光节点分组设置
      {
        if (row[2] && (strlen(device_mac_node) == 12)) //节点
        {
          ret = SendDimmingNodeGroup(device_mac,device_mac_node,_db);
        }
      }
      break;
    case CFG_DGM: //调光节点分组数据修改
      {
        if(row[4])
        {
          ret = SendDimmingNodeGroupModify(device_mac,device_group,_db);
        }
      }
      break;
    case CFG_MGM: //电表节点分组设置 需回复
      {
        
      }
      break;
    case CFG_SAT: //传感器报警阀值设置 需回复
      {
        ret = SendSensorThreshold(device_mac,_db);
      }
      break;
      case CTR_RGC: //远程开关编组控制 需回复
      {
        if(row[4] && row[5])
        {
          ret = SendSwitchGroupControl(device_mac,device_group,2,device_on_off);
        }
      }
      break;
    default:
      debug("指令不能识别:%d",device_command);
      break;
    }
  }

  mysql_free_result(res);

  return 0;
}

//时间同步广播
int TimeSyncBroadcast(void)
{
  //TIME_SYNC_INTERVAL_g 配置文件读取
  if(timeGloble_g%TIME_SYNC_INTERVAL_g==0)
  {
    int ret = 0;
    ret = SendNTP("");
    debug("时间同步广播结果:%d,当前时间同步间隔 %d \n",ret,TIME_SYNC_INTERVAL_g);
  }

  return 0;
}

//1.字节流转换为十六进制字符串
void ByteToHexStr(const unsigned char* source, char* dest, int sourceLen)
{
    short i;
    unsigned char highByte, lowByte;

    for (i = 0; i < sourceLen; i++)
    {
        highByte = source[i] >> 4;
        lowByte = source[i] & 0x0f ;

        highByte += 0x30;

        if (highByte > 0x39)
                dest[i * 2] = highByte + 0x07;
        else
                dest[i * 2] = highByte;

        lowByte += 0x30;
        if (lowByte > 0x39)
            dest[i * 2 + 1] = lowByte + 0x07;
        else
            dest[i * 2 + 1] = lowByte;
    }
    return ;
}

//2.字节流转换为十六进制字符串
void Hex2Str( const char *sSrc,  char *sDest, int nSrcLen )
{
    int  i;
    char szTmp[3];

    for( i = 0; i < nSrcLen; i++ )
    {
        sprintf( szTmp, "%02X", (unsigned char) sSrc[i] );
        memcpy( &sDest[i * 2], szTmp, 2 );
    }
    return ;
}

//十六进制字符串转换为字节流
void HexStrToByte(const char* source, unsigned char* dest, int sourceLen)
{
    short i;
    unsigned char highByte, lowByte;

    for (i = 0; i < sourceLen; i += 2)
    {
        highByte = toupper(source[i]);
        lowByte  = toupper(source[i + 1]);

        if (highByte > 0x39)
            highByte -= 0x37;
        else
            highByte -= 0x30;

        if (lowByte > 0x39)
            lowByte -= 0x37;
        else
            lowByte -= 0x30;

        dest[i / 2] = (highByte << 4) | lowByte;
    }
    return ;
}

//改变字节顺序
void EndianSwap(unsigned char *pData, int startIndex, int length)
{
    int i,cnt,end,start;
    cnt = length / 2;
    start = startIndex;
    end  = startIndex + length - 1;
    unsigned char tmp;
    for (i = 0; i < cnt; i++)
    {
        tmp            = pData[start+i];
        pData[start+i] = pData[end-i];
        pData[end-i]   = tmp;
    }

    return ;
}

//获取当前月份历史表
char* GetCurrentNYTable(void)
{
  time_t t = time(0);
  static char str[64] = {0};
  strftime(str,sizeof(str),"dev_status_history_%Y%m",localtime(&t));
  return str;
}

//获取系统时间年月日 时分秒
char* GetCurrentTime(void)
{
  time_t t = time(0);
  static char str[64] = {0};
  strftime(str,sizeof(str),"%Y%m%d %H:%M:%S",localtime(&t));
  return str;
}

//字符串中查找指定字符的个数
int find_char(char str[], char substr[])
{
    int count = 0,i,j,check;
    int len = strlen(str);
    int sublen = strlen(substr);
    for(i = 0; i < len; i++)
    {
        check = 1;
        for(j = 0; j + i < len && j < sublen; j++)
        {
            if(str[i+j] != substr[j])
            {
                check = 0;
                break;
            }
        }
        if(check == 1)
        {
            count++;
            i = i + sublen;
        }
    }

    return count;
}


//从主题中查找指定'/'分割的段
char* find_string(char* topicName, int section)
{
    static char tmp[50][50];
    memset(tmp,0x0,2500);
    char* p1 = (char*)malloc(1024);
    int i = 0;
    while ((p1 = strchr(topicName, '/')) != NULL)
    {
        strncpy(tmp[i], topicName,strlen(topicName)-strlen(p1));
        topicName = p1 + 1;
         i++;
    }
    strncpy(tmp[i], topicName, strlen(topicName));

    free(p1);
    return tmp[section];
}

//判断是否属于报警code
int IsRelayAlarmCode(int relayCode)
{
  int i = 0;
  for(i = 0;i<(int)(sizeof(sw)/sizeof(int));i++)
  {
    if(relayCode == sw[i])
      return 1;
  }

  return -1;
}

//继电器报警
int RelayAlarm(char* mac,char* subMac,int relayCode,MYSQL* _db)
{
  MYSQL_RES* res = NULL;
  MYSQL_ROW row;
  char querySql[256] = {0};
  char updateSql[256] = {0};
  char insertSql[256] = {0};
  char strAlarm[256] = {0};
  bool isExist = false;
  char strAlarmType[256] = {0};
  char strName[256] = {0};
  char macName[256] = {0};
  char subMacName[256] = {0};
  int affectedRows = 0;
  int queryRow = 0;

  //判断是否需要报警
  int i = 0;
  for(i = 0;i<(int)(sizeof(sw)/sizeof(int));i++)
  {
    if(relayCode == sw[i])
      isExist = true;
  }
  if(!isExist)
    return 1;

  //查询当前报警类型是否正在报警 fault_state 1: 未处理  2: 故障正在处理中  3: 处理完成
  sprintf(querySql,"select * from dev_fault where device_mac = '%s' and device_mac_node = '%s' and relay_code = %d and (fault_state = 1 or fault_state = 2)",mac,subMac,relayCode);
  excuteSql(_db,querySql);
  res = mysql_store_result(_db);
  queryRow = mysql_num_rows(res);
  if (res && queryRow>0)
  {
    //debug("res && queryRow>0 querySql:%s",querySql);
    mysql_free_result(res);
    return 1;
  }
  mysql_free_result(res);

  //查询网关节点名称
  if (strcmp(subMac,"0F0000000001") == 0)//网关
  {
    sprintf(querySql,"select device_name from dev_info_gateway where device_mac = '%s' ",mac);
    excuteSql(_db,querySql);
    res = mysql_store_result(_db);
    if (NULL == res)
    {
      return 1;
    }
    row = mysql_fetch_row(res);
    if (NULL == row)
    {
      mysql_free_result(res);
      return 1;
    }
    
    if(!row[0])
    {
      debug("device_name 为空");
      mysql_free_result(res);
      return 1;
    }
    strcpy(macName,row[0]);
    sprintf(strName,"设备名称:%s",macName);
    mysql_free_result(res);
  }
  else
  {
    sprintf(querySql,"select a.device_name as 'gateway_name',b.device_name as 'node_name' from dev_info_gateway a,dev_info_node b "
                    "where a.device_mac = b.gateway_mac and b.gateway_mac = '%s' and b.device_mac = '%s'",mac,subMac);
    excuteSql(_db,querySql);
    res = mysql_store_result(_db);
    if (NULL == res)
    {
        return 1;
    }
    row = mysql_fetch_row(res);
    if (NULL == row)
    {
        mysql_free_result(res);
        return 1;
    }
    
    if(!row[0] || !row[1])
    {
        debug("gateway_name 或者 node_name 为空 ");
        mysql_free_result(res);
        return 1;
    }
    strcpy(macName,row[0]);
    strcpy(subMacName,row[1]);
    mysql_free_result(res);

    sprintf(strName,"设备:%s,节点:%s",macName,subMacName);
  }
  
  //判断报警类型
  if(relayCode == SW_TEMPERATURE_HUMIDITY_ALARM)
  {
    strcpy(strAlarmType,"温湿度报警拉闸");
  }
  else if(relayCode == SW_FIRE_ALARM)
  {
    strcpy(strAlarmType,"烟感报警拉闸");
  }
  else if(relayCode == SW_TILT_ALARM)
  {
    strcpy(strAlarmType,"倾斜报警拉闸"); 
  }
  else if(relayCode == SW_LOCK_ALARM)
  {
    strcpy(strAlarmType,"锁具报警拉闸");
  }
  else if(relayCode == SW_LINE_TEMPERATURE_ALARM)
  {
    strcpy(strAlarmType,"线温报警拉闸");
  }
  else if(relayCode == SW_OVERVOLTAGE)
  {
    strcpy(strAlarmType,"过压报警拉闸");
  }
  else if(relayCode == SW_UNDERVOLTAGE)
  {
    strcpy(strAlarmType,"欠压报警拉闸");
  }
  else if(relayCode == SW_OVERLOAD_ALARM)
  {
    strcpy(strAlarmType,"过载报警拉闸");
  }
  else if(relayCode == SW_ELECTRIC_EXCESS)
  {
    strcpy(strAlarmType,"用电超额报警拉闸");
  }
  else if(relayCode == SW_OVER_SWITCH_OUT_COUNT)
  {
    strcpy(strAlarmType,"超自动合闸次数报警拉闸");
  }
  else if(relayCode == SW_FAST_CURRENT)
  {
    strcpy(strAlarmType,"快速电流报警拉闸");
  }
  else
  {
    debug("无法识别报警!");
    return 1;
  }
  

  //格式化报警内容
  sprintf(strAlarm,"%s,%s,时间:%s \n",strName,strAlarmType,GetCurrentTime());
  log(strAlarm);
  
  //更新到报警故障表
  sprintf(updateSql,"update dev_fault set fault_details = '%s',fault_state = 1,fault_time = now() where "
                    "device_mac = '%s' and device_mac_node = '%s' and relay_code = %d",strAlarm,mac,subMac,relayCode);
  excuteSql(_db,updateSql);
  affectedRows = mysql_affected_rows(_db);
  if (affectedRows < 1)
  {
    sprintf(insertSql,"insert into dev_fault(device_mac,device_mac_node,fault_details,relay_code,fault_state,fault_time)values('%s','%s','%s',%d,1,now())",
            mac,subMac,strAlarm,relayCode);
    excuteSql(_db,insertSql);
  }
  
  return 0;
}

//比较两个时间字符串的大小
int compareTimes(const char *time1, const char *time2) 
{
    struct tm tm_base, tm_time1, tm_time2;

    // 设置基准日期为当前日期
    time_t current_time = time(NULL);
    localtime_r(&current_time, &tm_base);

    // 解析时间字符串1
    if (strptime(time1, "%H:%M", &tm_time1) == NULL) 
    {
        fprintf(stderr, "Failed to parse time1\n");
        return 0; // or handle the error in an appropriate way
    }

    // 解析时间字符串2
    if (strptime(time2, "%H:%M", &tm_time2) == NULL)
     {
        fprintf(stderr, "Failed to parse time2\n");
        return 0; // or handle the error in an appropriate way
    }

    // 设置日期部分为基准日期的日期部分
    tm_time1.tm_year = tm_base.tm_year;
    tm_time1.tm_mon = tm_base.tm_mon;
    tm_time1.tm_mday = tm_base.tm_mday;

    tm_time2.tm_year = tm_base.tm_year;
    tm_time2.tm_mon = tm_base.tm_mon;
    tm_time2.tm_mday = tm_base.tm_mday;

    // 将 struct tm 结构转换为 time_t 类型
    time_t t1 = mktime(&tm_time1);
    time_t t2 = mktime(&tm_time2);

    // 检查转换是否成功
    if (t1 == -1 || t2 == -1)
    {
        fprintf(stderr, "Failed to convert time to time_t\n");
        return 0; // or handle the error in an appropriate way
    }

    // 比较时间并返回相应的结果
    if (t1 < t2) 
    {
        return -1;
    } else if (t1 > t2) 
    {
        return 1;
    } else 
    {
        return 0;
    }
}

//比较两个时间结构体的的大小
int compareModifiedTimes(struct tm t1, struct tm t2) 
{
    // 将时间结构体转换为秒数
    time_t time1 = mktime(&t1);
    time_t time2 = mktime(&t2);

    // 比较秒数
    if (time1 < time2) {
        return -1;
    } else if (time1 > time2) {
        return 1;
    } else {
        return 0;
    }
}

//比较给定时间和系统当前时间的函数
int compareWithCurrentTime(struct tm t1)
{
  // 获取系统当前时间
    time_t currentTime;
    time(&currentTime);

    // 将给定时间结构体转换为秒数
    time_t givenTime = mktime(&t1);

    // 比较秒数
    if (givenTime < currentTime) {
        return -1;
    } else if (givenTime > currentTime) {
        return 1;
    } else {
        return 0;
    }
}


//将需要处理sql放入队列
void* sendtoqueue(ArrQueue *pQueue,char* stringSql)
{
  ElemType *elememt = (ElemType *)malloc(sizeof(ElemType));
  if(elememt==NULL)
  {
    printf("0 malloc(sizeof(ElemType)) \n");
    exit(0);
  }
  memset(elememt,0,sizeof(ElemType));
  if(strlen(stringSql)>1024)
  {
    printf("stringSql length is too long \n");
    exit(0);
  }
  elememt->len = strlen(stringSql);
  strcpy(elememt->buf,stringSql);
  EnQueue(pQueue,elememt);
  return NULL;
}

//循环从队列中取出数据处理
void* getqueue(void *data)
{
  MYSQL *_db = NULL;
  ElemType *elememt;

  if (!_db)
  {
      // 先申请内存再初始化
      _db = malloc(sizeof(MYSQL));
      db_init(_db);
  }
  
  struct my_thread_info *info = data;
  
  while(1)
  {
    usleep(1000*1);
    DeQueue(m_pque,&elememt);
    if(elememt == NULL)
    {
      printf("elememt == NULL,number:%d\n",info->which);
      continue;
    }

    excuteSql(_db,elememt->buf);
    free(elememt);

    //log("getqueue sql number:%d \n",info->which);
  }

  free(info);
  return NULL;

}

//创建任务线程处理数据库执行
void CreateDbHandThread(void)
{
  int rc;
  long t;
  struct my_thread_info *info;
  sleep(1);
  for (t = 0; t < NUM_THREADS_UPLOAD_g; t++)
  {
    info = malloc(sizeof(struct my_thread_info));
    info->which = t;
    rc = pthread_create(&threads[t], NULL, getqueue, info);
    if (rc) 
    {
      printf("ERROR; return code from pthread_create() is %d\n", rc);
      exit(-1);
    }
    printf("pthread_create() threadid:%lu is started \n",threads[t]);
    sleep(1);
  }
  // for (t = 0; t < NUM_THREADS; t++) 
  // {
  //   pthread_join(threads[t], NULL);
  // }
}

//打印队列状态,队列处理线程状态,10min打印一次
int PrintQueueThreadState(void)
{
  if(timeGloble_g%600 == 0 && NUM_THREADS_UPLOAD_g>0)
  {
    int i = 0;
    char strState[256] = {0};
    int pthread_kill_err;
    memset(strState,0x0,256);
    sprintf(strState,"pid:%d,队列大小:%d",getpid(),GetLength(m_pque));
    for(i=0;i<NUM_THREADS_UPLOAD_g;i++)
    {
      pthread_kill_err = pthread_kill(threads[i],0);
      sprintf(strState,"%s,tid:%lu(%s)",strState,threads[i],(pthread_kill_err==0)?"alive":"death");
    }
    log("%s \n",strState);
  }
  
  return 0;
}

//关于远程升级

//生成CRC查询表
void init_crc32_tab(void)
{
    int32_t i, j;
    uint32_t crc;
    if (have_table)
    {
      return;
    }
    have_table = 1;
    
    for(i = 0; i < 256; i++)
    {
        crc = (uint32_t )i;
        for(j = 0; j < 8; j++)
        {
            if(crc & 0X00000001L)
            {
                crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
            }
            else
            {
                crc = crc >> 1;
            }
        }
        crc_table32[i] = crc;
    }

}

//获得CRC
uint32_t get_crc32(uint32_t crcinit, uint8_t *bs, uint32_t bssize)
{
    uint32_t crc = crcinit ^ 0XFFFFFFFF;
    while(bssize--)
    {
        crc = (crc>>8)^crc_table32[(crc&0XFF)^*bs++];
    }
    return crc ^ 0XFFFFFFFF;
}

//根据mac查询对应升级文件名
char* GetFileNameByMac(list_node* u_list,char* mac)
{
  list_node* list = u_list;

  if(list == NULL) return NULL;
  
  while(list)
  {
    upgrade_user_info* info = (upgrade_user_info*)list->data;
    if(strcmp(info->mac,mac) == 0)
    {
        return info->ota_file_name;
    }
    list = list->next;
  }

  return NULL;
}



//根据文件名和包序号查询分包数据
ota_info* GetOtaInfoByFileName(list_node* f_list,char* filename)
{
  list_node* list = f_list;

  if(list == NULL) return NULL;
  
  while(list)
  {
    ota_info* info = (ota_info*)list->data;
    if(strcmp(info->new_file_name,filename) == 0)
    {
        return info;
    }
    list = list->next;
  }

  return NULL;
}



/******************************************************************
 *	Function Name:	UpgradeFileAddFromDB
 *	Arguments:
 *	Return Value:	void
 *	Date: 			2022-04-02
 *	Editor:			chw
 *	Description:	新增升级文件映射节点
 ******************************************************************/
void UpgradeFileAddFromDB(list_node* f_list,char* filename,MYSQL *_db,int ota_mode)
{
  char logstr[512] = {0};
  unsigned short ota_file_total_packets = 0;
  unsigned int file_length_bytes = 0;
  unsigned int ota_length_bytes = 0;
  list_node* list = f_list;
  ota_info* info = (ota_info*)malloc(sizeof(ota_info));
  memset(info,0x0,sizeof(ota_info));

  ota_info* s = GetOtaInfoByFileName(file_list,filename);
  if(s != NULL)
  {
    log("有文件节点,不新增! \n");
    free(info);
    info = NULL;
    return;
  }

  //读取数据库升级文件
  unsigned char *fp = readfile_from_db(filename,_db,&file_length_bytes);
  if (file_length_bytes <= 0)
  {
    log("%s file_length_bytes <= 0 ! \n",file_length_bytes);
    free(info);
    info = NULL;
    return;
  }

  //计算数据库升级文件crc32校验
  init_crc32_tab();
  uint32_t crc_value = 0;
  if(calc_crc32_from_buff(fp,file_length_bytes,&crc_value) == 0)
  {
    log("crc_value = %x\n",crc_value);
  }

  //全量
  if(ota_mode == 1)
  {
    ota_length_bytes = file_length_bytes;
    memcpy(info->buf,fp,file_length_bytes);
    crc_value = get_crc32(0,info->buf,file_length_bytes);//ota文件crc校验

    info->ota_mode = 1;//模式
    strcpy(info->new_file_name,filename);//新文件名
    info->new_file_len = file_length_bytes;//新文件长度
    info->ota_file_len = file_length_bytes;//升级文件长度
    info->new_file_crc = crc_value;//新文件crc32校验
    info->ota_file_crc = info->new_file_crc;//升级文件crc32校验
    ota_file_total_packets = file_length_bytes/ota_file_packet_len + 1;
    info->ota_file_total_packets = ota_file_total_packets;//升级文件总包数
    info->ota_file_packet_len = ota_file_packet_len;//升级文件每包数据长度
    sprintf(logstr,"新文件名:%s,新文件长度:%d,升级文件长度:%d,升级文件总包数:%d,升级文件每包数据长度:%d,新文件crc32校验:%X,升级文件crc32校验:%X \n",
            info->new_file_name,info->new_file_len,info->ota_file_len,info->ota_file_total_packets,info->ota_file_packet_len,info->new_file_crc,info->ota_file_crc);
    log(logstr);
  }
  //差分
  else
  {
    ota_length_bytes = file_length_bytes;
    memcpy(info->buf,fp,ota_length_bytes);
    crc_value = get_crc32(0,info->buf,ota_length_bytes);//ota文件crc校验

    info->ota_mode = 0;//模式
    memcpy(info->old_file_name,fp,48);//旧文件名
    info->old_file_len = INT_FROM_BUFF(fp,48);//旧文件长度
    info->old_file_crc = INT_FROM_BUFF(fp,52);//旧文件crc32 校验值
    memcpy(info->new_file_name,fp+56,48);//新文件名
    info->new_file_len = INT_FROM_BUFF(fp,104);//新文件的长度
    info->new_file_crc = INT_FROM_BUFF(fp,108);//新文件crc32 校验值
    info->ota_state = (char)0;//升级状态
    info->ota_file_len = ota_length_bytes;//ota 文件的长度
    info->ota_file_crc = crc_value;//ota 文件的crc32校验值
    info->ota_file_total_packets = ota_length_bytes/ota_file_packet_len + 1;//ota文件的总的包数
    info->ota_file_packet_len = ota_file_packet_len;//ota文件每包的数据长度
    log("info->buf 模式:%d,旧文件名:%s,旧文件长度:%d,旧文件crc32:%X,新文件名:%s,新文件的长度:%d,新文件crc32:%X,ota状态:%d,ota文件的长度:%d,"
         "ota文件的crc32:%X,ota文件的总的包数:%d,ota文件每包的数据长度:%d \n", info->ota_mode,info->old_file_name,info->old_file_len,
         info->old_file_crc,info->new_file_name,info->new_file_len,info->new_file_crc,info->ota_state,info->ota_file_len,info->ota_file_crc,
         info->ota_file_total_packets,info->ota_file_packet_len);
  }

  if(fp != NULL)
  {
    free(fp);
    fp = NULL;
  }

  //第一个文件
  if(list == NULL)
  {
    file_list = list_create((void*)info);
    log("当前为文件映射第一个节点 \n");
  }
  //没有文件节点
  else
  {
    list_insert_end(file_list,(void*)info);
    log("没有文件节点,加入! \n");
  }

  return;
}

//数据库查询升级文件名
void GetUpgradeFileFromDB(char *mac,MYSQL *_db,char* filename)
{
  MYSQL_RES* res = NULL;
  MYSQL_ROW row;
  char query[1024] = {0};
  char ota_file[256] = {0};
  int  ota_mode = 0;
  sprintf(query,"select file_name,ota_mode from dev_info_gateway where device_mac ='%s'",mac);
  excuteSql(_db,query);
  res = mysql_store_result(_db);
  if (NULL == res)
  {
      return ;
  }
  row = mysql_fetch_row(res);
  if (NULL == row)
  {
      mysql_free_result(res);
      return ;
  }
  
  if(!row[0] || !row[1])
  {
      log("%s file_name、ota_mode为空 \n",mac);
      mysql_free_result(res);
      return ;
  }
  strcpy(ota_file,row[0]);
  ota_mode = atoi(row[1]);
  strcpy(filename,ota_file);
  mysql_free_result(res);
  
  //log("mac:%s,file_name:%s \n",mac,ota_file);
  return ;
}

/******************************************************************
 *	Function Name:	readfile_from_db
 *	Arguments:
 *	Return Value:	void
 *	Date: 			2022-04-29
 *	Editor:			chw
 *	Description:	从数据库读取升级文件
 ******************************************************************/
unsigned char *readfile_from_db(const char *filename, MYSQL *_db,int *file_length_bytes)
{
  MYSQL_RES* res = NULL;
  MYSQL_ROW row;
  char sql[512] = {0};
  int ret = 0;
  unsigned long *lengths;
  unsigned char* data;
  MYSQL_BIND result;

  MYSQL_STMT* stmt = mysql_stmt_init(_db);
  assert(NULL!=stmt);
  sprintf(sql,"select file_src from dev_upgrade_file where file_name ='%s'",filename);
  ret = mysql_stmt_prepare(stmt, sql, strlen(sql));
  assert(0==ret);
  ret = mysql_stmt_execute(stmt);
  assert(0==ret);

  memset(&result,0x0,sizeof(result));
  unsigned long total_length = 0;
  result.buffer_type = MYSQL_TYPE_LONG_BLOB;
  result.length = &total_length;
  ret = mysql_stmt_bind_result(stmt, &result);
  assert(0==ret);
  ret = mysql_stmt_store_result(stmt);
  assert(0==ret);
  ret = mysql_stmt_fetch(stmt);
  if(total_length <= 0)
  {
    log("total_length <= 0!\n");
    mysql_stmt_close(stmt);
    return NULL;
  }
  unsigned long start = 0;
  //char buf[1024] = {0};
  //lengths = mysql_fetch_lengths(stmt);
  data = (unsigned char*)malloc(total_length);
  *file_length_bytes = total_length;
  if(data == NULL)
  {
    log("malloc data failed!");
    return NULL;
  }
  log("readfile_from_db函数,total_length=%lu\n", total_length);
  while (start<(int)total_length)
  {
    result.buffer = (data+start);
    if(total_length < 1024)
    {
      result.buffer_length = total_length;
    }
    else if((start+1024) < total_length)
    {
      result.buffer_length = 1024;
    }
    else
    {
      result.buffer_length = total_length % 1024;
    }
    
    ret = mysql_stmt_fetch_column(stmt, &result, 0, start);
    if (ret!=0)
    {
      log("code=%d, msg=%s", (int)mysql_errno(_db), mysql_error(_db));
      free(data);
      mysql_stmt_close(stmt);
      return NULL;
    }
    start += result.buffer_length;
  }
  //log("%.*s\n", total_length, data);
  //free(data);
  mysql_stmt_close(stmt);
  return data;
}

/******************************************************************
 *	Function Name:	获取缓存中的crc32
 *	Arguments:
 *	Return Value:	void
 *	Date: 			2022-04-29
 *	Editor:			chw
 *	Description:	获取缓存中的crc32
 ******************************************************************/
int32_t calc_crc32_from_buff(const char *buff,int len, uint32_t *uiCrcValue)
{
  const uint32_t size = 2*1024;
  uint32_t crc = 0;  // CRC初始值为0
  int remain = len; //剩余未计算长度
  int index = 0;
  while(remain>0)
  {
    if(remain > size)
    {
      crc = get_crc32(crc, buff + index, size);
      index += size;
      remain = remain-size;
    }
    else
    {
      crc = get_crc32(crc, buff + index, remain);
      index += remain;
      remain = 0;
    }
    
  }
  *uiCrcValue = crc;
  return 0;
}

#ifdef UPGRADE_BY_FILE
//获取文件长度
int GetFileLength(char* file_path)
{
  FILE* pFile = fopen(file_path,"r");
  if(pFile == NULL)
  {
    return -1;
  }
  fseek(pFile,0,SEEK_END);
  unsigned int file_length_bytes = ftell(pFile);
  fclose(pFile);
	pFile = NULL;

  return file_length_bytes;
}

//获得文件CRC
int32_t calc_file_crc32(const char *pFileName, uint32_t *uiCrcValue)
{
    if(!pFileName || !uiCrcValue)
    {
        log("bad parameter\n");
        return -1;
    }
    if(access(pFileName, F_OK|R_OK)!=0)
    {
        log("file not exist or reading file has not permission\n");
        return -1;
    }
    const uint32_t size = 2*1024;
    uint8_t crcbuf[size];
    uint32_t rdlen;
    uint32_t crc = 0;  // CRC初始值为0

    FILE *fd = NULL;
    if((fd = fopen(pFileName, "r"))==NULL)
    {
        log("to do crc 32 check, open file error\n");
        return -1;
    }
    while((rdlen=fread(crcbuf, sizeof(uint8_t), size, fd))>0)
    {
        crc = get_crc32(crc, crcbuf, rdlen);
    }
    log("calc_file_crc32:%X \n",crc);
    *uiCrcValue = crc;
    fclose(fd);
    return 0;
}

//读取文件
// unsigned char *read_myfile(const char *path, int *file_size)
// {
//     if(!path||!file_size)
//     {
//         log("bad parameter\n");
//         return NULL;
//     }
//     //access
//     if(access(path, F_OK|R_OK))
//     {
//         log("access test file error\n");
//         return NULL;
//     }
//     //read file
//     struct stat calib_stat;
//     int ret = stat(path, &calib_stat);
//     if(ret!=0)
//     {
//         log("File error\n");
//         return NULL;
//     }
//     FILE *fd = fopen(path, "r");
//     if(NULL == fd)
//     {
//         log("Open test file error\n");
//         return NULL;
//     }
//     unsigned char *buffer = malloc(calib_stat.st_size);
//     if(!buffer)
//     {
//         log("malloc error\n");
//         fclose(fd);
//         return NULL;
//     }

//     memset(buffer, 0, calib_stat.st_size);
//     int totalSize = 0, readed = 0;
//     while((readed = fread(buffer + totalSize,1, 1024,fd)) > 0)
//     {
//         totalSize += readed;
//     }
//     *file_size = totalSize;
//     fclose(fd);
//     return buffer;
// }

// //增加用户
// void UpgradeUserAdd(list_node* u_list,char* mac,char* file_name)
// {
//   list_node* list = u_list;
//   upgrade_user_info* info = (upgrade_user_info*)malloc(sizeof(upgrade_user_info));
//   strcpy(info->mac,mac);
//   strcpy(info->ota_file_name,file_name);

//   //第一个用户
//   if(list == NULL)
//   {
//     user_list = list_create((void*)info);
//   }
//   else
//   {
//     //没查询到用户
//     if(GetFileNameByMac(u_list,mac) == NULL)
//     {
//       list_insert_end(u_list,(void*)info);
//     }
//     //查询到用户,修改
//     else
//     {
//       while(list)
//       {
//         upgrade_user_info* old_info = (upgrade_user_info*)list->data;
//         if(strcmp(old_info->mac,mac) == 0)
//         {
//             list->data = (void*)info;
//             free(old_info);
//             old_info = NULL;
//             break;
//         }
//         list = list->next;
//       }
//     }
//   }

//   return;
// }

// //新增升级文件映射节点
// void UpgradeFileAdd(list_node* f_list,char* filename,int ota_mode)
// {
//   char file_path[256];
//   char logstr[512];
//   unsigned short ota_file_total_packets = 0;
//   unsigned int file_length_bytes = 0;
//   unsigned int ota_length_bytes = 0;
//   list_node* list = f_list;
//   ota_info* info = (ota_info*)malloc(sizeof(ota_info));
//   memset(info,0x0,sizeof(ota_info));

//   sprintf(file_path,"/home/cao/ota/%s",filename);

//   //计算文件crc32校验
//   init_crc32_tab();
//   uint32_t crc_value = 0;
//   if(calc_file_crc32(file_path, &crc_value) == 0)
//   {
//     log("file_path:%s,crc_value = %x\n", file_path,crc_value);
//   }

//   //读取文件
//   unsigned char *fp = read_myfile(file_path,(int*)&file_length_bytes);
//   if (file_length_bytes <= 0)
//   {
//     log("%s file_length_bytes <= 0 ! \n",file_path);
//     free(info);
//     info = NULL;
//     return;
//   }
//   //全量
//   if(ota_mode == 1)
//   {
//     ota_length_bytes = file_length_bytes;
//     memcpy(info->buf,fp,file_length_bytes);
//     crc_value = get_crc32(0,info->buf,file_length_bytes);//ota文件crc校验

//     info->ota_mode = 1;//模式
//     strcpy(info->new_file_name,filename);//新文件名
//     info->new_file_len = file_length_bytes;//新文件长度
//     info->ota_file_len = file_length_bytes;//升级文件长度
//     info->new_file_crc = crc_value;//新文件crc32校验
//     info->ota_file_crc = info->new_file_crc;//升级文件crc32校验
//     ota_file_total_packets = file_length_bytes/ota_file_packet_len + 1;
//     info->ota_file_total_packets = ota_file_total_packets;//升级文件总包数
//     info->ota_file_packet_len = ota_file_packet_len;//升级文件每包数据长度
//     sprintf(logstr,"新文件名:%s,新文件长度:%d,升级文件长度:%d,升级文件总包数:%d,升级文件每包数据长度:%d,新文件crc32校验:%X,升级文件crc32校验:%X \n",
//             info->new_file_name,info->new_file_len,info->ota_file_len,info->ota_file_total_packets,info->ota_file_packet_len,info->new_file_crc,info->ota_file_crc);
//     log(logstr);
//   }
//   //差分
//   else
//   {
//     ota_length_bytes = file_length_bytes-130;
//     memcpy(info->buf,fp+130,ota_length_bytes);
//     //crc_value = get_crc32(0,info->buf,file_length_bytes-130);//ota文件crc校验

//     info->ota_mode = 0;//模式
//     memcpy(info->old_file_name,fp+1,48);//旧文件名
//     info->old_file_len = INT_FROM_BUFF(fp,49);//旧文件长度
//     info->old_file_crc = INT_FROM_BUFF(fp,53);//旧文件crc32 校验值
//     memcpy(info->new_file_name,fp+58,48);//新文件名
//     info->new_file_len = INT_FROM_BUFF(fp,105);//新文件的长度
//     info->new_file_crc = INT_FROM_BUFF(fp,109);//新文件crc32 校验值
//     info->ota_state = (char)*(fp+113);//ota 状态
//     info->ota_file_len = INT_FROM_BUFF(fp,114);//ota 文件的长度
//     info->ota_file_crc = INT_FROM_BUFF(fp,118);//ota 文件的crc32校验值
//     info->ota_file_total_packets = SHORT_FROM_BUFF(fp,122);//ota文件的总的包数
//     info->ota_file_packet_len = SHORT_FROM_BUFF(fp,124);//ota文件每包的数据长度
//     info->boot_addr = INT_FROM_BUFF(fp,126);//app 程序的启动地址
//     log("info->buf 模式:%d,旧文件名:%s,旧文件长度:%d,旧文件crc32:%X,新文件名:%s,新文件的长度:%d,新文件crc32:%X,ota状态:%d,ota文件的长度:%d,"
//          "ota文件的crc32:%X,ota文件的总的包数:%d,ota文件每包的数据长度:%d,app程序的启动地址:%X \n", info->ota_mode,info->old_file_name,info->old_file_len,
//          info->old_file_crc,info->new_file_name,info->new_file_len,info->new_file_crc,info->ota_state,info->ota_file_len,info->ota_file_crc,
//          info->ota_file_total_packets,info->ota_file_packet_len,info->boot_addr);
//   }
//   //log("info->buf crc = %x ,file_length_bytes = %d,ota_length_bytes = %d \n", crc_value,file_length_bytes,ota_length_bytes);
//   if(fp != NULL)
//   {
//     free(fp);
//   }
  
//   //第一个文件
//   if(list == NULL)
//   {
//     file_list = list_create((void*)info);
//     log("当前为文件映射第一个节点 \n");
//   }
//   else
//   {
//     ota_info* s = GetOtaInfoByFileName(file_list,filename);
//     if(s == NULL)
//     {
//       list_insert_end(file_list,(void*)info);
//       log("没有文件节点,加入! \n");
//     }
//     else
//     {
//       log("有文件节点,不新增! \n");
//     }
    
//   }
//   return;
// }
#endif