
//----------------------------------------------------
// Copyright (c) 2018, Djyos Open source Development team. All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------
// Copyright (c) 2018，著作权由都江堰操作系统开源开发团队所有。著作权人保留一切权利。
//
// 这份授权条款，在使用者符合下列条件的情形下，授予使用者使用及再散播本
// 软件包装原始码及二进位可执行形式的权利，无论此包装是否经改作皆然：
//
// 1. 对于本软件源代码的再散播，必须保留上述的版权宣告、本条件列表，以
//    及下述的免责声明。
// 2. 对于本套件二进位可执行形式的再散播，必须连带以文件以及／或者其他附
//    于散播包装中的媒介方式，重制上述之版权宣告、本条件列表，以及下述
//    的免责声明。

// 免责声明：本软件是本软件版权持有人以及贡献者以现状（"as is"）提供，
// 本软件包装不负任何明示或默示之担保责任，包括但不限于就适售性以及特定目
// 的的适用性为默示性担保。版权持有人及本软件之贡献者，无论任何条件、
// 无论成因或任何责任主义、无论此责任为因合约关系、无过失责任主义或因非违
// 约之侵权（包括过失或其他原因等）而起，对于任何因使用本软件包装所产生的
// 任何直接性、间接性、偶发性、特殊性、惩罚性或任何结果的损害（包括但不限
// 于替代商品或劳务之购用、使用损失、资料损失、利益损失、业务中断等等），
// 不负任何责任，即在该种使用已获事前告知可能会造成此类损害的情形下亦然。
//-----------------------------------------------------------------------------
/*
 * app_main.c
 *
 *  Created on: 2014-5-28
 *      Author: Administrator
 */
#include "stdio.h"
#include "stdint.h"
#include "stddef.h"
#include <dbug.h>
#include <djyos.h>
#include <mb.h>
#include <mb_m.h>
#include <shell.h>
#include "cJSON.h"
#include "Modbus_PCS.h"
#include "mongoose.h"
#include "Iboot_info.h"
#include <math.h>
#include "stdint.h"
#include <netbsp.h> //include/net/
#include "ntp.h"
#include "regex.h"
#include "BMSDaRen.h"
#include "OtherMessage.h"
#include "string.h"
#include <pthread.h>
#include <main.h>
#define DEBUG_CLIENT_ID     ("1001")


// DTU返回给服务器的消息最大长度，（没有明文规定，后续有规定的话要修改）
#define CMD_RET_MESSAGE_DATA_MAX_LEN    (512)

const u8 *RetMessageSet[] = 
{
    "success",                    //成功
    "cmd invalid",                //不支持该指令
    "param error",                //payload参数错误
    "dtu port not exist",         //deviceId不存在
    "device not exist",           //deviceId对应设备不存在
    "device not support cmd",     //deviceId对应设备不支持该指令
    "power off",                  //deviceId对应设备未上电
    "time out",                   //deviceID对应设备未返回数据
    "modbus:",                     //dtu发生modbus错误
    "data parse err"              //DTU收到设备回复报文，但报文解析错误
};


// bool_t reset = false; //用于判断是否初始化mongoose，但是初始化成功不代表连接建立成功
static bool_t LinkStatu = false;  //用与判断mongoos是否连上服务器，因为不论mg_connect(&Mgr, s_address, ev_handler)的成功或者失败都会进入回调函数
bool_t DHCP_SetIp = true;
u32 DHCP_IP = 0xffffffff;
static int exit_flag = 0;
int BreaktimeA = 0, BreaktimeB; //断线时间

static char s_address[] = "tcp://111.230.7.154:1883";
static char s_user_name[] = "dtu";            //账号
static char s_password[] = "2023@dd";         //密码
static char client_id[8];                     //客户端ID
static char client2server_topic[64];           //dtu订阅服务器的主题名
static char server2client_topic[64];           //服务器订阅dtu的主题名
static bool_t LinkStart = true;

