/********************************************************* * @file cm_demo_fota.c * @brief OpenCPU FOTA示例 * Copyright (c) 2022 China Mobile IOT. * All rights reserved. * created by WangPeng 2022/8/29 ********************************************************/ #include "stdio.h" #include "string.h" #include "cm_fota.h" #include "cm_sys.h" #include "cm_os.h" #include "cm_fs.h" #include "cm_http.h" #include "cm_rtc.h" #include "md.h" #include "base64.h" #include "cJSON.h" #include "cm_fs.h" #include "cm_demo_uart.h" /* 产品ID,平台创建产品后由平台分配的ID(https://open.iot.10086.cn/console/product/own)。此处为示例数据,实际使用须据实修改 */ static char OneNET_pid[16] = "07av4iD9CC"; /* 用户ID,平台网页中用户中心-账户信息(https://open.iot.10086.cn/account/profile)中查询到的用户ID。此处为示例数据,实际使用须据实修改 */ static char OneNET_userid[16] = "148865"; /* 设备名称,平台添加设备时添加设备的设备名称(https://open.iot.10086.cn/console/device/manage/devs)。此处为示例数据,实际使用须据实修改 */ static char OneNET_devname[16] = "ML307A-DSLN"; /* 用户Accesskey,平台网页中用户中心-访问权限(https://open.iot.10086.cn/account/access)中查询到的用户Accesskey。此处为示例数据,实际使用须据实修改 */ static char OneNET_userkey[128] = "xxxxxxx9acyjz4upifwnvbwuETqplZ0DEJ+9jTj2jWD0GzrDSrLu7/oqLmKIZk18SUPu6vQZDsaOrwtPethioA=="; /* 模组OneNET软件版本号,平台添加差分升级包时填写的待升级版本。此处为示例数据,实际使用须据实修改 */ static char OneNET_version[16] = "1.0"; static void __cm_fota_cb(cm_fota_error_e error) { cm_demo_printf("[FOTA] error code is %d\n", error); } /** * @brief 上报当前设备OneNET版本号 * * @return * = 0 - 成功 \n * = -1 - 失败 * * @details 所使用的OneNET接口地址为http://ota.heclouds.com/fuse-ota/{pro_id}/{dev_name}/version \n * 参考网页https://open.iot.10086.cn/doc/v5/fuse/detail/1454 \n * 与平台交互过程中使用鉴权信息会过期,开发使用过程中须保证在时间过期前完成升级。安全鉴权参考https://open.iot.10086.cn/doc/v5/fuse/detail/1464 \n * 因为OneNET平台会持续迭代,本demo示例在2023年6月5日可以正常使用OneNET FOTA功能,但不能保证后续OneNET平台版本迭代后还可使用 \n * 本接口为示例代码,开发人员可参考开发 */ static int32_t __cm_onenet_fota_report_ver(void) { int32_t ret = -1; cm_httpclient_handle_t client = NULL; ret = cm_httpclient_create((const uint8_t *)"http://ota.heclouds.com", NULL, &client); if (CM_HTTP_RET_CODE_OK != ret || NULL == client) { cm_log_printf(0, "[OneNET] cm_httpclient_create() error!\r\n"); return -1; } cm_httpclient_cfg_t client_cfg; client_cfg.ssl_enable = false; client_cfg.ssl_id = 0; client_cfg.cid = 0; client_cfg.conn_timeout = HTTPCLIENT_CONNECT_TIMEOUT_DEFAULT; client_cfg.rsp_timeout = HTTPCLIENT_WAITRSP_TIMEOUT_DEFAULT; client_cfg.dns_priority = 0; ret = cm_httpclient_set_cfg(client, client_cfg); char path[128] = {0}; char header[256] = {0}; char message[128] = {0}; char content[64] = {0}; unsigned char base64_tmp[128] = {0}; int32_t et = cm_rtc_get_current_time() + 2 * 24 * 60 * 60; sprintf(path, "/fuse-ota"); sprintf(path + strlen((char*)path), "/%s/%s/version", OneNET_pid, OneNET_devname); /* 新接口必须要上报MCU版本号,OpenCPU开发通常不涉及MCU,故s_version传入任意值 */ sprintf(content, "{\"s_version\": \"%s\",\"f_version\": \"%s\"}", "MCU1.0", OneNET_version); sprintf(header, "%ld\nsha1\nuserid/%s\n2022-05-01", et, OneNET_userid); int base64_len = 0; mbedtls_base64_decode((unsigned char*)base64_tmp, 128, (unsigned int*)&base64_len, (const unsigned char*)OneNET_userkey, strlen(OneNET_userkey)); mbedtls_md_context_t ctx = {0}; const mbedtls_md_info_t *info = NULL; mbedtls_md_init(&ctx); info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); mbedtls_md_setup(&ctx, info, 1); mbedtls_md_hmac_starts(&ctx, (void *)base64_tmp, base64_len); mbedtls_md_hmac_update(&ctx, (void *)header, strlen(header)); mbedtls_md_hmac_finish(&ctx, (void *)message); mbedtls_md_free(&ctx); mbedtls_base64_encode((unsigned char*)base64_tmp, 128, (unsigned int*)&base64_len, (const unsigned char*)message, 20);//SHA-1 算法输出为20字节 sprintf(header, "Authorization: version=2022-05-01&res=userid%s%s&et=%ld&method=sha1&sign=", "%2F", OneNET_userid, et); for(int i = 0; i < base64_len; i++) { if((base64_tmp[i] == '+') || (base64_tmp[i] == '/') || (base64_tmp[i] == '=')) { sprintf(header+strlen(header), "%s", (base64_tmp[i] == '+')?("%2B"):((base64_tmp[i] == '/')?("%2F"):("%3D"))); } else { sprintf(header+strlen(header), "%c", base64_tmp[i]); } } sprintf(header + strlen(header), "\r\nContent-Type:%s\r\n", "application/json"); cm_httpclient_sync_response_t response = {}; cm_httpclient_sync_param_t param = {HTTPCLIENT_REQUEST_POST, (const uint8_t *)path, strlen(content), (uint8_t *)content}; cm_httpclient_specific_header_set(client, (uint8_t *)header, strlen(header)); ret = cm_httpclient_sync_request(client, param, &response); if (CM_HTTP_RET_CODE_OK != ret || NULL == client) { cm_log_printf(0, "[OneNET] cm_httpclient_sync_request() error! ret is %d\r\n", ret); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } else { cm_log_printf(0, "%s\r\n", response.response_content); } cJSON *root = cJSON_Parse((const char *)response.response_content); cJSON *code = cJSON_GetObjectItem(root, "code"); if(code == NULL) { cJSON_Delete(root); cm_log_printf(0, "[OneNET] HTTP GET DATA ERROR\r\n"); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } if(0 == code->valueint) { cJSON_Delete(root); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return 0; } else { cm_log_printf(0, "[OneNET] REPORT VERSION ERROR [%d]\r\n", code->valueint); cJSON_Delete(root); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } } /** * @brief 检测平台是否存在升级任务 * * @return * = 0 - 存在升级任务 \n * = -1 - 失败或者不存在升级任务 * * @details 所使用的OneNET接口地址为http://ota.heclouds.com/fuse-ota/{pro_id}/{dev_name}/check \n * 参考网页https://open.iot.10086.cn/doc/v5/fuse/detail/1447 \n * 与平台交互过程中使用鉴权信息会过期,开发使用过程中须保证在时间过期前完成升级。安全鉴权参考https://open.iot.10086.cn/doc/v5/fuse/detail/1464 \n * 因为OneNET平台会持续迭代,本demo示例在2023年6月5日可以正常使用OneNET FOTA功能,但不能保证后续OneNET平台版本迭代后还可使用 \n * 本接口为示例代码,开发人员可参考开发 */ static int32_t __cm_onenet_fota_check_upgrade_task(void) { int32_t ret = -1; cm_httpclient_handle_t client = NULL; ret = cm_httpclient_create((const uint8_t *)"http://ota.heclouds.com", NULL, &client); if (CM_HTTP_RET_CODE_OK != ret || NULL == client) { cm_log_printf(0, "[OneNET] cm_httpclient_create() error!\r\n"); return -1; } cm_httpclient_cfg_t client_cfg; client_cfg.ssl_enable = false; client_cfg.ssl_id = 0; client_cfg.cid = 0; client_cfg.conn_timeout = HTTPCLIENT_CONNECT_TIMEOUT_DEFAULT; client_cfg.rsp_timeout = HTTPCLIENT_WAITRSP_TIMEOUT_DEFAULT; client_cfg.dns_priority = 0; ret = cm_httpclient_set_cfg(client, client_cfg); char path[128] = {0}; char header[256] = {0}; char message[128] = {0}; unsigned char base64_tmp[128] = {0}; int32_t et = cm_rtc_get_current_time() + 2 * 24 * 60 * 60; sprintf(path, "/fuse-ota"); sprintf(path + strlen((char*)path), "/%s/%s/check?type=1&version=%s", OneNET_pid, OneNET_devname, OneNET_version); sprintf(header, "%ld\nsha1\nuserid/%s\n2022-05-01", et, OneNET_userid); int base64_len = 0; mbedtls_base64_decode((unsigned char*)base64_tmp, 128, (unsigned int*)&base64_len, (const unsigned char*)OneNET_userkey, strlen(OneNET_userkey)); mbedtls_md_context_t ctx = {0}; const mbedtls_md_info_t *info = NULL; mbedtls_md_init(&ctx); info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); mbedtls_md_setup(&ctx, info, 1); mbedtls_md_hmac_starts(&ctx, (void *)base64_tmp, base64_len); mbedtls_md_hmac_update(&ctx, (void *)header, strlen(header)); mbedtls_md_hmac_finish(&ctx, (void *)message); mbedtls_md_free(&ctx); mbedtls_base64_encode((unsigned char*)base64_tmp, 128, (unsigned int*)&base64_len, (const unsigned char*)message, 20);//SHA-1 算法输出为20字节 sprintf(header, "Authorization: version=2022-05-01&res=userid%s%s&et=%ld&method=sha1&sign=", "%2F", OneNET_userid, et); for(int i = 0; i < base64_len; i++) { if((base64_tmp[i] == '+') || (base64_tmp[i] == '/') || (base64_tmp[i] == '=')) { sprintf(header+strlen(header), "%s", (base64_tmp[i] == '+')?("%2B"):((base64_tmp[i] == '/')?("%2F"):("%3D"))); } else { sprintf(header+strlen(header), "%c", base64_tmp[i]); } } sprintf(header + strlen(header), "\r\nContent-Type:%s\r\n", "application/json"); cm_httpclient_sync_response_t response = {}; cm_httpclient_sync_param_t param = {HTTPCLIENT_REQUEST_GET, (const uint8_t *)path, 0, NULL}; cm_httpclient_specific_header_set(client, (uint8_t *)header, strlen(header)); ret = cm_httpclient_sync_request(client, param, &response); if (CM_HTTP_RET_CODE_OK != ret || NULL == client) { cm_log_printf(0, "[OneNET] cm_httpclient_sync_request() error! ret is %d\r\n", ret); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } else { cm_log_printf(0, "%s\r\n", response.response_content); } cJSON *root = cJSON_Parse((const char *)response.response_content); cJSON *code = cJSON_GetObjectItem(root, "code"); if(code == NULL) { cJSON_Delete(root); cm_log_printf(0, "[OneNET] HTTP GET DATA ERROR\r\n"); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } if(0 == code->valueint) { cJSON *data = cJSON_GetObjectItem(root, "data"); if(data == NULL) { cm_log_printf(0, "[OneNET] HTTP GET data ERROR\r\n"); cJSON_Delete(root); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } cJSON *tid = cJSON_GetObjectItem(data, "tid"); if(tid == NULL) { cm_log_printf(0, "[OneNET] HTTP GET tid ERROR\r\n"); cJSON_Delete(root); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } char c_tid[16] = {0}; sprintf(c_tid, "%d", tid->valueint); /* 将tid写入文件系统,用于记录 */ if (true == cm_fs_exist("onenet_tid.txt")) { cm_fs_delete("onenet_tid.txt"); } int32_t fd = cm_fs_open("onenet_tid.txt", CM_FS_WB); int32_t f_len = cm_fs_write(fd, c_tid, strlen(c_tid)); if (f_len != strlen(c_tid)) { cm_log_printf(0, "[OneNET] FS WRITE tid ERROR\r\n"); } cm_fs_close(fd); cJSON_Delete(root); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return 0; } else { cm_log_printf(0, "[OneNET] REPORT VERSION ERROR [%d]\r\n", code->valueint); cJSON_Delete(root); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } } /** * @brief 组包下载url地址,并通过cm_fota_set_url()完成配置 * * @return * = 0 - 成功 \n * < 0 - 失败 * * @details 与平台交互过程中使用鉴权信息会过期,开发使用过程中须保证在时间过期前完成升级。安全鉴权参考https://open.iot.10086.cn/doc/v5/fuse/detail/1464 \n * 因为OneNET平台会持续迭代,本demo示例在2023年6月5日可以正常使用OneNET FOTA功能,但不能保证后续OneNET平台版本迭代后还可使用 \n * 鉴权数据原为header中数据,因本模组平台仅可使用最小系统升级方案,不支持header配置,故需将header数据以参数形式添加进url中(OneNET平台支持该方式) \n * 本接口为示例代码,开发人员可参考开发 */ static int32_t __cm_onenet_fota_set_url(void) { char download_url[256] = {0}; char c_tid[16] = {0}; int32_t fd = cm_fs_open("onenet_tid.txt", CM_FS_RB); int32_t f_len = cm_fs_read(fd, c_tid, 32); cm_fs_close(fd); if (0 == f_len) { cm_log_printf(0, "[OneNET] no tid\r\n"); return -1; } int32_t et = cm_rtc_get_current_time() + 2 * 24 * 60 * 60; sprintf(download_url, "http://ota.heclouds.com"); sprintf(download_url + strlen((char*)download_url), "/fuse-ota/%s/%s/%s/download", OneNET_pid, OneNET_devname, c_tid); /* 鉴权数据原为header中数据,因本模组平台仅可使用最小系统升级方案,不支持header配置,故需将header数据以参数形式添加进url中(OneNET平台支持该方式) */ char header[128] = {0}; unsigned char base64_tmp[128] = {0}; char message[128] = {0}; int base64_len = 0; sprintf(header, "%ld\nsha1\nuserid/%s\n2022-05-01", et, OneNET_userid); mbedtls_base64_decode((unsigned char*)base64_tmp, 128, (unsigned int*)&base64_len, (const unsigned char*)OneNET_userkey, strlen(OneNET_userkey)); mbedtls_md_context_t ctx = {0}; const mbedtls_md_info_t *info = NULL; mbedtls_md_init(&ctx); info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); mbedtls_md_setup(&ctx, info, 1); mbedtls_md_hmac_starts(&ctx, (void *)base64_tmp, base64_len); mbedtls_md_hmac_update(&ctx, (void *)header, strlen(header)); mbedtls_md_hmac_finish(&ctx, (void *)message); mbedtls_md_free(&ctx); mbedtls_base64_encode((unsigned char*)base64_tmp, 128, (unsigned int*)&base64_len, (const unsigned char*)message, 20);//SHA-1 算法输出为20字节 /* 鉴权数据原为header中数据,因本模组平台仅可使用最小系统升级方案,不支持header配置,故需将header数据以参数形式添加进url中(OneNET平台支持该方式) */ sprintf(download_url + strlen((char*)download_url), "?res=userid%s%s&et=%ld&method=sha1&sign=", "%2F", OneNET_userid, et); for(int i = 0; i < base64_len; i++) { if((base64_tmp[i] == '+') || (base64_tmp[i] == '/') || (base64_tmp[i] == '=')) { sprintf(download_url+strlen(download_url), "%s", (base64_tmp[i] == '+')?("%2B"):((base64_tmp[i] == '/')?("%2F"):("%3D"))); } else { sprintf(download_url+strlen(download_url), "%c", base64_tmp[i]); } } cm_log_printf(0, "[OneNET] download_url:%s\r\n", download_url); cm_demo_printf("[OneNET] download_url:%s\r\n", download_url); cm_fota_set_ota_plan(CM_FOTA_ASR_PLAN_MINI_INTEGRATE); cm_fota_res_callback_register((cm_fota_result_callback)__cm_fota_cb); return cm_fota_set_url(download_url); } /** * @brief 上报当前设备升级完成状态 * * @return * = 0 - 存在升级任务 \n * = -1 - 失败或者不存在升级任务 * * @details 所使用的OneNET接口地址为http://ota.heclouds.com/fuse-ota/{pro_id}/{dev_name}/{tid}/status \n * 参考网页https://open.iot.10086.cn/doc/v5/fuse/detail/1449 \n * 此接口示例用于模组升级完成时向平台上报升级完成状态,不含上报其余状态逻辑 \n * 与平台交互过程中使用鉴权信息会过期,开发使用过程中须保证在时间过期前完成升级。安全鉴权参考https://open.iot.10086.cn/doc/v5/fuse/detail/1464 \n * 因为OneNET平台会持续迭代,本demo示例在2023年6月5日可以正常使用OneNET FOTA功能,但不能保证后续OneNET平台版本迭代后还可使用 \n * 本接口为示例代码,开发人员可参考开发 */ static int32_t __cm_onenet_fota_report_progress(void) { int32_t ret = -1; char c_tid[16] = {0}; int32_t fd = cm_fs_open("onenet_tid.txt", CM_FS_RB); int32_t f_len = cm_fs_read(fd, c_tid, 32); cm_fs_close(fd); if (0 == f_len) { cm_log_printf(0, "[OneNET] no tid\r\n"); return -1; } cm_httpclient_handle_t client = NULL; ret = cm_httpclient_create((const uint8_t *)"http://ota.heclouds.com", NULL, &client); if (CM_HTTP_RET_CODE_OK != ret || NULL == client) { cm_log_printf(0, "[OneNET] cm_httpclient_create() error!\r\n"); return -1; } cm_httpclient_cfg_t client_cfg; client_cfg.ssl_enable = false; client_cfg.ssl_id = 0; client_cfg.cid = 0; client_cfg.conn_timeout = HTTPCLIENT_CONNECT_TIMEOUT_DEFAULT; client_cfg.rsp_timeout = HTTPCLIENT_WAITRSP_TIMEOUT_DEFAULT; client_cfg.dns_priority = 0; ret = cm_httpclient_set_cfg(client, client_cfg); char path[128] = {0}; char header[256] = {0}; char message[128] = {0}; char content[64] = "{\"step\":201}"; //升级成功,此时平台会把设备的版本号修改为任务的目标版本(设备状态变成:升级完成) unsigned char base64_tmp[128] = {0}; int32_t et = cm_rtc_get_current_time() + 2 * 24 * 60 * 60; sprintf(path, "/fuse-ota"); sprintf(path + strlen((char*)path), "/%s/%s/%s/status", OneNET_pid, OneNET_devname, c_tid); sprintf(header, "%ld\nsha1\nuserid/%s\n2022-05-01", et, OneNET_userid); int base64_len = 0; mbedtls_base64_decode((unsigned char*)base64_tmp, 128, (unsigned int*)&base64_len, (const unsigned char*)OneNET_userkey, strlen(OneNET_userkey)); mbedtls_md_context_t ctx = {0}; const mbedtls_md_info_t *info = NULL; mbedtls_md_init(&ctx); info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); mbedtls_md_setup(&ctx, info, 1); mbedtls_md_hmac_starts(&ctx, (void *)base64_tmp, base64_len); mbedtls_md_hmac_update(&ctx, (void *)header, strlen(header)); mbedtls_md_hmac_finish(&ctx, (void *)message); mbedtls_md_free(&ctx); mbedtls_base64_encode((unsigned char*)base64_tmp, 128, (unsigned int*)&base64_len, (const unsigned char*)message, 20);//SHA-1 算法输出为20字节 sprintf(header, "Authorization: version=2022-05-01&res=userid%s%s&et=%ld&method=sha1&sign=", "%2F", OneNET_userid, et); for(int i = 0; i < base64_len; i++) { if((base64_tmp[i] == '+') || (base64_tmp[i] == '/') || (base64_tmp[i] == '=')) { sprintf(header+strlen(header), "%s", (base64_tmp[i] == '+')?("%2B"):((base64_tmp[i] == '/')?("%2F"):("%3D"))); } else { sprintf(header+strlen(header), "%c", base64_tmp[i]); } } sprintf(header + strlen(header), "\r\nContent-Type:%s\r\n", "application/json"); cm_httpclient_sync_response_t response = {}; cm_httpclient_sync_param_t param = {HTTPCLIENT_REQUEST_POST, (const uint8_t *)path, strlen(content), (uint8_t *)content}; cm_httpclient_specific_header_set(client, (uint8_t *)header, strlen(header)); ret = cm_httpclient_sync_request(client, param, &response); //发送请求,同步接口 if (CM_HTTP_RET_CODE_OK != ret || NULL == client) { cm_log_printf(0, "[OneNET] cm_httpclient_sync_request() error! ret is %d\r\n", ret); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } else { cm_log_printf(0, "%s\r\n", response.response_content); } cJSON *root = cJSON_Parse((const char *)response.response_content); cJSON *code = cJSON_GetObjectItem(root, "code"); if(code == NULL) { cJSON_Delete(root); cm_log_printf(0, "[OneNET] HTTP GET DATA ERROR\r\n"); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } if(0 == code->valueint) { cJSON_Delete(root); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return 0; } else { cm_log_printf(0, "[OneNET] REPORT VERSION ERROR [%d]\r\n", code->valueint); cJSON_Delete(root); cm_httpclient_specific_header_free(client); cm_httpclient_terminate(client); cm_httpclient_delete(client); client = NULL; return -1; } } /** * UART口FOTA功能调试使用示例 * CM:FOTA:FULLPACKAGE_HTTP //HTTP FOTA完整包升级方式,配置HTTP服务器信息(仅为示例,配置的url不可使用) * CM:FOTA:FULLPACKAGE_FTP //FTP FOTA完整包升级方式,配置FTP服务器信息(仅为示例,配置的url不可使用) * CM:FOTA:ONENET:operation //从OneNET平台获取和配置下载升级包的url,operation为操作参数,详见下方代码 * CM:FOTA:UPGRADE //升级,须在完成配置后使用 */ void cm_test_fota(unsigned char **cmd,int len) { unsigned char operation[20] = {0}; sprintf((char *)operation, "%s", cmd[2]); int ret = 0; if (0 == strcmp((const char *)operation, "FULLPACKAGE_HTTP")) //HTTP FOTA完整包升级方式,配置FOTA信息 { cm_fota_set_ota_plan(CM_FOTA_ASR_PLAN_MINI_INTEGRATE); cm_fota_res_callback_register((cm_fota_result_callback)__cm_fota_cb); ret = cm_fota_set_url("http://xxx.com:8080/system_patch.bin"); //仅作为示例,url不可使用 if (0 != ret){ cm_log_printf(0, "cm_fota_set_url() error"); } } else if (0 == strcmp((const char *)operation, "FULLPACKAGE_FTP")) //FTP FOTA完整包升级方式,配置FOTA信息 { cm_fota_set_ota_plan(CM_FOTA_ASR_PLAN_MINI_INTEGRATE); cm_fota_res_callback_register((cm_fota_result_callback)__cm_fota_cb); ret = cm_fota_set_url("ftp://xxx.com:23/system_patch.bin"); //仅作为示例,url不可使用 if (0 != ret){ cm_log_printf(0, "cm_fota_set_url() error"); } ret = cm_fota_set_auth("user", "password"); if (0 != ret){ cm_log_printf(0, "cm_fota_set_auth() error"); } } else if (0 == strcmp((const char *)operation, "UPGRADE")) //启动升级 { cm_fs_system_info_t fs_info = {0, 0}; cm_fs_getinfo(&fs_info); /* 文件系统剩余空间为0时不建议执行升级,关键文件系统操作可能会失败 */ if (0 == fs_info.free_size) { cm_log_printf(0, "insufficient space left in the file system"); return; } cm_fota_info_t info = {0}; cm_fota_read_config(&info); if (CM_FOTA_TYPE_HTTP_HTTPS == info.fixed_info.fota_mode) { cm_log_printf(0, "HTTP server [%s]", info.fixed_info.url); } else if (CM_FOTA_TYPE_FTP == info.fixed_info.fota_mode) { cm_log_printf(0, "FTP server [%s] [%s] [%s]", info.fixed_info.url, info.fixed_info.username, info.fixed_info.passwd); } else { cm_log_printf(0, "HTTP server error"); return; } osDelay(200); cm_fota_exec_upgrade(); } else if (0 == strcmp((const char *)operation, "ONENET")) //使用OneNET FOTA服务程序示例 { /* 使用本示例需要用户将OneNET_pid、OneNET_userid、OneNET_devname、OneNET_userkey、OneNET_version填写为用户账号及产品的真实内容 */ /* OneNET HTTP升级必要步骤参考链接https://open.iot.10086.cn/doc/v5/fuse/detail/1204 */ /* 与平台交互过程中使用鉴权信息会过期,开发使用过程中须保证在时间过期前完成升级。安全鉴权参考https://open.iot.10086.cn/doc/v5/fuse/detail/1464 */ /* OneNET FOTA(必须使用整包 mini FOTA方案)服务步骤如下 */ /* 步骤1:上报当前版本号(测试指令CM:FOTA:ONENET:VERSION) */ /* 步骤2:增值服务-OTA升级(https://open.iot.10086.cn/console/valueAdded/ota/package)页面添加升级包(差分包),批量升级,跳过验证。该步骤在平台侧网页完成https://open.iot.10086.cn/doc/v5/fuse/detail/1068 */ /* 步骤3:检测升级任务并调用cm_fota_set_url()接口配置升级url(测试指令CM:FOTA:ONENET:CHECK) */ /* 步骤4:下载升级包并升级固件,此步由最小系统完成(测试指令CM:FOTA:UPGRADE) */ /* 步骤5:(待模组升级完成并重启后)上报升级完成状态(测试指令CM:FOTA:ONENET:PROGRESS) */ /* 因为OneNET平台会持续迭代,本demo示例在2023年6月5日可以正常使用OneNET FOTA功能,但不能保证后续OneNET平台版本迭代后还可使用 */ unsigned char onenet_operation[20] = {0}; sprintf((char *)onenet_operation, "%s", cmd[3]); if (0 == strcmp((const char *)onenet_operation, "VERSION")) { ret = __cm_onenet_fota_report_ver(); if (0 == ret) { cm_demo_printf("[OneNET] REPORT VERSION SUCC\r\n"); } else { cm_demo_printf("[OneNET] REPORT VERSION ERROR\r\n"); } } else if (0 == strcmp((const char *)onenet_operation, "CHECK")) { ret = __cm_onenet_fota_check_upgrade_task(); if (0 == ret) { cm_demo_printf("[OneNET] UPGRADE TASK IS EXIST\r\n"); ret = __cm_onenet_fota_set_url(); if (0 == ret) { cm_demo_printf("[OneNET] __cm_onenet_fota_set_url SUCC\r\n"); } else { cm_demo_printf("[OneNET] __cm_onenet_fota_set_url ERROR\r\n"); } } else { cm_demo_printf("[OneNET] CHEAK ERROR OR UPGRADE TASK IS NOT EXIST\r\n"); } } else if (0 == strcmp((const char *)onenet_operation, "PROGRESS")) { ret = __cm_onenet_fota_report_progress(); if (0 == ret) { cm_demo_printf("[OneNET] REPORT PROGRESS SUCC\r\n"); } else { cm_demo_printf("[OneNET] REPORT PROGRESS ERROR\r\n"); } } } else { cm_demo_printf("[FOTA] Illegal operation\n"); } return; }