support ota
This commit is contained in:
parent
47401c5a32
commit
fdd5dc370a
|
@ -11,6 +11,7 @@ option(ENABLE_LOG_DEBUG "是否打开DEBUG日志输出" OFF)
|
||||||
option(ENABLE_IOT_TRACE "是否打开函数跟踪" OFF)
|
option(ENABLE_IOT_TRACE "是否打开函数跟踪" OFF)
|
||||||
|
|
||||||
option(ENABLE_FEATURE_MQTT_COMM "是否打开MQTT通道的总开关" ON)
|
option(ENABLE_FEATURE_MQTT_COMM "是否打开MQTT通道的总开关" ON)
|
||||||
|
option(ENABLE_FEATURE_OTA "是否打开OTA固件升级总开关" ON)
|
||||||
option(ENABLE_FEATURE_AUTH_MODE_DYNAMIC "是否打开设备动态注册" ON)
|
option(ENABLE_FEATURE_AUTH_MODE_DYNAMIC "是否打开设备动态注册" ON)
|
||||||
option(ENABLE_TLS_SUPPORT "是否打开TLS支持" ON)
|
option(ENABLE_TLS_SUPPORT "是否打开TLS支持" ON)
|
||||||
option(ENABLE_SDK_TESTS "是否打开SDK测试用例编译" ON)
|
option(ENABLE_SDK_TESTS "是否打开SDK测试用例编译" ON)
|
||||||
|
@ -77,6 +78,14 @@ else ()
|
||||||
message("FEATURE_AUTH_MODE_DYNAMIC = n")
|
message("FEATURE_AUTH_MODE_DYNAMIC = n")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if (ENABLE_FEATURE_OTA)
|
||||||
|
message("ENABLE_FEATURE_OTA = y")
|
||||||
|
include_directories(src/ota/include)
|
||||||
|
AUX_SOURCE_DIRECTORY(src/ota/src OTA_SRC)
|
||||||
|
set(src_iot_sdk ${src_iot_sdk} ${OTA_SRC})
|
||||||
|
else ()
|
||||||
|
message("ENABLE_FEATURE_OTA = n")
|
||||||
|
endif ()
|
||||||
if (ENABLE_TLS_SUPPORT)
|
if (ENABLE_TLS_SUPPORT)
|
||||||
message("FEATURE_SUPPORT_TLS = y")
|
message("FEATURE_SUPPORT_TLS = y")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSUPPORT_TLS")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSUPPORT_TLS")
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -11,6 +11,7 @@ COMP_LIB_COMPONENTS := \
|
||||||
|
|
||||||
$(call CompLib_Map, MQTT_COMM_ENABLED, src/mqtt/src)
|
$(call CompLib_Map, MQTT_COMM_ENABLED, src/mqtt/src)
|
||||||
|
|
||||||
|
$(call CompLib_Map, OTA_ENABLED, src/ota/src)
|
||||||
$(call CompLib_Map, SUPPORT_AT_CMD, src/at/src src/at/class/$(PLATFORM_MODULE) platform/module)
|
$(call CompLib_Map, SUPPORT_AT_CMD, src/at/src src/at/class/$(PLATFORM_MODULE) platform/module)
|
||||||
IOTSDK_SRC_FILES := \
|
IOTSDK_SRC_FILES := \
|
||||||
|
|
||||||
|
@ -53,6 +54,9 @@ $(call CompInc_Map, MQTT_COMM_ENABLED, \
|
||||||
src/mqtt/include \
|
src/mqtt/include \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
$(call CompInc_Map, OTA_ENABLED, \
|
||||||
|
src/ota/include \
|
||||||
|
)
|
||||||
$(call CompInc_Map, SUPPORT_TLS, \
|
$(call CompInc_Map, SUPPORT_TLS, \
|
||||||
external_libs/mbedtls/include \
|
external_libs/mbedtls/include \
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,6 +15,7 @@ PLATFORM_MODULE = m26
|
||||||
# PLATFORM_AR = armar
|
# PLATFORM_AR = armar
|
||||||
|
|
||||||
FEATURE_MQTT_COMM_ENABLED = y # 是否打开MQTT连接云平台
|
FEATURE_MQTT_COMM_ENABLED = y # 是否打开MQTT连接云平台
|
||||||
|
FEATURE_OTA_ENABLED = y # 是否打开OTA固件升级
|
||||||
FEATURE_AUTH_MODE_DYNAMIC = y # 是否打开设备动态注册
|
FEATURE_AUTH_MODE_DYNAMIC = y # 是否打开设备动态注册
|
||||||
FEATURE_SUPPORT_TLS = y # 是否打开TLS支持
|
FEATURE_SUPPORT_TLS = y # 是否打开TLS支持
|
||||||
FEATURE_SUPPORT_AT_CMD = n # 是否打开AT命令支持
|
FEATURE_SUPPORT_AT_CMD = n # 是否打开AT命令支持
|
||||||
|
|
|
@ -25,7 +25,7 @@ static int _utils_parse_name(const char *url, char *name) {
|
||||||
}
|
}
|
||||||
host_ptr += 3;
|
host_ptr += 3;
|
||||||
|
|
||||||
path_ptr = strchr(host_ptr, '/');
|
path_ptr = strrchr(host_ptr, '/');
|
||||||
if (NULL == path_ptr) {
|
if (NULL == path_ptr) {
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ static int _utils_parse_name(const char *url, char *name) {
|
||||||
|
|
||||||
memcpy(name, path_ptr + 1, name_len - 1);
|
memcpy(name, path_ptr + 1, name_len - 1);
|
||||||
name[name_len] = '\0';
|
name[name_len] = '\0';
|
||||||
|
LOG_ERROR("file name:%s",name);
|
||||||
|
|
||||||
return SUCCESS_RET;
|
return SUCCESS_RET;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,16 @@ if (ENABLE_FEATURE_MQTT_COMM)
|
||||||
add_dependencies(mqtt_sample iot_sdk iot_platform)
|
add_dependencies(mqtt_sample iot_sdk iot_platform)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if (ENABLE_FEATURE_OTA)
|
||||||
|
add_executable(ota_sample ota/ota_sample.c)
|
||||||
|
add_dependencies(ota_sample iot_sdk iot_platform)
|
||||||
|
endif ()
|
||||||
if (ENABLE_FEATURE_AUTH_MODE_DYNAMIC)
|
if (ENABLE_FEATURE_AUTH_MODE_DYNAMIC)
|
||||||
add_executable(dynamic_auth_sample dynamic_auth/dynamic_auth_sample.c)
|
add_executable(dynamic_auth_sample dynamic_auth/dynamic_auth_sample.c)
|
||||||
add_dependencies(dynamic_auth_sample iot_sdk iot_platform)
|
add_dependencies(dynamic_auth_sample iot_sdk iot_platform)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if (ENABLE_FEATURE_OTA)
|
||||||
|
add_executable(ota_sample ota/ota_sample.c)
|
||||||
|
add_dependencies(ota_sample iot_sdk iot_platform)
|
||||||
|
endif ()
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file 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 <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "uiot_export.h"
|
||||||
|
#include "uiot_import.h"
|
||||||
|
#include "uiot_export_ota.h"
|
||||||
|
|
||||||
|
#define UIOT_MY_PRODUCT_SN "productSN"
|
||||||
|
|
||||||
|
#define UIOT_MY_DEVICE_SN "deviceSN"
|
||||||
|
|
||||||
|
#define UIOT_MY_DEVICE_SECRET "device_secret"
|
||||||
|
|
||||||
|
#define OTA_BUF_LEN (1024)
|
||||||
|
|
||||||
|
static void event_handler(void *pClient, void *handle_context, MQTTEventMsg *msg)
|
||||||
|
{
|
||||||
|
switch(msg->event_type) {
|
||||||
|
case MQTT_EVENT_UNDEF:
|
||||||
|
LOG_INFO("undefined event occur.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_DISCONNECT:
|
||||||
|
LOG_INFO("MQTT disconnect.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_RECONNECT:
|
||||||
|
LOG_INFO("MQTT reconnect.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_SUBSCRIBE_SUCCESS:
|
||||||
|
LOG_INFO("subscribe success.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_SUBSCRIBE_TIMEOUT:
|
||||||
|
LOG_INFO("subscribe wait ack timeout.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_SUBSCRIBE_NACK:
|
||||||
|
LOG_INFO("subscribe nack.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_PUBLISH_SUCCESS:
|
||||||
|
LOG_INFO("publish success.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_PUBLISH_TIMEOUT:
|
||||||
|
LOG_INFO("publish timeout.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_PUBLISH_NACK:
|
||||||
|
LOG_INFO("publish nack.\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_INFO("Should NOT arrive here.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int _setup_connect_init_params(MQTTInitParams* initParams)
|
||||||
|
{
|
||||||
|
initParams->device_sn = UIOT_MY_DEVICE_SN;
|
||||||
|
initParams->product_sn = UIOT_MY_PRODUCT_SN;
|
||||||
|
initParams->device_secret = UIOT_MY_DEVICE_SECRET;
|
||||||
|
initParams->command_timeout = UIOT_MQTT_COMMAND_TIMEOUT;
|
||||||
|
initParams->keep_alive_interval = UIOT_MQTT_KEEP_ALIVE_INTERNAL;
|
||||||
|
initParams->auto_connect_enable = 1;
|
||||||
|
initParams->event_handler.h_fp = event_handler;
|
||||||
|
|
||||||
|
return SUCCESS_RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
MQTTInitParams init_params = DEFAULT_MQTT_INIT_PARAMS;
|
||||||
|
rc = _setup_connect_init_params(&init_params);
|
||||||
|
if (rc != SUCCESS_RET) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *client = IOT_MQTT_Construct(&init_params);
|
||||||
|
if (client != NULL) {
|
||||||
|
LOG_INFO("MQTT Construct Success");
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("MQTT Construct Failed");
|
||||||
|
return FAILURE_RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *h_ota = IOT_OTA_Init(UIOT_MY_PRODUCT_SN, UIOT_MY_DEVICE_SN, client);
|
||||||
|
if (NULL == h_ota) {
|
||||||
|
IOT_MQTT_Destroy(&client);
|
||||||
|
LOG_ERROR("init OTA failed");
|
||||||
|
return FAILURE_RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
IOT_MQTT_Yield(client, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,15 @@ dynamic_auth_sample:
|
||||||
mv $@ $(FINAL_DIR)/bin
|
mv $@ $(FINAL_DIR)/bin
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter -DOTA_ENABLED,$(CFLAGS)))
|
||||||
|
ota_sample:
|
||||||
|
$(TOP_Q) \
|
||||||
|
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/ota/$@.c $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
$(TOP_Q) \
|
||||||
|
mv $@ $(FINAL_DIR)/bin
|
||||||
|
endif
|
||||||
|
|
||||||
samples_final:
|
samples_final:
|
||||||
$(TOP_Q) \
|
$(TOP_Q) \
|
||||||
cp -rf $(TOP_DIR)/src/sdk-impl/*port*.h $(FINAL_DIR)/include/
|
cp -rf $(TOP_DIR)/src/sdk-impl/*port*.h $(FINAL_DIR)/include/
|
||||||
|
|
|
@ -24,26 +24,69 @@ extern "C" {
|
||||||
#ifdef SUPPORT_TLS
|
#ifdef SUPPORT_TLS
|
||||||
static const char *iot_ca_crt = \
|
static const char *iot_ca_crt = \
|
||||||
{
|
{
|
||||||
"-----BEGIN CERTIFICATE-----\r\n"
|
"-----BEGIN CERTIFICATE-----\r\n"
|
||||||
"MIIDLDCCAhQCCQCnVOYTQCyIGjANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJD\r\n"
|
"MIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh\r\n"
|
||||||
"TjELMAkGA1UECAwCU0gxCzAJBgNVBAcMAlNIMQ8wDQYDVQQKDAZVQ0xPVUQxDTAL\r\n"
|
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\r\n"
|
||||||
"BgNVBAsMBFBBQVMxDzANBgNVBAMMBlVDTE9VRDAeFw0yMDEyMTYwNTI2MzVaFw00\r\n"
|
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\r\n"
|
||||||
"MDEyMTEwNTI2MzVaMFgxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJTSDELMAkGA1UE\r\n"
|
"QTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO\r\n"
|
||||||
"BwwCU0gxDzANBgNVBAoMBlVDTE9VRDENMAsGA1UECwwEUEFBUzEPMA0GA1UEAwwG\r\n"
|
"MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL\r\n"
|
||||||
"VUNMT1VEMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA312YPHXmEEP/\r\n"
|
"ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS\r\n"
|
||||||
"PaPdSB4+jFQGHRE+BbOme5NOOL9AmFi+jxJb/4UHD6WBdl4nb0fOuw2dfbqv4Qrl\r\n"
|
"U0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8\r\n"
|
||||||
"Vh/ZwOQoQdzIZJTHMQNZoOd/5nwa/WPBAldNzWH/IqjFrhCD9tfA0rldH0QTE1s2\r\n"
|
"Yh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa\r\n"
|
||||||
"vQ8WpNi5pyJJMGoBs7q1QY0GqIRJc3iTIqsNADZhNJ4zLRa05nBzXgKQRIz1Rumx\r\n"
|
"e+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO\r\n"
|
||||||
"MpRNuKFz4EHLDkRUZCYqw5SmtpaW4ja/sSC4UzGfTEkXmNyN9UrteyvUMPbN6vTz\r\n"
|
"JcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA\r\n"
|
||||||
"igymgHyES3ygm+sEHJXFvpvZVfq8anwyNs0uUlHhWcx+MqF93vd+T1RRAq+s0BmK\r\n"
|
"zjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK\r\n"
|
||||||
"YobbIrhCuQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBvvBmgA2IjcKca0mTZ9uvM\r\n"
|
"ZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe\r\n"
|
||||||
"EyskZMTnywGuYaSu0JrgY063RsoB/p9z86TqYzLxWR0en4S4VuBWERxuaYATHs6f\r\n"
|
"3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K\r\n"
|
||||||
"sKhSq9W9RqRj8PAhjLbLPKbhp6hM/VdpcIgJNrqlmFrAcZvddiozb2U832qp65/M\r\n"
|
"AYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD\r\n"
|
||||||
"1m2Tq9i1/NosoIoolirCiK4iEotK0zYsUig1dgRTvSGVbkrmIaFesQGU503dYct/\r\n"
|
"AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG\r\n"
|
||||||
"Uz2jEmg8o36cMk011PcbkcTV6Way2g0zXs5PJu3PsJkFgL9jsBFlF1/6sHRan2V9\r\n"
|
"AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au\r\n"
|
||||||
"7HFkvgolP7RSYFSJT2Hx1NQ71NoK18lnQpvjn2bZndGOACAadpWKvDAIouaB8v8w\r\n"
|
"ZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj\r\n"
|
||||||
"-----END CERTIFICATE-----\r\n"
|
"ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg\r\n"
|
||||||
|
"hkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t\r\n"
|
||||||
|
"L0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233\r\n"
|
||||||
|
"lDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ\r\n"
|
||||||
|
"DSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP\r\n"
|
||||||
|
"ISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F\r\n"
|
||||||
|
"UQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C\r\n"
|
||||||
|
"qnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY\r\n"
|
||||||
|
"RmE=\r\n"
|
||||||
|
"-----END CERTIFICATE-----\r\n"
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *iot_https_ca_crt = \
|
||||||
|
{
|
||||||
|
"-----BEGIN CERTIFICATE-----\r\n"
|
||||||
|
"MIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh\r\n"
|
||||||
|
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\r\n"
|
||||||
|
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\r\n"
|
||||||
|
"QTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO\r\n"
|
||||||
|
"MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL\r\n"
|
||||||
|
"ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS\r\n"
|
||||||
|
"U0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8\r\n"
|
||||||
|
"Yh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa\r\n"
|
||||||
|
"e+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO\r\n"
|
||||||
|
"JcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA\r\n"
|
||||||
|
"zjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK\r\n"
|
||||||
|
"ZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe\r\n"
|
||||||
|
"3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K\r\n"
|
||||||
|
"AYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD\r\n"
|
||||||
|
"AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG\r\n"
|
||||||
|
"AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au\r\n"
|
||||||
|
"ZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj\r\n"
|
||||||
|
"ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg\r\n"
|
||||||
|
"hkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t\r\n"
|
||||||
|
"L0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233\r\n"
|
||||||
|
"lDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ\r\n"
|
||||||
|
"DSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP\r\n"
|
||||||
|
"ISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F\r\n"
|
||||||
|
"UQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C\r\n"
|
||||||
|
"qnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY\r\n"
|
||||||
|
"RmE=\r\n"
|
||||||
|
"-----END CERTIFICATE-----\r\n"
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char *iot_ca_get() {
|
const char *iot_ca_get() {
|
||||||
|
@ -54,6 +97,15 @@ const char *iot_ca_get() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *iot_https_ca_get() {
|
||||||
|
#ifdef SUPPORT_TLS
|
||||||
|
return iot_https_ca_crt;
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,6 +21,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char *iot_ca_get(void);
|
const char *iot_ca_get(void);
|
||||||
|
const char *iot_https_ca_get();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef C_SDK_OTA_CONFIG_H_
|
||||||
|
#define C_SDK_OTA_CONFIG_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TYPE_FIELD "Method"
|
||||||
|
#define MD5_FIELD "Payload.MD5"
|
||||||
|
#define MODULE_FIELD "Payload.Module"
|
||||||
|
#define VERSION_FIELD "Payload.Version"
|
||||||
|
#define CURRENT_VERSION_FIELD "Payload.CurrentVersion"
|
||||||
|
#define URL_FIELD "Payload.URL"
|
||||||
|
#define SIZE_FIELD "Payload.Size"
|
||||||
|
#define TASKID_FILED "Payload.TaskID"
|
||||||
|
#define NOTIFY_METHOD "notify"
|
||||||
|
|
||||||
|
#define REPORT_VER_TEMPLATE "{\"Method\": \"report\", \"Payload\":{\"Module\":\"%s\", \"Version\":\"%s\"}}"
|
||||||
|
#define REPORT_SUCCESS_MSG_TEMPLATE "{\"Method\": \"success\", \"Payload\": {\"TaskID\": \"%s\"}}"
|
||||||
|
#define REPORT_FAIL_MSG_TEMPLATE "{\"Method\": \"fail\", \"Payload\": {\"TaskID\": %d, \"ErrMsg\":\"%s\"}}"
|
||||||
|
#define NOTIFY_MSG_TEMPLATE "{\"Method\": \"notify\", \"Payload\":{\"TaskID\":%d}}"
|
||||||
|
#define UPGRADING_MSG_TEMPLATE "{\"Method\": \"upgrading\", \"Payload\":{\"TaskID\":%d}}"
|
||||||
|
|
||||||
|
#define OTA_UPSTREAM_MSG_BUF_LEN (129)
|
||||||
|
#define OTA_TOPIC_BUF_LEN (129)
|
||||||
|
|
||||||
|
#define OTA_UPSTREAM_TOPIC_TYPE "upstream"
|
||||||
|
#define OTA_DOWNSTREAM_TOPIC_TYPE "downstream"
|
||||||
|
#define OTA_TOPIC_TEMPLATE "/$system/%s/%s/ota/%s"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //C_SDK_OTA_CONFIG_H_
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef C_SDK_OTA_INTERNAL_H_
|
||||||
|
#define C_SDK_OTA_INTERNAL_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "ota_config.h"
|
||||||
|
#include "uiot_export_ota.h"
|
||||||
|
#include "utils_httpc.h"
|
||||||
|
#include "utils_list.h"
|
||||||
|
|
||||||
|
// OTA Signal Channel
|
||||||
|
typedef void (*OnOTAMessageCallback)(void *pContext, const char *msg, uint32_t msgLen);
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
char *payload; // MQTT 消息负载
|
||||||
|
size_t payload_len; // MQTT 消息负载长度
|
||||||
|
}OTA_UPLOAD_Msg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
const char *url;
|
||||||
|
http_client_t http; /* http client */
|
||||||
|
http_client_data_t http_data; /* http client data */
|
||||||
|
|
||||||
|
} OTA_Http_Client;
|
||||||
|
|
||||||
|
void *osc_init(const char *product_sn, const char *device_sn, void *channel, OnOTAMessageCallback callback,
|
||||||
|
void *context);
|
||||||
|
|
||||||
|
/* OSC, OTA signal channel */
|
||||||
|
typedef struct {
|
||||||
|
void *mqtt;
|
||||||
|
const char *product_sn;
|
||||||
|
const char *device_sn;
|
||||||
|
char topic_upgrade[OTA_TOPIC_BUF_LEN];
|
||||||
|
OnOTAMessageCallback msg_callback;
|
||||||
|
List *msg_list; /* recv update msg */
|
||||||
|
void *msg_mutex; /* mutex for msg list */
|
||||||
|
void *context;
|
||||||
|
} OTA_MQTT_Struct_t;
|
||||||
|
|
||||||
|
int osc_deinit(void *handle);
|
||||||
|
|
||||||
|
int osc_report_progress(void *handle, const char *msg);
|
||||||
|
|
||||||
|
int osc_upstream_publish(void *handle, const char *msg);
|
||||||
|
|
||||||
|
// OTA Fetch Channel
|
||||||
|
void *ofc_init(const char *url);
|
||||||
|
|
||||||
|
int32_t ofc_connect(void *handle);
|
||||||
|
|
||||||
|
int32_t ofc_fetch(void *handle, uint32_t size_fetched, char *buf, uint32_t buf_len, size_t range_len, uint32_t timeout_s);
|
||||||
|
|
||||||
|
int ofc_deinit(void *handle);
|
||||||
|
|
||||||
|
// ota_lib
|
||||||
|
void *ota_lib_md5_init(void);
|
||||||
|
|
||||||
|
void ota_lib_md5_update(void *md5, const char *buf, size_t buf_len);
|
||||||
|
|
||||||
|
void ota_lib_md5_finalize(void *md5, char *output_str);
|
||||||
|
|
||||||
|
void ota_lib_md5_deinit(void *md5);
|
||||||
|
|
||||||
|
int ota_lib_get_msg_type(char *json, char **type);
|
||||||
|
|
||||||
|
int ota_lib_get_params(char *json, char **url, char **module, char **download_name, char **version, char **current_version, char **md5,
|
||||||
|
char **taskID, uint32_t *fileSize);
|
||||||
|
|
||||||
|
int ota_lib_gen_upstream_msg(char *buf, size_t bufLen, const char *module, const char *version, char *taskID,
|
||||||
|
IOT_OTA_UpstreamMsgType reportType);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //C_SDK_OTA_INTERNAL_H_
|
|
@ -0,0 +1,700 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file 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 "uiot_defs.h"
|
||||||
|
#include "uiot_export_ota.h"
|
||||||
|
#include "uiot_internal.h"
|
||||||
|
|
||||||
|
#include "ota_config.h"
|
||||||
|
#include "ota_internal.h"
|
||||||
|
|
||||||
|
#include "utils_timer.h"
|
||||||
|
|
||||||
|
#define HTTP_OTA_BUFF_LEN 1024
|
||||||
|
|
||||||
|
/* http slice len config HTTP_OTA_BUFF_LEN > HTTP_OTA_RANGE_LEN*/
|
||||||
|
#define HTTP_OTA_RANGE_LEN 1000
|
||||||
|
|
||||||
|
static void print_progress(uint32_t percent)
|
||||||
|
{
|
||||||
|
static unsigned char progress_sign[100 + 1];
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
if (percent > 100)
|
||||||
|
{
|
||||||
|
percent = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
if (i < percent)
|
||||||
|
{
|
||||||
|
progress_sign[i] = '=';
|
||||||
|
}
|
||||||
|
else if (percent == i)
|
||||||
|
{
|
||||||
|
progress_sign[i] = '>';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progress_sign[i] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
progress_sign[sizeof(progress_sign) - 1] = '\0';
|
||||||
|
|
||||||
|
LOG_INFO("Download: [%s] %d%%\r\n", progress_sign, percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_upstream_msg_with_version(void *handle, const char *module, const char *version, char *taskID, IOT_OTA_UpstreamMsgType reportType)
|
||||||
|
{
|
||||||
|
POINTER_VALID_CHECK(handle, ERR_OTA_INVALID_PARAM);
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
char *msg_upstream;
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||||
|
|
||||||
|
if (OTA_STATE_UNINITED == h_ota->state) {
|
||||||
|
LOG_ERROR("handle is uninitialized");
|
||||||
|
h_ota->err = ERR_OTA_INVALID_STATE;
|
||||||
|
return ERR_OTA_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL == (msg_upstream = HAL_Malloc(OTA_UPSTREAM_MSG_BUF_LEN))) {
|
||||||
|
LOG_ERROR("allocate for msg_informed failed");
|
||||||
|
h_ota->err = ERR_OTA_NO_MEMORY;
|
||||||
|
return ERR_OTA_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ota_lib_gen_upstream_msg(msg_upstream, OTA_UPSTREAM_MSG_BUF_LEN, module, version, taskID, reportType);
|
||||||
|
if (SUCCESS_RET != ret) {
|
||||||
|
LOG_ERROR("generate upstream message failed");
|
||||||
|
h_ota->err = ret;
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = osc_upstream_publish(h_ota->ch_signal, msg_upstream);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("Report result failed");
|
||||||
|
h_ota->err = ret;
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_exit:
|
||||||
|
if (NULL != msg_upstream) {
|
||||||
|
HAL_Free(msg_upstream);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ota_push_upload_msg(void *handle, const char *msg, uint32_t msg_len)
|
||||||
|
{
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *) handle;
|
||||||
|
OTA_MQTT_Struct_t *h_osc = h_ota->ch_signal;
|
||||||
|
|
||||||
|
OTA_UPLOAD_Msg *push_msg = (OTA_UPLOAD_Msg *)HAL_Malloc(sizeof(OTA_UPLOAD_Msg));
|
||||||
|
if (NULL == (push_msg->payload = HAL_Malloc(msg_len + 1))) {
|
||||||
|
LOG_ERROR("HAL_Malloc failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_Snprintf(push_msg->payload, msg_len + 1, "%s", msg);
|
||||||
|
push_msg->payload_len = msg_len;
|
||||||
|
|
||||||
|
ListNode *node = list_node_new((void *)push_msg);
|
||||||
|
if (NULL == node)
|
||||||
|
{
|
||||||
|
LOG_ERROR("run list_node_new is error!\n");
|
||||||
|
HAL_Free(push_msg->payload);
|
||||||
|
HAL_Free(push_msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_MutexLock(h_osc->msg_mutex);
|
||||||
|
list_rpush(h_osc->msg_list, node);
|
||||||
|
HAL_MutexUnlock(h_osc->msg_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ota_pop_upload_msg(void *handle)
|
||||||
|
{
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *) handle;
|
||||||
|
OTA_MQTT_Struct_t *h_osc = h_ota->ch_signal;
|
||||||
|
|
||||||
|
if(h_osc->msg_list->len > 0)
|
||||||
|
{
|
||||||
|
HAL_MutexLock(h_osc->msg_mutex);
|
||||||
|
ListNode *node = list_lpop(h_osc->msg_list);
|
||||||
|
HAL_MutexUnlock(h_osc->msg_mutex);
|
||||||
|
OTA_UPLOAD_Msg *pop_msg = node->val;
|
||||||
|
h_osc->msg_callback(h_ota, pop_msg->payload, pop_msg->payload_len);
|
||||||
|
HAL_Free(pop_msg->payload);
|
||||||
|
HAL_Free(pop_msg);
|
||||||
|
HAL_Free(node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ota_callback(void *pContext, const char *msg, uint32_t msg_len)
|
||||||
|
{
|
||||||
|
char *msg_method = NULL;
|
||||||
|
char *msg_str = NULL;
|
||||||
|
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *) pContext;
|
||||||
|
|
||||||
|
if (h_ota == NULL || msg == NULL) {
|
||||||
|
LOG_ERROR("pointer is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL == (msg_str = HAL_Malloc(msg_len + 1))) {
|
||||||
|
LOG_ERROR("HAL_Malloc failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_Snprintf(msg_str, msg_len + 1, "%s", msg);
|
||||||
|
|
||||||
|
if (SUCCESS_RET != ota_lib_get_msg_type(msg_str, &msg_method)) {
|
||||||
|
LOG_ERROR("Get message type failed!");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == strcmp(msg_method, NOTIFY_METHOD))
|
||||||
|
{
|
||||||
|
/* downloading, push update msg to list */
|
||||||
|
if (h_ota->state == OTA_STATE_FETCHING) {
|
||||||
|
LOG_INFO("In OTA_STATE_FETCHING state");
|
||||||
|
_ota_push_upload_msg(h_ota, msg_str, msg_len);
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCESS_RET != ota_lib_get_params(msg_str, &h_ota->url, &h_ota->module, &h_ota->download_name,
|
||||||
|
&h_ota->version, &h_ota->current_version, &h_ota->md5sum, &h_ota->taskID, &h_ota->size_file)) {
|
||||||
|
LOG_ERROR("Get firmware parameter failed");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* received updating msg */
|
||||||
|
send_upstream_msg_with_version(h_ota, "", "", h_ota->taskID, OTA_REPORT_START);
|
||||||
|
|
||||||
|
if (NULL == (h_ota->ch_fetch = ofc_init(h_ota->url))) {
|
||||||
|
LOG_ERROR("Initialize fetch module failed");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCESS_RET != ofc_connect(h_ota->ch_fetch)) {
|
||||||
|
LOG_ERROR("Connect fetch module failed");
|
||||||
|
h_ota->state = OTA_STATE_DISCONNECTED;
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
h_ota->state = OTA_STATE_FETCHING;
|
||||||
|
|
||||||
|
if(SUCCESS_RET != IOT_OTA_fw_download(h_ota)) {
|
||||||
|
LOG_ERROR("download file failed");
|
||||||
|
h_ota->state = OTA_STATE_DISCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* download over, pop first pushed msg to download */
|
||||||
|
_ota_pop_upload_msg(h_ota);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
do_exit:
|
||||||
|
HAL_Free(msg_str);
|
||||||
|
HAL_Free(msg_method);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *IOT_OTA_Init(const char *product_sn, const char *device_sn, void *ch_signal)
|
||||||
|
{
|
||||||
|
POINTER_VALID_CHECK(product_sn, NULL);
|
||||||
|
POINTER_VALID_CHECK(device_sn, NULL);
|
||||||
|
POINTER_VALID_CHECK(ch_signal, NULL);
|
||||||
|
|
||||||
|
OTA_Struct_t *h_ota = NULL;
|
||||||
|
|
||||||
|
if (NULL == (h_ota = HAL_Malloc(sizeof(OTA_Struct_t)))) {
|
||||||
|
LOG_ERROR("allocate failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(h_ota, 0, sizeof(OTA_Struct_t));
|
||||||
|
h_ota->state = OTA_STATE_UNINITED;
|
||||||
|
|
||||||
|
h_ota->ch_signal = osc_init(product_sn, device_sn, ch_signal, _ota_callback, h_ota);
|
||||||
|
if (NULL == h_ota->ch_signal) {
|
||||||
|
LOG_ERROR("initialize signal channel failed");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
h_ota->md5 = ota_lib_md5_init();
|
||||||
|
if (NULL == h_ota->md5) {
|
||||||
|
LOG_ERROR("initialize md5 failed");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
h_ota->state = OTA_STATE_INITED;
|
||||||
|
return h_ota;
|
||||||
|
|
||||||
|
do_exit:
|
||||||
|
if (NULL != h_ota->ch_signal) {
|
||||||
|
osc_deinit(h_ota->ch_signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != h_ota->md5) {
|
||||||
|
ota_lib_md5_deinit(h_ota->md5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != h_ota) {
|
||||||
|
HAL_Free(h_ota);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int IOT_OTA_Destroy(void *handle)
|
||||||
|
{
|
||||||
|
POINTER_VALID_CHECK(handle, ERR_OTA_INVALID_PARAM);
|
||||||
|
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t*) handle;
|
||||||
|
|
||||||
|
if (OTA_STATE_UNINITED == h_ota->state) {
|
||||||
|
LOG_ERROR("handle is uninitialized");
|
||||||
|
return FAILURE_RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
osc_deinit(h_ota->ch_signal);
|
||||||
|
ofc_deinit(h_ota->ch_fetch);
|
||||||
|
ota_lib_md5_deinit(h_ota->md5);
|
||||||
|
|
||||||
|
if (NULL != h_ota->url) {
|
||||||
|
HAL_Free(h_ota->url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != h_ota->module) {
|
||||||
|
HAL_Free(h_ota->module);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != h_ota->version) {
|
||||||
|
HAL_Free(h_ota->version);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != h_ota->md5sum) {
|
||||||
|
HAL_Free(h_ota->md5sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != h_ota->download_name) {
|
||||||
|
HAL_Free(h_ota->download_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_Free(h_ota);
|
||||||
|
return SUCCESS_RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOT_OTA_Clear(void *handle)
|
||||||
|
{
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||||
|
|
||||||
|
ofc_deinit(h_ota->ch_fetch);
|
||||||
|
|
||||||
|
if (NULL != h_ota->url) {
|
||||||
|
memset(h_ota->url, 0, strlen(h_ota->url));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != h_ota->module) {
|
||||||
|
memset(h_ota->module, 0, strlen(h_ota->module));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(NULL != h_ota->download_name){
|
||||||
|
memset(h_ota->download_name, 0, strlen(h_ota->download_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != h_ota->version) {
|
||||||
|
memset(h_ota->version, 0, strlen(h_ota->version));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != h_ota->md5sum) {
|
||||||
|
memset(h_ota->md5sum, 0, strlen(h_ota->md5sum));
|
||||||
|
}
|
||||||
|
|
||||||
|
h_ota->size_last_fetched = 0;
|
||||||
|
h_ota->size_fetched = 0;
|
||||||
|
h_ota->size_file = 0;
|
||||||
|
ota_lib_md5_deinit(h_ota->md5);
|
||||||
|
h_ota->md5 = ota_lib_md5_init();
|
||||||
|
h_ota->state = OTA_STATE_INITED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOT_OTA_ReportVersion(void *handle, const char *module, const char *version)
|
||||||
|
{
|
||||||
|
return send_upstream_msg_with_version(handle, module, version, 0, OTA_REPORT_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int IOT_OTA_ReportSuccess(void *handle)
|
||||||
|
{
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||||
|
|
||||||
|
if(h_ota->fetch_callback_func != NULL)
|
||||||
|
{
|
||||||
|
h_ota->fetch_callback_func(handle, OTA_REPORT_SUCCESS);
|
||||||
|
}
|
||||||
|
h_ota->current_version = h_ota->version;
|
||||||
|
return send_upstream_msg_with_version(handle, "", "", h_ota->taskID, OTA_REPORT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOT_OTA_ReportUpgrading(void *handle)
|
||||||
|
{
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||||
|
|
||||||
|
return send_upstream_msg_with_version(handle, "", "", h_ota->taskID, OTA_REPORT_UPGRADING);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOT_OTA_ReportFail(void *handle, IOT_OTA_ReportErrCode err_code)
|
||||||
|
{
|
||||||
|
POINTER_VALID_CHECK(handle, ERR_OTA_INVALID_PARAM);
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
char *msg_upstream;
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||||
|
|
||||||
|
if (OTA_STATE_UNINITED == h_ota->state) {
|
||||||
|
LOG_ERROR("handle is uninitialized");
|
||||||
|
h_ota->err = ERR_OTA_INVALID_STATE;
|
||||||
|
return ERR_OTA_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL == (msg_upstream = HAL_Malloc(OTA_UPSTREAM_MSG_BUF_LEN))) {
|
||||||
|
LOG_ERROR("allocate for msg_informed failed");
|
||||||
|
h_ota->err = ERR_OTA_NO_MEMORY;
|
||||||
|
return ERR_OTA_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ota_lib_gen_upstream_msg(msg_upstream, OTA_UPSTREAM_MSG_BUF_LEN, "", "", h_ota->taskID, (IOT_OTA_UpstreamMsgType)err_code);
|
||||||
|
if (SUCCESS_RET != ret) {
|
||||||
|
LOG_ERROR("generate upstream message failed");
|
||||||
|
h_ota->err = ret;
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = osc_upstream_publish(h_ota->ch_signal, msg_upstream);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("Report result failed");
|
||||||
|
h_ota->err = ret;
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(h_ota->fetch_callback_func != NULL)
|
||||||
|
h_ota->fetch_callback_func(handle, (IOT_OTA_UpstreamMsgType)err_code);
|
||||||
|
|
||||||
|
do_exit:
|
||||||
|
if (NULL != msg_upstream) {
|
||||||
|
HAL_Free(msg_upstream);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int IOT_OTA_IsFetching(void *handle)
|
||||||
|
{
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *)handle;
|
||||||
|
|
||||||
|
if (NULL == handle) {
|
||||||
|
LOG_ERROR("handle is NULL");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OTA_STATE_UNINITED == h_ota->state) {
|
||||||
|
LOG_ERROR("handle is uninitialized");
|
||||||
|
h_ota->err = ERR_OTA_INVALID_STATE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (OTA_STATE_FETCHING == h_ota->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int IOT_OTA_IsFetchFinish(void *handle)
|
||||||
|
{
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *) handle;
|
||||||
|
|
||||||
|
if (NULL == handle) {
|
||||||
|
LOG_ERROR("handle is NULL");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OTA_STATE_UNINITED == h_ota->state) {
|
||||||
|
LOG_ERROR("handle is uninitialized");
|
||||||
|
h_ota->err = ERR_OTA_INVALID_STATE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (OTA_STATE_FETCHED == h_ota->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOT_OTA_Yield(void *handle, uint32_t timeout_ms)
|
||||||
|
{
|
||||||
|
POINTER_VALID_CHECK(handle, FAILURE_RET);
|
||||||
|
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t*) handle;
|
||||||
|
|
||||||
|
return IOT_MQTT_Yield(((OTA_MQTT_Struct_t *)h_ota->ch_signal)->mqtt, timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOT_OTA_FetchYield(void *handle, char *buf, size_t buf_len, size_t range_len, uint32_t timeout_s)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
OTA_Struct_t *h_ota = (OTA_Struct_t *) handle;
|
||||||
|
int retry_time = 0;
|
||||||
|
|
||||||
|
POINTER_VALID_CHECK(handle, ERR_OTA_INVALID_PARAM);
|
||||||
|
POINTER_VALID_CHECK(buf, ERR_OTA_INVALID_PARAM);
|
||||||
|
NUMERIC_VALID_CHECK(buf_len, ERR_OTA_INVALID_PARAM);
|
||||||
|
|
||||||
|
if (OTA_STATE_FETCHING != h_ota->state) {
|
||||||
|
h_ota->err = ERR_OTA_INVALID_STATE;
|
||||||
|
return ERR_OTA_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(retry_time = 0; retry_time < 5; retry_time++)
|
||||||
|
{
|
||||||
|
/* fetch fail,try again utill 5 time */
|
||||||
|
ret = ofc_fetch(h_ota->ch_fetch, h_ota->size_fetched ,buf, buf_len, range_len, timeout_s);
|
||||||
|
/* range download send request too often maybe cutdown by server, need reconnect and continue to download. */
|
||||||
|
if((ret == ERR_HTTP_CONN_ERROR) && (h_ota->state != OTA_STATE_DISCONNECTED)) {
|
||||||
|
ofc_deinit(h_ota->ch_fetch);
|
||||||
|
h_ota->ch_fetch = ofc_init(h_ota->url);
|
||||||
|
ofc_connect(h_ota->ch_fetch);
|
||||||
|
h_ota->state = OTA_STATE_FETCHING;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("Fetch firmware failed");
|
||||||
|
h_ota->state = OTA_STATE_FETCHED;
|
||||||
|
h_ota->err = ret;
|
||||||
|
|
||||||
|
if (ret == ERR_OTA_FETCH_AUTH_FAIL) { // 上报签名过期
|
||||||
|
IOT_OTA_ReportFail(h_ota, OTA_ERRCODE_SIGNATURE_EXPIRED);
|
||||||
|
} else if (ret == ERR_OTA_FILE_NOT_EXIST) { // 上报文件不存在
|
||||||
|
IOT_OTA_ReportFail(h_ota, OTA_ERRCODE_FIRMWARE_NOT_EXIST);
|
||||||
|
} else if (ret == ERR_OTA_FETCH_TIMEOUT) { // 上报下载超时
|
||||||
|
IOT_OTA_ReportFail(h_ota, OTA_ERRCODE_DOWNLOAD_TIMEOUT);
|
||||||
|
} else {
|
||||||
|
h_ota->err = ERR_OTA_FETCH_FAILED;
|
||||||
|
}
|
||||||
|
HAL_SleepMs(1000);
|
||||||
|
} else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret > 0) {
|
||||||
|
ota_lib_md5_update(h_ota->md5, buf, ret);
|
||||||
|
h_ota->size_last_fetched = ret;
|
||||||
|
h_ota->size_fetched += ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* report percent every second. */
|
||||||
|
uint32_t percent = (h_ota->size_fetched * 100) / h_ota->size_file;
|
||||||
|
print_progress(percent);
|
||||||
|
|
||||||
|
if (h_ota->size_fetched >= h_ota->size_file) {
|
||||||
|
h_ota->state = OTA_STATE_FETCHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int IOT_OTA_Ioctl(void *handle, IOT_OTA_CmdType type, void *buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
OTA_Struct_t * h_ota = (OTA_Struct_t *) handle;
|
||||||
|
|
||||||
|
POINTER_VALID_CHECK(handle, ERR_OTA_INVALID_PARAM);
|
||||||
|
POINTER_VALID_CHECK(buf, ERR_OTA_INVALID_PARAM);
|
||||||
|
NUMERIC_VALID_CHECK(buf_len, ERR_OTA_INVALID_PARAM);
|
||||||
|
|
||||||
|
if (h_ota->state < OTA_STATE_FETCHING) {
|
||||||
|
h_ota->err = ERR_OTA_INVALID_STATE;
|
||||||
|
return ERR_OTA_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case OTA_IOCTL_FETCHED_SIZE:
|
||||||
|
if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) {
|
||||||
|
LOG_ERROR("Invalid parameter");
|
||||||
|
h_ota->err = ERR_OTA_INVALID_PARAM;
|
||||||
|
return FAILURE_RET;
|
||||||
|
} else {
|
||||||
|
*((uint32_t *)buf) = h_ota->size_fetched;
|
||||||
|
return SUCCESS_RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OTA_IOCTL_FILE_SIZE:
|
||||||
|
if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) {
|
||||||
|
LOG_ERROR("Invalid parameter");
|
||||||
|
h_ota->err = ERR_OTA_INVALID_PARAM;
|
||||||
|
return FAILURE_RET;
|
||||||
|
} else {
|
||||||
|
*((uint32_t *)buf) = h_ota->size_file;
|
||||||
|
return SUCCESS_RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OTA_IOCTL_VERSION:
|
||||||
|
strncpy(buf, h_ota->version, buf_len);
|
||||||
|
((char *)buf)[buf_len - 1] = '\0';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OTA_IOCTL_MD5SUM:
|
||||||
|
strncpy(buf, h_ota->md5sum, buf_len);
|
||||||
|
((char *)buf)[buf_len - 1] = '\0';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OTA_IOCTL_CHECK_FIRMWARE:
|
||||||
|
if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) {
|
||||||
|
LOG_ERROR("Invalid parameter");
|
||||||
|
h_ota->err = ERR_OTA_INVALID_PARAM;
|
||||||
|
return FAILURE_RET;
|
||||||
|
} else if (h_ota->state != OTA_STATE_FETCHED) {
|
||||||
|
h_ota->err = ERR_OTA_INVALID_STATE;
|
||||||
|
LOG_ERROR("Firmware can be checked in OTA_STATE_FETCHED state only");
|
||||||
|
return FAILURE_RET;
|
||||||
|
} else {
|
||||||
|
char md5_str[33];
|
||||||
|
ota_lib_md5_finalize(h_ota->md5, md5_str);
|
||||||
|
LOG_DEBUG("origin=%s, now=%s", h_ota->md5sum, md5_str);
|
||||||
|
if (0 == strcmp(h_ota->md5sum, md5_str)) {
|
||||||
|
*((uint32_t *)buf) = 1;
|
||||||
|
} else {
|
||||||
|
*((uint32_t *)buf) = 0;
|
||||||
|
// 上报MD5不匹配
|
||||||
|
h_ota->err = ERR_OTA_MD5_MISMATCH;
|
||||||
|
IOT_OTA_ReportFail(h_ota, OTA_ERRCODE_MD5_MISMATCH);
|
||||||
|
}
|
||||||
|
return SUCCESS_RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_ERROR("invalid cmd type");
|
||||||
|
h_ota->err = ERR_OTA_INVALID_PARAM;
|
||||||
|
return FAILURE_RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS_RET;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int IOT_OTA_GetLastError(void *handle)
|
||||||
|
{
|
||||||
|
OTA_Struct_t * h_ota = (OTA_Struct_t *) handle;
|
||||||
|
|
||||||
|
if (NULL == handle) {
|
||||||
|
LOG_ERROR("handle is NULL");
|
||||||
|
return ERR_OTA_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h_ota->err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOT_OTA_fw_download(void *handle)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int file_size = 0, length, firmware_valid, total_length = 0;
|
||||||
|
char *buffer_read = NULL;
|
||||||
|
OTA_Struct_t * h_ota = (OTA_Struct_t *) handle;
|
||||||
|
void * download_handle = NULL;
|
||||||
|
|
||||||
|
IOT_OTA_Ioctl(h_ota, OTA_IOCTL_FILE_SIZE, &file_size, 4);
|
||||||
|
|
||||||
|
download_handle = HAL_Download_Init(h_ota->download_name);
|
||||||
|
if(download_handle == NULL)
|
||||||
|
{
|
||||||
|
ret = FAILURE_RET;
|
||||||
|
goto __exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_read = (char *)HAL_Malloc(HTTP_OTA_BUFF_LEN);
|
||||||
|
if (buffer_read == NULL)
|
||||||
|
{
|
||||||
|
LOG_ERROR("No memory for http ota!");
|
||||||
|
ret = FAILURE_RET;
|
||||||
|
goto __exit;
|
||||||
|
}
|
||||||
|
memset(buffer_read, 0x00, HTTP_OTA_BUFF_LEN);
|
||||||
|
|
||||||
|
IOT_OTA_ReportUpgrading(h_ota);
|
||||||
|
|
||||||
|
LOG_INFO("OTA file size is (%d)", file_size);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
length = IOT_OTA_FetchYield(h_ota, buffer_read, HTTP_OTA_BUFF_LEN, HTTP_OTA_RANGE_LEN, 10);
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
/* Write the data to the corresponding partition address */
|
||||||
|
if(HAL_Download_Write(download_handle, total_length, buffer_read, length) == FAILURE_RET){
|
||||||
|
ret = FAILURE_RET;
|
||||||
|
goto __exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_length += length;
|
||||||
|
//wait cancel cmd
|
||||||
|
IOT_OTA_Yield(handle, 100);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("Exit: server return err (%d)!", length);
|
||||||
|
ret = ERR_OTA_FETCH_FAILED;
|
||||||
|
goto __exit;
|
||||||
|
}
|
||||||
|
} while (!IOT_OTA_IsFetchFinish(h_ota));
|
||||||
|
|
||||||
|
if (total_length == file_size)
|
||||||
|
{
|
||||||
|
ret = SUCCESS_RET;
|
||||||
|
IOT_OTA_Ioctl(h_ota, OTA_IOCTL_CHECK_FIRMWARE, &firmware_valid, 4);
|
||||||
|
if (0 == firmware_valid) {
|
||||||
|
LOG_ERROR("The firmware is invalid");
|
||||||
|
ret = IOT_OTA_GetLastError(h_ota);
|
||||||
|
goto __exit;
|
||||||
|
} else {
|
||||||
|
LOG_INFO("The firmware is valid");
|
||||||
|
IOT_OTA_ReportSuccess(h_ota);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(HAL_Download_End(download_handle))
|
||||||
|
ret = FAILURE_RET;
|
||||||
|
|
||||||
|
LOG_INFO("Download firmware to flash success.");
|
||||||
|
}
|
||||||
|
|
||||||
|
__exit:
|
||||||
|
if (buffer_read != NULL)
|
||||||
|
HAL_Free(buffer_read);
|
||||||
|
IOT_OTA_Clear(h_ota);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file 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 <string.h>
|
||||||
|
|
||||||
|
#include "uiot_export_ota.h"
|
||||||
|
#include "uiot_import.h"
|
||||||
|
#include "ota_internal.h"
|
||||||
|
#include "ca.h"
|
||||||
|
#include "utils_httpc.h"
|
||||||
|
|
||||||
|
void *ofc_init(const char *url)
|
||||||
|
{
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
OTA_Http_Client *h_ofc;
|
||||||
|
|
||||||
|
if (NULL == (h_ofc = HAL_Malloc(sizeof(OTA_Http_Client)))) {
|
||||||
|
LOG_ERROR("allocate for h_odc failed");
|
||||||
|
FUNC_EXIT_RC(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(h_ofc, 0, sizeof(OTA_Http_Client));
|
||||||
|
|
||||||
|
/* set http request-header parameter */
|
||||||
|
h_ofc->http.header = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" \
|
||||||
|
"Accept-Encoding: gzip, deflate\r\n";
|
||||||
|
|
||||||
|
h_ofc->url = url;
|
||||||
|
|
||||||
|
FUNC_EXIT_RC(h_ofc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32_t ofc_connect(void *handle)
|
||||||
|
{
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
OTA_Http_Client * h_ofc = (OTA_Http_Client *)handle;
|
||||||
|
|
||||||
|
#ifdef SUPPORT_TLS
|
||||||
|
const char *ca_crt = iot_https_ca_get();
|
||||||
|
#else
|
||||||
|
const char *ca_crt = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int32_t rc = http_client_connect(&h_ofc->http, h_ofc->url, ca_crt);
|
||||||
|
|
||||||
|
FUNC_EXIT_RC(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32_t ofc_fetch(void *handle, uint32_t size_fetched, char *buf, uint32_t buf_len, size_t range_len, uint32_t timeout_s)
|
||||||
|
{
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
int diff;
|
||||||
|
OTA_Http_Client * h_ofc = (OTA_Http_Client *)handle;
|
||||||
|
|
||||||
|
/* 分片请求 */
|
||||||
|
int rc = _http_send_request(&h_ofc->http, h_ofc->url, HTTP_GET, size_fetched, range_len, &h_ofc->http_data, 5000);
|
||||||
|
if (rc != SUCCESS_RET) {
|
||||||
|
LOG_ERROR("http_send_request error, rc = %d, size_fetched = %d\r\n", rc, size_fetched);
|
||||||
|
FUNC_EXIT_RC(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SUPPORT_AT_CMD
|
||||||
|
/* wait at module recv data */
|
||||||
|
HAL_SleepMs(5000);
|
||||||
|
#endif
|
||||||
|
h_ofc->http_data.response_buf = buf;
|
||||||
|
h_ofc->http_data.response_buf_len = buf_len;
|
||||||
|
h_ofc->http_data.response_content_len = 0;
|
||||||
|
h_ofc->http_data.response_received_len = 0;
|
||||||
|
diff = h_ofc->http_data.response_content_len - h_ofc->http_data.retrieve_len;
|
||||||
|
|
||||||
|
rc = http_client_recv_data(&h_ofc->http, timeout_s * 1000, &h_ofc->http_data);
|
||||||
|
if (SUCCESS_RET != rc) {
|
||||||
|
if (rc == ERR_HTTP_NOT_FOUND)
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_FILE_NOT_EXIST);
|
||||||
|
|
||||||
|
if (rc == ERR_HTTP_AUTH_ERROR)
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_FETCH_AUTH_FAIL);
|
||||||
|
|
||||||
|
if (rc == ERR_HTTP_TIMEOUT)
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_FETCH_TIMEOUT);
|
||||||
|
|
||||||
|
FUNC_EXIT_RC(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNC_EXIT_RC(h_ofc->http_data.response_content_len - h_ofc->http_data.retrieve_len - diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ofc_deinit(void *handle)
|
||||||
|
{
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
OTA_Http_Client *h_ofc = (OTA_Http_Client *)handle;
|
||||||
|
|
||||||
|
http_client_close(&h_ofc->http);
|
||||||
|
if (NULL != handle) {
|
||||||
|
HAL_Free(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNC_EXIT_RC(SUCCESS_RET);
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file 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 <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "ota_config.h"
|
||||||
|
#include "ota_internal.h"
|
||||||
|
|
||||||
|
#include "utils_md5.h"
|
||||||
|
#include "lite-utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
void *ota_lib_md5_init(void) {
|
||||||
|
iot_md5_context *ctx = HAL_Malloc(sizeof(iot_md5_context));
|
||||||
|
if (NULL == ctx) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils_md5_init(ctx);
|
||||||
|
utils_md5_starts(ctx);
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ota_lib_md5_update(void *md5, const char *buf, size_t buf_len) {
|
||||||
|
utils_md5_update(md5, (unsigned char *) buf, buf_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ota_lib_md5_finalize(void *md5, char *output_str) {
|
||||||
|
utils_md5_finish_hb2hex(md5, output_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ota_lib_md5_deinit(void *md5) {
|
||||||
|
if (NULL != md5) {
|
||||||
|
HAL_Free(md5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ota_lib_get_msg_type(char *json, char **type) {
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
if (NULL == (*type = LITE_json_value_of(TYPE_FIELD, json))) {
|
||||||
|
LOG_ERROR("get value of type key failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNC_EXIT_RC(SUCCESS_RET);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ota_lib_get_params(char *json, char **url, char **module, char **download_name, char **version, char **current_version, char **md5, char **taskID,
|
||||||
|
uint32_t *fileSize) {
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
char *module_str;
|
||||||
|
char *file_size_str;
|
||||||
|
char *version_str;
|
||||||
|
char *current_version_str;
|
||||||
|
char *url_str;
|
||||||
|
char *md5_str;
|
||||||
|
char *taskID_str;
|
||||||
|
|
||||||
|
/* get module */
|
||||||
|
if (NULL == (module_str = LITE_json_value_of(MODULE_FIELD, json))) {
|
||||||
|
LOG_ERROR("get value of module key failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
if (NULL != *module) {
|
||||||
|
HAL_Free(*module);
|
||||||
|
}
|
||||||
|
*module = module_str;
|
||||||
|
|
||||||
|
/* get version */
|
||||||
|
if (NULL == (version_str = LITE_json_value_of(VERSION_FIELD, json))) {
|
||||||
|
LOG_ERROR("get value of version key failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
if (NULL != *version) {
|
||||||
|
HAL_Free(*version);
|
||||||
|
}
|
||||||
|
*version = version_str;
|
||||||
|
|
||||||
|
/* get current version */
|
||||||
|
if (NULL == (current_version_str = LITE_json_value_of(CURRENT_VERSION_FIELD, json))) {
|
||||||
|
LOG_ERROR("get value of current version key failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
if (NULL != *current_version) {
|
||||||
|
HAL_Free(*current_version);
|
||||||
|
}
|
||||||
|
*current_version = current_version_str;
|
||||||
|
|
||||||
|
/* get URL */
|
||||||
|
if (NULL == (url_str = LITE_json_value_of(URL_FIELD, json))) {
|
||||||
|
LOG_ERROR("get value of url key failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
if (NULL != *url) {
|
||||||
|
HAL_Free(*url);
|
||||||
|
}
|
||||||
|
*url = url_str;
|
||||||
|
|
||||||
|
*download_name = HAL_Download_Name_Set((void*)url_str);
|
||||||
|
|
||||||
|
/* get md5 */
|
||||||
|
if (NULL == (md5_str = LITE_json_value_of(MD5_FIELD, json))) {
|
||||||
|
LOG_ERROR("get value of md5 failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
if (NULL != *md5) {
|
||||||
|
HAL_Free(*md5);
|
||||||
|
}
|
||||||
|
*md5 = md5_str;
|
||||||
|
|
||||||
|
/* get md5 */
|
||||||
|
if (NULL == (taskID_str = LITE_json_value_of(TASKID_FILED, json))) {
|
||||||
|
LOG_ERROR("get value of taskID failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != *taskID) {
|
||||||
|
HAL_Free(*taskID);
|
||||||
|
}
|
||||||
|
*taskID = taskID_str;
|
||||||
|
|
||||||
|
/* get file size */
|
||||||
|
if (NULL == (file_size_str = LITE_json_value_of(SIZE_FIELD, json))) {
|
||||||
|
LOG_ERROR("get value of file size failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCESS_RET != LITE_get_uint32(fileSize, file_size_str)) {
|
||||||
|
LOG_ERROR("get uint32 failed");
|
||||||
|
HAL_Free(file_size_str);
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
HAL_Free(file_size_str);
|
||||||
|
FUNC_EXIT_RC(SUCCESS_RET);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ota_lib_gen_upstream_msg(char *buf, size_t bufLen, const char *module, const char *version, char *taskID,
|
||||||
|
IOT_OTA_UpstreamMsgType reportType) {
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (reportType) {
|
||||||
|
case OTA_REPORT_DOWNLOAD_TIMEOUT:
|
||||||
|
case OTA_REPORT_FIRMWARE_NOT_EXIST:
|
||||||
|
case OTA_REPORT_MD5_MISMATCH:
|
||||||
|
case OTA_REPORT_SIGNATURE_EXPIRED:
|
||||||
|
case OTA_REPORT_FIRMWARE_BURN_FAILED:
|
||||||
|
case OTA_REPORT_UNDEFINED_ERROR:
|
||||||
|
ret = HAL_Snprintf(buf, bufLen, REPORT_FAIL_MSG_TEMPLATE, reportType);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OTA_REPORT_START:
|
||||||
|
ret = HAL_Snprintf(buf, bufLen, NOTIFY_MSG_TEMPLATE, taskID);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OTA_REPORT_UPGRADING:
|
||||||
|
ret = HAL_Snprintf(buf, bufLen, UPGRADING_MSG_TEMPLATE, taskID);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OTA_REPORT_SUCCESS:
|
||||||
|
ret = HAL_Snprintf(buf, bufLen, REPORT_SUCCESS_MSG_TEMPLATE, taskID);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OTA_REPORT_VERSION:
|
||||||
|
ret = HAL_Snprintf(buf, bufLen, REPORT_VER_TEMPLATE, module, version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("HAL_Snprintf failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
} else if (ret >= bufLen) {
|
||||||
|
LOG_ERROR("msg is too long");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_STR_TOO_LONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNC_EXIT_RC(SUCCESS_RET);
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file 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 <string.h>
|
||||||
|
|
||||||
|
#include "uiot_defs.h"
|
||||||
|
#include "uiot_export_mqtt.h"
|
||||||
|
#include "uiot_export_ota.h"
|
||||||
|
#include "uiot_import.h"
|
||||||
|
|
||||||
|
#include "ota_config.h"
|
||||||
|
#include "ota_internal.h"
|
||||||
|
|
||||||
|
static int _ota_mqtt_gen_topic_name(char *buf, size_t buf_len, const char *ota_topic_type, const char *product_sn,
|
||||||
|
const char *device_sn)
|
||||||
|
{
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
ret = HAL_Snprintf(buf, buf_len, OTA_TOPIC_TEMPLATE, product_sn, device_sn, ota_topic_type);
|
||||||
|
|
||||||
|
if(ret >= buf_len) {
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("HAL_Snprintf failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNC_EXIT_RC(SUCCESS_RET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _ota_mqtt_publish(OTA_MQTT_Struct_t *handle, const char *topic_type, int qos, const char *msg)
|
||||||
|
{
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
char topic_name[OTA_TOPIC_BUF_LEN];
|
||||||
|
PublishParams pub_params = DEFAULT_PUB_PARAMS;
|
||||||
|
|
||||||
|
//暂不支持QOS2
|
||||||
|
if (0 == qos) {
|
||||||
|
pub_params.qos = QOS0;
|
||||||
|
} else {
|
||||||
|
pub_params.qos = QOS1;
|
||||||
|
}
|
||||||
|
pub_params.payload = (void *)msg;
|
||||||
|
pub_params.payload_len = strlen(msg);
|
||||||
|
|
||||||
|
ret = _ota_mqtt_gen_topic_name(topic_name, OTA_TOPIC_BUF_LEN, topic_type, handle->product_sn, handle->device_sn);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("generate topic name of info failed");
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_GENERAL_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = IOT_MQTT_Publish(handle->mqtt, topic_name, &pub_params);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("publish to topic: %s failed", topic_name);
|
||||||
|
FUNC_EXIT_RC(ERR_OTA_OSC_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNC_EXIT_RC(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ota_mqtt_upgrade_cb(void *pClient, MQTTMessage *message, void *pContext)
|
||||||
|
{
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
OTA_MQTT_Struct_t *handle = (OTA_MQTT_Struct_t *) pContext;
|
||||||
|
|
||||||
|
LOG_DEBUG("topic=%s", message->topic);
|
||||||
|
LOG_INFO("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload);
|
||||||
|
|
||||||
|
if (NULL != handle->msg_callback) {
|
||||||
|
handle->msg_callback(handle->context, message->payload, message->payload_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNC_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *osc_init(const char *product_sn, const char *device_sn, void *channel, OnOTAMessageCallback callback,
|
||||||
|
void *context)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
OTA_MQTT_Struct_t *h_osc = NULL;
|
||||||
|
|
||||||
|
if (NULL == (h_osc = HAL_Malloc(sizeof(OTA_MQTT_Struct_t)))) {
|
||||||
|
LOG_ERROR("allocate for h_osc failed");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(h_osc, 0, sizeof(OTA_MQTT_Struct_t));
|
||||||
|
|
||||||
|
h_osc->mqtt = channel;
|
||||||
|
h_osc->product_sn = product_sn;
|
||||||
|
h_osc->device_sn = device_sn;
|
||||||
|
h_osc->msg_callback = callback;
|
||||||
|
h_osc->context = context;
|
||||||
|
h_osc->msg_list = list_new();
|
||||||
|
h_osc->msg_mutex = HAL_MutexCreate();
|
||||||
|
if (h_osc->msg_mutex == NULL)
|
||||||
|
goto do_exit;
|
||||||
|
|
||||||
|
/* subscribe the OTA topic: "/$system/$(product_sn)/$(device_sn)/ota/downstream" */
|
||||||
|
ret = _ota_mqtt_gen_topic_name(h_osc->topic_upgrade, OTA_TOPIC_BUF_LEN, OTA_DOWNSTREAM_TOPIC_TYPE, product_sn,
|
||||||
|
device_sn);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("generate topic name of upgrade failed");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
|
||||||
|
sub_params.on_message_handler = _ota_mqtt_upgrade_cb;
|
||||||
|
sub_params.qos = QOS1;
|
||||||
|
sub_params.user_data = h_osc;
|
||||||
|
|
||||||
|
ret = IOT_MQTT_Subscribe(channel, h_osc->topic_upgrade, &sub_params);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("ota mqtt subscribe failed!");
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h_osc;
|
||||||
|
|
||||||
|
do_exit:
|
||||||
|
if (NULL != h_osc) {
|
||||||
|
HAL_Free(h_osc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int osc_deinit(void *handle)
|
||||||
|
{
|
||||||
|
FUNC_ENTRY;
|
||||||
|
|
||||||
|
OTA_MQTT_Struct_t *h_osc = handle;
|
||||||
|
|
||||||
|
list_destroy(h_osc->msg_list);
|
||||||
|
HAL_MutexDestroy(h_osc->msg_mutex);
|
||||||
|
|
||||||
|
if (NULL != handle) {
|
||||||
|
HAL_Free(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNC_EXIT_RC(SUCCESS_RET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* report progress of OTA */
|
||||||
|
int osc_report_progress(void *handle, const char *msg)
|
||||||
|
{
|
||||||
|
return _ota_mqtt_publish(handle, OTA_UPSTREAM_TOPIC_TYPE, QOS0, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* report version of firmware */
|
||||||
|
int osc_upstream_publish(void *handle, const char *msg)
|
||||||
|
{
|
||||||
|
return _ota_mqtt_publish(handle, OTA_UPSTREAM_TOPIC_TYPE, QOS1, msg);
|
||||||
|
}
|
|
@ -0,0 +1,232 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2019 UCloud. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef C_SDK_UIOT_EXPORT_OTA_H_
|
||||||
|
#define C_SDK_UIOT_EXPORT_OTA_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "uiot_import.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
OTA_IOCTL_FETCHED_SIZE, /* 固件已经下载的大小 */
|
||||||
|
OTA_IOCTL_FILE_SIZE, /* 固件总大小 */
|
||||||
|
OTA_IOCTL_MD5SUM, /* md5(字符串类型) */
|
||||||
|
OTA_IOCTL_VERSION, /* 版本号(字符串类型)t */
|
||||||
|
OTA_IOCTL_CHECK_FIRMWARE /* 对固件进行校验 */
|
||||||
|
|
||||||
|
} IOT_OTA_CmdType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
OTA_ERRCODE_FIRMWARE_NOT_EXIST = -1, /* 固件文件不存在(URL无法访问) */
|
||||||
|
OTA_ERRCODE_SIGNATURE_EXPIRED = -2, /* URL签名过期 */
|
||||||
|
OTA_ERRCODE_DOWNLOAD_TIMEOUT = -3, /* 下载超时 */
|
||||||
|
OTA_ERRCODE_MD5_MISMATCH = -4, /* MD5不匹配 */
|
||||||
|
OTA_ERRCODE_FIRMWARE_BURN_FAILED = -5, /* 固件烧录失败 */
|
||||||
|
OTA_ERRCODE_UNDEFINED_ERROR = -6 /* 未定义错误 */
|
||||||
|
|
||||||
|
} IOT_OTA_ReportErrCode;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
OTA_REPORT_UNDEFINED_ERROR = -6,
|
||||||
|
OTA_REPORT_FIRMWARE_BURN_FAILED = -5,
|
||||||
|
OTA_REPORT_MD5_MISMATCH = -4,
|
||||||
|
OTA_REPORT_DOWNLOAD_TIMEOUT = -3,
|
||||||
|
OTA_REPORT_SIGNATURE_EXPIRED = -2,
|
||||||
|
OTA_REPORT_FIRMWARE_NOT_EXIST = -1,
|
||||||
|
OTA_REPORT_NONE = 0,
|
||||||
|
OTA_REPORT_START = 1,
|
||||||
|
OTA_REPORT_UPGRADING = 2,
|
||||||
|
OTA_REPORT_SUCCESS = 3,
|
||||||
|
OTA_REPORT_VERSION = 4,
|
||||||
|
|
||||||
|
} IOT_OTA_UpstreamMsgType;
|
||||||
|
|
||||||
|
typedef int (*IOT_OTA_FetchCallback)(void *handle, IOT_OTA_UpstreamMsgType state);
|
||||||
|
|
||||||
|
/* OTA状态 */
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
OTA_STATE_UNINITED = 0, /* 未初始化 */
|
||||||
|
OTA_STATE_INITED, /* 初始化完成 */
|
||||||
|
OTA_STATE_FETCHING, /* 正在下载固件 */
|
||||||
|
OTA_STATE_FETCHED, /* 固件下载完成 */
|
||||||
|
OTA_STATE_DISCONNECTED /* 连接已经断开 */
|
||||||
|
|
||||||
|
} IOT_OTA_State;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t id; /* message id */
|
||||||
|
IOT_OTA_State state; /* OTA state */
|
||||||
|
uint32_t size_last_fetched; /* size of last downloaded */
|
||||||
|
uint32_t size_fetched; /* size of already downloaded */
|
||||||
|
uint32_t size_file; /* size of file */
|
||||||
|
|
||||||
|
char *taskID; /* point to taskID */
|
||||||
|
char *url; /* point to URL */
|
||||||
|
char *download_name; /* download partition name */
|
||||||
|
char *module; /* download module name */
|
||||||
|
char *version; /* point to version */
|
||||||
|
char *current_version; /* point to current version */
|
||||||
|
char *md5sum; /* MD5 string */
|
||||||
|
|
||||||
|
void *md5; /* MD5 handle */
|
||||||
|
void *ch_signal; /* channel handle of signal exchanged with OTA server */
|
||||||
|
void *ch_fetch; /* channel handle of download */
|
||||||
|
|
||||||
|
int err; /* last error code */
|
||||||
|
|
||||||
|
Timer report_timer;
|
||||||
|
IOT_OTA_FetchCallback fetch_callback_func;
|
||||||
|
} OTA_Struct_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化OTA模块和返回句柄
|
||||||
|
* MQTT客户端必须在调用此接口之前进行初始化
|
||||||
|
*
|
||||||
|
* @param product_sn: 指定产品序列号
|
||||||
|
* @param device_sn: 指定设备序列号
|
||||||
|
* @param ch_signal: 指定的信号通道.
|
||||||
|
*
|
||||||
|
* @retval : 成功则返回句柄,失败返回NULL
|
||||||
|
*/
|
||||||
|
void *IOT_OTA_Init(const char *product_sn, const char *device_sn, void *ch_signal);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 释放OTA相关的资源
|
||||||
|
* 如果在下载之后没有调用重新启动,则须调用该接口以释放资源
|
||||||
|
*
|
||||||
|
* @param handle: 指定OTA模块
|
||||||
|
*
|
||||||
|
* @retval 0 : 成功
|
||||||
|
* @retval < 0 : 失败,返回具体错误码
|
||||||
|
*/
|
||||||
|
int IOT_OTA_Destroy(void *handle);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 向OTA服务器报告固件版本信息。
|
||||||
|
* NOTE: 进行OTA前请保证先上报一次本地固件的版本信息,以便服务器获取到设备目前的固件信息
|
||||||
|
*
|
||||||
|
* @param handle: 指定OTA模块
|
||||||
|
* @param module: 版本所属类型
|
||||||
|
* @param version: 以字符串格式指定固件版本
|
||||||
|
*
|
||||||
|
* @retval > 0 : 对应publish的packet id
|
||||||
|
* @retval < 0 : 失败,返回具体错误码
|
||||||
|
*/
|
||||||
|
int IOT_OTA_ReportVersion(void *handle, const char *module, const char *version);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 向OTA服务器上报升级成功
|
||||||
|
*
|
||||||
|
* @param handle: 指定OTA模块
|
||||||
|
*
|
||||||
|
* @retval > 0 : 对应publish的packet id
|
||||||
|
* @retval < 0 : 失败,返回具体错误码
|
||||||
|
*/
|
||||||
|
int IOT_OTA_ReportSuccess(void *handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 向OTA服务器上报失败信息
|
||||||
|
*
|
||||||
|
* @param handle: 指定OTA模块
|
||||||
|
* @param err_code: 错误码
|
||||||
|
*
|
||||||
|
* @retval > 0 : 对应publish的packet id
|
||||||
|
* @retval < 0 : 失败,返回具体错误码
|
||||||
|
*/
|
||||||
|
int IOT_OTA_ReportFail(void *handle, IOT_OTA_ReportErrCode err_code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查固件是否已经下载完成
|
||||||
|
*
|
||||||
|
* @param handle: 指定OTA模块
|
||||||
|
*
|
||||||
|
* @retval 1 : Yes.
|
||||||
|
* @retval 0 : No.
|
||||||
|
*/
|
||||||
|
int IOT_OTA_IsFetchFinish(void *handle);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 从具有特定超时值的远程服务器获取固件
|
||||||
|
* 注意:如果你想要下载的更快,那么应该给出更大的“buf”
|
||||||
|
*
|
||||||
|
* @param handle: 指定OTA模块
|
||||||
|
* @param buf: 指定存储固件数据的空间
|
||||||
|
* @param buf_len: 用字节指定“buf”的长度
|
||||||
|
* @param range_len: 用字节指定分片的长度
|
||||||
|
* @param timeout_s: 超时时间
|
||||||
|
*
|
||||||
|
* @retval < 0 : 对应的错误码
|
||||||
|
* @retval 0 : 在“timeout_s”超时期间没有任何数据被下载
|
||||||
|
* @retval (0, len] : 在“timeout_s”超时时间内以字节的方式下载数据的长度
|
||||||
|
*/
|
||||||
|
int IOT_OTA_FetchYield(void *handle, char *buf, size_t buf_len, size_t range_len, uint32_t timeout_s);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取指定的OTA信息
|
||||||
|
* 通过这个接口,可以获得诸如状态、文件大小、文件的md5等信息
|
||||||
|
*
|
||||||
|
* @param handle: 指定OTA模块
|
||||||
|
* @param type: 指定您想要的信息,请参见详细信息“IOT_OTA_CmdType”
|
||||||
|
* @param buf: 为数据交换指定缓冲区
|
||||||
|
* @param buf_len: 在字节中指定“buf”的长度
|
||||||
|
* @return
|
||||||
|
NOTE:
|
||||||
|
1) 如果 type==OTA_IOCTL_FETCHED_SIZE, 'buf' 需要传入 uint32_t 类型指针, 'buf_len' 需指定为 4
|
||||||
|
2) 如果 type==OTA_IOCTL_FILE_SIZE, 'buf' 需要传入 uint32_t 类型指针, 'buf_len' 需指定为 4
|
||||||
|
3) 如果 type==OTA_IOCTL_MD5SUM, 'buf' 需要传入 buffer, 'buf_len' 需指定为 33
|
||||||
|
4) 如果 type==OTA_IOCTL_VERSION, 'buf' 需要传入 buffer, 'buf_len' 需指定为 OTA_VERSION_LEN_MAX
|
||||||
|
5) 如果 type==OTA_IOCTL_CHECK_FIRMWARE, 'buf' 需要传入 uint32_t 类型指针, 'buf_len'需指定为 4
|
||||||
|
0, 固件MD5校验不通过, 固件是无效的; 1, 固件是有效的.
|
||||||
|
*
|
||||||
|
* @retval 0 : 执行成功
|
||||||
|
* @retval < 0 : 执行失败,返回对应的错误码
|
||||||
|
*/
|
||||||
|
int IOT_OTA_Ioctl(void *handle, IOT_OTA_CmdType type, void *buf, size_t buf_len);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 得到最后一个错误代码
|
||||||
|
*
|
||||||
|
* @param handle: 指定OTA模块
|
||||||
|
*
|
||||||
|
* @return 对应错误的错误码.
|
||||||
|
*/
|
||||||
|
int IOT_OTA_GetLastError(void *handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 下载固件,下载结束后重启设备
|
||||||
|
*
|
||||||
|
* @param handle: 指定OTA模块
|
||||||
|
*
|
||||||
|
* @return 对应错误的错误码.
|
||||||
|
*/
|
||||||
|
int IOT_OTA_fw_download(void *handle);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //C_SDK_UIOT_EXPORT_OTA_H_
|
|
@ -20,6 +20,7 @@ extern "C" {
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "uiot_defs.h"
|
#include "uiot_defs.h"
|
||||||
#include "utils_httpc.h"
|
#include "utils_httpc.h"
|
||||||
|
@ -33,17 +34,20 @@ extern "C" {
|
||||||
#define HTTP_CLIENT_READ_BUF_SIZE (1024) /* read payload */
|
#define HTTP_CLIENT_READ_BUF_SIZE (1024) /* read payload */
|
||||||
#define HTTP_CLIENT_READ_HEAD_SIZE (32) /* read header */
|
#define HTTP_CLIENT_READ_HEAD_SIZE (32) /* read header */
|
||||||
#define HTTP_CLIENT_SEND_BUF_SIZE (1024) /* send */
|
#define HTTP_CLIENT_SEND_BUF_SIZE (1024) /* send */
|
||||||
#define HTTP_CLIENT_REQUEST_BUF_SIZE (300) /* send */
|
#define HTTP_CLIENT_REQUEST_BUF_SIZE (1024) /* send */
|
||||||
#define HTTP_CLIENT_MAX_URL_LEN (256)
|
#define HTTP_CLIENT_MAX_URL_LEN (512)
|
||||||
#define HTTP_RETRIEVE_MORE_DATA (1) /**< More data needs to be retrieved. */
|
#define HTTP_RETRIEVE_MORE_DATA (1) /**< More data needs to be retrieved. */
|
||||||
#define HTTP_CLIENT_CHUNK_SIZE (1024)
|
#define HTTP_CLIENT_CHUNK_SIZE (1024)
|
||||||
static int _utils_parse_url(const char *url, char *host, char *path) {
|
static int _utils_parse_url(const char *url, char *host, char *path, int *port) {
|
||||||
char *host_ptr = (char *) strstr(url, "://");
|
char *host_ptr = (char *) strstr(url, "://");
|
||||||
uint32_t host_len = 0;
|
uint32_t host_len = 0;
|
||||||
uint32_t path_len;
|
uint32_t path_len;
|
||||||
|
uint32_t port_len;
|
||||||
/* char *port_ptr; */
|
/* char *port_ptr; */
|
||||||
char *path_ptr;
|
char *path_ptr;
|
||||||
char *fragment_ptr;
|
char *fragment_ptr;
|
||||||
|
char port_str[HTTP_CLIENT_MAX_URL_LEN] = {0};
|
||||||
|
char *port_ptr;
|
||||||
|
|
||||||
if (host_ptr == NULL) {
|
if (host_ptr == NULL) {
|
||||||
return ERR_PARAM_INVALID; /* URL is invalid */
|
return ERR_PARAM_INVALID; /* URL is invalid */
|
||||||
|
@ -69,6 +73,17 @@ static int _utils_parse_url(const char *url, char *host, char *path) {
|
||||||
memcpy(path, path_ptr, path_len);
|
memcpy(path, path_ptr, path_len);
|
||||||
path[path_len] = '\0';
|
path[path_len] = '\0';
|
||||||
|
|
||||||
|
port_ptr = strchr(host, ':');
|
||||||
|
if (NULL == port_ptr) {
|
||||||
|
return SUCCESS_RET;
|
||||||
|
}else{
|
||||||
|
port_len = port_ptr - host;
|
||||||
|
memcpy(port_str, port_ptr+1, strlen(port_ptr)-1);
|
||||||
|
port_str[strlen(port_ptr)-1] = '\0';
|
||||||
|
if(port_str != NULL)
|
||||||
|
*port = atoi(port_str);
|
||||||
|
host[port_len] = '\0';
|
||||||
|
}
|
||||||
return SUCCESS_RET;
|
return SUCCESS_RET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +370,7 @@ static int _http_parse_response_header(http_client_t *client, char *data, int le
|
||||||
client_data->response_content_len = atoi(tmp_ptr + strlen("Content-Length: "));
|
client_data->response_content_len = atoi(tmp_ptr + strlen("Content-Length: "));
|
||||||
client_data->retrieve_len = client_data->response_content_len;
|
client_data->retrieve_len = client_data->response_content_len;
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Could not parse header");
|
LOG_ERROR("Could not parse header data:%s",data);
|
||||||
return ERR_HTTP_CONN_ERROR;
|
return ERR_HTTP_CONN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,8 +420,9 @@ int _http_send_request(http_client_t *client, const char *url, HTTP_Request_Meth
|
||||||
int rc;
|
int rc;
|
||||||
char host[HTTP_CLIENT_MAX_URL_LEN] = {0};
|
char host[HTTP_CLIENT_MAX_URL_LEN] = {0};
|
||||||
char path[HTTP_CLIENT_MAX_URL_LEN] = {0};
|
char path[HTTP_CLIENT_MAX_URL_LEN] = {0};
|
||||||
|
int port;
|
||||||
|
|
||||||
rc = _utils_parse_url(url, host, path);
|
rc = _utils_parse_url(url, host, path, &port);
|
||||||
if (rc != SUCCESS_RET) {
|
if (rc != SUCCESS_RET) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -456,17 +472,18 @@ static int _http_client_recv_response(http_client_t *client, uint32_t timeout_ms
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_client_connect(http_client_t *client, const char *url, int port, const char *ca_crt) {
|
int http_client_connect(http_client_t *client, const char *url, const char *ca_crt) {
|
||||||
if (client->net.handle != 0) {
|
if (client->net.handle != 0) {
|
||||||
LOG_ERROR("http client has connected to host!");
|
LOG_ERROR("http client has connected to host!");
|
||||||
return ERR_HTTP_CONN_ERROR;
|
return ERR_HTTP_CONN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc;
|
int rc;
|
||||||
|
int port;
|
||||||
char host[HTTP_CLIENT_MAX_URL_LEN] = {0};
|
char host[HTTP_CLIENT_MAX_URL_LEN] = {0};
|
||||||
char path[HTTP_CLIENT_MAX_URL_LEN] = {0};
|
char path[HTTP_CLIENT_MAX_URL_LEN] = {0};
|
||||||
|
|
||||||
rc = _utils_parse_url(url, host, path);
|
rc = _utils_parse_url(url, host, path, &port);
|
||||||
if (rc != SUCCESS_RET) {
|
if (rc != SUCCESS_RET) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -486,27 +503,6 @@ int http_client_connect(http_client_t *client, const char *url, int port, const
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_client_common(http_client_t *client, const char *url, int port, const char *ca_crt,
|
|
||||||
HTTP_Request_Method method, http_client_data_t *client_data, uint32_t timeout_ms) {
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (client->net.handle == 0) {
|
|
||||||
rc = http_client_connect(client, url, port, ca_crt);
|
|
||||||
if (rc != SUCCESS_RET) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = _http_send_request(client, url, method, 0, 0, client_data, timeout_ms);
|
|
||||||
if (rc != SUCCESS_RET) {
|
|
||||||
LOG_ERROR("http_send_request error, rc = %d", rc);
|
|
||||||
http_client_close(client);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SUCCESS_RET;
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_client_recv_data(http_client_t *client, uint32_t timeout_ms, http_client_data_t *client_data) {
|
int http_client_recv_data(http_client_t *client, uint32_t timeout_ms, http_client_data_t *client_data) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
|
|
@ -57,10 +57,7 @@ typedef struct {
|
||||||
} http_client_data_t;
|
} http_client_data_t;
|
||||||
|
|
||||||
|
|
||||||
int http_client_connect(http_client_t *client, const char *url, int port, const char *ca_crt);
|
int http_client_connect(http_client_t *client, const char *url, const char *ca_crt);
|
||||||
|
|
||||||
int http_client_common(http_client_t *client, const char *url, int port, const char *ca_crt,
|
|
||||||
HTTP_Request_Method method, http_client_data_t *client_data, uint32_t timeout_ms);
|
|
||||||
|
|
||||||
int http_client_recv_data(http_client_t *client, uint32_t timeout_ms, http_client_data_t *client_data);
|
int http_client_recv_data(http_client_t *client, uint32_t timeout_ms, http_client_data_t *client_data);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ PLATFORM_OS ?= linux
|
||||||
PLATFORM_MODULE ?= esp8266
|
PLATFORM_MODULE ?= esp8266
|
||||||
|
|
||||||
FEATURE_MQTT_COMM_ENABLED ?= y
|
FEATURE_MQTT_COMM_ENABLED ?= y
|
||||||
|
FEATURE_OTA_ENABLED ?= n
|
||||||
FEATURE_AUTH_MODE_DYNAMIC ?= n
|
FEATURE_AUTH_MODE_DYNAMIC ?= n
|
||||||
FEATURE_SUPPORT_TLS ?= n
|
FEATURE_SUPPORT_TLS ?= n
|
||||||
FEATURE_SUPPORT_AT_CMD ?= n
|
FEATURE_SUPPORT_AT_CMD ?= n
|
||||||
|
|
|
@ -9,6 +9,7 @@ SETTING_VARS := \
|
||||||
|
|
||||||
SWITCH_VARS := \
|
SWITCH_VARS := \
|
||||||
FEATURE_MQTT_COMM_ENABLED \
|
FEATURE_MQTT_COMM_ENABLED \
|
||||||
|
FEATURE_OTA_ENABLED \
|
||||||
FEATURE_SUPPORT_TLS \
|
FEATURE_SUPPORT_TLS \
|
||||||
FEATURE_MQTT_RMDUP_MSG_ENABLED \
|
FEATURE_MQTT_RMDUP_MSG_ENABLED \
|
||||||
FEATURE_AUTH_MODE_DYNAMIC \
|
FEATURE_AUTH_MODE_DYNAMIC \
|
||||||
|
|
|
@ -16,6 +16,6 @@ endif
|
||||||
$(TOP_Q) \
|
$(TOP_Q) \
|
||||||
rm -rf ${TEMP_DIR}
|
rm -rf ${TEMP_DIR}
|
||||||
|
|
||||||
.PHONY: mqtt_sample dynamic_auth_sample
|
.PHONY: mqtt_sample dynamic_auth_sample ota_sample
|
||||||
|
|
||||||
final : mqtt_sample dynamic_auth_sample
|
final : mqtt_sample dynamic_auth_sample ota_sample
|
Loading…
Reference in New Issue