#define DTU_APP_VERSION_LEN     10
#define CMD_REG_MESSAGE     "{\"cmd\":\"reg\",\"payload\":{\"softVersion\":\"%s\",\"gps\":{\"longitude\":111.00,"\
                        "\"latitude\":111.00},\"deviceSN\":\"%s\",\"dtuStatus\":1,\"device\":{\"bms\":["\
                        "{\"deviceSN\":\"234\",\"deviceId\":\"1_2_1\",\"productType\":1,\"protocolVersion\""\
                        ":\"23\",\"deviceManufacturer\":2,\"hardwareVersion\":\"23\",\"deviceStatus\":0}],\"pcs"\
                        "\":[{\"deviceSN\":\"234\",\"deviceId\":\"1_1_1\",\"productType\":2,\"protocolVersion\":"\
                        " \"123\",\"deviceManufacturer\": 4,\"hardwareVersion\":\"123\",\"deviceStatus\":0}]},"\
                        "\"regTime\":\"2001-8-25\"}}"
#define CMD_REG_MESSAGE_LEN   (strlen(CMD_REG_MESSAGE)+strlen(client_id)+DTU_APP_VERSION_LEN)       
#define CFG_MG_MESSAGE_ID_NUM    100
#define CFG_PROTOCOL_DEV_ID_LEN  128            //设备ID最长长度
#define CFG_PROTOCOL_CMD_LEN  128               //CMD最长长度
static int ServerMsgID = 0;
static u8 ServerDevID[CFG_PROTOCOL_DEV_ID_LEN];  //TODO：后续如果id长度超过128，要修改
static u8 ServerCMD[CFG_PROTOCOL_DEV_ID_LEN];  //TODO：后续如果cmd长度超过128，要修改
static int ServerPortType = -1;              //根据设备ID，得到的接口类型
static int ServerNum = -1;                   //根据设备ID，得到的物理排序
static int ServerAddr = -1;                  //根据设备ID，得到的modbus地址
int id = 0;


//id，0不能用，所以加1，用1到CFG_MG_MESSAGE_ID_NUM范围
static u8 MgMessageID[CFG_MG_MESSAGE_ID_NUM + 1];  

int GetServerMessageID(void)
{
    return ServerMsgID;
}

u8 *GetServerCurrCMD(void)
{
    return ServerCMD;
}

u8 *GetServerDevID(void)
{
    return ServerDevID;
}

int GetServerPortType(void)
{
    return ServerPortType;
}

int GetServerNum(void)
{
    return ServerNum;
}

int GetServerAddr(void)
{
    return ServerAddr;
}

void MgMessageID_Init(void)
{
    // 0表示此ID空闲
    memset(MgMessageID, 0, sizeof(MgMessageID));
}

// 返回0，表示获取ID失败
u16 GetIdleMgMessageID(void)
{
    u16 i = 0;
    for (i = 1; i <= CFG_MG_MESSAGE_ID_NUM; i++)
    {
        if (0 == MgMessageID[i])
        {
            MgMessageID[i] = 1;
            break;
        }
    }
    if (i > CFG_MG_MESSAGE_ID_NUM)
    {
        i = 0;
    }
    return i;
}

bool_t FreeMgMessageID(u16 ID)
{
    if (ID > CFG_MG_MESSAGE_ID_NUM)
    {
        error_printf("Link", "free error message id (%d)\r\n", ID);
        return false;
    }
    MgMessageID[ID] = 0;
    return true;
}

u8 *GetErrorRetMessage(enum eRetMessageSet ID)
{
    if (ID >= sizeof(RetMessageSet))
    {
        return NULL;
    }

    return RetMessageSet[ID];
}

