esp8266-std/fota/esp_ota_mqtt_AliNetease.c

571 lines
19 KiB
C

/*
* Copyright (c) 2014-2016 Alibaba Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 "ota.h"
#include "cJSON.h"
#include "time.h"
#include "cfg.h"
#include "esp_mqtt.h"
#include "esp_MSG_ctrl.h"
#include "iot_import.h"
#include "iot_export.h"
#include "log.h"
#define string_content "msgContent"
#define string_wifiOTAInfo "wifiOTAInfo"
#define string_mcuOTAInfo "mcuOTAInfo"
#define string_OTA_URL "url"
#define string_OTA_MD5 "MD5"
#define string_OTA_TOTALSIZE "totalLength"
#define string_OTA_SEGSIZE "segmentLength"
#define string_OTA_MODE "otaMode"
#define string_OTA_VERSION "ver"
int ota_report_latest_version = 0;
// read buffer by byte still delimiter appear total_count times
// return delimiter current position in buffer
// return < 0 means could not find delim for total_count times
static int read_until_counts(char *buffer, char delim, int len, int total_count)
{
/*TODO: buffer check, delim check, count check,further: do an buffer length limited*/
int i = 0, valid_count = 0;
for (i = 0; i < len; ++i) {
if (buffer[i] == delim) {
valid_count++;
}
if (valid_count == total_count) {
return i;
}
}
return -1;
}
#if (MQTT_SERVER == MQTT_SERVER_NETEASE)
int upgrade_message_parse(cJSON *info_item, ota_info_t *ota_info)
{
cJSON *url_item, *version_item, *totalSize_item, *segSize_item, *md5_item;
ip_addr_t target_ip;
int ret = 0;
totalSize_item = cJSON_GetObjectItem(info_item, string_OTA_TOTALSIZE);
if (!totalSize_item) {
OTA_LOG_EX(LOG_Error, "get total size item\r\n");
return -1;
}
segSize_item = cJSON_GetObjectItem(info_item, string_OTA_SEGSIZE);
if (!segSize_item) {
OTA_LOG_EX(LOG_Error, "get segment size item\r\n");
return -1;
}
md5_item = cJSON_GetObjectItem(info_item, string_OTA_MD5);
if (!md5_item) {
OTA_LOG_EX(LOG_Error, "get MD5 item\r\n");
return -1;
}
version_item = cJSON_GetObjectItem(info_item, string_OTA_VERSION);
if (!version_item) {
OTA_LOG_EX(LOG_Error, "get version item");
return -1;
}
url_item = cJSON_GetObjectItem(info_item, string_OTA_URL);
if (!url_item) {
OTA_LOG_EX(LOG_Error, "get url item\r\n");
return -1;
}
url_item = cJSON_GetObjectItem(info_item, string_OTA_URL);
if (!url_item) {
OTA_LOG_EX(LOG_Error, "get url item\r\n");
return -1;
}
char *p = url_item->valuestring;
// p pointer point at the beginning of whole URL string
// fetch domain name for URL by delimiter '/'
int start_pos = read_until_counts(p, '/', strlen(p), 2);
int end_pos = read_until_counts(p, '/', strlen(p), 3);
char *target_name = (char *)zalloc(end_pos - start_pos);
memcpy(target_name, p + start_pos + 1, end_pos - start_pos - 1);
/* get ip by hostname */
OTA_LOG_EX(LOG_Info,"ota host: %s\r\n", target_name);
do {
ret = netconn_gethostbyname(target_name, &target_ip);
} while (ret);
OTA_LOG_EX(LOG_Info,"ota ip got:\r\n");
/* save ota information to flash, load it after system restart */
memset(ota_info, 0, sizeof(ota_info_t));
ota_info->ota_flag = 1;
ota_info->target_ip = target_ip;
ota_info->port = REMOTE_OTA_SERVER_PORT;
ota_info->bin_size = totalSize_item->valueint;
ota_info->seg_size = segSize_item->valueint;
memcpy(ota_info->md5, md5_item->valuestring, MAX_MD5_LEN);
sprintf(ota_info->latest_version,"%d", version_item->valueint);
ota_info->lastest_version_int = version_item->valueint;
memcpy(ota_info->hostname, target_name, strlen(target_name));
memcpy(ota_info->ota_path, p + end_pos, strlen(p) - end_pos);
return 0;
}
// callback of upgrade topic
void upgrade_message_arrive(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg)
{
iotx_mqtt_topic_info_pt ptopic_info = (iotx_mqtt_topic_info_pt) msg->msg;
cJSON *root, *content_item, *wifo_info_item, * mcu_info_item;
ota_info_t *mcu_ota_info = 0;
ota_info_t *wifi_ota_info = 0;
int rc;
/* print topic name and topic message */
OTA_LOG_EX(LOG_Info, "upgrade topic %s, len %x\r\n", ptopic_info->ptopic, ptopic_info->topic_len);
OTA_LOG_EX(LOG_Info, "upgrade payload %s, len %x\r\n", ptopic_info->payload, ptopic_info->payload_len);
root = cJSON_Parse(ptopic_info->payload);
if (!root) {
OTA_LOG_EX(LOG_Error, "Error before: [%s]\r\n", cJSON_GetErrorPtr());
return;
}
/* content json parse */
content_item = cJSON_GetObjectItem(root, string_content);
if (!root) {
OTA_LOG_EX(LOG_Error, "get content failed\r\n");
return;
}
mcu_info_item = cJSON_GetObjectItem(content_item, string_mcuOTAInfo);
if (mcu_info_item) {
mcu_ota_info = HAL_Malloc(sizeof(ota_info_t));
rc = upgrade_message_parse(mcu_info_item, mcu_ota_info);
if (rc < 0) {
HAL_Free(mcu_ota_info);
mcu_ota_info = 0;
}
} else {
OTA_LOG_EX(LOG_Info, "Do not get MCU info item\r\n");
}
wifo_info_item = cJSON_GetObjectItem(content_item, string_wifiOTAInfo);
if (wifo_info_item) {
wifi_ota_info = HAL_Malloc(sizeof(ota_info_t));
rc = upgrade_message_parse(wifo_info_item, wifi_ota_info);
if (rc < 0) {
HAL_Free(wifi_ota_info);
wifi_ota_info = 0;
}
} else {
OTA_LOG_EX(LOG_Info, "Do not get wifi info item\r\n");
}
/* report mcu ota information */
if (mcu_ota_info) {
ota_mqtt_setInfo(pclient, mcu_ota_info, OTA_DEVICE_MCU);
HAL_Free(mcu_ota_info);
}
/* report wifi ota information */
if (wifi_ota_info) {
ota_mqtt_setInfo(pclient, wifi_ota_info, OTA_DEVICE_WIFI);
HAL_Free(wifi_ota_info);
}
cJSON_Delete(root);
}
// construct report version topic message in json format
void construct_report_version_info(iotx_mqtt_topic_info_t *topic_msg, const char *version_info, char *msg_pub)
{
char MCU_Vesion_info[FIRMWARE_VERSION_MAXLEN];
int msg_len = 0;
HAL_GetMCUFirmwareVesion(MCU_Vesion_info);
memset(msg_pub, 0, MSG_PUB_MAX_SIZE);
sprintf(msg_pub, MQTT_PUB_OTA, version_info, MCU_Vesion_info);
msg_len = strlen(msg_pub);
topic_msg->payload = (void *)msg_pub;
topic_msg->payload_len = msg_len;
}
// construct report process topic message in json format
void construct_report_process_info(char *msg_pub, int type)
{
int msg_len = 0;
int content_type;
content_type = 0;
if (type == OTA_DEVICE_WIFI)
content_type = 1;
if (type == OTA_DEVICE_MCU)
content_type = 2;
sprintf(msg_pub, MQTT_PUB_OTA_START, content_type);
msg_len = strlen(msg_pub);
}
void construct_report_process_info_shadow(char *msg_pub, int type)
{
int msg_len = 0;
msg_pub[0] = '0';
if (type == OTA_DEVICE_WIFI)
msg_pub[0] = '1';
if (type == OTA_DEVICE_MCU)
msg_pub[0] = '2';
msg_pub[1] = 0;
msg_len = strlen(msg_pub);
}
#endif
#if (MQTT_SERVER == MQTT_SERVER_ALIBABA)
// callback of upgrade topic
void upgrade_message_arrive(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg)
{
iotx_mqtt_topic_info_pt ptopic_info = (iotx_mqtt_topic_info_pt) msg->msg;
cJSON *root, *data_item, *size_item, *version_item, *url_item;
int ret = 0;
ip_addr_t target_ip;
ota_info_t *ota_info;
/* print topic name and topic message */
OTA_LOG_EX(LOG_Info, "upgrade topic %s, len %x\r\n", ptopic_info->ptopic, ptopic_info->topic_len);
OTA_LOG_EX(LOG_Info, "upgrade payload %s, len %x\r\n", ptopic_info->payload, ptopic_info->payload_len);
// parse payload which is json format, save it to flash
// ota json format should obey https://help.aliyun.com/document_detail/58106.html?spm=a2c4g.11174283.6.569.JBBgOw
root = cJSON_Parse((char *)ptopic_info->payload);
if (!root) {
OTA_LOG_EX(LOG_Error,"Error before: [%s]\r\n", cJSON_GetErrorPtr());
}
data_item = cJSON_GetObjectItem(root, "data");
if (!data_item) {
OTA_LOG_EX(LOG_Error,"get data item\r\n");
}
size_item = cJSON_GetObjectItem(data_item, "size");
if (!size_item) {
OTA_LOG_EX(LOG_Error,"get size item\r\n");
}
version_item = cJSON_GetObjectItem(data_item, "version");
if (!version_item) {
OTA_LOG_EX(LOG_Error,"get version item\r\n");
}
url_item = cJSON_GetObjectItem(data_item, "url");
if (!url_item) {
OTA_LOG_EX(LOG_Error,"get url item\r\n");
}
char *p = url_item->valuestring;
// p pointer point at the beginning of whole URL string
// fetch domain name for URL by delimiter '/'
int start_pos = read_until_counts(p, '/', strlen(p), 2);
int end_pos = read_until_counts(p, '/', strlen(p), 3);
char *target_name = (char *)zalloc(end_pos - start_pos);
memcpy(target_name, p + start_pos + 1, end_pos - start_pos - 1);
/* get ip by hostname */
OTA_LOG_EX(LOG_Info,"ota host: %s\r\n", target_name);
do {
ret = netconn_gethostbyname(target_name, &target_ip);
} while (ret);
OTA_LOG_EX(LOG_Info,"ota ip got:\r\n");
/* save ota information to flash, load it after system restart */
ota_info = HAL_Malloc(sizeof(ota_info_t));
memset(ota_info, 0, sizeof(ota_info_t));
ota_info->ota_flag = 1;
ota_info->target_ip = target_ip;
ota_info->port = REMOTE_OTA_SERVER_PORT;
ota_info->bin_size = data_item->child->valueint;
memcpy(ota_info->latest_version, version_item->valuestring, strlen(version_item->valuestring));
memcpy(ota_info->hostname, target_name, strlen(target_name));
memcpy(ota_info->ota_path, p + end_pos, strlen(p) - end_pos);
ota_mqtt_setInfo(pclient, ota_info, OTA_DEVICE_WIFI);
HAL_Free(ota_info);
free(target_name);
}
// construct report version topic message in json format
void construct_report_version_info(iotx_mqtt_topic_info_t *topic_msg, const char *version_info, char *msg_pub)
{
int msg_len = 0;
cJSON *root = cJSON_CreateObject();
cJSON *version = cJSON_CreateObject();
cJSON *iNumber = cJSON_CreateNumber(1); // reserved, message ID
cJSON_AddItemToObject(root, "id", iNumber);
cJSON_AddItemToObject(version, "version", cJSON_CreateString((const char *)version_info));
cJSON_AddItemToObject(root, "params", version);
char *str = cJSON_Print(root);
msg_len = strlen(str);
// copy json to publish buffer
memcpy(msg_pub, str, msg_len);
topic_msg->payload = (void *)msg_pub;
topic_msg->payload_len = msg_len;
cJSON_Delete(root);
free(str);
str = NULL;
}
// construct report process topic message in json format
void construct_report_process_info(iotx_mqtt_topic_info_t *topic_msg, char *msg_pub)
{
int msg_len = 0;
memset(topic_msg, 0x0, sizeof(iotx_mqtt_topic_info_t));
cJSON *root = cJSON_CreateObject();
cJSON *params = cJSON_CreateObject();
cJSON *iNumber = cJSON_CreateNumber(1); // reserved, message ID
cJSON_AddItemToObject(root, "id", iNumber);
char c[3] = {0};
sprintf(c, "%d", 100);
cJSON_AddItemToObject(params, "step", cJSON_CreateString((const char *)c));
cJSON_AddItemToObject(params, "desc", cJSON_CreateString("process"));
cJSON_AddItemToObject(root, "params", params);
char *str = cJSON_Print(root);
msg_len = strlen(str);
memcpy(msg_pub, str, msg_len);
topic_msg->payload = (void *)msg_pub;
topic_msg->payload_len = msg_len;
cJSON_Delete(root);
free(str);
str = NULL;
}
#endif
int ota_mqtt_setup(void *pclient)
{
int rc = 0;
iotx_mqtt_topic_info_t topic_msg;
char version_info[FIRMWARE_VERSION_MAXLEN];
int get_len;
char *msg_pub;
/* Subscribe the upgrade topic */
rc = mqtt_client_subscribe(pclient, SUB_TYPE_OTA_UPGRADE, upgrade_message_arrive);
if (rc < 0) {
OTA_LOG_EX(LOG_Error, "MQTT_Sub UPGRADE failed, rc = %d", rc);
}
/* choose current time as current version and report */
get_len = HAL_GetFirmwareVesion(version_info);
if (get_len <= 0) {
OTA_LOG_EX(LOG_Error, "get fimware err:%d\r\n", get_len);
}
OTA_LOG_EX(LOG_Info, "Firmware Version %s\r\n", version_info);
/* construct report version info and set to topic_msg */
msg_pub = HAL_Malloc(MSG_PUB_MAX_SIZE);
memset(msg_pub, 0, MSG_PUB_MAX_SIZE);
construct_report_version_info(&topic_msg, (const char *)version_info, msg_pub);
rc = mqtt_client_publish(pclient, PUB_TYPE_OTA_INFORM, msg_pub);
if (rc < 0) {
OTA_LOG_EX(LOG_Error, "publish error, rc:%d\r\n", rc);
}
HAL_Free(msg_pub);
IOT_MQTT_Yield(pclient, 200);
/* constuct report OTA End */
#if (MQTT_SERVER == MQTT_SERVER_NETEASE)
if (pclient){
iotx_mqtt_topic_info_t topic_msg;
msg_pub = HAL_Malloc(MSG_PUB_MAX_SIZE);
memset(msg_pub, 0, MSG_PUB_MAX_SIZE);
construct_report_process_info_shadow(msg_pub, 0xff);
OTA_LOG_EX(LOG_Info, "OTA Report Message %s\r\n", msg_pub);
rc = mqtt_client_publish(pclient, PUB_TYPE_SHADOW_OTA_INFO, msg_pub);
if (rc < 0) {
HAL_Free(msg_pub);
OTA_LOG_EX(LOG_Error,"error occur when publish,rc:%d\r\n", rc);
return rc;
}
HAL_Free(msg_pub);
IOT_MQTT_Yield(pclient, 200);
}
#endif
return 0;
}
int ota_mqtt_setInfo(void *pclient, ota_info_t *ota_info, int type)
{
int rc = 0;
OTA_LOG_EX(LOG_Info, "OTA setInfo %x, %x\r\n", type, ota_info->ota_flag);
remote_ota_store_info(type, ota_info);
if (type == OTA_DEVICE_WIFI) {
struct OTA_Start_Cmd cmd;
cmd.type = OTA_DEVICE_WIFI;
MSG_ctrl_cmd_put(MSG_CONTROL_CMD_OTA_START, &cmd);
} else {
rc = MSG_ctrl_rsp_OTAInfo(type, ota_info);
}
return rc;
}
int ota_mqtt_start_execute(void *pclient, int type)
{
int rc = 0;
OTA_LOG_EX(LOG_Info, "OTA start %x\r\n", system_upgrade_flag_check());
/* report progress if needed */
#if (MQTT_SERVER == MQTT_SERVER_NETEASE)
if (pclient){
char *msg_pub;
msg_pub = HAL_Malloc(MSG_PUB_MAX_SIZE);
memset(msg_pub, 0, MSG_PUB_MAX_SIZE);
construct_report_process_info(msg_pub, type);
OTA_LOG_EX(LOG_Info, "OTA Report Message %s\r\n", msg_pub);
rc = mqtt_client_publish(pclient, PUB_TYPE_OTA_INFORM, msg_pub);
if (rc < 0) {
HAL_Free(msg_pub);
OTA_LOG_EX(LOG_Error,"error occur when publish,rc:%d\r\n", rc);
return rc;
}
memset(msg_pub, 0, MSG_PUB_MAX_SIZE);
construct_report_process_info_shadow(msg_pub, type);
rc = mqtt_client_publish(pclient, PUB_TYPE_SHADOW_OTA_INFO, msg_pub);
if (rc < 0) {
HAL_Free(msg_pub);
OTA_LOG_EX(LOG_Error,"error occur when publish,rc:%d\r\n", rc);
return rc;
}
HAL_Free(msg_pub);
IOT_MQTT_Yield(pclient, 2000);
}
#endif
#if (MQTT_SERVER == MQTT_SERVER_ALIBABA)
if (pclient){
char *msg_pub;
iotx_mqtt_topic_info_t topic_msg;
OTA_LOG_EX(LOG_Info, "OTA Report %x\r\n", system_upgrade_flag_check());
msg_pub = HAL_Malloc(MSG_PUB_MAX_SIZE);
memset(msg_pub, 0, MSG_PUB_MAX_SIZE);
construct_report_process_info(&topic_msg, msg_pub);
topic_msg.qos = IOTX_MQTT_QOS0;
topic_msg.retain = 0;
topic_msg.dup = 0;
rc = IOT_MQTT_Publish(pclient, TOPIC_OTA_PROGRESS, &topic_msg);
if (rc < 0) {
HAL_Free(msg_pub);
OTA_LOG_EX(LOG_Error,"error occur when publish,rc:%d\r\n", rc);
return rc;
}
HAL_Free(msg_pub);
IOT_MQTT_Yield(pclient, 1000);
}
#endif
ne_cfg_set_init_type(type);
/* restart system to enter ota mode */
system_restart();
return rc;
}
#if 1
#if (OTA_SERVER_TYPE == OTA_HTTP)
//#define ota_payload "{\"cmdId\":2001,\"cryptoType\":0,\"timeStamp\":1526625689,\"msgContent\":{\"mcuOTAInfo\":{\"url\":\"https://www.163.com/mcu_ota_2.bin\",\"md5\":\"1209a15c8794da4301780c479a7835a6\",\"totalLength\":487156,\"segmentLength\":262144,\"otaMode\":0,\"ver\":3456},\"wifiOTAInfo\":{\"url\":\"http://10.240.84.20/user1.2048.new.5.bin\",\"md5\":\"Adca8a82934afde782f6b16b1d83e375\",\"totalLength\":470676,\"segmentLength\":470676,\"otaMode\":1,\"ver\":2}}}"
#define ota_payload "{\"cmdId\":2001,\"cryptoType\":0,\"timeStamp\":1526625689,\"msgContent\":{\"wifiOTAInfo\":{\"url\":\"https://nim.nosdn.127.net/23056021/1/1/1529374349/\",\"md5\":\"Adca8a82934afde782f6b16b1d83e375\",\"totalLength\":470676,\"segmentLength\":470676,\"otaMode\":1,\"ver\":1232},\"mcuOTAInfo\":{\"url\":\"https://nim.nosdn.127.net/23056021/2/3/1529483539/\",\"md5\":\"4515be28c739e86328998bce84b2d05f\",\"totalLength\":452324,\"segmentLength\":226162,\"otaMode\":1,\"ver\":1234}}}"
#else
#define ota_payload "{\"cmdId\":2001,\"cryptoType\":0,\"timeStamp\":1526625689,\"msgContent\":{\"wifiOTAInfo\":{\"url\":\"https://nim.nosdn.127.net/23056021/1/1/1529374349/\",\"md5\":\"Adca8a82934afde782f6b16b1d83e375\",\"totalLength\":470676,\"segmentLength\":470676,\"otaMode\":1,\"ver\":1232},\"mcuOTAInfo\":{\"url\":\"https://nim.nosdn.127.net/23056021/1/1/1529374349/\",\"md5\":\"Adca8a82934afde782f6b16b1d83e375\",\"totalLength\":470676,\"segmentLength\":8192,\"otaMode\":1,\"ver\":1234}}}"
#endif
extern char __product_key[PRODUCT_KEY_LEN + 1];
extern char __device_name[DEVICE_NAME_LEN + 1];
void ota_mqtt_test_OTA_received(void *pclient)
{
iotx_mqtt_event_msg_pt pMsg;
iotx_mqtt_topic_info_pt topic_info;
char *topic, *payload;
topic_info = HAL_Malloc(sizeof(iotx_mqtt_topic_info_t));
topic = HAL_Malloc(128);
sprintf(topic, TOPIC_OTA_UPGRADE, __product_key, __device_name);
topic_info->topic_len = strlen(topic);
topic_info->ptopic = topic;
payload = HAL_Malloc(512);
sprintf(payload, ota_payload);
topic_info->payload_len = strlen(payload);
topic_info->payload = payload;
pMsg = HAL_Malloc(sizeof(iotx_mqtt_event_msg_t));
pMsg->event_type = 0;
pMsg->msg = topic_info;
upgrade_message_arrive(NULL, pclient, pMsg);
HAL_Free(topic);
HAL_Free(payload);
HAL_Free(topic_info);
HAL_Free(pMsg);
}
#endif