1.增加重命名bat
authord15521469561 <1731678236@qq.com>
Wed, 10 Jun 2026 07:33:10 +0000 (15:33 +0800)
committerd15521469561 <1731678236@qq.com>
Wed, 10 Jun 2026 07:33:10 +0000 (15:33 +0800)
2.CMakeLists.txt增加命名脚本处理

12 files changed:
CMakeLists.txt
main/app_main.c
main/https_ota.c
main/n455_ota.c
main/project_common.c
main/project_common.h
main/uart.c
main/user_flash.c
main/user_mqtt.c
main/user_mqtt.h
main/wifi.c
rename_fw.bat [new file with mode: 0644]

index c7b182a..5b820a0 100644 (file)
@@ -12,4 +12,12 @@ add_custom_target(
 )
 
 include($ENV{IDF_PATH}/tools/cmake/project.cmake)
-project(mqtt_ssl_mutual_auth)
\ No newline at end of file
+project(mqtt_ssl_mutual_auth)
+
+add_custom_command(
+    TARGET app
+    POST_BUILD
+    COMMAND if exist "${CMAKE_SOURCE_DIR}/rename_fw.bat" (cmd /c "${CMAKE_SOURCE_DIR}/rename_fw.bat")
+    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+    COMMENT "自动重命名固件文件(如果存在脚本)..."
+)
\ No newline at end of file
index 5f7e988..3d74223 100644 (file)
@@ -190,6 +190,7 @@ void Main_Loop_Task(void *pvParameters)
     
     for(;;)
     {
+        
         #if ENABLE_BLE_FUNC
         Ble_Enable_Status_Check();
         #endif
@@ -257,6 +258,11 @@ void Main_Loop_Task(void *pvParameters)
             }
             
         }
+        if((xEventGroupWaitBits(common_event_group, COMMON_FACTORY_SET_BIT, pdFALSE, pdFALSE, 0) & COMMON_FACTORY_SET_BIT) != 0)
+        {
+            xEventGroupClearBits(common_event_group, COMMON_FACTORY_SET_BIT);
+            Esp32_Factory_Reset();
+        }
 
         if((xEventGroupWaitBits(common_event_group, COMMON_RESET_BIT, pdFALSE, pdFALSE, 0) & COMMON_RESET_BIT) != 0)
         {
@@ -283,11 +289,6 @@ void app_main(void)
     
     ESP_LOGI(MAIN_TAG, "[APP] IDF version: %s", esp_get_idf_version());
     ESP_LOGI(MAIN_TAG, "[DEVICE] Version: %04x %04x", FW_VERSION, BUILD_VERSION);
-    // esp_log_level_set("*", ESP_LOG_INFO);
-    // esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
-    // esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
-    // esp_log_level_set("transport", ESP_LOG_VERBOSE);
-    // esp_log_level_set("outbox", ESP_LOG_VERBOSE);
     ESP_LOGI(MAIN_TAG, "[APP] Free memory start: %" PRIu32 " bytes", esp_get_free_heap_size());
     // Uart_Initialize();
     // uart_task_handler = xTaskCreateStatic(Uart_Task, "Uart_Task", UART_TASK_STACK, NULL, 7, uart_task_stack, &uart_task_tcb);
@@ -330,9 +331,6 @@ void app_main(void)
     Uart_Initialize();
     uart_task_handler = xTaskCreateStatic(Uart_Task, "Uart_Task", UART_TASK_STACK, NULL, 7, uart_task_stack, &uart_task_tcb);
 
-    // uart_send_task_handler = xTaskCreateStatic(Uart_Send_Task, "Uart_Send_Task", UART_SEND_TASK_STACK, NULL, 5, uart_send_task_stack, &uart_send_task_tcb);
-
-    // ESP_LOGI(MAIN_TAG, "[APP] Free memory after Uart_Initialize: %" PRIu32 " bytes", esp_get_free_heap_size());
 #if (1)//#if (IOT_ENABLE)
     // LWIP
     ESP_ERROR_CHECK(esp_netif_init());
@@ -343,7 +341,7 @@ void app_main(void)
     // WIFI
     #if ENABLE_WIFI_FUNC
     Wifi_Sta_Init();
-    vTaskDelay(1000);
+    vTaskDelay(500);
 
     
     #endif
@@ -352,17 +350,8 @@ void app_main(void)
     Https_Ota_Handler_Init();
 
     #endif
-
-      
-    // ESP_LOGI(MAIN_TAG, "chip_id:%s chip_version:%d\n",chip_info.model,chip_info.res);
-    //等待wifi稳定再去连接wifi
-    // ESP_LOGI(MAIN_TAG, "[APP] Free memory after wifi: %" PRIu32 " bytes", esp_get_free_heap_size());
 #endif
     main_loop_task_handler = xTaskCreateStatic(Main_Loop_Task, "Main_Loop_Task", MAIN_LOOP_TASK_STACK, NULL, 4, main_loop_task_stack, &main_loop_task_tcb);
-    // ESP_LOGI(MAIN_TAG, "[APP] Free memory after Main_Loop: %" PRIu32 " bytes", esp_get_free_heap_size());
-    #if (!USER_TEST_ENABLE)
-    
-    #endif
 }
 
 
index ca3d58b..7ed6143 100644 (file)
@@ -53,10 +53,11 @@ typedef struct{
     volatile uint16_t ota_faile_count;//失败计数器
     uint8_t https_update_ota_flag;//根据版本号是否需要升级
     uint8_t https_ota_init;//ota升级task初始化
-    esp_https_ota_handle_t https_ota_handle; //ota句柄
+
 }__attribute__((packed)) https_ota_ctx_t;
 
 static https_ota_ctx_t s_ota_ctx = { 0 };
+
 #define HTTPS_OTA_RETRY_NUM  3
 
 #define OTA_URL_SIZE 128
@@ -67,6 +68,287 @@ static char https_ota_url[OTA_URL_SIZE] = "https://pxn-iot.s3-accelerate.amazona
 /*
  *函数功能:sdk原生自动版本校验 未使用
 */