//用于区分特殊命令
bool_t sub_analyze(char *sub, struct mg_connection *nc)
{
    char ErrBackMessage[CMD_RET_MESSAGE_DATA_MAX_LEN];
    enum eRetMessageSet ErrID = DTU_RET_SUCCESS;
    char *OtherErrMsg = NULL;
    char json_data[50];
    cJSON * json = NULL;
    cJSON * json_member = NULL;
    cJSON * json_cmd = NULL;
    char DTU_version[10];
    char *msg_back;
    u16 MgMessageID = 0;
    u32 i = 0;
    

    if ((NULL == sub) || (NULL == nc))
    {
        error_printf("Analysis", "param error\n");
        OtherErrMsg = "sub_analyze sub or nc NULL";
        ErrID = DTU_RET_OTHER_ERR;
    }

    json = cJSON_Parse(sub);
    if (json == NULL)
    {
        error_printf("Analysis", "json parse fail\n");
        OtherErrMsg = "sub_analyze json parse fail";
        ErrID = DTU_RET_OTHER_ERR;
    }
    else
    {
        json_member = cJSON_GetObjectItem(json, "msgId");
        if (json_member != NULL)
        {
            ServerMsgID = json_member->valueint;
        }
        json_cmd = cJSON_GetObjectItem(json, "cmd"); //取到cmd
        if (json_cmd == NULL)
        {
            error_printf("Analysis", "cmd is NULL\n");
        }
        else
        {
            json_member = cJSON_GetObjectItem(json, "payload");    //取到消息里面的payload
            if (NULL == json_member)
            {
                error_printf("Analysis", "get payload fail\n");
                ErrID = DTU_RET_PARAM_ERR;
            }
            else
            {
                strncpy(ServerCMD, json_cmd->valuestring, sizeof(ServerCMD));
                ServerCMD[sizeof(ServerCMD) - 1] = '\0';
                if (strcmp(ServerCMD, "updateNotice") == 0) //代表着收到了新版本可以更新的消息只要是新版本就直接更新
                {
                    json_member = cJSON_GetObjectItem(json_member, "version"); //取到version_json里面的version
                    if (NULL == json_member)
                    {
                        error_printf("Analysis", "get version fail\n");
                        ErrID = DTU_RET_PARAM_ERR;
                    }
                    else
                    {
                        Iboot_GetProductInfo(APP_HEAD_VERSION_NUM, DTU_version, 10); //取现在的版本号
                        if (strcmp(DTU_version, json_member->valuestring) != 0)
                        {
                            MgMessageID = GetIdleMgMessageID();
                            if (MgMessageID > 0)
                            {
                                sprintf(json_data, "{\"cmd\":\"update\",\"payload\":{\"version\":\"%s\"}}", json_member->valuestring);
                                mg_mqtt_publish(nc, server2client_topic, MgMessageID, MG_MQTT_QOS(1), json_data, strlen(json_data)); // DTU发布更新消息
                                //将新版本号添加到消息体里面
                            }
                            else
                            {
                                error_printf("Analysis", "get MgMessageID fail\n");
                                OtherErrMsg = "sub_analyze get MgMessageID fail";
                                ErrID = DTU_RET_OTHER_ERR;
                            }
                        }
                        else
                        {
                            debug_printf("Analysis", "latest version\r\n");
                        }
                    }
                }
                else if (strcmp(ServerCMD, "update") == 0)
                {

                }
                else
                {
                    json_member = cJSON_GetObjectItem(json_member, "deviceId");
                    if (json_member == NULL)
                    {
                        error_printf("Analysis", "get deviceId fail\n");
                        ErrID = DTU_RET_PARAM_ERR;
                        // 查DTU设备的信息,暂时没有先不处理
                    }
                    else
                    {
                        strncpy(ServerDevID, json_member->valuestring, sizeof(ServerDevID));
                        ServerDevID[sizeof(ServerDevID) - 1] = '\0';

                        if (ServerDevID[i] >= '0' && ServerDevID[i] <= '9')
                        {
                            ServerPortType = 0;
                            while (ServerDevID[i] >= '0' && ServerDevID[i] <= '9')
                            {
                                ServerPortType *= 10;
                                ServerPortType += ServerDevID[i ++] - '0';
                            }
                        }
                        if (ServerDevID[i++] == '_')
                        {

                            if (ServerDevID[i] >= '0' && ServerDevID[i] <= '9')
                            {
                                ServerNum = 0;
                                while (ServerDevID[i] >= '0' && ServerDevID[i] <= '9')
                                {
                                    ServerNum *= 10;
                                    ServerNum += ServerDevID[i ++] - '0';
                                }
                            }
                            if (ServerDevID[i++] == '_')
                            {
                                if (ServerDevID[i] >= '0' && ServerDevID[i] <= '9')
                                {
                                    ServerAddr = 0;
                                    while (ServerDevID[i] >= '0' && ServerDevID[i] <= '9')
                                    {
                                        ServerAddr *= 10;
                                        ServerAddr += ServerDevID[i ++] - '0';
                                    }
                                }
                            }
                        }

                        if ((ServerPortType != -1) && (ServerNum != -1) && (ServerAddr != -1))
                        {
                            if (strcmp(ServerDevID, "1_1_1") == 0)
                            {
                                msg_back = QMqtt(json);

                                printf("\n\r%s\n\r",msg_back);

                                if (msg_back == NULL)
                                {
                                    ErrID = GetPCS_ErrorCode();
                                    OtherErrMsg = GetPCS_ErrorLog();
                                }

                            }
                            else if (strcmp(ServerDevID, "1_2_1") == 0)
                            {
                                msg_back = QYDT_1363(sub);

                                printf("\n\r%s\n\r",msg_back);

                                if (msg_back == NULL)
                                {
                                    ErrID = GetPCS_ErrorCode();
                                    // OtherErrMsg = GetBMS_ErrorLog;
                                }
                            }

                            if (msg_back != NULL)
                            {
                                // char *msg_back = "{\"payload\":{\"code\":0,\"data\":{\"chargePower\":0,\"packVoltage\":\"47.9\",\"packSOC\":53,\"packCurrent\":\"1.1\",\"pvCurrent\":\"0.0\",\"chargeStatus\":\"Chgarge_off\",\"pvVoltage\":\"0.0\",\"pvPower\":0},\"message\":\"NoErr\",\"deviceId\":\"1_1_1\"},\"msgId\":1,\"cmd\":\"query_PCS_ControllerData\"}";
                                // printf("%s\n", msg_back);
                                //审核 检查下列代码是否在返回前完成数据发送
                                MgMessageID = GetIdleMgMessageID();
                                if (MgMessageID > 0)
                                {
                                    mg_mqtt_publish(nc, server2client_topic, MgMessageID, MG_MQTT_QOS(1), msg_back, strlen(msg_back));
                                }
                                else
                                {
                                    error_printf("Analysis", "get MgMessageID fail\n");
                                    OtherErrMsg = "sub_analyze get MgMessageID fail";
                                    ErrID = DTU_RET_OTHER_ERR;
                                }
                                free(msg_back);
                            }
                        }
                        else
                        {
                            error_printf("Analysis", "deviceId is error, %s\n", ServerDevID);
                            ErrID = DTU_RET_PORT_NOT_EXIST;
                        }
                        
                    }
                }
            }
    }
    if (ErrID != DTU_RET_SUCCESS)
        {
            if ((ErrID != DTU_RET_OTHER_ERR) && (ErrID != DTU_RET_MODBUS))
            {
                OtherErrMsg = &RetMessageSet[ErrID];
            }
            if (ServerMsgID == 0)
            {
                if (ServerDevID[0] != 0)
                {
                    sprintf(ErrBackMessage, 
                        "{\"cmd\": \"%s\",\"payload\": {\"code\": %s,\"message\": \"%s\",\"deviceId\": \"%s\"}}", 
                        ServerCMD, ErrID, OtherErrMsg, ServerDevID);
                }
                else
                {
                    sprintf(ErrBackMessage, 
                        "{\"cmd\": \"%s\",\"payload\": {\"code\": %s,\"message\": \"%s\"}}", 
                        ServerCMD, ErrID, OtherErrMsg);
                }
            }
            else
            {
                if (ServerDevID[0] != 0)
                {
                    sprintf(ErrBackMessage, 
                        "{\"cmd\": \"%s\",\"msgId\":%d,\"payload\": {\"code\": %s,\"message\": \"%s\",\"deviceId\": \"%s\"}}", 
                        ServerCMD, ServerMsgID, ErrID, OtherErrMsg, ServerDevID);
                }
                else
                {
                    sprintf(ErrBackMessage, 
                        "{\"cmd\": \"%s\",\"msgId\":%d,\"payload\": {\"code\": %s,\"message\": \"%s\"}}", 
                        ServerCMD, ServerMsgID, ErrID, OtherErrMsg);
                }
            }
            MgMessageID = GetIdleMgMessageID();
            if (MgMessageID > 0)
            {
                mg_mqtt_publish(nc, server2client_topic, MgMessageID, MG_MQTT_QOS(1), ErrBackMessage, strlen(ErrBackMessage));
            }
            else
            {
                error_printf("Analysis", "get MgMessageID fail\n");
            }
        }
    }
    memset(ServerDevID, 0, sizeof(ServerDevID));
    memset(ServerCMD, 0, sizeof(ServerCMD));
    ServerMsgID = 0;
    ServerAddr = -1;
    ServerNum = -1;
    ServerPortType = -1;
    cJSON_Delete(json);
    if (ErrID)
    {
        return false;
    }

    return true;
}

