Просмотр исходного кода

Merge pull request #11 from ucloud/support_http_slice

support http slice
ethanDu1 6 лет назад
Родитель
Сommit
554917ae53

+ 36 - 33
README.md

@@ -8,20 +8,20 @@ UCloud IOT SDK for rt-thread Package 是基于[UCloud设备端C-SDK](https://git
 
 ### 1.2 目录结构
 
-| 名称            	| 说明 |
-| ----            	| ---- |
-| uiot            	| UCloud设备端C-SDK |
-| ports           	| 移植文件目录 |
-| samples         	| 示例目录 |
-|  ├─mqtt      		| 静态注册收发消息示例 |
+| 名称              | 说明 |
+| ----              | ---- |
+| uiot              | UCloud设备端C-SDK |
+| ports             | 移植文件目录 |
+| samples           | 示例目录 |
+|  ├─mqtt           | 静态注册收发消息示例 |
 |  ├─dynamic_auth   | 动态注册示例 |
 |  ├─dev_model      | 物模型示例 |
-|  ├─ota      		| ota升级示例 |
-|  ├─shadow      	| 设备影子示例 |
-| docs         	    | 说明文档 |
-| LICENSE         	| 许可证文件 |
-| README.md       	| 软件包使用说明 |
-| SConscript      	| RT-Thread 默认的构建脚本 |
+|  ├─ota            | ota升级示例 |
+|  ├─shadow         | 设备影子示例 |
+| docs              | 说明文档 |
+| LICENSE           | 许可证文件 |
+| README.md         | 软件包使用说明 |
+| SConscript        | RT-Thread 默认的构建脚本 |
 
 ### 1.3 许可证
 
@@ -40,31 +40,32 @@ menuconfig配置
 路径如下:
 ```
 RT-Thread online packages  --->
-	IoT - internet of things  --->
-		IoT Cloud  --->
-			[ ] ucloud-iot-sdk: ucloud iot sdk for uiot-core platform.  --->
-			  --- ucloud-iothub:  ucloud iot sdk for uiot-core platform 
-				[ ]   Enable Mqtt 
-				ucloud Device Config  --->  
-				Version (latest)  --->	
+    IoT - internet of things  --->
+        IoT Cloud  --->
+            [ ] ucloud-iot-sdk: ucloud iot sdk for uiot-core platform.  --->
+              --- ucloud-iothub:  ucloud iot sdk for uiot-core platform 
+                [ ]   Enable Mqtt 
+                ucloud Device Config  --->  
+                Version (latest)  --->	
 ```
 
 ## 3 软件包的使用
 根据产品需求选择合适的应用示例修改新增业务逻辑,也可新增例程编写新的业务逻辑。
-```			
-	--- ucloud-iot-sdk: ucloud iot sdk for uiot-core platform.
-	[*]   Enable mqtt                                                                                             
-			Auth Mode (Enable Static Register)  --->                                                               
-		  Ucloud Device Config  --->    
-	[ ]   Enable Tls                                                                                            
-	[ ]   Enable Ucloud Mqtt Sample 			
-	[ ]   Enable Shadow      
-	[ ]   	Enable Ucloud Shadow Sample   	
-	[ ]   Enable Dev Model  
-	[ ]   	Enable Ucloud Dev Model Sample  	
-	[ ]   Enable Ota                                                                                                
-	[ ]   	Enable Ucloud Ota Sample                                                                                                                                                                                                                                                                                                          
-		  Version (latest)  --->
+```	
+    --- ucloud-iot-sdk: ucloud iot sdk for uiot-core platform.
+    [*]   Enable mqtt                                                                                             
+            Auth Mode (Enable Static Register)  --->                                                               
+          Ucloud Device Config  --->    
+    [ ]   Enable Tls                                                                                            
+    [ ]   Enable Ucloud Mqtt Sample 
+    [ ]   Enable Shadow      
+    [ ]     Enable Ucloud Shadow Sample
+    [ ]   Enable Dev Model  
+    [ ]     Enable Ucloud Dev Model Sample
+    [ ]   Enable Ota                                                                                                
+    [ ]     Enable Ucloud Ota Sample  
+    [ ]   Enable Ucloud Debug
+          Version (latest)  --->
 ```
 
 - 选项说明
@@ -95,6 +96,8 @@ RT-Thread online packages  --->
 
 `Enable Ucloud Ota Sample`:使能远程升级版本的案例
 
+`Enable Ucloud Debug`: 使能打印输出
+
 `Version (latest)  --->`:
 
 - 使用 `pkgs --update` 命令下载软件包

+ 32 - 28
SConscript

@@ -29,66 +29,70 @@ CPPPATH += [cwd + '/uiot/sdk-impl']
 CPPPATH += [cwd + '/uiot/shadow/include']
 CPPPATH += [cwd + '/uiot/utils']
 
+#Debug
+if GetDepend(['PKG_USING_UCLOUD_DEBUG']):
+    CPPDEFINES += ['ENABLE_LOG_DEBUG', 'ENABLE_LOG_INFO', 'ENABLE_LOG_WARN', 'ENABLE_LOG_ERROR']
+
 #Gen MQTT src file
 if GetDepend(['PKG_USING_UCLOUD_MQTT']):
-	src_base += Glob('uiot/mqtt/src/*.c')
-	src_base += Glob('uiot/utils/*.c')
-	src_base += Glob('ports/rtthread/*.c')
-	src_base += Glob('ports/fal/*.c')
-	SrcRemove(src_base, 'uiot/utils/utils_sha2.c')		
+    src_base += Glob('uiot/mqtt/src/*.c')
+    src_base += Glob('uiot/utils/*.c')
+    src_base += Glob('ports/rtthread/*.c')
+    src_base += Glob('ports/fal/*.c')
+    SrcRemove(src_base, 'uiot/utils/utils_sha2.c')
 
 #enable dynamic auth
 #if GetDepend(['PKG_USING_UCLOUD_MQTT_DYNAMIC_AUTH']):
 
 #Gen shadow src file
 if GetDepend(['PKG_USING_UCLOUD_SHADOW']):
-	src_base += Glob('uiot/shadow/src/*.c')
+    src_base += Glob('uiot/shadow/src/*.c')
 
 #Gen dev model src file
 if GetDepend(['PKG_USING_UCLOUD_DEV_MODEL']):
-	src_base += Glob('uiot/dev_model/src/*.c')
+    src_base += Glob('uiot/dev_model/src/*.c')
 
 #Gen ota src file
 if GetDepend(['PKG_USING_UCLOUD_OTA']):
-	src_base += Glob('uiot/ota/src/*.c')
-	
+    src_base += Glob('uiot/ota/src/*.c')
+
 #TLS used
 if GetDepend(['PKG_USING_UCLOUD_TLS']):
-	src_base += Glob('uiot/certs/ca.c')
-	src_base += Glob('ports/ssl/HAL_TLS_mbedtls.c')
-	CPPDEFINES += ['MBEDTLS_CONFIG_FILE=<HAL_TLS_config.h>']	
+    src_base += Glob('uiot/certs/ca.c')
+    src_base += Glob('ports/ssl/HAL_TLS_mbedtls.c')
+    CPPDEFINES += ['MBEDTLS_CONFIG_FILE=<HAL_TLS_config.h>']
 
 #Hub C-SDK core
 group = DefineGroup('ucloud_iot_sdk', src_base, depend = ['PKG_USING_UCLOUD_IOT_SDK'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)
 
 #MQTT Example
 if GetDepend(['PKG_USING_UCLOUD_MQTT_SAMPLE']):
-	sample_ucloud_mqtt_src += Glob('samples/mqtt/mqtt_sample.c')
-	
-group = DefineGroup('sample_ucloud_mqtt', sample_ucloud_mqtt_src, depend = ['PKG_USING_UCLOUD_MQTT_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)	
+    sample_ucloud_mqtt_src += Glob('samples/mqtt/mqtt_sample.c')
+
+group = DefineGroup('sample_ucloud_mqtt', sample_ucloud_mqtt_src, depend = ['PKG_USING_UCLOUD_MQTT_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)
 
 #MQTT Dynamic Auth Example
 if GetDepend(['PKG_USING_UCLOUD_MQTT_DYNAMIC_AUTH_SAMPLE']):
-	sample_ucloud_mqtt_dynamic_auth_src += Glob('samples/dynamic_auth/dynamic_auth_sample.c')
-	
-group = DefineGroup('sample_ucloud_mqtt_dynamic_auth', sample_ucloud_mqtt_dynamic_auth_src, depend = ['PKG_USING_UCLOUD_MQTT_DYNAMIC_AUTH_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)	
-	
+    sample_ucloud_mqtt_dynamic_auth_src += Glob('samples/dynamic_auth/dynamic_auth_sample.c')
+
+group = DefineGroup('sample_ucloud_mqtt_dynamic_auth', sample_ucloud_mqtt_dynamic_auth_src, depend = ['PKG_USING_UCLOUD_MQTT_DYNAMIC_AUTH_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)
+
 #Shadow Example
 if GetDepend(['PKG_USING_UCLOUD_SHADOW_SAMPLE']):
-	sample_ucloud_shadow_src += Glob('samples/shadow/shadow_sample.c')
-	
-group = DefineGroup('sample_ucloud_shadow', sample_ucloud_shadow_src, depend = ['PKG_USING_UCLOUD_SHADOW_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)	
+    sample_ucloud_shadow_src += Glob('samples/shadow/shadow_sample.c')
+
+group = DefineGroup('sample_ucloud_shadow', sample_ucloud_shadow_src, depend = ['PKG_USING_UCLOUD_SHADOW_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)
 
 #Dev Model Example
 if GetDepend(['PKG_USING_UCLOUD_DEV_MODEL_SAMPLE']):
-	sample_ucloud_dev_model_src += Glob('samples/dev_model/dev_model_sample.c')
-	
-group = DefineGroup('sample_ucloud_dev_model', sample_ucloud_dev_model_src, depend = ['PKG_USING_UCLOUD_DEV_MODEL_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)	
+    sample_ucloud_dev_model_src += Glob('samples/dev_model/dev_model_sample.c')
+
+group = DefineGroup('sample_ucloud_dev_model', sample_ucloud_dev_model_src, depend = ['PKG_USING_UCLOUD_DEV_MODEL_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)
 
 #OTA Example
 if GetDepend(['PKG_USING_UCLOUD_OTA_SAMPLE']):
-	sample_ucloud_ota_src += Glob('samples/ota/ota_sample.c')
-	
-group = DefineGroup('sample_ucloud_ota', sample_ucloud_ota_src, depend = ['PKG_USING_UCLOUD_OTA_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)		
+    sample_ucloud_ota_src += Glob('samples/ota/ota_sample.c')
+
+group = DefineGroup('sample_ucloud_ota', sample_ucloud_ota_src, depend = ['PKG_USING_UCLOUD_OTA_SAMPLE'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)
   
 Return('group')

+ 1 - 1
docs/api.md

@@ -8,7 +8,7 @@
 #define UIOT_MQTT_KEEP_ALIVE_INTERNAL                               (240)
 
 /* MQTT 阻塞调用(包括连接, 订阅, 发布等)的超时时间 */
-#define UIOT_MQTT_COMMAND_TIMEOUT                                   (5 * 10000)
+#define UIOT_MQTT_COMMAND_TIMEOUT                                   (5 * 1000)
 
 /* 接收到 MQTT 包头以后,接收剩余长度及剩余包,最大延迟等待时延 */
 #define UIOT_MQTT_MAX_REMAIN_WAIT_MS                                (2000)

+ 1 - 1
samples/shadow/shadow_sample.c

@@ -243,7 +243,7 @@ static void shadow_test_thread(void)
     HAL_Free(Property5);
     HAL_Free(Property6);
     IOT_Shadow_Destroy(sg_pshadow);
-
+    IOT_MQTT_Destroy(&mqtt_client);
     return;
 }
 

+ 1 - 1
uiot/mqtt/include/mqtt_client.h

@@ -50,7 +50,7 @@ extern "C" {
 #define MIN_COMMAND_TIMEOUT                                         (500)
 
 /* MQTT报文最大超时时间 */
-#define MAX_COMMAND_TIMEOUT                                         (50000)
+#define MAX_COMMAND_TIMEOUT                                         (5000)
 
 /* 云端保留主题的最大长度 */
 #define MAX_SIZE_OF_CLOUD_TOPIC                                     (128)

+ 1 - 1
uiot/ota/include/ota_internal.h

@@ -69,7 +69,7 @@ void *ofc_init(const char *url);
 
 int32_t ofc_connect(void *handle);
 
-int32_t ofc_fetch(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s);
+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);
 

+ 350 - 3
uiot/ota/src/ota_client.c

@@ -26,6 +26,43 @@
 
 #include "utils_timer.h"
 
+#include <fal.h>
+
+#define HTTP_OTA_BUFF_LEN         4100
+
+/* http slice len config HTTP_OTA_BUFF_LEN > HTTP_OTA_RANGE_LEN*/
+#define HTTP_OTA_RANGE_LEN        4096
+
+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';
+
+    HAL_Printf("Download: [%s] %d%%\r\n", progress_sign, percent);
+}
 
 typedef struct  {
     uint32_t                id;                      /* message id */
@@ -86,9 +123,20 @@ static void _ota_callback(void *pContext, const char *msg, uint32_t msg_len) {
         goto do_exit;
     }
 
-    char **argurl = NULL;
-    argurl[1] = h_ota->url;
-    http_ota(2, argurl);
+    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;
+    
+    IOT_OTA_fw_download(h_ota);
 
 do_exit:
     HAL_Free(msg_str);
@@ -333,3 +381,302 @@ int IOT_OTA_ReportFail(void *handle, IOT_OTA_ReportErrCode err_code)
 }
 
 
+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_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);
+        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 if (0 == h_ota->size_fetched) {
+            /* force report status in the first */
+            IOT_OTA_ReportProgress(h_ota, 0, OTA_PROGRESS_DOWNLOADING);
+
+            init_timer(&h_ota->report_timer);
+            countdown(&h_ota->report_timer, OTA_REPORT_PROGRESS_INTERVAL);
+            break;
+        } 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;
+    if (percent == 100) {
+        IOT_OTA_ReportProgress(h_ota, percent, OTA_PROGRESS_DOWNLOADING);
+    } else if (h_ota->size_last_fetched > 0 && has_expired(&h_ota->report_timer)) {
+        IOT_OTA_ReportProgress(h_ota, percent, OTA_PROGRESS_DOWNLOADING);
+        countdown(&h_ota->report_timer, OTA_REPORT_PROGRESS_INTERVAL);
+        HAL_SleepMs(100);
+    }
+
+    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;
+    uint8_t *buffer_read = RT_NULL;
+    const struct fal_partition * dl_part = RT_NULL;
+    OTA_Struct_t * h_ota = (OTA_Struct_t *) handle;
+    // 用于存放云端下发的固件版本
+    char msg_version[33];
+
+    IOT_OTA_Ioctl(h_ota, OTA_IOCTL_FILE_SIZE, &file_size, 4);
+    
+    /* Get download partition information and erase download partition data */
+    if ((dl_part = fal_partition_find("download")) == RT_NULL)
+    {
+        LOG_ERROR("Firmware download failed! Partition (%s) find error!", "download");
+        ret = -RT_ERROR;
+        goto __exit;
+    }
+
+    LOG_INFO("Start erase flash (%s) partition!", dl_part->name);
+
+    if (fal_partition_erase(dl_part, 0, file_size) < 0)
+    {
+        LOG_ERROR("Firmware download failed! Partition (%s) erase error!", dl_part->name);
+        ret = -RT_ERROR;
+        goto __exit;
+    }
+    LOG_INFO("Erase flash (%s) partition success!", dl_part->name);
+
+    buffer_read = (uint8_t *)HAL_Malloc(HTTP_OTA_BUFF_LEN);
+    if (buffer_read == RT_NULL)
+    {
+        LOG_ERROR("No memory for http ota!");
+        ret = -RT_ERROR;
+        goto __exit;
+    }
+    memset(buffer_read, 0x00, HTTP_OTA_BUFF_LEN);
+
+    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 (fal_partition_write(dl_part, total_length, buffer_read, length) < 0)
+            {
+                LOG_ERROR("Firmware download failed! Partition (%s) write data error!", dl_part->name);
+                ret = -RT_ERROR;
+                goto __exit;
+            }
+            total_length += length;
+        }
+        else
+        {
+            LOG_ERROR("Exit: server return err (%d)!", length);
+            ret = -RT_ERROR;                
+            goto __exit;
+        }
+    } while (!IOT_OTA_IsFetchFinish(h_ota));
+
+    if (total_length == file_size)
+    {    
+        ret = RT_EOK;
+        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_Ioctl(h_ota, OTA_IOCTL_VERSION, msg_version, 33);
+            IOT_OTA_ReportSuccess(h_ota, msg_version);
+        }
+
+        LOG_INFO("Download firmware to flash success.");
+        LOG_INFO("System now will restart...");
+
+        rt_thread_delay(rt_tick_from_millisecond(5));
+
+        /* Reset the device, Start new firmware */
+        extern void rt_hw_cpu_reset(void);
+        rt_hw_cpu_reset();
+    }
+
+__exit:
+    if (buffer_read != RT_NULL)
+        HAL_Free(buffer_read);
+
+    IOT_OTA_Destroy(h_ota);
+
+    return ret;
+}
+
+

+ 12 - 3
uiot/ota/src/ota_fetch.c

@@ -67,24 +67,33 @@ int32_t ofc_connect(void *handle)
     const char *ca_crt = NULL;
 #endif
 
-    int32_t rc = http_client_common(&h_ofc->http, h_ofc->url, port, ca_crt, HTTP_GET, &h_ofc->http_data, 5000);
+    int32_t rc = http_client_connect(&h_ofc->http, h_ofc->url, port, ca_crt);
 
     FUNC_EXIT_RC(rc);
 }
 
 
-int32_t ofc_fetch(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s)
+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);
+    }    
+
     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;
     
-    int rc = http_client_recv_data(&h_ofc->http, timeout_s * 1000, &h_ofc->http_data);
+    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);

+ 1 - 1
uiot/sdk-impl/uiot_export.h

@@ -24,7 +24,7 @@ extern "C" {
 #define UIOT_MQTT_KEEP_ALIVE_INTERNAL                               (240)
 
 /* MQTT 阻塞调用(包括连接, 订阅, 发布等)的超时时间 */
-#define UIOT_MQTT_COMMAND_TIMEOUT                                   (5 * 10000)
+#define UIOT_MQTT_COMMAND_TIMEOUT                                   (5 * 1000)
 
 /* 接收到 MQTT 包头以后,接收剩余长度及剩余包,最大延迟等待时延 */
 #define UIOT_MQTT_MAX_REMAIN_WAIT_MS                                (2000)

+ 68 - 0
uiot/sdk-impl/uiot_export_ota.h

@@ -125,6 +125,66 @@ int IOT_OTA_ReportSuccess(void *handle, const char *version);
  */
 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 请求固件更新消息。设备离线时,不能接收服务端推送的升级消息。通过MQTT协议接入物联网平台的设备再次上线后,主动请求固件更新消息
  *
@@ -136,6 +196,14 @@ int IOT_OTA_ReportFail(void *handle, IOT_OTA_ReportErrCode err_code);
  */
 int IOT_OTA_RequestFirmware(void *handle, const char *version);
 
+/**
+ * @brief 下载固件,下载结束后重启设备
+ *
+ * @param handle:   指定OTA模块
+ *
+ * @return 对应错误的错误码.
+ */
+int IOT_OTA_fw_download(void *handle);
 
 #ifdef __cplusplus
 }

+ 0 - 2
uiot/shadow/src/shadow_client.c

@@ -86,8 +86,6 @@ int IOT_Shadow_Destroy(void *handle)
     UIoT_Shadow* shadow_client = (UIoT_Shadow*)handle;
     uiot_shadow_reset(handle);
 
-    IOT_MQTT_Destroy(&shadow_client->mqtt);
-
     if (NULL != shadow_client->request_mutex) {
         HAL_MutexDestroy(shadow_client->request_mutex);
     }

+ 26 - 57
uiot/utils/utils_httpc.c

@@ -108,7 +108,7 @@ static int _utils_fill_tx_buffer(http_client_t *client, unsigned char *send_buf,
     return SUCCESS_RET;
 }
 
-static int _http_send_header(http_client_t *client, char *host, const char *path, int method,
+static int _http_send_header(http_client_t *client, char *host, const char *path, int method, uint32_t size_fetched, size_t range_len,
                              http_client_data_t *client_data) {
     int len;
     unsigned char send_buf[HTTP_CLIENT_SEND_BUF_SIZE] = {0};
@@ -122,7 +122,7 @@ static int _http_send_header(http_client_t *client, char *host, const char *path
     memset(send_buf, 0, HTTP_CLIENT_SEND_BUF_SIZE);
     len = 0; /* Reset send buffer */
 
-    HAL_Snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", pMethod, path, host); /* Write request */
+    HAL_Snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\nRange: bytes=%d-%d\r\n", pMethod, path, host, size_fetched, size_fetched + range_len); /* Write request */
 
     ret = _utils_fill_tx_buffer(client, send_buf, &len, buf, strlen(buf));
     if (ret < 0) {
@@ -175,14 +175,10 @@ int _http_send_user_data(http_client_t *client, http_client_data_t *client_data,
 static int _http_recv(http_client_t *client, unsigned char *buf, int max_len, int *p_read_len,
                       uint32_t timeout_ms) {
     int ret = 0;
-    Timer timer;
-
-    init_timer(&timer);
-    countdown_ms(&timer, timeout_ms);
 
     *p_read_len = 0;
 
-    ret = client->net.read(&client->net, buf, max_len, left_ms(&timer));
+    ret = client->net.read(&client->net, buf, max_len, timeout_ms);
 
     if (ret > 0) {
         *p_read_len = ret;
@@ -282,7 +278,7 @@ static int _http_get_response_body(http_client_t *client, unsigned char *data, i
                                              client_data->response_buf_len - 1 - written_response_buf_len);
                 max_len_to_receive = Min(max_len_to_receive, client_data->retrieve_len);
 
-                ret = _http_recv(client, data, max_len_to_receive, &data_len_actually_received, left_ms(&timer));
+                ret = _http_recv(client, data, max_len_to_receive, &data_len_actually_received, timeout_ms);
                 if (ret == ERR_HTTP_CONN_ERROR) {
                     return ret;
                 }
@@ -306,14 +302,10 @@ static int _http_get_response_body(http_client_t *client, unsigned char *data, i
 static int _http_parse_response_header(http_client_t *client, char *data, int len, uint32_t timeout_ms,
                                        http_client_data_t *client_data) {
     int crlf_pos;
-    Timer timer;
     char *tmp_ptr, *ptr_body_end;
     int new_trf_len, ret;
     char *crlf_ptr;
 
-    init_timer(&timer);
-    countdown_ms(&timer, timeout_ms);
-
     client_data->response_content_len = -1;
 
     /* http client response */
@@ -343,7 +335,7 @@ static int _http_parse_response_header(http_client_t *client, char *data, int le
     while (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) {
         /* try to read more header */
         ret = _http_recv(client, (unsigned char *) (data + len), HTTP_CLIENT_READ_HEAD_SIZE, &new_trf_len,
-                         left_ms(&timer));
+                         timeout_ms);
         if (ret == ERR_HTTP_CONN_ERROR) {
             return ret;
         }
@@ -359,7 +351,7 @@ static int _http_parse_response_header(http_client_t *client, char *data, int le
         LOG_ERROR("Could not parse header");
         return ERR_HTTP_CONN_ERROR;
     }
-
+    
     /* remove header length */
     /* len is Had read body's length */
     /* if client_data->response_content_len != 0, it is know response length */
@@ -367,7 +359,7 @@ static int _http_parse_response_header(http_client_t *client, char *data, int le
     len = len - (ptr_body_end + 4 - data);
     memmove(data, ptr_body_end + 4, len + 1);
     client_data->response_received_len += len;
-    return _http_get_response_body(client, (unsigned char *) data, len, left_ms(&timer), client_data);
+    return _http_get_response_body(client, (unsigned char *) data, len, timeout_ms, client_data);
 }
 
 static int _http_connect(http_client_t *client) {
@@ -395,7 +387,7 @@ static int _http_connect(http_client_t *client) {
     return SUCCESS_RET;
 }
 
-int _http_send_request(http_client_t *client, const char *url, HTTP_Request_Method method,
+int _http_send_request(http_client_t *client, const char *url, HTTP_Request_Method method, uint32_t size_fetched, size_t range_len,
                        http_client_data_t *client_data, uint32_t timeout_ms) {
     int ret = ERR_HTTP_CONN_ERROR;
 
@@ -412,7 +404,7 @@ int _http_send_request(http_client_t *client, const char *url, HTTP_Request_Meth
         return rc;
     }
 
-    ret = _http_send_header(client, host, path, method, client_data);
+    ret = _http_send_header(client, host, path, method, size_fetched, range_len, client_data);
     if (ret != 0) {
         return -2;
     }
@@ -430,10 +422,6 @@ int _http_send_request(http_client_t *client, const char *url, HTTP_Request_Meth
 static int _http_client_recv_response(http_client_t *client, uint32_t timeout_ms, http_client_data_t *client_data) {
     int read_len = 0, ret = ERR_HTTP_CONN_ERROR;
     char buf[HTTP_CLIENT_READ_BUF_SIZE] = {0};
-    Timer timer;
-
-    init_timer(&timer);
-    countdown_ms(&timer, timeout_ms);
 
     if (0 == client->net.handle) {
         LOG_ERROR("no connection have been established");
@@ -442,11 +430,11 @@ static int _http_client_recv_response(http_client_t *client, uint32_t timeout_ms
 
     if (client_data->is_more) {
         client_data->response_buf[0] = '\0';
-        ret = _http_get_response_body(client, (unsigned char *) buf, read_len, left_ms(&timer), client_data);
+        ret = _http_get_response_body(client, (unsigned char *) buf, read_len, timeout_ms, client_data);
     } else {
         client_data->is_more = 1;
         /* try to read header */
-        ret = _http_recv(client, (unsigned char *) buf, HTTP_CLIENT_READ_HEAD_SIZE, &read_len, left_ms(&timer));
+        ret = _http_recv(client, (unsigned char *) buf, HTTP_CLIENT_READ_HEAD_SIZE, &read_len, timeout_ms);
         if (ret != 0) {
             return ret;
         }
@@ -454,7 +442,7 @@ static int _http_client_recv_response(http_client_t *client, uint32_t timeout_ms
         buf[read_len] = '\0';
 
         if (read_len) {
-            ret = _http_parse_response_header(client, buf, read_len, left_ms(&timer), client_data);
+            ret = _http_parse_response_header(client, buf, read_len, timeout_ms, client_data);
         }
     }
 
@@ -491,44 +479,25 @@ int http_client_connect(http_client_t *client, const char *url, int port, const
     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, 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 rc;
+    int rc = SUCCESS_RET;
     Timer timer;
 
     init_timer(&timer);
-    countdown_ms(&timer, (unsigned int) timeout_ms);
-
-    if ((NULL != client_data->response_buf)
-        && (0 != client_data->response_buf_len)) {
-        rc = _http_client_recv_response(client, left_ms(&timer), client_data);
-        if (rc < 0) {
-            LOG_ERROR("_http_client_recv_response is error, rc = %d", rc);
-            http_client_close(client);
-            return rc;
+    countdown_ms(&timer, timeout_ms);
+
+    do
+    {
+        if ((NULL != client_data->response_buf)
+            && (0 != client_data->response_buf_len)) {
+            rc = _http_client_recv_response(client, timeout_ms, client_data);
+        } 
+        if(client_data->is_more)
+        {
+            return SUCCESS_RET;
         }
-    }
-    return SUCCESS_RET;
+    }while((rc != SUCCESS_RET) && (!has_expired(&timer)));
+    return rc;
 }
 
 void http_client_close(http_client_t *client) {

+ 4 - 3
uiot/utils/utils_httpc.h

@@ -59,9 +59,6 @@ typedef struct {
 
 int http_client_connect(http_client_t *client, const char *url, int port, 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);
 
 void http_client_close(http_client_t *client);
@@ -70,6 +67,10 @@ int _http_send_user_data(http_client_t *client, http_client_data_t *client_data,
 
 void http_client_file_md5(char* file_path, char *output);
 
+int _http_send_request(http_client_t *client, const char *url, HTTP_Request_Method method, uint32_t size_fetched, size_t range_len, 
+                       http_client_data_t *client_data, uint32_t timeout_ms);
+
+
 #ifdef __cplusplus
 }
 #endif