+#define HTTPS_OTA_IS_RETRY_FUNC 
+// #define HTTPS_OTA_USER_CILENT 
+#ifdef HTTPS_OTA_USER_CILENT
+//===== 自研OTA工具函数(直接复制即可)=====
+#include "esp_ota_ops.h"
+#include "esp_app_format.h"   // ESP_APP_DESC_MAGIC_WORD
+
+static esp_err_t self_ota_get_target_part(const esp_partition_t **out_ota_part)
+{
+    const esp_partition_t *running = esp_ota_get_running_partition();
+    const esp_partition_t *ota_part = esp_ota_get_next_update_partition(running);
+    if (!ota_part) {
+        ESP_LOGE(HTTPS_OTA, "get ota partition failed");
+        return ESP_FAIL;
+    }
+    *out_ota_part = ota_part;
+    return ESP_OK;
+}
+
+static esp_err_t self_ota_check_firmware_header(const uint8_t *data, size_t len)
+{
+    // 至少要读到 app_desc 大小
+    if (len < sizeof(esp_app_desc_t) + 32) {
+        return ESP_ERR_INVALID_SIZE;
+    }
+
+    // 偏移 24 字节后才是 esp_app_desc_t
+    const esp_app_desc_t *app_desc = (const esp_app_desc_t *)(data + 32);
+
+    // 1. 校验魔数(正确写法!!!)
+    uint32_t magic = ESP_APP_DESC_MAGIC_WORD;
+    if (app_desc->magic_word != magic) {
+        ESP_LOGE(HTTPS_OTA, "firmware magic word error");
+        return ESP_ERR_INVALID_ARG;
+    }
+    return ESP_OK;
+    // 2. 获取当前运行固件版本
+    const esp_partition_t *running_part = esp_ota_get_running_partition();
+    esp_app_desc_t running_desc;
+    if (esp_ota_get_partition_description(running_part, &running_desc) != ESP_OK) {
+        return ESP_FAIL;
+    }
+
+    // 3. 打印版本、判断是否相同
+    ESP_LOGI(HTTPS_OTA, "run ver:%s, new ver:%s",
+             running_desc.version, app_desc->version);
+
+    // 版本相同则不升级
+    if (strcmp((const char*)running_desc.version, (const char*)app_desc->version) == 0) {
+        ESP_LOGW(HTTPS_OTA, "same version, skip");
+        return ESP_ERR_NOT_SUPPORTED;
+    }
+
+    return ESP_OK;
+}
+
+//会占用ram
+// OTA 分片大小,建议 4KB / 8KB,兼顾效率与栈/内存
+#define OTA_DOWNLOAD_BUF_SIZE    (4096)
+// HTTP 单次超时(毫秒),核心防阻塞
+#define OTA_HTTP_TIMEOUT_MS      (6000)
+// 连续无数据最大次数(判定网络卡死)
+#define OTA_STUCK_MAX_CNT        (8)
+// OTA 最大重试次数
+#define OTA_SELF_MAX_RETRY       (3)
+
+// 下载缓冲区
+static uint8_t ota_download_buf[OTA_DOWNLOAD_BUF_SIZE];
+static esp_err_t self_ota_download_and_write(const char *url)
+{
+    esp_err_t ret = ESP_FAIL;
+    esp_http_client_handle_t http_client = NULL;
+    const esp_partition_t *ota_part = NULL;
+    esp_ota_handle_t ota_handle = 0;
+
+    uint32_t total_read = 0;
+   // 卡死计数
+    bool header_checked = false;// 固件头只校验一次
+
+    // 1. 获取OTA分区
+    ret = self_ota_get_target_part(&ota_part);
+    if (ret != ESP_OK) goto clean_exit;
+
+    // 2. 初始化HTTP客户端
+    esp_http_client_config_t http_cfg = {
+        .url = url,
+        .timeout_ms = OTA_HTTP_TIMEOUT_MS,
+        .keep_alive_enable = false,
+        .crt_bundle_attach = esp_crt_bundle_attach, // HTTPS证书
+    };
+    http_client = esp_http_client_init(&http_cfg);
+    if (!http_client) {
+        ESP_LOGE(HTTPS_OTA, "http client init fail");
+        ret = ESP_FAIL;
+        goto clean_exit;
+    }
+
+    // 3. 发起连接
+    ret = esp_http_client_open(http_client, 0);
+    if (ret != ESP_OK) {
+        ESP_LOGE(HTTPS_OTA, "http open fail");
+        goto clean_exit;
+    }
+    ret =  esp_http_client_fetch_headers(http_client);
+    int code = esp_http_client_get_status_code(http_client);
+    if (code != 200 || ret < 0) {
+        ESP_LOGI(HTTPS_OTA, "HTTP code error");
+        goto clean_exit;
+    }
+    int content_len = esp_http_client_get_content_length(http_client);
+    ESP_LOGI(HTTPS_OTA, "Firmware total len: %d", content_len);
+
+    // 4. 初始化OTA写入句柄
+    ret = esp_ota_begin(ota_part, OTA_SIZE_UNKNOWN, &ota_handle);
+    if (ret != ESP_OK) {
+        ESP_LOGE(HTTPS_OTA, "esp_ota_begin fail");
+        goto clean_exit;
+    }
+
+    // s_self_ota_state = SELF_OTA_DOWNLOADING;
+    ESP_LOGI(HTTPS_OTA, "Start self ota download");
+
+    // 5. 循环分片读取 + 写入 Flash(核心防阻塞循环)
+    while (1)
+    {
+        // 上层主动停止标记(对应你原来的 ota_timeout_req)
+        if (s_ota_ctx.ota_timeout_req) {
+            ESP_LOGW(HTTPS_OTA, "OTA user stop");
+            ret = ESP_ERR_TIMEOUT;
+            break;
+        }
+
+        // 单次读取分片数据
+        int read_len = esp_http_client_read(http_client, (char *)ota_download_buf, OTA_DOWNLOAD_BUF_SIZE);
+        if (read_len < 0) {
+            ESP_LOGE(HTTPS_OTA, "http read error");
+            ret = ESP_FAIL;
+            break;
+        }
+        // 读到末尾,正常结束
+        if (read_len == 0) {
+            ESP_LOGI(HTTPS_OTA, "Download complete, total read: %lu", total_read);
+            
+            if(total_read != content_len)
+            {
+                ret = ESP_FAIL;
+            } else {
+                ret = ESP_OK;
+            }
+            break;
+        }
+        total_read += read_len;
+
+        // 第一次读到数据,校验固件头部
+        if (!header_checked) {
+            ret = self_ota_check_firmware_header(ota_download_buf, read_len);
+            if (ret != ESP_OK) break;
+            header_checked = true;
+        }
+
+        // 写入OTA分区
+        ret = esp_ota_write(ota_handle, ota_download_buf, read_len);
+        if (ret != ESP_OK) {
+            ESP_LOGE(HTTPS_OTA, "esp_ota_write fail");
+            break;
+        }
+
+        // 打印进度(可选)
+        ESP_LOGI(HTTPS_OTA, "Download progress: %lu / %d", total_read, content_len);
+    }
+
+    // 6. 下载完成,收尾校验
+    if (ret == ESP_OK) {
+        // s_self_ota_state = SELF_OTA_VERIFY;
+        ret = esp_ota_end(ota_handle);
+        if (ret != ESP_OK) {
+            ESP_LOGE(HTTPS_OTA, "esp_ota_end verify fail");
+            goto clean_exit;
+        } else {
+            // 切换启动分区
+            ret = esp_ota_set_boot_partition(ota_part);
+            if (ret != ESP_OK) {
+                // s_self_ota_state = SELF_OTA_SUCCESS;
+                ESP_LOGI(HTTPS_OTA, "OTA set boot partition ok");
+                goto clean_exit;
+            }
+            ota_handle=0;
+        }
+    }else{
+        //失败需要关闭
+        goto clean_exit;
+    }
+
+clean_exit:
+    // 统一资源释放(重中之重,防止内存/句柄泄漏)
+    if (http_client) {
+        esp_http_client_close(http_client);
+        esp_http_client_cleanup(http_client);
+    }
+    // 失败则终止OTA,标记分区无效
+    if (ret != ESP_OK && ota_handle != 0) {
+        esp_ota_abort(ota_handle);
+        // s_self_ota_state = SELF_OTA_FAILED;
+    }
+    return ret;
+}
+//用户自定义的OTA任务回调函数,主要用于处理OTA升级流程 https 
+static void Https_Ota_Task_Cb(void *pvParameter)
+{
+    Mqtt_Disconnect();
+    vTaskDelay(200 / portTICK_PERIOD_MS);
+
+    ESP_LOGI(HTTPS_OTA, "Self OTA start, url: %s", https_ota_url);
+    g_ota_status = HTTPS_OTA_STATUS_UPGRADING;
+    Https_Ota_Report_Status(HTTPS_OTA_STATUS_UPGRADING);
+
+    esp_err_t ota_ret = ESP_FAIL;
+    uint8_t try_idx = 0;
+    bool ota_success = false;
+
+    s_ota_ctx.ota_timeout_count = HTTPS_OTA_TIMEOUT_TIME;
+    // 多层重试
+    for (try_idx = 0; try_idx < HTTPS_OTA_MAX_RETRY_CNT; try_idx++)
+    {
+        ESP_LOGI(HTTPS_OTA, "==== Self OTA retry %d/%d ====", try_idx+1, HTTPS_OTA_MAX_RETRY_CNT);
+        if (s_ota_ctx.ota_timeout_req) {
+            ota_success = false;
+            break;;
+        }
+        // 调用自研下载函数
+        ota_ret = self_ota_download_and_write(https_ota_url);
+        if (ota_ret == ESP_OK) {
+            ota_success = true;
+            break;
+        }
+        vTaskDelay(pdMS_TO_TICKS(HTTPS_OTA_RETRY_TIMES));
+    }
+
+    // ========== 分支处理:成功 / 失败 ==========
+    if (ota_success)
+    {
+        g_ota_status = HTTPS_OTA_STATUS_SUCCESS;
+        #if (!ENABLE_HTTP_N455_OTA_FUNC)
+        Https_Ota_Report_Status(HTTPS_OTA_STATUS_SUCCESS);
+        Https_Ota_Clear_Upgrade_Flag();
+        esp_restart(); // 正常重启
+        #else
+        // 保留你原有 N455 联动逻辑
+        if(N455_Ota_Get_Update_Flag())
+        {
+            if(N455_Ota_Task() == 1)
+            {
+                esp_ota_mark_app_invalid_rollback();
+                Https_Ota_Report_Status(HTTPS_OTA_STATUS_FAILED);
+                N455_Ota_Clear_Upgrade_Flag();
+                Https_Ota_Clear_Upgrade_Flag();
+                xEventGroupSetBits(common_event_group, COMMON_MQTT_CONNECT_BIT);
+            }
+        }else{
+            Https_Ota_Report_Status(HTTPS_OTA_STATUS_SUCCESS);
+            Https_Ota_Clear_Upgrade_Flag();
+            esp_restart();
+        }
+        #endif
+        vTaskDelete(NULL);
+        return;
+    }
+    else
+    {
+        // 升级失败分支
+        ESP_LOGE(HTTPS_OTA, "Self OTA all retry failed");
+        g_ota_status = HTTPS_OTA_STATUS_FAILED;
+        Https_Ota_Report_Status(HTTPS_OTA_STATUS_FAILED);
+        Https_Ota_Clear_Upgrade_Flag();
+        xEventGroupSetBits(common_event_group, COMMON_MQTT_CONNECT_BIT);
+        vTaskDelete(NULL);
+    }
+}
+#endif
+#ifndef HTTPS_OTA_USER_CILENT
+#ifndef HTTPS_OTA_IS_RETRY_FUNC 
 static esp_err_t validate_image_header(esp_app_desc_t *new_app_info)
 {
     return ESP_OK;
@@ -110,14 +392,13 @@ static esp_err_t _http_client_init_cb(esp_http_client_handle_t http_client)
     // err = esp_http_client_set_header(http_client, "Custom-Header", "Value");
     return err;
 }