static void ev_handler2(struct mg_connection *c, int ev, void *p)
{
    struct http_message *hm = (struct http_message *)p;
    if (ev == MG_EV_HTTP_REPLY)
    {
        c->flags |= MG_F_CLOSE_IMMEDIATELY;
        FILE *pFile;
        pFile = fopen("/fat/hzgj_dtu_App_Debug.bin", "ab");
        fwrite(hm->body.p, hm->body.len, 1, pFile);
        fclose(pFile);
        printk("Write:/fat/hzgj_dtu_App_Debug.bin:%d\r\n", hm->body.len);
        exit_flag = 1;
    }
    else if (ev == MG_EV_CLOSE)
    {
        printk("HTTP:MG_EV_CLOSE\r\n");
        // exit_flag = 1;
    };
}



static void ev_handler(struct mg_connection *nc, int ev, void *p)
{
    struct mg_mqtt_message *msg = (struct mg_mqtt_message *)p;
    static s64 LastPingRespTime = 0;
    (void)nc;

    if ((NULL == nc) || (NULL == msg))
    {
        error_printf("Link", "param error\n");
        return ;
    }

    // if (ev != MG_EV_POLL)
    // {
    //     printk("\r\n<<<< mqtt_handler >>>>\r\n");
    //     printk("\r\nUSER HANDLER GOT EVENT %d\r\n", ev);
    // }

    if (ev == MG_EV_MQTT_PINGRESP)//心跳响应
    {
        s64 CurrPingRespTime = DJY_GetSysTime() / 1000; //获取时间
        //计算差值
        debug_printf("Link", "Difference %lld\r\n", CurrPingRespTime - LastPingRespTime);
        LastPingRespTime = CurrPingRespTime;
    }

    switch (ev)
    {
        case MG_EV_CONNECT:
        {
            struct mg_send_mqtt_handshake_opts opts;
            memset(&opts, 0, sizeof(opts));
            opts.user_name = s_user_name;
            opts.password = s_password;
            opts.will_message = "{\"cmd\": \"3S251ZzRajIrmxkER9tE-offline\"}"; //遗嘱消息
            opts.flags = MG_MQTT_CLEAN_SESSION;
            opts.keep_alive = 60;
            mg_set_protocol_mqtt(nc);
            mg_send_mqtt_handshake_opt(nc, client_id, opts);
            break;
        }
        case MG_EV_MQTT_CONNACK:
        {
            if (msg->connack_ret_code != MG_EV_MQTT_CONNACK_ACCEPTED)
            {
                error_printf("Link", "Got mqtt connection error: %d\n", msg->connack_ret_code);
                LinkStart = true;           //连接失败，关闭网络连接，再重新连接
            }
            else
            {
                struct mg_mqtt_topic_expression sub_topic_expr;
                // 订阅主题固定用CFG_MG_MESSAGE_ID_NUM + 1做ID
                // 下面MG_EV_MQTT_SUBACK好判断
                sub_topic_expr.topic = client2server_topic;
                sub_topic_expr.qos = 1;
                mg_mqtt_subscribe(nc, &sub_topic_expr, sizeof(sub_topic_expr) 
                        / sizeof(struct mg_mqtt_topic_expression), CFG_MG_MESSAGE_ID_NUM + 1); //连接成功后订阅主题
                // mg_mqtt_subscribe(nc, &server2client_topic, 1, 23);//连接成功后订阅主题
                LinkStatu = true;
            }
            break;
        }
        case MG_EV_MQTT_PUBACK:
        {
            if (false == FreeMgMessageID(msg->message_id))
            {
                error_printf("Link", "Message publishing acknowledged (msg_id: %d)\r\n", msg->message_id);
            }
            break;
        }
        case MG_EV_MQTT_SUBACK: //再确认订阅里面发布上线消息
        {
            if (CFG_MG_MESSAGE_ID_NUM + 1 == msg->message_id)
            {
                char version[DTU_APP_VERSION_LEN];
                char *json_data = "{\"cmd\":\"online\"}";
                char RegistrationMessage[CMD_REG_MESSAGE_LEN];
                u16 PubID = 0;
                debug_printf("Link", "Subscription acknowledged, forwarding to '%s' succes\r\n", msg->topic.p);
                //收到订阅确认消息后立马上报设备在线
                PubID = GetIdleMgMessageID();
                if (PubID > 0)
                {
                    mg_mqtt_publish(nc, server2client_topic, PubID, MG_MQTT_QOS(1), json_data, strlen(json_data)); 
                    Iboot_GetProductInfo(APP_HEAD_VERSION_NUM, version, DTU_APP_VERSION_LEN); //取现在的版本号
                    // printk("Version number %s\r\n", version);                //打印现在的版本号
                    PubID = GetIdleMgMessageID();
                    if (PubID > 0)
                    {
                        memset(RegistrationMessage, 0, sizeof(RegistrationMessage));
                        sprintf(RegistrationMessage, CMD_REG_MESSAGE, client_id, version);
                        //上线后立马注册，暂时先不去检测
                        mg_mqtt_publish(nc, server2client_topic, GetIdleMgMessageID(), MG_MQTT_QOS(1), RegistrationMessage, strlen(RegistrationMessage)); 
                    }
                    else
                    {
                        error_printf("Link", "get message id fail\r\n");
                    }
                }
                else
                {
                    error_printf("Link", "get message id fail\r\n");
                }
            }
            else
            {   //message_id不对
                debug_printf("Link", "Subscription acknowledged, message_id is '%d' succes\r\n", msg->message_id);
            }
            break;
        }
        case MG_EV_MQTT_PUBLISH:
        {
    #if 0
            char hex[1024] = {0};m,n,m,
            mg_hexdump(nc->recv_mbuf.buf, msg->payload.len, hex, sizeof(hex));
            printk("Got incoming message %.*s:\n%s", (int)msg->topic.len, msg->topic.p, hex);
    #else
            //打印出收到的消息和来自那个主题
            debug_printf("Link","Got incoming message %s: %s\r\n", msg->topic.p, msg->payload.p);
            mg_mqtt_puback(nc, msg->message_id); //报文要自己发布mongoose本身不自带这个功能就挺恶心
            if ((msg->message_id != id) && (strncmp(msg->topic.p, "dd_platform/cn/1001", msg->topic.len) == 0))
            {
                sub_analyze(msg->payload.p, nc);
                /*            char *msg_back= "{\"cmd\":\"test\"}";
                            mg_mqtt_publish(nc, server2client_topic, 7, MG_MQTT_QOS(1), msg_back,strlen(msg_back));*/
                id = msg->message_id;
            }
    #endif
            break;
        }
        case MG_EV_CLOSE:
        {
            debug_printf("Link", "mqtt close\r\n");
            //这里掉线之所以不释放资源是因为暂时设定为mongoose一直在线不会存在掉线
            // struct in_addr Addr;
            // bool_t test = false;
            // test = NetDev_GetDefaultIP(EN_IPV_4, &Addr);

            // internet_state = false; //查看网络
            // char *test_website = "baidu.com";
            // internet_state = PING(test_website);
            // u8 *networkstate;
            // u8 *write_data ;
            // if (internet_state)
            // {
            //     printf("With network\r\n");
            //     networkstate = "\nWith_network";
            // }
            // else
            // {
            //     printf("No network\r\n");
            //     networkstate = "\nNo_network";

            // }

            // int test_heap = M_GetFreeMem(); //查看内存
            // printf("heap %d\r\n", test_heap);

            // char num_str[20]={0};
            // char *heap_log = malloc(40);
            // sprintf(num_str, "%d", test_heap);
            // heap_log[strlen(heap_log)-1] = '\0';
            // sprintf(heap_log,"\nheap ");
            // strcat(heap_log, num_str);

            // FILE *fp = fopen("/fat/Djy_TopKitchen1001.txt", "a+"); //
            // size_t networkstate_num = fwrite(networkstate, 1, strlen(networkstate), fp);
            // size_t arr = fwrite(heap_log,1, strlen(heap_log), fp); // 使用每个元素的大小和元素数量作为参数

            // fclose(fp);
            // free(heap_log);
            LinkStart = false;
            break;
        }
    }
}
ptu32_t djy_main(void)
{
    struct mg_mgr Mgr;
    struct in_addr Addr;
     bool_t test = false;
    int WaitLinkNum = 0;
    memset(ServerCMD,  0, sizeof(ServerCMD));
    memset(ServerDevID,  0, sizeof(ServerDevID));
    memset(&Mgr, 0, sizeof(Mgr));
    MgMessageID_Init();
    memset(client_id, 0, sizeof(client_id));
    memset(client2server_topic, 0, sizeof(client2server_topic));
    memset(server2client_topic, 0, sizeof(server2client_topic));
    strncpy(client_id, DEBUG_CLIENT_ID, sizeof(client_id));
    sprintf(client2server_topic, "dd_platform/cn/%s", DEBUG_CLIENT_ID);
    sprintf(server2client_topic, "dd_dtu/cn/%s", DEBUG_CLIENT_ID);
    while (1)
    {
        if (GetDTU_ResetFlag())//重启DTU
        {
            runapp("1");
        }
        if (LinkStart)
        {
            //第一次运行这里时，因为Mgr里都是0，所以mg_mgr_free中并不会执行什么
            // 后来的每次重连都要关闭之前的连接
            mg_mgr_free(&Mgr);
            mg_mgr_init(&Mgr, NULL); //初始化
            if (mg_connect(&Mgr, s_address, ev_handler) == NULL)
            {
                error_printf("Link", "mg_connect(%s) failed\r\n", s_address);
            }
            else
            {
                //不为null后启动mongoose
                debug_printf("Link", "mg_connect(%s) succes\r\n");
                LinkStatu = false;
                LinkStart = false;
                WaitLinkNum = 0;
            }
        }
        else
        {
            mg_mgr_poll(&Mgr, 1500);
            if (false == LinkStatu)
            {
                error_printf("Link", "mongoose client falie.\r\n");
                if (WaitLinkNum++ > 10) //连接次数达到20次后基本不可能存在在连接上的可能了，所以要重新初始化
                {
                    //因为mongoose一直连不上服务器，所以重新初始化
                    LinkStart = true;
                }
            }

            u32 freeheap=M_GetFreeMem();//代买没有完全测试完成，为了应对测试所写，后续必定删除
            if(freeheap<90000)
            {
                LinkStart=true;
            }

        }
        DJY_EventDelay(1000 * 1000);
    }
    return 0;
}



