Files
TencentOS-tiny/components/connectivity/qcloud-iot-hub-sdk-3.1.2/3rdparty/samples/ota/ota_mqtt_sample.c
daishengdong 943db74fc7 merge new qcloud sdk
1. qcloud has a great revolution, the protocol has been changed to implement data template, so the old TencentCloud_SDK developed by us will not work fine now(mqtt still works, but data template will not works fine for recently created product/devices).

2. I merge the official qlcoud sdk(include both the iot-hub and iot-explorer sdk) into the componet/conectivity to support new protocol of data template

3. iot-hub sdk, supply the fundamental iot protocol(like mqtt coap, etc.)
iot-explorer sdk, supply the high level service like data template based on mqtt

4. To know how it works, see qcloud_iot_explorer_sdk_data_template、qcloud_iot_hub_sdk_mqtt example(keil project in board\TencentOS_tiny_EVB_MX_Plus\KEIL\qcloud_iot_explorer_sdk_data_template and  board\TencentOS_tiny_EVB_MX_Plus\KEIL\qcloud_iot_hub_sdk_mqtt)
2019-11-14 15:09:00 +08:00

510 lines
14 KiB
C

/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "lite-utils.h"
#ifdef AUTH_MODE_CERT
static char sg_cert_file[PATH_MAX + 1]; // full path of device cert file
static char sg_key_file[PATH_MAX + 1]; // full path of device key file
#endif
static DeviceInfo sg_devInfo;
#define OTA_BUF_LEN (5000)
static bool sg_pub_ack = false;
static int sg_packet_id = 0;
static void event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
uintptr_t packet_id = (uintptr_t)msg->msg;
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 (sg_packet_id == packet_id)
sg_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;
}
}
/* demo of firmware info management in device side for resuming download from break point */
#define VERSION_FILE_PATH "./local_fw_info.json"
#define KEY_VER "version"
#define KEY_MD5 "md5"
#define KEY_SIZE "downloadSize"
#define KEY_STATE "state"
#define KEY_PREVER "running_version"
static char * get_local_fw_version(char **ver, char **md5, char **size)
{
#define INFO_FILE_MAX_LEN 256
FILE *fp;
int len;
int rlen;
char *preVer;
char *reportVer = NULL;
fp = fopen(VERSION_FILE_PATH, "r");
if(NULL == fp) {
Log_e("open file %s failed", VERSION_FILE_PATH);
goto exit;
}
fseek(fp, 0L, SEEK_END);
len = ftell(fp);
if(len > INFO_FILE_MAX_LEN){
Log_e("%s is too big, pls check", VERSION_FILE_PATH);
goto exit;
}
char *JsonDoc = (char *)HAL_Malloc(len + 10);
if(NULL == JsonDoc){
Log_e("malloc buffer for json file read fail");
goto exit;
}
rewind(fp);
rlen = fread(JsonDoc, 1, len, fp);
if(len != rlen){
Log_e("read data len (%d) less than needed (%d), %s", rlen, len, JsonDoc);
}
*ver = LITE_json_value_of(KEY_VER, JsonDoc);
*md5 = LITE_json_value_of(KEY_MD5, JsonDoc);
*size = LITE_json_value_of(KEY_SIZE, JsonDoc);
preVer = LITE_json_value_of(KEY_PREVER, JsonDoc);
if((NULL != *ver) && (NULL != preVer) && (0 == strcmp(*ver, preVer))){
reportVer = *ver;
HAL_Free(preVer);
}else{
reportVer = preVer;
}
exit:
if(NULL != fp){
fclose(fp);
}
return reportVer;
#undef INFO_FILE_MAX_LEN
}
/* update local firmware info for resuming download from break point */
static int update_local_fw_info(const char *version, const char *preVer, const char *md5, uint32_t downloadedSize)
{
#define INFO_FILE_MAX_LEN 256
FILE *fp;
int wlen;
int ret = QCLOUD_RET_SUCCESS;
char dataBuff[INFO_FILE_MAX_LEN];
memset(dataBuff, 0, INFO_FILE_MAX_LEN);
HAL_Snprintf(dataBuff, INFO_FILE_MAX_LEN, "{\"%s\":\"%s\", \"%s\":\"%s\",\"%s\":%d,\"%s\":\"%s\"}",\
KEY_VER, version, KEY_MD5, md5, KEY_SIZE, downloadedSize, \
KEY_PREVER, (NULL == preVer)?"1.0.0": preVer);
fp = fopen(VERSION_FILE_PATH, "w");
if(NULL == fp) {
Log_e("open file %s failed", VERSION_FILE_PATH);
ret = QCLOUD_ERR_FAILURE;
goto exit;
}
wlen = fwrite(dataBuff, 1, strlen(dataBuff), fp);
if(wlen != strlen(dataBuff)){
Log_e("save version to file err");
ret = QCLOUD_ERR_FAILURE;
}
exit:
if(NULL != fp){
fclose(fp);
}
return ret;
#undef INFO_FILE_MAX_LEN
}
/* get local firmware offset for resuming download from break point */
static int getFwOffset(void *h_ota, char *local_ver, char *local_md5, char *local_size, uint32_t *offset, uint32_t *size_file)
{
char version[128], md5sum[33];
uint32_t local_len;
int Ret;
Ret = IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, version, 128);
Ret |= IOT_OTA_Ioctl(h_ota, IOT_OTAG_MD5SUM, md5sum, 33);
Ret |= IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, size_file, 4);
local_len = (NULL == local_size)?0:atoi(local_size);
if((NULL == local_ver)||(NULL == local_md5)||(NULL == local_size)){
*offset = 0;
}
else if((0 != strcmp(local_ver, version))||(0 != strcmp(local_md5, md5sum))||(local_len > *size_file)){
*offset = 0;
}else {
*offset = local_len;
}
return Ret;
}
/* calculate left MD5 for resuming download from break point */
static int cal_exist_fw_md5(void *h_ota, FILE *fp, size_t size){
#define BUFF_LEN 1024
char buff[BUFF_LEN];
size_t rlen;
int Ret = QCLOUD_RET_SUCCESS;
while((size > 0) && (!feof(fp))){
rlen = (size > BUFF_LEN)?BUFF_LEN:size;
if(rlen != fread(buff, 1, rlen, fp)){
Log_e("read data len not expected");
Ret = QCLOUD_ERR_FAILURE;
break;
}
IOT_OTA_UpdateClientMd5(h_ota, buff, rlen);
size -= rlen;
}
return Ret;
#undef BUFF_LEN
}
static int _setup_connect_init_params(MQTTInitParams* initParams)
{
int ret;
ret = HAL_GetDevInfo((void *)&sg_devInfo);
if(QCLOUD_RET_SUCCESS != ret){
return ret;
}
initParams->device_name = sg_devInfo.device_name;
initParams->product_id = sg_devInfo.product_id;
#ifdef AUTH_MODE_CERT
char certs_dir[PATH_MAX + 1] = "certs";
char current_path[PATH_MAX + 1];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL)
{
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
sprintf(sg_cert_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_cert_file_name);
sprintf(sg_key_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_key_file_name);
initParams->cert_file = sg_cert_file;
initParams->key_file = sg_key_file;
#else
initParams->device_secret = sg_devInfo.device_secret;
#endif
initParams->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;
return QCLOUD_RET_SUCCESS;
}
int main(int argc, char **argv)
{
IOT_Log_Set_Level(eLOG_DEBUG);
int rc;
uint32_t firmware_valid;
char version[128], md5sum[33];
uint32_t size_downloaded, size_file;
int len;
int ota_over = 0;
bool upgrade_fetch_success = true;
char buf_ota[OTA_BUF_LEN];
FILE *fp = NULL;
uint32_t offset = 0;
MQTTInitParams init_params = DEFAULT_MQTTINIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
void *client = IOT_MQTT_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return QCLOUD_ERR_FAILURE;
}
void *h_ota = IOT_OTA_Init(sg_devInfo.product_id, sg_devInfo.device_name, client);
if (NULL == h_ota) {
Log_e("initialize OTA failed");
return QCLOUD_ERR_FAILURE;
}
IOT_MQTT_Yield(client, 1000); //make sure subscribe success
char *local_ver = NULL, *local_md5 = NULL, *local_size = NULL, *reportVer = NULL;
reportVer = get_local_fw_version(&local_ver, &local_md5, &local_size);
Log_d("local_ver:%s local_md5:%s, local_size:%s", local_ver, local_md5, local_size);
/* Must report version first */
if (0 > IOT_OTA_ReportVersion(h_ota, (NULL == reportVer)?"1.0.0": reportVer)) {
Log_e("report OTA version failed");
goto exit;
}
do {
Log_i("wait for ota upgrade command...");
IOT_MQTT_Yield(client, 200);
if (IOT_OTA_IsFetching(h_ota)) {
/*check pre-download finished or not*/
/*if version & MD5 is the same,then pre-download not finished,get breakpoint continue download.otherwise the version is new*/
rc = getFwOffset(h_ota, local_ver, local_md5, local_size, &offset, &size_file);
if(QCLOUD_RET_SUCCESS != rc){
Log_e("get fw offset err,rc:%d",rc);
upgrade_fetch_success = false;
break;
}
/*cal file md5*/
//Log_d("Get offset:%d(%x)", offset, offset);
if(offset > 0){
if (NULL == (fp = fopen("ota.bin", "ab+"))) {
Log_e("open file failed");
upgrade_fetch_success = false;
break;
}
if(QCLOUD_RET_SUCCESS != cal_exist_fw_md5(h_ota, fp, offset)){
Log_e("cal exist fw md5 failed");
upgrade_fetch_success = false;
break;
}
}else{
if (NULL == (fp = fopen("ota.bin", "wb+"))) {
Log_e("open file failed");
upgrade_fetch_success = false;
break;
}
}
/*set offset and start http connect*/
fseek(fp, offset, SEEK_SET);
rc = IOT_OTA_StartDownload(h_ota, offset, size_file);
if(QCLOUD_RET_SUCCESS != rc){
Log_e("OTA download start err,rc:%d",rc);
upgrade_fetch_success = false;
break;
}
do {
len = IOT_OTA_FetchYield(h_ota, buf_ota, OTA_BUF_LEN, 1);
if (len > 0) {
if (1 != fwrite(buf_ota, len, 1, fp)) {
Log_e("write data to file failed");
upgrade_fetch_success = false;
break;
}
} else if (len < 0) {
Log_e("download fail rc=%d", len);
upgrade_fetch_success = false;
break;
}
fflush(fp);
/* get OTA information and update local info */
IOT_OTA_Ioctl(h_ota, IOT_OTAG_FETCHED_SIZE, &size_downloaded, 4);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &size_file, 4);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_MD5SUM, md5sum, 33);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, version, 128);
rc = update_local_fw_info(version, reportVer, md5sum, size_downloaded);
if(QCLOUD_RET_SUCCESS != rc){
Log_e("update local fw info err,rc:%d", rc);
}
IOT_MQTT_Yield(client, 100);
} while (!IOT_OTA_IsFetchFinish(h_ota));
fclose(fp);
fp = NULL;
/* Must check MD5 match or not */
if (upgrade_fetch_success) {
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;
rc = update_local_fw_info(NULL, reportVer, NULL, 0);
if(QCLOUD_RET_SUCCESS != rc){
Log_e("update local fw info err,rc:%d", rc);
}
} else {
Log_i("The firmware is valid");
upgrade_fetch_success = true;
}
}
ota_over = 1;
}
HAL_SleepMs(2000);
} while(!ota_over);
if (upgrade_fetch_success)
{
/* begin execute OTA files, should report upgrade begin */
sg_packet_id = IOT_OTA_ReportUpgradeBegin(h_ota);
if (0 > sg_packet_id) {
Log_e("report OTA begin failed error:%d", sg_packet_id);
return QCLOUD_ERR_FAILURE;
}
while (!sg_pub_ack) {
HAL_SleepMs(1000);
IOT_MQTT_Yield(client, 200);
}
sg_pub_ack = false;
//* add your own upgrade logic here*//
//* fw_upgrade.....
if(QCLOUD_RET_SUCCESS == rc){
/* if upgrade success */
/* after execute OTA files, should report upgrade result */
sg_packet_id = IOT_OTA_ReportUpgradeSuccess(h_ota, NULL);
if (0 > sg_packet_id) {
Log_e("report OTA result failed error:%d", sg_packet_id);
return QCLOUD_ERR_FAILURE;
}
while (!sg_pub_ack) {
HAL_SleepMs(1000);
IOT_MQTT_Yield(client, 200);
}
rc = update_local_fw_info(version, version, md5sum, size_downloaded); // just for example, add your own logic
sg_pub_ack = false;
}else{
/* if upgrade fail */
sg_packet_id = IOT_OTA_ReportUpgradeFail(h_ota, NULL);
if (0 > sg_packet_id) {
Log_e("report OTA result failed error:%d", sg_packet_id);
return QCLOUD_ERR_FAILURE;
}
while (!sg_pub_ack) {
HAL_SleepMs(1000);
IOT_MQTT_Yield(client, 200);
}
rc = update_local_fw_info(NULL, reportVer, NULL, 0); // just for example, add your own logic
sg_pub_ack = false;
}
}
exit:
if(NULL != fp){
fclose(fp);
fp = NULL;
}
if(NULL != local_ver){
reportVer = (reportVer == local_ver)?NULL: reportVer;
HAL_Free(local_ver);
local_ver = NULL;
}
if(NULL != local_md5){
HAL_Free(local_md5);
local_md5 = NULL;
}
if(NULL != local_size){
HAL_Free(local_size);
local_size = NULL;
}
if(NULL != reportVer){
HAL_Free(reportVer);
reportVer = NULL;
}
IOT_OTA_Destroy(h_ota);
IOT_MQTT_Destroy(&client);
return 0;
}