当前位置: 首页 > news >正文

STM32+腾讯物联网平台OTA升级详细教程

STM32+腾讯物联网平台OTA升级详细教程

  • 一、什么是OTA升级
  • 二、腾讯物联网SDK移植
  • 三、STM32 OTA代码移植
  • 四、腾讯平台操作步骤

一、什么是OTA升级


什么是OTA升级

  1. 定义

    • OTA(Over-The-Air)升级是一种通过无线网络对设备进行软件更新的技术。它广泛应用于智能手机、智能家居设备、汽车等电子设备中,允许用户在不连接电脑或使用物理介质的情况下,直接通过互联网下载并安装更新。
  2. 应用场景

    • 智能手机:更新操作系统、修复安全漏洞、改进功能。
    • 汽车:更新车载系统、优化驾驶体验、提升安全性。
    • 智能家居设备:更新固件、增加新功能、提高性能。
  3. 升级过程

    1. 检测更新:设备自动或手动检查是否有可用的更新。
    2. 下载更新包:从服务器下载新的软件版本。
    3. 安装更新:设备安装下载的更新包。
    4. 重启设备:部分更新需要重启设备以完成安装。
  4. 优势

    • 便捷性:用户无需亲自前往服务中心即可完成更新。
    • 及时性:厂商可以快速推送重要更新和修复。
    • 成本效益:减少物理维护的成本和时间。
  5. 注意事项

    • 网络连接:确保设备连接到稳定的网络。
    • 电量充足:避免在低电量情况下进行更新。
    • 备份数据:重要数据建议提前备份,以防意外丢失。

二、腾讯物联网SDK移植

参考我这篇博文STM32+rt-thread使用MQTT协议连接腾讯物联网平台

三、STM32 OTA代码移植