-
-#if 0
 /*
 func:OTA升级回调函数
 */
 
 static void Https_Ota_Task_Cb(void *pvParameter)
 {
+    esp_https_ota_handle_t https_ota_handle = NULL;
     ota_timeout_count = HTTPS_OTA_TIMEOUT_TIME;
     Mqtt_Disconnect();  // 关闭MQTTs
     // 2. 延迟一下确保资源释放
@@ -293,20 +574,64 @@ ota_end:
     // 删除
     vTaskDelete(NULL);
 }
-#else
+#endif
+#ifdef HTTPS_OTA_IS_RETRY_FUNC
+static esp_err_t validate_image_header(esp_app_desc_t *new_app_info)
+{
+    return ESP_OK;
+    if (new_app_info == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    const esp_partition_t *running = esp_ota_get_running_partition();
+    esp_app_desc_t running_app_info;
+    if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {
+        ESP_LOGI(HTTPS_OTA, "Running firmware version: %s", running_app_info.version);
+    }
+    ESP_LOGI(HTTPS_OTA, "Running firmware version: %s new_app_info->version:%s", running_app_info.version,new_app_info->version);
+#if 1
+    if (memcmp(new_app_info->version, running_app_info.version, sizeof(new_app_info->version)) == 0) {
+        ESP_LOGW(HTTPS_OTA, "Current running version is the same as a new. We will not continue the update.");
+        return ESP_FAIL;
+    }
+#endif
+
+#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
+    /**
+     * Secure version check from firmware image header prevents subsequent download and flash write of
+     * entire firmware image. However this is optional because it is also taken care in API
+     * esp_https_ota_finish at the end of OTA update procedure.
+     */
+    const uint32_t hw_sec_version = esp_efuse_read_secure_version();
+    if (new_app_info->secure_version < hw_sec_version) {
+        ESP_LOGW(HTTPS_OTA, "New firmware security version is less than eFuse programmed, %"PRIu32" < %"PRIu32, new_app_info->secure_version, hw_sec_version);
+        return ESP_FAIL;
+    }
+#endif
+
+    return ESP_OK;
+}
+
+static esp_err_t _http_client_init_cb(esp_http_client_handle_t http_client)
+{
+    esp_err_t err = ESP_OK;
+    /* Uncomment to add custom headers to HTTP request */
+    // err = esp_http_client_set_header(http_client, "Custom-Header", "Value");
+    return err;
+}
 static void Https_Ota_Task_Cb(void *pvParameter)
 {
     
-    
+    esp_https_ota_handle_t https_ota_handle = NULL;
     Mqtt_Disconnect();  // 关闭MQTTs
-    vTaskDelay(200 / portTICK_PERIOD_MS);
+    vTaskDelay(50 / portTICK_PERIOD_MS);
 
-    s_ota_ctx.https_ota_handle=NULL;
+    https_ota_handle=NULL;
     ESP_LOGI(HTTPS_OTA, "Starting Advanced OTA example:%s\n",https_ota_url);
     g_ota_status = HTTPS_OTA_STATUS_UPGRADING;
     Https_Ota_Report_Status(HTTPS_OTA_STATUS_UPGRADING);
 
-    vTaskDelay(100 / portTICK_PERIOD_MS);
+    vTaskDelay(50 / portTICK_PERIOD_MS);
     esp_err_t ota_finish_err = ESP_OK;
     bool ota_success = false;
     
@@ -320,7 +645,7 @@ static void Https_Ota_Task_Cb(void *pvParameter)
         ESP_LOGI(HTTPS_OTA,"==== OTA try %d/%d ====",try_idx+1,HTTPS_OTA_MAX_RETRY_CNT);
         esp_http_client_config_t config = {
             .url = https_ota_url,
-            .timeout_ms = 5000,
+            .timeout_ms = 3000,
             .keep_alive_enable = false,
         };
         config.crt_bundle_attach = esp_crt_bundle_attach;
@@ -332,13 +657,13 @@ static void Https_Ota_Task_Cb(void *pvParameter)
 
         esp_err_t err = ESP_FAIL;
         // 先释放上一轮句柄
-        if (s_ota_ctx.https_ota_handle != NULL)
+        if (https_ota_handle != NULL)
         {
-            esp_https_ota_abort(s_ota_ctx.https_ota_handle);
-            s_ota_ctx.https_ota_handle = NULL;
+            esp_https_ota_abort(https_ota_handle);
+            https_ota_handle = NULL;
         }
-        s_ota_ctx.https_ota_handle = NULL;
-        err = esp_https_ota_begin(&ota_config, &s_ota_ctx.https_ota_handle);
+        https_ota_handle = NULL;
+        err = esp_https_ota_begin(&ota_config, &https_ota_handle);
         if(err != ESP_OK)
         {
             ESP_LOGI(HTTPS_OTA, "esp_https_ota_begin failed, try:%d", try_idx+1);
@@ -348,7 +673,7 @@ static void Https_Ota_Task_Cb(void *pvParameter)
 
         err = ESP_FAIL;
         esp_app_desc_t app_desc;
-        err = esp_https_ota_get_img_desc(s_ota_ctx.https_ota_handle, &app_desc);
+        err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc);
         if (err != ESP_OK) {
             ESP_LOGI(HTTPS_OTA, "esp_https_ota_get_img_desc failed");
             vTaskDelay(pdMS_TO_TICKS(HTTPS_OTA_RETRY_TIMES));
@@ -377,14 +702,14 @@ static void Https_Ota_Task_Cb(void *pvParameter)
                 download_abort = true;
                 break;
             }
-            if(s_ota_ctx.https_ota_handle == NULL)
+            if(https_ota_handle == NULL)
             {
                 download_abort = true;
                 break;
             }
-            err = esp_https_ota_perform(s_ota_ctx.https_ota_handle);
+            err = esp_https_ota_perform(https_ota_handle);
             if (err == ESP_ERR_HTTPS_OTA_IN_PROGRESS) {
-                ESP_LOGI(HTTPS_OTA, "Image bytes read: %d ota_timeout_req:%d", esp_https_ota_get_image_len_read(s_ota_ctx.https_ota_handle),s_ota_ctx.ota_timeout_req);
+                ESP_LOGI(HTTPS_OTA, "Image bytes read: %d ota_timeout_req:%d", esp_https_ota_get_image_len_read(https_ota_handle),s_ota_ctx.ota_timeout_req);
                 if(s_ota_ctx.ota_timeout_req){
                     ESP_LOGI(HTTPS_OTA, "user stop!!!!timeout!!!!");
 
@@ -400,19 +725,19 @@ static void Https_Ota_Task_Cb(void *pvParameter)
         }
 
         // 数据没收全
-        if (esp_https_ota_is_complete_data_received(s_ota_ctx.https_ota_handle) != true) {
+        if (esp_https_ota_is_complete_data_received(https_ota_handle) != true) {
             ESP_LOGI(HTTPS_OTA, "Complete data was not received. continue ota %d",common_setting.wifi_status.wifi_state);
             vTaskDelay(pdMS_TO_TICKS(HTTPS_OTA_RETRY_TIMES));
             continue;
         }
 
         // 执行finish
-        ota_finish_err = esp_https_ota_finish(s_ota_ctx.https_ota_handle);
+        ota_finish_err = esp_https_ota_finish(https_ota_handle);
         if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) {
             ESP_LOGI(HTTPS_OTA, "ESP_HTTPS_OTA upgrade successful. Rebooting ...");
             g_ota_status = HTTPS_OTA_STATUS_SUCCESS;
             s_ota_ctx.ota_timeout_count=0;
-            s_ota_ctx.https_ota_handle = NULL;
+            https_ota_handle = NULL;
             ota_success = true;
             break; //升级成功跳出for,不再重试
         } else {
@@ -464,9 +789,9 @@ static void Https_Ota_Task_Cb(void *pvParameter)
         vTaskDelete(NULL);
         return;
     }else{
-        if(s_ota_ctx.https_ota_handle != NULL && g_ota_status != HTTPS_OTA_STATUS_SUCCESS){
-            esp_https_ota_abort(s_ota_ctx.https_ota_handle);
-            s_ota_ctx.https_ota_handle = NULL;
+        if(https_ota_handle != NULL && g_ota_status != HTTPS_OTA_STATUS_SUCCESS){
+            esp_https_ota_abort(https_ota_handle);
+            https_ota_handle = NULL;
         }
         s_ota_ctx.ota_timeout_req=0;
         ESP_LOGI(HTTPS_OTA, "ESP_HTTPS_OTA upgrade failed after 3 retry");
@@ -486,6 +811,7 @@ static void Https_Ota_Task_Cb(void *pvParameter)
     }
 }
 #endif
+#endif
 //清空升级标识
 void Https_Ota_Clear_Upgrade_Flag(void)
 {
index 7097e69..01021fd 100644 (file)
@@ -39,15 +39,6 @@ static char n455_ota_url[OTA_URL_MAX_LEN] = "https://pxn-iot.s3-accelerate.amazo
 // BIN 文件头
 #define FW_HEADER_SIZE          256     // 前256字节是头,需要跳过
 
-// // 全局升级应答
-// static volatile bool  uart_ack_received = false; // UART应答的 1 标识uart收到回复 
-// static volatile uint8_t uart_ack = 0xFF; //UART应答的 1 成功 2 失败 0xFF未收到应答 0表示收到但失败
-
-// //task 标识
-// static  uint8_t n455_ota_init = 0;
-// static volatile uint8_t n455_ota_stop_flag = 0;
-// static volatile uint16_t n455_ota_timeout_cnt = 0;
-// static uint8_t n455_ota_update_flag = 0; //ota是否需要升级 根据版本号比对
 
 typedef struct{
     volatile bool  uart_ack_received; //收到回复串口的应答 1收到应答
@@ -579,7 +570,7 @@ void N455_Ota_Task_Cb(void *param)
         .crt_bundle_attach = esp_crt_bundle_attach,
         .event_handler = _http_ota_event_handler,
         .timeout_ms = 5000,
-        .keep_alive_enable = false,
+        .keep_alive_enable = false, //true 会占用很多内存建议是false 不需要保持连接
     };
     /*
         *模组不需要升级的时候需要上报状态 模组升级了不需要再次上报升级中的状态
@@ -587,7 +578,7 @@ void N455_Ota_Task_Cb(void *param)
     if(!Https_Ota_Get_Update_Flag())
     {
         Mqtt_Disconnect();  // 关闭MQTTs
-        vTaskDelay(200 / portTICK_PERIOD_MS);
+        vTaskDelay(50 / portTICK_PERIOD_MS);
         n455_g_ota_status = N455_OTA_STATUS_UPGRADING;
         Https_Ota_Report_Status(N455_OTA_STATUS_UPGRADING);
     }
@@ -599,7 +590,6 @@ void N455_Ota_Task_Cb(void *param)
     uint32_t real_write_len = 0;
     CRC32_CTX_T crc_ctx;
     CRC32_Init(&crc_ctx);
-    uint32_t offset_size = 0;
     // uint8_t write_data[MAX_PACKET_CONTENT+6] = {0};
     int wlen = 0;
     esp_http_client_handle_t client = NULL;
@@ -627,7 +617,6 @@ void N455_Ota_Task_Cb(void *param)
         memset(buf, 0, sizeof(buf));
         real_write_len = 0;
         CRC32_Init(&crc_ctx);
-        offset_size = 0;
         memset(write_data, 0, sizeof(write_data));
         
         // memset(header_buf,0,sizeof(header_buf));
@@ -710,10 +699,10 @@ void N455_Ota_Task_Cb(void *param)
 
                 wlen = 0;
                 CRC32_Update(&crc_ctx, buf, r);
-                write_data[wlen++] = offset_size & 0xFF;
-                write_data[wlen++] = (offset_size >> 8) & 0xFF;
-                write_data[wlen++] = (offset_size >> 16) & 0xFF;
-                write_data[wlen++] = (offset_size >> 24) & 0xFF;
+                write_data[wlen++] = real_write_len & 0xFF;
+                write_data[wlen++] = (real_write_len >> 8) & 0xFF;
+                write_data[wlen++] = (real_write_len >> 16) & 0xFF;
+                write_data[wlen++] = (real_write_len >> 24) & 0xFF;
                 write_data[wlen++] = r & 0xFF;
                 write_data[wlen++] = (r >> 8) & 0xFF;
                 memcpy(&write_data[wlen], buf, r);
@@ -724,8 +713,9 @@ void N455_Ota_Task_Cb(void *param)
                     break;
                 }
                 
-                offset_size += r;
+                // offset_size += r;
                 real_write_len += r;
+                ESP_LOGE(N455_OTA, "W:%d",real_write_len);
             }
             ESP_LOGE(N455_OTA, "WRITE END:%d",real_write_len);
             //超时退出不再继续ota升级
index 6ca406d..d6914b6 100644 (file)
@@ -1094,7 +1094,7 @@ void get_chip_info(char *chip_id,uint8_t *chip_len)
     *chip_len=len;
     memcpy(chip_id,chip_name,strlen(chip_name));
     // 最终清晰打印
-    ESP_LOGI(CHIP_LOG, "chip_name: %s chip_info.revision %d", chip_name,chip_info.revision);
+    // ESP_LOGI(CHIP_LOG, "chip_name: %s chip_info.revision %d", chip_name,chip_info.revision);
 }
 
 void print_chip_info(void)
index 1d9a018..5d089cf 100644 (file)
 #define FW_VERSION_B        VERSION_MAX_HEX
 #endif
 
+#define DEFAULT_MAGRIC_MCU  0xBAD0C0FFEE00CAFE
+
 // 最终对外版本
-#define FW_VERSION                             (FW_VERSION_B >  VERSION_MAX_HEX ?  VERSION_MAX_HEX:FW_VERSION_B)               // 固件版本 //10.22         // 固件版本 //10.22         // 固件版本 //10.22         // 固件版本 //0A00 10.00 10.21
+#define FW_VERSION                             (0x0101)        // 固件版本 //10.22         // 固件版本 //10.22         // 固件版本 //10.22         // 固件版本 //0A00 10.00 10.21
 #define BUILD_VERSION                  (0x000C)        // 编译测试版本
 #define DEVICE_VID                  (0x36E6)        // 设备厂商代码
 #define DEVICE_PID                  (0xEC01)        // 设备型号代码
@@ -168,6 +170,7 @@ typedef enum
     COMMON_HTTP_GET_URL_BIT = BIT6,
     COMMON_HTTP_BIND_BIT = BIT7,
     COMMON_HTTPS_N455_OTA_BIT = BIT8,
+    COMMON_FACTORY_SET_BIT = BIT9,
 }COMMON_EVENT_GROUP_BIT_E;
 
 typedef enum
@@ -360,6 +363,7 @@ typedef struct
     uint8_t reserved:4;
     
     int  tz_offset_min;
+    
     // UNIVERSAL
     uint32_t heart_beat_interval; // ms
     MCU_INFO_T mcu_info;
@@ -500,7 +504,6 @@ typedef struct
 void int64_to_str(uint64_t ts, char *out,size_t out_len);
 void Get_Time(struct tm *time_out);
 void set_system_time_int_from_utc(int64_t utc_timestamp_sec,const char *zone);
-void set_system_time_str_from_utc(int64_t utc_timestamp_sec, const char *timeZone);
 void network_request_replay(uint8_t status);
 
 void get_chip_info(char *chip_id,uint8_t *chip_len);
index 44b45e1..a1c880a 100644 (file)
@@ -537,7 +537,8 @@ void Uart_Pairing_Handle(uint8_t *data ,uint16_t len, uint8_t host_type)
             //
             case COMMON_UART_FACTORY_RESET:
             {
-               Esp32_Factory_Reset();
+              
+               xEventGroupSetBits(common_event_group, COMMON_FACTORY_SET_BIT);
                uart_pairing_reply.send_flag=1;
                uart_pairing_reply.len = 0;
             }
index 197922a..102ffc7 100644 (file)
@@ -97,7 +97,7 @@ void User_Erase_NotReset(void)
        //清除信息
        User_Erase_Nimble_NetWork_Infor();
        //read wifi 信息
-       User_Flash_Check();
+       
        memset(&common_storage, 0, sizeof(common_storage));
 
        memset(&common_setting.net_pairing_info,0x00,sizeof(common_setting.net_pairing_info));
@@ -107,7 +107,7 @@ void User_Erase_NotReset(void)
        memset(&common_setting.mqtt_user_cfg,0x00,sizeof(common_setting.mqtt_user_cfg));
 
        memset(&common_setting.https_ota_cfg,0x00,sizeof(common_setting.https_ota_cfg));
-       
+       User_Flash_Check();
        
 }
 esp_err_t User_Flash_Erase(size_t offset, size_t size)
index 50b2480..abb453d 100644 (file)
@@ -177,7 +177,7 @@ const char *get_methon(uint8_t methon_mode)
 
 }
 
-// ===================== MQTT 事件拆分(原大函数拆分为子函数) =====================
+// ===================== MQTT 事件连接函数 =====================
 static void mqtt_event_on_connected(esp_mqtt_event_handle_t event)
 {
     esp_mqtt_client_handle_t mqtt_client = event->client;
@@ -206,7 +206,7 @@ static void mqtt_event_on_connected(esp_mqtt_event_handle_t event)
     }
     #endif
 }
-
+/************mqtt****断开事件函数******************************* */
 static void mqtt_event_on_disconnected(void)
 {
     
@@ -214,7 +214,7 @@ static void mqtt_event_on_disconnected(void)
     mqtt_ctx.sub_flag = 0;
     ESP_LOGI(MQTT_TAG, "MQTT_EVENT_DISCONNECTED");
 }
-
+/****************mqtt**********订阅成功事件*********************** */
 static void mqtt_event_on_subscribed(void)
 {
     mqtt_ctx.sub_flag = 1;
@@ -222,11 +222,12 @@ static void mqtt_event_on_subscribed(void)
     ESP_LOGI(MQTT_TAG, "MQTT_EVENT_SUBSCRIBED");
 }
 
+/***************mqtt*******服务下发数据事件***************************************** */
 static void mqtt_event_on_data(esp_mqtt_event_handle_t event)
 {
     Mqtt_Recv_Data(event->topic, event->topic_len, event->data, event->data_len);
 }
-
+/*****************mqtt*****事件错误回调******************************************************** */
 static void mqtt_event_on_error(esp_mqtt_event_handle_t event)
 {
     ESP_LOGI(MQTT_TAG, "MQTT_EVENT_ERROR");
@@ -286,8 +287,8 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_
 
     case MQTT_EVENT_DATA:
         // ESP_LOGI(MQTT_TAG, "TOPIC=%.*s\r\n", event->topic_len, event->topic);
-        ESP_LOGI(MQTT_TAG, "DATA=%.*s\r\n", event->data_len, event->data);
-        
+        // ESP_LOGI(MQTT_TAG, "DATA=%.*s\r\n", event->data_len, event->data);
+        ESP_LOGI(MQTT_TAG, "DATA=%d %d\r\n", event->data_len,event->topic_len);
         mqtt_event_on_data(event);
         break;
 
@@ -435,11 +436,19 @@ void Mqtt_Recv_Data(char *topic, int topic_len, char *data, int data_len)
 {
     // 1. 长度判断
     
+    
     if (topic_len > MQTT_TOPIC_LEN || data_len > MQTT_DATA_BUF_SIZE || data_len <= 0 || topic_len <= 0) {
         ESP_LOGI(MQTT_TAG, "len large :%d\n",data_len);
         return;
     }
-
+    if (topic_len == strlen(get_publish_topic(TOPIC_FIRMWARE_OTA_UPGRADE)) && 
+        strcmp(get_publish_topic(TOPIC_FIRMWARE_OTA_UPGRADE), topic) == 0)
+    {
+        ESP_LOGI(MQTT_TAG, "ota json");
+        mqtt_parse_recv_data(topic, topic_len, data, data_len);
+        return;
+    }
+    
     // 2. 构建消息
     mqtt_recv_msg_t msg;
     memset(&msg, 0, sizeof(mqtt_recv_msg_t));
@@ -600,27 +609,32 @@ void Mqtt_Disconnect(void)
  *函数功能:开机连上mqtt订阅成功之后发送主控信息
 */
 
-void Mqtt_Send_Mcu_Info(void)
+uint8_t Mqtt_Send_Mcu_Info(void)
 {
 
     if(mqtt_ctx.mqtt_send_mcu_info_flag)
     {
-        return;
+        return 0;
     }
     if(!Mqtt_Get_Connect_Flag()) 
     {
-        return;
+        return 0;
     }
     char pid_str[10] = {0};
     char vid_str[10] = {0};
     char wifi_soc[16] = {"Unknown"};
 
+    esp_chip_info_t chip_info;
+    esp_chip_info(&chip_info);
     
     // 获取芯片型号
-    uint8_t chip_len = 0;
-    get_chip_info(wifi_soc, &chip_len);
-    if (chip_len == 0) {
-        strcpy(wifi_soc, "Unknown");
+    // uint8_t chip_len = 0;
+    // get_chip_info(wifi_soc, &chip_len);
+    
+    if (chip_info.model == CHIP_ESP32C2) {
+        strcpy(wifi_soc, "ESP32-C2");
+    }else{
+        strcpy(wifi_soc, "Unknown"); 
     }
     // PID、VID 大写十六进制格式
     snprintf(pid_str, sizeof(pid_str), "%04X", common_setting.mcu_info.pid);
@@ -636,7 +650,7 @@ void Mqtt_Send_Mcu_Info(void)
     
     // ===================== 构建正确的 JSON =====================
     cJSON *root = cJSON_CreateObject();
-    if (root == NULL) return;
+    if (root == NULL) return 0;
     
 
     // 把设备信息加到里面
@@ -656,7 +670,7 @@ void Mqtt_Send_Mcu_Info(void)
     char *post_data = cJSON_PrintUnformatted(root);
     cJSON_Delete(root);
     root=NULL;
-    if (post_data == NULL) return;
+    if (post_data == NULL) return 0;
 
     
     if(strlen(post_data) >= MQTT_SEND_RECV_DATA_BUF_SIZE)
@@ -664,19 +678,19 @@ void Mqtt_Send_Mcu_Info(void)
         ESP_LOGI(MQTT_TAG, "len large %d", strlen(post_data));
         free(post_data);
         post_data=NULL;
-        return;
+        return 0 ;
     }
     if(strlen(post_data) == 0 || strlen(get_publish_topic(TOPIC_PROPERTY_ACK_POST)) == 0)
     {
         ESP_LOGI(MQTT_TAG, "len no %d", strlen(get_publish_topic(TOPIC_PROPERTY_ACK_POST)),strlen(post_data));
         free(post_data);
         post_data=NULL;
-        return;
+        return 0;
     }
     // static char data_buf[64] = {0};
     // static mqtt_send_msg_t send_msg={0};
     // memcpy(data_buf,post_data,strlen(post_data));
-    ESP_LOGI(MQTT_TAG, "CJSON:%s", post_data);
+    ESP_LOGI(MQTT_TAG, "mcu info:%d", strlen(post_data));
     
 
     // memcpy(send_msg.topic,get_publish_topic(TOPIC_PROPERTY_ACK_POST),strlen(get_publish_topic(TOPIC_PROPERTY_ACK_POST)));
@@ -684,13 +698,13 @@ void Mqtt_Send_Mcu_Info(void)
     if(mqtt_dev_report_queue_handle==NULL)
     {
         ESP_LOGI(MQTT_TAG, "Mqtt_Send_Mcu_Info is null\n");
-        return;
+        return 0;
     }
-    user_esp_mqtt_client_publish(post_data,strlen(post_data),get_publish_topic(TOPIC_PROPERTY_ACK_POST));
+    int ret = user_esp_mqtt_client_publish(post_data,strlen(post_data),get_publish_topic(TOPIC_PROPERTY_ACK_POST));
     free(post_data);
     post_data = NULL;
     mqtt_ctx.mqtt_send_mcu_info_flag=0;
-    return;
+    return 1;
 }
 void mqtt_get_dev_test(uint16_t *dpid,uint8_t num);
 /*
@@ -717,10 +731,24 @@ void Mqtt_Send_Data(void)
 
         // mqtt_get_dev_test(test_dpid,49);
     }
-    if(mqtt_ctx.mqtt_send_data_count >= 30)
+    ESP_LOGI(MQTT_TAG,"%d %d",mqtt_ctx.sub_flag,mqtt_ctx.connect_flag);
+    if(mqtt_ctx.sub_flag == 1 && mqtt_ctx.connect_flag == 1)
     {
+        static uint8_t send_flag_first = 0;
+        if(send_flag_first == 0 && mqtt_ctx.mqtt_send_data_count >= 2)
+        {
+            if(Mqtt_Send_Mcu_Info())
+            {
+                send_flag_first=1;
+            }  
+        }
+        if(mqtt_ctx.mqtt_send_data_count >= 30)
+        {
+            mqtt_ctx.mqtt_send_data_count = 0;
+            Mqtt_Send_Mcu_Info();
+        }
+    }else{
         mqtt_ctx.mqtt_send_data_count = 0;
-        Mqtt_Send_Mcu_Info();  
     }
     mqtt_ctx.mqtt_send_data_count++;
 }
@@ -745,7 +773,8 @@ bool is_pure_number(const char *str)
 
 
 
-
+//用户自定义的json生成函数测试数据
+#if 0
 char *set_test_json(void)
 {
     // 1. 创建根对象
@@ -1010,6 +1039,8 @@ char *get_test_json(void)
     cJSON_Delete(root);
     return out;
 }
+#endif
+
 /*
  *函数功能: ota报文解析
  *参数array:数组[{},{}]
@@ -1147,8 +1178,11 @@ void mqtt_parse_recv_data(char *topic, int topic_len,char *data, int data_len)
         if(reset->valueint)
         {
             //2.重启设备
+            Wifi_Stop();
+            vTaskDelay(pdMS_TO_TICKS(50));
+            Mqtt_Disconnect();
+            vTaskDelay(pdMS_TO_TICKS(50));
             User_Erase_Nimble_NetWork_Infor();
-            vTaskDelay(pdMS_TO_TICKS(100));
             if(root != NULL)
             {
                 cJSON_Delete(root);
@@ -1721,7 +1755,7 @@ int mqtt_get_dev_property(const cJSON *array)
         {
             
             ret = Uart_Reply_Send(COMMON_UART_PROPERTY_BATCH_REPORT_CMD,send_data, send_len,HOST_TYPE_UART);
-            ESP_LOGI(MQTT_TAG,"end ret %d\n",ret);
+            ESP_LOGI(MQTT_TAG,"send=%d\n",ret);
             return ret;
         }
         else{
index fc32b9d..0e13243 100644 (file)
@@ -40,9 +40,9 @@ typedef enum {
 #define MQTT_TOPIC_LEN    64
 #define MQTT_MAX_TRY_CONNECT_TIME   10
 #define MQTT_DATA_BUF_SIZE  MQTT_SEND_RECV_DATA_BUF_SIZE
-#define MQTT_RECV_QUEUE_LENGTH 8
+#define MQTT_RECV_QUEUE_LENGTH 10
 
-#define MQTT_SEND_QUEUE_LENGTH  4
+#define MQTT_SEND_QUEUE_LENGTH  8
 #define MQTT_SEND_MSG_MAX_LEN   MQTT_SEND_RECV_DATA_BUF_SIZE
 
 
@@ -103,7 +103,7 @@ void Mqtt_Send_Data(void);
 void Mqtt_Recv_Data(char *topic,int topic_len,char *data,int data_len);
 void Mqtt_Init_Task(void);
 void Mqtt_Disconnect(void);
-void Mqtt_Send_Mcu_Info(void);
+
 uint8_t Mqtt_Get_Connect_Flag(void);
 void Mqtt_Send_Connect_Status(void);//发送mqtt连接状态给主控
 int mqtt_set_dev_property(const cJSON *array);
@@ -118,5 +118,6 @@ void mqtt_parse_recv_data(char *topic, int topic_len,char *data, int data_len);
 void mqtt_check_isconnect(void);
 void mqtt_ota_data_parse(const cJSON *array);
 uint8_t get_mqtt_init_flag(void);
+uint8_t Mqtt_Send_Mcu_Info(void);
 #endif
 #endif
\ No newline at end of file
index 4f8695e..24aef57 100644 (file)
@@ -259,17 +259,7 @@ void Wifi_Sta_Init(void)
 
 static esp_timer_handle_t wifi_one_timer_handle;//创建定时器handle
 static uint8_t wifi_one_timer_flag = 0;//0:未创建  1:已创建
-void Wifi_Connect_Set_Flag(void)
-{
-    if(common_setting.wifi_status.connect_mode != 2)//只有用户配网才开启定时器
-    {
-        return;
-    }
-    #if (1)
-    
-    
-    #endif
-}
+
 void Wifi_Connect_Timerout_Stop(void)
 {
     if(wifi_one_timer_flag)
@@ -306,7 +296,7 @@ void Wifi_Start(void)
     s_retry_num = 0;
    if(common_setting.wifi_status.connect_mode == 2)
     {
-        // Create and start one-time timer for 80 ms
+        // Create and start one-time timer for 80s
         if(common_setting.ble_status.ble_adv_flag > 0) //蓝牙开启说明在配网状态 如果在设定的时间内没有连上就发送超时蓝牙指令
         {
             wifi_connect_timeout_flag = 1;
diff --git a/rename_fw.bat b/rename_fw.bat
new file mode 100644 (file)
index 0000000..b4893f4
--- /dev/null
@@ -0,0 +1,111 @@
+@echo off
+chcp 65001 >nul 2>&1
+setlocal enabledelayedexpansion
+
+set "BAT_PATH=%~dp0"
+set "BAT_PATH=!BAT_PATH:~0,-1!"
+
+set "PROJ_DIR=!BAT_PATH!"
+set "H_FILE=!PROJ_DIR!\main\project_common.h"
+set "SRC_BIN=!PROJ_DIR!\build\mqtt_ssl_mutual_auth.bin"
+set "DST_DIR=!PROJ_DIR!\update_bin"
+set "PREFIX=ESP32_C2_IOT_Update_"
+
+if not exist "!SRC_BIN!" (
+    echo ERROR: Source bin not found: !SRC_BIN!
+    pause
+    exit /b 1
+)
+
+set "LINE="
+for /f "delims=" %%a in ('findstr /r /C:"#define[ \t]*FW_VERSION" "!H_FILE!"') do (
+    set "LINE=%%a"
+)
+if "!LINE!"=="" (
+    echo ERROR: FW_VERSION not found in header
+    pause
+    exit /b 1
+)
+
+:: ======================
+:: 修复:支持 (0x0101) 括号
+:: ======================
+for /f "tokens=3 delims=() " %%b in ("!LINE!") do set "RAW=%%b"
+set "RAW=!RAW:;=!"
+set "RAW=!RAW: =!"
+
+set "HEX=!RAW:~2,4!"
+set "HIB_HEX=!HEX:~0,2!"
+set "LOB_HEX=!HEX:~2,2!"
+if "!LOB_HEX!"=="" set "LOB_HEX=00"
+if "!HIB_HEX!"=="" set "HIB_HEX=00"
+
+call :hex2dec !HIB_HEX! HIB
+call :hex2dec !LOB_HEX! LOB
+
+if !LOB! lss 10 set "LOB=0!LOB!"
+set "VER=V!HIB!.!LOB!"
+
+for /f "tokens=2-4 delims=/-. " %%a in ("%date%") do (
+    set "YYYY=%%a"
+    set "MM=%%b"
+    set "DD=%%c"
+)
+set "HH=%time:~0,2%"
+set "MI=%time:~3,2%"
+set "HH=!HH: =0!"
+set "MI=!MI: =0!"
+set "DATETIME=!YYYY!!MM!!DD!!HH!!MI!"
+
+set "DST_BIN=!DST_DIR!\!PREFIX!!VER!_!DATETIME!.bin"
+if not exist "!DST_DIR!" md "!DST_DIR!"
+
+copy /y "!SRC_BIN!" "!DST_BIN!" >nul
+if !errorlevel! equ 0 (
+    echo SUCCESS: !DST_BIN!
+) else (
+    echo ERROR: Copy failed
+)
+
+pause
+exit /b
+
+:hex2dec
+setlocal
+set "hex=%1"
+set "hex=!hex:a=A!"
+set "hex=!hex:b=B!"
+set "hex=!hex:c=C!"
+set "hex=!hex:d=D!"
+set "hex=!hex:e=E!"
+set "hex=!hex:f=F!"
+set "c1=!hex:~0,1!"
+set "c2=!hex:~1,1!"
+call :char2dec !c1! v1
+call :char2dec !c2! v2
+set /a dec=v1*16+v2
+endlocal & set "%2=%dec%"
+goto :eof
+
+:char2dec
+setlocal
+set "c=%1"
+set "val=0"
+if /i "!c!"=="0" set val=0
+if /i "!c!"=="1" set val=1
+if /i "!c!"=="2" set val=2
+if /i "!c!"=="3" set val=3
+if /i "!c!"=="4" set val=4
+if /i "!c!"=="5" set val=5
+if /i "!c!"=="6" set val=6
+if /i "!c!"=="7" set val=7
+if /i "!c!"=="8" set val=8
+if /i "!c!"=="9" set val=9
+if /i "!c!"=="A" set val=10
+if /i "!c!"=="B" set val=11
+if /i "!c!"=="C" set val=12
+if /i "!c!"=="D" set val=13
+if /i "!c!"=="E" set val=14
+if /i "!c!"=="F" set val=15
+endlocal & set "%2=%val%"
+goto :eof
\ No newline at end of file