static bool_t start_update(char *Param)
{
    u8 week[4] = "2319";
    u8 Serial[5] = "12abc";
    u8 path[30] = "/fat/hzgj_dtu_App_Debug.bin";
    path[27] = 0;
    Iboot_SetWeek(week);                      //设置生成时间
    Iboot_SetSerial(Serial);                  //设置生存序号
    Iboot_SetOtaUserInfo(path, sizeof(path)); //设置升级用的信息
    Iboot_SetUpdateSource(0);                 //设置升级方式
    Iboot_SetAfterUpdateRunMode(1);           //设置升级完后运行app
    Iboot_SetRunIbootAndUpdateApp(1);         //设置去升级
    runiboot("1");                            //复位
    return (TRUE);
}

void http(char *sub) // http 所有操作全是在网络通畅的基础上进行的，没做错误处理
{
    int i;
    cJSON *version_json = cJSON_GetObjectItem(cJSON_Parse(sub), "payload"); //取到消息里面的payload
    // cJSON* flie_array=version_json->child;//指向子节点数组file
    cJSON *flie = cJSON_GetObjectItem(version_json, "file"); //取到消息里面的file
    cJSON *file = cJSON_GetArrayItem(flie, 0);               //拿到file数组下表一的值
    cJSON *blockSu = cJSON_GetObjectItem(file, "blockSum");  //从中找到blockSum也就是分成了多少份文件
    int blockSum = blockSu->valueint;                        //拿到具体份数
    cJSON *block_data = cJSON_GetObjectItem(file, "block");  //从中找到拿到block也就是url数组
    FILE *pFile;
    pFile = fopen("/fat/hzgj_dtu_App_Debug.bin", "r"); //能读就是存在
    if (pFile != NULL)
    {
        fclose(pFile);
        remove("/fat/hzgj_dtu_App_Debug.bin"); //直接删掉
    }
    /*    else
        {
            pFile=fopen("/fat/hzgj_dtu_App_Debug.bin", "w ");
            fclose(pFile);
        }*/
    for (i = 0; i < blockSum; i++)
    {
        exit_flag = 0;
        struct mg_mgr Mgr;
        cJSON *block_arry = cJSON_GetArrayItem(block_data, i);    //拿到block数组下标i的值
        cJSON *url_data = cJSON_GetObjectItem(block_arry, "url"); //拿到url
        char *url = url_data->valuestring;                        //请求地址
        mg_mgr_init(&Mgr, NULL);
        mg_connect_http(&Mgr, ev_handler2, url,
                        "Accept: */*\r\n"
                        "Connection: keep-alive\r\n"
                        "User-Agent: Mongoose/6.15\r\n"
                        "Cache-Control: no-cache\r\n"
                        "Content-Type: content-type: text/plain\r\n",
                        NULL);
        while (exit_flag == 0)
        {
            mg_mgr_poll(&Mgr, 1000);
        }
        mg_mgr_free(&Mgr);
    }
    start_update(NULL);
}

ADD_TO_ROUTINE_SHELL(start_update, start_update, "运行iboot升级app.");