直接使用腾讯sdk示例的代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include "lite-utils.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_getopt.h"#define FW_RUNNING_MCU_VERSION    "mcu_v1.0.0"
#define FW_RUNNING_MODULE_VERSION "module_v1.0.0"#define KEY_VER  "version"
#define KEY_SIZE "downloaded_size"#define FW_VERSION_MAX_LEN        32
#define FW_FILE_PATH_MAX_LEN      128
#define OTA_BUF_LEN               5000
#define FW_INFO_FILE_DATA_LEN     128
#define OTA_HTTP_MAX_FETCHED_SIZE (50 * 1024)#define MAX_OTA_RETRY_CNT 5typedef struct OTAContextData {void *ota_handle;void *mqtt_client;char  fw_file_path[FW_FILE_PATH_MAX_LEN];char  fw_info_file_path[FW_FILE_PATH_MAX_LEN];// remote_version means version for the FW in the cloud and to be downloadedchar          remote_version[FW_VERSION_MAX_LEN];uint32_t      fw_file_size;IOT_OTAFWType fw_type; /* fw type */// for resuming download/* local_version means downloading but not running */char local_version[FW_VERSION_MAX_LEN];int  downloaded_size;// to make sure report is ackedbool     report_pub_ack;int      report_packet_id;uint32_t ota_fail_cnt;
} OTAContextData;static DeviceInfo sg_devInfo;static void _event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{uintptr_t       packet_id = (uintptr_t)msg->msg;OTAContextData *ota_ctx   = (OTAContextData *)handle_context;switch (msg->event_type) {case MQTT_EVENT_UNDEF:Log_i("undefined event occur.");break;case MQTT_EVENT_DISCONNECT:Log_i("MQTT disconnect.");break;case MQTT_EVENT_RECONNECT:Log_i("MQTT reconnect.");break;case MQTT_EVENT_SUBCRIBE_SUCCESS:Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);break;case MQTT_EVENT_SUBCRIBE_TIMEOUT:Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);break;case MQTT_EVENT_SUBCRIBE_NACK:Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);break;case MQTT_EVENT_PUBLISH_SUCCESS:Log_i("publish success, packet-id=%u", (unsigned int)packet_id);if (ota_ctx->report_packet_id == packet_id)ota_ctx->report_pub_ack = true;break;case MQTT_EVENT_PUBLISH_TIMEOUT:Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);break;case MQTT_EVENT_PUBLISH_NACK:Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);break;default:Log_i("Should NOT arrive here.");break;}
}static int _setup_connect_init_params(MQTTInitParams *initParams, void *ota_ctx, DeviceInfo *device_info)
{initParams->region      = device_info->region;initParams->product_id  = device_info->product_id;initParams->device_name = device_info->device_name;#ifdef AUTH_MODE_CERTchar  certs_dir[16] = "certs";char  current_path[128];char *cwd = getcwd(current_path, sizeof(current_path));if (cwd == NULL) {Log_e("getcwd return NULL");return QCLOUD_ERR_FAILURE;}#ifdef WIN32HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,device_info->dev_cert_file_name);HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,device_info->dev_key_file_name);
#elseHAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,device_info->dev_cert_file_name);HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,device_info->dev_key_file_name);
#endif#elseinitParams->device_secret = device_info->device_secret;
#endifinitParams->command_timeout        = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;initParams->auto_connect_enable  = 1;initParams->event_handle.h_fp    = _event_handler;initParams->event_handle.context = ota_ctx;return QCLOUD_RET_SUCCESS;
}static void _wait_for_pub_ack(OTAContextData *ota_ctx, int packet_id)
{int wait_cnt              = 10;ota_ctx->report_pub_ack   = false;ota_ctx->report_packet_id = packet_id;while (!ota_ctx->report_pub_ack) {HAL_SleepMs(500);IOT_MQTT_Yield(ota_ctx->mqtt_client, 500);if (wait_cnt-- == 0) {Log_e("wait report pub ack timeout!");break;}}ota_ctx->report_pub_ack = false;return;
}/*********************************************************************************** OTA file operations START* these are platform-dependant functions* POSIX FILE is used in this sample code**********************************************************************************/
// calculate left MD5 for resuming download from break point
static int _cal_exist_fw_md5(OTAContextData *ota_ctx)
{char   buff[OTA_BUF_LEN];size_t rlen, total_read = 0;int    ret = QCLOUD_RET_SUCCESS;ret = IOT_OTA_ResetClientMD5(ota_ctx->ota_handle);if (ret) {Log_e("reset MD5 failed: %d", ret);return QCLOUD_ERR_FAILURE;}void *fp = HAL_FileOpen(ota_ctx->fw_file_path, "ab+");if (NULL == fp) {Log_e("open file %s failed", ota_ctx->fw_file_path);return QCLOUD_ERR_FAILURE;}// rewind(fp);size_t size = ota_ctx->downloaded_size;while ((size > 0) && (!HAL_FileEof(fp))) {rlen = (size > OTA_BUF_LEN) ? OTA_BUF_LEN : size;if (rlen != HAL_FileRead(buff, 1, rlen, fp)) {Log_e("read data len not expected");ret = QCLOUD_ERR_FAILURE;break;}IOT_OTA_UpdateClientMd5(ota_ctx->ota_handle, buff, rlen);size -= rlen;total_read += rlen;}HAL_FileClose(fp);Log_d("total read: %d", total_read);return ret;
}/* update local firmware info for resuming download from break point */
static int _update_local_fw_info(OTAContextData *ota_ctx)
{void *fp;int   wlen;int   ret = QCLOUD_RET_SUCCESS;char  data_buf[FW_INFO_FILE_DATA_LEN];memset(data_buf, 0, sizeof(data_buf));HAL_Snprintf(data_buf, sizeof(data_buf), "{\"%s\":\"%s\", \"%s\":%d}", KEY_VER, ota_ctx->remote_version, KEY_SIZE,ota_ctx->downloaded_size);fp = HAL_FileOpen(ota_ctx->fw_info_file_path, "w");if (NULL == fp) {Log_e("open file %s failed", ota_ctx->fw_info_file_path);ret = QCLOUD_ERR_FAILURE;goto exit;}wlen = HAL_FileWrite(data_buf, 1, strlen(data_buf), fp);if (wlen != strlen(data_buf)) {Log_e("save version to file err");ret = QCLOUD_ERR_FAILURE;}exit:if (NULL != fp) {HAL_FileClose(fp);}return ret;
}static int _get_local_fw_info(char *file_name, char *local_version)
{int  len;int  rlen;char json_doc[FW_INFO_FILE_DATA_LEN] = {0};void *fp = HAL_FileOpen(file_name, "r");if (NULL == fp) {Log_e("open file %s failed", file_name);return 0;}HAL_FileSeek(fp, 0L, SEEK_END);len = ftell(fp);if (len > FW_INFO_FILE_DATA_LEN) {Log_e("%s is too big, pls check", file_name);HAL_FileClose(fp);return 0;}rewind(fp);rlen = HAL_FileRead(json_doc, 1, len, fp);if (len != rlen) {Log_e("read data len (%d) less than needed (%d), %s", rlen, len, json_doc);HAL_FileClose(fp);return 0;}char *version = LITE_json_value_of(KEY_VER, json_doc);char *size    = LITE_json_value_of(KEY_SIZE, json_doc);if ((NULL == version) || (NULL == size)) {if (version)HAL_Free(version);if (size)HAL_Free(size);HAL_FileClose(fp);return 0;}int local_size = atoi(size);HAL_Free(size);if (local_size <= 0) {Log_w("local info offset invalid: %d", local_size);local_size = 0;} else {strncpy(local_version, version, FW_VERSION_MAX_LEN);}HAL_Free(version);HAL_FileClose(fp);return local_size;
}/* get local firmware offset for resuming download from break point */
static int _update_fw_downloaded_size(OTAContextData *ota_ctx)
{int local_size = _get_local_fw_info(ota_ctx->fw_info_file_path, ota_ctx->local_version);if (local_size == 0) {ota_ctx->downloaded_size = 0;return 0;}if ((0 != strcmp(ota_ctx->local_version, ota_ctx->remote_version)) ||(ota_ctx->downloaded_size > ota_ctx->fw_file_size)) {ota_ctx->downloaded_size = 0;return 0;}ota_ctx->downloaded_size = local_size;Log_i("calc MD5 for resuming download from offset: %d", ota_ctx->downloaded_size);int ret = _cal_exist_fw_md5(ota_ctx);if (ret) {Log_e("regen OTA MD5 error: %d", ret);HAL_FileRemove(ota_ctx->fw_info_file_path);ota_ctx->downloaded_size = 0;return 0;}Log_d("local MD5 update done!");return local_size;
}static int _delete_fw_info_file(char *file_name)
{return HAL_FileRemove(file_name);
}static int _save_fw_data_to_file(char *file_name, uint32_t offset, char *buf, int len)
{void *fp;if (offset > 0) {if (NULL == (fp = HAL_FileOpen(file_name, "ab+"))) {Log_e("open file failed");return QCLOUD_ERR_FAILURE;}} else {if (NULL == (fp = HAL_FileOpen(file_name, "wb+"))) {Log_e("open file failed");return QCLOUD_ERR_FAILURE;}}HAL_FileSeek(fp, offset, SEEK_SET);if (1 != HAL_FileWrite(buf, len, 1, fp)) {Log_e("write data to file failed");HAL_FileClose(fp);return QCLOUD_ERR_FAILURE;}HAL_FileFlush(fp);HAL_FileClose(fp);return 0;
}static char *_get_local_fw_running_version(IOT_OTAFWType type)
{// asuming the version is inside the code and binary// you can also get from a meta fileif (type == IOT_OTA_FWTYPE_MCU) {Log_i("FW running mcu version: %s", FW_RUNNING_MCU_VERSION);return FW_RUNNING_MCU_VERSION;}Log_i("FW running module version: %s", FW_RUNNING_MODULE_VERSION);return FW_RUNNING_MODULE_VERSION;
}
/*********************************************************************************** OTA file operations END**********************************************************************************/// main OTA cycle
bool process_ota(OTAContextData *ota_ctx)
{bool  download_finished     = false;bool  upgrade_fetch_success = true;char  buf_ota[OTA_BUF_LEN]  = {0};int   rc                    = 0;void *h_ota                 = ota_ctx->ota_handle;int   packet_id             = 0;int   local_offset          = 0;int   last_downloaded_size  = 0;/* Must report version first */if (0 > IOT_OTA_ReportVersion(h_ota, IOT_OTA_FWTYPE_MCU, _get_local_fw_running_version(IOT_OTA_FWTYPE_MCU))) {Log_e("report OTA version failed");upgrade_fetch_success = false;goto end_of_ota;}if (0 > IOT_OTA_ReportVersion(h_ota, IOT_OTA_FWTYPE_MODULE, _get_local_fw_running_version(IOT_OTA_FWTYPE_MODULE))) {Log_e("report OTA version failed");upgrade_fetch_success = false;goto end_of_ota;}do {IOT_MQTT_Yield(ota_ctx->mqtt_client, 200);Log_i("wait for ota upgrade command...");begin_of_ota:// recv the upgrade cmdif (IOT_OTA_IsFetching(h_ota)) {IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &ota_ctx->fw_file_size, 4);IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, ota_ctx->remote_version, FW_VERSION_MAX_LEN);IOT_OTA_Ioctl(h_ota, IOT_OTAG_FWTYPE, &ota_ctx->fw_type, 4);HAL_Snprintf(ota_ctx->fw_file_path, FW_FILE_PATH_MAX_LEN, "./FW_%s.bin", ota_ctx->remote_version);HAL_Snprintf(ota_ctx->fw_info_file_path, FW_FILE_PATH_MAX_LEN, "./FW_%s.json", ota_ctx->remote_version);/* check if pre-downloading finished or not *//* if local FW downloaded size (ota_ctx->downloaded_size) is not zero, it* will do resuming download */local_offset = _update_fw_downloaded_size(ota_ctx);if (ota_ctx->fw_file_size == local_offset) {  // have already downloadedupgrade_fetch_success = true;goto end_of_download;}/*set offset and start http connect*/rc = IOT_OTA_StartDownload(h_ota, ota_ctx->downloaded_size, ota_ctx->fw_file_size,OTA_HTTP_MAX_FETCHED_SIZE);if (QCLOUD_RET_SUCCESS != rc) {Log_e("OTA download start err,rc:%d", rc);upgrade_fetch_success = false;goto end_of_ota;}Log_d("remote fw type : %d %s", ota_ctx->fw_type,ota_ctx->fw_type == IOT_OTA_FWTYPE_MCU ? IOT_OTA_FWTYPE_MCU_STR : IOT_OTA_FWTYPE_MODULE_STR);// download and save the fwdo {int len = IOT_OTA_FetchYield(h_ota, buf_ota, OTA_BUF_LEN, 1);if (len > 0) {rc = _save_fw_data_to_file(ota_ctx->fw_file_path, ota_ctx->downloaded_size, buf_ota, len);if (rc) {Log_e("write data to file failed rc=%d", rc);upgrade_fetch_success = false;ota_ctx->ota_fail_cnt = MAX_OTA_RETRY_CNT;goto end_of_ota;}} else if (len <= 0) {Log_e("download fail rc=%d", len);upgrade_fetch_success = false;if (len == IOT_OTA_ERR_FETCH_AUTH_FAIL || len == IOT_OTA_ERR_FETCH_NOT_EXIST) {ota_ctx->ota_fail_cnt = MAX_OTA_RETRY_CNT;}goto end_of_ota;}/* get OTA information and update local info */IOT_OTA_Ioctl(h_ota, IOT_OTAG_FETCHED_SIZE, &ota_ctx->downloaded_size, 4);rc = _update_local_fw_info(ota_ctx);if (QCLOUD_RET_SUCCESS != rc) {Log_e("update local fw info err,rc:%d", rc);}// quit ota process as something wrong with mqttrc = IOT_MQTT_Yield(ota_ctx->mqtt_client, 100);if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) {Log_e("MQTT error: %d", rc);upgrade_fetch_success = false;goto end_of_ota;}} while (!IOT_OTA_IsFetchFinish(h_ota));/* Must check MD5 match or not */end_of_download:if (upgrade_fetch_success) {// download is finished, delete the fw info file_delete_fw_info_file(ota_ctx->fw_info_file_path);uint32_t firmware_valid;IOT_OTA_Ioctl(h_ota, IOT_OTAG_CHECK_FIRMWARE, &firmware_valid, 4);if (0 == firmware_valid) {Log_e("The firmware is invalid");upgrade_fetch_success = false;goto end_of_ota;} else {Log_i("The firmware is valid");upgrade_fetch_success = true;}}download_finished = true;}if (!download_finished)HAL_SleepMs(1000);} while (!download_finished);// do some post-download stuff for your needend_of_ota:if (!upgrade_fetch_success) {// retry againif (IOT_MQTT_IsConnected(ota_ctx->mqtt_client)) {if ((ota_ctx->downloaded_size - last_downloaded_size) != OTA_HTTP_MAX_FETCHED_SIZE) {ota_ctx->ota_fail_cnt++;}if (ota_ctx->ota_fail_cnt <= MAX_OTA_RETRY_CNT) {upgrade_fetch_success = true;last_downloaded_size  = ota_ctx->downloaded_size;Log_e("OTA failed, retry %drd time!", ota_ctx->ota_fail_cnt);HAL_SleepMs(1000);goto begin_of_ota;} else {ota_ctx->ota_fail_cnt = 0;Log_e("report download fail!");packet_id = IOT_OTA_ReportUpgradeFail(h_ota, NULL);}}} else if (upgrade_fetch_success) {packet_id             = IOT_OTA_ReportUpgradeSuccess(h_ota, NULL);ota_ctx->ota_fail_cnt = 0;}_wait_for_pub_ack(ota_ctx, packet_id);return upgrade_fetch_success;
}static int parse_arguments(int argc, char **argv)
{int c;while ((c = utils_getopt(argc, argv, "c:l:")) != EOF) switch (c) {case 'c':if (HAL_SetDevInfoFile(utils_optarg))return -1;break;default:HAL_Printf("usage: %s [options]\n""  [-c <config file for DeviceInfo>] \n",argv[0]);return -1;}return 0;
}int main(int argc, char **argv)
{int             rc;OTAContextData *ota_ctx     = NULL;void           *mqtt_client = NULL;void           *h_ota       = NULL;IOT_Log_Set_Level(eLOG_DEBUG);// parse arguments for device info filerc = parse_arguments(argc, argv);if (rc != QCLOUD_RET_SUCCESS) {Log_e("parse arguments error, rc = %d", rc);return rc;}ota_ctx = (OTAContextData *)HAL_Malloc(sizeof(OTAContextData));if (ota_ctx == NULL) {Log_e("malloc failed");goto exit;}memset(ota_ctx, 0, sizeof(OTAContextData));rc = HAL_GetDevInfo(&sg_devInfo);if (QCLOUD_RET_SUCCESS != rc) {Log_e("get device info failed: %d", rc);goto exit;}// setup MQTT init paramsMQTTInitParams init_params = DEFAULT_MQTTINIT_PARAMS;rc                         = _setup_connect_init_params(&init_params, ota_ctx, &sg_devInfo);if (rc != QCLOUD_RET_SUCCESS) {Log_e("init params err,rc=%d", rc);return rc;}// create MQTT mqtt_client and connect to servermqtt_client = IOT_MQTT_Construct(&init_params);if (mqtt_client != NULL) {Log_i("Cloud Device Construct Success");} else {Log_e("Cloud Device Construct Failed");return QCLOUD_ERR_FAILURE;}// init OTA handleh_ota = IOT_OTA_Init(sg_devInfo.product_id, sg_devInfo.device_name, mqtt_client);if (NULL == h_ota) {Log_e("initialize OTA failed");goto exit;}ota_ctx->ota_handle  = h_ota;ota_ctx->mqtt_client = mqtt_client;bool ota_success;do {// mqtt should be ready firstrc = IOT_MQTT_Yield(mqtt_client, 500);if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {HAL_SleepMs(1000);continue;} else if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) {if (rc == QCLOUD_ERR_MQTT_RECONNECT_TIMEOUT) {Log_e("exit. mqtt reconnect timeout! Please check the network connection, or try to increase ""MAX_RECONNECT_WAIT_INTERVAL(%d)",MAX_RECONNECT_WAIT_INTERVAL);} else {Log_e("exit with error: %d", rc);}break;}// OTA processota_success = process_ota(ota_ctx);if (!ota_success) {Log_e("OTA failed! Do it again");HAL_SleepMs(2000);}} while (!ota_success);exit:if (NULL != ota_ctx)HAL_Free(ota_ctx);if (NULL != h_ota)IOT_OTA_Destroy(h_ota);IOT_MQTT_Destroy(&mqtt_client);return 0;
}

修改固件存储位置修改这儿:

HAL_Snprintf(ota_ctx->fw_file_path, FW_FILE_PATH_MAX_LEN, "./FW_%s.bin", ota_ctx->remote_version);
HAL_Snprintf(ota_ctx->fw_info_file_path, FW_FILE_PATH_MAX_LEN, "./FW_%s.json", ota_ctx->remote_version);

四、腾讯平台操作步骤

在这里插入图片描述
在这里插入图片描述
填写相关信息
在这里插入图片描述
添加完成后选择固件升级
在这里插入图片描述
填写信息后点击提交
在这里插入图片描述
完成后STM32就会接受到升级推送消息,升级完成后发送升级成功消息,平台就会显示升级成功。
在这里插入图片描述

http://www.xdnf.cn/news/610597.html

相关文章:

  • 华为OD机试_2025 B卷_爱吃蟠桃的孙悟空(Python,100分)(附详细解题思路)
  • 从逆流监测到智慧用电:ADL200N-CT系列单相导轨表赋能家庭绿色能源
  • ubuntu设置开机不输密码笔记
  • 解决Vue项目依赖错误:使用electron-vite重建
  • 提升开发运维效率:原力棱镜游戏公司的 Amazon Q Developer CLI 实践
  • 使用clickhouse的ReplacingMergeTree引擎表做活跃玩家信息表
  • Unity 打包程序全屏置顶无边框
  • 宽松相等(==) 的转换规则(仅考虑基本数据类型)
  • 怎么判断一个Android APP使用了Ionic这个跨端框架
  • 智能交通红绿灯系统(Python)
  • TCP 三次握手,第二次握手报文丢失会发生什么?
  • IP隧道技术中数据包头部的变化分析:必然增加的封装机制
  • (15)关于窗体的右键菜单的学习与使用,这关系到了信号与事件 event
  • 特殊的完全平方数
  • 【MySQL】 数据库基础数据类型
  • 【c++】: c++11线程库
  • 【Hexo】3.主题
  • Kafka 集群中,Broker和Controller的关系
  • TPDS-2014《Efficient $k$-means++ Approximation with MapReduce》
  • Python匿名函数(lambda)全面详解
  • 黑马k8s(十三)
  • 【机械视觉】Halcon—【二、Halcon算子全面介绍(超详细版)】
  • 免费AI工具整理
  • HarmonyOS NEXT 使用 relationalStore 实现数据库操作
  • 文章记单词 | 第113篇(六级)
  • 数据挖掘算法大汇总
  • AI推介-大语言模型LLMs论文速览(arXiv方向):2024.12.20-2024.12.25
  • 什么是DAQ采集卡?它的优势有哪些?
  • 【Qt开发】显示类控件——QLCDNumber
  • 搭配前端食用