diff --git a/customer_app/bl602_demo_qcloud/BLE_Use_Manual.docx b/customer_app/bl602_demo_qcloud/BLE_Use_Manual.docx new file mode 100644 index 00000000..38b62c8a Binary files /dev/null and b/customer_app/bl602_demo_qcloud/BLE_Use_Manual.docx differ diff --git a/customer_app/bl602_demo_qcloud/BLE_Use_Manual.pdf b/customer_app/bl602_demo_qcloud/BLE_Use_Manual.pdf new file mode 100644 index 00000000..e5b34639 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/BLE_Use_Manual.pdf differ diff --git a/customer_app/bl602_demo_qcloud/BLE_Use_Manual.rst b/customer_app/bl602_demo_qcloud/BLE_Use_Manual.rst new file mode 100644 index 00000000..b14aa404 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/BLE_Use_Manual.rst @@ -0,0 +1,204 @@ +========== +准备 +========== + +1. 硬件:BL602模块一个,Windows PC一台,装有配网app的安卓手机一台,USB转串口线一根。 +2. 软件:烧写工具,烧录的sdk_app_ble_sync.bin文件,路径:Bouffalolab_BL602_Evaluation_Package/App_Demos/sdk_app_ble_sync/build_out/sdk_app_ble_sync.bin,串口工具putty。(\ `下载链接 `__\) + +.. figure:: picture/image1.png + :align: center + + Putty下载 + +=========== +烧录 +=========== + +连接 +====== +BL602模块的相关引脚连接如下图所示,其中图1是模块的正面图,其标号1处用跳线帽短接,标号2处将左边两根排针短接,标号3处将上面的两根排针短接;图2是模块的背面图,烧录时将IO8和HI两根排针短接,烧录完成后将IO8和LOW两根排针短接并重新上电。用USB转串口线连接PC和模块,此时模块上的电源灯常亮,表明模块通电正常。 + +.. figure:: picture/image2.png + :align: center + + 正面 + +.. figure:: picture/image3.png + :align: center + + 背面 + +软件下载 +============ +打开烧写工具Bouffalo Lab Dev Cube 中的BLFlashEnv.exe,chip type选择BL602/604,打开后界面参数参考下图配置: + +.. figure:: picture/image4.png + :align: center + + 烧写工具界面 + +.. figure:: picture/image5.png + :align: center + + 烧写成功 + +其中图3的左框中COM Port选项根据实际串口情况选择(右击我的电脑->管理->设备管理器->端口,查看端口号,模块是双串口,选择端口号较小的),右框中的相关路径依据实际情况选择。配置完成后点击Download按钮下载,下载成功如图4所示。 + +putty配置 +============= + +将IO8和LOW两根排针短接并重新上电,打开putty工具,设置对应的端口号,波特率设定为2000000 bps。 + +.. figure:: picture/image6.png + :align: center + + Putty + +============== +App配网步骤 +============== +1. 在putty中输入“reboot”命令重启模块,模块上电后会自动开启ble广播,等待手机APP连接配网,串口打印如下所示: + +.. figure:: picture/image7.png + :align: center + + 开启ble广播log + +2. 打开配网APP,APP自动搜索蓝牙设备(需手机蓝牙已开启),搜索到设备名“BL602-BLE-DEV”; + +.. figure:: picture/image8.png + :align: center + + 手机搜索到的蓝牙设备 + +3. 点击该设备名,然后点击APP中的“连接”,APP会显示连接模块蓝牙的状态,串口中会打印设备连接成功的log; + +.. figure:: picture/image9.png + :align: center + + APP显示的蓝牙状态 + +.. figure:: picture/image10.png + :align: center + + 蓝牙连接成功log + +4. 点击“扫描”,等待数秒后APP会显示模块扫描到的WiFi设备列表,用户可以通过扫描出来的设备列表选择相应的WiFi进行连接,连接成功后页面红色字体部分为模块的WiFi相关信息(此状态暂时不会自动更新,需要用户点击“状态”选项手动更新)。用户可以点击“断开wifi”选项使模块断开WiFi连接。 + +.. figure:: picture/image11.png + :align: center + + APP显示模块扫描到的WiFi列表 + +.. figure:: picture/image12.png + :align: center + + 模块扫描的WiFi列表log + +.. figure:: picture/image13.png + :align: center + + 连接WiFi + +.. figure:: picture/image14.png + :align: center + + 模块成功连接WiFi的log + +.. figure:: picture/image15.png + :align: center + + APP显示WiFi连接成功(通过点击“状态”更新后模块的WiFi信息) + +.. figure:: picture/image16.png + :align: center + + 断开WiFi连接 + +.. figure:: picture/image17.png + :align: center + + 模块断开WiFi连接log + +5. 当用户确定配网完成时,不需要再使用配网功能,可以使用“blsync_ble_stop”命令将其关闭,如需重新配网请重复步骤1-5。 + +.. figure:: picture/image18.png + :align: center + + 关闭BLE + +======================== +微信小程序配网步骤 +======================== +1. 在putty中输入“reboot”命令重启模块,模块上电运行会自动开启ble广播,串口打印如下所示: + +.. figure:: picture/image19.png + :align: center + + 开启ble广播log + +2. 打开微信扫描下图二维码,点击“搜索”(需手机蓝牙已开启),搜索到设备名“BL602-BLE-DEV”,点击“BL602-BLE-DEV”连接设备,连接成功后界面上出现操作WiFi相关的功能; + +.. figure:: picture/image20.png + :align: center + + 配网二维码 + +.. figure:: picture/image21.png + :align: center + + 搜到的设备 + +.. figure:: picture/image22.png + :align: center + + 连接设备成功 + +.. figure:: picture/image23.png + :align: center + + 蓝牙连接成功log + +3. 点击小程序中的“获取WiFi列表”,小程序会回显获取到的WiFi列表,用户可以通过扫描出来的设备列表对需要配网的WiFi进行连接,点击需要连接的WiFi名称,接着在输入框输入WiFi密码,点击“发送密码”,即可连接WiFi; + +.. figure:: picture/image24.png + :align: center + + 模块扫描到的WiFi列表 + +.. figure:: picture/image25.png + :align: center + + 连接WiFi成功 + +.. figure:: picture/image26.png + :align: center + + 模块成功连接WiFi的log + +4. 点击小程序中的“更新WiFi状态”按钮,获取WiFi当前的连接状态; + +.. figure:: picture/image27.png + :align: center + + 更新WiFi连接状态 + +5. 点击断开WiFi按钮,即可断开WiFi,再次点击”获取状态“按钮可以获取当前WiFi已经断开; + +.. figure:: picture/image28.png + :align: center + + 断开WiFi + +.. figure:: picture/image29.png + :align: center + + 模块断开WiFi连接log + +6. 当用户确定配网完成时,不需要再使用配网功能,可以使用“blsync_ble_stop”命令将其关闭,如需重新配网请重复步骤1-6。 + +.. figure:: picture/image30.png + :align: center + + 关闭BLE + diff --git a/customer_app/bl602_demo_qcloud/Makefile b/customer_app/bl602_demo_qcloud/Makefile new file mode 100644 index 00000000..b2e84f95 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/Makefile @@ -0,0 +1,40 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := sdk_app_qcloud +PROJECT_PATH := $(abspath .) +PROJECT_BOARD := evb +export PROJECT_PATH PROJECT_BOARD +#CONFIG_TOOLPREFIX := + +-include ./proj_config.mk + +ifeq ($(origin BL60X_SDK_PATH), undefined) +BL60X_SDK_PATH_GUESS ?= $(shell pwd) +BL60X_SDK_PATH ?= $(BL60X_SDK_PATH_GUESS)/../.. +$(info ****** Please SET BL60X_SDK_PATH ******) +$(info ****** Trying SDK PATH [$(BL60X_SDK_PATH)]) +endif + +COMPONENTS_NETWORK := sntp dns_server +COMPONENTS_BLSYS := bltime blfdt blmtd blota bloop loopadc looprt loopset +COMPONENTS_VFS := romfs +COMPONENTS_BLE := blecontroller blestack + +INCLUDE_COMPONENTS += freertos_riscv_ram bl602 bl602_std bl602_wifi bl602_wifidrv hal_drv lwip lwip_dhcpd mbedtls vfs yloop utils cli httpc netutils blog blog_testc blsync_ble cjson qcloud_iot_c_sdk +INCLUDE_COMPONENTS += easyflash4 +INCLUDE_COMPONENTS += $(COMPONENTS_NETWORK) +INCLUDE_COMPONENTS += $(COMPONENTS_BLSYS) +INCLUDE_COMPONENTS += $(COMPONENTS_VFS) +INCLUDE_COMPONENTS += $(PROJECT_NAME) + +ifeq ($(CONFIG_BT),1) +INCLUDE_COMPONENTS += $(COMPONENTS_BLE) +ifeq ($(CONFIG_BT_MESH),1) +INCLUDE_COMPONENTS += blemesh +endif +endif + +include $(BL60X_SDK_PATH)/make_scripts_riscv/project.mk diff --git a/customer_app/bl602_demo_qcloud/README.md b/customer_app/bl602_demo_qcloud/README.md new file mode 100644 index 00000000..f89fd881 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/README.md @@ -0,0 +1,30 @@ +# BL602 IoT Device Access Tencent Cloud + +1.设备配网 + +如何使用此例程请参考目录下的[用户手册](BLE_Use_ Manual.pdf)进行BLE配网或者使用wifi_sta_connect的命令行配置。 + +2.腾讯云平台接入 + +此demo已经完成了腾讯云平台的接入,用户只需要修改腾讯三元组即可,配置好在配网之后发送tencent命令即可运行。 + +sg_product_id : product Id + +sg_device_name : device name + +sg_product_secret : product secret for device dynamic Registration + +这三个信息可以在云平台的设备信息里面查到: + +![deviceinfo](deviceinfo.jpg) + + + +如何构建一个产品和具体上报信息json适配可以参考腾讯云平台的接入文档: + +腾讯云官方文档:[腾讯云]:https://cloud.tencent.com/document/product/1081/44921 + +此工程的使用的Sensor芯片为北京中科银河芯科技的GXHT3X Humidity and Temperature Sensor。 + +北京中科银河芯科技有限公司是依托中国科学院微电子研究所雄厚的人才和科研技术资源成立的技术创新驱动型企业;公司面向汽车电子、智能制造、物联网、工业领域、消费电子领域的产业需求,致力于温度、湿度、水分、压力、电子标签等传感芯片设计、开发、销售并提供相关技术咨询和技术服务。如需了解更多请访问:http://gxcas.com/ + diff --git a/customer_app/bl602_demo_qcloud/bleapp.apk b/customer_app/bl602_demo_qcloud/bleapp.apk new file mode 100644 index 00000000..995c637c Binary files /dev/null and b/customer_app/bl602_demo_qcloud/bleapp.apk differ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/bouffalo.mk b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/bouffalo.mk new file mode 100644 index 00000000..5216e887 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/bouffalo.mk @@ -0,0 +1,69 @@ +# Component Makefile +# +## These include paths would be exported to project level +COMPONENT_ADD_INCLUDEDIRS += include \ + include/exports \ + sdk_src/internal_inc + +qcloud_iot_src := sdk_src \ + platform +## not be exported to project level +COMPONENT_PRIV_INCLUDEDIRS := + +## This component's src +COMPONENT_SRCS := platform/HAL_Device_freertos.c \ + platform/HAL_DTLS_mbedtls.c \ + platform/HAL_OS_freertos.c \ + platform/HAL_TCP_lwip.c \ + platform/HAL_Timer_freertos.c \ + platform/HAL_TLS_mbedtls.c \ + platform/HAL_UDP_lwip.c \ + sdk_src/asr_client.c \ + sdk_src/data_template_action.c \ + sdk_src/data_template_client.c \ + sdk_src/data_template_client_common.c \ + sdk_src/data_template_client_json.c \ + sdk_src/data_template_client_manager.c \ + sdk_src/data_template_event.c \ + sdk_src/dynreg.c \ + sdk_src/json_parser.c \ + sdk_src/json_token.c \ + sdk_src/mqtt_client.c \ + sdk_src/mqtt_client_common.c \ + sdk_src/mqtt_client_connect.c \ + sdk_src/mqtt_client_net.c \ + sdk_src/mqtt_client_publish.c \ + sdk_src/mqtt_client_subscribe.c \ + sdk_src/mqtt_client_unsubscribe.c \ + sdk_src/mqtt_client_yield.c \ + sdk_src/network_interface.c \ + sdk_src/network_socket.c \ + sdk_src/network_tls.c \ + sdk_src/ota_client.c \ + sdk_src/ota_fetch.c \ + sdk_src/ota_lib.c \ + sdk_src/ota_mqtt.c \ + sdk_src/qcloud_iot_ca.c \ + sdk_src/qcloud_iot_device.c \ + sdk_src/qcloud_iot_log.c \ + sdk_src/qutils_base64.c \ + sdk_src/qutils_hmac.c \ + sdk_src/qutils_list.c \ + sdk_src/qutils_md5.c \ + sdk_src/qutils_sha1.c \ + sdk_src/resource_client.c \ + sdk_src/service_mqtt.c \ + sdk_src/qstring_utils.c \ + sdk_src/qutils_aes.c \ + sdk_src/qutils_httpc.c \ + sdk_src/qutils_ringbuff.c \ + sdk_src/qutils_timer.c \ + sdk_src/qutils_url_download.c\ + sdk_src/qutils_url_upload.c \ + sdk_src/qutils_getopt.c +COMPONENT_OBJS := $(patsubst %.c,%.o, $(COMPONENT_SRCS)) + +COMPONENT_SRCDIRS := $(qcloud_iot_src) + + + diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/config.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/config.h new file mode 100644 index 00000000..169f06af --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/config.h @@ -0,0 +1,23 @@ +/* #undef AUTH_MODE_CERT */ +#define AUTH_MODE_KEY +/* #undef AUTH_WITH_NOTLS */ +/* #undef GATEWAY_ENABLED */ +/* #undef COAP_COMM_ENABLED */ +#define OTA_MQTT_CHANNEL +/* #undef SYSTEM_COMM */ +/* #undef EVENT_POST_ENABLED */ +/* #undef ACTION_ENABLED */ +#define DEV_DYN_REG_ENABLED +/* #undef LOG_UPLOAD */ +/* #undef IOT_DEBUG */ +/* #undef DEBUG_DEV_INFO_USED */ +/* #undef AT_TCP_ENABLED */ +/* #undef AT_UART_RECV_IRQ */ +/* #undef AT_OS_USED */ +/* #undef AT_DEBUG */ +#define OTA_USE_HTTPS +/* #undef GATEWAY_ENABLED */ +/* #undef MULTITHREAD_ENABLED */ +/* #undef GATEWAY_DYN_BIND_SUBDEV_ENABLED */ +#define ASR_ENABLED +#define RESOURCE_UPDATE_ENABLED diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_asr.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_asr.h new file mode 100644 index 00000000..96de4277 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_asr.h @@ -0,0 +1,171 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_ASR_H_ +#define QCLOUD_IOT_EXPORT_ASR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_import.h" + +#define REAL_TIME_SLICE_FILE_NAME_LEN (64) +#define VOICE_ID_LEN (16) + +// refer to https://cloud.tencent.com/document/product/1093/37823#2.-.E8.BE.93.E5.85.A5.E5.8F.82.E6.95.B0 +typedef enum { + eENGINE_8K_EN = 0, + eENGINE_8K_ZH = 1, + eENGINE_8K_ZH_S = 2, + eENGINE_16K_ZH = 3, + eENGINE_16K_ZH_VIDEO = 4, + eENGINE_16K_EN = 5, + eENGINE_16K_CA = 6, + eENGINE_16K_JA = 7, + eENGINE_16K_WUU_SH = 8, + eENGINE_DEFAULT = 9, +} eAsrEngineType; + +typedef enum { + eASR_FILE = 0, + eASR_REALTIME = 1, + eASR_SENTENCE = 2, +} eAsrType; + +typedef enum { + eVOICE_WAVE = 1, + eVOICE_SPEEX = 4, + eVOICE_SILK = 6, + eVOICE_MP3 = 8, + eVOICE_OPUS = 10, +} eVoiceType; + +typedef enum { + eRESPONSE_PER_SLICE = 0, + eRESPONSE_END = 1, +} eResType; + +typedef struct _RecordAsrConf_ { + uint32_t request_timeout_ms; + + // Required parameters + eAsrType req_type; + eAsrEngineType engine_type; + int ch_num; + + // Optional parameters + int filter_dirty; + int filter_modal; + int filter_punc; + int convert_num_mode; + int speaker_diarization; + int speaker_number; + char *hot_word_id; +} RecordAsrConf; + +// refer to https://cloud.tencent.com/document/product/1093/35799#.E8.AF.B7.E6.B1.82.E7.BB.93.E6.9E.84 +typedef struct _RealTimeAsrConf_ { + uint32_t request_timeout_ms; + char file_name[REAL_TIME_SLICE_FILE_NAME_LEN]; + + // Required parameters + eAsrType req_type; + eAsrEngineType engine_type; + eResType res_type; + eVoiceType voice_format; + char voice_id[VOICE_ID_LEN + 1]; + int seq; + int end; + + // Optional parameters + int need_vad; + int vad_silence_time; + int filter_dirty; + int filter_modal; + int filter_punc; + int convert_num_mode; + char *hot_word_id; +} RealTimeAsrConf; + +typedef void (*OnAsrResultCB)(uint32_t request_id, char *res_text, int total_resutl_num, int resutl_seq); + +typedef int (*OnAsrResourceEventUsrCallback)(void *pContext, const char *msg, uint32_t msgLen, int event); + +/** + * @brief Init asr client + * MQTT Client should be constructed beforehand + * + * @param product_id: product Id + * @param device_name: device name + * @param pTemplate_client: data template client + * @param usr_cb: user callback + * + * @return a valid asr client handle when success, or NULL otherwise + */ +void *IOT_Asr_Init(const char *product_id, const char *device_name, void *pTemplate_client, + OnAsrResourceEventUsrCallback usr_cb); + +/** + * @brief Destroy asr client + * + * @param handle: asr client handle + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Asr_Destroy(void *handle); + +/** + * @brief Record file asr request + * + * @param handle: asr client handle + * + * @param file_name: record file name with path + * + * @param conf: record file parameter and request conf + * + * @param cb: callback function when asr result received + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Asr_RecordFile_Request(void *handle, const char *file_name, RecordAsrConf *conf, OnAsrResultCB cb); + +/** + * @brief Realtime asr + * + * @param handle: asr client handle + * + * @param audio_buff: audio data with encoding,like wav/speex/silk/mp3/opus + * + * @param audio_data_len: audio data len + * + * @param conf: real time audio data parameter and request conf + * + * @param cb: callback function when asr result received + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Asr_Realtime_Request(void *handle, char *audio_buff, uint32_t audio_data_len, RealTimeAsrConf *conf, + OnAsrResultCB cb); +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_OTA_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_data_template.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_data_template.h new file mode 100644 index 00000000..de02da10 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_data_template.h @@ -0,0 +1,614 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_DATA_TEMPLATE_H_ +#define QCLOUD_IOT_EXPORT_DATA_TEMPLATE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_export_method.h" +#include "qcloud_iot_export_mqtt.h" + +#define MAX_CONTORL_REPLY_STATUS_LEN 64 // max len of status within control reply msg + +/** + * @brief Data type of template + */ + +#define TYPE_TEMPLATE_INT JINT32 +#define TYPE_TEMPLATE_ENUM JINT32 +#define TYPE_TEMPLATE_FLOAT JFLOAT +#define TYPE_TEMPLATE_BOOL JINT8 +#define TYPE_TEMPLATE_STRING JSTRING +#define TYPE_TEMPLATE_TIME JUINT32 +#define TYPE_TEMPLATE_JOBJECT JOBJECT + +typedef int32_t TYPE_DEF_TEMPLATE_INT; +typedef int32_t TYPE_DEF_TEMPLATE_ENUM; +typedef float TYPE_DEF_TEMPLATE_FLOAT; +typedef char TYPE_DEF_TEMPLATE_BOOL; +typedef char TYPE_DEF_TEMPLATE_STRING; +typedef uint32_t TYPE_DEF_TEMPLATE_TIME; +typedef void * TYPE_DEF_TEMPLATE_OBJECT; + +#ifdef EVENT_POST_ENABLED // enable event function of data_template + +#define TYPE_STR_INFO "info" +#define TYPE_STR_ALERT "alert" +#define TYPE_STR_FAULT "fault" + +/*If defined,event's timesamp should be accurate UTC timestamp in millisecond */ +#define EVENT_TIMESTAMP_USED + +#define FLAG_EVENT0 (1U << 0) +#define FLAG_EVENT1 (1U << 1) +#define FLAG_EVENT2 (1U << 2) +#define FLAG_EVENT3 (1U << 3) +#define FLAG_EVENT4 (1U << 4) +#define FLAG_EVENT5 (1U << 5) +#define FLAG_EVENT6 (1U << 6) +#define FLAG_EVENT7 (1U << 7) +#define FLAG_EVENT8 (1U << 8) +#define FLAG_EVENT9 (1U << 9) + +#define ALL_EVENTS_MASK (0xFFFFFFFF) + +typedef struct _sEvent_ { + char * event_name; // event name + char * type; // event type + uint32_t timestamp; // event timestamp + uint8_t eventDataNum; // number of event properties + DeviceProperty *pEventData; // event properties +} sEvent; + +#endif + +typedef enum{ + eGET_CTL, + eOPERATION_CTL, +}eControlType; +typedef void (*ControlMsgCb)(void *pClient, char *control_str, eControlType type); + +/* The structure of data_template init parameters */ +typedef struct { + char *region; // region + /* device info */ + char *product_id; // product ID + char *device_name; // device name + +#ifdef AUTH_MODE_CERT + char *cert_file; // cert file path + char *key_file; // key file path +#else + char *device_secret; // device secret +#endif + + uint32_t command_timeout; // timeout value (unit: ms) for MQTT + // connect/pub/sub/yield + uint32_t keep_alive_interval_ms; // MQTT keep alive time interval in millisecond + + uint8_t clean_session; // flag of clean session, 1 clean, 0 not clean + + uint8_t auto_connect_enable; // flag of auto reconnection, 1 is enable and + // recommended + + MQTTEventHandler event_handle; // event callback + ControlMsgCb usr_control_handle; // user can register cb to handle control msg instend of sdk's handle +} TemplateInitParams; + +#ifdef AUTH_MODE_CERT +#define DEFAULT_TEMPLATE_INIT_PARAMS \ + { \ + "china", NULL, NULL, NULL, NULL, 2000, 240 * 1000, 1, 1, { 0 } \ + } +#else +#define DEFAULT_TEMPLATE_INIT_PARAMS \ + { \ + "china", NULL, NULL, NULL, 2000, 240 * 1000, 1, 1, { 0 } \ + } +#endif + +typedef enum _eReplyCode_ { + eDEAL_SUCCESS = 0, + eDEAL_FAIL = -1, +} eReplyCode; + +/** + * @brief control msg reply parameter + */ +typedef struct _sReplyPara { + uint32_t timeout_ms; // request timeout time, unit:ms + eReplyCode code; // reply code. 0:success, ~0:failed + char status_msg[MAX_CONTORL_REPLY_STATUS_LEN]; // reply message + +} sReplyPara; + +/** + * @brief Define property status in data template + */ +typedef enum _eDataState_ { + eNOCHANGE = 0, + eCHANGED = 1, +} eDataState; + +/** + * @brief Define data point in data template + */ +typedef struct { + DeviceProperty data_property; + eDataState state; +} sDataPoint; + +typedef void (*DataTemplateDestroyCb)(void *pclient); + +/** + * @brief Create data_template client and connect to MQTT server + * + * @param pParams data_template init parameters + * + * @param pMqttClient data_template mqtt_client,construct mqtt_client if input + * NULL + * + * @return a valid data_template client handle when success, or NULL otherwise + */ +void *IOT_Template_Construct(TemplateInitParams *pParams, void *pMqttClient); + +/** + * @brief Publish MQTT message + * + * @param pClient handle to data_template client + * @param topicName MQTT topic name + * @param pParams publish parameters + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Template_Publish(void *pClient, char *topicName, PublishParams *pParams); + +/** + * @brief Subscribe MQTT message + * + * @param pClient handle to data_template client + * @param topicFilter MQTT topic filter + * @param pParams subscribe parameters + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Template_Subscribe(void *pClient, char *topicFilter, SubscribeParams *pParams); + +/** + * @brief Unsubscribe MQTT message + * + * @param pClient handle to data_template client + * @param topicFilter MQTT topic filter + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Template_Unsubscribe(void *pClient, char *topicFilter); + +/** + * @brief Check if MQTT data_template is connected + * + * @param pClient handle to data_template client + * @return true= connected, false = unconnected + */ +bool IOT_Template_IsConnected(void *pClient); + +/** + * @brief Close connection and destroy MQTT data_template client + * + * @param pClient pointer of handle to data_template client + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int IOT_Template_Destroy(void *pClient); + +/** + * @brief Check connection and keep alive state, read/handle MQTT message by synchronized way + * + * @param pClient handle to data_template client + * @param timeout_ms timeout value (unit: ms) for this operation + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Template_Yield(void *pClient, uint32_t timeout_ms); + +/** + * @brief Get the mqtt client from data_template client + * + * @param pClient handle to data_template client + * @param timeout_ms timeout value (unit: ms) for this operation + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +void *IOT_Template_Get_MQTT_Client(void *pClient); + +#ifdef MULTITHREAD_ENABLED +/** + * @brief Start the default yield thread to read and handle data_template control and reply msg + * + * @param pClient handle to data_template client + * @return QCLOUD_RET_SUCCESS when success, err code for failure + */ +int IOT_Template_Start_Yield_Thread(void *pClient); + +/** + * @brief Stop the default yield thread to read and handle data_template control and reply msg + * + * @param pClient handle to data_template client + */ +void IOT_Template_Stop_Yield_Thread(void *pClient); + +/** + * @brief Get the status of yield thread + * + * @param pClient handle to data_template client + * @param exit_code exit code of the thread + * @return true= thread running, false = thread quit + */ +bool IOT_Template_Get_Yield_Status(void *pClient, int *exit_code); + +/** + * @brief Only release Data_Template Client resource, retain mqtt client for + * multi-thread case + * + * @param pClient handle to data_template client + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int IOT_Template_Destroy_Except_MQTT(void *pClient); +#endif + +/** + * @brief Register device property + * + * @param pClient handle to data_template client + * @param pProperty reference to device property + * @param callback callback when property changes + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Template_Register_Property(void *pClient, DeviceProperty *pProperty, OnPropRegCallback callback); + +/** + * @brief UnRegister device property + * + * @param pClient handle to data_template client + * @param pProperty reference to device property + * @return QCLOUD_RET_SUCCESS when success, or err code for + * failure + */ +int IOT_Template_UnRegister_Property(void *pClient, DeviceProperty *pProperty); + +/** + * @brief Get data_template client's data template + * + * @param pClient handle to data_template client + * @return data_template client's data template + */ +void *IOT_Template_Get_DataTemplate(void *pClient); + +/** + * @brief Set data_template client's data template + * + * @param pClient handle to data_template client + * @param data_template handle to data_template + * @param cb call back to destroy data_template + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Template_Set_DataTemplate(void *pClient, void *data_template, DataTemplateDestroyCb cb); + +#ifdef ACTION_ENABLED +int IOT_Template_Register_Action(void *pClient, DeviceAction *pAction, OnActionHandleCallback callback); + +int IOT_Template_UnRegister_Action(void *pClient, DeviceAction *pAction); +#endif + +/** + * @brief Add reported fields array in JSON document, don't overwrite + * + * @param pClient handle to data_template client + * @param jsonBuffer string buffer to store JSON document + * @param sizeOfBuffer size of string buffer + * @param count number of properties + * @param pDeviceProperties array of properties + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Template_JSON_ConstructReportArray(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, + DeviceProperty *pDeviceProperties[]); + +/** + * @brief report data_template data in asynchronized way + * + * @param pClient handle to data_template client + * @param pJsonDoc source JSON document for report + * @param sizeOfBuffer length of JSON document + * @param callback callback when response arrive + * @param userContext user data for callback + * @param timeout_ms timeout value for this operation (unit: ms) + * @return QCLOUD_RET_SUCCESS when success, or err code for + * failure + */ +int IOT_Template_Report(void *handle, char *pJsonDoc, size_t sizeOfBuffer, OnReplyCallback callback, void *userContext, + uint32_t timeout_ms); + +/** + * @brief report data_template data in synchronized way + * + * @param pClient handle to data_template client + * @param pJsonDoc source JSON document for report + * @param sizeOfBuffer length of JSON document + * @param timeout_ms timeout value for this operation (unit: ms) + * @return QCLOUD_RET_SUCCESS when success, or err code for + failure + + */ +int IOT_Template_Report_Sync(void *handle, char *pJsonDoc, size_t sizeOfBuffer, uint32_t timeout_ms); + +/** + * @brief Get data_template state from server in asynchronized way. + * Generally it's a way to sync data_template data during offline + * + * @param pClient handle to data_template client + * @param callback callback when response arrive + * @param userContext user data for callback + * @param timeout_ms timeout value for this operation (unit: ms) + * @return QCLOUD_RET_SUCCESS when success, or err code for + * failure + */ +int IOT_Template_GetStatus(void *handle, OnReplyCallback callback, void *userContext, uint32_t timeout_ms); + +/** + * @brief Get Get data_template state from server in asynchronized way + * + * @param pClient handle to data_template client + * @param timeout_ms timeout value for this operation (unit: ms) + * @return QCLOUD_RET_SUCCESS when success, or err code for + * failure + */ +int IOT_Template_GetStatus_sync(void *handle, uint32_t timeout_ms); + +/** + * @brief clear the control msg when IOT_Template_GetStatus get control msg + * @param pClient handle to data_template client + * @param pClientToken correspond to the clientToken of control msg + * @return QCLOUD_RET_SUCCESS when success, or err code for + * failure + */ +int IOT_Template_ClearControl(void *handle, char *pClientToken, OnReplyCallback callback, uint32_t timeout_ms); + +/** + * @brief reply to the control msg + * @param pClient handle to data_template client + * @param pJsonDoc data buffer for reply + * @param sizeOfBuffer length of data buffer + * @param replyPara reply info + * @return QCLOUD_RET_SUCCESS when success, or err code for + * failure + */ +int IOT_Template_ControlReply(void *handle, char *pJsonDoc, size_t sizeOfBuffer, sReplyPara *replyPara); + +/** + * @brief construct system information in json format + * @param pClient handle to data_template client + * @param jsonBuffer data buffer for construct + * @param sizeOfBuffer length of data buffer + * @param pPlatInfo pointer of platform info, compulsory + * @param pSelfInfo pointer of self-define info, option + * @return QCLOUD_RET_SUCCESS when success, or err +code for failure + + *package format for system info report +* { +* "method": "report_info", +* "clientToken": "client-token1618", +* "params": { +* "module_hardinfo": "esp8266", //if module used, compulsory +* "module_softinfo": "APP_2.0.0", //compulsory +* "fw_ver": "FW_1.0.0", //compulsory +* "imei": "123456789", //option +* "lat": "22.546015" //latitude,option +* "lon": "113.941125", //longitude,option +* "device_label": { +* "append_info": "your self define info" //self-define information,option +* ... +* } +* } +*/ +int IOT_Template_JSON_ConstructSysInfo(void *handle, char *jsonBuffer, size_t sizeOfBuffer, DeviceProperty *pPlatInfo, + DeviceProperty *pSelfInfo); + +/** + * @brief report system information in asynchronized way + * + * @param pClient handle to data_template client + * @param pJsonDoc source JSON document for report + * @param sizeOfBuffer length of JSON document + * @param callback callback when response arrive + * @param userContext user data for callback + * @param timeout_ms timeout value for this operation (unit: ms) + * @return QCLOUD_RET_SUCCESS when success, or err code + * for failure + */ +int IOT_Template_Report_SysInfo(void *handle, char *pJsonDoc, size_t sizeOfBuffer, OnReplyCallback callback, + void *userContext, uint32_t timeout_ms); + +/** + * @brief report data_template data in synchronized way + * + * @param pClient handle to data_template client + * @param pJsonDoc source JSON document for report + * @param sizeOfBuffer length of JSON document + * @param callback callback when response arrive + * @param userContext user data for callback + * @param timeout_ms timeout value for this operation (unit: ms) + * @return QCLOUD_RET_SUCCESS when success, or err code + * for failure + */ +int IOT_Template_Report_SysInfo_Sync(void *handle, char *pJsonDoc, size_t sizeOfBuffer, uint32_t timeout_ms); + +#ifdef EVENT_POST_ENABLED +/** + * @brief callback of event reply + * + * @param client handle to data_template client + * @param msg event reply msg + * + */ +typedef void (*OnEventReplyCallback)(void *client, MQTTMessage *msg); + +/** + * @brief set events flag when events occured + * + * @param client handle to data_template client + * @param flag event flags for set. per bit of 32bits represent one + * event. + * + */ +void IOT_Event_setFlag(void *client, uint32_t flag); + +/** + * @brief clear events flag after events dealed + * + * @param client handle to data_template client + * @param flag event flags for clear. per bit of 32bits represent one + * event. + * + */ +void IOT_Event_clearFlag(void *client, uint32_t flag); + +/** + * @brief get events flag setted + * + * @param client handle to data_template client + * @return events flag status + * + */ +uint32_t IOT_Event_getFlag(void *client); + +/** + * @brief init event function of data_template client + * + * @param c handle to data_template client + */ +int IOT_Event_Init(void *c); + +/** + * @brief handle event wait for reply timeout + * + * @param client handle to data_template client + */ +void handle_template_expired_event(void *client); + +/** + * @brief post event to cloud, SDK construct event json package + * @param pClient handle to data_template client + * @param pJsonDoc data buffer for event post + * @param sizeOfBuffer length of data buffer + * @param event_count event counts to post + * @param pEventArry pointer of events array to post + * @param replyCb callback when event reply received + * @return @see IoT_Error_Code + */ +int IOT_Post_Event(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, uint8_t event_count, sEvent *pEventArry[], + OnEventReplyCallback replyCb); + +/** + * @brief post event to cloud, user input raw event data + * @param pClient handle to data_template client + * @param pJsonDoc data buffer for event post + * @param sizeOfBuffer length of data buffer + * @param pEventMsg user input event raw data in json format + * event package format: + * {"method": "event_post", + * "clientToken": "123", + * "version": "1.0", + * "eventId": "PowerAlarm", + * "type": "fatal", + * "timestamp": 1212121221, + * "params": { + * "Voltage": 2.8, + * "Percent": 20 + * } + * } + + * pEventMsg for example + * single event: + * { + * "eventId": "PowerAlarm", + * "type": "fatal", + * "timestamp": 1212121221, + * "params": { + * "Voltage": 2.8, + * "Percent": 20 + * } + * } + * + * multi event: + * { + * "eventId": "PowerAlarm", + * "type": "fatal", + * "timestamp": 1212121221, + * "params": { + * "Voltage": 2.8, + * "Percent": 20 + * } + * }, + * { + * "name": "PowerAlarm", + * "type": "fatal", + * "timestamp": 1212121223, + * "params": { + * "Voltage": 2.1, + * "Percent": 10 + * } + * }, + * .... + * + * @param replyCb event callback when event reply received + * @return @see IoT_Error_Code + */ +int IOT_Post_Event_Raw(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, char *pEventMsg, + OnEventReplyCallback replyCb); + +#endif + +#ifdef ACTION_ENABLED +/** + * @brief reply to the action msg + * @param pClient handle to data_template client + * @param pClientToken correspond to the clientToken of action msg + * @param pJsonDoc data buffer for reply + * @param sizeOfBuffer length of data buffer + * @param pAction pointer of action + * @param replyPara action reply info + * @return QCLOUD_RET_SUCCESS when success, or err code + * for failure + */ + +int IOT_Action_Reply(void *pClient, const char *pClientToken, char *pJsonDoc, size_t sizeOfBuffer, + DeviceAction *pAction, sReplyPara *replyPara); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_TEMPLATE_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_dynreg.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_dynreg.h new file mode 100644 index 00000000..299dce0a --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_dynreg.h @@ -0,0 +1,45 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QLCOUD_IOT_EXPORT_DYNREG_H_ +#define QLCOUD_IOT_EXPORT_DYNREG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_export.h" + +/** + * @brief Do dynamic register/create device + * + * @param pDevInfo In: device info with [ProductId, ProductKey, DeviceName] + * Out: device info with [ProductId, DeviceName, + * DeviceSecret or Device cert/key file] + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int IOT_DynReg_Device(DeviceInfo *pDevInfo); + +#ifdef __cplusplus +} +#endif + +#endif // QLCOUD_IOT_EXPORT_DYNREG_H_ \ No newline at end of file diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_error.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_error.h new file mode 100644 index 00000000..36af264f --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_error.h @@ -0,0 +1,145 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_ERROR_H_ +#define QCLOUD_IOT_EXPORT_ERROR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * IOT SDK return/error code + * Enumeration of return code in QCloud IoT C-SDK. + * Values less than 0 are specific error codes + * Value of 0 is successful return + * Values greater than 0 are specific non-error return codes + */ +typedef enum { + QCLOUD_RET_MQTT_ALREADY_CONNECTED = 4, // Already connected with MQTT server + QCLOUD_RET_MQTT_CONNACK_CONNECTION_ACCEPTED = 3, // MQTT connection accepted by server + QCLOUD_RET_MQTT_MANUALLY_DISCONNECTED = 2, // Manually disconnected with MQTT server + QCLOUD_RET_MQTT_RECONNECTED = 1, // Reconnected with MQTT server successfully + + QCLOUD_RET_SUCCESS = 0, // Successful return + + QCLOUD_ERR_FAILURE = -1001, // Generic failure return + QCLOUD_ERR_INVAL = -1002, // Invalid parameter + QCLOUD_ERR_DEV_INFO = -1003, // Fail to get device info + QCLOUD_ERR_MALLOC = -1004, // Fail to malloc memory + + QCLOUD_ERR_HTTP_CLOSED = -3, // HTTP server close the connection + QCLOUD_ERR_HTTP = -4, // HTTP unknown error + QCLOUD_ERR_HTTP_PRTCL = -5, // HTTP protocol error + QCLOUD_ERR_HTTP_UNRESOLVED_DNS = -6, // HTTP DNS resolve failed + QCLOUD_ERR_HTTP_PARSE = -7, // HTTP URL parse failed + QCLOUD_ERR_HTTP_CONN = -8, // HTTP connect failed + QCLOUD_ERR_HTTP_AUTH = -9, // HTTP auth failed + QCLOUD_ERR_HTTP_NOT_FOUND = -10, // HTTP 404 + QCLOUD_ERR_HTTP_TIMEOUT = -11, // HTTP timeout + + QCLOUD_ERR_MQTT_PUSH_TO_LIST_FAILED = -102, // Fail to push node to MQTT waiting list + QCLOUD_ERR_MQTT_NO_CONN = -103, // Not connected with MQTT server + QCLOUD_ERR_MQTT_UNKNOWN = -104, // MQTT unknown error + QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT = -105, // Reconnecting with MQTT server + QCLOUD_ERR_MQTT_RECONNECT_TIMEOUT = -106, // MQTT reconnect timeout + QCLOUD_ERR_MQTT_MAX_SUBSCRIPTIONS = -107, // MQTT topic subscription out of range + QCLOUD_ERR_MQTT_SUB = -108, // MQTT topic subscription fail + QCLOUD_ERR_MQTT_NOTHING_TO_READ = -109, // MQTT nothing to read + QCLOUD_ERR_MQTT_PACKET_READ = -110, // Something wrong when reading MQTT packet + QCLOUD_ERR_MQTT_REQUEST_TIMEOUT = -111, // MQTT request timeout + QCLOUD_ERR_MQTT_CONNACK_UNKNOWN = -112, // MQTT connection refused: unknown error + QCLOUD_ERR_MQTT_CONNACK_UNACCEPTABLE_PROTOCOL_VERSION = -113, // MQTT connection refused: protocol version invalid + QCLOUD_ERR_MQTT_CONNACK_IDENTIFIER_REJECTED = -114, // MQTT connection refused: identifier rejected + QCLOUD_ERR_MQTT_CONNACK_SERVER_UNAVAILABLE = -115, // MQTT connection refused: service not available + QCLOUD_ERR_MQTT_CONNACK_BAD_USERDATA = -116, // MQTT connection refused: bad user name or password + QCLOUD_ERR_MQTT_CONNACK_NOT_AUTHORIZED = -117, // MQTT connection refused: not authorized + QCLOUD_ERR_RX_MESSAGE_INVAL = -118, // MQTT received invalid msg + QCLOUD_ERR_BUF_TOO_SHORT = -119, // MQTT recv buffer not enough + QCLOUD_ERR_MQTT_QOS_NOT_SUPPORT = -120, // MQTT QoS level not supported + QCLOUD_ERR_MQTT_UNSUB_FAIL = -121, // MQTT unsubscribe failed + + QCLOUD_ERR_JSON_PARSE = -132, // JSON parsing error + QCLOUD_ERR_JSON_BUFFER_TRUNCATED = -133, // JSON buffer truncated + QCLOUD_ERR_JSON_BUFFER_TOO_SMALL = -134, // JSON parsing buffer not enough + QCLOUD_ERR_JSON = -135, // JSON generation error + QCLOUD_ERR_MAX_JSON_TOKEN = -136, // JSON token out of range + + QCLOUD_ERR_MAX_APPENDING_REQUEST = -137, // appending request out of range + QCLOUD_ERR_MAX_TOPIC_LENGTH = -138, // Topic length oversize + + QCLOUD_ERR_COAP_NULL = -150, // COAP null pointer + QCLOUD_ERR_COAP_DATA_SIZE = -151, // COAP data size out of range + QCLOUD_ERR_COAP_INTERNAL = -152, // COAP interval error + QCLOUD_ERR_COAP_BADMSG = -153, // COAP bad msg + QCLOUD_ERR_DTLS_PEER_CLOSE_NOTIFY = -160, // DTLS connection is closed + + QCLOUD_ERR_PROPERTY_EXIST = -201, // property already exist + QCLOUD_ERR_NOT_PROPERTY_EXIST = -202, // property not exist + QCLOUD_ERR_REPORT_TIMEOUT = -203, // update timeout + QCLOUD_ERR_REPORT_REJECTED = -204, // update rejected by server + QCLOUD_ERR_GET_TIMEOUT = -205, // get timeout + QCLOUD_ERR_GET_REJECTED = -206, // get rejected by server + + QCLOUD_ERR_ACTION_EXIST = -210, // acion already exist + QCLOUD_ERR_NOT_ACTION_EXIST = -211, // acion not exist + + QCLOUD_ERR_GATEWAY_CREATE_SESSION_FAIL = -221, // Gateway fail to create sub-device session + QCLOUD_ERR_GATEWAY_SESSION_NO_EXIST = -222, // Gateway sub-device session not exist + QCLOUD_ERR_GATEWAY_SESSION_TIMEOUT = -223, // Gateway sub-device session timeout + QCLOUD_ERR_GATEWAY_SUBDEV_ONLINE = -224, // Gateway sub-device online + QCLOUD_ERR_GATEWAY_SUBDEV_OFFLINE = -225, // Gateway sub-device offline + + QCLOUD_ERR_TCP_SOCKET_FAILED = -601, // TLS TCP socket connect fail + QCLOUD_ERR_TCP_UNKNOWN_HOST = -602, // TCP unknown host (DNS fail) + QCLOUD_ERR_TCP_CONNECT = -603, // TCP/UDP socket connect fail + QCLOUD_ERR_TCP_READ_TIMEOUT = -604, // TCP read timeout + QCLOUD_ERR_TCP_WRITE_TIMEOUT = -605, // TCP write timeout + QCLOUD_ERR_TCP_READ_FAIL = -606, // TCP read error + QCLOUD_ERR_TCP_WRITE_FAIL = -607, // TCP write error + QCLOUD_ERR_TCP_PEER_SHUTDOWN = -608, // TCP server close connection + QCLOUD_ERR_TCP_NOTHING_TO_READ = -609, // TCP socket nothing to read + + QCLOUD_ERR_SSL_INIT = -701, // TLS/SSL init fail + QCLOUD_ERR_SSL_CERT = -702, // TLS/SSL certificate issue + QCLOUD_ERR_SSL_CONNECT = -703, // TLS/SSL connect fail + QCLOUD_ERR_SSL_CONNECT_TIMEOUT = -704, // TLS/SSL connect timeout + QCLOUD_ERR_SSL_WRITE_TIMEOUT = -705, // TLS/SSL write timeout + QCLOUD_ERR_SSL_WRITE = -706, // TLS/SSL write error + QCLOUD_ERR_SSL_READ_TIMEOUT = -707, // TLS/SSL read timeout + QCLOUD_ERR_SSL_READ = -708, // TLS/SSL read error + QCLOUD_ERR_SSL_NOTHING_TO_READ = -709, // TLS/SSL nothing to read + + QCLOUD_ERR_BIND_PARA_ERR = -801, // bind sub device param error + QCLOUD_ERR_BIND_SUBDEV_ERR = -802, // sub device not exist or illegal + QCLOUD_ERR_BIND_SIGN_ERR = -803, // signature check err + QCLOUD_ERR_BIND_SIGN_METHOD_RRR = -804, // signmethod not supporte + QCLOUD_ERR_BIND_SIGN_EXPIRED = -805, // signature expired + QCLOUD_ERR_BIND_BEEN_BINDED = -806, // sub device has been binded by other gateway + QCLOUD_ERR_BIND_SUBDEV_FORBID = -807, // sub device not allow to bind + QCLOUD_ERR_BIND_OP_FORBID = -808, // operation not permit + QCLOUD_ERR_BIND_REPEATED_REQ = -809, // repeated bind request,has been binded +} IoT_Return_Code; + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_ERROR_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_gateway.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_gateway.h new file mode 100644 index 00000000..676df2b7 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_gateway.h @@ -0,0 +1,223 @@ + +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_GATEWAY_H_ +#define QCLOUD_IOT_EXPORT_GATEWAY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_export_mqtt.h" + +/* Gateway and sub-device parameter */ +typedef struct { + /*gateway device info */ + char *product_id; + char *device_name; + /*sub-device device info */ + char *subdev_product_id; + char *subdev_device_name; + +} GatewayParam; + +#define DEFAULT_GATEWAY_PARAMS \ + { \ + NULL, NULL, NULL, NULL \ + } + +/** + * @brief Define a callback to be invoked when gatway event happen + * + * @param context, the program context + * @param client, the gateway client + * @param msg, the event message. + * + * @return none + */ +typedef void (*GatewayEventHandleFun)(void *client, void *context, void *msg); + +/* The structure of gateway init param */ +typedef struct { + MQTTInitParams init_param; /* MQTT params */ + void * event_context; /* the user context */ + GatewayEventHandleFun event_handler; /* event handler for gateway user*/ +} GatewayInitParam; + +#define DEFAULT_GATEWAY_INIT_PARAMS \ + { \ + DEFAULT_MQTTINIT_PARAMS, NULL, NULL \ + } + +/** + * @brief Create gateway client and connect to MQTT server + * + * @param init_param Gateway MQTT init parameters + * + * @return a valid gateway client handle when success, or NULL otherwise + */ +void *IOT_Gateway_Construct(GatewayInitParam *init_param); + +/** + * @brief Close connection and destroy gateway client + * + * @param client handle to gateway client + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int IOT_Gateway_Destroy(void *client); + +/** + * @brief Make sub-device online + * + * @param client handle to gateway client + * @param param sub-device parameters + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int IOT_Gateway_Subdev_Online(void *client, GatewayParam *param); + +/** + * @brief Make sub-device offline + * + * @param client handle to gateway client + * @param param sub-device parameters + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int IOT_Gateway_Subdev_Offline(void *client, GatewayParam *param); + +/** + * @brief Make sub-device bind + * + * @param client handle to gateway client + * @param param gateway parameters + * @param pBindSubDevInfo sub dev info wait bind + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int IOT_Gateway_Subdev_Bind(void *client, GatewayParam *param, DeviceInfo *pBindSubDevInfo); + +/** + * @brief Make sub-device unbind + * + * @param client handle to gateway client + * @param param gateway parameters + * @param pBindSubDevInfo sub dev info wait unbind + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int IOT_Gateway_Subdev_Unbind(void *client, GatewayParam *param, DeviceInfo *pSubDevInfo); + +/** + * @brief Publish gateway MQTT message + * + * @param client handle to gateway client + * @param topic_name MQTT topic name + * @param params publish parameters + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Gateway_Publish(void *client, char *topic_name, PublishParams *params); + +/** + * @brief Subscribe gateway MQTT topic + * + * @param client handle to gateway client + * @param topic_filter MQTT topic filter + * @param params subscribe parameters + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Gateway_Subscribe(void *client, char *topic_filter, SubscribeParams *params); + +/** + * @brief unsubscribe gateway MQTT topic + * + * @param client handle to gateway client + * @param topic_filter MQTT topic filter + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Gateway_Unsubscribe(void *client, char *topic_filter); + +/** + * @brief check if MQTT topic has been subscribed or not + * + * @param pClient handle to MQTT client + * @param topicFilter MQTT topic filter + * + * @return true when successfully subscribed, or false if not yet + */ +int IOT_Gateway_IsSubReady(void *client, char *topic_filter); + +/** + * @brief Check connection and keep alive state, read/handle MQTT message in + * synchronized way + * + * @param client handle to gateway client + * @param timeout_ms timeout value (unit: ms) for this operation + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Gateway_Yield(void *client, uint32_t timeout_ms); + +/** + * @brief Get mqtt_client of GateWay + * + * @param client handle to gateway client + * + * @return mqtt_client of GateWay + */ +void *IOT_Gateway_Get_Mqtt_Client(void *client); + +#ifdef MULTITHREAD_ENABLED +/** + * @brief Start the default yield thread to read and handle gateway msg + * + * @param pClient handle to gateway client + * @return QCLOUD_RET_SUCCESS when success, err code for failure + */ +int IOT_Gateway_Start_Yield_Thread(void *pClient); + +/** + * @brief Stop the default yield thread to read and handle data_template control + * and reply msg + * + * @param pClient handle to gateway client + */ +void IOT_Gateway_Stop_Yield_Thread(void *pClient); + +/** + * @brief Get the status of yield thread + * + * @param pClient handle to gateway client + * @param exit_code exit code of the thread + * @return true= thread running, false = thread quit + */ +bool IOT_Gateway_Get_Yield_Status(void *pClient, int *exit_code); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_GATEWAY_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_log.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_log.h new file mode 100644 index 00000000..9b85cffb --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_log.h @@ -0,0 +1,209 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_LOG_H_ +#define QCLOUD_IOT_EXPORT_LOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#include "qcloud_iot_export_variables.h" + +/** + * SDK log print/upload level + */ +typedef enum { eLOG_DISABLE = 0, eLOG_ERROR = 1, eLOG_WARN = 2, eLOG_INFO = 3, eLOG_DEBUG = 4 } LOG_LEVEL; + +/** + * log print level control, only print logs with level less or equal to this + * variable + */ +extern LOG_LEVEL g_log_print_level; + +/** + * log upload level control, only upload logs with level less or equal to this + * variable + */ +extern LOG_LEVEL g_log_upload_level; + +/* user's self defined log handler callback */ +typedef bool (*LogMessageHandler)(const char *message); + +/** + * @brief user callback for saving/reading logs into/from NVS(files/FLASH) after + * upload fail/recover + */ +// callback for saving logs into NVS(files/FLASH) after upload fail +typedef size_t (*LogSaveFunc)(const char *msg, size_t wLen); +// callback for reading logs from NVS(files/FLASH) when upload ready +typedef size_t (*LogReadFunc)(char *buff, size_t rLen); +// callback for deleting logs in NVS(files/FLASH). return 0 when success +typedef int (*LogDelFunc)(); +// callback for reading the size of logs in NVS(files/FLASH). return 0 when +// nothing exist +typedef size_t (*LogGetSizeFunc)(); + +/** + * @brief data structure to init feature of log upload + */ +typedef struct { + const char *region; // region + /* device info */ + const char *product_id; + const char *device_name; + /* auth key, use device secret for PSK device and cert file path for cert + * device */ + const char *sign_key; + /* user callback saving/reading logs into/from NVS(files/FLASH) */ + LogSaveFunc save_func; + LogReadFunc read_func; + LogDelFunc del_func; + LogGetSizeFunc get_size_func; +} LogUploadInitParams; + +/** + * @brief Set the global log level of print + * + * @param level + */ +void IOT_Log_Set_Level(LOG_LEVEL level); + +/** + * @brief Get the global log level of print + * + * @return + */ +LOG_LEVEL IOT_Log_Get_Level(); + +/** + * @brief Set the global log level of upload + * + * @param level + */ +void IOT_Log_Set_Upload_Level(LOG_LEVEL level); + +/** + * @brief Get the global log level of upload + * + * @return + */ +LOG_LEVEL IOT_Log_Get_Upload_Level(); + +/** + * @brief Set user callback to print log into whereever you want + * + * @param handler function pointer of callback + * + */ +void IOT_Log_Set_MessageHandler(LogMessageHandler handler); + +/** + * @brief Init the resource for log upload + * + * @param init_params init parameter + * @return QCLOUD_RET_SUCCESS when success, or error code when fail + * + */ +int IOT_Log_Init_Uploader(LogUploadInitParams *init_params); + +/** + * @brief Stop log upload and release the resource + * + * @return + */ +void IOT_Log_Fini_Uploader(void); + +/** + * @brief Do one log upload + * + * @param force_upload true = upload log at once, false = upload in defined time + * interval + * @return QCLOUD_RET_SUCCESS when success, or error code when fail + */ +int IOT_Log_Upload(bool force_upload); + +/** + * @brief Generate log for print/upload, call LogMessageHandler if defined + * + * When LOG_UPLOAD is enabled, the log will be uploaded to cloud server + * + * @param file + * @param func + * @param line + * @param level + */ +void IOT_Log_Gen(const char *file, const char *func, const int line, const int level, const char *fmt, ...); + +/* Simple APIs for log generation in different level */ +#define Log_d(fmt, ...) IOT_Log_Gen(__FILE__, __FUNCTION__, __LINE__, eLOG_DEBUG, fmt, ##__VA_ARGS__) +#define Log_i(fmt, ...) IOT_Log_Gen(__FILE__, __FUNCTION__, __LINE__, eLOG_INFO, fmt, ##__VA_ARGS__) +#define Log_w(fmt, ...) IOT_Log_Gen(__FILE__, __FUNCTION__, __LINE__, eLOG_WARN, fmt, ##__VA_ARGS__) +#define Log_e(fmt, ...) IOT_Log_Gen(__FILE__, __FUNCTION__, __LINE__, eLOG_ERROR, fmt, ##__VA_ARGS__) + +/* Macro for debug mode */ +#ifdef IOT_DEBUG +#define IOT_FUNC_ENTRY \ + { \ + printf("FUNC_ENTRY: %s L#%d \n", __FUNCTION__, __LINE__); \ + } +#define IOT_FUNC_EXIT \ + { \ + printf("FUNC_EXIT: %s L#%d \n", __FUNCTION__, __LINE__); \ + return; \ + } +#define IOT_FUNC_EXIT_RC(x) \ + { \ + printf("FUNC_EXIT: %s L#%d Return Code : %ld \n", __FUNCTION__, __LINE__, (long)(x)); \ + return x; \ + } +#else +#define IOT_FUNC_ENTRY +#define IOT_FUNC_EXIT \ + { \ + return; \ + } +#define IOT_FUNC_EXIT_RC(x) \ + { \ + return x; \ + } +#endif + +/* Macro for interval debug */ +//#define LOG_UPLOAD_DEBUG +#ifdef LOG_UPLOAD_DEBUG +#define UPLOAD_DBG(fmt, ...) HAL_Printf(">>LOG-DBG>>%s(%d): " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) +#else +#define UPLOAD_DBG(...) +#endif +#define UPLOAD_ERR(fmt, ...) HAL_Printf(">>LOG-ERR>>%s(%d): " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) + +#define STRING_PTR_PRINT_SANITY_CHECK(ptr) ((ptr) ? (ptr) : "null") + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_LOG_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_method.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_method.h new file mode 100644 index 00000000..2bc1c109 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_method.h @@ -0,0 +1,112 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_METHOD_H_ +#define QCLOUD_IOT_EXPORT_METHOD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Type of request ACK + */ +typedef enum { + ACK_NONE = -3, // request timeout + ACK_TIMEOUT = -2, // request timeout + ACK_REJECTED = -1, // request rejected + ACK_ACCEPTED = 0 // request accepted +} ReplyAck; + +/** + * @brief Type of interaction with server + */ +typedef enum { + GET = 0, // Get data_template state from server + REPORT = 1, // Report property to server + RINFO = 2, // Report system information to server + REPLY = 3, // Reply to control msg + CLEAR = 4, // Clear control msg +} Method; + +/** + * @brief JSON data type + */ +typedef enum { JINT32, JINT16, JINT8, JUINT32, JUINT16, JUINT8, JFLOAT, JDOUBLE, JBOOL, JSTRING, JOBJECT } JsonDataType; + +/** + * @brief Define a device property, as a JSON document node + */ +typedef struct _JSONNode { + char *key; // Key of this JSON node + void *data; // Value of this JSON node + union { + uint16_t data_buff_len; // data buff len, for string type value update + uint16_t struct_obj_num; // member number of struct + }; + JsonDataType type; // Data type of this JSON node +} DeviceProperty; + +/** + * @brief Define a device action + */ +typedef struct { + char * pActionId; // action id + uint32_t timestamp; // action timestamp + uint8_t input_num; // input num + uint8_t output_num; // output mun + DeviceProperty *pInput; // input + DeviceProperty *pOutput; // output +} DeviceAction; + +/** + * @brief Define MQTT data_template callback when request response arrived + * + * @param method type of request + * @param requestAck response type + * @param pJsonDocument JSON document from server + * @param userContext User context + * + */ +typedef void (*OnReplyCallback)(void *pClient, Method method, ReplyAck replyAck, const char *pJsonDocument, + void *userContext); + +/** + * @brief Define callback when device property change + * + * @param pJsonValueBuffer property JSON buffer + * @param valueLength property length + * @param DeviceProperty reference to device property + */ +typedef void (*OnPropRegCallback)(void *pClient, const char *pJsonValueBuffer, uint32_t valueLength, + DeviceProperty *pProperty); + +/** + * @brief action handle callback + * + * @param pAction action with input data + */ +typedef void (*OnActionHandleCallback)(void *pClient, const char *pClientToken, DeviceAction *pAction); + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_SHADOW_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_mqtt.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_mqtt.h new file mode 100644 index 00000000..a1c84be8 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_mqtt.h @@ -0,0 +1,332 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_MQTT_H_ +#define QCLOUD_IOT_EXPORT_MQTT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * @brief MQTT Quality of Service level + * + * Check MQTT spec for QoS define + */ +typedef enum _QoS { + QOS0 = 0, // At most once delivery + QOS1 = 1, // At least once delivery, PUBACK is required + QOS2 = 2 // Exactly once delivery. NOT supported currently +} QoS; + +/** + * @brief MQTT message parameter for pub/sub + */ +typedef struct { + QoS qos; // MQTT QoS level + uint8_t retained; // RETAIN flag + uint8_t dup; // DUP flag + uint16_t id; // MQTT Id + + const char *ptopic; // MQTT topic + size_t topic_len; // topic length + + void * payload; // MQTT msg payload + size_t payload_len; // MQTT length of msg payload +} MQTTMessage; + +typedef MQTTMessage PublishParams; + +#define DEFAULT_PUB_PARAMS \ + { \ + QOS0, 0, 0, 0, NULL, 0, NULL, 0 \ + } + +typedef enum { + + /* MQTT undefined event */ + MQTT_EVENT_UNDEF = 0, + + /* MQTT disconnect */ + MQTT_EVENT_DISCONNECT = 1, + + /* MQTT reconnect */ + MQTT_EVENT_RECONNECT = 2, + + /* MQTT subscribe success */ + MQTT_EVENT_SUBCRIBE_SUCCESS = 3, + + /* MQTT subscribe timeout */ + MQTT_EVENT_SUBCRIBE_TIMEOUT = 4, + + /* MQTT subscribe fail */ + MQTT_EVENT_SUBCRIBE_NACK = 5, + + /* MQTT unsubscribe success */ + MQTT_EVENT_UNSUBCRIBE_SUCCESS = 6, + + /* MQTT unsubscribe timeout */ + MQTT_EVENT_UNSUBCRIBE_TIMEOUT = 7, + + /* MQTT unsubscribe fail */ + MQTT_EVENT_UNSUBCRIBE_NACK = 8, + + /* MQTT publish success */ + MQTT_EVENT_PUBLISH_SUCCESS = 9, + + /* MQTT publish timeout */ + MQTT_EVENT_PUBLISH_TIMEOUT = 10, + + /* MQTT publish fail */ + MQTT_EVENT_PUBLISH_NACK = 11, + + /* MQTT received msg from server */ + MQTT_EVENT_PUBLISH_RECVEIVED = 12, + + /* MQTT client destroy */ + MQTT_EVENT_CLIENT_DESTROY = 13, + + /* MQTT unsubscribe */ + MQTT_EVENT_UNSUBSCRIBE = 14, + +} MQTTEventType; + +/** + * @brief Define MQTT SUBSCRIBE callback when message arrived + */ +typedef void (*OnMessageHandler)(void *pClient, MQTTMessage *message, void *pUserData); + +/** + * @brief Define MQTT SUBSCRIBE callback when event happened + */ +typedef void (*OnSubEventHandler)(void *pClient, MQTTEventType event_type, void *pUserData); + +/** + * @brief Define structure to do MQTT subscription + */ +typedef struct { + QoS qos; // MQTT QoS level + OnMessageHandler on_message_handler; // callback when message arrived + OnSubEventHandler on_sub_event_handler; // callback when event happened + void * user_data; // user context for callback +} SubscribeParams; + +/** + * Default MQTT subscription parameters + */ +#define DEFAULT_SUB_PARAMS \ + { \ + QOS0, NULL, NULL, NULL \ + } + +typedef struct { + /* MQTT event type */ + MQTTEventType event_type; + + void *msg; +} MQTTEventMsg; + +/** + * @brief Define MQTT callback when MQTT event happen + * + * @param pclient, the MQTT client + * @param context, user callback context + * @param msg, the event message. + * + * @return none + */ +typedef void (*MQTTEventHandleFun)(void *pclient, void *context, MQTTEventMsg *msg); + +/* The structure of MQTT event handle */ +typedef struct { + MQTTEventHandleFun h_fp; + void * context; +} MQTTEventHandler; + +/* The structure of MQTT init parameters */ +typedef struct { + char *region; // region + + /* device info */ + char *product_id; // product ID + char *device_name; // device name + +#ifdef AUTH_MODE_CERT + char *cert_file; // cert file path + char *key_file; // key file path +#else + char *device_secret; // device secret +#endif + + uint32_t command_timeout; // timeout value (unit: ms) for MQTT + // connect/pub/sub/yield + uint32_t keep_alive_interval_ms; // MQTT keep alive time interval in millisecond + + uint8_t clean_session; // flag of clean session, 1 clean, 0 not clean + + uint8_t auto_connect_enable; // flag of auto reconnection, 1 is enable and + // recommended + + MQTTEventHandler event_handle; // event callback + +} MQTTInitParams; + +/** + * Default MQTT init parameters + */ +#ifdef AUTH_MODE_CERT +#define DEFAULT_MQTTINIT_PARAMS \ + { \ + "china", NULL, NULL, NULL, NULL, 5000, 240 * 1000, 1, 1, { 0 } \ + } +#else +#define DEFAULT_MQTTINIT_PARAMS \ + { \ + "china", NULL, NULL, NULL, 5000, 240 * 1000, 1, 1, { 0 } \ + } +#endif + +/** + * @brief Create MQTT client and connect to MQTT server + * + * @param pParams MQTT init parameters + * + * @return a valid MQTT client handle when success, or NULL otherwise + */ +void *IOT_MQTT_Construct(MQTTInitParams *pParams); + +/** + * @brief Close connection and destroy MQTT client + * + * @param pClient pointer of handle to MQTT client + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int IOT_MQTT_Destroy(void **pClient); + +/** + * @brief Check connection and keep alive state, read/handle MQTT message in synchronized way + * + * @param pClient handle to MQTT client + * @param timeout_ms timeout value (unit: ms) for this operation + * + * @return QCLOUD_RET_SUCCESS when success, QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT + * when try reconnecing, or err code for failure + */ +int IOT_MQTT_Yield(void *pClient, uint32_t timeout_ms); + +/** + * @brief set mqtt yield is by thread or not + * + * @param pClient handle to MQTT client + * @param state yield thread running state + */ +#ifdef MULTITHREAD_ENABLED +/** + * @brief Start the default loop thread to read and handle MQTT packet + * + * @param pClient handle to MQTT client + * @return QCLOUD_RET_SUCCESS when success, err code for failure + */ +int IOT_MQTT_StartLoop(void *pClient); + +/** + * @brief Stop the default loop thread to read and handle MQTT packet + * + * @param pClient handle to MQTT client + */ +void IOT_MQTT_StopLoop(void *pClient); + +/** + * @brief Get the status of loop thread + * + * @param pClient handle to MQTT client + * @param exit_code exit code of the thread + * @return true= thread running, false = thread quit + */ +bool IOT_MQTT_GetLoopStatus(void *pClient, int *exit_code); +#endif + +/** + * @brief Publish MQTT message + * + * @param pClient handle to MQTT client + * @param topicName MQTT topic name + * @param pParams publish parameters + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_MQTT_Publish(void *pClient, char *topicName, PublishParams *pParams); + +/** + * @brief Subscribe MQTT topic + * + * @param pClient handle to MQTT client + * @param topicFilter MQTT topic filter + * @param pParams subscribe parameters + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_MQTT_Subscribe(void *pClient, char *topicFilter, SubscribeParams *pParams); + +/** + * @brief Unsubscribe MQTT topic + * + * @param pClient handle to MQTT client + * @param topicFilter MQTT topic filter + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_MQTT_Unsubscribe(void *pClient, char *topicFilter); + +/** + * @brief check if MQTT topic has been subscribed or not + * + * @param pClient handle to MQTT client + * @param topicFilter MQTT topic filter + * + * @return true when successfully subscribed, or false if not yet + */ +bool IOT_MQTT_IsSubReady(void *pClient, char *topicFilter); + +/** + * @brief Check if MQTT is connected + * + * @param pClient handle to MQTT client + * @return true= connected, false = unconnected + */ +bool IOT_MQTT_IsConnected(void *pClient); + +/** + * @brief Get error code of last IOT_MQTT_Construct operation + * + * @return error code of last IOT_MQTT_Construct operation + */ +int IOT_MQTT_GetErrCode(void); + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_MQTT_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_ota.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_ota.h new file mode 100644 index 00000000..212b3ed2 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_ota.h @@ -0,0 +1,265 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_OTA_H_ +#define QCLOUD_IOT_EXPORT_OTA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_import.h" + +typedef enum { + + IOT_OTA_ERR_FAIL = -1, + IOT_OTA_ERR_INVALID_PARAM = -2, + IOT_OTA_ERR_INVALID_STATE = -3, + IOT_OTA_ERR_STR_TOO_LONG = -4, + IOT_OTA_ERR_FETCH_FAILED = -5, + IOT_OTA_ERR_FETCH_NOT_EXIST = -6, + IOT_OTA_ERR_FETCH_AUTH_FAIL = -7, + IOT_OTA_ERR_FETCH_TIMEOUT = -8, + IOT_OTA_ERR_NOMEM = -9, + IOT_OTA_ERR_OSC_FAILED = -10, + IOT_OTA_ERR_REPORT_VERSION = -11, + IOT_OTA_ERR_NONE = 0 + +} IOT_OTA_Error_Code; + +/* type of OTA state */ +typedef enum { + IOT_OTAS_UNINITED = 0, /* un-inited */ + IOT_OTAS_INITED, /* inited */ + IOT_OTAS_FETCHING, /* fetching */ + IOT_OTAS_FETCHED, /* fetched */ + IOT_OTAS_DISCONNECTED /* disconnected */ +} IOT_OTA_State_Code; + +/* type of OTA progress */ +typedef enum { + + /* firmware upgrade failed */ + IOT_OTAP_BURN_FAILED = -4, + + /* firmware checksum failed */ + IOT_OTAP_CHECK_FALIED = -3, + + /* firmware download failed */ + IOT_OTAP_FETCH_FAILED = -2, + + /* init failed */ + IOT_OTAP_GENERAL_FAILED = -1, + + /* [0, 100], progress percentage */ + + /* minimal of progress percentage */ + IOT_OTAP_FETCH_PERCENTAGE_MIN = 0, + + /* maximal of progress percentage */ + IOT_OTAP_FETCH_PERCENTAGE_MAX = 100 + +} IOT_OTA_Progress_Code; + +typedef enum { + + IOT_OTAG_FETCHED_SIZE, /* Size of firmware fetched */ + IOT_OTAG_FILE_SIZE, /* Total size of firmware */ + IOT_OTAG_MD5SUM, /* firmware md5 checksum (string) */ + IOT_OTAG_VERSION, /* firmware version (string) */ + IOT_OTAG_CHECK_FIRMWARE /* check firmware */ + +} IOT_OTA_CmdType; + +typedef enum { + + IOT_OTAR_DOWNLOAD_TIMEOUT = -1, + IOT_OTAR_FILE_NOT_EXIST = -2, + IOT_OTAR_AUTH_FAIL = -3, + IOT_OTAR_MD5_NOT_MATCH = -4, + IOT_OTAR_UPGRADE_FAIL = -5, + IOT_OTAR_NONE = 0, + IOT_OTAR_DOWNLOAD_BEGIN = 1, + IOT_OTAR_DOWNLOADING = 2, + IOT_OTAR_UPGRADE_BEGIN = 3, + IOT_OTAR_UPGRADE_SUCCESS = 4, + +} IOT_OTAReportType; + +/** + * @brief Init OTA module and resources + * MQTT/COAP Client should be constructed beforehand + * + * @param product_id: product Id + * @param device_name: device name + * @param ch_signal: channel: MQTT or COAP + * + * @return a valid OTA module handle when success, or NULL otherwise + */ +void *IOT_OTA_Init(const char *product_id, const char *device_name, void *ch_signal); + +/** + * @brief Destroy OTA module and resources + * + * @param handle: OTA module handle + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_OTA_Destroy(void *handle); + +/** + * @brief Setup HTTP connection and prepare OTA download + * + * @param handle: OTA module handle + * @param offset: offset of firmware downloaded + * @param size: size of firmware + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_OTA_StartDownload(void *handle, uint32_t offset, uint32_t size); + +/** + * @brief Update MD5 of local firmware + * + * @param handle: OTA module handle + * @param buff: buffer to firmware + * @param size: size of buffer + * + */ +void IOT_OTA_UpdateClientMd5(void *handle, char *buff, uint32_t size); + +/** + * @brief Reset MD5 of local firmware + * + * @param handle: OTA module handle + * + */ +int IOT_OTA_ResetClientMD5(void *handle); + +/** + * @brief Report local firmware version to server + * NOTE: do this report before real download + * + * @param handle: OTA module handle + * @param version: local firmware version string + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_OTA_ReportVersion(void *handle, const char *version); + +/** + * @brief Report upgrade begin to server + * + * @param handle: OTA module handle + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_OTA_ReportUpgradeBegin(void *handle); + +/** + * @brief Report upgrade success to server + * + * @param handle: OTA module handle + * @param version: version string of firmware to upgrade + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_OTA_ReportUpgradeSuccess(void *handle, const char *version); + +/** + * @brief Report upgrade fail to server + * + * @param handle: OTA module handle + * @param version: version string of firmware to upgrade + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_OTA_ReportUpgradeFail(void *handle, const char *version); + +/** + * @brief Check if firmware is fetching/downloading + * + * @param handle: OTA module handle + * + * @retval 1 : Yes. + * @retval 0 : No. + */ +int IOT_OTA_IsFetching(void *handle); + +/** + * @brief Check if firmware fetching/downloading is finished + * + * @param handle: OTA module handle + * + * @retval 1 : Yes. + * @retval 0 : No. + */ +int IOT_OTA_IsFetchFinish(void *handle); + +/** + * @brief Download firmware from HTTP server and save to buffer + * + * @param handle: OTA module handle + * @param buf: buffer to store firmware + * @param buf_len: length of buffer + * @param timeout_s: timeout value in second + * + * @retval < 0 : error code + * @retval 0 : no data is downloaded in this period and timeout happen + * @retval (0, len] : size of the downloaded data + */ +int IOT_OTA_FetchYield(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s); + +/** + * @brief Get OTA info (version, file_size, MD5, download state) from OTA module + * + * @param handle: OTA module handle + * @param type: type of info to get, refer to IOT_OTA_CmdType + * @param buf: buffer for the data + * @param buf_len: length of buffer + * @return + NOTE: + 1) if type==IOT_OTAG_FETCHED_SIZE, 'buf' = uint32_t pointer, 'buf_len' = 4 + 2) if type==IOT_OTAG_FILE_SIZE, 'buf' = uint32_t pointer, 'buf_len' = 4 + 3) if type==IOT_OTAG_MD5SUM, 'buf' = char array buffer, 'buf_len = 33 + 4) if type==IOT_OTAG_VERSION, 'buf'= char array buffer, 'buf_len = + OTA_VERSION_LEN_MAX + 5) if type==IOT_OTAG_CHECK_FIRMWARE, 'buf' = uint32_t pointer, 'buf_len' = + 4 + * + * @retval 0 : success + * @retval < 0 : error code for failure + */ +int IOT_OTA_Ioctl(void *handle, IOT_OTA_CmdType type, void *buf, size_t buf_len); + +/** + * @brief Get error code of last operation + * + * @param handle: OTA module handle + * + * @return error code + */ +int IOT_OTA_GetLastError(void *handle); + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_OTA_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_resource.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_resource.h new file mode 100644 index 00000000..40d98911 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_resource.h @@ -0,0 +1,343 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_RESOURCE_H_ +#define QCLOUD_IOT_EXPORT_RESOURCE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_import.h" + +//{"resource_name":"","version":"","resource_type":""}, +#define RESOURCE_VERSION_STR_LEN_MIN (1) +#define RESOURCE_VERSION_STR_LEN_MAX (32) +#define RESOURCE_NAME_STR_LEN_MAX (64) +#define RESOURCE_TYPE_STR_LEN_MAX (10) +#define RESOURCE_INFO_FIXED_LEN (53) +#define RESOURCE_INFO_LEN_MAX \ + (RESOURCE_VERSION_STR_LEN_MAX + RESOURCE_NAME_STR_LEN_MAX + RESOURCE_INFO_FIXED_LEN + RESOURCE_TYPE_STR_LEN_MAX) + +#define RESOURCE_TYPE_FILE "FILE" +#define RESOURCE_TYPE_AUDIO "AUDIO" +#define RESOURCE_TYPE_VOICE "VOICE" +#define RESOURCE_TYPE_VIDEO "VIDEO" + +/* error code of resource update */ +typedef enum { + IOT_RES_ERR_FAIL = -1, + IOT_RES_ERR_INVALID_PARAM = -2, + IOT_RES_ERR_INVALID_STATE = -3, + IOT_RES_ERR_STR_TOO_LONG = -4, + IOT_RES_ERR_FETCH_FAILED = -5, + IOT_RES_ERR_FETCH_NOT_EXIST = -6, + IOT_RES_ERR_FETCH_AUTH_FAIL = -7, + IOT_RES_ERR_FETCH_TIMEOUT = -8, + IOT_RES_ERR_MALLOC = -9, + IOT_RES_ERR_REPORT_VERSION = -10, + IOT_RES_ERR_REPORT_PROGRESS = -11, + IOT_RES_ERR_REPORT_UPGRADE_RESULT = -12, + IOT_RES_ERR_NONE = 0 +} IOT_RES_ErrorCode; + +/* type of resource update state */ +typedef enum { + IOT_RES_STATE_UNINITTED = 0, /* un-initted */ + IOT_RES_STATE_INITTED, /* initted */ + IOT_RES_STATE_FETCHING, /* fetching */ + IOT_RES_STATE_FETCHED, /* fetched */ + IOT_RES_STATE_DELETING, /* deleting */ + IOT_RES_STATE_DELETED, /* deleted */ + IOT_RES_STATE_DISCONNECTED /* disconnected */ +} IOT_RES_StateCode; + +/* cmd type of resource update */ +typedef enum { + IOT_RES_CMD_FETCHED_SIZE = 0, /* Size of firmware fetched */ + IOT_RES_CMD_FILE_SIZE, /* Total size of firmware */ + IOT_RES_CMD_MD5SUM, /* firmware md5 checksum (string) */ + IOT_RES_CMD_VERSION, /* firmware version (string) */ + IOT_RES_CMD_FILE_NAME, /* file name (string) */ + IOT_RES_CMD_FILE_TYPE, /* file type */ + IOT_RES_CMD_CHECK_FIRMWARE /* check firmware */ +} IOT_RES_CmdType; + +/* report type of resource update */ +typedef enum { + IOT_RES_TYPE_DOWNLOAD_TIMEOUT = -1, + IOT_RES_TYPE_FILE_NOT_EXIST = -2, + IOT_RES_TYPE_AUTH_FAIL = -3, + IOT_RES_TYPE_MD5_NOT_MATCH = -4, + IOT_RES_TYPE_UPGRADE_FAIL = -5, + IOT_RES_TYPE_SPACE_NOT_ENOUGH = -6, + IOT_RES_TYPE_FILE_DEL_FAIL = -7, + IOT_RES_TYPE_POST_FAIL = -8, + IOT_RES_TYPE_NONE = 0, + IOT_RES_TYPE_DOWNLOAD_BEGIN = 1, + IOT_RES_TYPE_DOWNLOADING = 2, + IOT_RES_TYPE_UPGRADE_BEGIN = 3, + IOT_RES_TYPE_UPGRADE_SUCCESS = 4, + IOT_RES_TYPE_FILE_DEL_SUCCESS = 5, + IOT_RES_TYPE_REQUEST_URL = 6, + IOT_RES_TYPE_POST_SUCCESS = 7, + +} IOT_RES_ReportType; + +/* usr event of resource update */ +typedef enum { + IOT_RES_EVENT_DEL_RESOURCE = 0, + IOT_RES_EVENT_REPORT_VERSION_RESP = 1, + IOT_RES_EVENT_REQUEST_URL_RESP = 2, +} IOT_RES_UsrEvent; + +/* resource info filed */ +typedef struct { + char *res_name; + char *res_ver; + char *res_type; +} resInfo; + +typedef int (*OnResourceEventUsrCallback)(void *pContext, const char *msg, uint32_t msgLen, IOT_RES_UsrEvent event); + +//=========== init & destory =================// + +/** + * @brief Init resource module + * MQTT Client should be constructed beforehand + * + * @param product_id: product Id + * @param device_name: device name + * @param mqtt_client: resouce MQTT channel + * @param usr_cb: user call back + * @param usr_context: user context + * + * @return a valid resource module handle when success, or NULL otherwise + */ +void *IOT_Resource_Init(const char *product_id, const char *device_name, void *mqtt_client, + OnResourceEventUsrCallback usr_cb, void *usr_context); + +/** + * @brief Destroy resource module + * + * @param handle: resource module handle + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Resource_Destroy(void *handle); + +//=========== md5 function =================// + +/** + * @brief Update MD5 of local resource + * + * @param handle: resource module handle + * @param buff: buff to resource + * @param size: size of buff + * + * @return + */ +void IOT_Resource_UpdateClientMd5(void *handle, char *buff, uint32_t size); + +/** + * @brief Reset MD5 context + * + * @param handle: resource module handle + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Resource_ResetClientMD5(void *handle); + +//=========== download =================// + +/** + * @brief Setup HTTP connection and prepare resource download + * + * @param handle: resource module handle + * @param offset: offset of resource downloaded + * @param size: size of resource + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Resource_StartDownload(void *handle, uint32_t offset, uint32_t size); + +/** + * @brief Check if resource is fetching/downloading + * + * @param handle: resource module handle + * + * @retval 1 : Yes. + * @retval 0 : No. + */ +int IOT_Resource_IsFetching(void *handle); + +/** + * @brief Check if resource fetching/downloading is finished + * + * @param handle: resource module handle + * + * @retval 1 : Yes. + * @retval 0 : No. + */ +int IOT_Resource_IsFetchFinish(void *handle); + +/** + * @brief Download resource from HTTP server and save to buffer + * + * @param handle: resource module handle + * @param buf: buffer to store resource + * @param buf_len: length of buffer + * @param timeout_s: timeout value in second + * + * @retval < 0 : error code + * @retval 0 : no data is downloaded in this period and timeout happen + * @retval (0, len] : size of the downloaded data + */ +int IOT_Resource_FetchYield(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s); + +//=========== report =================// + +/** + * @brief Report local resource version list to server + * NOTE: do this report before real download + * + * @param handle: resource module handle + * @param ver_list: local resource version list + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Resource_ReportVersion(void *handle, uint16_t res_num, resInfo *res_list[]); + +/** + * @brief Report upgrade begin to server + * + * @param handle: resource module handle + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Resource_ReportUpgradeBegin(void *handle); + +/** + * @brief Report upgrade success to server + * + * @param handle: resource module handle + * @param version: version string of firmware to upgrade + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Resource_ReportUpgradeSuccess(void *handle, const char *version); + +/** + * @brief Report upgrade fail to server + * + * @param handle: resource module handle + * @param version: version string of firmware to upgrade + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Resource_ReportUpgradeFail(void *handle, const char *version); + +/** + * @brief Report space not enough to server + * + * @param handle: resource module handle + * @param version: version string of firmware to upgrade + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int IOT_Resource_ReportSpaceNotEnough(void *handle, const char *version); + +//=========== get status =================// + +/** + * @brief Get resource info (file name, version, file_size, MD5, download state) from resource module + * + * @param handle: resource module handle + * @param type: type of info to get, refer to IOT_RES_CmdType + * @param buf: buffer for the data + * @param buf_len: length of buffer + * @return + NOTE: + 1) if type==IOT_RES_CMD_FETCHED_SIZE, 'buf' = uint32_t pointer, 'buf_len' = 4 + 2) if type==IOT_RES_CMD_FILE_SIZE, 'buf' = uint32_t pointer, 'buf_len' = 4 + 3) if type==IOT_RES_CMD_MD5SUM, 'buf' = char array buffer, 'buf_len = 33 + 4) if type==IOT_RES_CMD_VERSION, 'buf'= char array buffer, 'buf_len > RESOURCE_VERSION_STR_LEN_MAX + 5) if type==IOT_RES_CMD_FILE_NAME, 'buf'= char array buffer, 'buf_len > RESOURCE_NAME_STR_LEN_MAX + 6) if type==IOT_RES_CMD_FILE_TYPE, 'buf'= char array buffer, 'buf_len' = 5 + 7) if type==IOT_RES_CMD_CHECK_FIRMWARE, 'buf' = uint32_t pointer, 'buf_len' = 4 + * + * @retval 0 : success + * @retval < 0 : error code for failure + */ +int IOT_Resource_Ioctl(void *handle, IOT_RES_CmdType type, void *buf, size_t buf_len); + +/** + * @brief Get error code of last operation + * + * @param handle: resource module handle + * + * @return error code + */ +int IOT_Resource_GetLastError(void *handle); + +/** + * @brief Get result of _resource_report_upgrade_result in IOT_Resource_FetchYield + * + * @param handle: resource module handle + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Resource_GetReportResult(void *handle); + +/** + * @brief publish msg to resource topic + * + * @param handle: resource module handle + * + * @param msg: msg to be reported + * + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int IOT_Resource_Report_Msg(void *handle, char *msg); + +//=========== request_url =================// + +/** + * @brief request url for resource post + * + * @param handle: resource module handle + * + * @param timeout_ms: request timeout + * + * @param res_name: resource name to be posted + * + * @param res_version: resource version to be posted + * + * @param res_type: resource type to be posted + * + * @return request id (>0) when success, or err code (<0) for failure + */ +int IOT_Resource_Post_Request(void *handle, uint32_t timeout_ms, const char *res_name, char *res_version, char *res_type); + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_OTA_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_system.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_system.h new file mode 100644 index 00000000..a124b898 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/exports/qcloud_iot_export_system.h @@ -0,0 +1,51 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_SYSTEM_H_ +#define QCLOUD_IOT_EXPORT_SYSTEM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP_MAX_NUM 10 +#define ONE_IP_MAX_LEN 24 + +typedef enum { + eRESOURCE_TIME = 0, + eRESOURCE_IP, +} eSysResourcType; + +/** + * @brief Get domain ip list for dns disaster recovery + * + * @param pClient MQTTClient pointer + * @param eType type of sys resource to get + * @param usrArg usr arg to return the target resource + * @return QCLOUD_RET_SUCCESS for success + * otherwise, failure + */ +int IOT_Get_Sys_Resource(void *pClient, eSysResourcType eType, DeviceInfo *pDevInfo, void *usrArg); + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_COAP_H_ */ \ No newline at end of file diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/lite-list.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/lite-list.h new file mode 100644 index 00000000..4ceb2c45 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/lite-list.h @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2017-2019 Tencent Group. All rights reserved. + * License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/** + * Edit by shockcao@tencent.com 2018/3/15 + */ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define inline __inline + +typedef struct list_head list_head_t; + +struct list_head { + struct list_head *next, *prev; +}; + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#define LIST_HEAD_INIT(name) \ + { \ + &(name), &(name) \ + } + +#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new_ptr entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new_ptr, struct list_head *prev, struct list_head *next) +{ + next->prev = new_ptr; + new_ptr->next = next; + new_ptr->prev = prev; + prev->next = new_ptr; +} + +/** + * list_add - add a new_ptr entry + * @new_ptr: new_ptr entry to be added + * @head: list head to add it after + * + * Insert a new_ptr entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new_ptr, struct list_head *head) +{ + __list_add(new_ptr, head, head->next); +} + +/** + * list_add_tail - add a new_ptr entry + * @new_ptr: new_ptr entry to be added + * @head: list head to add it before + * + * Insert a new_ptr entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new_ptr, struct list_head *head) +{ + __list_add(new_ptr, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_replace - replace old entry by new_ptr one + * @old : the element to be replaced + * @new_ptr : the new_ptr element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, struct list_head *new_ptr) +{ + new_ptr->next = old->next; + new_ptr->next->prev = new_ptr; + new_ptr->prev = old->prev; + new_ptr->prev->next = new_ptr; +} + +static inline void list_replace_init(struct list_head *old, struct list_head *new_ptr) +{ + list_replace(old, new_ptr); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del_entry(list); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, struct list_head *head) +{ + __list_del_entry(list); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_rotate_left - rotate the list to the left + * @head: the head of the list + */ +static inline void list_rotate_left(struct list_head *head) +{ + struct list_head *first; + + if (!list_empty(head)) { + first = head->next; + list_move_tail(first, head); + } +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) list_entry((ptr)->next, type, member) + +/** + * list_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member) + +/** + * list_first_entry_or_null - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note that if the list is empty, it returns NULL. + */ +#define list_first_entry_or_null(ptr, type, member) (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) + +/** + * list_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_struct within the struct. + */ +#define list_next_entry(pos, member, type) list_entry((pos)->member.next, type, member) + +/** + * list_prev_entry - get the prev element in list + * @pos: the type * to cursor + * @member: the name of the list_struct within the struct. + */ +#define list_prev_entry(pos, member, type) list_entry((pos)->member.prev, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant doesn't differ from list_for_each() any more. + * We don't do prefetching in either case. + */ +#define __list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) for (pos = (head)->prev; pos != (head); pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) for (pos = (head)->next, n = pos->next; pos != (head); pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal + * of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; pos != (head); pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member, type) \ + for (pos = list_entry((head)->next, type, member); &pos->member != (head); \ + pos = list_entry(pos->member.next, type, member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member, type) \ + for (pos = list_entry((head)->prev, type, member); &pos->member != (head); \ + pos = list_entry(pos->member.prev, type, member)) + +/** + * list_prepare_entry - prepare a pos entry for use in + * list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in + * list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member, type) ((pos) ?: list_entry(head, type, member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member, type) \ + for (pos = list_entry(pos->member.next, type, member); &pos->member != (head); \ + pos = list_entry(pos->member.next, type, member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member, type) \ + for (pos = list_entry(pos->member.prev, type, member); &pos->member != (head); \ + pos = list_entry(pos->member.prev, type, member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current + * point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member, type) \ + for (; &pos->member != (head); pos = list_entry(pos->member.next, type, member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against + * removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member, type) \ + for (pos = list_entry((head)->next, type, member), n = list_entry(pos->member.next, type, member); \ + &pos->member != (head); pos = n, n = list_entry(n->member.next, type, member)) + +/** + * list_for_each_entry_safe_continue - continue list iteration safe against + * removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member, type) \ + for (pos = list_entry(pos->member.next, type, member), n = list_entry(pos->member.next, type, member); \ + &pos->member != (head); pos = n, n = list_entry(n->member.next, type, member)) + +/** + * list_for_each_entry_safe_from - iterate over list from current point safe + * against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member, type) \ + for (n = list_entry(pos->member.next, type, member); &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, type, member)) + +/** + * list_for_each_entry_safe_reverse - iterate backwards over list safe against + * removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member, type) \ + for (pos = list_entry((head)->prev, type, member), n = list_entry(pos->member.prev, type, member); \ + &pos->member != (head); pos = n, n = list_entry(n->member.prev, type, member)) + +/** + * list_safe_reset_next - reset a stale list_for_each_entry_safe loop + * @pos: the loop cursor used in the list_for_each_entry_safe loop + * @n: temporary storage used in list_for_each_entry_safe + * @member: the name of the list_struct within the struct. + * + * list_safe_reset_next is not safe to use in general if the list may be + * modified concurrently (eg. the lock is dropped in the loop body). An + * exception to this is if the cursor element (pos) is pinned in the list, + * and list_safe_reset_next is called after re-taking the lock and before + * completing the current iteration of the loop body. + */ +#define list_safe_reset_next(pos, n, member, type) n = list_entry(pos->member.next, type, member) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/lite-utils.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/lite-utils.h new file mode 100644 index 00000000..5ab3244f --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/lite-utils.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017-2019 Tencent Group. All rights reserved. + * License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/** + * Edit by shockcao@tencent.com 2018/3/15 + */ + +#ifndef __LITE_UTILS_H__ +#define __LITE_UTILS_H__ +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#if defined(_PLATFORM_IS_LINUX_) +#include +#endif + +#include "lite-list.h" +#include "qcloud_iot_import.h" + +#define LITE_TRUE (1) +#define LITE_FALSE (0) + +#ifndef container_of +#define container_of(ptr, type, member) ((type *)((char *)(ptr)-offsetof(type, member))) +#endif + +#define LITE_MINIMUM(a, b) (((a) <= (b)) ? (a) : (b)) +#define LITE_MAXIMUM(a, b) (((a) >= (b)) ? (a) : (b)) +#define LITE_isdigit(c) (((c) <= '9' && (c) >= '0') ? (LITE_TRUE) : (LITE_FALSE)) + +#if defined(_PLATFORM_IS_LINUX_) +#define LITE_ASSERT(expr) assert(expr) +#else +#define LITE_ASSERT(expr) \ + do { \ + if (!(expr)) { \ + HAL_Printf("### %s | %s(%d): ASSERT FAILED ###: %s is FALSE\r\n", __FILE__, __func__, __LINE__, #expr); \ + } \ + } while (0) +#endif + +char *LITE_strdup(const char *src); +char *LITE_format_string(const char *fmt, ...); +char *LITE_format_nstring(const int len, const char *fmt, ...); +void LITE_hexbuf_convert(unsigned char *digest, char *out, int buflen, int uppercase); +void LITE_hexstr_convert(char *hexstr, uint8_t *out_buf, int len); +void LITE_replace_substr(char orig[], char key[], char swap[]); +void LITE_str_strip_char(char *src, char destCh); + +char * LITE_json_value_of(char *key, char *src); +list_head_t *LITE_json_keys_of(char *src, char *prefix); +void LITE_json_keys_release(list_head_t *keylist); +char * LITE_json_string_value_strip_transfer(char *key, char *src); +void LITE_string_strip_char(char *src, char ch); + +int LITE_get_int32(int32_t *value, char *src); +int LITE_get_int16(int16_t *value, char *src); +int LITE_get_int8(int8_t *value, char *src); +int LITE_get_uint32(uint32_t *value, char *src); +int LITE_get_uint16(uint16_t *value, char *src); +int LITE_get_uint8(uint8_t *value, char *src); +int LITE_get_float(float *value, char *src); +int LITE_get_double(double *value, char *src); +int LITE_get_boolean(bool *value, char *src); +int LITE_get_string(int8_t *value, char *src, uint16_t max_len); + +typedef struct _json_key_t { + char * key; + list_head_t list; +} json_key_t; + +#define foreach_json_keys_in(src, iter_key, keylist, pos) \ + for (keylist = (void *)LITE_json_keys_of((char *)src, ""), \ + pos = (void *)list_first_entry((list_head_t *)keylist, json_key_t, list), iter_key = ((json_key_t *)pos)->key; \ + (iter_key = ((json_key_t *)pos)->key); pos = list_next_entry((json_key_t *)pos, list, json_key_t)) + +#ifdef __cplusplus +} +#endif + +#endif /* __LITE_UTILS_H__ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/platform.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/platform.h new file mode 100644 index 00000000..9661557f --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/platform.h @@ -0,0 +1,57 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef PLATFORM_H_ +#define PLATFORM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define PATH_MAX 1024 +/* Max size of cert/key file full path */ +#define FILE_PATH_MAX_LEN 256 + +#ifdef WIN32 +#include +#include +#include +typedef unsigned long ssize_t; +#define getcwd(buffer, len) _getcwd(buffer, len) +#endif + +#if defined(__linux__) +#include +#include +//#include +#include +#include +#include +#include +#include +#include + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PLATFORM_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qcloud_iot_export.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qcloud_iot_export.h new file mode 100644 index 00000000..70f9a925 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qcloud_iot_export.h @@ -0,0 +1,115 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_H_ +#define QCLOUD_IOT_EXPORT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "config.h" +#include "platform.h" + +/* IoT C-SDK version info */ +#define QCLOUD_IOT_DEVICE_SDK_VERSION "3.1.5" + +/**************** QCloud IoT C-SDK constants begin ************************/ + +/* MAX size of client ID */ +#define MAX_SIZE_OF_CLIENT_ID (80) + +/* MAX size of product ID */ +#define MAX_SIZE_OF_PRODUCT_ID (10) + +/* MAX size of product secret */ +#define MAX_SIZE_OF_PRODUCT_SECRET (32) + +/* MAX size of device name */ +#define MAX_SIZE_OF_DEVICE_NAME (48) + +/* MAX size of device secret */ +#define MAX_SIZE_OF_DEVICE_SECRET (64) + +/* MAX size of device cert file name */ +#define MAX_SIZE_OF_DEVICE_CERT_FILE_NAME (128) + +/* MAX size of device key file name */ +#define MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME (128) + +/* MAX size of region len */ +#define MAX_SIZE_OF_REGION (64) + +/* MAX num of subdevice */ +#define MAX_NUM_SUB_DEV (50) + +/**************** QCloud IoT C-SDK constants end *************************/ +typedef enum { + eCOMMON_DEV = 0, // common dev + eGW_DEV = 1, // Gateway dev + eGW_SUB_DEV = 2, // sub dev of Gateway + eDEFAULT_DEV +} eDevType; + +typedef struct { + char product_id[MAX_SIZE_OF_PRODUCT_ID + 1]; + char device_name[MAX_SIZE_OF_DEVICE_NAME + 1]; + char client_id[MAX_SIZE_OF_CLIENT_ID + 1]; + +#ifdef AUTH_MODE_CERT + char dev_cert_file_name[MAX_SIZE_OF_DEVICE_CERT_FILE_NAME + 1]; + char dev_key_file_name[MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME + 1]; +#else + char device_secret[MAX_SIZE_OF_DEVICE_SECRET + 1]; +#endif + +#ifdef DEV_DYN_REG_ENABLED + char product_secret[MAX_SIZE_OF_PRODUCT_SECRET + 1]; +#endif + char region[MAX_SIZE_OF_REGION]; + + eDevType dev_type; +} DeviceInfo; + +#ifdef GATEWAY_ENABLED +typedef struct { + DeviceInfo gw_info; + DeviceInfo sub_dev_info[MAX_NUM_SUB_DEV]; + int sub_dev_num; +} GatewayDeviceInfo; +#endif + +#include "qcloud_iot_export_variables.h" +#include "qcloud_iot_export_error.h" +#include "qcloud_iot_export_log.h" +#include "qcloud_iot_export_mqtt.h" +#include "qcloud_iot_export_data_template.h" +#include "qcloud_iot_export_ota.h" +#include "qcloud_iot_export_resource.h" +#include "qcloud_iot_export_asr.h" +#include "qcloud_iot_export_gateway.h" +#include "qcloud_iot_export_dynreg.h" +#include "qcloud_iot_export_system.h" + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qcloud_iot_export_variables.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qcloud_iot_export_variables.h new file mode 100644 index 00000000..7031958e --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qcloud_iot_export_variables.h @@ -0,0 +1,82 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_EXPORT_VARIABLES_H_ +#define QCLOUD_IOT_EXPORT_VARIABLES_H_ + +/* + * Below variables are dependant on user situation (network status/device + * memory/application context) + * Adjust the default value to meet your requirement + */ + +/* default MQTT/CoAP timeout value when connect/pub/sub (unit: ms) */ +#define QCLOUD_IOT_MQTT_COMMAND_TIMEOUT (5 * 1000) + +/* default MQTT keep alive interval (unit: ms) */ +#define QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL (240 * 1000) + +/* default MQTT Tx buffer size, MAX: 16*1024 */ +#define QCLOUD_IOT_MQTT_TX_BUF_LEN (2048) + +/* default MQTT Rx buffer size, MAX: 16*1024 */ +#define QCLOUD_IOT_MQTT_RX_BUF_LEN (2048) + +/* default COAP Tx buffer size, MAX: 1*1024 */ +#define COAP_SENDMSG_MAX_BUFLEN (512) + +/* default COAP Rx buffer size, MAX: 1*1024 */ +#define COAP_RECVMSG_MAX_BUFLEN (512) + +/* MAX MQTT reconnect interval (unit: ms) */ +#define MAX_RECONNECT_WAIT_INTERVAL (60 * 1000) + +/* MAX valid time when connect to MQTT server. 0: always valid */ +/* Use this only if the device has accurate UTC time. Otherwise, set to 0 */ +#define MAX_ACCESS_EXPIRE_TIMEOUT (0) + +/* log print/upload related variables */ +/* MAX size of log buffer for one log item including header and content */ +#define MAX_LOG_MSG_LEN (511) + +#if defined(__linux__) +#undef MAX_LOG_MSG_LEN +#define MAX_LOG_MSG_LEN (1023) +#endif + +/* + * Log upload related params, which will affect the size of device memory/disk + * consumption + * the default value can be changed for different user situation + */ +// size of buffer for log upload +#define LOG_UPLOAD_BUFFER_SIZE 5000 + +// Max size of one http log upload. Should not larger than 5000 +#define MAX_HTTP_LOG_POST_SIZE 3000 + +// MAX size for saving log into NVS (files/FLASH) after upload fail +#define MAX_LOG_SAVE_SIZE (3 * LOG_UPLOAD_BUFFER_SIZE) + +// interval of log upload (unit: ms) Decrease this value if +// LOG_UPLOAD_BUFFER_SIZE is small +#define LOG_UPLOAD_INTERVAL_MS 2000 + +#endif /* QCLOUD_IOT_EXPORT_VARIABLES_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qcloud_iot_import.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qcloud_iot_import.h new file mode 100644 index 00000000..0edf6d4a --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qcloud_iot_import.h @@ -0,0 +1,656 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_IMPORT_H_ +#define QCLOUD_IOT_IMPORT_H_ +#if defined(__cplusplus) +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "platform.h" + +#define _IN_ /* indicate an input parameter */ +#define _OU_ /* indicate a output parameter */ + +#define IOT_TRUE (1) /* indicate boolean value true */ +#define IOT_FALSE (0) /* indicate boolean value false */ + +#define Max(a, b) ((a) > (b) ? (a) : (b)) +#define Min(a, b) ((a) < (b) ? (a) : (b)) + +/********************************************************************** + * QCloud IoT C-SDK Hardware Abstraction Layer + * Platform/OS/IP stack/SSL dependant functions + * Check platform folder for reference implementaions + * Require porting when adapt SDK to new platform/OS + *********************************************************************/ + +typedef void (*ThreadRunFunc)(void *arg); + +typedef struct ThreadParams { + char * thread_name; + size_t thread_id; + ThreadRunFunc thread_func; + void * user_arg; + uint16_t priority; + uint32_t stack_size; +} ThreadParams; + +/** + * @brief Create a thread/task + * + * @param params thread parameters + * @return 0 when success, or error code otherwise + */ +int HAL_ThreadCreate(ThreadParams *params); + +/** + * @brief Destroy a thread/task + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_ThreadDestroy(void *thread_t); + +/** + * @brief create semaphore + * + * @return a valid semaphore handle when success, or NULL otherwise + */ +void *HAL_SemaphoreCreate(void); + +/** + * @brief Destroy semaphore + * @param sem semaphore handle + */ +void HAL_SemaphoreDestroy(void *sem); + +/** + * @brief Post semaphore + * @param sem semaphore handle + */ +void HAL_SemaphorePost(void *sem); + +/** + * @brief Wait for semaphore + * @param sem semaphore handle + * @param timeout_ms waiting timeout value (unit: ms) + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_SemaphoreWait(void *sem, uint32_t timeout_ms); + +/** + * @brief Create mutex + * + * @return a valid mutex handle when success, or NULL otherwise + */ +void *HAL_MutexCreate(void); + +/** + * @brief Destroy mutex + * + * @param mutex mutex handle + */ +void HAL_MutexDestroy(_IN_ void *mutex); + +/** + * @brief Lock a mutex in blocking way + * + * @param mutex mutex handle + */ +void HAL_MutexLock(_IN_ void *mutex); + +/** + * @brief Lock a mutex in non-blocking way + * + * @param mutex mutex handle + * @return 0 for success, or err code for failure + */ +int HAL_MutexTryLock(_IN_ void *mutex); + +/** + * @brief Unlock/release mutex + * + * @param mutex mutex handle + */ +void HAL_MutexUnlock(_IN_ void *mutex); + +/** + * @brief Malloc memory + * + * @param size Expected memory size (unit: byte) + * @return pointer to the memory + */ +void *HAL_Malloc(_IN_ uint32_t size); + +/** + * @brief Free memory + * + * @param ptr pointer to the pre-malloc memory + */ +void HAL_Free(_IN_ void *ptr); + +/** + * @brief Print data to console in format + * + * @param fmt print format + * @param ... variable number of arguments + */ +void HAL_Printf(_IN_ const char *fmt, ...); + +/** + * @brief Print data to string in format + * + * @param str destination string + * @param len Max size of the output + * @param fmt print format + * @param ... variable number of arguments + * @return number of bytes that print successfull + */ +int HAL_Snprintf(_IN_ char *str, const int len, const char *fmt, ...); + +/** + Print data to string in format + * + * @param str destination string + * @param len Max size of the output + * @param fmt print format + * @param ap arguments list + * @return number of bytes that print successfull + + */ +int HAL_Vsnprintf(_OU_ char *str, _IN_ const int len, _IN_ const char *fmt, _IN_ va_list ap); + +/** + * @brief Get timestamp in millisecond + * + * @return timestamp in millisecond + */ +uint32_t HAL_GetTimeMs(void); + +/** + * @brief Delay operation in blocking way + * + * @param ms sleep interval in millisecond + */ +void HAL_DelayMs(_IN_ uint32_t ms); + +/** + * @brief Sleep for a while + * + * @param ms sleep interval in millisecond + */ +void HAL_SleepMs(_IN_ uint32_t ms); + +/** + * @brief Set device info to NVS(flash/files) + * + * @param pdevInfo reference to device info + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_SetDevInfo(void *pdevInfo); + +/** + * @brief Get device info from NVS(flash/files) + * + * @param pdevInfo reference to device info + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_GetDevInfo(void *pdevInfo); + +/** + * @brief Get device info from a JSON file + * + * @param file_name JSON file path + * @param pdevInfo reference to device info + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_GetDevInfoFromFile(const char *file_name, void *dev_info); + +#ifdef GATEWAY_ENABLED +/** + * @brief Get gateway device info from NVS(flash/files) + * + * @param pgwDeviceInfo reference to gateway device info + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_GetGwDevInfo(void *pgwDeviceInfo); +#endif + +/** + * @brief Set the name of file which contain device info + * + * @param file_name the name of file which contain device info + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_SetDevInfoFile(const char *file_name); + +/** + * Define timer structure, platform dependant + */ +struct Timer { +#if defined(__linux__) && defined(__GLIBC__) + struct timeval end_time; +#else + uintptr_t end_time; +#endif +}; + +typedef struct Timer Timer; + +/** + * @brief Check if timer expires or not + * + * @param timer reference to timer + * @return true = expired, false = not expired yet + */ +bool HAL_Timer_expired(Timer *timer); + +/** + * @brief Set the countdown/expired value for the timer + * + * @param timer reference to timer + * @param timeout_ms countdown/expired value (unit: millisecond) + */ +void HAL_Timer_countdown_ms(Timer *timer, unsigned int timeout_ms); + +/** + * @brief Set the countdown/expired value for the timer + * + * @param timer reference to timer + * @param timeout countdown/expired value (unit: second) + */ +void HAL_Timer_countdown(Timer *timer, unsigned int timeout); + +/** + * @brief Check the remain time of the timer + * + * @param timer reference to timer + * @return 0 if expired, or the left time in millisecond + */ +int HAL_Timer_remain(Timer *timer); + +/** + * @brief Init the timer + * + * @param timer reference to timer + */ +void HAL_Timer_init(Timer *timer); + +#define TIME_FORMAT_STR_LEN (20) +/** + * @brief Get local time in format: %y-%m-%d %H:%M:%S + * + * @return string of formatted time + */ +char *HAL_Timer_current(char *time_str); + +/** + * @brief Get timestamp in second + * + * @return timestamp in second + */ +long HAL_Timer_current_sec(void); + +#ifdef AT_TCP_ENABLED +int HAL_AT_TCP_Init(void); +uintptr_t HAL_AT_TCP_Connect(const char *host, uint16_t port); +int HAL_AT_TCP_Disconnect(uintptr_t fd); +int HAL_AT_TCP_Write(uintptr_t fd, const unsigned char *buf, uint32_t len, uint32_t timeout_ms, size_t *written_len); +int HAL_AT_TCP_Read(uintptr_t fd, uint8_t *buf, uint32_t len, uint32_t timeout_ms, uint32_t *read_len); +int at_device_init(void); +int HAL_AT_Uart_Init(void); +int HAL_AT_Uart_Deinit(void); +int HAL_AT_Uart_Send(void *data, uint32_t size); +int HAL_AT_Uart_Recv(void *data, uint32_t expect_size, uint32_t *recv_size, uint32_t timeout); +#endif + +/********** TLS/DTLS network sturcture and operations **********/ +#ifndef AUTH_WITH_NOTLS + +#ifndef MAX_SIZE_OF_CLIENT_ID +#define MAX_SIZE_OF_CLIENT_ID (80) +#endif +/** + * @brief Define structure for TLS connection parameters + * + */ +typedef struct { + const char *ca_crt; + uint16_t ca_crt_len; + +#ifdef AUTH_MODE_CERT + /** + * Device with certificate + */ + const char *cert_file; // public certificate file + const char *key_file; // pravite certificate file +#else + /** + * Device with PSK + */ + const char *psk; // PSK string + char psk_id[MAX_SIZE_OF_CLIENT_ID + 1]; // PSK ID +#endif + + size_t psk_length; // PSK length + + unsigned int timeout_ms; // SSL handshake timeout in millisecond + +} SSLConnectParams; + +typedef SSLConnectParams TLSConnectParams; + +/** + * @brief Setup TLS connection with server + * + * @param pConnectParams reference to TLS connection parameters + * @host server address + * @port server port + * @return TLS connect handle when success, or 0 otherwise + */ +uintptr_t HAL_TLS_Connect(TLSConnectParams *pConnectParams, const char *host, int port); + +/** + * @brief Disconnect with TLS server and release resources + * + * @param handle TLS connect handle + */ +void HAL_TLS_Disconnect(uintptr_t handle); + +/** + * @brief Write data via TLS connection + * + * @param handle TLS connect handle + * @param data source data to write + * @param totalLen length of data + * @param timeout_ms timeout value in millisecond + * @param written_len length of data written successfully + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_TLS_Write(uintptr_t handle, unsigned char *data, size_t totalLen, uint32_t timeout_ms, size_t *written_len); + +/** + * @brief Read data via TLS connection + * + * @param handle TLS connect handle + * @param data destination data buffer where to put data + * @param totalLen length of data + * @param timeout_ms timeout value in millisecond + * @param read_len length of data read successfully + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_TLS_Read(uintptr_t handle, unsigned char *data, size_t totalLen, uint32_t timeout_ms, size_t *read_len); + +/********** DTLS network **********/ +#ifdef COAP_COMM_ENABLED +typedef SSLConnectParams DTLSConnectParams; + +/** + * @brief Setup DTLS connection with server + * + * @param pConnectParams reference to DTLS connection parameters + * @host server address + * @port server port + * @return DTLS connect handle when success, or 0 otherwise + */ +uintptr_t HAL_DTLS_Connect(DTLSConnectParams *pConnectParams, const char *host, int port); + +/** + * @brief Disconnect with DTLS server and release resources + * + * @param handle DTLS connect handle + */ +void HAL_DTLS_Disconnect(uintptr_t handle); + +/** + * @brief Write data via DTLS connection + * + * @param handle DTLS connect handle + * @param data source data to write + * @param totalLen length of data + * @param timeout_ms timeout value in millisecond + * @param written_len length of data written successfully + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_DTLS_Write(uintptr_t handle, const unsigned char *data, size_t datalen, size_t *written_len); + +/** + * @brief Read data via DTLS connection + * + * @param handle DTLS connect handle + * @param data destination data buffer where to put data + * @param totalLen length of data + * @param timeout_ms timeout value in millisecond + * @param read_len length of data read successfully + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_DTLS_Read(uintptr_t handle, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len); + +#endif // COAP_COMM_ENABLED +#endif // AUTH_WITH_NOTLS + +/********** TCP network **********/ +/** + * @brief Setup TCP connection with server + * + * @host server address + * @port server port + * @return TCP socket handle (value>0) when success, or 0 otherwise + */ +uintptr_t HAL_TCP_Connect(const char *host, uint16_t port); + +/** + * @brief Disconnect with server and release resource + * + * @param fd TCP Socket handle + * @return 0 when success + */ +int HAL_TCP_Disconnect(uintptr_t fd); + +/** + * @brief Write data via TCP connection + * + * @param fd TCP socket handle + * @param data source data to write + * @param len length of data + * @param timeout_ms timeout value in millisecond + * @param written_len length of data written successfully + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_TCP_Write(uintptr_t fd, const unsigned char *data, uint32_t len, uint32_t timeout_ms, size_t *written_len); + +/** + * @brief Read data via TCP connection + * + * @param fd TCP socket handle + * @param data destination data buffer where to put data + * @param len length of data + * @param timeout_ms timeout value in millisecond + * @param read_len length of data read successfully + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int HAL_TCP_Read(uintptr_t fd, unsigned char *data, uint32_t len, uint32_t timeout_ms, size_t *read_len); + +/********** UDP network **********/ +#ifdef COAP_COMM_ENABLED +/** + * @brief Setup UDP connection with server + * + * @host server address + * @port server port + * @return UPD socket handle (value>0) when success, or 0 otherwise + */ +uintptr_t HAL_UDP_Connect(const char *host, unsigned short port); + +/** + * @brief Disconnect with server and release resource + * + * @param fd UDP Socket handle + * @return 0 when success + */ +void HAL_UDP_Disconnect(uintptr_t fd); + +/** + * @brief Write data via UDP connection + * + * @param fd UDP socket handle + * @param data source data to write + * @param len length of data + * @return length of data written when success, or err code for + * failure + */ +int HAL_UDP_Write(uintptr_t fd, const unsigned char *data, unsigned int len); + +/** + * @brief Read data via UDP connection + * + * @param fd UDP socket handle + * @param data destination data buffer where to put data + * @param len length of data + * @return length of data read when success, or err code for + * failure + */ +int HAL_UDP_Read(uintptr_t fd, unsigned char *data, unsigned int len); + +/** + * @brief Read data via UDP connection + * + * @param fd UDP socket handle + * @param data destination data buffer where to put data + * @param len length of data + * @param timeout_ms timeout value in millisecond + * @return length of data read when success, or err code for + * failure + */ +int HAL_UDP_ReadTimeout(uintptr_t fd, unsigned char *p_data, unsigned int datalen, unsigned int timeout_ms); +#endif // COAP_COMM_ENABLED + +#ifdef LOG_UPLOAD +/* Functions for saving/reading logs into/from NVS(files/FLASH) after log upload + * fail/recover */ +/** + * @brief Functions for saving logs into NVS(files/FLASH) after log upload fail + * @param log source log buffer + * @param len length of log to save + * @return length of data save when success, or 0 for failure + */ +size_t HAL_Log_Save(const char *log, size_t len); + +/** + * @brief Functions for reading logs from NVS(files/FLASH) when log upload ready + * @param buf destination log buffer + * @param len length of log to read + * @return length of data read when success, or 0 for failure + */ +size_t HAL_Log_Read(char *buf, size_t len); + +/** + * @brief Functions for deleting logs in NVS(files/FLASH). + * @return 0 when success + */ +int HAL_Log_Del(void); + +/** + * @brief Functions for reading the size of logs in NVS(files/FLASH). + * @return 0 when nothing exist + */ +size_t HAL_Log_Get_Size(void); +#endif + +/** + * @brief Opens the filename pointed to by filename using the given mode. + */ +void *HAL_FileOpen(const char *filename, const char *mode); + +/** + * @brief Reads data from the given stream into the array pointed to by ptr. + */ +size_t HAL_FileRead(void *ptr, size_t size, size_t nmemb, void *fp); + +/** + * @brief Writes data from the array pointed to by ptr to the given stream. + */ +size_t HAL_FileWrite(const void *ptr, size_t size, size_t nmemb, void *fp); + +/** + * @brief Sets the file position of the stream to the given offset. The argument + * offset signifies the number of bytes to seek from the given whence position. + */ +int HAL_FileSeek(void *fp, long int offset, int whence); + +/** + * @brief Closes the stream. All buffers are flushed. + */ +int HAL_FileClose(void *fp); + +/** + * @brief Deletes the given filename so that it is no longer accessible. + */ +int HAL_FileRemove(const char *filename); + +/** + * @brief Sets the file position to the beginning of the file of the given stream. + */ +int HAL_FileRewind(void *fp); + +/** + * @brief Causes the filename referred to, by old_filename to be changed to new_filename + */ +int HAL_FileRename(const char *old_filename, const char *new_filename); + +/** + * @brief Tests the end-of-file indicator for the given stream. + */ +int HAL_FileEof(void *fp); + +/** + * @brief Get the current pose of stream. + */ +long HAL_FileTell(void *fp); + +/** + * @brief Get the stream size. + */ +long HAL_FileSize(void *fp); + +/** + * @brief Get one line from the stream. + */ +char *HAL_FileGets(char *str, int n, void *fp); + +/** + * @brief Flushes the output buffer of a stream. + */ +int HAL_FileFlush(void *fp); + +#if defined(__cplusplus) +} +#endif +#endif /* QCLOUD_IOT_IMPORT_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qutils_getopt.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qutils_getopt.h new file mode 100644 index 00000000..e02a586c --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/include/qutils_getopt.h @@ -0,0 +1,36 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef __UTILS_GETOPT_H__ +#define __UTILS_GETOPT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *utils_optarg; /* pointer to argument of current option */ +int qutils_getopt(int nargc, char *const *nargv, const char *options); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_DTLS_mbedtls.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_DTLS_mbedtls.c new file mode 100644 index 00000000..8e807d44 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_DTLS_mbedtls.c @@ -0,0 +1,385 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" + +#ifndef AUTH_WITH_NOTLS + +#ifdef COAP_COMM_ENABLED + +#include +#include +#include + +#include "mbedtls/certs.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/debug.h" +#include "mbedtls/entropy.h" +#include "mbedtls/error.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_cookie.h" +#include "mbedtls/timing.h" +#include "qutils_param_check.h" +#include "qutils_timer.h" + +#define DEBUG_LEVEL 0 + +#ifndef AUTH_MODE_CERT +static const int ciphersuites[] = {MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, 0}; +#endif + +/** + * @brief data structure for mbedtls SSL connection + */ +typedef struct { + mbedtls_net_context socket_fd; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ssl; + mbedtls_ssl_config ssl_conf; + mbedtls_x509_crt ca_cert; + mbedtls_x509_crt client_cert; + mbedtls_pk_context private_key; + + mbedtls_timing_delay_context timer; + mbedtls_ssl_cookie_ctx cookie_ctx; +} DTLSDataParams; + +/** + * @brief free memory/resources allocated by mbedtls + */ +static void _free_mebeddtls(DTLSDataParams *pParams) +{ + mbedtls_net_free(&(pParams->socket_fd)); + mbedtls_x509_crt_free(&(pParams->client_cert)); + mbedtls_x509_crt_free(&(pParams->ca_cert)); + mbedtls_pk_free(&(pParams->private_key)); + mbedtls_ssl_free(&(pParams->ssl)); + mbedtls_ssl_config_free(&(pParams->ssl_conf)); + mbedtls_ctr_drbg_free(&(pParams->ctr_drbg)); + mbedtls_entropy_free(&(pParams->entropy)); + mbedtls_ssl_cookie_free(&(pParams->cookie_ctx)); + + HAL_Free(pParams); +} + +static void _dtls_debug(void *ctx, int level, const char *file, int line, const char *str) +{ + Log_i("[mbedTLS]:[%s]:[%d]: %s\r\n", STRING_PTR_PRINT_SANITY_CHECK(file), line, STRING_PTR_PRINT_SANITY_CHECK(str)); +} + +static int _mbedtls_client_init(DTLSDataParams *pDataParams, DTLSConnectParams *pConnectParams) +{ + int ret = QCLOUD_RET_SUCCESS; + +#if defined(MBEDTLS_DEBUG_C) + mbedtls_debug_set_threshold(DEBUG_LEVEL); +#endif + + mbedtls_net_init(&(pDataParams->socket_fd)); + mbedtls_ssl_init(&(pDataParams->ssl)); + mbedtls_ssl_config_init(&(pDataParams->ssl_conf)); + mbedtls_x509_crt_init(&(pDataParams->ca_cert)); + mbedtls_x509_crt_init(&(pDataParams->client_cert)); + mbedtls_pk_init(&(pDataParams->private_key)); + mbedtls_ctr_drbg_init(&(pDataParams->ctr_drbg)); + mbedtls_entropy_init(&(pDataParams->entropy)); + + if ((ret = mbedtls_ctr_drbg_seed(&pDataParams->ctr_drbg, mbedtls_entropy_func, &pDataParams->entropy, NULL, 0)) != + 0) { + Log_e("mbedtls_ctr_drbg_seed failed returned -0x%x", -ret); + return QCLOUD_ERR_SSL_INIT; + } + + mbedtls_ssl_conf_authmode(&pDataParams->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); + + if (pConnectParams->ca_crt != NULL) { + if ((ret = mbedtls_x509_crt_parse(&(pDataParams->ca_cert), (const unsigned char *)pConnectParams->ca_crt, + (pConnectParams->ca_crt_len + 1)))) { + Log_e("parse ca crt failed returned -0x%04x", -ret); + return QCLOUD_ERR_SSL_CERT; + } + } + +#ifdef AUTH_MODE_CERT + if (pConnectParams->cert_file != NULL && pConnectParams->key_file != NULL) { + if ((ret = mbedtls_x509_crt_parse_file(&(pDataParams->client_cert), pConnectParams->cert_file)) != 0) { + Log_e("load client cert file failed returned -0x%x", ret); + return QCLOUD_ERR_SSL_CERT; + } + + if ((ret = mbedtls_pk_parse_keyfile(&(pDataParams->private_key), pConnectParams->key_file, "")) != 0) { + Log_e("load client key file failed returned -0x%x", ret); + return QCLOUD_ERR_SSL_CERT; + } + + if (0 == ret) { + mbedtls_ssl_conf_ca_chain(&(pDataParams->ssl_conf), &(pDataParams->ca_cert), NULL); + if ((ret = mbedtls_ssl_conf_own_cert(&(pDataParams->ssl_conf), &(pDataParams->client_cert), + &(pDataParams->private_key))) != 0) { + Log_e("mbedtls_ssl_conf_own_cert failed returned -0x%x", -ret); + return QCLOUD_ERR_SSL_CERT; + } + } + } else { + Log_d("cert_file/key_file is empty!|cert_file=%s|key_file=%s", + STRING_PTR_PRINT_SANITY_CHECK(pConnectParams->cert_file), + STRING_PTR_PRINT_SANITY_CHECK(pConnectParams->key_file)); + } + +#else + if (pConnectParams->psk != NULL && pConnectParams->psk_id != NULL) { + const char *psk_id = pConnectParams->psk_id; + ret = mbedtls_ssl_conf_psk(&(pDataParams->ssl_conf), (unsigned char *)pConnectParams->psk, + pConnectParams->psk_length, (const unsigned char *)psk_id, strlen(psk_id)); + } else { + Log_d("psk/pskid is empty!"); + } + + if (0 != ret) { + Log_e("mbedtls_ssl_conf_psk fail: -0x%x", -ret); + return ret; + } +#endif + + return ret; +} + +/** + * @brief Setup UDP connection + * + * @param socket_fd socket handle + * @param host server address + * @param port server port + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int _mbedtls_udp_connect(mbedtls_net_context *socket_fd, const char *host, int port) +{ + int ret = 0; + char port_str[6]; + HAL_Snprintf(port_str, 6, "%d", port); + if ((ret = mbedtls_net_connect(socket_fd, host, port_str, MBEDTLS_NET_PROTO_UDP)) != 0) { + Log_e("mbedtls_net_connect host:%s port:%s returned -0x%04x errno: %d", STRING_PTR_PRINT_SANITY_CHECK(host), + port_str, -ret, errno); + switch (ret) { + case MBEDTLS_ERR_NET_SOCKET_FAILED: + return QCLOUD_ERR_TCP_SOCKET_FAILED; + case MBEDTLS_ERR_NET_UNKNOWN_HOST: + return QCLOUD_ERR_TCP_UNKNOWN_HOST; + default: + return QCLOUD_ERR_TCP_CONNECT; + } + } + + if ((ret = mbedtls_net_set_block(socket_fd)) != 0) { + Log_e("set block faliled returned -0x%04x", -ret); + return QCLOUD_ERR_TCP_CONNECT; + } + + return QCLOUD_RET_SUCCESS; +} + +uintptr_t HAL_DTLS_Connect(DTLSConnectParams *pConnectParams, const char *host, int port) +{ + IOT_FUNC_ENTRY; + + int ret = QCLOUD_RET_SUCCESS; + + DTLSDataParams *pDataParams = (DTLSDataParams *)HAL_Malloc(sizeof(DTLSDataParams)); + + if ((ret = _mbedtls_client_init(pDataParams, pConnectParams)) != QCLOUD_RET_SUCCESS) { + goto error; + } + + if ((ret = _mbedtls_udp_connect(&(pDataParams->socket_fd), host, port)) != QCLOUD_RET_SUCCESS) { + goto error; + } + + if ((ret = mbedtls_ssl_config_defaults(&pDataParams->ssl_conf, MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + Log_e("mbedtls_ssl_config_defaults result 0x%04x", ret); + goto error; + } + + mbedtls_ssl_conf_authmode(&(pDataParams->ssl_conf), MBEDTLS_SSL_VERIFY_REQUIRED); + + mbedtls_ssl_conf_rng(&pDataParams->ssl_conf, mbedtls_ctr_drbg_random, &pDataParams->ctr_drbg); + mbedtls_ssl_conf_dbg(&pDataParams->ssl_conf, _dtls_debug, NULL); + + if ((ret = mbedtls_ssl_cookie_setup(&pDataParams->cookie_ctx, mbedtls_ctr_drbg_random, &pDataParams->ctr_drbg)) != + 0) { + Log_e("mbedtls_ssl_cookie_setup result 0x%04x", ret); + goto error; + } + + mbedtls_ssl_conf_dtls_cookies(&pDataParams->ssl_conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, + &pDataParams->cookie_ctx); + +#ifndef AUTH_MODE_CERT + mbedtls_ssl_conf_ciphersuites(&(pDataParams->ssl_conf), ciphersuites); +#endif + +#ifdef MBEDTLS_SSL_PROTO_DTLS + if (pDataParams->ssl_conf.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) { + mbedtls_ssl_conf_min_version(&pDataParams->ssl_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); + + mbedtls_ssl_conf_max_version(&pDataParams->ssl_conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); + + mbedtls_ssl_conf_handshake_timeout(&pDataParams->ssl_conf, (MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN * 2), + (MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN * 2 * 4)); + } +#endif + + if ((ret = mbedtls_ssl_setup(&(pDataParams->ssl), &(pDataParams->ssl_conf))) != 0) { + Log_e("mbedtls_ssl_setup failed returned -0x%x", -ret); + goto error; + } + + if (pDataParams->ssl_conf.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) { + mbedtls_ssl_set_timer_cb(&(pDataParams->ssl), (void *)&pDataParams->timer, mbedtls_timing_set_delay, + mbedtls_timing_get_delay); + } + + if ((ret = mbedtls_ssl_set_hostname(&(pDataParams->ssl), host)) != 0) { + Log_e("mbedtls_ssl_set_hostname failed returned -0x%x", -ret); + goto error; + } + + mbedtls_ssl_set_bio(&(pDataParams->ssl), (void *)&pDataParams->socket_fd, mbedtls_net_send, mbedtls_net_recv, + mbedtls_net_recv_timeout); + + while ((ret = mbedtls_ssl_handshake(&(pDataParams->ssl))) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + Log_e("mbedtls_ssl_handshake failed returned -0x%x", -ret); + if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { + Log_e("Unable to verify the server's certificate"); + } + goto error; + } + } + + if ((ret = mbedtls_ssl_get_verify_result(&(pDataParams->ssl))) != 0) { + Log_e("mbedtls_ssl_get_verify_result failed returned -0x%x", -ret); + goto error; + } + + return (uintptr_t)pDataParams; + +error: + _free_mebeddtls(pDataParams); + return 0; +} + +void HAL_DTLS_Disconnect(uintptr_t handle) +{ + if ((uintptr_t)NULL == handle) { + Log_d("handle is NULL"); + return; + } + + DTLSDataParams *pParams = (DTLSDataParams *)handle; + int ret = 0; + do { + ret = mbedtls_ssl_close_notify(&(pParams->ssl)); + } while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE); + + mbedtls_net_free(&(pParams->socket_fd)); + mbedtls_x509_crt_free(&(pParams->client_cert)); + mbedtls_x509_crt_free(&(pParams->ca_cert)); + mbedtls_pk_free(&(pParams->private_key)); + mbedtls_ssl_free(&(pParams->ssl)); + mbedtls_ssl_config_free(&(pParams->ssl_conf)); + mbedtls_ctr_drbg_free(&(pParams->ctr_drbg)); + mbedtls_entropy_free(&(pParams->entropy)); + mbedtls_ssl_cookie_free(&(pParams->cookie_ctx)); + + HAL_Free((void *)handle); +} + +int HAL_DTLS_Write(uintptr_t handle, const unsigned char *data, size_t datalen, size_t *written_len) +{ + DTLSDataParams *data_params = (DTLSDataParams *)handle; + POINTER_SANITY_CHECK(data_params, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(data, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(written_len, QCLOUD_ERR_INVAL); + + int rc = mbedtls_ssl_write(&data_params->ssl, data, datalen); + + if (rc < 0) { + Log_e("failed! mbedtls_ssl_write returned %d", rc); + rc = QCLOUD_ERR_SSL_WRITE; + } + + *written_len = rc; + rc = QCLOUD_RET_SUCCESS; + + IOT_FUNC_EXIT_RC(rc); +} + +int HAL_DTLS_Read(uintptr_t handle, unsigned char *data, size_t datalen, unsigned int timeout_ms, size_t *read_len) +{ + DTLSDataParams *data_params = (DTLSDataParams *)handle; + POINTER_SANITY_CHECK(data_params, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(data, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(read_len, QCLOUD_ERR_INVAL); + + int rc = QCLOUD_ERR_SSL_READ; + + mbedtls_ssl_conf_read_timeout(&(data_params->ssl_conf), timeout_ms); + + do { + rc = mbedtls_ssl_read(&(data_params->ssl), data, datalen); + } while (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE); + + if (rc <= 0) { + *read_len = 0; + switch (rc) { + case MBEDTLS_ERR_SSL_TIMEOUT: + rc = QCLOUD_ERR_SSL_READ_TIMEOUT; + break; + + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + Log_e("connection was closed gracefully"); + rc = QCLOUD_ERR_DTLS_PEER_CLOSE_NOTIFY; + break; + + default: + Log_e(" mbedtls_ssl_read returned -0x%x", -rc); + break; + } + } else { + *read_len = rc; + rc = QCLOUD_RET_SUCCESS; + } + + return rc; +} +#endif + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_Device_freertos.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_Device_freertos.c new file mode 100644 index 00000000..45130eb6 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_Device_freertos.c @@ -0,0 +1,186 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include + +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_param_check.h" + +/* Enable this macro (also control by cmake) to use static string buffer to + * store device info */ +/* To use specific storing methods like files/flash, disable this macro and + * implement dedicated methods */ +#define DEBUG_DEV_INFO_USED + +#ifdef DEBUG_DEV_INFO_USED +/* product Id */ +static char sg_product_id[MAX_SIZE_OF_PRODUCT_ID + 1] = "US0JEK629P"; //shchen + +/* device name */ +static char sg_device_name[MAX_SIZE_OF_DEVICE_NAME + 1] = "BL602"; + +/* region */ +static char sg_region[MAX_SIZE_OF_REGION + 1] = "china"; + +#ifdef DEV_DYN_REG_ENABLED +/* product secret for device dynamic Registration */ +static char sg_product_secret[MAX_SIZE_OF_PRODUCT_SECRET + 1] = "yggBSwXfvg6zrxf+VU9+vQ=="; + +#endif + +#ifdef AUTH_MODE_CERT +/* public cert file name of certificate device */ +static char sg_device_cert_file_name[MAX_SIZE_OF_DEVICE_CERT_FILE_NAME + 1] = "YOUR_DEVICE_NAME_cert.crt"; +/* private key file name of certificate device */ +static char sg_device_privatekey_file_name[MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME + 1] = "YOUR_DEVICE_NAME_private.key"; +#else +/* device secret of PSK device */ +static char sg_device_secret[MAX_SIZE_OF_DEVICE_SECRET + 1] = "yggBSwXfvg6zrxf+VU9+vQ=="; +#endif + +#ifdef GATEWAY_ENABLED +/* sub-device product id */ +static char sg_sub_device_product_id[MAX_SIZE_OF_PRODUCT_ID + 1] = "PRODUCT_ID"; +/* sub-device device name */ +static char sg_sub_device_name[MAX_SIZE_OF_DEVICE_NAME + 1] = "YOUR_SUB_DEV_NAME"; +#endif + +static int device_info_copy(void *pdst, void *psrc, uint8_t max_len) +{ + if (strlen(psrc) > max_len) { + return QCLOUD_ERR_FAILURE; + } + memset(pdst, '\0', max_len); + strncpy(pdst, psrc, max_len); + return QCLOUD_RET_SUCCESS; +} + +#endif + +int HAL_SetDevInfo(void *pdevInfo) +{ + POINTER_SANITY_CHECK(pdevInfo, QCLOUD_ERR_DEV_INFO); + int ret; + DeviceInfo *devInfo = (DeviceInfo *)pdevInfo; + +#ifdef DEBUG_DEV_INFO_USED + ret = device_info_copy(sg_product_id, devInfo->product_id, + MAX_SIZE_OF_PRODUCT_ID); // set product ID + ret |= device_info_copy(sg_device_name, devInfo->device_name, + MAX_SIZE_OF_DEVICE_NAME); // set dev name + +#ifdef AUTH_MODE_CERT + ret |= device_info_copy(sg_device_cert_file_name, devInfo->dev_cert_file_name, + MAX_SIZE_OF_DEVICE_CERT_FILE_NAME); // set dev cert file name + ret |= device_info_copy(sg_device_privatekey_file_name, devInfo->dev_key_file_name, + MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME); // set dev key file name +#else + ret |= device_info_copy(sg_device_secret, devInfo->device_secret, + MAX_SIZE_OF_DEVICE_SECRET); // set dev secret +#endif + +#else + Log_e("HAL_SetDevInfo not implement yet"); + ret = QCLOUD_ERR_DEV_INFO; +#endif + + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("Set device info err"); + ret = QCLOUD_ERR_DEV_INFO; + } + return ret; +} + +int HAL_GetDevInfo(void *pdevInfo) +{ + POINTER_SANITY_CHECK(pdevInfo, QCLOUD_ERR_DEV_INFO); + int ret; + DeviceInfo *devInfo = (DeviceInfo *)pdevInfo; + memset((char *)devInfo, '\0', sizeof(DeviceInfo)); + +#ifdef DEBUG_DEV_INFO_USED + ret = device_info_copy(devInfo->product_id, sg_product_id, + MAX_SIZE_OF_PRODUCT_ID); // get product ID + ret |= device_info_copy(devInfo->device_name, sg_device_name, + MAX_SIZE_OF_DEVICE_NAME); // get dev name + ret |= device_info_copy(devInfo->region, sg_region, + MAX_SIZE_OF_REGION); // get region + +#ifdef DEV_DYN_REG_ENABLED + ret |= device_info_copy(devInfo->product_secret, sg_product_secret, + MAX_SIZE_OF_PRODUCT_SECRET); // get product ID +#endif + +#ifdef AUTH_MODE_CERT + ret |= device_info_copy(devInfo->dev_cert_file_name, sg_device_cert_file_name, + MAX_SIZE_OF_DEVICE_CERT_FILE_NAME); // get dev cert file name + ret |= device_info_copy(devInfo->dev_key_file_name, sg_device_privatekey_file_name, + MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME); // get dev key file name +#else + ret |= device_info_copy(devInfo->device_secret, sg_device_secret, + MAX_SIZE_OF_DEVICE_SECRET); // get dev secret +#endif + +#else + Log_e("HAL_GetDevInfo not implement yet"); + ret = QCLOUD_ERR_DEV_INFO; +#endif + + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("Get device info err"); + ret = QCLOUD_ERR_DEV_INFO; + } + return ret; +} + +#ifdef GATEWAY_ENABLED +int HAL_GetGwDevInfo(void *pgwDeviceInfo) +{ + POINTER_SANITY_CHECK(pgwDeviceInfo, QCLOUD_ERR_DEV_INFO); + int ret; + GatewayDeviceInfo *gwDevInfo = (GatewayDeviceInfo *)pgwDeviceInfo; + memset((char *)gwDevInfo, 0, sizeof(GatewayDeviceInfo)); + +#ifdef DEBUG_DEV_INFO_USED + ret = HAL_GetDevInfo(&(gwDevInfo->gw_info)); // get gw dev info + // only one sub-device is supported now + gwDevInfo->sub_dev_num = 1; + gwDevInfo->sub_dev_info = (DeviceInfo *)HAL_Malloc(sizeof(DeviceInfo) * (gwDevInfo->sub_dev_num)); + memset((char *)gwDevInfo->sub_dev_info, '\0', sizeof(DeviceInfo)); + // copy sub dev info + ret = device_info_copy(gwDevInfo->sub_dev_info->product_id, sg_sub_device_product_id, MAX_SIZE_OF_PRODUCT_ID); + ret |= device_info_copy(gwDevInfo->sub_dev_info->device_name, sg_sub_device_name, MAX_SIZE_OF_DEVICE_NAME); + +#else + Log_e("HAL_GetDevInfo not implement yet"); + ret = QCLOUD_ERR_DEV_INFO; +#endif + + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("Get gateway device info err"); + ret = QCLOUD_ERR_DEV_INFO; + } + return ret; +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_OS_freertos.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_OS_freertos.c new file mode 100644 index 00000000..860f8729 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_OS_freertos.c @@ -0,0 +1,229 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ +#include +#include +#include + +#include "FreeRTOS.h" +#include "semphr.h" +#include "task.h" +#include "qcloud_iot_export_error.h" +#include "qcloud_iot_import.h" + +//#define PLATFORM_HAS_CMSIS + +#ifdef PLATFORM_HAS_CMSIS +#include "cmsis_os.h" +#include "stm32l4xx_hal.h" +#endif + +// TODO platform dependant +void HAL_SleepMs(_IN_ uint32_t ms) +{ + TickType_t ticks = ms / portTICK_PERIOD_MS; + + vTaskDelay(ticks ? ticks : 1); /* Minimum delay = 1 tick */ + + return; +} + +void HAL_Printf(_IN_ const char *fmt, ...) +{ + printf(fmt); +} + +int HAL_Snprintf(_IN_ char *str, const int len, const char *fmt, ...) +{ + va_list args; + int rc; + + va_start(args, fmt); + rc = vsnprintf(str, len, fmt, args); + va_end(args); + + return rc; +} + +int HAL_Vsnprintf(_IN_ char *str, _IN_ const int len, _IN_ const char *format, va_list ap) +{ + return vsnprintf(str, len, format, ap); +} + +void *HAL_Malloc(_IN_ uint32_t size) +{ + return pvPortMalloc(size); +} + +void HAL_Free(_IN_ void *ptr) +{ + if (ptr) + vPortFree(ptr); +} + +void *HAL_MutexCreate(void) +{ +#ifdef MULTITHREAD_ENABLED + SemaphoreHandle_t mutex = xSemaphoreCreateMutex(); + if (NULL == mutex) { + HAL_Printf("%s: xSemaphoreCreateMutex failed\n", __FUNCTION__); + return NULL; + } + + return mutex; +#else + return (void *)0xFFFFFFFF; +#endif +} + +void HAL_MutexDestroy(_IN_ void *mutex) +{ +#ifdef MULTITHREAD_ENABLED + if (xSemaphoreTake(mutex, 0) != pdTRUE) { + HAL_Printf("%s: xSemaphoreTake failed\n", __FUNCTION__); + } + + vSemaphoreDelete(mutex); +#else + return; +#endif +} + +void HAL_MutexLock(_IN_ void *mutex) +{ +#ifdef MULTITHREAD_ENABLED + if (!mutex) { + HAL_Printf("%s: invalid mutex\n", __FUNCTION__); + return; + } + + if (xSemaphoreTake(mutex, portMAX_DELAY) != pdTRUE) { + HAL_Printf("%s: xSemaphoreTake failed\n", __FUNCTION__); + return; + } +#else + return; +#endif +} + +int HAL_MutexTryLock(_IN_ void *mutex) +{ +#ifdef MULTITHREAD_ENABLED + if (!mutex) { + HAL_Printf("%s: invalid mutex\n", __FUNCTION__); + return -1; + } + + if (xSemaphoreTake(mutex, 0) != pdTRUE) { + HAL_Printf("%s: xSemaphoreTake failed\n", __FUNCTION__); + return -1; + } + + return 0; +#else + return 0; +#endif +} + +void HAL_MutexUnlock(_IN_ void *mutex) +{ +#ifdef MULTITHREAD_ENABLED + if (!mutex) { + HAL_Printf("%s: invalid mutex\n", __FUNCTION__); + return; + } + + if (xSemaphoreGive(mutex) != pdTRUE) { + HAL_Printf("%s: xSemaphoreGive failed\n", __FUNCTION__); + return; + } +#else + return; +#endif +} + +#ifdef MULTITHREAD_ENABLED + +// platform-dependant thread routine/entry function +static void _HAL_thread_func_wrapper_(void *ptr) +{ + ThreadParams *params = (ThreadParams *)ptr; + + params->thread_func(params->user_arg); + + vTaskDelete(NULL); +} + +// platform-dependant thread create function +int HAL_ThreadCreate(ThreadParams *params) +{ + if (params == NULL) + return QCLOUD_ERR_INVAL; + + if (params->thread_name == NULL) { + HAL_Printf("thread name is required for FreeRTOS platform!\n"); + return QCLOUD_ERR_INVAL; + } + + int ret = xTaskCreate(_HAL_thread_func_wrapper_, params->thread_name, params->stack_size, (void *)params, + params->priority, (void *)¶ms->thread_id); + if (ret != pdPASS) { + HAL_Printf("%s: xTaskCreate failed: %d\n", __FUNCTION__, ret); + return QCLOUD_ERR_FAILURE; + } + + return QCLOUD_RET_SUCCESS; +} + +#endif + +#if defined(PLATFORM_HAS_CMSIS) && defined(AT_TCP_ENABLED) + +void *HAL_SemaphoreCreate(void) +{ + return (void *)osSemaphoreCreate(NULL, 1); +} + +void HAL_SemaphoreDestroy(void *sem) +{ + osStatus ret; + + ret = osSemaphoreDelete((osSemaphoreId)sem); + if (osOK != ret) { + HAL_Printf("HAL_SemaphoreDestroy err, err:%d\n\r", ret); + } +} + +void HAL_SemaphorePost(void *sem) +{ + osStatus ret; + + ret = osSemaphoreRelease((osSemaphoreId)sem); + + if (osOK != ret) { + HAL_Printf("HAL_SemaphorePost err, err:%d\n\r", ret); + } +} + +int HAL_SemaphoreWait(void *sem, uint32_t timeout_ms) +{ + return osSemaphoreWait((osSemaphoreId)sem, timeout_ms); +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_TCP_lwip.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_TCP_lwip.c new file mode 100644 index 00000000..ed3e2d8c --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_TCP_lwip.c @@ -0,0 +1,271 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include + +#include "lwip/inet.h" +#include "lwip/netdb.h" +#include "lwip/sockets.h" +#include "qcloud_iot_common.h" +#include "qcloud_iot_export_error.h" +#include "qcloud_iot_export_log.h" +#include "qcloud_iot_import.h" + +/* lwIP socket handle start from 0 */ +#define LWIP_SOCKET_FD_SHIFT 3 + +static uint32_t _time_left(uint32_t t_end, uint32_t t_now) +{ + uint32_t t_left; + + if (t_end > t_now) { + t_left = t_end - t_now; + } else { + t_left = 0; + } + + return t_left; +} + +uintptr_t HAL_TCP_Connect(const char *host, uint16_t port) +{ + int ret; + struct addrinfo hints, *addr_list, *cur; + int fd = 0; + + char port_str[6]; + HAL_Snprintf(port_str, 6, "%d", port); + + memset(&hints, 0x00, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + ret = getaddrinfo(host, port_str, &hints, &addr_list); + if (ret) { + printf("getaddrinfo(%s:%s) error", STRING_PTR_PRINT_SANITY_CHECK(host), port_str); + return 0; + } + + for (cur = addr_list; cur != NULL; cur = cur->ai_next) { + fd = (int)socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol); + if (fd < 0) { + ret = 0; + continue; + } + + if (connect(fd, cur->ai_addr, cur->ai_addrlen) == 0) { + ret = fd + LWIP_SOCKET_FD_SHIFT; + break; + } + + close(fd); + ret = 0; + } + + if (ret == 0) { + Log_e("failed to connect with TCP server: %s:%s", STRING_PTR_PRINT_SANITY_CHECK(host), port_str); + } else { + /* reduce log print due to frequent log server connect/disconnect */ + if (strstr(host, LOG_UPLOAD_SERVER_PATTEN)) + UPLOAD_DBG("connected with TCP server: %s:%s", STRING_PTR_PRINT_SANITY_CHECK(host), port_str); + else + Log_i("connected with TCP server: %s:%s", STRING_PTR_PRINT_SANITY_CHECK(host), port_str); + } + + freeaddrinfo(addr_list); + + return (uintptr_t)ret; +} + +int HAL_TCP_Disconnect(uintptr_t fd) +{ + int rc; + + fd -= LWIP_SOCKET_FD_SHIFT; + + /* Shutdown both send and receive operations. */ + rc = shutdown((int)fd, 2); + if (0 != rc) { + Log_e("shutdown error: %s", STRING_PTR_PRINT_SANITY_CHECK(strerror(errno))); + return -1; + } + + rc = close((int)fd); + if (0 != rc) { + Log_e("closesocket error: %s", STRING_PTR_PRINT_SANITY_CHECK(strerror(errno))); + return -1; + } + + return 0; +} + +int HAL_TCP_Write(uintptr_t fd, const unsigned char *buf, uint32_t len, uint32_t timeout_ms, size_t *written_len) +{ + int ret; + uint32_t len_sent; + uint32_t t_end, t_left; + fd_set sets; + printf("HAL_TCP_Write\n"); + fd -= LWIP_SOCKET_FD_SHIFT; + + t_end = HAL_GetTimeMs() + timeout_ms; + len_sent = 0; + ret = 1; /* send one time if timeout_ms is value 0 */ + + do { + t_left = _time_left(t_end, HAL_GetTimeMs()); + + if (0 != t_left) { + struct timeval timeout; + + FD_ZERO(&sets); + FD_SET(fd, &sets); + + timeout.tv_sec = t_left / 1000; + timeout.tv_usec = (t_left % 1000) * 1000; + + ret = select(fd + 1, NULL, &sets, NULL, &timeout); + if (ret > 0) { + if (0 == FD_ISSET(fd, &sets)) { + Log_e("Should NOT arrive"); + /* If timeout in next loop, it will not sent any data */ + ret = 0; + continue; + } + } else if (0 == ret) { + ret = QCLOUD_ERR_TCP_WRITE_TIMEOUT; + Log_e("select-write timeout %d", (int)fd); + break; + } else { + if (EINTR == errno) { + Log_e("EINTR be caught"); + continue; + } + + ret = QCLOUD_ERR_TCP_WRITE_FAIL; + Log_e("select-write fail: %s", STRING_PTR_PRINT_SANITY_CHECK(strerror(errno))); + break; + } + } else { + ret = QCLOUD_ERR_TCP_WRITE_TIMEOUT; + } + + if (ret > 0) { + ret = send(fd, buf + len_sent, len - len_sent, 0); + if (ret > 0) { + len_sent += ret; + } else if (0 == ret) { + Log_e("No data be sent. Should NOT arrive"); + } else { + if (EINTR == errno) { + Log_e("EINTR be caught"); + continue; + } + + ret = QCLOUD_ERR_TCP_WRITE_FAIL; + Log_e("send fail: %s", STRING_PTR_PRINT_SANITY_CHECK(strerror(errno))); + break; + } + } + } while ((len_sent < len) && (_time_left(t_end, HAL_GetTimeMs()) > 0)); + + *written_len = (size_t)len_sent; + + return len_sent > 0 ? QCLOUD_RET_SUCCESS : ret; +} + +int HAL_TCP_Read(uintptr_t fd, unsigned char *buf, uint32_t len, uint32_t timeout_ms, size_t *read_len) +{ + int ret, err_code; + uint32_t len_recv; + uint32_t t_end, t_left; + fd_set sets; + struct timeval timeout; + + fd -= LWIP_SOCKET_FD_SHIFT; + t_end = HAL_GetTimeMs() + timeout_ms; + len_recv = 0; + err_code = 0; + + do { + t_left = _time_left(t_end, HAL_GetTimeMs()); + if (0 == t_left) { + err_code = QCLOUD_ERR_TCP_READ_TIMEOUT; + break; + } + + FD_ZERO(&sets); + FD_SET(fd, &sets); + + timeout.tv_sec = t_left / 1000; + timeout.tv_usec = (t_left % 1000) * 1000; + + ret = select(fd + 1, &sets, NULL, NULL, &timeout); + if (ret > 0) { + ret = recv(fd, buf + len_recv, len - len_recv, 0); + if (ret > 0) { + len_recv += ret; + } else if (0 == ret) { + struct sockaddr_in peer; + socklen_t sLen = sizeof(peer); + int peer_port = 0; + getpeername(fd, (struct sockaddr *)&peer, &sLen); + peer_port = ntohs(peer.sin_port); + + /* reduce log print due to frequent log server connect/disconnect */ + if (peer_port == LOG_UPLOAD_SERVER_PORT) + UPLOAD_DBG("connection is closed by server: %s:%d", + STRING_PTR_PRINT_SANITY_CHECK(inet_ntoa(peer.sin_addr)), peer_port); + else + Log_e("connection is closed by server: %s:%d", + STRING_PTR_PRINT_SANITY_CHECK(inet_ntoa(peer.sin_addr)), peer_port); + + err_code = QCLOUD_ERR_TCP_PEER_SHUTDOWN; + break; + } else { + if (EINTR == errno) { + Log_e("EINTR be caught"); + continue; + } + Log_e("recv error: %s", STRING_PTR_PRINT_SANITY_CHECK(strerror(errno))); + err_code = QCLOUD_ERR_TCP_READ_FAIL; + break; + } + } else if (0 == ret) { + err_code = QCLOUD_ERR_TCP_READ_TIMEOUT; + break; + } else { + Log_e("select-recv error: %s", STRING_PTR_PRINT_SANITY_CHECK(strerror(errno))); + err_code = QCLOUD_ERR_TCP_READ_FAIL; + break; + } + } while ((len_recv < len)); + + *read_len = (size_t)len_recv; + + if (err_code == QCLOUD_ERR_TCP_READ_TIMEOUT && len_recv == 0) + err_code = QCLOUD_ERR_TCP_NOTHING_TO_READ; + + return (len == len_recv) ? QCLOUD_RET_SUCCESS : err_code; +} diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_TLS_mbedtls.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_TLS_mbedtls.c new file mode 100644 index 00000000..5229b37b --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_TLS_mbedtls.c @@ -0,0 +1,408 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_import.h" + +#ifndef AUTH_WITH_NOTLS + +#include +#include +#include + +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/debug.h" +#include "mbedtls/entropy.h" +#include "mbedtls/error.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/ssl.h" +#include "qcloud_iot_export_error.h" +#include "qcloud_iot_export_log.h" +#include "qutils_param_check.h" +#include "qutils_timer.h" + +#ifndef AUTH_MODE_CERT +static const int ciphersuites[] = {MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, 0}; +#endif + +/** + * @brief data structure for mbedtls SSL connection + */ +typedef struct { + mbedtls_net_context socket_fd; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ssl; + mbedtls_ssl_config ssl_conf; + mbedtls_x509_crt ca_cert; + mbedtls_x509_crt client_cert; + mbedtls_pk_context private_key; +} TLSDataParams; + +/** + * @brief free memory/resources allocated by mbedtls + */ +static void _free_mebedtls(TLSDataParams *pParams) +{ + mbedtls_net_free(&(pParams->socket_fd)); + mbedtls_x509_crt_free(&(pParams->client_cert)); + mbedtls_x509_crt_free(&(pParams->ca_cert)); + mbedtls_pk_free(&(pParams->private_key)); + mbedtls_ssl_free(&(pParams->ssl)); + mbedtls_ssl_config_free(&(pParams->ssl_conf)); + mbedtls_ctr_drbg_free(&(pParams->ctr_drbg)); + mbedtls_entropy_free(&(pParams->entropy)); + + HAL_Free(pParams); +} + +#if defined(MBEDTLS_DEBUG_C) +#define DEBUG_LEVEL 0 +static void _ssl_debug(void *ctx, int level, const char *file, int line, const char *str) +{ + Log_i("[mbedTLS]:[%s]:[%d]: %s\r\n", STRING_PTR_PRINT_SANITY_CHECK(file), line, STRING_PTR_PRINT_SANITY_CHECK(str)); +} + +#endif + +/** + * @brief mbedtls SSL client init + * + * 1. call a series of mbedtls init functions + * 2. init and set seed for random functions + * 3. load CA file, cert files or PSK + * + * @param pDataParams mbedtls TLS parmaters + * @param pConnectParams device info for TLS connection + * @return QCLOUD_RET_SUCCESS when success, or err code for + * failure + */ +static int _mbedtls_client_init(TLSDataParams *pDataParams, TLSConnectParams *pConnectParams) +{ + int ret = QCLOUD_RET_SUCCESS; + + mbedtls_net_init(&(pDataParams->socket_fd)); + mbedtls_ssl_init(&(pDataParams->ssl)); + mbedtls_ssl_config_init(&(pDataParams->ssl_conf)); + mbedtls_ctr_drbg_init(&(pDataParams->ctr_drbg)); + mbedtls_x509_crt_init(&(pDataParams->ca_cert)); + mbedtls_x509_crt_init(&(pDataParams->client_cert)); + mbedtls_pk_init(&(pDataParams->private_key)); + + mbedtls_entropy_init(&(pDataParams->entropy)); + +#if defined(MBEDTLS_DEBUG_C) + mbedtls_debug_set_threshold(DEBUG_LEVEL); + mbedtls_ssl_conf_dbg(&pDataParams->ssl_conf, _ssl_debug, NULL); +#endif + + // custom parameter is NULL for now + if ((ret = mbedtls_ctr_drbg_seed(&(pDataParams->ctr_drbg), mbedtls_entropy_func, &(pDataParams->entropy), NULL, + 0)) != 0) { + Log_e("mbedtls_ctr_drbg_seed failed returned 0x%04x", ret < 0 ? -ret : ret); + return QCLOUD_ERR_SSL_INIT; + } + + if (pConnectParams->ca_crt != NULL) { + if ((ret = mbedtls_x509_crt_parse(&(pDataParams->ca_cert), (const unsigned char *)pConnectParams->ca_crt, + (pConnectParams->ca_crt_len + 1)))) { + Log_e("parse ca crt failed returned 0x%04x", ret < 0 ? -ret : ret); + return QCLOUD_ERR_SSL_CERT; + } + } + +#ifdef AUTH_MODE_CERT + if (pConnectParams->cert_file != NULL && pConnectParams->key_file != NULL) { + if ((ret = mbedtls_x509_crt_parse_file(&(pDataParams->client_cert), pConnectParams->cert_file)) != 0) { + Log_e("load client cert file failed returned 0x%x", ret < 0 ? -ret : ret); + return QCLOUD_ERR_SSL_CERT; + } + + if ((ret = mbedtls_pk_parse_keyfile(&(pDataParams->private_key), pConnectParams->key_file, "")) != 0) { + Log_e("load client key file failed returned 0x%x", ret < 0 ? -ret : ret); + return QCLOUD_ERR_SSL_CERT; + } + } else { + Log_d("cert_file/key_file is empty!|cert_file=%s|key_file=%s", + STRING_PTR_PRINT_SANITY_CHECK(pConnectParams->cert_file), + STRING_PTR_PRINT_SANITY_CHECK(pConnectParams->key_file)); + } +#else + if (pConnectParams->psk != NULL && pConnectParams->psk_id != NULL) { + const char *psk_id = pConnectParams->psk_id; + ret = mbedtls_ssl_conf_psk(&(pDataParams->ssl_conf), (unsigned char *)pConnectParams->psk, + pConnectParams->psk_length, (const unsigned char *)psk_id, strlen(psk_id)); + } else { + Log_d("psk/pskid is empty!"); + } + + if (0 != ret) { + Log_e("mbedtls_ssl_conf_psk fail: 0x%x", ret < 0 ? -ret : ret); + return ret; + } +#endif + + return QCLOUD_RET_SUCCESS; +} + +/** + * @brief Setup TCP connection + * + * @param socket_fd socket handle + * @param host server address + * @param port server port + * @return QCLOUD_RET_SUCCESS when success, or err code for failure + */ +int _mbedtls_tcp_connect(mbedtls_net_context *socket_fd, const char *host, int port) +{ + int ret = 0; + char port_str[6]; + HAL_Snprintf(port_str, 6, "%d", port); + if ((ret = mbedtls_net_connect(socket_fd, host, port_str, MBEDTLS_NET_PROTO_TCP)) != 0) { + Log_e("tcp connect failed returned 0x%04x errno: %d", ret < 0 ? -ret : ret, errno); + + switch (ret) { + case MBEDTLS_ERR_NET_SOCKET_FAILED: + return QCLOUD_ERR_TCP_SOCKET_FAILED; + case MBEDTLS_ERR_NET_UNKNOWN_HOST: + return QCLOUD_ERR_TCP_UNKNOWN_HOST; + default: + return QCLOUD_ERR_TCP_CONNECT; + } + } + + if ((ret = mbedtls_net_set_block(socket_fd)) != 0) { + Log_e("set block faliled returned 0x%04x", ret < 0 ? -ret : ret); + return QCLOUD_ERR_TCP_CONNECT; + } + + return QCLOUD_RET_SUCCESS; +} + +/** + * @brief verify server certificate + * + * mbedtls has provided similar function mbedtls_x509_crt_verify_with_profile + * + * @return + */ +int _qcloud_server_certificate_verify(void *hostname, mbedtls_x509_crt *crt, int depth, uint32_t *flags) +{ + return *flags; +} + +uintptr_t HAL_TLS_Connect(TLSConnectParams *pConnectParams, const char *host, int port) +{ + int ret = 0; + + TLSDataParams *pDataParams = (TLSDataParams *)HAL_Malloc(sizeof(TLSDataParams)); + + if ((ret = _mbedtls_client_init(pDataParams, pConnectParams)) != QCLOUD_RET_SUCCESS) { + goto error; + } + + Log_d("Setting up the SSL/TLS structure..."); + if ((ret = mbedtls_ssl_config_defaults(&(pDataParams->ssl_conf), MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + Log_e("mbedtls_ssl_config_defaults failed returned 0x%04x", ret < 0 ? -ret : ret); + goto error; + } + + mbedtls_ssl_conf_verify(&(pDataParams->ssl_conf), _qcloud_server_certificate_verify, (void *)host); + + mbedtls_ssl_conf_authmode(&(pDataParams->ssl_conf), MBEDTLS_SSL_VERIFY_REQUIRED); + + mbedtls_ssl_conf_rng(&(pDataParams->ssl_conf), mbedtls_ctr_drbg_random, &(pDataParams->ctr_drbg)); + + mbedtls_ssl_conf_ca_chain(&(pDataParams->ssl_conf), &(pDataParams->ca_cert), NULL); + if ((ret = mbedtls_ssl_conf_own_cert(&(pDataParams->ssl_conf), &(pDataParams->client_cert), + &(pDataParams->private_key))) != 0) { + Log_e("mbedtls_ssl_conf_own_cert failed returned 0x%04x", ret < 0 ? -ret : ret); + goto error; + } + + mbedtls_ssl_conf_read_timeout(&(pDataParams->ssl_conf), pConnectParams->timeout_ms); + if ((ret = mbedtls_ssl_setup(&(pDataParams->ssl), &(pDataParams->ssl_conf))) != 0) { + Log_e("mbedtls_ssl_setup failed returned 0x%04x", ret < 0 ? -ret : ret); + goto error; + } + +#ifndef AUTH_MODE_CERT + // ciphersuites selection for PSK device + if (pConnectParams->psk != NULL) { + mbedtls_ssl_conf_ciphersuites(&(pDataParams->ssl_conf), ciphersuites); + } +#endif + + // Set the hostname to check against the received server certificate and sni + if ((ret = mbedtls_ssl_set_hostname(&(pDataParams->ssl), host)) != 0) { + Log_e("mbedtls_ssl_set_hostname failed returned 0x%04x", ret < 0 ? -ret : ret); + goto error; + } + + mbedtls_ssl_set_bio(&(pDataParams->ssl), &(pDataParams->socket_fd), mbedtls_net_send, mbedtls_net_recv, + mbedtls_net_recv_timeout); + + Log_d("Performing the SSL/TLS handshake..."); + Log_d("Connecting to /%s/%d...", STRING_PTR_PRINT_SANITY_CHECK(host), port); + if ((ret = _mbedtls_tcp_connect(&(pDataParams->socket_fd), host, port)) != QCLOUD_RET_SUCCESS) { + goto error; + } + + while ((ret = mbedtls_ssl_handshake(&(pDataParams->ssl))) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + Log_e("mbedtls_ssl_handshake failed returned 0x%04x", ret < 0 ? -ret : ret); + if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { + Log_e("Unable to verify the server's certificate"); + } + goto error; + } + } + + if ((ret = mbedtls_ssl_get_verify_result(&(pDataParams->ssl))) != 0) { + Log_e("mbedtls_ssl_get_verify_result failed returned 0x%04x", ret < 0 ? -ret : ret); + goto error; + } + + mbedtls_ssl_conf_read_timeout(&(pDataParams->ssl_conf), 100); + + Log_d("connected with /%s/%d...", STRING_PTR_PRINT_SANITY_CHECK(host), port); + + return (uintptr_t)pDataParams; + +error: + _free_mebedtls(pDataParams); + return 0; +} + +void HAL_TLS_Disconnect(uintptr_t handle) +{ + if ((uintptr_t)NULL == handle) { + Log_d("handle is NULL"); + return; + } + TLSDataParams *pParams = (TLSDataParams *)handle; + int ret = 0; + do { + ret = mbedtls_ssl_close_notify(&(pParams->ssl)); + } while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE); + + mbedtls_net_free(&(pParams->socket_fd)); + mbedtls_x509_crt_free(&(pParams->client_cert)); + mbedtls_x509_crt_free(&(pParams->ca_cert)); + mbedtls_pk_free(&(pParams->private_key)); + mbedtls_ssl_free(&(pParams->ssl)); + mbedtls_ssl_config_free(&(pParams->ssl_conf)); + mbedtls_ctr_drbg_free(&(pParams->ctr_drbg)); + mbedtls_entropy_free(&(pParams->entropy)); + + HAL_Free((void *)handle); +} + +int HAL_TLS_Write(uintptr_t handle, unsigned char *msg, size_t totalLen, uint32_t timeout_ms, size_t *written_len) +{ + + Timer timer; + InitTimer(&timer); + countdown_ms(&timer, (unsigned int)timeout_ms); + size_t written_so_far; + bool errorFlag = false; + int write_rc = 0; + + TLSDataParams *pParams = (TLSDataParams *)handle; + + for (written_so_far = 0; written_so_far < totalLen && !expired(&timer); written_so_far += write_rc) { + while (!expired(&timer) && + (write_rc = mbedtls_ssl_write(&(pParams->ssl), msg + written_so_far, totalLen - written_so_far)) <= 0) { + if (write_rc != MBEDTLS_ERR_SSL_WANT_READ && write_rc != MBEDTLS_ERR_SSL_WANT_WRITE) { + printf("HAL_TLS_write failed 0x%04x", write_rc < 0 ? -write_rc : write_rc); + errorFlag = true; + break; + } + } + + if (errorFlag) { + break; + } + } + + *written_len = written_so_far; + + if (errorFlag) { + printf("QCLOUD_ERR_SSL_WRITE"); + return QCLOUD_ERR_SSL_WRITE; + + } else if (expired(&timer) && written_so_far != totalLen) { + printf("QCLOUD_ERR_SSL_WRITE_TIMEOUT"); + return QCLOUD_ERR_SSL_WRITE_TIMEOUT; + } + + return QCLOUD_RET_SUCCESS; +} + +int HAL_TLS_Read(uintptr_t handle, unsigned char *msg, size_t totalLen, uint32_t timeout_ms, size_t *read_len) +{ + // mbedtls_ssl_conf_read_timeout(&(pParams->ssl_conf), timeout_ms); TODO:this + // cause read blocking and no return even timeout + // use non-blocking read + Timer timer; + InitTimer(&timer); + countdown_ms(&timer, (unsigned int)timeout_ms); + *read_len = 0; + + TLSDataParams *pParams = (TLSDataParams *)handle; + + do { + int read_rc = 0; + read_rc = mbedtls_ssl_read(&(pParams->ssl), msg + *read_len, totalLen - *read_len); + + if (read_rc > 0) { + *read_len += read_rc; + } else if (read_rc == 0 || (read_rc != MBEDTLS_ERR_SSL_WANT_WRITE && read_rc != MBEDTLS_ERR_SSL_WANT_READ && + read_rc != MBEDTLS_ERR_SSL_TIMEOUT)) { + Log_e("cloud_iot_network_tls_read failed: 0x%04x", read_rc < 0 ? -read_rc : read_rc); + return QCLOUD_ERR_SSL_READ; + } + + if (expired(&timer)) { + break; + } + + } while (*read_len < totalLen); + + if (totalLen == *read_len) { + return QCLOUD_RET_SUCCESS; + } + + if (*read_len == 0) { + return QCLOUD_ERR_SSL_NOTHING_TO_READ; + } else { + return QCLOUD_ERR_SSL_READ_TIMEOUT; + } +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_Timer_freertos.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_Timer_freertos.c new file mode 100644 index 00000000..d11aa666 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_Timer_freertos.c @@ -0,0 +1,120 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "qcloud_iot_import.h" + +//#define PLATFORM_HAS_TIME_FUNCS +//#define PLATFORM_HAS_CMSIS + +#ifdef PLATFORM_HAS_TIME_FUNCS +#include +#include +#endif + +#ifdef PLATFORM_HAS_CMSIS +#include "cmsis_os.h" +#include "stm32l4xx_hal.h" +#endif + +uint32_t HAL_GetTimeMs(void) +{ + +#if defined PLATFORM_HAS_TIME_FUNCS + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; + +#else + return xTaskGetTickCount(); +#endif + + +} + +/*Get timestamp*/ +long HAL_Timer_current_sec(void) +{ + return HAL_GetTimeMs() / 1000; +} + +char *HAL_Timer_current(char *time_str) +{ +#if defined PLATFORM_HAS_TIME_FUNCS + struct timeval tv; + gettimeofday(&tv, NULL); + time_t now_time = tv.tv_sec; + struct tm tm_tmp = *localtime(&now_time); + strftime(time_str, TIME_FORMAT_STR_LEN, "%F %T", &tm_tmp); + return time_str; +#else + long time_sec; + time_sec = HAL_Timer_current_sec(); + memset(time_str, 0, TIME_FORMAT_STR_LEN); + snprintf(time_str, TIME_FORMAT_STR_LEN, "%ld", time_sec); + return time_str; +#endif +} + +bool HAL_Timer_expired(Timer *timer) +{ + uint32_t now_ts; + + now_ts = HAL_GetTimeMs(); + + return (now_ts > timer->end_time) ? true : false; +} + +void HAL_Timer_countdown_ms(Timer *timer, unsigned int timeout_ms) +{ + timer->end_time = HAL_GetTimeMs(); + timer->end_time += timeout_ms; +} + +void HAL_Timer_countdown(Timer *timer, unsigned int timeout) +{ + timer->end_time = HAL_GetTimeMs(); + timer->end_time += timeout * 1000; +} + +int HAL_Timer_remain(Timer *timer) +{ + return (int)(timer->end_time - HAL_GetTimeMs()); +} + +void HAL_Timer_init(Timer *timer) +{ + timer->end_time = 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_UDP_lwip.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_UDP_lwip.c new file mode 100644 index 00000000..d9c98880 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/platform/HAL_UDP_lwip.c @@ -0,0 +1,166 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#include "lwip/inet.h" +#include "lwip/netdb.h" +#include "lwip/sockets.h" +#include "qcloud_iot_export_error.h" +#include "qcloud_iot_export_log.h" +#include "qcloud_iot_import.h" + +#ifdef COAP_COMM_ENABLED + +/* lwIP socket handle start from 0 */ +#define LWIP_SOCKET_FD_SHIFT 3 + +uintptr_t HAL_UDP_Connect(const char *host, unsigned short port) +{ +#define NETWORK_ADDR_LEN (16) + + int ret; + struct addrinfo hints, *addr_list, *cur; + int fd = 0; + + char port_str[6] = {0}; + HAL_Snprintf(port_str, 6, "%d", port); + + memset((char *)&hints, 0x00, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_family = AF_INET; + hints.ai_protocol = IPPROTO_UDP; + + Log_d("establish tcp connection with server(host=%s port=%s)", STRING_PTR_PRINT_SANITY_CHECK(host), port_str); + + if (getaddrinfo(host, port_str, &hints, &addr_list) != 0) { + Log_e("getaddrinfo error,errno:%s", STRING_PTR_PRINT_SANITY_CHECK(strerror(errno))); + return 0; + } + + for (cur = addr_list; cur != NULL; cur = cur->ai_next) { + fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol); + if (fd < 0) { + ret = 0; + continue; + } + + if (0 == connect(fd, cur->ai_addr, cur->ai_addrlen)) { + ret = fd + LWIP_SOCKET_FD_SHIFT; + break; + } + + close(fd); + ret = 0; + } + + if (0 == ret) { + Log_e("fail to establish udp"); + } else { + Log_d("success to establish udp, fd=%d", ret); + } + + freeaddrinfo(addr_list); + + return (uintptr_t)ret; + +#undef NETWORK_ADDR_LEN +} + +void HAL_UDP_Disconnect(uintptr_t fd) +{ + long socket_id = -1; + fd -= LWIP_SOCKET_FD_SHIFT; + + socket_id = (int)fd; + close(socket_id); +} + +int HAL_UDP_Write(uintptr_t fd, const unsigned char *p_data, unsigned int datalen) +{ + int rc = -1; + long socket_id = -1; + fd -= LWIP_SOCKET_FD_SHIFT; + + socket_id = (int)fd; + rc = send(socket_id, (char *)p_data, (int)datalen, 0); + if (-1 == rc) { + return -1; + } + + return rc; +} + +int HAL_UDP_Read(uintptr_t fd, unsigned char *p_data, unsigned int datalen) +{ + long socket_id = -1; + int count = -1; + fd -= LWIP_SOCKET_FD_SHIFT; + + socket_id = (int)fd; + count = (int)read(socket_id, p_data, datalen); + + return count; +} + +int HAL_UDP_ReadTimeout(uintptr_t fd, unsigned char *p_data, unsigned int datalen, unsigned int timeout_ms) +{ + int ret; + struct timeval tv; + fd_set read_fds; + int socket_id = -1; + fd -= LWIP_SOCKET_FD_SHIFT; + + socket_id = (int)fd; + + if (socket_id < 0) { + return -1; + } + + FD_ZERO(&read_fds); + FD_SET(socket_id, &read_fds); + + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; + + ret = select(socket_id + 1, &read_fds, NULL, NULL, timeout_ms == 0 ? NULL : &tv); + + /* Zero fds ready means we timed out */ + if (ret == 0) { + return QCLOUD_ERR_SSL_READ_TIMEOUT; /* receive timeout */ + } + + if (ret < 0) { + if (errno == EINTR) { + return -3; /* want read */ + } + + return QCLOUD_ERR_SSL_READ; /* receive failed */ + } + + /* This call will not block */ + return HAL_UDP_Read(fd, p_data, datalen); +} + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/asr_client.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/asr_client.c new file mode 100644 index 00000000..ec137c2b --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/asr_client.c @@ -0,0 +1,851 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include "qcloud_iot_export.h" +#include "qutils_param_check.h" +#include "qutils_timer.h" +#include "qutils_list.h" +#include "json_parser.h" +#include "asr_client.h" + +#define RESOURCE_TOKEN "resource_token" +#define REQUEST_ID "request_id" +#define KEY_ASR_RESULT "result_code" +#define KEY_ASR_TOKEN "resource_token" +#define KEY_ASR_TEXT_SEGS "total_num" +#define KEY_ASR_TEXT_SEQ "seq" +#define KEY_ASR_TEXT "res_text" +#define ONE_PARA_STR_LEN (25) + +#define ASR_RESPONSE_PROPERTY_KEY "_sys_asr_response" +#define ASR_SYS_PROPERTY_BUFFF_LEN 2048 +#define TOTAL_ASR_SYS_PROPERTY_COUNT 1 + +typedef struct _AsrHandle_ { + void * resource_handle; + OnAsrResourceEventUsrCallback usrCb; + void * mutex; + List * asr_req_list; +} AsrHandle; + +typedef struct _AsrReq_ { + eAsrType req_type; + int request_id; + + Timer timer; + uint32_t request_timeout_ms; + OnAsrResultCB result_cb; + char * asr_token; + union { + RecordAsrConf record_conf; + RealTimeAsrConf realtime_conf; + }; +} AsrReq; + +typedef struct _ASR_SYS_PROPERTY { + TYPE_DEF_TEMPLATE_STRING m_asr_response[ASR_SYS_PROPERTY_BUFFF_LEN + 1]; +} ASR_SYS_PROPERTY; + +static ASR_SYS_PROPERTY sg_asr_property; +static sDataPoint sg_asr_data[TOTAL_ASR_SYS_PROPERTY_COUNT]; +static void *sg_asr_client = NULL; + +int _asr_result_notify(void *handle, char *asr_response); + +static void _init_asr_property() +{ + sg_asr_property.m_asr_response[0] = '\0'; + sg_asr_data[0].data_property.data = sg_asr_property.m_asr_response; + sg_asr_data[0].data_property.data_buff_len = ASR_SYS_PROPERTY_BUFFF_LEN; + sg_asr_data[0].data_property.key = ASR_RESPONSE_PROPERTY_KEY; + sg_asr_data[0].data_property.type = TYPE_TEMPLATE_STRING; + sg_asr_data[0].state = eNOCHANGE; +}; + +static void _OnAsrControlMsgCallback(void *pTemplate_client, const char *pJsonValueBuffer, uint32_t valueLength, + DeviceProperty *pProperty) +{ + if(!strcmp(pProperty->key, ASR_RESPONSE_PROPERTY_KEY)) { + LITE_string_strip_char((char *)pProperty->data, '\\'); + int rc = _asr_result_notify(sg_asr_client, (char *)pProperty->data); + if(QCLOUD_RET_SUCCESS != rc) { + Log_e("asr result notify fail, err:%d", rc); + } + } +} + +static int _register_asr_property(void *pTemplate_client) +{ + int i, rc; + + _init_asr_property(); + for (i = 0; i < TOTAL_ASR_SYS_PROPERTY_COUNT; i++) { + rc = IOT_Template_Register_Property(pTemplate_client, &sg_asr_data[i].data_property, _OnAsrControlMsgCallback); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + } + + return QCLOUD_RET_SUCCESS; +} + +static char *_engine_type_to_str(eAsrEngineType eType) +{ + char *type; + switch (eType) { + case eENGINE_8K_EN: + type = "8k_en"; + break; + + case eENGINE_8K_ZH: + type = "8k_zh"; + break; + + case eENGINE_8K_ZH_S: + type = "8k_zh_s"; + break; + + case eENGINE_16K_ZH_VIDEO: + type = "16k_zh_video"; + break; + + case eENGINE_16K_EN: + type = "16k_en"; + break; + + case eENGINE_16K_CA: + type = "16k_ca"; + break; + + case eENGINE_16K_JA: + type = "16k_ja"; + break; + + case eENGINE_16K_WUU_SH: + type = "6k_wuu-SH"; + break; + + case eENGINE_16K_ZH: + default: + type = "16k_zh"; + break; + } + + return type; +} + +static int _gen_record_asr_request_msg(char *msg_buff, int len, AsrReq *req) +{ + int ret, remain_size; + POINTER_SANITY_CHECK(msg_buff, QCLOUD_ERR_INVAL); + // required parameters + memset(msg_buff, 0, len); + ret = HAL_Snprintf(msg_buff, len, + "{\"method\":\"request_asr\",\"params\":{\"req_type\":%d," + "\"engine_type\":\"%s\",\"channel_num\":%d,\"resource_token\":\"%s\",", + req->req_type, _engine_type_to_str(req->record_conf.engine_type), req->record_conf.ch_num, + STRING_PTR_PRINT_SANITY_CHECK(req->asr_token)); + + // option parameters + if (req->record_conf.speaker_diarization) { + if ((remain_size = len - strlen(msg_buff)) < 2 * ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = + HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"speaker_diarization\":%d,\"speaker_number\":%d,", + req->record_conf.speaker_diarization, req->record_conf.speaker_number); + } + + if (req->record_conf.filter_dirty) { + if ((remain_size = len - strlen(msg_buff)) < ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"filter_dirty\":%d,", + req->record_conf.filter_dirty); + } + + if (req->record_conf.filter_modal) { + if ((remain_size = len - strlen(msg_buff)) < ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"filter_modal\":%d,", + req->record_conf.filter_modal); + } + + if (req->record_conf.filter_punc) { + if ((remain_size = len - strlen(msg_buff)) < ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = + HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"filter_punc\":%d,", req->record_conf.filter_punc); + } + + if (req->record_conf.convert_num_mode) { + if ((remain_size = len - strlen(msg_buff)) < ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"convert_num_mode\":%d,", + req->record_conf.convert_num_mode); + } + + if (req->record_conf.hot_word_id) { + if ((remain_size = len - strlen(msg_buff)) < 2 * ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"hot_word_id\":\"%s\",", + req->record_conf.hot_word_id); + } + + if ((remain_size = len - strlen(msg_buff)) < 2) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff) - 1, remain_size, "}}"); + + return ret; +} + +static int _gen_realtime_asr_request_msg(char *msg_buff, int len, AsrReq *req) +{ + int ret, remain_size; + POINTER_SANITY_CHECK(msg_buff, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(req, QCLOUD_ERR_INVAL); + memset(msg_buff, 0, len); + // required parameters + ret = HAL_Snprintf(msg_buff, len, + "{\"method\":\"request_asr\",\"params\":{\"req_type\":%d," + "\"engine_type\":\"%s\",\"res_type\":%d,\"voice_format\":%d," + "\"seq\":%d,\"end\":%d,\"voice_id\":\"%s\",\"resource_token\":\"%s\",", + req->req_type, _engine_type_to_str(req->realtime_conf.engine_type), req->realtime_conf.res_type, + req->realtime_conf.voice_format, req->realtime_conf.seq, req->realtime_conf.end, + STRING_PTR_PRINT_SANITY_CHECK(req->realtime_conf.voice_id), + STRING_PTR_PRINT_SANITY_CHECK(req->asr_token)); + + // option parameters + if (req->realtime_conf.need_vad) { + if ((remain_size = len - strlen(msg_buff)) < 2 * ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"need_vad\":%d,\"vad_silence_time\":%d,", + req->realtime_conf.need_vad, req->realtime_conf.vad_silence_time); + } + + if (req->realtime_conf.filter_dirty) { + if ((remain_size = len - strlen(msg_buff)) < ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"filter_dirty\":%d,", + req->realtime_conf.filter_dirty); + } + + if (req->realtime_conf.filter_modal) { + if ((remain_size = len - strlen(msg_buff)) < ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"filter_modal\":%d,", + req->realtime_conf.filter_modal); + } + + if (req->realtime_conf.filter_punc) { + if ((remain_size = len - strlen(msg_buff)) < ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"filter_punc\":%d,", + req->realtime_conf.filter_punc); + } + + if (req->realtime_conf.convert_num_mode) { + if ((remain_size = len - strlen(msg_buff)) < ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"convert_num_mode\":%d,", + req->realtime_conf.convert_num_mode); + } + + if (req->realtime_conf.hot_word_id) { + if ((remain_size = len - strlen(msg_buff)) < 2 * ONE_PARA_STR_LEN) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff), remain_size, "\"hot_word_id\":\"%s\",", + req->realtime_conf.hot_word_id); + } + + if ((remain_size = len - strlen(msg_buff)) < 2) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + ret = HAL_Snprintf(msg_buff + strlen(msg_buff) - 1, remain_size, "}}"); + + return ret; +} + +static int _add_request_to_asr_req_list(AsrHandle *pAsrClient, AsrReq *request) +{ + IOT_FUNC_ENTRY; + + HAL_MutexLock(pAsrClient->mutex); + if (pAsrClient->asr_req_list->len >= MAX_ASR_REQUEST) { + HAL_MutexUnlock(pAsrClient->mutex); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_APPENDING_REQUEST); + } + ListNode *node = list_node_new(request); + if (NULL == node) { + HAL_MutexUnlock(pAsrClient->mutex); + Log_e("run list_node_new is error!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + list_rpush(pAsrClient->asr_req_list, node); + HAL_MutexUnlock(pAsrClient->mutex); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +static AsrReq *_get_req_node_by_request_id(AsrHandle *pAsrClient, uint32_t request_id) +{ + POINTER_SANITY_CHECK(pAsrClient, NULL); + AsrReq *req = NULL; + HAL_MutexLock(pAsrClient->mutex); + if (pAsrClient->asr_req_list->len) { + ListIterator *iter; + ListNode * node = NULL; + + if (NULL == (iter = list_iterator_new(pAsrClient->asr_req_list, LIST_TAIL))) { + HAL_MutexUnlock(pAsrClient->mutex); + return NULL; + } + + for (;;) { + node = list_iterator_next(iter); + if (NULL == node) { + break; + } + + if (NULL == node->val) { + Log_e("node's value is invalid!"); + list_remove(pAsrClient->asr_req_list, node); + continue; + } + req = (AsrReq *)node->val; + if (req->request_id == request_id) { + break; + } else { + if (expired(&req->timer)) { + Log_e("%d timeout removed from list", req->request_id); + list_remove(pAsrClient->asr_req_list, node); + } + req = NULL; + } + } + + list_iterator_destroy(iter); + } + HAL_MutexUnlock(pAsrClient->mutex); + + return req; +} + +static AsrReq *_get_req_node_by_asr_token(AsrHandle *pAsrClient, const char *asr_token) +{ + POINTER_SANITY_CHECK(pAsrClient, NULL); + AsrReq *req = NULL; + HAL_MutexLock(pAsrClient->mutex); + if (pAsrClient->asr_req_list->len) { + ListIterator *iter; + ListNode * node = NULL; + + if (NULL == (iter = list_iterator_new(pAsrClient->asr_req_list, LIST_TAIL))) { + HAL_MutexUnlock(pAsrClient->mutex); + return NULL; + } + + for (;;) { + node = list_iterator_next(iter); + if (NULL == node) { + break; + } + + if (NULL == node->val) { + Log_e("node's value is invalid!"); + list_remove(pAsrClient->asr_req_list, node); + continue; + } + req = (AsrReq *)node->val; + if (req->asr_token) { + if (!strcmp(req->asr_token, asr_token)) { + break; + } + } else { + if (expired(&req->timer)) { + Log_e("%d timeout removed from list", req->request_id); + list_remove(pAsrClient->asr_req_list, node); + } + req = NULL; + } + } + + list_iterator_destroy(iter); + } + HAL_MutexUnlock(pAsrClient->mutex); + + return req; +} + +static void _del_timeout_req_node(AsrHandle *pAsrClient) +{ + POINTER_SANITY_CHECK_RTN(pAsrClient); + AsrReq *req = NULL; + HAL_MutexLock(pAsrClient->mutex); + if (pAsrClient->asr_req_list->len) { + ListIterator *iter; + ListNode * node = NULL; + + if (NULL == (iter = list_iterator_new(pAsrClient->asr_req_list, LIST_TAIL))) { + HAL_MutexUnlock(pAsrClient->mutex); + return; + } + + for (;;) { + node = list_iterator_next(iter); + if (NULL == node) { + break; + } + + if (NULL == node->val) { + Log_e("node's value is invalid!"); + list_remove(pAsrClient->asr_req_list, node); + continue; + } + req = (AsrReq *)node->val; + if (expired(&req->timer)) { + Log_e("%d timeout removed from list", req->request_id); + if (req->req_type == eASR_REALTIME) { + Log_d("remove file %s", req->realtime_conf.file_name); + HAL_FileRemove(req->realtime_conf.file_name); + } + list_remove(pAsrClient->asr_req_list, node); + } + } + + list_iterator_destroy(iter); + } + HAL_MutexUnlock(pAsrClient->mutex); +} + +int _asr_result_notify(void *handle, char *asr_response) +{ + POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(asr_response, QCLOUD_ERR_INVAL); + + AsrHandle *asr_handle = (AsrHandle *)handle; + int rc = QCLOUD_RET_SUCCESS; + char * str_result = NULL; + char * asr_token = NULL; + char * str_num = NULL; + char * str_seq = NULL; + char * asr_txt = NULL; + + Log_d("asr_response:%s", asr_response); + str_result = LITE_json_value_of(KEY_ASR_RESULT, asr_response); + asr_token = LITE_json_value_of(KEY_ASR_TOKEN, asr_response); + if (!str_result || !asr_token) { + Log_e("required result key not found in asr_response:%s", asr_response); + rc = QCLOUD_ERR_JSON_PARSE; + goto exit; + } + AsrReq *req = _get_req_node_by_asr_token(asr_handle, asr_token); + if(!req){ + Log_e("asr_token: %s not found", asr_token); + rc = QCLOUD_ERR_FAILURE; + goto exit; + } + + rc = atoi(str_result); + if (QCLOUD_RET_SUCCESS == rc) { + str_num = LITE_json_value_of(KEY_ASR_TEXT_SEGS, asr_response); + str_seq = LITE_json_value_of(KEY_ASR_TEXT_SEQ, asr_response); + if (!str_num || !str_seq) { + Log_e("required text key not found in asr_response"); + rc = QCLOUD_ERR_JSON_PARSE; + goto exit; + } + + int num = atoi(str_num); + int seq = atoi(str_seq); + if (req->result_cb) { + asr_txt = LITE_json_value_of(KEY_ASR_TEXT, asr_response); + if (!asr_txt) { + req->result_cb(req->request_id, "NULL", num, seq); + } else { + req->result_cb(req->request_id, asr_txt, num, seq); + } + } + + if ((num == seq) || (num < 2)) { + if (req->asr_token) { + HAL_Free(req->asr_token); + } + HAL_MutexLock(asr_handle->mutex); + list_remove(asr_handle->asr_req_list, list_find(asr_handle->asr_req_list, req)); + HAL_MutexUnlock(asr_handle->mutex); + } + } else { + Log_e("%s request asr result fail:%d", asr_token, rc); + if (req->asr_token) { + HAL_Free(req->asr_token); + } + HAL_MutexLock(asr_handle->mutex); + list_remove(asr_handle->asr_req_list, list_find(asr_handle->asr_req_list, req)); + HAL_MutexUnlock(asr_handle->mutex); + } + +exit: + + if (str_result) { + HAL_Free(str_result); + } + + if (asr_token) { + HAL_Free(asr_token); + } + + if (str_num) { + HAL_Free(str_num); + } + + if (str_seq) { + HAL_Free(str_seq); + } + + if (asr_txt) { + HAL_Free(asr_txt); + } + + return rc; +} + +int _request_asr_resource_result(void *handle, AsrReq *req) +{ + char asr_request_buff[ASR_REQUEST_BUFF_LEN]; + int ret = 0; + + if (eASR_REALTIME == req->req_type) { + ret = _gen_realtime_asr_request_msg(asr_request_buff, ASR_REQUEST_BUFF_LEN, req); + } else { + ret = _gen_record_asr_request_msg(asr_request_buff, ASR_REQUEST_BUFF_LEN, req); + } + + if (ret < 0) { + Log_e("generate asr request message failed"); + return ret; + } + Log_d("%s", asr_request_buff); + ret = IOT_Resource_Report_Msg(handle, asr_request_buff); + + return ret; +} + +static int _asr_resource_event_usr_cb(void *pContext, const char *msg, uint32_t msgLen, IOT_RES_UsrEvent event) +{ + int ret = QCLOUD_RET_SUCCESS; + + AsrHandle *asr_handle = (AsrHandle *)pContext; + char * json_str = (char *)msg; + char * request_id; + AsrReq * req; + int id; + + Log_d("event(%d) msg:%*s", event, msgLen, msg); + switch (event) { + case IOT_RES_EVENT_REQUEST_URL_RESP: + request_id = LITE_json_value_of(REQUEST_ID, json_str); + if (!request_id) { + Log_e("no request_id found"); + goto exit; + } + id = atoi(request_id); + req = _get_req_node_by_request_id(asr_handle, id); + if (!req) { + Log_e("no req found according to request_id"); + HAL_Free(request_id); + goto exit; + } + req->asr_token = LITE_json_value_of(RESOURCE_TOKEN, json_str); + if (!req->asr_token) { + Log_e("no req->asr_token found"); + HAL_Free(request_id); + goto exit; + } + if (req->req_type == eASR_REALTIME) { + // Log_d("remove file %s", req->realtime_conf.file_name); + HAL_FileRemove(req->realtime_conf.file_name); + } + ret = _request_asr_resource_result(asr_handle->resource_handle, req); + HAL_Free(request_id); + break; + + default: + break; + } + + if (asr_handle->usrCb) { + ret = asr_handle->usrCb(asr_handle->resource_handle, msg, msgLen, event); + } + +exit: + + return ret; +} + +void *IOT_Asr_Init(const char *product_id, const char *device_name, void *pTemplate_client, + OnAsrResourceEventUsrCallback usr_cb) +{ + AsrHandle *asr_handle = NULL; + int rc = QCLOUD_RET_SUCCESS; + + rc = _register_asr_property(pTemplate_client); + if(QCLOUD_RET_SUCCESS != rc){ + Log_e("register asr system property fail,rc:%d",rc); + goto exit; + } + + asr_handle = HAL_Malloc(sizeof(AsrHandle)); + if (!asr_handle) { + Log_e("allocate asr client failed"); + rc = QCLOUD_ERR_MALLOC; + goto exit; + } + + // init resource client handle + asr_handle->resource_handle = + IOT_Resource_Init(product_id, device_name, IOT_Template_Get_MQTT_Client(pTemplate_client), + _asr_resource_event_usr_cb, asr_handle); + if (!asr_handle->resource_handle) { + Log_e("init resource client failed"); + rc = QCLOUD_ERR_FAILURE; + goto exit; + } + + asr_handle->mutex = HAL_MutexCreate(); + if (asr_handle->mutex == NULL) { + Log_e("create asr mutex fail"); + rc = QCLOUD_ERR_FAILURE; + goto exit; + } + + asr_handle->asr_req_list = list_new(); + if (asr_handle->asr_req_list) { + asr_handle->asr_req_list->free = HAL_Free; + } else { + Log_e("no memory to allocate asr_req_list"); + rc = QCLOUD_ERR_FAILURE; + } + asr_handle->usrCb = usr_cb; + sg_asr_client = asr_handle; + +exit: + + if (rc != QCLOUD_RET_SUCCESS) { + if (asr_handle) { + HAL_Free(asr_handle); + if (asr_handle->resource_handle) { + IOT_Resource_Destroy(asr_handle->resource_handle); + } + if (asr_handle->mutex) { + HAL_MutexDestroy(asr_handle->mutex); + } + if (asr_handle->asr_req_list) { + list_destroy(asr_handle->asr_req_list); + } + } + asr_handle = NULL; + } + + return asr_handle; +} + +int IOT_Asr_Destroy(void *handle) +{ + POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL); + AsrHandle *asr_handle = (AsrHandle *)handle; + int rc = QCLOUD_RET_SUCCESS; + + if (asr_handle->resource_handle) { + rc = IOT_Resource_Destroy(asr_handle->resource_handle); + } + if (asr_handle->mutex) { + HAL_MutexDestroy(asr_handle->mutex); + } + if (asr_handle->asr_req_list) { + list_destroy(asr_handle->asr_req_list); + } + + return rc; +} + +int IOT_Asr_RecordFile_Request(void *handle, const char *file_name, RecordAsrConf *conf, OnAsrResultCB cb) +{ + POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL); + AsrHandle *asr_handle = (AsrHandle *)handle; + int rc = QCLOUD_RET_SUCCESS; + + AsrReq *req = (AsrReq *)HAL_Malloc(sizeof(AsrReq)); + if (!req) { + Log_e("malloc mem err"); + rc = QCLOUD_ERR_MALLOC; + goto exit; + } + // required parameters + req->req_type = conf->req_type; + req->record_conf.engine_type = conf->engine_type; + req->record_conf.ch_num = conf->ch_num; + req->asr_token = NULL; + // option parameters + req->record_conf.filter_dirty = conf->filter_dirty; + req->record_conf.filter_modal = conf->filter_modal; + req->record_conf.filter_punc = conf->filter_punc; + req->record_conf.convert_num_mode = conf->convert_num_mode; + req->record_conf.speaker_diarization = conf->speaker_diarization; + req->record_conf.speaker_number = conf->speaker_number; + req->record_conf.hot_word_id = NULL; + + char time_str[TIME_FORMAT_STR_LEN] = {0}; + HAL_Snprintf(time_str, TIME_FORMAT_STR_LEN, "%d", HAL_Timer_current_sec()); + conf->request_timeout_ms = (conf->request_timeout_ms > 0) ? conf->request_timeout_ms : DEFAULT_REQ_TIMEOUT_MS; + char *type = (req->req_type == eASR_FILE)?RESOURCE_TYPE_AUDIO:RESOURCE_TYPE_VOICE; + req->request_id = + IOT_Resource_Post_Request(asr_handle->resource_handle, conf->request_timeout_ms, file_name, time_str, type); + if (req->request_id < 0) { + Log_e("%s resource post request fail", STRING_PTR_PRINT_SANITY_CHECK(file_name)); + HAL_Free(req); + rc = QCLOUD_ERR_FAILURE; + goto exit; + } + req->result_cb = cb; + + InitTimer(&(req->timer)); + countdown(&(req->timer), conf->request_timeout_ms); + rc = _add_request_to_asr_req_list(asr_handle, req); + if (QCLOUD_RET_SUCCESS != rc) { + _del_timeout_req_node(asr_handle); + } + +exit: + + return (rc == QCLOUD_RET_SUCCESS) ? req->request_id : rc; +} + +int IOT_Asr_Realtime_Request(void *handle, char *audio_buff, uint32_t audio_data_len, RealTimeAsrConf *conf, + OnAsrResultCB cb) +{ +#define VERSION_LEN 10 + POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL); + AsrHandle *asr_handle = (AsrHandle *)handle; + int rc = QCLOUD_RET_SUCCESS; + + AsrReq *req = (AsrReq *)HAL_Malloc(sizeof(AsrReq)); + if (!req) { + Log_e("malloc mem err"); + rc = QCLOUD_ERR_MALLOC; + goto exit; + } + // required parameters + req->req_type = conf->req_type; + req->realtime_conf.engine_type = conf->engine_type; + req->realtime_conf.res_type = conf->res_type; + req->realtime_conf.voice_format = conf->voice_format; + req->realtime_conf.seq = conf->seq; + req->realtime_conf.end = conf->end; + req->asr_token = NULL; + + // option parameters + req->realtime_conf.need_vad = conf->need_vad; + req->realtime_conf.vad_silence_time = conf->vad_silence_time; + req->realtime_conf.filter_dirty = conf->filter_dirty; + req->realtime_conf.filter_modal = conf->filter_modal; + req->realtime_conf.filter_punc = conf->filter_punc; + req->realtime_conf.convert_num_mode = conf->convert_num_mode; + req->realtime_conf.hot_word_id = NULL; + + static char voice_id[VOICE_ID_LEN + 1]; + if (0 == conf->seq) { + memset(voice_id, '\0', VOICE_ID_LEN + 1); + HAL_Snprintf(voice_id, VOICE_ID_LEN + 1, "%016d", HAL_Timer_current_sec()); + HAL_FileRemove("./*.bin"); + } + memset(req->realtime_conf.voice_id, '\0', VOICE_ID_LEN + 1); + strncpy(req->realtime_conf.voice_id, voice_id, VOICE_ID_LEN); + + char version[VERSION_LEN] = {0}; + HAL_Snprintf(version, VERSION_LEN, "%d", conf->seq); + memset(req->realtime_conf.file_name, 0, REAL_TIME_SLICE_FILE_NAME_LEN); + HAL_Snprintf(req->realtime_conf.file_name, VOICE_ID_LEN + VERSION_LEN, "./%s-%s.dat", voice_id, version); + // save audio data to file + void *fp = HAL_FileOpen(req->realtime_conf.file_name, "wb"); + if(!fp){ + Log_e("create file %s fail", req->realtime_conf.file_name); + goto exit; + } + + if (audio_data_len != HAL_FileWrite(audio_buff, 1, audio_data_len, fp)) { + Log_e("write data buff to %s fail", req->realtime_conf.file_name); + HAL_Free(req); + HAL_FileClose(fp); + rc = QCLOUD_ERR_FAILURE; + goto exit; + } + + HAL_FileClose(fp); + + conf->request_timeout_ms = (conf->request_timeout_ms > 0) ? conf->request_timeout_ms : DEFAULT_REQ_TIMEOUT_MS; + req->request_id = IOT_Resource_Post_Request(asr_handle->resource_handle, conf->request_timeout_ms, + req->realtime_conf.file_name, version, RESOURCE_TYPE_VOICE); + if (req->request_id < 0) { + Log_e("%s resource post request fail", req->realtime_conf.file_name); + HAL_FileRemove(req->realtime_conf.file_name); + rc = QCLOUD_ERR_FAILURE; + HAL_Free(req); + goto exit; + } + req->result_cb = cb; + + InitTimer(&(req->timer)); + countdown(&(req->timer), conf->request_timeout_ms); + rc = _add_request_to_asr_req_list(asr_handle, req); + if (QCLOUD_RET_SUCCESS != rc) { + _del_timeout_req_node(asr_handle); + HAL_FileRemove(req->realtime_conf.file_name); + HAL_Free(req); + } + +exit: + + return (rc == QCLOUD_RET_SUCCESS) ? req->request_id : rc; +#undef VERSION_LEN +} +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_action.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_action.c new file mode 100644 index 00000000..e158b8f1 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_action.c @@ -0,0 +1,413 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include "config.h" + +#if defined(ACTION_ENABLED) +#include +#include +#include +#include + +#include "qutils_param_check.h" +#include "lite-utils.h" +#include "data_template_client.h" +#include "data_template_action.h" +#include "data_template_client_json.h" +#include "qcloud_iot_export_data_template.h" + +// Action Subscribe +static int _parse_action_input(DeviceAction *pAction, char *pInput) +{ + int i; + char * temp; + DeviceProperty *pActionInput = pAction->pInput; + + // check and copy + for (i = 0; i < pAction->input_num; i++) { + if (JSTRING == pActionInput[i].type) { + pActionInput[i].data = LITE_json_value_of(pActionInput[i].key, pInput); + if (NULL == pActionInput[i].data) { + Log_e("action input data [%s] not found!", STRING_PTR_PRINT_SANITY_CHECK(pActionInput[i].key)); + return -1; + } + } else { + temp = LITE_json_value_of(pActionInput[i].key, pInput); + if (NULL == temp) { + Log_e("action input data [%s] not found!", STRING_PTR_PRINT_SANITY_CHECK(pActionInput[i].key)); + return -1; + } + if (JINT32 == pActionInput[i].type) { + if (sscanf(temp, "%" SCNi32, (int32_t *)pActionInput[i].data) != 1) { + HAL_Free(temp); + Log_e("parse code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE); + return -1; + } + } else if (JFLOAT == pActionInput[i].type) { + if (sscanf(temp, "%f", (float *)pActionInput[i].data) != 1) { + HAL_Free(temp); + Log_e("parse code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE); + return -1; + } + } else if (JUINT32 == pActionInput[i].type) { + if (sscanf(temp, "%" SCNu32, (uint32_t *)pActionInput[i].data) != 1) { + HAL_Free(temp); + Log_e("parse code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE); + return -1; + } + } + HAL_Free(temp); + } + } + + return 0; +} + +static void _handle_action(Qcloud_IoT_Template *pTemplate, List *list, const char *pClientToken, const char *pActionId, + uint32_t timestamp, char *pInput) +{ + IOT_FUNC_ENTRY; + + HAL_MutexLock(pTemplate->mutex); + + if (list->len) { + ListIterator *iter; + ListNode * node = NULL; + + if (NULL == (iter = list_iterator_new(list, LIST_TAIL))) { + HAL_MutexUnlock(pTemplate->mutex); + IOT_FUNC_EXIT; + } + + for (;;) { + node = list_iterator_next(iter); + if (NULL == node) { + break; + } + + if (NULL == node->val) { + Log_e("node's value is invalid!"); + continue; + } + + ActionHandler *pActionHandle = (ActionHandler *)node->val; + + // check action id and call callback + if (0 == strcmp(pActionId, ((DeviceAction *)pActionHandle->action)->pActionId)) { + if (NULL != pActionHandle->callback) { + if (!_parse_action_input(pActionHandle->action, pInput)) { + ((DeviceAction *)pActionHandle->action)->timestamp = timestamp; + pActionHandle->callback(pTemplate, pClientToken, pActionHandle->action); + } + } + } + } + list_iterator_destroy(iter); + } + HAL_MutexUnlock(pTemplate->mutex); + IOT_FUNC_EXIT; +} + +static void _on_action_handle_callback(void *pClient, MQTTMessage *message, void *pUserData) +{ + POINTER_SANITY_CHECK_RTN(message); + // Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient; + // Qcloud_IoT_Template *template_client = + // (Qcloud_IoT_Template*)mqtt_client->event_handle.context; + Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)pUserData; + + char *type_str = NULL; + char *client_token = NULL; + char *action_id = NULL; + char *pInput = NULL; + int timestamp = 0; + + Log_d("recv:%.*s", (int)message->payload_len, (char *)message->payload); + + // prase_method + if (!parse_template_method_type((char *)message->payload, &type_str)) { + Log_e("Fail to parse method!"); + goto EXIT; + } + + if (strcmp(type_str, CALL_ACTION)) { + goto EXIT; + } + + // prase client Token + if (!parse_client_token((char *)message->payload, &client_token)) { + Log_e("fail to parse client token!"); + goto EXIT; + } + + // prase action ID + if (!parse_action_id((char *)message->payload, &action_id)) { + Log_e("fail to parse action id!"); + goto EXIT; + } + + // prase timestamp + if (!parse_time_stamp((char *)message->payload, ×tamp)) { + Log_e("fail to parse timestamp!"); + goto EXIT; + } + + // prase action input + if (!parse_action_input((char *)message->payload, &pInput)) { + Log_e("fail to parse action input!"); + goto EXIT; + } + + // find action ID in register list and call handle + if (template_client != NULL) + _handle_action(template_client, template_client->inner_data.action_handle_list, client_token, action_id, + timestamp, pInput); + +EXIT: + HAL_Free(type_str); + HAL_Free(client_token); + HAL_Free(pInput); + return; +} + +int IOT_Action_Init(void *c) +{ + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)c; + static char topic_name[MAX_SIZE_OF_CLOUD_TOPIC] = {0}; + + int size = HAL_Snprintf(topic_name, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/down/action/%s/%s", + pTemplate->device_info.product_id, pTemplate->device_info.device_name); + + if (size < 0 || size > sizeof(topic_name) - 1) { + Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name)); + return QCLOUD_ERR_FAILURE; + } + + SubscribeParams sub_params = DEFAULT_SUB_PARAMS; + sub_params.on_message_handler = _on_action_handle_callback; + sub_params.user_data = pTemplate; + + return IOT_MQTT_Subscribe(pTemplate->mqtt, topic_name, &sub_params); +} + +// Action register +static int _add_action_handle_to_template_list(Qcloud_IoT_Template *pTemplate, DeviceAction *pAction, + OnActionHandleCallback callback) +{ + IOT_FUNC_ENTRY; + + ActionHandler *action_handle = (ActionHandler *)HAL_Malloc(sizeof(ActionHandler)); + if (NULL == action_handle) { + Log_e("run memory malloc is error!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + action_handle->callback = callback; + action_handle->action = pAction; + + ListNode *node = list_node_new(action_handle); + if (NULL == node) { + Log_e("run list_node_new is error!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + list_rpush(pTemplate->inner_data.action_handle_list, node); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +static int _check_action_existence(Qcloud_IoT_Template *ptemplate, DeviceAction *pAction) +{ + ListNode *node; + HAL_MutexLock(ptemplate->mutex); + node = list_find(ptemplate->inner_data.action_handle_list, pAction); + HAL_MutexUnlock(ptemplate->mutex); + return (NULL != node); +} + +int IOT_Action_Register(void *pTemplate, DeviceAction *pAction, OnActionHandleCallback callback) +{ + IOT_FUNC_ENTRY; + + Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)pTemplate; + + POINTER_SANITY_CHECK(pTemplate, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(callback, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pAction, QCLOUD_ERR_INVAL); + + if (_check_action_existence(ptemplate, pAction)) + IOT_FUNC_EXIT_RC(QCLOUD_ERR_ACTION_EXIST); + + int rc; + HAL_MutexLock(ptemplate->mutex); + rc = _add_action_handle_to_template_list(ptemplate, pAction, callback); + HAL_MutexUnlock(ptemplate->mutex); + + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Action_Remove(void *pTemplate, DeviceAction *pAction) +{ + Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)pTemplate; + if (!_check_action_existence(ptemplate, pAction)) + IOT_FUNC_EXIT_RC(QCLOUD_ERR_NOT_ACTION_EXIST); + + int rc = QCLOUD_RET_SUCCESS; + + ListNode *node; + HAL_MutexLock(ptemplate->mutex); + node = list_find(ptemplate->inner_data.action_handle_list, pAction); + if (NULL == node) { + rc = QCLOUD_ERR_NOT_PROPERTY_EXIST; + Log_e("Try to remove a non-existent action."); + } else { + list_remove(ptemplate->inner_data.action_handle_list, node); + } + HAL_MutexUnlock(ptemplate->mutex); + + return rc; +} + +// Action post to server +static int _iot_action_json_init(void *handle, char *jsonBuffer, size_t sizeOfBuffer, const char *pClientToken, + DeviceAction *pAction) +{ + POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL); + int32_t rc_of_snprintf; + memset(jsonBuffer, 0, sizeOfBuffer); + rc_of_snprintf = HAL_Snprintf(jsonBuffer, sizeOfBuffer, "{\"method\":\"%s\", \"clientToken\":\"%s\", ", + REPORT_ACTION, STRING_PTR_PRINT_SANITY_CHECK(pClientToken)); + + return check_snprintf_return(rc_of_snprintf, sizeOfBuffer); +} + +static int _iot_construct_action_json(void *handle, char *jsonBuffer, size_t sizeOfBuffer, const char *pClientToken, + DeviceAction *pAction, sReplyPara *replyPara) +{ + size_t remain_size = 0; + int32_t rc_of_snprintf = 0; + uint8_t i; + Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)handle; + + POINTER_SANITY_CHECK(ptemplate, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pClientToken, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pAction, QCLOUD_ERR_INVAL); + + int rc = _iot_action_json_init(ptemplate, jsonBuffer, sizeOfBuffer, pClientToken, pAction); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("event json init failed: %d", rc); + return rc; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"code\":%d, \"status\":\"%s\", \"response\":{", + replyPara->code, replyPara->status_msg); + + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + DeviceProperty *pJsonNode = pAction->pOutput; + for (i = 0; i < pAction->output_num; i++) { + if (pJsonNode != NULL && pJsonNode->key != NULL) { + rc = template_put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type); + + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + } else { + Log_e("%dth/%d null event property data", i, pAction->output_num); + return QCLOUD_ERR_INVAL; + } + pJsonNode++; + } + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "}"); + + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + // finish json + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) < 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "}"); + + return check_snprintf_return(rc_of_snprintf, remain_size); +} + +static int _publish_action_to_cloud(void *c, char *pJsonDoc) +{ + IOT_FUNC_ENTRY; + int rc = QCLOUD_RET_SUCCESS; + char topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0}; + Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)c; + + int size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/up/action/%s/%s", ptemplate->device_info.product_id, + ptemplate->device_info.device_name); + if (size < 0 || size > sizeof(topic) - 1) { + Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic)); + return QCLOUD_ERR_FAILURE; + } + + PublishParams pubParams = DEFAULT_PUB_PARAMS; + pubParams.qos = QOS1; + pubParams.payload_len = strlen(pJsonDoc); + pubParams.payload = (char *)pJsonDoc; + + rc = IOT_MQTT_Publish(ptemplate->mqtt, topic, &pubParams); + + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Action_Reply(void *pClient, const char *pClientToken, char *pJsonDoc, size_t sizeOfBuffer, + DeviceAction *pAction, sReplyPara *replyPara) +{ + int rc; + + rc = _iot_construct_action_json(pClient, pJsonDoc, sizeOfBuffer, pClientToken, pAction, replyPara); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("construct action json fail, %d", rc); + return rc; + } + + rc = _publish_action_to_cloud(pClient, pJsonDoc); + if (rc < 0) { + Log_e("publish action to cloud fail, %d", rc); + } + + return rc; +} + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client.c new file mode 100644 index 00000000..10ac9788 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client.c @@ -0,0 +1,944 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "data_template_client.h" + +#include +#include +#include + +#include "data_template_action.h" +#include "data_template_client_common.h" +#include "data_template_client_json.h" +#include "qutils_param_check.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" + +static void _init_request_params(RequestParams *pParams, Method method, OnReplyCallback callback, void *userContext, + uint8_t timeout_sec) +{ + pParams->method = method; + pParams->user_context = userContext; + pParams->timeout_sec = timeout_sec; + pParams->request_callback = callback; +} + +int IOT_Template_Publish(void *pClient, char *topicName, PublishParams *pParams) +{ + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + return qcloud_iot_mqtt_publish(pTemplate->mqtt, topicName, pParams); +} + +int IOT_Template_Subscribe(void *pClient, char *topicFilter, SubscribeParams *pParams) +{ + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + return qcloud_iot_mqtt_subscribe(pTemplate->mqtt, topicFilter, pParams); +} + +int IOT_Template_Unsubscribe(void *pClient, char *topicFilter) +{ + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + return qcloud_iot_mqtt_unsubscribe(pTemplate->mqtt, topicFilter); +} + +bool IOT_Template_IsConnected(void *pClient) +{ + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + IOT_FUNC_EXIT_RC(IOT_MQTT_IsConnected(pTemplate->mqtt)) +} + +int IOT_Template_Set_DataTemplate(void *pClient, void *data_template, DataTemplateDestroyCb cb) +{ + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(data_template, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + pTemplate->pDataTemplate = data_template; + pTemplate->DataTemplateDestroyCb = cb; + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +void *IOT_Template_Get_DataTemplate(void *pClient) +{ + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + return (NULL != pTemplate) ? pTemplate->pDataTemplate : NULL; +} + +int IOT_Template_Register_Property(void *pClient, DeviceProperty *pProperty, OnPropRegCallback callback) +{ + IOT_FUNC_ENTRY; + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + int rc; + + if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + if (template_common_check_property_existence(pTemplate, pProperty)) + IOT_FUNC_EXIT_RC(QCLOUD_ERR_PROPERTY_EXIST); + + rc = template_common_register_property_on_delta(pTemplate, pProperty, callback); + + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Template_UnRegister_Property(void *pClient, DeviceProperty *pProperty) +{ + IOT_FUNC_ENTRY; + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + if (!template_common_check_property_existence(pTemplate, pProperty)) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_NOT_PROPERTY_EXIST); + } + int rc = template_common_remove_property(pTemplate, pProperty); + IOT_FUNC_EXIT_RC(rc); +} + +#ifdef ACTION_ENABLED +int IOT_Template_Register_Action(void *pClient, DeviceAction *pAction, OnActionHandleCallback callback) +{ + IOT_FUNC_ENTRY; + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + int rc; + + if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + rc = IOT_Action_Register(pTemplate, pAction, callback); + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Template_UnRegister_Action(void *pClient, DeviceAction *pAction) +{ + IOT_FUNC_ENTRY; + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + int rc = IOT_Action_Remove(pTemplate, pAction); + IOT_FUNC_EXIT_RC(rc); +} +#endif + +static void _copy_template_init_params_to_mqtt(MQTTInitParams *pMqttInitParams, TemplateInitParams *templateInitParams) +{ + pMqttInitParams->region = templateInitParams->region; + pMqttInitParams->device_name = templateInitParams->device_name; + pMqttInitParams->product_id = templateInitParams->product_id; + +#ifdef AUTH_MODE_CERT + pMqttInitParams->cert_file = templateInitParams->cert_file; + pMqttInitParams->key_file = templateInitParams->key_file; +#else + pMqttInitParams->device_secret = templateInitParams->device_secret; +#endif + + pMqttInitParams->command_timeout = templateInitParams->command_timeout; + pMqttInitParams->keep_alive_interval_ms = templateInitParams->keep_alive_interval_ms; + pMqttInitParams->clean_session = templateInitParams->clean_session; + pMqttInitParams->auto_connect_enable = templateInitParams->auto_connect_enable; +} + +static void _reply_ack_cb(void *pClient, Method method, ReplyAck replyAck, const char *pReceivedJsonDocument, + void *pUserdata) +{ + Request *request = (Request *)pUserdata; + Log_d("replyAck=%d", replyAck); + + if (NULL != pReceivedJsonDocument) { + Log_d("Received Json Document=%s", pReceivedJsonDocument); + } else { + Log_d("Received Json Document is NULL"); + } + + *((ReplyAck *)(request->user_context)) = replyAck; +} + +/*control data may be for get status replay*/ +static void _get_status_reply_ack_cb(void *pClient, Method method, ReplyAck replyAck, const char *pReceivedJsonDocument, + void *pUserdata) +{ + Request *request = (Request *)pUserdata; + + Log_d("replyAck=%d", replyAck); + if (NULL == pReceivedJsonDocument) { + Log_d("Received Json Document is NULL"); + } else { + Log_d("Received Json Document=%s", pReceivedJsonDocument); + } + + if (*((ReplyAck *)request->user_context) == ACK_ACCEPTED) { + IOT_Template_ClearControl(pClient, request->client_token, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT); + } else { + *((ReplyAck *)request->user_context) = replyAck; + } +} + +static int _template_ConstructControlReply(char *jsonBuffer, size_t sizeOfBuffer, sReplyPara *replyPara) +{ + POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL); + + int rc; + size_t remain_size = 0; + int32_t rc_of_snprintf; + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + rc_of_snprintf = HAL_Snprintf(jsonBuffer, remain_size, "{\"code\":%d, \"clientToken\":\"%s\",", replyPara->code, + get_control_clientToken()); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + if (strlen(replyPara->status_msg) > 0) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"status\":\"%s\"}", replyPara->status_msg); + } else { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "}"); + } + + rc = check_snprintf_return(rc_of_snprintf, remain_size); + + return rc; +} + +static void _template_mqtt_event_handler(void *pclient, void *context, MQTTEventMsg *msg) +{ + POINTER_SANITY_CHECK_RTN(context); + uintptr_t packet_id = (uintptr_t)msg->msg; + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)context; + MQTTMessage * topic_info = (MQTTMessage *)msg->msg; + + if (pTemplate) { + if (pclient != pTemplate->mqtt) { + //Log_d("not template topic event"); + return; + } + } + + switch (msg->event_type) { + case MQTT_EVENT_SUBCRIBE_SUCCESS: + Log_d("template subscribe success, packet-id=%u", packet_id); + if (pTemplate->inner_data.sync_status > 0) + pTemplate->inner_data.sync_status = 0; + break; + case MQTT_EVENT_SUBCRIBE_TIMEOUT: + Log_d("template subscribe wait ack timeout, packet-id=%u", packet_id); + if (pTemplate->inner_data.sync_status > 0) + pTemplate->inner_data.sync_status = -1; + break; + case MQTT_EVENT_SUBCRIBE_NACK: + Log_d("template subscribe nack, packet-id=%u", packet_id); + if (pTemplate->inner_data.sync_status > 0) + pTemplate->inner_data.sync_status = -1; + break; + case MQTT_EVENT_PUBLISH_RECVEIVED: + Log_d( + "template topic message arrived but without any related pClient: " + "topic=%.*s, topic_msg=%.*s", + topic_info->topic_len, topic_info->ptopic, topic_info->payload_len, topic_info->payload); + break; + default: + /* Log_i("Should NOT arrive here."); */ + break; + } + if (pTemplate->event_handle.h_fp != NULL) { + pTemplate->event_handle.h_fp(pTemplate, pTemplate->event_handle.context, msg); + } +} + +int IOT_Template_JSON_ConstructReportArray(void *pClient, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, + DeviceProperty *pDeviceProperties[]) +{ + POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pDeviceProperties, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + POINTER_SANITY_CHECK(pTemplate, QCLOUD_ERR_INVAL); + + size_t remain_size = 0; + int32_t rc_of_snprintf = 0; + int rc; + int8_t i; + + build_empty_json(&(pTemplate->inner_data.token_num), jsonBuffer, pTemplate->device_info.product_id); + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, ", \"params\":{"); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + for (i = 0; i < count; i++) { + DeviceProperty *pJsonNode = pDeviceProperties[i]; + if (pJsonNode != NULL && pJsonNode->key != NULL) { + rc = put_json_node(jsonBuffer, remain_size, pJsonNode); + + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + } else { + return QCLOUD_ERR_INVAL; + } + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "}}"); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("construct datatemplate report array failed: %d", rc); + return rc; + } + + return rc; +} + +int IOT_Template_ClearControl(void *pClient, char *pClientToken, OnReplyCallback callback, uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + int rc; + char JsonDoc[MAX_CLEAE_DOC_LEN]; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pClientToken, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) { + Log_e("template is disconnected"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + // if topic $thing/down/property subscribe not success before, subsrcibe again + if (pTemplate->inner_data.sync_status < 0) { + rc = subscribe_template_downstream_topic(pTemplate); + if (rc < 0) { + Log_e("Subcribe $thing/down/property fail!"); + } + } + + memset(JsonDoc, 0, MAX_CLEAE_DOC_LEN); + int rc_of_snprintf = HAL_Snprintf(JsonDoc, MAX_CLEAE_DOC_LEN, "{\"clientToken\":\"%s\"}", pClientToken); + rc = check_snprintf_return(rc_of_snprintf, MAX_CLEAE_DOC_LEN); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + RequestParams request_params = DEFAULT_REQUEST_PARAMS; + _init_request_params(&request_params, CLEAR, callback, NULL, timeout_ms / 1000); + + rc = send_template_request(pTemplate, &request_params, JsonDoc, MAX_CLEAE_DOC_LEN); + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Template_Report(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, OnReplyCallback callback, void *userContext, + uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + int rc; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL); + NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) { + Log_e("template is disconnected"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + // if topic $thing/down/property subscribe not success before, subsrcibe again + if (pTemplate->inner_data.sync_status < 0) { + rc = subscribe_template_downstream_topic(pTemplate); + if (rc < 0) { + Log_e("Subcribe $thing/down/property fail!"); + } + } + + // Log_d("Report Document: %s", pJsonDoc); + + RequestParams request_params = DEFAULT_REQUEST_PARAMS; + _init_request_params(&request_params, REPORT, callback, userContext, timeout_ms / 1000); + + rc = send_template_request(pTemplate, &request_params, pJsonDoc, sizeOfBuffer); + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Template_Report_Sync(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + int rc = QCLOUD_RET_SUCCESS; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL); + NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *template = (Qcloud_IoT_Template *)pClient; + + if (IOT_MQTT_IsConnected(template->mqtt) == false) { + Log_e("template is disconnected"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + ReplyAck ack_report = ACK_NONE; + rc = IOT_Template_Report(pClient, pJsonDoc, sizeOfBuffer, _reply_ack_cb, &ack_report, timeout_ms); + if (rc != QCLOUD_RET_SUCCESS) + IOT_FUNC_EXIT_RC(rc); + while (ACK_NONE == ack_report) { + IOT_Template_Yield(pClient, 200); + } + + if (ACK_ACCEPTED == ack_report) { + rc = QCLOUD_RET_SUCCESS; + } else if (ACK_TIMEOUT == ack_report) { + rc = QCLOUD_ERR_REPORT_TIMEOUT; + } else if (ACK_REJECTED == ack_report) { + rc = QCLOUD_ERR_REPORT_REJECTED; + } + + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Template_JSON_ConstructSysInfo(void *pClient, char *jsonBuffer, size_t sizeOfBuffer, DeviceProperty *pPlatInfo, + DeviceProperty *pSelfInfo) +{ + POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pPlatInfo, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + POINTER_SANITY_CHECK(pTemplate, QCLOUD_ERR_INVAL); + + size_t remain_size = 0; + int32_t rc_of_snprintf = 0; + int rc; + + build_empty_json(&(pTemplate->inner_data.token_num), jsonBuffer, pTemplate->device_info.product_id); + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, ", \"params\":{"); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + DeviceProperty *pJsonNode = pPlatInfo; + while ((NULL != pJsonNode) && (NULL != pJsonNode->key)) { + rc = put_json_node(jsonBuffer, remain_size, pJsonNode); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + pJsonNode++; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "},"); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + pJsonNode = pSelfInfo; + if ((NULL == pJsonNode) || (NULL == pJsonNode->key)) { + Log_d("No self define info"); + goto end; + } + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 2, remain_size, ", \"device_label\":{"); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + while ((NULL != pJsonNode) && (NULL != pJsonNode->key)) { + rc = put_json_node(jsonBuffer, remain_size, pJsonNode); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + pJsonNode++; + } + + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "}},"); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + +end: + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "}"); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + + return rc; +} + +int IOT_Template_Report_SysInfo(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, OnReplyCallback callback, + void *userContext, uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + int rc; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL); + NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) { + Log_e("template is disconnected"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + // if topic $thing/down/property subscribe not success before, subsrcibe again + if (pTemplate->inner_data.sync_status < 0) { + rc = subscribe_template_downstream_topic(pTemplate); + if (rc < 0) { + Log_e("Subcribe $thing/down/property fail!"); + } + } + + // Log_d("eLOG_INFO Document: %s", pJsonDoc); + + RequestParams request_params = DEFAULT_REQUEST_PARAMS; + _init_request_params(&request_params, RINFO, callback, userContext, timeout_ms / 1000); + + rc = send_template_request(pTemplate, &request_params, pJsonDoc, sizeOfBuffer); + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Template_Report_SysInfo_Sync(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + int rc = QCLOUD_RET_SUCCESS; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL); + NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *template = (Qcloud_IoT_Template *)pClient; + + if (IOT_MQTT_IsConnected(template->mqtt) == false) { + Log_e("template is disconnected"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + ReplyAck ack_report = ACK_NONE; + rc = IOT_Template_Report_SysInfo(pClient, pJsonDoc, sizeOfBuffer, _reply_ack_cb, &ack_report, timeout_ms); + + if (rc != QCLOUD_RET_SUCCESS) + IOT_FUNC_EXIT_RC(rc); + while (ACK_NONE == ack_report) { + IOT_Template_Yield(pClient, 200); + } + + if (ACK_ACCEPTED == ack_report) { + rc = QCLOUD_RET_SUCCESS; + } else if (ACK_TIMEOUT == ack_report) { + rc = QCLOUD_ERR_REPORT_TIMEOUT; + } else if (ACK_REJECTED == ack_report) { + rc = QCLOUD_ERR_REPORT_REJECTED; + } + + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Template_GetStatus(void *pClient, OnReplyCallback callback, void *userContext, uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + int rc; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(callback, QCLOUD_ERR_INVAL); + NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + // if topic $thing/down/property subscribe not success before, subsrcibe again + if (pTemplate->inner_data.sync_status < 0) { + rc = subscribe_template_downstream_topic(pTemplate); + if (rc < 0) { + Log_e("Subcribe $thing/down/property fail!"); + } + } + + char getRequestJsonDoc[MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN]; + build_empty_json(&(pTemplate->inner_data.token_num), getRequestJsonDoc, pTemplate->device_info.product_id); + + // Log_d("GET Status Document: %s", getRequestJsonDoc); + + RequestParams request_params = DEFAULT_REQUEST_PARAMS; + _init_request_params(&request_params, GET, callback, userContext, timeout_ms / 1000); + + rc = send_template_request(pTemplate, &request_params, getRequestJsonDoc, MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN); + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Template_GetStatus_sync(void *pClient, uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + int rc = QCLOUD_RET_SUCCESS; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + ReplyAck ack_request = ACK_NONE; + rc = IOT_Template_GetStatus(pClient, _get_status_reply_ack_cb, &ack_request, timeout_ms); + if (rc != QCLOUD_RET_SUCCESS) + IOT_FUNC_EXIT_RC(rc); + while (ACK_NONE == ack_request) { + IOT_Template_Yield(pClient, 200); + } + + if (ACK_ACCEPTED == ack_request) { + rc = QCLOUD_RET_SUCCESS; + } else if (ACK_TIMEOUT == ack_request) { + rc = QCLOUD_ERR_GET_TIMEOUT; + } else if (ACK_REJECTED == ack_request) { + rc = QCLOUD_ERR_GET_REJECTED; + } + + IOT_FUNC_EXIT_RC(rc); +} + +int IOT_Template_ControlReply(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, sReplyPara *replyPara) +{ + IOT_FUNC_ENTRY; + int rc; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + if (IOT_MQTT_IsConnected(pTemplate->mqtt) == false) { + Log_e("template is disconnected"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + // if topic $thing/down/property subscribe not success before, subsrcibe again + if (pTemplate->inner_data.sync_status < 0) { + rc = subscribe_template_downstream_topic(pTemplate); + if (rc < 0) { + Log_e("Subcribe $thing/down/property fail!"); + } + } + + rc = _template_ConstructControlReply(pJsonDoc, sizeOfBuffer, replyPara); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("Construct ControlReply fail,rc=%d", rc); + return rc; + } + Log_d("Report Document: %s", pJsonDoc); + + RequestParams request_params = DEFAULT_REQUEST_PARAMS; + _init_request_params(&request_params, REPLY, NULL, NULL, replyPara->timeout_ms / 1000); + + rc = send_template_request(pTemplate, &request_params, pJsonDoc, sizeOfBuffer); + IOT_FUNC_EXIT_RC(rc); +} + +#ifdef MULTITHREAD_ENABLED + +int IOT_Template_Start_Yield_Thread(void *pClient) +{ + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + int rc = IOT_MQTT_StartLoop(pTemplate->mqtt); + if(QCLOUD_RET_SUCCESS == rc) { + pTemplate->yield_thread_running = true; + } else { + pTemplate->yield_thread_running = false; + } + + return rc; +} + +void IOT_Template_Stop_Yield_Thread(void *pClient) +{ + POINTER_SANITY_CHECK_RTN(pClient); + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + IOT_MQTT_StopLoop(pTemplate->mqtt); + pTemplate->yield_thread_running = false; + HAL_SleepMs(1000); + + return; +} + +bool IOT_Template_Get_Yield_Status(void *pClient, int *exit_code) +{ + POINTER_SANITY_CHECK(pClient, false); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + pTemplate->yield_thread_running = IOT_MQTT_GetLoopStatus(pTemplate->mqtt, exit_code); + + return pTemplate->yield_thread_running; +} + +int IOT_Template_Destroy_Except_MQTT(void *pClient) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + qcloud_iot_template_reset(pClient); + + if (NULL != pTemplate->DataTemplateDestroyCb) { + pTemplate->DataTemplateDestroyCb(pClient); + } + + if (NULL != pTemplate->mutex) { + HAL_MutexDestroy(pTemplate->mutex); + } + + if (NULL != pTemplate->inner_data.downstream_topic) { + HAL_Free(pTemplate->inner_data.downstream_topic); + pTemplate->inner_data.downstream_topic = NULL; + } + + HAL_Free(pClient); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS) +} +#endif + + +int IOT_Template_Yield(void *pClient, uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + int rc; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + handle_template_expired_reply(pTemplate); + +#ifdef EVENT_POST_ENABLED + handle_template_expired_event(pTemplate); +#endif + + rc = IOT_MQTT_Yield(pTemplate->mqtt, timeout_ms); + + IOT_FUNC_EXIT_RC(rc); +} + +void *IOT_Template_Get_MQTT_Client(void *pClient) +{ + POINTER_SANITY_CHECK(pClient, NULL); + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + + return pTemplate->mqtt; +} + +void *IOT_Template_Construct(TemplateInitParams *pParams, void *pMqttClient) +{ + POINTER_SANITY_CHECK(pParams, NULL); + int rc; + + Qcloud_IoT_Template *pTemplate = NULL; + if ((pTemplate = (Qcloud_IoT_Template *)HAL_Malloc(sizeof(Qcloud_IoT_Template))) == NULL) { + Log_e("memory not enough to malloc TemplateClient"); + return NULL; + } + + MQTTInitParams mqtt_init_params; + _copy_template_init_params_to_mqtt(&mqtt_init_params, pParams); + + mqtt_init_params.event_handle.h_fp = _template_mqtt_event_handler; + mqtt_init_params.event_handle.context = pTemplate; + + rc = iot_device_info_set(&pTemplate->device_info, pParams->product_id, pParams->device_name); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("failed to set device info: %d", rc); + goto End; + } + + void *mqtt_client = NULL; + if (NULL == pMqttClient) { + if ((mqtt_client = IOT_MQTT_Construct(&mqtt_init_params)) == NULL) { + HAL_Free(pTemplate); + goto End; + } + } else { // multi dev share the same mqtt client + mqtt_client = pMqttClient; + } + +#ifdef MULTITHREAD_ENABLED + pTemplate->yield_thread_running = false; +#endif + + pTemplate->mqtt = mqtt_client; + pTemplate->event_handle = pParams->event_handle; + pTemplate->usr_control_handle = pParams->usr_control_handle; + pTemplate->inner_data.upstream_topic = NULL; + pTemplate->inner_data.downstream_topic = NULL; + pTemplate->inner_data.token_num = 0; + pTemplate->inner_data.eventflags = 0; + + rc = qcloud_iot_template_init(pTemplate); + if (rc != QCLOUD_RET_SUCCESS) { + IOT_MQTT_Destroy(&(pTemplate->mqtt)); + IOT_Template_Destroy(pTemplate); + HAL_Free(pTemplate); + goto End; + } + + rc = subscribe_template_downstream_topic(pTemplate); + if (rc < 0) { + Log_e("Subcribe $thing/down/property fail!"); + } else { + if (!pMqttClient) { + pTemplate->inner_data.sync_status = rc; + while (rc == pTemplate->inner_data.sync_status) { + IOT_Template_Yield(pTemplate, 100); + } + + if (0 == pTemplate->inner_data.sync_status) { + Log_i("Sync device data successfully"); + } else { + Log_e("Sync device data failed"); + } + } else { + pTemplate->inner_data.sync_status = 0; + } + } + +#ifdef EVENT_POST_ENABLED + rc = IOT_Event_Init(pTemplate); + if (rc < 0) { + Log_e("event init failed: %d", rc); + IOT_Template_Destroy(pTemplate); + goto End; + } +#endif + +#ifdef ACTION_ENABLED + rc = IOT_Action_Init(pTemplate); + if (rc < 0) { + Log_e("action init failed: %d", rc); + IOT_Template_Destroy(pTemplate); + goto End; + } +#endif + + return pTemplate; + +End: + + return NULL; +} + +int IOT_Template_Destroy(void *pClient) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)pClient; + qcloud_iot_template_reset(pTemplate); + IOT_MQTT_Destroy(&pTemplate->mqtt); + + if (NULL != pTemplate->mutex) { + HAL_MutexDestroy(pTemplate->mutex); + } + + if (NULL != pTemplate->inner_data.downstream_topic) { + HAL_Free(pTemplate->inner_data.downstream_topic); + pTemplate->inner_data.downstream_topic = NULL; + } + + HAL_Free(pClient); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS) +} +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client_common.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client_common.c new file mode 100644 index 00000000..ffa9a7e4 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client_common.c @@ -0,0 +1,107 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "data_template_client_common.h" + +#include "qcloud_iot_import.h" + +/** + * @brief add registered propery's call back to data_template handle list + */ +static int _add_property_handle_to_template_list(Qcloud_IoT_Template *pTemplate, DeviceProperty *pProperty, + OnPropRegCallback callback) +{ + IOT_FUNC_ENTRY; + + PropertyHandler *property_handle = (PropertyHandler *)HAL_Malloc(sizeof(PropertyHandler)); + if (NULL == property_handle) { + Log_e("run memory malloc is error!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + property_handle->callback = callback; + property_handle->property = pProperty; + + ListNode *node = list_node_new(property_handle); + if (NULL == node) { + Log_e("run list_node_new is error!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + list_rpush(pTemplate->inner_data.property_handle_list, node); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int template_common_check_property_existence(Qcloud_IoT_Template *ptemplate, DeviceProperty *pProperty) +{ + ListNode *node; + + HAL_MutexLock(ptemplate->mutex); + node = list_find(ptemplate->inner_data.property_handle_list, pProperty); + HAL_MutexUnlock(ptemplate->mutex); + + return (NULL != node); +} + +int template_common_remove_property(Qcloud_IoT_Template *ptemplate, DeviceProperty *pProperty) +{ + int rc = QCLOUD_RET_SUCCESS; + + ListNode *node; + HAL_MutexLock(ptemplate->mutex); + node = list_find(ptemplate->inner_data.property_handle_list, pProperty); + if (NULL == node) { + rc = QCLOUD_ERR_NOT_PROPERTY_EXIST; + Log_e("Try to remove a non-existent property."); + } else { + list_remove(ptemplate->inner_data.property_handle_list, node); + } + HAL_MutexUnlock(ptemplate->mutex); + + return rc; +} + +int template_common_register_property_on_delta(Qcloud_IoT_Template *pTemplate, DeviceProperty *pProperty, + OnPropRegCallback callback) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pTemplate, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(callback, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pProperty, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pProperty->key, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pProperty->data, QCLOUD_ERR_INVAL); + + int rc; + + HAL_MutexLock(pTemplate->mutex); + rc = _add_property_handle_to_template_list(pTemplate, pProperty, callback); + HAL_MutexUnlock(pTemplate->mutex); + + IOT_FUNC_EXIT_RC(rc); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client_json.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client_json.c new file mode 100644 index 00000000..34ad2e4f --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client_json.c @@ -0,0 +1,349 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "data_template_client_json.h" + +#include +#include +#include +#include +#include + +#include "lite-utils.h" +#include "qcloud_iot_device.h" +#include "qcloud_iot_export_method.h" + +int check_snprintf_return(int32_t returnCode, size_t maxSizeOfWrite) +{ + if (returnCode >= maxSizeOfWrite) { + return QCLOUD_ERR_JSON_BUFFER_TRUNCATED; + } else if (returnCode < 0) { // err + return QCLOUD_ERR_JSON; + } + + return QCLOUD_RET_SUCCESS; +} + +void insert_str(char *pDestStr, char *pSourceStr, int pos) +{ + int len = strlen(pDestStr); + int nlen = strlen(pSourceStr); + int i; + for (i = len - 1; i >= pos; --i) { + *(pDestStr + i + nlen) = *(pDestStr + i); + } + + int n; + for (n = 0; n < nlen; n++) *(pDestStr + pos + n) = *pSourceStr++; + *(pDestStr + len + nlen) = 0; +} + +static int _direct_update_value(char *value, DeviceProperty *pProperty) +{ + int rc = QCLOUD_RET_SUCCESS; + uint16_t index = 0; + + if (pProperty->type == JBOOL) { + rc = LITE_get_boolean(pProperty->data, value); + } else if (pProperty->type == JINT32) { + rc = LITE_get_int32(pProperty->data, value); + } else if (pProperty->type == JINT16) { + rc = LITE_get_int16(pProperty->data, value); + } else if (pProperty->type == JINT8) { + rc = LITE_get_int8(pProperty->data, value); + } else if (pProperty->type == JUINT32) { + rc = LITE_get_uint32(pProperty->data, value); + } else if (pProperty->type == JUINT16) { + rc = LITE_get_uint16(pProperty->data, value); + } else if (pProperty->type == JUINT8) { + rc = LITE_get_uint8(pProperty->data, value); + } else if (pProperty->type == JFLOAT) { + rc = LITE_get_float(pProperty->data, value); + } else if (pProperty->type == JDOUBLE) { + rc = LITE_get_double(pProperty->data, value); + } else if (pProperty->type == JSTRING) { + rc = LITE_get_string(pProperty->data, value, pProperty->data_buff_len); + } else if (pProperty->type == JOBJECT) { + for (index = 0; index < pProperty->struct_obj_num; index++) { + DeviceProperty *pJsonNode = &((((sDataPoint *)(pProperty->data)) + index)->data_property); + if ((pJsonNode != NULL) && (pJsonNode->key != NULL)) { + update_value_if_key_match(value, pJsonNode); + } + } + } else { + Log_e("pProperty type unknow,%d", pProperty->type); + } + + return rc; +} + +int put_json_node(char *jsonBuffer, size_t sizeOfBuffer, DeviceProperty *pJsonNode) +{ + int rc; + int32_t rc_of_snprintf = 0; + size_t remain_size = 0; + char *pKey = pJsonNode->key; + void *pData = pJsonNode->data; + JsonDataType type = pJsonNode->type; + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"%s\":", STRING_PTR_PRINT_SANITY_CHECK(pKey)); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + if (pData == NULL) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "null,"); + } else { + if (type == JINT32) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi32 ",", *(int32_t *)(pData)); + } else if (type == JINT16) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi16 ",", *(int16_t *)(pData)); + } else if (type == JINT8) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi8 ",", *(int8_t *)(pData)); + } else if (type == JUINT32) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu32 ",", *(uint32_t *)(pData)); + } else if (type == JUINT16) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu16 ",", *(uint16_t *)(pData)); + } else if (type == JUINT8) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu8 ",", *(uint8_t *)(pData)); + } else if (type == JDOUBLE) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%f,", *(double *)(pData)); + } else if (type == JFLOAT) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%f,", *(float *)(pData)); + } else if (type == JBOOL) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%s,", *(bool *)(pData) ? "true" : "false"); + } else if (type == JSTRING) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"%s\",", (char *)(pData)); + } else if (type == JOBJECT) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "{"); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + uint16_t index = 0; + + for (index = 0; index < pJsonNode->struct_obj_num; index++) { + DeviceProperty *pNode = &((((sDataPoint *)(pJsonNode->data)) + index)->data_property); + if ((pNode != NULL) && (pNode->key) != NULL) { + rc = put_json_node(jsonBuffer + strlen(jsonBuffer), remain_size, pNode); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + } + } + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "},"); + } + } + + rc = check_snprintf_return(rc_of_snprintf, remain_size); + + return rc; +} + +int template_put_json_node(char *jsonBuffer, size_t sizeOfBuffer, const char *pKey, void *pData, JsonDataType type) +{ + int rc; + int32_t rc_of_snprintf = 0; + size_t remain_size = 0; + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"%s\":", STRING_PTR_PRINT_SANITY_CHECK(pKey)); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + if (pData == NULL) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "null,"); + } else { + if (type == JINT32) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi32 ",", *(int32_t *)(pData)); + } else if (type == JINT16) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi16 ",", *(int16_t *)(pData)); + } else if (type == JINT8) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIi8 ",", *(int8_t *)(pData)); + } else if (type == JUINT32) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu32 ",", *(uint32_t *)(pData)); + } else if (type == JUINT16) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu16 ",", *(uint16_t *)(pData)); + } else if (type == JUINT8) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%" PRIu8 ",", *(uint8_t *)(pData)); + } else if (type == JDOUBLE) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%f,", *(double *)(pData)); + } else if (type == JFLOAT) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%f,", *(float *)(pData)); + } else if (type == JBOOL) { + rc_of_snprintf = + HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%u,", *(bool *)(pData) ? 1 : 0); + } else if (type == JSTRING) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"%s\",", (char *)(pData)); + } else if (type == JOBJECT) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "%s,", (char *)(pData)); + } + } + + rc = check_snprintf_return(rc_of_snprintf, remain_size); + + return rc; +} + +void build_empty_json(uint32_t *tokenNumber, char *pJsonBuffer, char *tokenPrefix) +{ + HAL_Snprintf(pJsonBuffer, MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN, "{\"clientToken\":\"%s-%u\"}", + STRING_PTR_PRINT_SANITY_CHECK(tokenPrefix), (*tokenNumber)++); +} + +bool parse_client_token(char *pJsonDoc, char **pClientToken) +{ + *pClientToken = LITE_json_value_of(CLIENT_TOKEN_FIELD, pJsonDoc); + return *pClientToken == NULL ? false : true; +} + +bool parse_action_id(char *pJsonDoc, char **pActionID) +{ + *pActionID = LITE_json_value_of(ACTION_ID_FIELD, pJsonDoc); + return *pActionID == NULL ? false : true; +} + +bool parse_time_stamp(char *pJsonDoc, int32_t *pTimestamp) +{ + bool ret = false; + + char *timestamp = LITE_json_value_of(TIME_STAMP_FIELD, pJsonDoc); + if (timestamp == NULL) + return false; + + if (sscanf(timestamp, "%" SCNu32, pTimestamp) != 1) { + Log_e("parse code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE); + } else { + ret = true; + } + + HAL_Free(timestamp); + + return ret; +} + +bool parse_action_input(char *pJsonDoc, char **pActionInput) +{ + *pActionInput = LITE_json_value_of(CMD_CONTROL_PARA, pJsonDoc); + return *pActionInput == NULL ? false : true; +} + +bool parse_code_return(char *pJsonDoc, int32_t *pCode) +{ + bool ret = false; + + char *code = LITE_json_value_of(REPLY_CODE, pJsonDoc); + if (code == NULL) + return false; + + if (sscanf(code, "%" SCNi32, pCode) != 1) { + Log_e("parse code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE); + } else { + ret = true; + } + + HAL_Free(code); + + return ret; +} + +bool parse_status_return(char *pJsonDoc, char **pStatus) +{ + *pStatus = LITE_json_value_of(REPLY_STATUS, pJsonDoc); + return *pStatus == NULL ? false : true; +} + +bool update_value_if_key_match(char *pJsonDoc, DeviceProperty *pProperty) +{ + bool ret = false; + + char *property_data = LITE_json_value_of(pProperty->key, pJsonDoc); + if ((property_data == NULL) || !(strncmp(property_data, "null", 4)) || !(strncmp(property_data, "NULL", 4))) { + ret = false; + } else { + _direct_update_value(property_data, pProperty); + ret = true; + } + + if (property_data) { + HAL_Free(property_data); + } + + return ret; +} + +bool parse_template_method_type(char *pJsonDoc, char **pMethod) +{ + *pMethod = LITE_json_value_of(METHOD_FIELD, pJsonDoc); + return *pMethod == NULL ? false : true; +} + +bool parse_template_get_control(char *pJsonDoc, char **control) +{ + *control = LITE_json_value_of(GET_CONTROL_PARA, pJsonDoc); + return *control == NULL ? false : true; +} + +bool parse_template_cmd_control(char *pJsonDoc, char **control) +{ + *control = LITE_json_value_of(CMD_CONTROL_PARA, pJsonDoc); + return *control == NULL ? false : true; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client_manager.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client_manager.c new file mode 100644 index 00000000..08451a39 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_client_manager.c @@ -0,0 +1,590 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#include "data_template_client.h" +#include "data_template_client_json.h" +#include "qcloud_iot_import.h" +#include "qutils_list.h" +#include "qutils_param_check.h" + +typedef void (*TraverseTemplateHandle)(Qcloud_IoT_Template *pTemplate, ListNode **node, List *list, + const char *pClientToken, const char *pType); + +static char sg_template_cloud_rcv_buf[CLOUD_IOT_JSON_RX_BUF_LEN]; +static char sg_template_clientToken[MAX_SIZE_OF_CLIENT_TOKEN]; + +/** + * @brief unsubsribe topic: $thing/down/property/{ProductId}/{DeviceName} + */ +static int _unsubscribe_template_downstream_topic(Qcloud_IoT_Template *pTemplate_client) +{ + IOT_FUNC_ENTRY; + int rc = QCLOUD_RET_SUCCESS; + + char downstream_topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0}; + int size = HAL_Snprintf(downstream_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/down/property/%s/%s", + pTemplate_client->device_info.product_id, pTemplate_client->device_info.device_name); + + if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC - 1) { + Log_e("buf size < topic length!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + IOT_MQTT_Unsubscribe(pTemplate_client->mqtt, downstream_topic); + if (rc < 0) { + Log_e("unsubscribe topic: %s failed: %d.", downstream_topic, rc); + } + + IOT_FUNC_EXIT_RC(rc); +} + +/** + * @brief add request to data_template request wait for reply list + */ +static int _add_request_to_template_list(Qcloud_IoT_Template *pTemplate, const char *pClientToken, + RequestParams *pParams) +{ + IOT_FUNC_ENTRY; + + HAL_MutexLock(pTemplate->mutex); + if (pTemplate->inner_data.reply_list->len >= MAX_APPENDING_REQUEST_AT_ANY_GIVEN_TIME) { + HAL_MutexUnlock(pTemplate->mutex); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_APPENDING_REQUEST); + } + + Request *request = (Request *)HAL_Malloc(sizeof(Request)); + if (NULL == request) { + HAL_MutexUnlock(pTemplate->mutex); + Log_e("run memory malloc is error!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + request->callback = pParams->request_callback; + strncpy(request->client_token, pClientToken, MAX_SIZE_OF_CLIENT_TOKEN); + + request->user_context = pParams->user_context; + request->method = pParams->method; + + InitTimer(&(request->timer)); + countdown(&(request->timer), pParams->timeout_sec); + + ListNode *node = list_node_new(request); + if (NULL == node) { + HAL_MutexUnlock(pTemplate->mutex); + Log_e("run list_node_new is error!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + list_rpush(pTemplate->inner_data.reply_list, node); + + HAL_MutexUnlock(pTemplate->mutex); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * @brief publish operation to server + * + * @param pClient handle to data_template client + * @param method method type + * @param pJsonDoc JSON to publish + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int _publish_to_template_upstream_topic(Qcloud_IoT_Template *pTemplate, Method method, char *pJsonDoc) +{ + IOT_FUNC_ENTRY; + int rc = QCLOUD_RET_SUCCESS; + + char topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0}; + int size; + + size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/up/property/%s/%s", pTemplate->device_info.product_id, + pTemplate->device_info.device_name); + + if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC - 1) { + Log_e("buf size < topic length!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + PublishParams pubParams = DEFAULT_PUB_PARAMS; + pubParams.qos = QOS0; + pubParams.payload_len = strlen(pJsonDoc); + pubParams.payload = (char *)pJsonDoc; + + rc = IOT_MQTT_Publish(pTemplate->mqtt, topic, &pubParams); + + IOT_FUNC_EXIT_RC(rc); +} + +/** + * @brief fill method json filed with the value of RequestParams and Method + */ +static int _set_template_json_type(char *pJsonDoc, size_t sizeOfBuffer, Method method) +{ + IOT_FUNC_ENTRY; + + int rc = QCLOUD_RET_SUCCESS; + + POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL); + char *method_str = NULL; + switch (method) { + case GET: + method_str = GET_STATUS; + break; + case REPORT: + method_str = REPORT_CMD; + break; + case RINFO: + method_str = INFO_CMD; + break; + case REPLY: + method_str = CONTROL_CMD_REPLY; + break; + case CLEAR: + method_str = CLEAR_CONTROL; + break; + default: + Log_e("unexpected method!"); + rc = QCLOUD_ERR_INVAL; + break; + } + if (rc != QCLOUD_RET_SUCCESS) + IOT_FUNC_EXIT_RC(rc); + + size_t json_len = strlen(pJsonDoc); + size_t remain_size = sizeOfBuffer - json_len; + + char json_node_str[64] = {0}; + HAL_Snprintf(json_node_str, 64, "\"method\":\"%s\", ", method_str); + + size_t json_node_len = strlen(json_node_str); + if (json_node_len >= remain_size - 1) { + rc = QCLOUD_ERR_INVAL; + } else { + insert_str(pJsonDoc, json_node_str, 1); + } + + IOT_FUNC_EXIT_RC(rc); +} + +/** + * @brief iterator list and call traverseHandle for each node + */ +static void _traverse_template_list(Qcloud_IoT_Template *pTemplate, List *list, const char *pClientToken, + const char *pType, TraverseTemplateHandle traverseHandle) +{ + IOT_FUNC_ENTRY; + + HAL_MutexLock(pTemplate->mutex); + + if (list->len) { + ListIterator *iter; + ListNode * node = NULL; + + if (NULL == (iter = list_iterator_new(list, LIST_TAIL))) { + HAL_MutexUnlock(pTemplate->mutex); + IOT_FUNC_EXIT; + } + + for (;;) { + node = list_iterator_next(iter); + if (NULL == node) { + break; + } + + if (NULL == node->val) { + Log_e("node's value is invalid!"); + continue; + } + + traverseHandle(pTemplate, &node, list, pClientToken, pType); + } + + list_iterator_destroy(iter); + } + HAL_MutexUnlock(pTemplate->mutex); + + IOT_FUNC_EXIT; +} + +/** + * @brief handle the timeout request wait for reply + */ +static void _handle_template_expired_reply_callback(Qcloud_IoT_Template *pTemplate, ListNode **node, List *list, + const char *pClientToken, const char *pType) +{ + IOT_FUNC_ENTRY; + + Request *request = (Request *)(*node)->val; + if (NULL == request) + IOT_FUNC_EXIT; + + if (expired(&request->timer)) { + if (request->callback != NULL) { + request->callback(pTemplate, request->method, ACK_TIMEOUT, sg_template_cloud_rcv_buf, request); + } + + list_remove(list, *node); + *node = NULL; + } + + IOT_FUNC_EXIT; +} + +static void _set_control_clientToken(const char *pClientToken) +{ + memset(sg_template_clientToken, '\0', MAX_SIZE_OF_CLIENT_TOKEN); + strncpy(sg_template_clientToken, pClientToken, MAX_SIZE_OF_CLIENT_TOKEN); +} + +char *get_control_clientToken(void) +{ + return sg_template_clientToken; +} + +void qcloud_iot_template_reset(Qcloud_IoT_Template *pTemplate) +{ + POINTER_SANITY_CHECK_RTN(pTemplate); + + _unsubscribe_template_downstream_topic(pTemplate); + if (pTemplate->inner_data.property_handle_list) { + list_destroy(pTemplate->inner_data.property_handle_list); + pTemplate->inner_data.property_handle_list = NULL; + } + + if (pTemplate->inner_data.reply_list) { + list_destroy(pTemplate->inner_data.reply_list); + pTemplate->inner_data.reply_list = NULL; + } + + if (pTemplate->inner_data.event_list) { + list_destroy(pTemplate->inner_data.event_list); + pTemplate->inner_data.event_list = NULL; + } + + if (NULL != pTemplate->inner_data.action_handle_list) { + list_destroy(pTemplate->inner_data.action_handle_list); + pTemplate->inner_data.action_handle_list = NULL; + } +} + +int qcloud_iot_template_init(Qcloud_IoT_Template *pTemplate) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pTemplate, QCLOUD_ERR_INVAL); + + pTemplate->mutex = HAL_MutexCreate(); + if (pTemplate->mutex == NULL) + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + + pTemplate->inner_data.property_handle_list = list_new(); + if (pTemplate->inner_data.property_handle_list) { + pTemplate->inner_data.property_handle_list->free = HAL_Free; + } else { + Log_e("no memory to allocate property_handle_list"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + pTemplate->inner_data.reply_list = list_new(); + if (pTemplate->inner_data.reply_list) { + pTemplate->inner_data.reply_list->free = HAL_Free; + } else { + Log_e("no memory to allocate reply_list"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + pTemplate->inner_data.event_list = list_new(); + if (pTemplate->inner_data.event_list) { + pTemplate->inner_data.event_list->free = HAL_Free; + } else { + Log_e("no memory to allocate event_list"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + pTemplate->inner_data.action_handle_list = list_new(); + if (pTemplate->inner_data.action_handle_list) { + pTemplate->inner_data.action_handle_list->free = HAL_Free; + } else { + Log_e("no memory to allocate action_handle_list"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +void handle_template_expired_reply(Qcloud_IoT_Template *pTemplate) +{ + IOT_FUNC_ENTRY; + + _traverse_template_list(pTemplate, pTemplate->inner_data.reply_list, NULL, NULL, + _handle_template_expired_reply_callback); + + IOT_FUNC_EXIT; +} + +int send_template_request(Qcloud_IoT_Template *pTemplate, RequestParams *pParams, char *pJsonDoc, size_t sizeOfBuffer) +{ + IOT_FUNC_ENTRY; + int rc = QCLOUD_RET_SUCCESS; + + POINTER_SANITY_CHECK(pTemplate, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL); + + char *client_token = NULL; + + // parse clientToken in pJsonDoc, return err if parse failed + if (!parse_client_token(pJsonDoc, &client_token)) { + Log_e("fail to parse client token!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL); + } + + if (rc != QCLOUD_RET_SUCCESS) + IOT_FUNC_EXIT_RC(rc); + + rc = _set_template_json_type(pJsonDoc, sizeOfBuffer, pParams->method); + if (rc != QCLOUD_RET_SUCCESS) + IOT_FUNC_EXIT_RC(rc); + + if (rc == QCLOUD_RET_SUCCESS) { + rc = _publish_to_template_upstream_topic(pTemplate, pParams->method, pJsonDoc); + } + + if ((rc == QCLOUD_RET_SUCCESS) && (NULL != pParams->request_callback)) { + rc = _add_request_to_template_list(pTemplate, client_token, pParams); + } + + HAL_Free(client_token); + + IOT_FUNC_EXIT_RC(rc); +} + +static void _handle_control(Qcloud_IoT_Template *pTemplate, char *control_str) +{ + IOT_FUNC_ENTRY; + if (pTemplate->inner_data.property_handle_list->len) { + ListIterator * iter; + ListNode * node = NULL; + PropertyHandler *property_handle = NULL; + + if (NULL == (iter = list_iterator_new(pTemplate->inner_data.property_handle_list, LIST_TAIL))) { + HAL_MutexUnlock(pTemplate->mutex); + IOT_FUNC_EXIT; + } + + for (;;) { + node = list_iterator_next(iter); + if (NULL == node) { + break; + } + + property_handle = (PropertyHandler *)(node->val); + if (NULL == property_handle) { + Log_e("node's value is invalid!"); + continue; + } + + if (property_handle->property != NULL) { + if (update_value_if_key_match(control_str, property_handle->property)) { + if (property_handle->callback != NULL) { + property_handle->callback(pTemplate, control_str, strlen(control_str), + property_handle->property); + } + node = NULL; + } + } + } + + list_iterator_destroy(iter); + } + + IOT_FUNC_EXIT; +} + +static void _handle_template_reply_callback(Qcloud_IoT_Template *pTemplate, ListNode **node, List *list, + const char *pClientToken, const char *pType) +{ + IOT_FUNC_ENTRY; + + Request *request = (Request *)(*node)->val; + if (NULL == request) + IOT_FUNC_EXIT; + + if (strcmp(request->client_token, pClientToken) == 0) { + ReplyAck status = ACK_NONE; + + // check operation success or not according to code field of reply message + int32_t reply_code = 0; + + bool parse_success = parse_code_return(sg_template_cloud_rcv_buf, &reply_code); + if (parse_success) { + if (reply_code == 0) { + status = ACK_ACCEPTED; + } else { + status = ACK_REJECTED; + } + + if (strcmp(pType, GET_STATUS_REPLY) == 0 && status == ACK_ACCEPTED) { + char *control_str = NULL; + if (parse_template_get_control(sg_template_cloud_rcv_buf, &control_str)) { + Log_d("control data from get_status_reply"); + _set_control_clientToken(pClientToken); + if(NULL != pTemplate->usr_control_handle){ //call usr's cb if delta_handle registered,otherwise use _handle_delta + pTemplate->usr_control_handle(pTemplate, control_str, eGET_CTL); + }else{ + _handle_control(pTemplate, control_str); + } + HAL_Free(control_str); + *((ReplyAck *)request->user_context) = ACK_ACCEPTED; // prepare for clear_control + } + } + + if (request->callback != NULL) { + request->callback(pTemplate, request->method, status, sg_template_cloud_rcv_buf, request); + } + } else { + Log_e("parse template operation result code failed."); + } + + list_remove(list, *node); + *node = NULL; + } + + IOT_FUNC_EXIT; +} + +static void _on_template_downstream_topic_handler(void *pClient, MQTTMessage *message, void *pUserdata) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK_RTN(pClient); + POINTER_SANITY_CHECK_RTN(message); + Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)pUserdata; + + const char *topic = message->ptopic; + size_t topic_len = message->topic_len; + if (NULL == topic || topic_len <= 0) { + IOT_FUNC_EXIT; + } + + char *client_token = NULL; + char *type_str = NULL; + + if (message->payload_len > CLOUD_IOT_JSON_RX_BUF_LEN) { + Log_e("The length of the received message exceeds the specified length!"); + goto End; + } + + int cloud_rcv_len = min(CLOUD_IOT_JSON_RX_BUF_LEN - 1, message->payload_len); + memset(sg_template_cloud_rcv_buf, 0, sizeof(sg_template_cloud_rcv_buf)); + memcpy(sg_template_cloud_rcv_buf, message->payload, cloud_rcv_len + 1); + sg_template_cloud_rcv_buf[cloud_rcv_len] = '\0'; // jsmn_parse relies on a string + //Log_i("recv:%s", sg_template_cloud_rcv_buf); + + // parse the message type from topic $thing/down/property + if (!parse_template_method_type(sg_template_cloud_rcv_buf, &type_str)) { + Log_e("Fail to parse method!"); + goto End; + } + + if (!parse_client_token(sg_template_cloud_rcv_buf, &client_token)) { + Log_e("Fail to parse client token! Json=%s", sg_template_cloud_rcv_buf); + goto End; + } + + // handle control message + if (!strcmp(type_str, CONTROL_CMD)) { + HAL_MutexLock(template_client->mutex); + char *control_str = NULL; + if (parse_template_cmd_control(sg_template_cloud_rcv_buf, &control_str)) { + // Log_d("control_str:%s", control_str); + _set_control_clientToken(client_token); + if(NULL != template_client->usr_control_handle){ //call usr's cb if delta_handle registered,otherwise use _handle_delta + template_client->usr_control_handle(template_client, control_str, eOPERATION_CTL); + }else{ + _handle_control(template_client, control_str); + } + HAL_Free(control_str); + } + + HAL_MutexUnlock(template_client->mutex); + goto End; + } + + if (template_client != NULL) + _traverse_template_list(template_client, template_client->inner_data.reply_list, client_token, type_str, + _handle_template_reply_callback); + +End: + HAL_Free(type_str); + HAL_Free(client_token); + + IOT_FUNC_EXIT; +} + +int subscribe_template_downstream_topic(Qcloud_IoT_Template *pTemplate) +{ + IOT_FUNC_ENTRY; + + int rc; + int size; + + if (pTemplate->inner_data.downstream_topic == NULL) { + char *downstream_topic = (char *)HAL_Malloc(MAX_SIZE_OF_CLOUD_TOPIC * sizeof(char)); + if (downstream_topic == NULL) + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + + memset(downstream_topic, 0x0, MAX_SIZE_OF_CLOUD_TOPIC); + size = HAL_Snprintf(downstream_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/down/property/%s/%s", + pTemplate->device_info.product_id, pTemplate->device_info.device_name); + if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC - 1) { + Log_e("buf size < topic length!"); + HAL_Free(downstream_topic); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + pTemplate->inner_data.downstream_topic = downstream_topic; + } + + SubscribeParams subscribe_params = DEFAULT_SUB_PARAMS; + subscribe_params.on_message_handler = _on_template_downstream_topic_handler; + subscribe_params.qos = QOS0; + subscribe_params.user_data = pTemplate; + + rc = IOT_MQTT_Subscribe(pTemplate->mqtt, pTemplate->inner_data.downstream_topic, &subscribe_params); + if (rc < 0) { + Log_e("subscribe topic: %s failed: %d.", pTemplate->inner_data.downstream_topic, rc); + } + + IOT_FUNC_EXIT_RC(rc); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_event.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_event.c new file mode 100644 index 00000000..4ea42b8b --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/data_template_event.c @@ -0,0 +1,509 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "config.h" + +#if defined(EVENT_POST_ENABLED) +#include +#include +#include +#include + +#include "data_template_client.h" +#include "data_template_event.h" +#include "lite-utils.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_param_check.h" + +/** + * @brief iterator event list and call traverseHandle for each node + */ +static void _traverse_event_list(Qcloud_IoT_Template *pTemplate, List *list, const char *pClientToken, + MQTTMessage *message, eEventDealType eDealType) +{ + IOT_FUNC_ENTRY; + + HAL_MutexLock(pTemplate->mutex); + + if (list->len) { + ListIterator *iter; + ListNode * node = NULL; + + if (NULL == (iter = list_iterator_new(list, LIST_TAIL))) { + HAL_MutexUnlock(pTemplate->mutex); + IOT_FUNC_EXIT; + } + + for (;;) { + node = list_iterator_next(iter); + if (NULL == node) { + break; + } + + if (NULL == node->val) { + Log_e("node's value is invalid!"); + continue; + } + + sEventReply *pReply = (sEventReply *)node->val; + /*timeout check*/ + if (eDEAL_EXPIRED == eDealType) { + if (expired(&pReply->timer)) { + Log_e("eventToken[%s] timeout", pReply->client_token); + list_remove(list, node); + node = NULL; + } + } + + /*match event wait for reply by clientToken*/ + if ((eDEAL_REPLY_CB == eDealType) && (0 == strcmp(pClientToken, pReply->client_token))) { + if (NULL != pReply->callback) { + pReply->callback(pTemplate, message); + Log_d("eventToken[%s] released", pReply->client_token); + list_remove(list, node); + node = NULL; + } + } + } + + list_iterator_destroy(iter); + } + HAL_MutexUnlock(pTemplate->mutex); + + IOT_FUNC_EXIT; +} + +static void _on_event_reply_callback(void *pClient, MQTTMessage *message, void *userData) +{ + POINTER_SANITY_CHECK_RTN(message); + Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)userData; + + int32_t code; + char * client_token = NULL; + char * status = NULL; + + Log_d("recv:%.*s", (int)message->payload_len, (char *)message->payload); + + // parse clientToken from payload + if (!parse_client_token((char *)message->payload, &client_token)) { + Log_e("fail to parse client token!"); + return; + } + + // parse code from payload + if (!parse_code_return((char *)message->payload, &code)) { + HAL_Free(client_token); + Log_e("fail to parse code"); + return; + } + + if (!parse_status_return((char *)message->payload, &status)) { + // Log_d("no status return"); + } + + Log_d("eventToken:%s code:%d ", STRING_PTR_PRINT_SANITY_CHECK(client_token), code); + + if (template_client != NULL) + _traverse_event_list(template_client, template_client->inner_data.event_list, client_token, message, + eDEAL_REPLY_CB); + + HAL_Free(client_token); + HAL_Free(status); + + return; +} + +/** + * @brief create event reply struct and add to event_list + */ +static sEventReply *_create_event_add_to_list(Qcloud_IoT_Template *pTemplate, OnEventReplyCallback replyCb, + uint32_t reply_timeout_ms) +{ + IOT_FUNC_ENTRY; + + HAL_MutexLock(pTemplate->mutex); + if (pTemplate->inner_data.event_list->len >= MAX_EVENT_WAIT_REPLY) { + HAL_MutexUnlock(pTemplate->mutex); + Log_e("Too many event wait for reply"); + IOT_FUNC_EXIT_RC(NULL); + } + + sEventReply *pReply = (sEventReply *)HAL_Malloc(sizeof(sEventReply)); + if (NULL == pReply) { + HAL_MutexUnlock(pTemplate->mutex); + Log_e("run memory malloc is error!"); + IOT_FUNC_EXIT_RC(NULL); + } + + pReply->callback = replyCb; + pReply->user_context = pTemplate; + + InitTimer(&(pReply->timer)); + countdown(&(pReply->timer), reply_timeout_ms / 1000); + HAL_Snprintf(pReply->client_token, EVENT_TOKEN_MAX_LEN, "%s-%u", pTemplate->device_info.product_id, + pTemplate->inner_data.token_num++); + + ListNode *node = list_node_new(pReply); + if (NULL == node) { + HAL_MutexUnlock(pTemplate->mutex); + Log_e("run list_node_new is error!"); + HAL_Free(pReply); + IOT_FUNC_EXIT_RC(NULL); + } + + list_rpush(pTemplate->inner_data.event_list, node); + + HAL_MutexUnlock(pTemplate->mutex); + + IOT_FUNC_EXIT_RC(pReply); +} + +static int _iot_event_json_init(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t event_count, + OnEventReplyCallback replyCb, uint32_t reply_timeout_ms) +{ + POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)handle; + int32_t rc_of_snprintf; + sEventReply * pReply; + + pReply = _create_event_add_to_list(ptemplate, replyCb, reply_timeout_ms); + if (!pReply) { + Log_e("create event failed"); + return QCLOUD_ERR_FAILURE; + } + + memset(jsonBuffer, 0, sizeOfBuffer); + if (event_count > SIGLE_EVENT) { + rc_of_snprintf = HAL_Snprintf(jsonBuffer, sizeOfBuffer, "{\"method\":\"%s\", \"clientToken\":\"%s\", ", + POST_EVENTS, pReply->client_token); + } else { + rc_of_snprintf = HAL_Snprintf(jsonBuffer, sizeOfBuffer, "{\"method\":\"%s\", \"clientToken\":\"%s\", ", + POST_EVENT, pReply->client_token); + } + + return check_snprintf_return(rc_of_snprintf, sizeOfBuffer); +} + +static int _iot_construct_event_json(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t event_count, + sEvent *pEventArry[], OnEventReplyCallback replyCb, uint32_t reply_timeout_ms) +{ + size_t remain_size = 0; + int32_t rc_of_snprintf = 0; + uint8_t i, j; + Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)handle; + + POINTER_SANITY_CHECK(ptemplate, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(jsonBuffer, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pEventArry, QCLOUD_ERR_INVAL); + + int rc = _iot_event_json_init(ptemplate, jsonBuffer, sizeOfBuffer, event_count, replyCb, reply_timeout_ms); + + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("event json init failed: %d", rc); + return rc; + } + // Log_d("event_count:%d, Doc_init:%s",event_count, jsonBuffer); + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + if (event_count > SIGLE_EVENT) { // mutlti event + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"events\":["); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + for (i = 0; i < event_count; i++) { + sEvent *pEvent = pEventArry[i]; + if (NULL == pEvent) { + Log_e("%dth/%d null event", i, event_count); + return QCLOUD_ERR_INVAL; + } + + if (0 == pEvent->timestamp) { // no accurate UTC time, set 0 + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, + "{\"eventId\":\"%s\", \"type\":\"%s\", " + "\"timestamp\":0, \"params\":{", + STRING_PTR_PRINT_SANITY_CHECK(pEvent->event_name), + STRING_PTR_PRINT_SANITY_CHECK(pEvent->type)); + } else { // accurate UTC time is second,change to ms + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, + "{\"eventId\":\"%s\", \"type\":\"%s\", " + "\"timestamp\":%u000, \"params\":{", + STRING_PTR_PRINT_SANITY_CHECK(pEvent->event_name), + STRING_PTR_PRINT_SANITY_CHECK(pEvent->type), pEvent->timestamp); + } + + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + DeviceProperty *pJsonNode = pEvent->pEventData; + for (j = 0; j < pEvent->eventDataNum; j++) { + if (pJsonNode != NULL && pJsonNode->key != NULL) { + rc = template_put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, + pJsonNode->type); + + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + } else { + Log_e("%dth/%d null event property data", i, pEvent->eventDataNum); + return QCLOUD_ERR_INVAL; + } + pJsonNode++; + } + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "}},"); + + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + pEvent++; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "]"); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + } else { // single + sEvent *pEvent = pEventArry[0]; + if (0 == pEvent->timestamp) { // no accurate UTC time, set 0 + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, + "\"eventId\":\"%s\", \"type\":\"%s\", \"timestamp\":0, \"params\":{", + STRING_PTR_PRINT_SANITY_CHECK(pEvent->event_name), + STRING_PTR_PRINT_SANITY_CHECK(pEvent->type)); + } else { // accurate UTC time is second,change to ms + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, + "\"eventId\":\"%s\", \"type\":\"%s\", " + "\"timestamp\":%u000, \"params\":{", + STRING_PTR_PRINT_SANITY_CHECK(pEvent->event_name), + STRING_PTR_PRINT_SANITY_CHECK(pEvent->type), pEvent->timestamp); + } + + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + DeviceProperty *pJsonNode = pEvent->pEventData; + for (i = 0; i < pEvent->eventDataNum; i++) { + if (pJsonNode != NULL && pJsonNode->key != NULL) { + rc = template_put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type); + + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + } else { + Log_e("%dth/%d null event property data", i, pEvent->eventDataNum); + return QCLOUD_ERR_INVAL; + } + pJsonNode++; + } + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer) - 1, remain_size, "}"); + + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + } + + // finish json + if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) < 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "}"); + + return check_snprintf_return(rc_of_snprintf, remain_size); +} + +static int _publish_event_to_cloud(void *c, char *pJsonDoc) +{ + IOT_FUNC_ENTRY; + int rc = QCLOUD_RET_SUCCESS; + char topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0}; + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)c; + + int size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/up/event/%s/%s", pTemplate->device_info.product_id, + pTemplate->device_info.device_name); + if (size < 0 || size > sizeof(topic) - 1) { + Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic)); + return QCLOUD_ERR_FAILURE; + } + + PublishParams pubParams = DEFAULT_PUB_PARAMS; + pubParams.qos = QOS1; + pubParams.payload_len = strlen(pJsonDoc); + pubParams.payload = (char *)pJsonDoc; + + rc = IOT_MQTT_Publish(pTemplate->mqtt, topic, &pubParams); + + IOT_FUNC_EXIT_RC(rc); +} + +void handle_template_expired_event(void *client) +{ + IOT_FUNC_ENTRY; + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)client; + + _traverse_event_list(pTemplate, pTemplate->inner_data.event_list, NULL, NULL, eDEAL_EXPIRED); + + IOT_FUNC_EXIT; +} + +void IOT_Event_setFlag(void *client, uint32_t flag) +{ + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)client; + + pTemplate->inner_data.eventflags |= flag & 0xffffffff; +} + +void IOT_Event_clearFlag(void *client, uint32_t flag) +{ + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)client; + + pTemplate->inner_data.eventflags &= (~flag) & 0xffffffff; +} + +uint32_t IOT_Event_getFlag(void *client) +{ + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)client; + + return pTemplate->inner_data.eventflags; +} + +int IOT_Event_Init(void *c) +{ + static char topic_name[MAX_SIZE_OF_CLOUD_TOPIC] = {0}; + Qcloud_IoT_Template *pTemplate = (Qcloud_IoT_Template *)c; + + int size = HAL_Snprintf(topic_name, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/down/event/%s/%s", + pTemplate->device_info.product_id, pTemplate->device_info.device_name); + + if (size < 0 || size > sizeof(topic_name) - 1) { + Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name)); + return QCLOUD_ERR_FAILURE; + } + SubscribeParams sub_params = DEFAULT_SUB_PARAMS; + sub_params.on_message_handler = _on_event_reply_callback; + sub_params.user_data = pTemplate; + + return IOT_MQTT_Subscribe(pTemplate->mqtt, topic_name, &sub_params); +} + +int IOT_Post_Event(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, uint8_t event_count, sEvent *pEventArry[], + OnEventReplyCallback replyCb) +{ + int rc; + + rc = _iot_construct_event_json(pClient, pJsonDoc, sizeOfBuffer, event_count, pEventArry, replyCb, + QCLOUD_IOT_MQTT_COMMAND_TIMEOUT); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("construct event json fail, %d", rc); + return rc; + } + + rc = _publish_event_to_cloud(pClient, pJsonDoc); + if (rc < 0) { + Log_e("publish event to cloud fail, %d", rc); + } + + return rc; +} + +int IOT_Post_Event_Raw(void *pClient, char *pJsonDoc, size_t sizeOfBuffer, char *pEventMsg, + OnEventReplyCallback replyCb) +{ + int rc; + size_t remain_size = 0; + int32_t rc_of_snprintf; + + Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)pClient; + + POINTER_SANITY_CHECK(ptemplate, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pEventMsg, QCLOUD_ERR_INVAL); + + rc = _iot_event_json_init(ptemplate, pJsonDoc, sizeOfBuffer, MUTLTI_EVENTS, replyCb, + QCLOUD_IOT_MQTT_COMMAND_TIMEOUT); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("event json init failed: %d", rc); + return rc; + } + + if ((remain_size = sizeOfBuffer - strlen(pJsonDoc)) <= 1) { + return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL; + } + + rc_of_snprintf = HAL_Snprintf(pJsonDoc + strlen(pJsonDoc), remain_size, "\"events\":[%s]}", pEventMsg); + rc = check_snprintf_return(rc_of_snprintf, remain_size); + if (rc != QCLOUD_RET_SUCCESS) { + return rc; + } + + Log_d("JsonDoc:%s", pJsonDoc); + + rc = _publish_event_to_cloud(pClient, pJsonDoc); + if (rc < 0) { + Log_e("publish event raw to cloud fail, %d", rc); + } + + return rc; +} + +#endif +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/dynreg.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/dynreg.c new file mode 100644 index 00000000..274e0a7c --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/dynreg.c @@ -0,0 +1,501 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lite-utils.h" +#include "qcloud_iot_ca.h" +#include "qcloud_iot_common.h" +#include "qcloud_iot_device.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_aes.h" +#include "qutils_base64.h" +#include "qutils_hmac.h" +#include "qutils_httpc.h" + +#define REG_URL_MAX_LEN (128) +#define DYN_REG_SIGN_LEN (64) +#define DYN_BUFF_DATA_MORE (10) +#define BASE64_ENCODE_OUT_LEN(x) (((x + 3) * 4) / 3) +#define DYN_REG_RES_HTTP_TIMEOUT_MS (2000) + +#ifdef AUTH_MODE_CERT +#define DYN_RESPONSE_BUFF_LEN (5 * 1024) +#define DECODE_BUFF_LEN (5 * 1024) +#else +#define DYN_RESPONSE_BUFF_LEN (256) +#define DECODE_BUFF_LEN (256) +#endif + +/* Knuth's TAOCP section 3.6 */ +#define M ((1U << 31) - 1) +#define A 48271 +#define Q 44488 // M/A +#define R 3399 // M%A; R < Q !!! + +#define CODE_RESAULT "code" +#define ENCRYPT_TYPE "encryptionType" +#define PSK_DATA "psk" +#define CERT_DATA "clientCert" +#define KEY_DATA "clientKey" + +typedef enum { + eCERT_TYPE = 1, + ePSK_TYPE = 2, +} eAuthType; + +/*Global value*/ +static unsigned int _seed = 1; + +int rand_r(unsigned int *seed) +{ + int32_t X; + + X = *seed; + X = A * (X % Q) - R * (int32_t)(X / Q); + if (X < 0) + X += M; + + *seed = X; + return X; +} + +int rand_d(void) +{ + return rand_r(&_seed); +} + +void srand_d(unsigned int i) +{ + _seed = i; +} + +static int _get_json_result_code(char *json) +{ + int resault = -1; + char *v = LITE_json_value_of(CODE_RESAULT, json); + + if (v == NULL) { + Log_e("Invalid json content: %s", STRING_PTR_PRINT_SANITY_CHECK(json)); + return -1; + } + + if (LITE_get_int32(&resault, v) != QCLOUD_RET_SUCCESS) { + Log_e("Invalid json content: %s", STRING_PTR_PRINT_SANITY_CHECK(json)); + HAL_Free(v); + return -1; + } + + HAL_Free(v); + + return resault; +} + +static int _get_json_encry_type(char *json) +{ + int type = -1; + char *v = LITE_json_value_of(ENCRYPT_TYPE, json); + + if (v == NULL) { + Log_e("Get encry type fail, %s", STRING_PTR_PRINT_SANITY_CHECK(json)); + return -1; + } + + if (LITE_get_int32(&type, v) != QCLOUD_RET_SUCCESS) { + Log_e("Invalid json content: %s", STRING_PTR_PRINT_SANITY_CHECK(json)); + HAL_Free(v); + return -1; + } + + HAL_Free(v); + + return type; +} + +#ifndef AUTH_MODE_CERT + +static char *_get_json_psk(char *json) +{ + char *psk = LITE_json_value_of(PSK_DATA, json); + + if (psk == NULL) { + Log_e("Get psk fail: %s", STRING_PTR_PRINT_SANITY_CHECK(json)); + } + + return psk; +} + +#else +static char *_get_json_cert_data(char *json) +{ + char *cert = LITE_json_value_of(CERT_DATA, json); + + if (cert == NULL) { + Log_e("Get clientCert fail: %s", STRING_PTR_PRINT_SANITY_CHECK(json)); + } + + return cert; +} + +static char *_get_json_key_data(char *json) +{ + char *key = LITE_json_value_of(KEY_DATA, json); + + if (key == NULL) { + Log_e("Get clientCert fail: %s", STRING_PTR_PRINT_SANITY_CHECK(json)); + } + + return key; +} + +/*\\n in data change to '\n'*/ +static void _deal_transfer(char *data, uint32_t dataLen) +{ + int i; + + for (i = 0; i < dataLen; i++) { + if ((data[i] == '\\') && (data[i + 1] == 'n')) { + data[i] = ' '; + data[i + 1] = '\n'; + } + } +} + +static int _cert_file_save(const char *fileName, char *data, uint32_t dataLen) +{ + void * fp; + char filePath[FILE_PATH_MAX_LEN]; + uint32_t len; + int Ret = QCLOUD_ERR_FAILURE; + + memset(filePath, 0, FILE_PATH_MAX_LEN); + HAL_Snprintf(filePath, FILE_PATH_MAX_LEN, "./certs/%s", STRING_PTR_PRINT_SANITY_CHECK(fileName)); + + if ((fp = HAL_FileOpen(filePath, "w+")) == NULL) { + Log_e("fail to open file %s", STRING_PTR_PRINT_SANITY_CHECK(fileName)); + goto exit; + } + + _deal_transfer(data, dataLen); + len = fprintf(fp, "%s", STRING_PTR_PRINT_SANITY_CHECK(data)); + HAL_FileClose(fp); + + if (len == dataLen) { + Log_d("save %s file succes", STRING_PTR_PRINT_SANITY_CHECK(fileName)); + Ret = QCLOUD_RET_SUCCESS; + } + +exit: + return Ret; +} + +#endif + +static int _parse_devinfo(char *jdoc, DeviceInfo *pDevInfo) +{ + int ret = 0; + size_t len; + int datalen; + int enType; + unsigned int keybits; + char key[UTILS_AES_BLOCK_LEN + 1]; + char decodeBuff[DECODE_BUFF_LEN] = {0}; + unsigned char iv[16]; + char * payload = NULL; + +#ifdef AUTH_MODE_CERT + char *clientCert; + char *clientKey; +#else + char *psk; +#endif + + Log_d("recv: %s", STRING_PTR_PRINT_SANITY_CHECK(jdoc)); + + ret = _get_json_result_code(jdoc); + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("response err, ret:%d", ret); + goto exit; + } + + payload = LITE_json_value_of("payload", jdoc); + if (payload == NULL) { + Log_e("Invalid json content: %s", jdoc); + ret = QCLOUD_ERR_FAILURE; + goto exit; + } else { + Log_d("payload:%s", payload); + } + + ret = qcloud_iot_utils_base64decode((uint8_t *)decodeBuff, sizeof(decodeBuff), &len, (uint8_t *)payload, + strlen(payload)); + if (ret != QCLOUD_RET_SUCCESS) { + Log_e("Response decode err, response:%s", payload); + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + + datalen = len + (UTILS_AES_BLOCK_LEN - len % UTILS_AES_BLOCK_LEN); + keybits = AES_KEY_BITS_128; + memset(key, 0, UTILS_AES_BLOCK_LEN); + strncpy(key, pDevInfo->product_secret, UTILS_AES_BLOCK_LEN); + memset(iv, '0', UTILS_AES_BLOCK_LEN); + ret = utils_aes_cbc((uint8_t *)decodeBuff, datalen, (uint8_t *)decodeBuff, DECODE_BUFF_LEN, UTILS_AES_DECRYPT, + (uint8_t *)key, keybits, iv); + if (QCLOUD_RET_SUCCESS == ret) { + // Log_d("The decrypted data is:%s", decodeBuff); + + } else { + Log_e("data decry err,ret:%d", ret); + goto exit; + } + + enType = _get_json_encry_type(decodeBuff); + if (enType < 0) { + Log_e("invlid encryt type, decrypt maybe faild"); + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + +#ifdef AUTH_MODE_CERT + if (eCERT_TYPE != enType) { + Log_e("encryt type should be cert type"); + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + + clientCert = _get_json_cert_data(decodeBuff); + if (NULL != clientCert) { + memset(pDevInfo->dev_cert_file_name, 0, MAX_SIZE_OF_DEVICE_CERT_FILE_NAME); + HAL_Snprintf(pDevInfo->dev_cert_file_name, MAX_SIZE_OF_DEVICE_CERT_FILE_NAME, "%s_cert.crt", + pDevInfo->device_name); + if (QCLOUD_RET_SUCCESS != _cert_file_save(pDevInfo->dev_cert_file_name, clientCert, strlen(clientCert))) { + Log_e("save %s file fail", pDevInfo->dev_cert_file_name); + ret = QCLOUD_ERR_FAILURE; + } + + HAL_Free(clientCert); + + } else { + Log_e("Get clientCert data fail"); + ret = QCLOUD_ERR_FAILURE; + } + + clientKey = _get_json_key_data(decodeBuff); + if (NULL != clientKey) { + memset(pDevInfo->dev_key_file_name, 0, MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME); + HAL_Snprintf(pDevInfo->dev_key_file_name, MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME, "%s_private.key", + pDevInfo->device_name); + if (QCLOUD_RET_SUCCESS != _cert_file_save(pDevInfo->dev_key_file_name, clientKey, strlen(clientKey))) { + Log_e("save %s file fail", pDevInfo->dev_key_file_name); + ret = QCLOUD_ERR_FAILURE; + } + + HAL_Free(clientKey); + + } else { + Log_e("Get clientCert data fail"); + ret = QCLOUD_ERR_FAILURE; + } + +#else + if (ePSK_TYPE != enType) { + Log_e("encryt type should be psk type"); + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + + psk = _get_json_psk(decodeBuff); + if (NULL != psk) { + if (strlen(psk) > MAX_SIZE_OF_DEVICE_SECRET) { + Log_e("psk exceed max len,%s", psk); + strcpy(pDevInfo->device_secret, psk); + } else { + strncpy(pDevInfo->device_secret, psk, MAX_SIZE_OF_DEVICE_SECRET); + pDevInfo->device_secret[MAX_SIZE_OF_DEVICE_SECRET] = '\0'; + } + HAL_Free(psk); + } else { + Log_e("Get psk data fail"); + } +#endif +exit: + + if (payload) { + HAL_Free(payload); + } + + return ret; +} + +static int _post_reg_request_by_http(char *request_buf, DeviceInfo *pDevInfo) +{ + int Ret = 0; + HTTPClient http_client; /* http client */ + HTTPClientData http_data; /* http client data */ + + const char *url_format = "%s://%s/register/dev"; + char url[REG_URL_MAX_LEN] = {0}; + int port; + const char *ca_crt = NULL; + char respbuff[DYN_RESPONSE_BUFF_LEN]; + +/*format URL*/ +#ifndef AUTH_WITH_NOTLS + HAL_Snprintf(url, REG_URL_MAX_LEN, url_format, "https", + STRING_PTR_PRINT_SANITY_CHECK(iot_get_dyn_reg_domain(pDevInfo->region))); + port = DYN_REG_SERVER_PORT_TLS; + ca_crt = iot_ca_get(); +#else + HAL_Snprintf(url, REG_URL_MAX_LEN, url_format, "http", + STRING_PTR_PRINT_SANITY_CHECK(iot_get_dyn_reg_domain(pDevInfo->region))); + port = DYN_REG_SERVER_PORT; +#endif + + memset((char *)&http_client, 0, sizeof(HTTPClient)); + memset((char *)&http_data, 0, sizeof(HTTPClientData)); + + http_client.header = "Accept: text/xml,application/json;*/*\r\n"; + + http_data.post_content_type = "application/x-www-form-urlencoded"; + http_data.post_buf = request_buf; + http_data.post_buf_len = strlen(request_buf); + + Ret = qcloud_http_client_common(&http_client, url, port, ca_crt, HTTP_POST, &http_data); + if (QCLOUD_RET_SUCCESS != Ret) { + Log_e("qcloud_http_client_common failed, Ret = %d", Ret); + return Ret; + } + + memset(respbuff, 0, DYN_RESPONSE_BUFF_LEN); + http_data.response_buf_len = DYN_RESPONSE_BUFF_LEN; + http_data.response_buf = respbuff; + + Ret = qcloud_http_recv_data(&http_client, DYN_REG_RES_HTTP_TIMEOUT_MS, &http_data); + if (QCLOUD_RET_SUCCESS != Ret) { + Log_e("dynamic register response fail, Ret = %d", Ret); + } else { + /*Parse dev info*/ + Ret = _parse_devinfo(http_data.response_buf, pDevInfo); + if (QCLOUD_RET_SUCCESS != Ret) { + Log_e("parse device info err"); + } + } + + qcloud_http_client_close(&http_client); + + return Ret; +} + +static int _cal_dynreg_sign(DeviceInfo *pDevInfo, char *signout, int max_signlen, int nonce, uint32_t timestamp) +{ + int sign_len; + size_t olen = 0; + char * pSignSource = NULL; + const char *sign_fmt = "deviceName=%s&nonce=%d&productId=%s×tamp=%d"; + char sign[DYN_REG_SIGN_LEN] = {0}; + + /*format sign data*/ + sign_len = strlen(sign_fmt) + strlen(pDevInfo->device_name) + strlen(pDevInfo->product_id) + sizeof(int) + + sizeof(uint32_t) + DYN_BUFF_DATA_MORE; + pSignSource = HAL_Malloc(sign_len); + if (pSignSource == NULL) { + Log_e("malloc sign source buff fail"); + return QCLOUD_ERR_FAILURE; + } + memset(pSignSource, 0, sign_len); + HAL_Snprintf((char *)pSignSource, sign_len, sign_fmt, pDevInfo->device_name, nonce, pDevInfo->product_id, + timestamp); + + /*cal hmac sha1*/ + utils_hmac_sha1(pSignSource, strlen(pSignSource), sign, pDevInfo->product_secret, strlen(pDevInfo->product_secret)); + + /*base64 encode*/ + qcloud_iot_utils_base64encode((uint8_t *)signout, max_signlen, &olen, (const uint8_t *)sign, strlen(sign)); + + HAL_Free(pSignSource); + + return (olen > max_signlen) ? QCLOUD_ERR_FAILURE : QCLOUD_RET_SUCCESS; +} + +int IOT_DynReg_Device(DeviceInfo *pDevInfo) +{ + const char *para_format = + "{\"deviceName\":\"%s\",\"nonce\":%d,\"productId\":\"%s\",\"timestamp\":%d,\"signature\":\"%s\"}"; + int nonce; + int Ret; + uint32_t timestamp; + int len; + char sign[DYN_REG_SIGN_LEN] = {0}; + char * pRequest = NULL; + + if (strlen(pDevInfo->product_secret) < UTILS_AES_BLOCK_LEN) { + Log_e("product key inllegal"); + return QCLOUD_ERR_FAILURE; + } + + srand_d(HAL_GetTimeMs()); + nonce = rand_d(); + timestamp = time(0); + + /*cal sign*/ + if (QCLOUD_RET_SUCCESS == _cal_dynreg_sign(pDevInfo, sign, DYN_REG_SIGN_LEN, nonce, timestamp)) { + Log_d("sign:%s", sign); + } else { + Log_e("cal sign fail"); + return QCLOUD_ERR_FAILURE; + } + + /*format http request*/ + len = strlen(para_format) + strlen(pDevInfo->product_id) + strlen(pDevInfo->device_name) + sizeof(int) + + sizeof(uint32_t) + strlen(sign) + DYN_BUFF_DATA_MORE; + pRequest = HAL_Malloc(len); + if (!pRequest) { + Log_e("malloc request memory fail"); + return QCLOUD_ERR_FAILURE; + } + memset(pRequest, 0, len); + HAL_Snprintf(pRequest, len, para_format, pDevInfo->device_name, nonce, pDevInfo->product_id, timestamp, sign); + Log_d("request:%s", pRequest); + /*post request*/ + Ret = _post_reg_request_by_http(pRequest, pDevInfo); + if (QCLOUD_RET_SUCCESS == Ret) { + Log_d("request dev info success"); + } else { + Log_e("request dev info fail"); + } + + HAL_Free(pRequest); + + return Ret; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/asr_client.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/asr_client.h new file mode 100644 index 00000000..e0e7de1c --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/asr_client.h @@ -0,0 +1,43 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef __ASR_CLIENT_H__ +#define __ASR_CLIENT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_ASR_REQUEST (20) +#define DEFAULT_REQ_TIMEOUT_MS (5000) +#define ASR_REQUEST_BUFF_LEN (512) + +typedef enum { + eASR_REQ_IDLE = 0, + eASR_REQ_INIT = 1, + eASR_REQ_DONE = 2, +} eAsrReqState; + +#ifdef __cplusplus +} +#endif + +#endif /* __AT_H__ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_client.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_client.h new file mode 100644 index 00000000..52b7bc37 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_client.h @@ -0,0 +1,171 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef __AT_CLIENT_H__ +#define __AT_CLIENT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "config.h" +#include "stddef.h" +#include "qutils_ringbuff.h" + +#define AT_FRAME_VERSION "1.0.0" + +#define AT_CMD_NAME_LEN 16 +#define AT_END_MARK_LEN 4 + +#define CLINET_BUFF_LEN (1024) +#define RING_BUFF_LEN CLINET_BUFF_LEN // uart ring buffer len +#define GET_CHAR_TIMEOUT_MS (5000) +#define CMD_RESPONSE_INTERVAL_MS (100) + +typedef void (*ParserFunc)(void *userContex); + +typedef enum { + AT_STATUS_UNINITIALIZED = 0, + AT_STATUS_INITIALIZED = 0x55, + AT_STATUS_BUSY = 0xaa, +} at_status; + +enum at_resp_status { + AT_RESP_OK = 0, /* AT response end is OK */ + AT_RESP_ERROR = -1, /* AT response end is ERROR */ + AT_RESP_TIMEOUT = -2, /* AT response is timeout */ + AT_RESP_BUFF_FULL = -3, /* AT response buffer is full */ +}; + +typedef enum at_resp_status at_resp_status_t; + +typedef struct _at_response_ { + /* response buffer */ + char *buf; + /* the maximum response buffer size */ + int buf_size; + /* the number of setting response lines + * == 0: the response data will auto return when received 'OK' or 'ERROR' + * != 0: the response data will return when received setting lines number data + */ + int line_num; + /* the count of received response lines */ + int line_counts; + /* the maximum response time */ + uint32_t timeout; +} at_response; + +typedef at_response *at_response_t; + +/* URC(Unsolicited Result Code) object, such as: 'RING', 'READY' request by AT + * server */ +typedef struct _at_urc_ { + const char *cmd_prefix; + const char *cmd_suffix; + void (*func)(const char *data, size_t size); +} at_urc; + +typedef at_urc *at_urc_t; + +typedef struct _at_client_ { + at_status status; + char end_sign; + + ring_buff_t pRingBuff; + + char * recv_buffer; + uint32_t recv_bufsz; + uint32_t cur_recv_len; + void * lock; // pre cmd take the lock wait for resp , another cmd need wait for + // unlock + + at_response_t resp; + at_resp_status_t resp_status; + + const at_urc *urc_table; + uint16_t urc_table_size; + +#ifdef AT_OS_USED + void * resp_sem; // resp received, send sem to notic ack wait + ParserFunc parser; // RX parser +#else +// bool resp_notice; +#endif +} at_client; + +typedef at_client *at_client_t; + +/* AT client initialize and start*/ +int at_client_init(at_client_t *pClient); + +/* AT client deinitial*/ +int at_client_deinit(at_client_t pClient); + +/* get AT client handle*/ +at_client_t at_client_get(void); + +/*AT connect detect*/ +int at_client_wait_connect(uint32_t timeout); + +/*wrapper for os and nonos delay*/ +void at_delayms(uint32_t delayms); +void at_setFlag(uint32_t flag); +void at_clearFlag(uint32_t flag); +uint32_t at_getFlag(void); +bool at_waitFlag(uint32_t flag, uint32_t timeout); + +/* ========================== multiple AT client function + * ============================ */ +/* set AT client a line end sign */ +void at_set_end_sign(char ch); + +/* Set URC(Unsolicited Result Code) table */ +void at_set_urc_table(at_client_t client, const at_urc_t table, uint32_t size); + +/* AT client send or receive data */ +int at_client_send(at_client_t client, const char *buf, int size, uint32_t timeout); +int at_client_obj_recv(char *buf, int size, int timeout); + +/* AT client send commands to AT server and waiter response */ +int at_obj_exec_cmd(at_response_t resp, const char *cmd_expr, ...); + +#define at_exec_cmd(resp, ...) at_obj_exec_cmd(resp, __VA_ARGS__) +#define at_client_recv(buf, size, timeout) at_client_obj_recv(buf, size, timeout) + +/* AT response object create and delete */ +at_response_t at_create_resp(uint32_t buf_size, uint32_t line_num, uint32_t timeout); +void at_delete_resp(at_response_t resp); + +/* AT response line buffer get and parse response buffer arguments */ +const char *at_resp_get_line(at_response_t resp, uint32_t resp_line); +const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword); +int at_resp_parse_line_args(at_response_t resp, uint32_t resp_line, const char *resp_expr, ...); +int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...); + +/* ========================== single AT client function + * ============================ */ +void at_client_yeild(at_urc *expect_urc, uint32_t timeout); + +#ifdef __cplusplus +} +#endif + +#endif /* __AT_H__ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_socket_inf.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_socket_inf.h new file mode 100644 index 00000000..e325508d --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_socket_inf.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019-2021 Tencent Group. All rights reserved. + * License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _AT_SOCKET_INF_H_ +#define _AT_SOCKET_INF_H_ + +#include +#include + +#include "qutils_list.h" + +#define UNUSED_SOCKET (-1) +#define MAX_AT_SOCKET_NUM (5) +#define AT_SOCKET_SEND_TIMEOUT_MS (1000) +#define AT_SOCKET_RECV_TIMEOUT_MS (1000) +#define IPV4_STR_MAX_LEN (16) + +typedef enum { eNET_TCP = 6, eNET_UDP = 17, eNET_DEFAULT = 0xff } eNetProto; + +typedef enum { eSOCKET_ALLOCED = 0, eSOCKET_CONNECTED, eSOCKET_CLOSED } eSocketState; + +/* AT receive package list structure */ +typedef struct at_recv_pkt { + List list; + size_t bfsz_totle; + size_t bfsz_index; + char * buff; +} at_recv_pkt; + +typedef enum { + AT_SOCKET_EVT_RECV = 0, + AT_SOCKET_EVT_CLOSED, +} at_socket_evt_t; + +typedef void (*at_evt_cb_t)(int fd, at_socket_evt_t event, char *buff, size_t bfsz); + +/*at device driver ops, use at_device_op_register register to at socket*/ +typedef struct { + int (*init)(void); + int (*get_local_mac)(char *macbuff, size_t bufflen); + int (*get_local_ip)(char *ip, size_t iplen, char *gw, size_t gwlen, char *mask, size_t masklen); + int (*parse_domain)(const char *host_name, char *host_ip, size_t host_ip_len); + int (*connect)(const char *ip, uint16_t port, eNetProto proto); + int (*send)(int fd, const void *buf, size_t len); + int (*recv_timeout)(int fd, void *buf, size_t len, uint32_t timeout); + int (*close)(int fd); + void (*set_event_cb)(at_socket_evt_t event, at_evt_cb_t cb); + char *deviceName; +} at_device_op_t; + +/*at socket context*/ +typedef struct { + int fd; /** socket fd */ + List * recvpkt_list; + char remote_ip[IPV4_STR_MAX_LEN]; + uint16_t remote_port; + uint32_t send_timeout_ms; + uint32_t recv_timeout_ms; + void * recv_lock; + at_device_op_t *dev_op; + eNetProto net_type; + eSocketState state; +} at_socket_ctx_t; + +// at socket api +int at_device_op_register(at_device_op_t *device_op); +int at_socket_init(void); +int at_socket_parse_domain(const char *host_name, char *host_ip, size_t host_ip_len); +int at_socket_get_local_mac(char *macbuff, size_t bufflen); +int at_socket_get_local_ip(char *ip, size_t iplen, char *gw, size_t gwlen, char *mask, size_t masklen); +int at_socket_connect(const char *host, uint16_t port, eNetProto eProto); +int at_socket_close(int fd); +int at_socket_send(int fd, const void *buf, size_t len); +int at_socket_recv(int fd, void *buf, size_t len); +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_uart_hal.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_uart_hal.h new file mode 100644 index 00000000..aa00f5b3 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_uart_hal.h @@ -0,0 +1,108 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef __AT_UART_HAL_H__ +#define __AT_UART_HAL_H__ + +/* + * UART data width + */ +typedef enum { + BAUDRATE_2400 = 2400, + BAUDRATE_4800 = 4800, + BAUDRATE_9600 = 9600, + BAUDRATE_19200 = 19200, + BAUDRATE_115200 = 115200, + BAUDRATE_921600 = 921600, + BAUDRATE_DEFAULT = 115200 +} hal_uart_baudr_t; + +/* + * UART data width + */ +typedef enum { + DATA_WIDTH_5BIT, + DATA_WIDTH_6BIT, + DATA_WIDTH_7BIT, + DATA_WIDTH_8BIT, + DATA_WIDTH_9BIT +} hal_uart_data_width_t; + +/* + * UART stop bits + */ +typedef enum { STOP_BITS_1, STOP_BITS_2 } hal_uart_stop_bits_t; + +/* + * UART flow control + */ +typedef enum { + FLOW_CONTROL_DISABLED, + FLOW_CONTROL_CTS, + FLOW_CONTROL_RTS, + FLOW_CONTROL_CTS_RTS +} hal_uart_flow_control_t; + +/* + * UART parity + */ +typedef enum { NO_PARITY, ODD_PARITY, EVEN_PARITY } hal_uart_parity_t; + +/* + * UART mode + */ +typedef enum { MODE_TX, MODE_RX, MODE_TX_RX } hal_uart_mode_t; + +/* + * UART state + */ +typedef enum { + eUNUSED = 0, + eOPENED = 1, + eCLOSED = 2, +} hal_uart_state_t; + +/* + * UART configuration + */ +typedef struct { + uint32_t baud_rate; + hal_uart_data_width_t data_width; + hal_uart_parity_t parity; + hal_uart_stop_bits_t stop_bits; + hal_uart_flow_control_t flow_control; + hal_uart_mode_t mode; +} uart_config_t; + +typedef struct { +#ifdef __linux__ + int fd; /* uart fd */ +#else + void *uart_handle; /* uart handle,like stm32 UART_HandleTypeDef */ +#endif + hal_uart_state_t state; /* uart state */ + uart_config_t config; /* uart config */ +} uart_dev_t; + +#ifdef __cplusplus +} +#endif + +#endif /* __AT_H__ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_utils.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_utils.h new file mode 100644 index 00000000..53cc744f --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/at_utils.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019-2021 Tencent Group. All rights reserved. + * License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _AT_UTILS_H_ +#define _AT_UTILS_H_ + +#include +#include +#include + +#define WIDTH_SIZE 32 + +#ifndef __INT_MAX__ +#define __INT_MAX__ 2147483647 +#endif + +#ifndef INT_MAX +#define INT_MAX (__INT_MAX__) +#endif + +#define AT_CMD_COMMA_MARK ',' +#define AT_CMD_DQUOTES_MARK '"' + +#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ') + +int at_vprintfln(const char *format, va_list args); +void at_print_raw_cmd(const char *name, const char *cmd, int size); +const char *at_get_last_cmd(int *cmd_size); +int at_req_parse_args(const char *req_args, const char *req_expr, ...); +int at_sscanf(const char *buf, const char *fmt, va_list args); +void at_strip(char *str, const char patten); +void chr_strip(char *str, const char patten); + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_action.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_action.h new file mode 100644 index 00000000..516cc200 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_action.h @@ -0,0 +1,52 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef _DATA_TEMPLATE_ACTION_H_ +#define _DATA_TEMPLATE_ACTION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#define ACTION_NAME_MAX_LEN (20) // action name max len +#define ACTION_TOKEN_MAX_LEN (32) // action token max len + +#define MAX_ACTION_WAIT_REPLY (10) +#define ACTION_MAX_DATA_NUM (255) // input or output max data num + +#define REPORT_ACTION "action_reply" +#define CALL_ACTION "action" + +int IOT_Action_Init(void *c); + +int IOT_Action_Register(void *pTemplate, DeviceAction *pAction, OnActionHandleCallback callback); + +int IOT_Action_Remove(void *ptemplate, DeviceAction *pAction); + +#ifdef __cplusplus +} +#endif + +#endif //_DATA_TEMPLATE_ACTION_H_ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_client.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_client.h new file mode 100644 index 00000000..6e7faf25 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_client.h @@ -0,0 +1,126 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +/** + * @brief API of data_template + * + */ +#ifndef IOT_TEMPLATE_CLIENT_H_ +#define IOT_TEMPLATE_CLIENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "data_template_client_json.h" +#include "mqtt_client.h" +#include "qcloud_iot_device.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_param_check.h" + +#define MAX_CLEAE_DOC_LEN 256 + +typedef struct _TemplateInnerData { + uint32_t token_num; + int32_t sync_status; + uint32_t eventflags; + List * event_list; + List * reply_list; + List * action_handle_list; + List * property_handle_list; + char * upstream_topic; // upstream topic + char * downstream_topic; // downstream topic +} TemplateInnerData; + +typedef struct _Template { + void * mqtt; + void * mutex; + void * pDataTemplate; + DeviceInfo device_info; + MQTTEventHandler event_handle; + TemplateInnerData inner_data; + DataTemplateDestroyCb DataTemplateDestroyCb; + ControlMsgCb usr_control_handle; + +#ifdef MULTITHREAD_ENABLED + bool yield_thread_running; + int yield_thread_exit_code; +#endif +} Qcloud_IoT_Template; + +/** + * @brief init data template client + * + * @param pTemplate handle to data_template client + */ +int qcloud_iot_template_init(Qcloud_IoT_Template *pTemplate); + +/** + * @brief deinit data template client list and topics + * + * @param pClient data template client + */ + +void qcloud_iot_template_reset(Qcloud_IoT_Template *pTemplate); + +/** + * @brief deal upstream msg wait for reply timeout + * + * @param pTemplate data template client + */ +void handle_template_expired_reply(Qcloud_IoT_Template *pTemplate); + +/** + * @brief get the clientToken of control message for control_reply + * + * @param void + * @return clientToken + */ +char *get_control_clientToken(void); + +/** + * @brief all the upstream data by the way of request + * + * @param pTemplate handle to data_template client + * @param pParams request params + * @param pJsonDoc data buffer for request + * @param sizeOfBuffer length of data buffer + * @return QCLOUD_RET_SUCCESS when success, or err code for + * failure + */ +int send_template_request(Qcloud_IoT_Template *pTemplate, RequestParams *pParams, char *pJsonDoc, size_t sizeOfBuffer); + +/** + * @brief subscribe data_template topic $thing/down/property/%s/%s + * + * @param pShadow shadow client + * @return QCLOUD_RET_SUCCESS for success, or err code for + * failure + */ +int subscribe_template_downstream_topic(Qcloud_IoT_Template *pTemplate); + +#ifdef __cplusplus +} +#endif + +#endif /* IOT_TEMPLATE_CLIENT_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_client_common.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_client_common.h new file mode 100644 index 00000000..284b9b31 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_client_common.h @@ -0,0 +1,64 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_DATA_TEMPLATE_CLIENT_COMMON_H_ +#define IOT_DATA_TEMPLATE_CLIENT_COMMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "data_template_client.h" + +/** + * @brief register a device property + * + * @param pTemplate handle to data_template client + * @param pProperty device property + * @param callback callback when property changes + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ + +int template_common_register_property_on_delta(Qcloud_IoT_Template *pTemplate, DeviceProperty *pProperty, + OnPropRegCallback callback); + +/** + * @brief remove a device property + * + * @param pTemplate handle to data_template client + * @param pProperty device property + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int template_common_remove_property(Qcloud_IoT_Template *ptemplate, DeviceProperty *pProperty); + +/** + * @brief check if a device property exists + * + * @param pShadow handle to data_template client + * @param pProperty device property + * @return 0 = not existed + */ +int template_common_check_property_existence(Qcloud_IoT_Template *ptemplate, DeviceProperty *pProperty); + +#ifdef __cplusplus +} +#endif + +#endif // IOT_DATA_TEMPLATE_CLIENT_COMMON_H_ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_client_json.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_client_json.h new file mode 100644 index 00000000..02c15e70 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_client_json.h @@ -0,0 +1,265 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef UTILS_METHOD_H_ +#define UTILS_METHOD_H_ + +#ifdef __cplusplus +extern "C" { +#endif +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" + +#define min(a, b) (a) < (b) ? (a) : (b) + +/* Max number of requests in appending state */ +#define MAX_APPENDING_REQUEST_AT_ANY_GIVEN_TIME (10) + +/* Size of buffer to receive JSON document from server */ +#define CLOUD_IOT_JSON_RX_BUF_LEN (QCLOUD_IOT_MQTT_RX_BUF_LEN + 1) + +/* Max size of clientToken */ +#define MAX_SIZE_OF_CLIENT_TOKEN (MAX_SIZE_OF_CLIENT_ID + 10) + +/* Max size of JSON string which only contain clientToken field */ +#define MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN (MAX_SIZE_OF_CLIENT_TOKEN + 20) + +#define CLIENT_TOKEN_FIELD "clientToken" +#define METHOD_FIELD "method" +#define TYPE_FIELD "type" +#define ACTION_ID_FIELD "actionId" +#define TIME_STAMP_FIELD "timestamp" + +#define REPLY_CODE "code" +#define REPLY_STATUS "status" + +#define GET_STATUS "get_status" // method field for get_status +#define GET_STATUS_REPLY "get_status_reply" // method field for get_status reply + +#define CONTROL_CMD "control" // method field for control msg +#define CONTROL_CMD_REPLY "control_reply" // method field for control msg reply + +#define CLEAR_CONTROL "clear_control" // method field for clear control + +#define REPORT_CMD "report" // method field for report +#define REPORT_CMD_REPLY "report_reply" // method field for report reply + +#define INFO_CMD "report_info" // method field for report system informaiton +#define INFO_CMD_REPLY "report_info_reply" // method field for report system informaiton reply + +#define GET_CONTROL_PARA "data.control" +#define CMD_CONTROL_PARA "params" + +/** + * @brief define type of request parameters + */ +typedef struct _RequestParam { + Method method; // method type: GET, REPORT, RINFO, REPLY, CLEAR + + uint32_t timeout_sec; // request timeout in second + + OnReplyCallback request_callback; // request callback + + void *user_context; // user context for callback + +} RequestParams; + +#define DEFAULT_REQUEST_PARAMS {GET, 4, NULL, NULL}; + +/** + * @brief type for document request + */ +typedef struct { + char client_token[MAX_SIZE_OF_CLIENT_TOKEN]; // clientToken + Method method; // method type + + void *user_context; // user context + Timer timer; // timer for timeout + + OnReplyCallback callback; // request response callback +} Request; + +/** + * @brief for property and it's callback + */ +typedef struct { + void *property; + + OnPropRegCallback callback; + +} PropertyHandler; + +/** + * @brief save the action registed and its callback + */ +typedef struct { + void *action; + + OnActionHandleCallback callback; + +} ActionHandler; + +/** + * @brief check return value of snprintf + * + * @param returnCode return value of snprintf + * @param maxSizeOfWrite max size of write buffer + * @return QCLOUD_RET_SUCCESS for success, or err code for + * failure + */ + +int check_snprintf_return(int32_t returnCode, size_t maxSizeOfWrite); + +/** + * @brief insert source string to the dest string with specified position + * + * @param pSourceStr source string + * @param pDestStr dest string + * @param pos dest string positon + */ +void insert_str(char *pDestStr, char *pSourceStr, int pos); + +/** + * add a JSON node to JSON string + * + * @param jsonBuffer JSON string buffer + * @param sizeOfBuffer size of buffer + * @param pJsonNode JSON node + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int put_json_node(char *jsonBuffer, size_t sizeOfBuffer, DeviceProperty *pJsonNode); + +/** + * add a JSON node to JSON string, data_template's bool type not the same to + * put_json_node + * + * @param jsonBuffer JSON string buffer + * @param sizeOfBuffer size of buffer + * @param pKey key of JSON node + * @param pData value of JSON node + * @param type value type of JSON node + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int template_put_json_node(char *jsonBuffer, size_t sizeOfBuffer, const char *pKey, void *pData, JsonDataType type); + +/** + * @brief generate an empty JSON with only clientToken + * + * @param tokenNumber token number, increment every time + * @param pJsonBuffer JSON string buffer + * @param tokenPrefix prefix of token, like product_id + */ +void build_empty_json(uint32_t *tokenNumber, char *pJsonBuffer, char *tokenPrefix); + +/** + * @brief parse field of clientToken from JSON string + * + * @param pJsonDoc source JSON string + * @param pClientToken pointer to field of ClientToken + * @return true for success + */ +bool parse_client_token(char *pJsonDoc, char **pClientToken); + +/** + * @brief parse field of aciont_id from JSON string + * + * @param pJsonDoc source JSON string + * @param pActionID pointer to field of action_id + * @return true for success + */ +bool parse_action_id(char *pJsonDoc, char **pActionID); + +/** + * @brief parse field of timestamp from JSON string + * + * @param pJsonDoc source JSON string + * @param pTimestamp pointer to field of timestamp + * @return true for success + */ +bool parse_time_stamp(char *pJsonDoc, int32_t *pTimestamp); + +/** + * @brief parse field of input from JSON string + * + * @param pJsonDoc source JSON string + * @param pActionInput filed of params as action input parameters + * @return true for success + */ +bool parse_action_input(char *pJsonDoc, char **pActionInput); + +/** + * @brief parse field of status from JSON string + * + * @param pJsonDoc source JSON string + * @param pStatus pointer to field of status + * @return true for success + */ +bool parse_status_return(char *pJsonDoc, char **pStatus); + +/** + * @brief parse field of code from JSON string + * + * @param pJsonDoc source JSON string + * @param pCode pointer to field of Code + * @return true for success + */ +bool parse_code_return(char *pJsonDoc, int32_t *pCode); + +/** + * @brief update value in JSON if key is matched, not for OBJECT type + * + * @param pJsonDoc JSON string + * @param pProperty device property + * @return true for success + */ +bool update_value_if_key_match(char *pJsonDoc, DeviceProperty *pProperty); + +/** + * @brief parse field of method from JSON string + * + * @param pJsonDoc source JSON string + * @param pMethod pointer to field of method + * @return true for success + */ +bool parse_template_method_type(char *pJsonDoc, char **pMethod); + +/** + * @brief parse field of control from get_status_reply JSON string + * + * @param pJsonDoc source JSON string + * @param control pointer to field of control + * @return true for success + */ +bool parse_template_get_control(char *pJsonDoc, char **control); + +/** + * @brief parse field of control from control JSON string + * + * @param pJsonDoc source JSON string + * @param control pointer to field of control + * @return true for success + */ +bool parse_template_cmd_control(char *pJsonDoc, char **control); + +#ifdef __cplusplus +} +#endif + +#endif /* QCLOUD_IOT_EXPORT_SHADOW_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_event.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_event.h new file mode 100644 index 00000000..c38ce930 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/data_template_event.h @@ -0,0 +1,70 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef _DATA_TEMPLATE_EVENT_H_ +#define _DATA_TEMPLATE_EVENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#define NAME_MAX_LEN (32) +#define TYPE_MAX_LEN (32) +#define EVENT_TOKEN_MAX_LEN (32) +#define SIGLE_EVENT (1) +#define MUTLTI_EVENTS (2) + +#define MAX_EVENT_WAIT_REPLY (10) +#define EVENT_MAX_DATA_NUM (255) + +#define POST_EVENT "event_post" +#define POST_EVENTS "events_post" +#define REPLY_EVENT "event_reply" + +/** + * @brief event's method, post and reply + */ +typedef enum { + eEVENT_POST, + eEVENT_REPLY, +} eEventMethod; + +typedef enum _eEventDealType_ { + eDEAL_REPLY_CB = 0, + eDEAL_EXPIRED = 1, +} eEventDealType; + +typedef struct _sReply_ { + char client_token[EVENT_TOKEN_MAX_LEN]; // clientToken for this event reply + void *user_context; // user context + Timer timer; // timer for request timeout + + OnEventReplyCallback callback; // callback for this event reply +} sEventReply; + +#ifdef __cplusplus +} +#endif +#endif //_DATA_TEMPLATE_EVENT_H_ \ No newline at end of file diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/gateway_common.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/gateway_common.h new file mode 100644 index 00000000..4f513829 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/gateway_common.h @@ -0,0 +1,124 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_GATEWAY_COMMON_H_ +#define IOT_GATEWAY_COMMON_H_ + +#include "qcloud_iot_export.h" + +#define GATEWAY_PAYLOAD_BUFFER_LEN 1024 +#define GATEWAY_RECEIVE_BUFFER_LEN 1024 +#define GATEWAY_LOOP_MAX_COUNT 100 +#define SUBDEV_BIND_SIGN_LEN 64 +#define BIND_SIGN_KEY_SIZE MAX_SIZE_OF_DEVICE_SECRET +#define GATEWAY_ONLINE_OP_STR "online" +#define GATEWAY_OFFLIN_OP_STR "offline" +#define GATEWAY_BIND_OP_STR "bind" +#define GATEWAY_UNBIND_OP_STR "unbind" + +/* The format of operation of gateway topic */ +#define GATEWAY_TOPIC_OPERATION_FMT "$gateway/operation/%s/%s" + +/* The format of operation result of gateway topic */ +#define GATEWAY_TOPIC_OPERATION_RESULT_FMT "$gateway/operation/result/%s/%s" + +/* The format of gateway client id */ +#define GATEWAY_CLIENT_ID_FMT "%s/%s" + +/* The format of status cmd payload */ +#define GATEWAY_PAYLOAD_STATUS_FMT \ + "{\"type\":\"%s\",\"payload\":{\"devices\":[{\"product_id\":\"%s\"," \ + "\"device_name\":\"%s\"}]}}" + +/* The format of bind cmd payload */ +#define GATEWAY_PAYLOAD_OP_FMT \ + "{\"type\":\"%s\",\"payload\":{\"devices\":[{\"product_id\":\"%s\"," \ + "\"device_name\":\"%s\",\"signature\":\"%s\",\"random\":%d,\"timestamp\":%d," \ + "\"signmethod\":\"%s\",\"authtype\":\"%s\"}]}}" + +/* Subdevice seesion status */ +typedef enum _SubdevSessionStatus { + /* Initial */ + SUBDEV_SEESION_STATUS_INIT, + + /* Online */ + SUBDEV_SEESION_STATUS_ONLINE, + + /* Offline */ + SUBDEV_SEESION_STATUS_OFFLINE, + + /* Maximum number of seesion status type */ + SUBDEV_SEESION_STATUS_MAX +} SubdevSessionStatus; + +/* The structure of subdevice session */ +typedef struct _SubdevSession { + char product_id[MAX_SIZE_OF_PRODUCT_ID + 1]; + char device_name[MAX_SIZE_OF_DEVICE_NAME + 1]; + SubdevSessionStatus session_status; + struct _SubdevSession *next; +} SubdevSession; + +/* The structure of common reply data */ +typedef struct _ReplyData { + int32_t result; + char client_id[MAX_SIZE_OF_CLIENT_ID + 1]; +} ReplyData; + +/* The structure of gateway data */ +typedef struct _GatewayData { + int32_t sync_status; + ReplyData online; + ReplyData offline; + ReplyData bind; + ReplyData unbind; +} GatewayData; + +/* The structure of gateway context */ +typedef struct _Gateway { + void * mqtt; + SubdevSession * session_list; + GatewayData gateway_data; + MQTTEventHandler event_handle; + int is_construct; + +#ifdef MULTITHREAD_ENABLED + bool yield_thread_running; + int yield_thread_exit_code; +#endif +} Gateway; + +SubdevSession *subdev_add_session(Gateway *gateway, char *product_id, char *device_name); + +SubdevSession *subdev_find_session(Gateway *gateway, char *product_id, char *device_name); + +int subdev_remove_session(Gateway *gateway, char *product_id, char *device_name); + +int gateway_subscribe_unsubscribe_topic(Gateway *gateway, char *topic_filter, SubscribeParams *params, + int is_subscribe); + +int gateway_subscribe_unsubscribe_default(Gateway *gateway, GatewayParam *param); + +int gateway_publish_sync(Gateway *gateway, char *topic, PublishParams *params, int32_t *result); + +int subdev_bind_hmac_sha1_cal(DeviceInfo *pDevInfo, char *signout, int max_signlen, int nonce, long timestamp); + +#endif /* IOT_GATEWAY_COMMON_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/json_parser.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/json_parser.h new file mode 100644 index 00000000..bfea2043 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/json_parser.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2017-2019 Tencent Group. All rights reserved. + * License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/** + * Edit by shockcao@tencent.com 2018/3/15 + */ + +#ifndef __JSON_PARSER_H__ +#define __JSON_PARSER_H__ + +#include "lite-utils.h" + +/** +The descriptions of the json value node type +**/ +enum JSONTYPE { JSNONE = -1, JSSTRING = 0, JSOBJECT, JSARRAY, JSNUMBER, JSBOOLEAN, JSNULL, JSTYPEMAX }; + +/** +The error codes produced by the JSON parsers +**/ +enum JSON_PARSE_CODE { JSON_PARSE_ERR, JSON_PARSE_OK, JSON_PARSE_FINISH }; + +/** +The return codes produced by the JSON parsers +**/ +enum JSON_PARSE_RESULT { JSON_RESULT_ERR = -1, JSON_RESULT_OK }; + +typedef int (*json_parse_cb)(char *p_cName, int iNameLen, char *p_cValue, int iValueLen, int iValueType, + void *p_Result); + +/** + * @brief Parse the JSON string, and iterate through all keys and values, + * then handle the keys and values by callback function. + * + * @param[in] p_cJsonStr @n The JSON string + * @param[in] iStrLen @n The JSON string length + * @param[in] pfnCB @n Callback function + * @param[out] p_CBData @n User data + * @return JSON_RESULT_OK success, JSON_RESULT_ERR failed + * @see None. + * @note None. + **/ +int json_parse_name_value(char *p_cJsonStr, int iStrLen, json_parse_cb pfnCB, void *p_CBData); + +/** + * @brief Get the value by a specified key from a json string + * + * @param[in] p_cJsonStr @n the JSON string + * @param[in] iStrLen @n the JSON string length + * @param[in] p_cName @n the specified key string + * @param[out] p_iValueLen @n the value length + * @param[out] p_iValueType @n the value type + * @return A pointer to the value + * @see None. + * @note None. + **/ +char *json_get_value_by_name(char *p_cJsonStr, int iStrLen, char *p_cName, int *p_iValueLen, int *p_iValueType); + +/** + * @brief Get the JSON object point associate with a given type. + * + * @param[in] type @n The object type + * @param[in] str @n The JSON string + * @returns The json object point with the given field type. + * @see None. + * @note None. + */ +char *json_get_object(int type, char *str); +char *json_get_next_object(int type, char *str, char **key, int *key_len, char **val, int *val_len, int *val_type); + +/** + * @brief retrieve each key&value pair from the json string + * + * @param[in] str @n Json string to revolve + * @param[in] pos @n cursor + * @param[out] key @n pointer to the next Key object + * @param[out] klen @n Key object length + * @param[out] val @n pointer to the next Value object + * @param[out] vlen @n Value object length + * @param[out] vtype @n Value object type(digital, string, object, array) + * @see None. + * @note None. + */ +#define json_object_for_each_kv(str, pos, key, klen, val, vlen, vtype) \ + for (pos = json_get_object(JSOBJECT, str); \ + pos != 0 && *pos != 0 && (pos = json_get_next_object(JSOBJECT, pos, &key, &klen, &val, &vlen, &vtype)) != 0;) + +/** + * @brief retrieve each entry from the json array + * + * @param[in] str @n Json array to revolve + * @param[in] pos @n cursor + * @param[out] entry @n pointer to the next entry from the array + * @param[out] len @n entry length + * @param[out] type @n entry type(digital, string, object, array) + * @see None. + * @note None. + */ +#define json_array_for_each_entry(str, pos, entry, len, type) \ + for (pos = json_get_object(JSARRAY, str); \ + pos != 0 && *pos != 0 && (pos = json_get_next_object(JSARRAY, ++pos, 0, 0, &entry, &len, &type)) != 0;) + +/** + * @brief backup the last character to register parameters, + * and set the end character with '\0' + * + * @param[in] json_str @n json string + * @param[in] str_len @n json string lenth + * @param[out] register @n used to backup the last character + * @see None. + * @note None. + */ +#define backup_json_str_last_char(json_str, str_len, register) \ + { \ + register = *((char *)json_str + str_len); \ + *((char *)json_str + str_len) = '\0'; \ + } + +/** + * @brief restore the last character from register parameters + * + * @param[in] json_str @n json string + * @param[in] str_len @n json string lenth + * @param[in] register @n used to restore the last character + * @see None. + * @note None. + */ +#define restore_json_str_last_char(json_str, str_len, register) \ + { \ + *((char *)json_str + str_len) = register; \ + } + +#endif /* __JSON_PARSER_H__ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/log_upload.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/log_upload.h new file mode 100644 index 00000000..af521c37 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/log_upload.h @@ -0,0 +1,115 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_LOG_UPLOAD_H_ +#define QCLOUD_IOT_LOG_UPLOAD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_export_log.h" + +/** + * @brief init the log upload functions + * + * @param init_params + * @return QCLOUD_RET_SUCCESS when success + */ +int init_log_uploader(LogUploadInitParams *init_params); + +/** + * @brief free log buffer and finish the log upload functions + */ +void fini_log_uploader(void); + +/** + * @brief check if log uploader is init or not + */ +bool is_log_uploader_init(void); + +/** + * @brief append one log item to upload buffer + * + * @param log_content + * @param log_size + * @return 0 when success, -1 when fail + */ +int append_to_upload_buffer(const char *log_content, size_t log_size); + +/** + * @brief clear current upload buffer + * + * @return + */ +void clear_upload_buffer(void); + +/** + * @brief do one upload to server + * + * @param force_upload if true, it will do upload right away, otherwise it will + * check log_level, buffer left and upload interval + * @return QCLOUD_RET_SUCCESS when success or no log to upload or timer is not + * expired + */ +int do_log_upload(bool force_upload); + +/** + * @brief set the log mqtt client to get system time + * + * @param client + */ +void set_log_mqtt_client(void *client); + +/** + * @brief set if only do log upload when communication error with IoT Hub + * + * @param value if true, only do log upload when communication error with IoT + * Hub + */ +void set_log_upload_in_comm_err(bool value); + +/** + * @brief get current upload log_level from IoT Hub + * + * @param log_level + * @return QCLOUD_RET_SUCCESS when success + */ +int qcloud_get_log_level(int *log_level); + +/** + * @brief get the log mqtt client + * + * @return log mqtt client + */ +void *get_log_mqtt_client(void); + +/** + * @brief get the device info of log client + * + * @return device info pointer of log client + */ +void *get_log_dev_info(void); + +#ifdef __cplusplus +} +#endif + +#endif // QCLOUD_IOT_LOG_UPLOAD_H_ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/mqtt_client.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/mqtt_client.h new file mode 100644 index 00000000..c4d720cd --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/mqtt_client.h @@ -0,0 +1,556 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_MQTT_CLIENT_H_ +#define IOT_MQTT_CLIENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "mqtt_client_net.h" +#include "qcloud_iot_common.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_list.h" +#include "qutils_param_check.h" +#include "qutils_timer.h" + +/* packet id, random from [1 - 65536] */ +#define MAX_PACKET_ID (65535) + +/* Max size of conn Id */ +#define MAX_CONN_ID_LEN (6) + +/* Max number of topic subscribed */ +#define MAX_MESSAGE_HANDLERS (10) + +/* Max number in repub list */ +#define MAX_REPUB_NUM (20) + +/* Minimal wait interval when reconnect */ +#define MIN_RECONNECT_WAIT_INTERVAL (1000) + +/* Minimal MQTT timeout value */ +#define MIN_COMMAND_TIMEOUT (500) + +/* Maxmal MQTT timeout value */ +#define MAX_COMMAND_TIMEOUT (20000) + +/* Max size of a topic name */ +#define MAX_SIZE_OF_CLOUD_TOPIC ((MAX_SIZE_OF_DEVICE_NAME) + (MAX_SIZE_OF_PRODUCT_ID) + 64 + 6) + +/* minimal TLS handshaking timeout value (unit: ms) */ +#define QCLOUD_IOT_TLS_HANDSHAKE_TIMEOUT (5 * 1000) + +#define MQTT_RMDUP_MSG_ENABLED + +/** + * @brief MQTT Message Type + */ +typedef enum msgTypes { + RESERVED = 0, // Reserved + CONNECT = 1, // Client request to connect to Server + CONNACK = 2, // Connect Acknowledgment + PUBLISH = 3, // Publish message + PUBACK = 4, // Publish Acknowledgment + PUBREC = 5, // Publish Received + PUBREL = 6, // Publish Release + PUBCOMP = 7, // Publish Complete + SUBSCRIBE = 8, // Client Subscribe request + SUBACK = 9, // Subscribe Acknowledgment + UNSUBSCRIBE = 10, // Client Unsubscribe request + UNSUBACK = 11, // Unsubscribe Acknowledgment + PINGREQ = 12, // PING Request + PINGRESP = 13, // PING Response + DISCONNECT = 14 // Client is Disconnecting +} MessageTypes; + +typedef enum { NOTCONNECTED = 0, CONNECTED = 1 } ConnStatus; + +/** + * MQTT byte 1: fixed header + * bits |7654: Message Type | 3:DUP flag | 21:QoS level | 0:RETAIN | + */ +#define MQTT_HEADER_TYPE_SHIFT 0x04 +#define MQTT_HEADER_TYPE_MASK 0xF0 +#define MQTT_HEADER_DUP_SHIFT 0x03 +#define MQTT_HEADER_DUP_MASK 0x08 +#define MQTT_HEADER_QOS_SHIFT 0x01 +#define MQTT_HEADER_QOS_MASK 0x06 +#define MQTT_HEADER_RETAIN_MASK 0x01 + +/** + * @brief MQTT will options sturcture + * + */ +typedef struct { + char struct_id[4]; // The eyecatcher for this structure. must be MQTW + uint8_t struct_version; // struct version = 0 + char * topic_name; + char * message; + uint8_t retained; + QoS qos; +} WillOptions; + +/** + * default MQTT will options + */ +#define DEFAULT_WILL_OPTIONS \ + { \ + {'M', 'Q', 'T', 'W'}, 0, NULL, NULL, 0, QOS0 \ + } + +/** + * @brief define MQTT connect parameters structure + * + */ +typedef struct { + char *client_id; // unique client id + char *username; // user name + char *password; // passwrod + + char conn_id[MAX_CONN_ID_LEN]; + + char struct_id[4]; // The eyecatcher for this structure. must be MQTC. + uint8_t struct_version; // struct version = 0 + uint8_t mqtt_version; // MQTT protocol version: 4 = 3.1.1 + + uint16_t keep_alive_interval; // keep alive interval, unit: second + uint8_t clean_session; // flag of clean session, refer to MQTT spec 3.1.2.4 + + uint8_t auto_connect_enable; // enable auto connection or not + +#ifdef AUTH_WITH_NOTLS + char *device_secret; // PSK + int device_secret_len; // length of PSK +#endif + +} MQTTConnectParams; + +/** + * default value of MQTT connect parameters structure + */ +#ifdef AUTH_WITH_NOTLS +#define DEFAULT_MQTTCONNECT_PARAMS \ + { \ + NULL, NULL, NULL, {0}, {'M', 'Q', 'T', 'C'}, 0, 4, 240, 1, 1, NULL, 0 \ + } +#else +#define DEFAULT_MQTTCONNECT_PARAMS \ + { \ + NULL, NULL, NULL, {0}, {'M', 'Q', 'T', 'C'}, 0, 4, 240, 1, 1 \ + } +#endif + +/** + * @brief data structure for topic subscription handle + */ +typedef struct SubTopicHandle { + const char * topic_filter; // topic name, wildcard filter is supported + OnMessageHandler message_handler; // callback when msg of this subscription arrives + OnSubEventHandler sub_event_handler; // callback when event of this subscription happens + void * handler_user_data; // user context for callback + QoS qos; // QoS +} SubTopicHandle; + +/** + * @brief MQTT QCloud IoT Client structure + */ +typedef struct Client { + uint8_t is_connected; + uint8_t was_manually_disconnected; + uint8_t is_ping_outstanding; // 1 = ping request is sent while ping response + // not arrived yet + + uint16_t next_packet_id; // MQTT random packet id + uint32_t command_timeout_ms; // MQTT command timeout, unit:ms + + uint32_t current_reconnect_wait_interval; // unit:ms + uint32_t counter_network_disconnected; // number of disconnection + + size_t write_buf_size; // size of MQTT write buffer + size_t read_buf_size; // size of MQTT read buffer + unsigned char write_buf[QCLOUD_IOT_MQTT_TX_BUF_LEN]; // MQTT write buffer + unsigned char read_buf[QCLOUD_IOT_MQTT_RX_BUF_LEN]; // MQTT read buffer + + void *lock_generic; // mutex/lock for this client struture + void *lock_write_buf; // mutex/lock for write buffer + + void *lock_list_pub; // mutex/lock for puback waiting list + void *lock_list_sub; // mutex/lock for suback waiting list + + List *list_pub_wait_ack; // puback waiting list + List *list_sub_wait_ack; // suback waiting list + + MQTTEventHandler event_handle; // callback for MQTT event + + MQTTConnectParams options; // handle to connection parameters + + Network network_stack; // MQTT network stack + + Timer ping_timer; // MQTT ping timer + Timer reconnect_delay_timer; // MQTT reconnect delay timer + + SubTopicHandle sub_handles[MAX_MESSAGE_HANDLERS]; // subscription handle array + + char host_addr[HOST_STR_LENGTH]; + +#ifdef AUTH_MODE_CERT + char cert_file_path[FILE_PATH_MAX_LEN]; // full path of device cert file + char key_file_path[FILE_PATH_MAX_LEN]; // full path of device key file +#else + unsigned char psk_decode[DECODE_PSK_LENGTH]; +#endif + +#ifdef MQTT_RMDUP_MSG_ENABLED +#define MQTT_MAX_REPEAT_BUF_LEN 10 + uint16_t repeat_packet_id_buf[MQTT_MAX_REPEAT_BUF_LEN]; + unsigned int current_packet_id_cnt; +#endif + +#ifdef MULTITHREAD_ENABLED + bool yield_thread_running; + int yield_thread_exit_code; +#endif + +} Qcloud_IoT_Client; + +/** + * @brief MQTT protocol version + */ +typedef enum { MQTT_3_1_1 = 4 } MQTT_VERSION; + +typedef enum MQTT_NODE_STATE { + MQTT_NODE_STATE_NORMANL = 0, + MQTT_NODE_STATE_INVALID, +} MQTTNodeState; + +/* topic publish info */ +typedef struct REPUBLISH_INFO { + Timer pub_start_time; /* timer for puback waiting */ + MQTTNodeState node_state; /* node state in wait list */ + uint16_t msg_id; /* packet id */ + uint32_t len; /* msg length */ + unsigned char *buf; /* msg buffer */ +} QcloudIotPubInfo; + +/* topic subscribe/unsubscribe info */ +typedef struct SUBSCRIBE_INFO { + enum msgTypes type; /* type: sub or unsub */ + uint16_t msg_id; /* packet id */ + Timer sub_start_time; /* timer for suback waiting */ + MQTTNodeState node_state; /* node state in wait list */ + SubTopicHandle handler; /* handle of topic subscribed(unsubcribed) */ + uint16_t len; /* msg length */ + unsigned char *buf; /* msg buffer */ +} QcloudIotSubInfo; + +/** + * @brief Init MQTT client + * + * @param pClient handle to MQTT client + * @param pParams MQTT init parameters + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_iot_mqtt_init(Qcloud_IoT_Client *pClient, MQTTInitParams *pParams); + +/** + * @brief Release resources of MQTT client + * + * @param pClient handle to MQTT client + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_iot_mqtt_fini(Qcloud_IoT_Client *pClient); + +/** + * @brief Connect with MQTT server + * + * @param pClient handle to MQTT client + * @param pParams MQTT connect parameters + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_iot_mqtt_connect(Qcloud_IoT_Client *pClient, MQTTConnectParams *pParams); + +/** + * @brief Reconnect with MQTT server and re-subscribe topics if reconnected + * + * @param pClient handle to MQTT client + * + * @return QCLOUD_RET_MQTT_RECONNECTED for success, or err code for failure + */ +int qcloud_iot_mqtt_attempt_reconnect(Qcloud_IoT_Client *pClient); + +/** + * @brief Disconnect with MQTT server + * + * @param pClient handle to MQTT client + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_iot_mqtt_disconnect(Qcloud_IoT_Client *pClient); + +/** + * @brief Publish MQTT message + * + * @param pClient handle to MQTT client + * @param topicName MQTT topic name + * @param pParams publish parameters + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int qcloud_iot_mqtt_publish(Qcloud_IoT_Client *pClient, char *topicName, PublishParams *pParams); + +/** + * @brief Subscribe MQTT topic + * + * @param pClient handle to MQTT client + * @param topicFilter MQTT topic filter + * @param pParams subscribe parameters + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int qcloud_iot_mqtt_subscribe(Qcloud_IoT_Client *pClient, char *topicFilter, SubscribeParams *pParams); + +/** + * @brief Re-subscribe MQTT topics + * + * @param pClient handle to MQTT client + * + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_iot_mqtt_resubscribe(Qcloud_IoT_Client *pClient); + +/** + * @brief Unsubscribe MQTT topic + * + * @param pClient handle to MQTT client + * @param topicFilter MQTT topic filter + * + * @return packet id (>=0) when success, or err code (<0) for failure + */ +int qcloud_iot_mqtt_unsubscribe(Qcloud_IoT_Client *pClient, char *topicFilter); + +/** + * @brief check if MQTT topic has been subscribed or not + * + * @param pClient handle to MQTT client + * @param topicFilter MQTT topic filter + * + * @return true when successfully subscribed, or false if not yet + */ +bool qcloud_iot_mqtt_is_sub_ready(Qcloud_IoT_Client *pClient, char *topicFilter); + +/** + * @brief Check connection and keep alive state, read/handle MQTT message in + * synchronized way + * + * @param pClient handle to MQTT client + * @param timeout_ms timeout value (unit: ms) for this operation + * + * @return QCLOUD_RET_SUCCESS when success, QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT + * when try reconnecing, or err code for + * failure + */ +int qcloud_iot_mqtt_yield(Qcloud_IoT_Client *pClient, uint32_t timeout_ms); + +/** + * @brief Check if auto reconnect is enabled or not + * + * @param pClient handle to MQTT client + * @return true if auto reconnect is enabled + */ +bool qcloud_iot_mqtt_is_autoreconnect_enabled(Qcloud_IoT_Client *pClient); + +/** + * @brief Set to enable auto reconnect or not + * + * @param pClient handle to MQTT client + * @param value enable or disable + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_iot_mqtt_set_autoreconnect(Qcloud_IoT_Client *pClient, bool value); + +/** + * @brief Get the count of disconnection + * + * @param pClient handle to MQTT client + * @return count of disconnection + */ +int qcloud_iot_mqtt_get_network_disconnected_count(Qcloud_IoT_Client *pClient); + +/** + * @brief Set the count of disconnection + * + * @param pClient handle to MQTT client + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_iot_mqtt_reset_network_disconnected_count(Qcloud_IoT_Client *pClient); + +/** + * @brief Get next packet id + * + * @param pClient + * @return + */ +uint16_t get_next_packet_id(Qcloud_IoT_Client *pClient); + +/** + * @brief Get next conn id + * + * @param options + * @return + */ +void get_next_conn_id(char *conn_id); + +/** + * @brief Init packet header + * @param header + * @param message_type + * @param qos + * @param dup + * @param retained + * @return + */ +int mqtt_init_packet_header(unsigned char *header, MessageTypes message_type, QoS qos, uint8_t dup, uint8_t retained); + +/** + * @brief Read and handle one MQTT msg/ack from server + * + * @param pClient + * @param timer + * @param packet_type + * @param qos + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int cycle_for_read(Qcloud_IoT_Client *pClient, Timer *timer, uint8_t *packet_type, QoS qos); + +/** + * @brief Send the packet in buffer + * + * @param pClient + * @param length + * @param timer + * @return + */ +int send_mqtt_packet(Qcloud_IoT_Client *pClient, size_t length, Timer *timer); + +/** + * @brief wait for a specific packet with timeout + * + * only used in single-threaded mode where one command at a time is in process + * + * @param pClient MQTT Client + * @param packet_type MQTT packet type + * @param timer timer with timeout + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int wait_for_read(Qcloud_IoT_Client *pClient, uint8_t packet_type, Timer *timer, QoS qos); + +/** + * @brief Set MQTT connection state + * + * @param pClient MQTT Client + * @param connected 0: disconnected 1: connected + * @return + */ +void set_client_conn_state(Qcloud_IoT_Client *pClient, uint8_t connected); + +/** + * @brief Get MQTT connection state + * + * @param pClient MQTT Client + * @return 0: disconnected 1: connected + */ +uint8_t get_client_conn_state(Qcloud_IoT_Client *pClient); + +/** + * @brief Check Publish ACK waiting list, remove the node if PUBACK received or + * timeout + * + * @param pClient MQTT client + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_iot_mqtt_pub_info_proc(Qcloud_IoT_Client *pClient); + +/** + * @brief Check Subscribe ACK waiting list, remove the node if SUBACK received + * or timeout + * + * @param pClient MQTT client + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_iot_mqtt_sub_info_proc(Qcloud_IoT_Client *pClient); + +int push_sub_info_to(Qcloud_IoT_Client *c, int len, unsigned short msgId, MessageTypes type, SubTopicHandle *handler, + ListNode **node); + +int serialize_pub_ack_packet(unsigned char *buf, size_t buf_len, MessageTypes packet_type, uint8_t dup, + uint16_t packet_id, uint32_t *serialized_len); + +int serialize_packet_with_zero_payload(unsigned char *buf, size_t buf_len, MessageTypes packetType, + uint32_t *serialized_len); + +int deserialize_publish_packet(unsigned char *dup, QoS *qos, uint8_t *retained, uint16_t *packet_id, char **topicName, + uint16_t *topicNameLen, unsigned char **payload, size_t *payload_len, unsigned char *buf, + size_t buf_len); + +int deserialize_suback_packet(uint16_t *packet_id, uint32_t max_count, uint32_t *count, QoS *grantedQoSs, + unsigned char *buf, size_t buf_len); + +int deserialize_unsuback_packet(uint16_t *packet_id, unsigned char *buf, size_t buf_len); + +int deserialize_ack_packet(uint8_t *packet_type, uint8_t *dup, uint16_t *packet_id, unsigned char *buf, size_t buf_len); + +#ifdef MQTT_RMDUP_MSG_ENABLED + +void reset_repeat_packet_id_buffer(Qcloud_IoT_Client *pClient); + +#endif + +size_t get_mqtt_packet_len(size_t rem_len); + +size_t mqtt_write_packet_rem_len(unsigned char *buf, uint32_t length); + +int mqtt_read_packet_rem_len_form_buf(unsigned char *buf, uint32_t *value, uint32_t *readBytesLen); + +uint16_t mqtt_read_uint16_t(unsigned char **pptr); + +unsigned char mqtt_read_char(unsigned char **pptr); + +void mqtt_write_char(unsigned char **pptr, unsigned char c); + +void mqtt_write_uint_16(unsigned char **pptr, uint16_t anInt); + +void mqtt_write_utf8_string(unsigned char **pptr, const char *string); + +#ifdef __cplusplus +} +#endif + +#endif // IOT_MQTT_CLIENT_H_ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/mqtt_client_net.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/mqtt_client_net.h new file mode 100644 index 00000000..659bc5db --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/mqtt_client_net.h @@ -0,0 +1,43 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_MQTT_CLIENT_NET_H_ +#define IOT_MQTT_CLIENT_NET_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "network_interface.h" + +/** + * @brief Init network stack + * + * @param pNetwork + * @param pConnectParams + * @return 0 for success + */ +int qcloud_iot_mqtt_network_init(Network *pNetwork); + +#ifdef __cplusplus +} +#endif + +#endif // IOT_MQTT_CLIENT_NET_H_ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/network_interface.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/network_interface.h new file mode 100644 index 00000000..2e07fae1 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/network_interface.h @@ -0,0 +1,132 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef _NETWORK_INTERFACE_H_ +#define _NETWORK_INTERFACE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "qcloud_iot_import.h" + +/* + * Type of network interface + */ + +typedef enum { NETWORK_TCP = 0, NETWORK_UDP = 1, NETWORK_TLS = 2, NETWORK_DTLS = 3 } NETWORK_TYPE; + +/** + * @brief Define structure for network stack + */ +typedef struct Network Network; + +/** + * @brief Define structure for network stack + * + * Network init/connect/read/write/disconnect/state + */ +struct Network { + int (*init)(Network *); + + int (*connect)(Network *); + + int (*read)(Network *, unsigned char *, size_t, uint32_t, size_t *); + + int (*write)(Network *, unsigned char *, size_t, uint32_t, size_t *); + + void (*disconnect)(Network *); + + int (*is_connected)(Network *); + + // connetion handle: + // for non-AT: 0 = not connected, non-zero = connected + // for AT: 0 = valid connection, MAX_UNSINGED_INT = invalid + uintptr_t handle; + +#ifndef AUTH_WITH_NOTLS + SSLConnectParams ssl_connect_params; +#endif + + const char * host; // server address + int port; // server port + NETWORK_TYPE type; +}; + +/* + * Init network stack + */ +int network_init(Network *pNetwork); + +/* return the handle */ +int is_network_connected(Network *pNetwork); + +/* network stack API */ +#ifdef AT_TCP_ENABLED + +#define AT_NO_CONNECTED_FD 0xffffffff + +int network_at_tcp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len); +int network_at_tcp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, + size_t *written_len); +void network_at_tcp_disconnect(Network *pNetwork); +int network_at_tcp_connect(Network *pNetwork); +int network_at_tcp_init(Network *pNetwork); + +#else +int network_tcp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len); +int network_tcp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len); +void network_tcp_disconnect(Network *pNetwork); +int network_tcp_connect(Network *pNetwork); +int network_tcp_init(Network *pNetwork); +#endif + +#ifndef AUTH_WITH_NOTLS +int network_tls_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len); +int network_tls_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len); +void network_tls_disconnect(Network *pNetwork); +int network_tls_connect(Network *pNetwork); +int network_tls_init(Network *pNetwork); +#endif + +#ifdef COAP_COMM_ENABLED +#ifdef AUTH_WITH_NOTLS +int network_udp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len); +int network_udp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len); +void network_udp_disconnect(Network *pNetwork); +int network_udp_connect(Network *pNetwork); +int network_udp_init(Network *pNetwork); +#else +int network_dtls_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len); +int network_dtls_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, + size_t *written_len); +void network_dtls_disconnect(Network *pNetwork); +int network_dtls_connect(Network *pNetwork); +int network_dtls_init(Network *pNetwork); +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif /* _NETWORK_INTERFACE_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/ota_client.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/ota_client.h new file mode 100644 index 00000000..0099ea3c --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/ota_client.h @@ -0,0 +1,62 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_OTA_CLIENT_H_ +#define IOT_OTA_CLIENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Specify the maximum characters of version */ +#define OTA_MAX_TOPIC_LEN (64) + +#define TYPE_FIELD "type" +#define MD5_FIELD "md5sum" +#define VERSION_FIELD "version" +#define URL_FIELD "url" +#define FILESIZE_FIELD "file_size" +#define RESULT_FIELD "result_code" + +#define REPORT_VERSION_RSP "report_version_rsp" +#define UPDATE_FIRMWARE "update_firmware" + +enum { MQTT_CHANNEL, COAP_CHANNEL }; + +typedef void (*OnOTAMessageCallback)(void *pcontext, const char *msg, uint32_t msgLen); + +void *qcloud_osc_init(const char *productId, const char *deviceName, void *channel, OnOTAMessageCallback callback, + void *context); + +int qcloud_osc_deinit(void *handle); + +int qcloud_osc_report_progress(void *handle, const char *msg); + +int qcloud_osc_report_version(void *handle, const char *msg); + +int qcloud_osc_report_upgrade_result(void *handle, const char *msg); + +#ifdef __cplusplus +} +#endif + +#endif /* IOT_OTA_CLIENT_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/ota_fetch.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/ota_fetch.h new file mode 100644 index 00000000..49c7facd --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/ota_fetch.h @@ -0,0 +1,42 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_OTA_FETCH_H_ +#define IOT_OTA_FETCH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void *ofc_Init(const char *url, uint32_t offset, uint32_t size); + +int32_t qcloud_ofc_connect(void *handle); + +int32_t qcloud_ofc_fetch(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s); + +int qcloud_ofc_deinit(void *handle); + +#ifdef __cplusplus +} +#endif + +#endif /* IOT_OTA_FETCH_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/ota_lib.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/ota_lib.h new file mode 100644 index 00000000..6b23d5a5 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/ota_lib.h @@ -0,0 +1,87 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_OTA_LIB_H_ +#define IOT_OTA_LIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "qcloud_iot_export_ota.h" + +void *qcloud_otalib_md5_init(void); + +void qcloud_otalib_md5_update(void *md5, const char *buf, size_t buf_len); + +void qcloud_otalib_md5_finalize(void *md5, char *output_str); + +void qcloud_otalib_md5_deinit(void *md5); + +int qcloud_otalib_get_firmware_type(const char *json, char **type); + +int qcloud_otalib_get_report_version_result(const char *json); + +/** + * @brief Parse firmware info from JSON string + * + * @param json source JSON string + * @param type parsed type + * @param url parsed url + * @param version parsed version + * @param md5 parsed MD5 + * @param fileSize parsed file size + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_otalib_get_params(const char *json, char **type, char **url, char **version, char *md5, uint32_t *fileSize); + +/** + * @brief Generate firmware info from id and version + * + * @param buf output buffer + * @param bufLen size of buffer + * @param id firmware id + * @param version firmware version + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_otalib_gen_info_msg(char *buf, size_t bufLen, uint32_t id, const char *version); + +/** + * @brief Generate firmware report + * + * @param buf output buffer + * @param bufLen size of buffer + * @param id firmware id + * @param version firmware version + * @param progress download progress + * @param reportType report type + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_otalib_gen_report_msg(char *buf, size_t bufLen, uint32_t id, const char *version, int progress, + IOT_OTAReportType reportType); + +#ifdef __cplusplus +} +#endif + +#endif /* IOT_OTA_LIB_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qcloud_iot_ca.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qcloud_iot_ca.h new file mode 100644 index 00000000..ba9b731d --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qcloud_iot_ca.h @@ -0,0 +1,42 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_CA_H_ +#define IOT_CA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +const char *iot_ca_get(void); + +const char *iot_https_ca_get(void); + +const char *iot_get_mqtt_domain(const char *region); + +const char *iot_get_dyn_reg_domain(const char *region); + +const char *iot_get_log_domain(const char *region); + +#ifdef __cplusplus +} +#endif + +#endif /* IOT_CA_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qcloud_iot_common.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qcloud_iot_common.h new file mode 100644 index 00000000..33de81dd --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qcloud_iot_common.h @@ -0,0 +1,59 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_COMMON_H_ +#define QCLOUD_IOT_COMMON_H_ + +/* IoT C-SDK APPID */ +#define QCLOUD_IOT_DEVICE_SDK_APPID "21010406" + +/* MQTT server domain */ +#define QCLOUD_IOT_MQTT_DIRECT_DOMAIN "iotcloud.tencentdevices.com" +#define QCLOUD_IOT_MQTT_US_EAST_DOMAIN "us-east.iotcloud.tencentdevices.com" + +#define MQTT_SERVER_PORT_TLS 8883 +#define MQTT_SERVER_PORT_NOTLS 1883 + +/* CoAP server domain */ +#define QCLOUD_IOT_COAP_DEIRECT_DOMAIN "iotcloud.tencentdevices.com" + +#define COAP_SERVER_PORT 5684 + +/* server domain for dynamic registering device */ +#define DYN_REG_SERVER_URL "gateway.tencentdevices.com" +#define DYN_REG_SERVER_US_EAST_URL "us-east.gateway.tencentdevices.com" + +#define DYN_REG_SERVER_PORT 80 +#define DYN_REG_SERVER_PORT_TLS 443 + +/* URL for doing log upload */ +#define LOG_UPLOAD_SERVER_DOMAIN "http://devicelog.iot.cloud.tencent.com/cgi-bin/report-log" +#define LOG_UPLOAD_SERVER_US_EAST_DOMAIN "http://us-east.devicelog.iot.cloud.tencent.com/cgi-bin/report-log" +#define LOG_UPLOAD_SERVER_PATTEN "devicelog.iot.cloud.tencent.com" + +#define LOG_UPLOAD_SERVER_PORT 80 + +/* Max size of a host name */ +#define HOST_STR_LENGTH 64 + +/* Max size of base64 encoded PSK = 64, after decode: 64/4*3 = 48*/ +#define DECODE_PSK_LENGTH 48 + +#endif /* QCLOUD_IOT_COMMON_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qcloud_iot_device.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qcloud_iot_device.h new file mode 100644 index 00000000..b67772cd --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qcloud_iot_device.h @@ -0,0 +1,37 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_DEVICE_H_ +#define IOT_DEVICE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" + +int iot_device_info_set(DeviceInfo *device_info, const char *product_id, const char *device_name); + +#ifdef __cplusplus +} +#endif + +#endif /* IOT_DEVICE_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_aes.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_aes.h new file mode 100644 index 00000000..134353dd --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_aes.h @@ -0,0 +1,299 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ +#ifndef QCLOUD_IOT_UTILS_AES_H_ +#define QCLOUD_IOT_UTILS_AES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +//========Platform================================// +#define UTILS_AES_C +#define UTILS_CIPHER_MODE_CBC +//#define UTILS_SELF_TEST + +#define UTILS_ERR_PLATFORM_HW_ACCEL_FAILED -0x0070 /**< Hardware accelerator failed */ +#define UTILS_ERR_PLATFORM_FEATURE_UNSUPPORTED -0x0072 /**< The requested feature is not supported by the platform */ + +/* Internal macros meant to be called only from within the library. */ +#define UTILS_INTERNAL_VALIDATE_RET(cond, ret) \ + do { \ + } while (0) +#define UTILS_INTERNAL_VALIDATE(cond) \ + do { \ + } while (0) +//==============================================// + +/* padlock.c and aesni.c rely on these values! */ +#define UTILS_AES_ENCRYPT 1 /**< AES encryption. */ +#define UTILS_AES_DECRYPT 0 /**< AES decryption. */ + +#define UTILS_AES_BLOCK_LEN 16 +#define AES_KEY_BITS_128 128 +#define AES_KEY_BITS_192 192 +#define AES_KEY_BITS_256 256 + +/* Error codes in range 0x0020-0x0022 */ +#define UTILS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ +#define UTILS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ + +/* Error codes in range 0x0021-0x0025 */ +#define UTILS_ERR_AES_BAD_INPUT_DATA -0x0021 /**< Invalid input data. */ + +/* UTILS_ERR_AES_FEATURE_UNAVAILABLE is deprecated and should not be used. */ +#define UTILS_ERR_AES_FEATURE_UNAVAILABLE \ + -0x0023 /**< Feature not available. For example, an unsupported AES key \ + size. */ + +/* UTILS_ERR_AES_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define UTILS_ERR_AES_HW_ACCEL_FAILED -0x0025 /**< AES hardware accelerator failed. */ + +#if !defined(UTILS_AES_ALT) +// Regular implementation +// + +/** + * \brief The AES context-type definition. + */ +typedef struct utils_aes_context { + int nr; /*!< The number of rounds. */ + uint32_t *rk; /*!< AES round keys. */ + uint32_t buf[68]; /*!< Unaligned data buffer. This buffer can + hold 32 extra Bytes, which can be used for + one of the following purposes: +
  • Alignment if VIA padlock is + used.
  • +
  • Simplifying key expansion in the 256-bit + case by generating an extra round key. +
*/ +} utils_aes_context; + +#else /* UTILS_AES_ALT */ +#include "aes_alt.h" +#endif /* UTILS_AES_ALT */ + +/** + * \brief This function initializes the specified AES context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The AES context to initialize. This must not be \c NULL. + */ +void utils_aes_init(utils_aes_context *ctx); + +/** + * \brief This function releases and clears the specified AES context. + * + * \param ctx The AES context to clear. + * If this is \c NULL, this function does nothing. + * Otherwise, the context must have been at least initialized. + */ +void utils_aes_free(utils_aes_context *ctx); + +/** + * \brief This function sets the encryption key. + * + * \param ctx The AES context to which the key should be bound. + * It must be initialized. + * \param key The encryption key. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of data passed in bits. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return #UTILS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int utils_aes_setkey_enc(utils_aes_context *ctx, const unsigned char *key, unsigned int keybits); + +/** + * \brief This function sets the decryption key. + * + * \param ctx The AES context to which the key should be bound. + * It must be initialized. + * \param key The decryption key. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of data passed. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return #UTILS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int utils_aes_setkey_dec(utils_aes_context *ctx, const unsigned char *key, unsigned int keybits); + +/** + * \brief This function performs an AES single-block encryption or + * decryption operation. + * + * It performs the operation defined in the \p mode parameter + * (encrypt or decrypt), on the input data buffer defined in + * the \p input parameter. + * + * utils_aes_init(), and either utils_aes_setkey_enc() or + * utils_aes_setkey_dec() must be called before the first + * call to this API with the same context. + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param mode The AES operation: #UTILS_AES_ENCRYPT or + * #UTILS_AES_DECRYPT. + * \param input The buffer holding the input data. + * It must be readable and at least \c 16 Bytes long. + * \param output The buffer where the output data will be written. + * It must be writeable and at least \c 16 Bytes long. + + * \return \c 0 on success. + */ +int utils_aes_crypt_ecb(utils_aes_context *ctx, int mode, const unsigned char input[16], unsigned char output[16]); + +#if defined(UTILS_CIPHER_MODE_CBC) +/** + * \brief This function performs an AES-CBC encryption or decryption operation + * on full blocks. + * + * It performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer defined in + * the \p input parameter. + * + * It can be called as many times as needed, until all the input + * data is processed. utils_aes_init(), and either + * utils_aes_setkey_enc() or utils_aes_setkey_dec() must be called + * before the first call to this API with the same context. + * + * \note This function operates on full blocks, that is, the input size + * must be a multiple of the AES block size of \c 16 Bytes. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the IV, you should + * either save it manually or use the cipher module instead. + * + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param mode The AES operation: #UTILS_AES_ENCRYPT or + * #UTILS_AES_DECRYPT. + * \param length The length of the input data in Bytes. This must be a + * multiple of the block size (\c 16 Bytes). + * \param iv Initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + * \return #UTILS_ERR_AES_INVALID_INPUT_LENGTH + * on failure. + */ +int utils_aes_crypt_cbc(utils_aes_context *ctx, int mode, size_t length, unsigned char iv[16], + const unsigned char *input, unsigned char *output); +#endif /* UTILS_CIPHER_MODE_CBC */ + +/** + * \brief Internal AES block encryption function. This is only + * exposed to allow overriding it using + * \c UTILS_AES_ENCRYPT_ALT. + * + * \param ctx The AES context to use for encryption. + * \param input The plaintext block. + * \param output The output (ciphertext) block. + * + * \return \c 0 on success. + */ +int utils_internal_aes_encrypt(utils_aes_context *ctx, const unsigned char input[16], unsigned char output[16]); + +/** + * \brief Internal AES block decryption function. This is only + * exposed to allow overriding it using see + * \c UTILS_AES_DECRYPT_ALT. + * + * \param ctx The AES context to use for decryption. + * \param input The ciphertext block. + * \param output The output (plaintext) block. + * + * \return \c 0 on success. + */ +int utils_internal_aes_decrypt(utils_aes_context *ctx, const unsigned char input[16], unsigned char output[16]); + +#if !defined(UTILS_DEPRECATED_REMOVED) +#if defined(UTILS_DEPRECATED_WARNING) +#define UTILS_DEPRECATED __attribute__((deprecated)) +#else +#define UTILS_DEPRECATED +#endif +/** + * \brief Deprecated internal AES block encryption function + * without return value. + * + * \deprecated Superseded by utils_internal_aes_encrypt() + * + * \param ctx The AES context to use for encryption. + * \param input Plaintext block. + * \param output Output (ciphertext) block. + */ +UTILS_DEPRECATED void utils_aes_encrypt(utils_aes_context *ctx, const unsigned char input[16], + unsigned char output[16]); + +/** + * \brief Deprecated internal AES block decryption function + * without return value. + * + * \deprecated Superseded by utils_internal_aes_decrypt() + * + * \param ctx The AES context to use for decryption. + * \param input Ciphertext block. + * \param output Output (plaintext) block. + */ +UTILS_DEPRECATED void utils_aes_decrypt(utils_aes_context *ctx, const unsigned char input[16], + unsigned char output[16]); + +#undef UTILS_DEPRECATED +#endif /* !UTILS_DEPRECATED_REMOVED */ + +#if defined(UTILS_SELF_TEST) +/** + * \brief Checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int utils_aes_self_test(int verbose); + +#endif /* UTILS_SELF_TEST */ + +int aes_sample(int verbose); + +int utils_aes_cbc(uint8_t *pInData, uint32_t datalen, uint8_t *pOutData, uint32_t outBuffLen, uint8_t mode, + uint8_t *pKey, uint16_t keybits, uint8_t *iv); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_base64.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_base64.h new file mode 100644 index 00000000..659c0da0 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_base64.h @@ -0,0 +1,40 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_UTILS_BASE64_H_ +#define QCLOUD_IOT_UTILS_BASE64_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "qcloud_iot_export_error.h" +#include "qcloud_iot_export_log.h" + +int qcloud_iot_utils_base64encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen); + +int qcloud_iot_utils_base64decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen); + +#ifdef __cplusplus +} +#endif +#endif /* QCLOUD_IOT_UTILS_BASE64_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_hmac.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_hmac.h new file mode 100644 index 00000000..88a053ac --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_hmac.h @@ -0,0 +1,32 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_UTILS_HMAC_H_ +#define QCLOUD_IOT_UTILS_HMAC_H_ + +#include + +void utils_hmac_md5(const char *msg, int msg_len, char *digest, const char *key, int key_len); + +void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len); + +int utils_hmac_sha1_hex(const char *msg, int msg_len, char *digest, const char *key, int key_len); + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_httpc.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_httpc.h new file mode 100644 index 00000000..3d283f4a --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_httpc.h @@ -0,0 +1,85 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_UTILS_HTTPC_H_ +#define QCLOUD_IOT_UTILS_HTTPC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "network_interface.h" + +#define HTTP_PREFIX ("http://") +#define HTTPS_PREFIX ("https://") +#define HTTP_PORT 80 +#define HTTPS_PORT 443 + +typedef enum { HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_DELETE, HTTP_HEAD } HttpMethod; + +typedef struct { + int remote_port; + int response_code; + char * header; + char * auth_user; + char * auth_password; + Network network_stack; +} HTTPClient; + +typedef struct { + bool is_more; // if more data to check + bool is_chunked; // if response in chunked data + int retrieve_len; // length of retrieve + int response_content_len; // length of resposne content + int post_buf_len; // post data length + int response_buf_len; // length of response data buffer + char *post_content_type; // type of post content + char *post_buf; // post data buffer + char *response_buf; // response data buffer +} HTTPClientData; + +/** + * @brief do one http request + * + * @param client http client + * @param url server url + * @param port server port + * @param ca_crt_dir ca path + * @param method type of request + * @param client_data http data + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +int qcloud_http_client_common(HTTPClient *client, const char *url, int port, const char *ca_crt, HttpMethod method, + HTTPClientData *client_data); + +int qcloud_http_recv_data(HTTPClient *client, uint32_t timeout_ms, HTTPClientData *client_data); + +int qcloud_http_send_data(HTTPClient *client, HttpMethod method, uint32_t timeout_ms, HTTPClientData *client_data); + +int qcloud_http_client_connect(HTTPClient *client, const char *url, int port, const char *ca_crt); + +void qcloud_http_client_close(HTTPClient *client); + +#ifdef __cplusplus +} +#endif +#endif /* QCLOUD_IOT_UTILS_HTTPC_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_list.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_list.h new file mode 100644 index 00000000..22a94478 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_list.h @@ -0,0 +1,97 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_UTILS_LIST_H_ +#define QCLOUD_IOT_UTILS_LIST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * ListNode iterator direction + */ +typedef enum { LIST_HEAD, LIST_TAIL } ListDirection; + +/* + * define list node + */ +typedef struct ListNode { + struct ListNode *prev; + struct ListNode *next; + void * val; +} ListNode; + +/* + * Double Linked List + */ +typedef struct { + ListNode * head; + ListNode * tail; + unsigned int len; + void (*free)(void *val); + int (*match)(void *a, void *b); +} List; + +/* + * list iterator + */ +typedef struct { + ListNode * next; + ListDirection direction; +} ListIterator; + +/* create node */ +ListNode *list_node_new(void *val); + +/* create list */ +List *list_new(void); + +ListNode *list_rpush(List *self, ListNode *node); + +ListNode *list_lpush(List *self, ListNode *node); + +ListNode *list_find(List *self, void *val); + +ListNode *list_at(List *self, int index); + +ListNode *list_rpop(List *self); + +ListNode *list_lpop(List *self); + +void list_remove(List *self, ListNode *node); + +void list_destroy(List *self); + +/* create iterator */ +ListIterator *list_iterator_new(List *list, ListDirection direction); + +ListIterator *list_iterator_new_from_node(ListNode *node, ListDirection direction); + +ListNode *list_iterator_next(ListIterator *self); + +void list_iterator_destroy(ListIterator *self); + +#ifdef __cplusplus +} +#endif +#endif // QCLOUD_IOT_UTILS_LIST_H_ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_md5.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_md5.h new file mode 100644 index 00000000..bda3022a --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_md5.h @@ -0,0 +1,130 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_UTILS_MD5_H_ +#define QCLOUD_IOT_UTILS_MD5_H_ + +#include "qcloud_iot_import.h" + +typedef struct { + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} iot_md5_context; + +/** + * @brief init MD5 context + * + * @param ctx MD5 context + */ +void utils_md5_init(iot_md5_context *ctx); + +/** + * @brief free MD5 context + * + * @param ctx MD5 context + */ +void utils_md5_free(iot_md5_context *ctx); + +/** + * @brief clone MD5 context + * + * @param dst destination MD5 context + * @param src source MD5 context + */ +void utils_md5_clone(iot_md5_context *dst, const iot_md5_context *src); + +/** + * @brief start MD5 calculation + * + * @param ctx MD5 context + */ +void utils_md5_starts(iot_md5_context *ctx); + +/** + * @brief MD5 update + * + * @param ctx MD5 context + * @param input input data + * @param ilen data length + */ +void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, size_t ilen); + +/** + * @brief finish MD5 calculation + * + * @param ctx MD5 context + * @param output MD5 result + */ +void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16]); + +/* MD5 internal process */ +void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64]); + +/** + * @brief Output = MD5( input buffer ) + * + * @param input data input + * @param ilen data length + * @param output MD5 result + */ +void utils_md5(const unsigned char *input, size_t ilen, unsigned char output[16]); + +/** + * @brief Output = MD5( input buffer ) + * + * @param input data input + * @param ilen data length + * @param output string MD5 result + */ +void utils_md5_str(const unsigned char *input, size_t ilen, unsigned char *output); + +int8_t utils_hb2hex(uint8_t hb); + +/** + * @brief create md5 context dynamic + * + * @return MD5 context + */ +void *utils_md5_create(void); + +/** + * @brief Output = str(md5) + * + * @param ctx MD5 ctx + * @param output_str string MD5 result + */ +void utils_md5_finish_str(void *ctx, char *output_str); + +/** + * @brief free MD5 context + * + * @param ctx MD5 ctx + */ +void utils_md5_delete(void *ctx); + +/** + * @brief reset MD5 context + * + * @param ctx MD5 ctx + */ +void utils_md5_reset(void *ctx); + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_param_check.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_param_check.h new file mode 100644 index 00000000..3b89d548 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_param_check.h @@ -0,0 +1,90 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef _UTILS_PARAM_CHECK_H_ +#define _UTILS_PARAM_CHECK_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +#include "qcloud_iot_export_log.h" + +#define NUMBERIC_SANITY_CHECK(num, err) \ + do { \ + if (0 == (num)) { \ + Log_e("Invalid argument, numeric 0"); \ + return (err); \ + } \ + } while (0) + +#define NUMBERIC_SANITY_CHECK_RTN(num) \ + do { \ + if (0 == (num)) { \ + Log_e("Invalid argument, numeric 0"); \ + return; \ + } \ + } while (0) + +#define POINTER_SANITY_CHECK(ptr, err) \ + do { \ + if (NULL == (ptr)) { \ + Log_e("Invalid argument, %s = %p", #ptr, ptr); \ + return (err); \ + } \ + } while (0) + +#define POINTER_SANITY_CHECK_RTN(ptr) \ + do { \ + if (NULL == (ptr)) { \ + Log_e("Invalid argument, %s = %p", #ptr, ptr); \ + return; \ + } \ + } while (0) + +#define STRING_PTR_SANITY_CHECK(ptr, err) \ + do { \ + if (NULL == (ptr)) { \ + Log_e("Invalid argument, %s = %p", #ptr, (ptr)); \ + return (err); \ + } \ + if (0 == strlen((ptr))) { \ + Log_e("Invalid argument, %s = '%s'", #ptr, (ptr)); \ + return (err); \ + } \ + } while (0) + +#define STRING_PTR_SANITY_CHECK_RTN(ptr) \ + do { \ + if (NULL == (ptr)) { \ + Log_e("Invalid argument, %s = %p", #ptr, (ptr)); \ + return; \ + } \ + if (0 == strlen((ptr))) { \ + Log_e("Invalid argument, %s = '%s'", #ptr, (ptr)); \ + return; \ + } \ + } while (0) + +#if defined(__cplusplus) +} +#endif + +#endif /* _UTILS_PARAM_CHECK_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_ringbuff.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_ringbuff.h new file mode 100644 index 00000000..cb88e9c4 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_ringbuff.h @@ -0,0 +1,47 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef __AT_RING_BUFF_H__ +#define __AT_RING_BUFF_H__ + +#include "stdbool.h" +#include "stdint.h" + +#define RINGBUFF_OK 0 /* No error, everything OK. */ +#define RINGBUFF_ERR -1 /* Out of memory error. */ +#define RINGBUFF_EMPTY -3 /* Timeout. */ +#define RINGBUFF_FULL -4 /* Routing problem. */ +#define RINGBUFF_TOO_SHORT -5 + +typedef struct _ring_buff_ { + uint32_t size; + uint32_t readpoint; + uint32_t writepoint; + char * buffer; + bool full; +} sRingbuff; + +typedef sRingbuff *ring_buff_t; + +int ring_buff_init(sRingbuff *ring_buff, char *buff, uint32_t size); +int ring_buff_flush(sRingbuff *ring_buff); +int ring_buff_push_data(sRingbuff *ring_buff, uint8_t *pData, int len); +int ring_buff_pop_data(sRingbuff *ring_buff, uint8_t *pData, int len); +#endif // __ringbuff_h__ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_sha1.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_sha1.h new file mode 100644 index 00000000..02caa479 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_sha1.h @@ -0,0 +1,93 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_UTILS_SHA1_H_ +#define QCLOUD_IOT_UTILS_SHA1_H_ + +#include "qcloud_iot_import.h" + +/** + * \brief SHA-1 context structure + */ +typedef struct { + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} iot_sha1_context; + +/** + * \brief Initialize SHA-1 context + * + * \param ctx SHA-1 context to be initialized + */ +void utils_sha1_init(iot_sha1_context *ctx); + +/** + * \brief Clear SHA-1 context + * + * \param ctx SHA-1 context to be cleared + */ +void utils_sha1_free(iot_sha1_context *ctx); + +/** + * \brief Clone (the state of) a SHA-1 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void utils_sha1_clone(iot_sha1_context *dst, const iot_sha1_context *src); + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void utils_sha1_starts(iot_sha1_context *ctx); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]); + +/* Internal use */ +void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]); + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20]); + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_timer.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_timer.h new file mode 100644 index 00000000..168ba6db --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_timer.h @@ -0,0 +1,85 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef QCLOUD_IOT_UTILS_TIMER_H_ +#define QCLOUD_IOT_UTILS_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Add the platform specific timer includes to define the Timer struct +#include "qcloud_iot_import.h" + +/** + * @brief Check if a timer is expired + * + * Call this function passing in a timer to check if that timer has expired. + * + * @param timer - pointer to the timer to be checked for expiration + * @return bool - true = timer expired, false = timer not expired + */ +bool expired(Timer *timer); + +/** + * @brief Create a timer (milliseconds) + * + * Sets the timer to expire in a specified number of milliseconds. + * + * @param timer - pointer to the timer to be set to expire in milliseconds + * @param timeout_ms - set the timer to expire in this number of milliseconds + */ +void countdown_ms(Timer *timer, unsigned int timeout_ms); + +/** + * @brief Create a timer (seconds) + * + * Sets the timer to expire in a specified number of seconds. + * + * @param timer - pointer to the timer to be set to expire in seconds + * @param timeout - set the timer to expire in this number of seconds + */ +void countdown(Timer *timer, unsigned int timeout); + +/** + * @brief Check the time remaining on a give timer + * + * Checks the input timer and returns the number of milliseconds remaining on + * the timer. + * + * @param timer - pointer to the timer to be set to checked + * @return int - milliseconds left on the countdown timer + */ +int left_ms(Timer *timer); + +/** + * @brief Initialize a timer + * + * Performs any initialization required to the timer passed in. + * + * @param timer - pointer to the timer to be initialized + */ +void InitTimer(Timer *timer); + +#ifdef __cplusplus +} +#endif + +#endif // QCLOUD_IOT_UTILS_TIMER_H_ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_url_download.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_url_download.h new file mode 100644 index 00000000..7b8a55a1 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_url_download.h @@ -0,0 +1,42 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef UTILS_URL_DOWNLOAD_H_ +#define UTILS_URL_DOWNLOAD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void *qcloud_url_download_init(const char *url, uint32_t offset, uint32_t size); + +int32_t qcloud_url_download_connect(void *handle, int https_enabled); + +int32_t qcloud_url_download_fetch(void *handle, char *buf, uint32_t bufLen, uint32_t timeout_s); + +int qcloud_url_download_deinit(void *handle); + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_URL_DOWNLOAD_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_url_upload.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_url_upload.h new file mode 100644 index 00000000..6fc791cf --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/qutils_url_upload.h @@ -0,0 +1,44 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifndef UTILS_URL_UPLOAD_H_ +#define UTILS_URL_UPLOAD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void *qcloud_url_upload_init(const char *url, uint32_t content_len); + +int32_t qcloud_url_upload_connect(void *handle, int method); + +int32_t qcloud_url_upload_body(void *handle, char *data_buf, uint32_t data_Len, uint32_t timeout_ms); + +int32_t qcloud_url_upload_recv_response(void *handle, char *response_buf, uint32_t bufLen, uint32_t timeout_ms); + +int qcloud_url_upload_deinit(void *handle); + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_URL_DOWNLOAD_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/resource_client.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/resource_client.h new file mode 100644 index 00000000..ba936be7 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/resource_client.h @@ -0,0 +1,40 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_RESOURCE_CLIENT_H_ +#define IOT_RESOURCE_CLIENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "qcloud_iot_export_resource.h" + +#define MAX_RES_WAIT_POST (10) + +typedef enum { + eRESOURCE_PROGRESS, + eRESOURCE_VERSION, + eRESOURCE_UPGRADE_RESULT, + eRESOURCE_POST_REQ, + eRESOURCE_POST_RESULT +} eResourceReportType; + +#ifdef __cplusplus +} +#endif + +#endif /* IOT_RESOURCE_CLIENT_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/service_mqtt.h b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/service_mqtt.h new file mode 100644 index 00000000..90fd6130 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/internal_inc/service_mqtt.h @@ -0,0 +1,50 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef IOT_SERVICE_COM_H_ +#define IOT_SERVICE_COM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define FIELD_METHOD "method" +#define METHOD_RES_REPORT_VERSION_RSP "report_version_rsp" +#define METHOD_RES_UPDATE_RESOURCE "update_resource" +#define METHOD_RES_DELETE_RESOURCE "del_resource" +#define METHOD_RES_REQ_URL_RESP "request_url_resp" +#define METHOD_FACE_AI_REPLY "call_service_reply" + + +typedef enum { + eSERVICE_RESOURCE = 0, + eSERVICE_FACE_AI = 1, + eSERVICE_DEFAULT = 0xff +} eServiceEvent; + +typedef void (*OnServiceMessageCallback)(void *pContext, const char *msg, uint32_t msgLen); + +int qcloud_service_mqtt_init(const char *productId, const char *deviceName, void *mqtt_client); +void qcloud_service_mqtt_deinit(void *mqtt_client); +int qcloud_service_mqtt_post_msg(void *mqtt_client, const char *msg, int qos); +int qcloud_service_mqtt_event_register(eServiceEvent evt, OnServiceMessageCallback callback, void *context); + +#ifdef __cplusplus +} +#endif + +#endif /* IOT_SERVICE_COM_H_ */ diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/json_parser.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/json_parser.c new file mode 100644 index 00000000..e42d78b4 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/json_parser.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2017-2019 Tencent Group. All rights reserved. + * License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/** + * Edit by shockcao@tencent.com 2018/3/15 + */ + +#include "json_parser.h" + +#include +#include +#include +#include + +#include "lite-utils.h" +#include "qcloud_iot_export_log.h" + +#define json_debug Log_d + +typedef struct JSON_NV { + int nLen; + int vLen; + int vType; + char *pN; + char *pV; +} JSON_NV; + +char *json_get_object(int type, char *str) +{ + char *pos = 0; + char ch = (type == JSOBJECT) ? '{' : '['; + while (str != 0 && *str != 0) { + if (*str == ' ') { + str++; + continue; + } + pos = (*str == ch) ? str : 0; + break; + } + return pos; +} + +char *json_get_next_object(int type, char *str, char **key, int *key_len, char **val, int *val_len, int *val_type) +{ + char JsonMark[JSTYPEMAX][2] = {{'\"', '\"'}, {'{', '}'}, {'[', ']'}, {'0', ' '}}; + int iMarkDepth = 0, iValueType = JSNONE, iNameLen = 0, iValueLen = 0; + char *p_cName = 0, *p_cValue = 0, *p_cPos = str; + char lastchr = ' '; + + if (type == JSOBJECT) { + /* Get Key */ + p_cPos = strchr(p_cPos, '"'); + if (!p_cPos) { + return 0; + } + p_cName = ++p_cPos; + p_cPos = strchr(p_cPos, '"'); + if (!p_cPos) { + return 0; + } + iNameLen = p_cPos - p_cName; + + /* Get Value */ + p_cPos = strchr(p_cPos, ':'); + } + while (p_cPos && *p_cPos) { + if (*p_cPos == '"') { + iValueType = JSSTRING; + lastchr = *p_cPos; + p_cValue = ++p_cPos; + break; + } else if (*p_cPos == '{') { + iValueType = JSOBJECT; + p_cValue = p_cPos++; + break; + } else if (*p_cPos == '[') { + iValueType = JSARRAY; + p_cValue = p_cPos++; + break; + } else if ((*p_cPos == '-') || (*p_cPos >= '0' && *p_cPos <= '9')) { + iValueType = JSNUMBER; + p_cValue = p_cPos++; + break; + } else if (*p_cPos == 't' || *p_cPos == 'T' || *p_cPos == 'f' || *p_cPos == 'F') { + iValueType = JSBOOLEAN; + p_cValue = p_cPos; + break; + } else if (*p_cPos == 'n' || *p_cPos == 'N') { + iValueType = JSNULL; + p_cValue = p_cPos; + break; + } + p_cPos++; + } + while (p_cPos && *p_cPos && iValueType > JSNONE) { + if (iValueType == JSBOOLEAN) { + int len = strlen(p_cValue); + + if ((*p_cValue == 't' || *p_cValue == 'T') && len >= 4 && + (!strncmp(p_cValue, "true", 4) || !strncmp(p_cValue, "TRUE", 4))) { + iValueLen = 4; + // p_cPos = p_cValue + iValueLen; + break; + } else if ((*p_cValue == 'f' || *p_cValue == 'F') && len >= 5 && + (!strncmp(p_cValue, "false", 5) || !strncmp(p_cValue, "FALSE", 5))) { + iValueLen = 5; + // p_cPos = p_cValue + iValueLen; + break; + } + } else if (iValueType == JSNULL) { // support null/NULL + int nlen = strlen(p_cValue); + + if ((*p_cValue == 'n' || *p_cValue == 'N') && nlen >= 4 && + (!strncmp(p_cValue, "null", 4) || !strncmp(p_cValue, "NULL", 4))) { + iValueLen = 4; + // p_cPos = p_cValue + iValueLen; + break; + } + } else if (iValueType == JSNUMBER) { + // if (*p_cPos < '0' || *p_cPos > '9') { + if ((*p_cPos < '0' || *p_cPos > '9') && (*p_cPos != '.')) { // support float + iValueLen = p_cPos - p_cValue; + break; + } + } else if (*p_cPos == JsonMark[iValueType][1]) { + if (iMarkDepth == 0) { + iValueLen = p_cPos - p_cValue + (iValueType == JSSTRING ? 0 : 1); + p_cPos++; + if ((iValueType == JSSTRING) && (lastchr == '\\')) { + lastchr = *p_cPos; + continue; + } else { + break; + } + } else { + iMarkDepth--; + } + } else if (*p_cPos == JsonMark[iValueType][0]) { + iMarkDepth++; + } + lastchr = *p_cPos; + p_cPos++; + } + + if (type == JSOBJECT) { + *key = p_cName; + *key_len = iNameLen; + } + + *val = p_cValue; + *val_len = iValueLen; + *val_type = iValueType; + if (iValueType == JSSTRING) { + return p_cValue + iValueLen + 1; + } else { + return p_cValue + iValueLen; + } +} + +int json_parse_name_value(char *p_cJsonStr, int iStrLen, json_parse_cb pfnCB, void *p_CBData) +{ + char *pos = 0, *key = 0, *val = 0; + int klen = 0, vlen = 0, vtype = 0; + char last_char = 0; + int ret = JSON_RESULT_ERR; + + if (p_cJsonStr == NULL || iStrLen == 0 || pfnCB == NULL) { + return ret; + } + + if (iStrLen != strlen(p_cJsonStr)) { + Log_w("Backup last_char since %d != %d", iStrLen, (int)strlen(p_cJsonStr)); + backup_json_str_last_char(p_cJsonStr, iStrLen, last_char); + } + + json_object_for_each_kv(p_cJsonStr, pos, key, klen, val, vlen, vtype) + { + if (key && klen && val && vlen) { + ret = JSON_RESULT_OK; + if (JSON_PARSE_FINISH == pfnCB(key, klen, val, vlen, vtype, p_CBData)) { + break; + } + } + } + + if (iStrLen != strlen(p_cJsonStr)) { + restore_json_str_last_char(p_cJsonStr, iStrLen, last_char); + } + + return ret; +} + +int json_get_value_by_name_cb(char *p_cName, int iNameLen, char *p_cValue, int iValueLen, int iValueType, + void *p_CBData) +{ + JSON_NV *p_stNameValue = (JSON_NV *)p_CBData; + +#if (JSON_DEBUG == 1) + int i; + + if (p_cName) { + json_debug("Name:"); + for (i = 0; i < iNameLen; i++) { + json_debug("%c", *(p_cName + i)); + } + } + + if (p_cValue) { + json_debug("Value:"); + for (i = 0; i < iValueLen; i++) { + json_debug("%c", *(p_cValue + i)); + } + } +#endif + + if ((iNameLen == p_stNameValue->nLen) && !strncmp(p_cName, p_stNameValue->pN, p_stNameValue->nLen)) { + p_stNameValue->pV = p_cValue; + p_stNameValue->vLen = iValueLen; + p_stNameValue->vType = iValueType; + return JSON_PARSE_FINISH; + } else { + return JSON_PARSE_OK; + } +} + +char *json_get_value_by_name(char *p_cJsonStr, int iStrLen, char *p_cName, int *p_iValueLen, int *p_iValueType) +{ + JSON_NV stNV; + + memset(&stNV, 0, sizeof(stNV)); + stNV.pN = p_cName; + stNV.nLen = strlen(p_cName); + if (JSON_RESULT_OK == json_parse_name_value(p_cJsonStr, iStrLen, json_get_value_by_name_cb, (void *)&stNV)) { + if (p_iValueLen) { + *p_iValueLen = stNV.vLen; + } + if (p_iValueType) { + *p_iValueType = stNV.vType; + if (JSNULL == stNV.vType) { + stNV.pV = NULL; + } + } + } + return stNV.pV; +} diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/json_token.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/json_token.c new file mode 100644 index 00000000..202ba88c --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/json_token.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2017-2019 Tencent Group. All rights reserved. + * License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/** + * Edit by shockcao@tencent.com 2018/3/15 + */ + +#include "json_parser.h" +#include "lite-utils.h" +#include "qcloud_iot_export_error.h" + +#ifndef SCNi8 +#define SCNi8 "hhi" +#endif + +#ifndef SCNu8 +#define SCNu8 "hhu" +#endif + +char *LITE_json_value_of(char *key, char *src) +{ + char *value = NULL; + int value_len = -1; + char *ret = NULL; + + char *delim = NULL; + char *key_iter; + char *key_next; + int key_len; + char *src_iter; + + src_iter = src; + key_iter = key; + + do { + if ((delim = strchr(key_iter, '.')) != NULL) { + key_len = delim - key_iter; + key_next = HAL_Malloc(key_len + 1); + strncpy(key_next, key_iter, key_len); + key_next[key_len] = '\0'; + value = json_get_value_by_name(src_iter, strlen(src_iter), key_next, &value_len, 0); + + if (value == NULL) { + HAL_Free(key_next); + return NULL; + } + + src_iter = value; + key_iter = delim + 1; + HAL_Free(key_next); + } + } while (delim); + + value = json_get_value_by_name(src_iter, strlen(src_iter), key_iter, &value_len, 0); + if (NULL == value) { + return NULL; + } + ret = HAL_Malloc((value_len + 1) * sizeof(char)); + if (NULL == ret) { + return NULL; + } + HAL_Snprintf(ret, value_len + 1, "%s", value); + return ret; +} + +list_head_t *LITE_json_keys_of(char *src, char *prefix) +{ + static LIST_HEAD(keylist); + + char *pos = 0, *key = 0, *val = 0; + int klen = 0, vlen = 0, vtype = 0; + + if (src == NULL || prefix == NULL) { + return NULL; + } + + if (!strcmp("", prefix)) { + INIT_LIST_HEAD(&keylist); + } + + json_object_for_each_kv(src, pos, key, klen, val, vlen, vtype) + { + if (key && klen && val && vlen) { + json_key_t *entry = NULL; + + entry = HAL_Malloc(sizeof(json_key_t)); + memset(entry, 0, sizeof(json_key_t)); + entry->key = LITE_format_string("%s%.*s", prefix, klen, key); + list_add_tail(&entry->list, &keylist); + + if (JSOBJECT == vtype) { + char *iter_val = LITE_format_string("%.*s", vlen, val); + char *iter_pre = LITE_format_string("%s%.*s.", prefix, klen, key); + LITE_json_keys_of(iter_val, iter_pre); + HAL_Free(iter_val); + HAL_Free(iter_pre); + } + } + } + + if (!strcmp("", prefix)) { + json_key_t *entry = NULL; + + entry = HAL_Malloc(sizeof(json_key_t)); + memset(entry, 0, sizeof(json_key_t)); + list_add_tail(&entry->list, &keylist); + + return &keylist; + } + + return NULL; +} + +void LITE_json_keys_release(list_head_t *keylist) +{ + json_key_t *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, keylist, list, json_key_t) + { + if (pos->key) { + HAL_Free(pos->key); + } + list_del(&pos->list); + HAL_Free(pos); + } +} + +void LITE_string_strip_char(char *src, char ch) +{ + char *end = src + strlen(src) + 1; + + while (*src != '\0') { + if (*src == ch) { + memmove(src, src + 1, end - src); + end--; + } + src++; + } +} + +char *LITE_json_string_value_strip_transfer(char *key, char *src) +{ + char *str = LITE_json_value_of(key, src); + + if (NULL != str) { + LITE_string_strip_char(str, '\\'); + } + return str; +} + +int LITE_get_int32(int32_t *value, char *src) +{ + return (sscanf(src, "%" SCNi32, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE; +} + +int LITE_get_int16(int16_t *value, char *src) +{ + return (sscanf(src, "%" SCNi16, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE; +} + +int LITE_get_int8(int8_t *value, char *src) +{ + return (sscanf(src, "%" SCNi8, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE; +} + +int LITE_get_uint32(uint32_t *value, char *src) +{ + return (sscanf(src, "%" SCNu32, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE; +} + +int LITE_get_uint16(uint16_t *value, char *src) +{ + return (sscanf(src, "%" SCNu16, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE; +} + +int LITE_get_uint8(uint8_t *value, char *src) +{ + return (sscanf(src, "%" SCNu8, value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE; +} + +int LITE_get_float(float *value, char *src) +{ + return (sscanf(src, "%f", value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE; +} + +int LITE_get_double(double *value, char *src) +{ + return (sscanf(src, "%lf", value) == 1) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE; +} + +int LITE_get_boolean(bool *value, char *src) +{ + if (!strcmp(src, "false")) { + *value = false; + } else { + *value = true; + } + + return QCLOUD_RET_SUCCESS; +} + +int LITE_get_string(int8_t *value, char *src, uint16_t max_len) +{ + int rc; + + if (NULL != strncpy((char *)value, src, max_len)) { + value[Min(strlen(src), max_len)] = '\0'; + rc = QCLOUD_RET_SUCCESS; + } else { + rc = QCLOUD_ERR_FAILURE; + } + + return rc; +} diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client.c new file mode 100644 index 00000000..d2b66ea1 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client.c @@ -0,0 +1,568 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lite-utils.h" +#include "log_upload.h" +#include "mqtt_client.h" +#include "qcloud_iot_ca.h" +#include "qcloud_iot_common.h" +#include "qcloud_iot_device.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_base64.h" +#include "qutils_list.h" + +static uint16_t _get_random_start_packet_id(void) +{ + srand((unsigned)HAL_GetTimeMs()); + return rand() % 65536 + 1; +} + +// currently return a constant value +int IOT_MQTT_GetErrCode(void) +{ + return QCLOUD_ERR_FAILURE; +} + +void *IOT_MQTT_Construct(MQTTInitParams *pParams) +{ + POINTER_SANITY_CHECK(pParams, NULL); + STRING_PTR_SANITY_CHECK(pParams->product_id, NULL); + STRING_PTR_SANITY_CHECK(pParams->device_name, NULL); + + Qcloud_IoT_Client *mqtt_client = NULL; + char * client_id = NULL; + + // create and init MQTTClient + if ((mqtt_client = (Qcloud_IoT_Client *)HAL_Malloc(sizeof(Qcloud_IoT_Client))) == NULL) { + Log_e("malloc MQTTClient failed"); + return NULL; + } + + int rc = qcloud_iot_mqtt_init(mqtt_client, pParams); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("mqtt init failed: %d", rc); + HAL_Free(mqtt_client); + return NULL; + } + + MQTTConnectParams connect_params = DEFAULT_MQTTCONNECT_PARAMS; + client_id = HAL_Malloc(MAX_SIZE_OF_CLIENT_ID + 1); + if (client_id == NULL) { + Log_e("malloc client_id failed"); + HAL_Free(mqtt_client); + return NULL; + } + memset(client_id, 0, MAX_SIZE_OF_CLIENT_ID + 1); + HAL_Snprintf(client_id, MAX_SIZE_OF_CLIENT_ID, "%s%s", pParams->product_id, pParams->device_name); + + connect_params.client_id = client_id; + // Upper limit of keep alive interval is (11.5 * 60) seconds + connect_params.keep_alive_interval = Min(pParams->keep_alive_interval_ms / 1000, 690); + connect_params.clean_session = pParams->clean_session; + connect_params.auto_connect_enable = pParams->auto_connect_enable; +#if defined(AUTH_WITH_NOTLS) && defined(AUTH_MODE_KEY) + if (pParams->device_secret == NULL) { + Log_e("Device secret is null!"); + qcloud_iot_mqtt_fini(mqtt_client); + HAL_Free(mqtt_client); + HAL_Free(client_id); + return NULL; + } + size_t src_len = strlen(pParams->device_secret); + size_t len; + memset(mqtt_client->psk_decode, 0x00, DECODE_PSK_LENGTH); + rc = qcloud_iot_utils_base64decode(mqtt_client->psk_decode, DECODE_PSK_LENGTH, &len, + (unsigned char *)pParams->device_secret, src_len); + connect_params.device_secret = (char *)mqtt_client->psk_decode; + connect_params.device_secret_len = len; + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("Device secret decode err, secret:%s", pParams->device_secret); + qcloud_iot_mqtt_fini(mqtt_client); + HAL_Free(mqtt_client); + HAL_Free(client_id); + return NULL; + } +#endif + + rc = qcloud_iot_mqtt_connect(mqtt_client, &connect_params); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("mqtt connect with id: %s failed: %d", mqtt_client->options.conn_id, rc); + qcloud_iot_mqtt_fini(mqtt_client); + HAL_Free(mqtt_client); + HAL_Free(client_id); + return NULL; + } else { + Log_i("mqtt connect with id: %s success", mqtt_client->options.conn_id); + } + +#ifdef LOG_UPLOAD + // log subscribe topics + if (is_log_uploader_init()) { + set_log_mqtt_client((void *)mqtt_client); + int log_level; + rc = qcloud_get_log_level(&log_level); + if (rc < 0) { + Log_e("client get log topic failed: %d", rc); + } + + IOT_Log_Upload(true); + } +#endif + return mqtt_client; +} + +int IOT_MQTT_Destroy(void **pClient) +{ + POINTER_SANITY_CHECK(*pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)(*pClient); + + int rc = qcloud_iot_mqtt_disconnect(mqtt_client); + // disconnect network stack by force + if (rc != QCLOUD_RET_SUCCESS) { + mqtt_client->network_stack.disconnect(&(mqtt_client->network_stack)); + set_client_conn_state(mqtt_client, NOTCONNECTED); + } + + int i = 0; + for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) { + /* notify this event to topic subscriber */ + if (NULL != mqtt_client->sub_handles[i].topic_filter && NULL != mqtt_client->sub_handles[i].sub_event_handler) + mqtt_client->sub_handles[i].sub_event_handler(mqtt_client, MQTT_EVENT_CLIENT_DESTROY, + mqtt_client->sub_handles[i].handler_user_data); + + if (NULL != mqtt_client->sub_handles[i].topic_filter) { + HAL_Free((void *)mqtt_client->sub_handles[i].topic_filter); + mqtt_client->sub_handles[i].topic_filter = NULL; + } + } + +#ifdef MQTT_RMDUP_MSG_ENABLED + reset_repeat_packet_id_buffer(mqtt_client); +#endif + + HAL_MutexDestroy(mqtt_client->lock_generic); + HAL_MutexDestroy(mqtt_client->lock_write_buf); + + HAL_MutexDestroy(mqtt_client->lock_list_sub); + HAL_MutexDestroy(mqtt_client->lock_list_pub); + + list_destroy(mqtt_client->list_pub_wait_ack); + list_destroy(mqtt_client->list_sub_wait_ack); + HAL_Free(mqtt_client->options.client_id); + + HAL_Free(*pClient); + *pClient = NULL; +#ifdef LOG_UPLOAD + set_log_mqtt_client(NULL); +#endif + Log_i("mqtt release!"); + + return rc; +} + +int IOT_MQTT_Yield(void *pClient, uint32_t timeout_ms) +{ + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient; + +#ifdef MULTITHREAD_ENABLED + /* only one instance of yield is allowed in running state*/ + if (mqtt_client->yield_thread_running) { + HAL_SleepMs(timeout_ms); + return QCLOUD_RET_SUCCESS; + } +#endif + + int rc = qcloud_iot_mqtt_yield(mqtt_client, timeout_ms); + +#ifdef LOG_UPLOAD + /* do instant log uploading if MQTT communication error */ + if (rc == QCLOUD_RET_SUCCESS) + IOT_Log_Upload(false); + else + IOT_Log_Upload(true); +#endif + + return rc; +} + +int IOT_MQTT_Publish(void *pClient, char *topicName, PublishParams *pParams) +{ + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient; + + return qcloud_iot_mqtt_publish(mqtt_client, topicName, pParams); +} + +int IOT_MQTT_Subscribe(void *pClient, char *topicFilter, SubscribeParams *pParams) +{ + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient; + + return qcloud_iot_mqtt_subscribe(mqtt_client, topicFilter, pParams); +} + +int IOT_MQTT_Unsubscribe(void *pClient, char *topicFilter) +{ + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient; + + return qcloud_iot_mqtt_unsubscribe(mqtt_client, topicFilter); +} + +bool IOT_MQTT_IsSubReady(void *pClient, char *topicFilter) +{ + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient; + + return qcloud_iot_mqtt_is_sub_ready(mqtt_client, topicFilter); +} + +bool IOT_MQTT_IsConnected(void *pClient) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient; + + IOT_FUNC_EXIT_RC(get_client_conn_state(mqtt_client) == 1) +} + +#ifdef MULTITHREAD_ENABLED +static void _mqtt_yield_thread(void *ptr) +{ + int rc = QCLOUD_RET_SUCCESS; + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)ptr; + + Log_d("start mqtt_yield_thread..."); + while (mqtt_client->yield_thread_running) { + int rc = qcloud_iot_mqtt_yield(mqtt_client, 200); + +#ifdef LOG_UPLOAD + /* do instant log uploading if MQTT communication error */ + if (rc == QCLOUD_RET_SUCCESS) + IOT_Log_Upload(false); + else + IOT_Log_Upload(true); +#endif + + if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) { + HAL_SleepMs(500); + continue; + } else if (rc == QCLOUD_RET_MQTT_MANUALLY_DISCONNECTED || rc == QCLOUD_ERR_MQTT_RECONNECT_TIMEOUT) { + Log_e("MQTT Yield thread exit with error: %d", rc); + break; + } else if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) { + Log_e("MQTT Yield thread error: %d", rc); + } + + HAL_SleepMs(200); + } + + mqtt_client->yield_thread_running = false; + mqtt_client->yield_thread_exit_code = rc; + +#ifdef LOG_UPLOAD + IOT_Log_Upload(true); +#endif + +} + +int IOT_MQTT_StartLoop(void *pClient) +{ + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient; + ThreadParams thread_params = {0}; + thread_params.thread_func = _mqtt_yield_thread; + thread_params.thread_name = "mqtt_yield_thread"; + thread_params.user_arg = pClient; + thread_params.stack_size = 4096; + thread_params.priority = 1; + mqtt_client->yield_thread_running = true; + + int rc = HAL_ThreadCreate(&thread_params); + if (rc) { + Log_e("create mqtt yield thread fail: %d", rc); + return QCLOUD_ERR_FAILURE; + } + + HAL_SleepMs(500); + return QCLOUD_RET_SUCCESS; +} + +void IOT_MQTT_StopLoop(void *pClient) +{ + POINTER_SANITY_CHECK_RTN(pClient); + + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient; + mqtt_client->yield_thread_running = false; + HAL_SleepMs(1000); + return; +} + +bool IOT_MQTT_GetLoopStatus(void *pClient, int *exit_code) +{ + POINTER_SANITY_CHECK(pClient, false); + Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient; + *exit_code = mqtt_client->yield_thread_exit_code; + return mqtt_client->yield_thread_running; +} + +#endif + +int qcloud_iot_mqtt_init(Qcloud_IoT_Client *pClient, MQTTInitParams *pParams) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL); + + memset(pClient, 0x0, sizeof(Qcloud_IoT_Client)); + + int size = + HAL_Snprintf(pClient->host_addr, HOST_STR_LENGTH, "%s.%s", STRING_PTR_PRINT_SANITY_CHECK(pParams->product_id), + STRING_PTR_PRINT_SANITY_CHECK(iot_get_mqtt_domain(pParams->region))); + if (size < 0 || size > HOST_STR_LENGTH - 1) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + int i = 0; + for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) { + pClient->sub_handles[i].topic_filter = NULL; + pClient->sub_handles[i].message_handler = NULL; + pClient->sub_handles[i].sub_event_handler = NULL; + pClient->sub_handles[i].qos = QOS0; + pClient->sub_handles[i].handler_user_data = NULL; + } + + if (pParams->command_timeout < MIN_COMMAND_TIMEOUT) + pParams->command_timeout = MIN_COMMAND_TIMEOUT; + if (pParams->command_timeout > MAX_COMMAND_TIMEOUT) + pParams->command_timeout = MAX_COMMAND_TIMEOUT; + pClient->command_timeout_ms = pParams->command_timeout; + + // packet id, random from [1 - 65536] + pClient->next_packet_id = _get_random_start_packet_id(); + pClient->write_buf_size = QCLOUD_IOT_MQTT_TX_BUF_LEN; + pClient->read_buf_size = QCLOUD_IOT_MQTT_RX_BUF_LEN; + pClient->is_ping_outstanding = 0; + pClient->was_manually_disconnected = 0; + pClient->counter_network_disconnected = 0; +#ifdef MULTITHREAD_ENABLED + pClient->yield_thread_running = false; +#endif + pClient->event_handle = pParams->event_handle; + + pClient->lock_generic = HAL_MutexCreate(); + if (NULL == pClient->lock_generic) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + set_client_conn_state(pClient, NOTCONNECTED); + + if ((pClient->lock_write_buf = HAL_MutexCreate()) == NULL) { + Log_e("create write buf lock failed."); + goto error; + } + if ((pClient->lock_list_sub = HAL_MutexCreate()) == NULL) { + Log_e("create sub list lock failed."); + goto error; + } + if ((pClient->lock_list_pub = HAL_MutexCreate()) == NULL) { + Log_e("create pub list lock failed."); + goto error; + } + + if ((pClient->list_pub_wait_ack = list_new()) == NULL) { + Log_e("create pub wait list failed."); + goto error; + } + pClient->list_pub_wait_ack->free = HAL_Free; + + if ((pClient->list_sub_wait_ack = list_new()) == NULL) { + Log_e("create sub wait list failed."); + goto error; + } + pClient->list_sub_wait_ack->free = HAL_Free; + +#ifndef AUTH_WITH_NOTLS +// device param for TLS connection +#ifdef AUTH_MODE_CERT + Log_d("cert file: %s", STRING_PTR_PRINT_SANITY_CHECK(pParams->cert_file)); + Log_d("key file: %s", STRING_PTR_PRINT_SANITY_CHECK(pParams->key_file)); + + strncpy(pClient->cert_file_path, pParams->cert_file, FILE_PATH_MAX_LEN - 1); + strncpy(pClient->key_file_path, pParams->key_file, FILE_PATH_MAX_LEN - 1); + + pClient->network_stack.ssl_connect_params.cert_file = pClient->cert_file_path; + pClient->network_stack.ssl_connect_params.key_file = pClient->key_file_path; + pClient->network_stack.ssl_connect_params.ca_crt = iot_ca_get(); + pClient->network_stack.ssl_connect_params.ca_crt_len = strlen(pClient->network_stack.ssl_connect_params.ca_crt); +#else + if (pParams->device_secret != NULL) { + size_t src_len = strlen(pParams->device_secret); + size_t len; + memset(pClient->psk_decode, 0x00, DECODE_PSK_LENGTH); + qcloud_iot_utils_base64decode(pClient->psk_decode, DECODE_PSK_LENGTH, &len, + (unsigned char *)pParams->device_secret, src_len); + pClient->network_stack.ssl_connect_params.psk = (char *)pClient->psk_decode; + pClient->network_stack.ssl_connect_params.psk_length = len; + } else { + Log_e("psk is empty!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL); + } + + memset(pClient->network_stack.ssl_connect_params.psk_id, 0, MAX_SIZE_OF_CLIENT_ID); + HAL_Snprintf(pClient->network_stack.ssl_connect_params.psk_id, MAX_SIZE_OF_CLIENT_ID, "%s%s", + STRING_PTR_PRINT_SANITY_CHECK(pParams->product_id), + STRING_PTR_PRINT_SANITY_CHECK(pParams->device_name)); + pClient->network_stack.ssl_connect_params.ca_crt = NULL; + pClient->network_stack.ssl_connect_params.ca_crt_len = 0; +#endif + + pClient->network_stack.host = pClient->host_addr; + pClient->network_stack.port = MQTT_SERVER_PORT_TLS; + pClient->network_stack.ssl_connect_params.timeout_ms = + (pClient->command_timeout_ms > QCLOUD_IOT_TLS_HANDSHAKE_TIMEOUT) ? pClient->command_timeout_ms + : QCLOUD_IOT_TLS_HANDSHAKE_TIMEOUT; +#else + pClient->network_stack.host = pClient->host_addr; + pClient->network_stack.port = MQTT_SERVER_PORT_NOTLS; +#endif + + // init network stack + qcloud_iot_mqtt_network_init(&(pClient->network_stack)); + + // ping timer and reconnect delay timer + InitTimer(&(pClient->ping_timer)); + InitTimer(&(pClient->reconnect_delay_timer)); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + +error: + if (pClient->list_pub_wait_ack) { + pClient->list_pub_wait_ack->free(pClient->list_pub_wait_ack); + pClient->list_pub_wait_ack = NULL; + } + if (pClient->list_sub_wait_ack) { + pClient->list_sub_wait_ack->free(pClient->list_sub_wait_ack); + pClient->list_sub_wait_ack = NULL; + } + if (pClient->lock_generic) { + HAL_MutexDestroy(pClient->lock_generic); + pClient->lock_generic = NULL; + } + if (pClient->lock_list_sub) { + HAL_MutexDestroy(pClient->lock_list_sub); + pClient->lock_list_sub = NULL; + } + if (pClient->lock_list_pub) { + HAL_MutexDestroy(pClient->lock_list_pub); + pClient->lock_list_pub = NULL; + } + if (pClient->lock_write_buf) { + HAL_MutexDestroy(pClient->lock_write_buf); + pClient->lock_write_buf = NULL; + } + + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE) +} + +int qcloud_iot_mqtt_fini(Qcloud_IoT_Client *mqtt_client) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(mqtt_client, QCLOUD_ERR_INVAL); + + HAL_MutexDestroy(mqtt_client->lock_generic); + HAL_MutexDestroy(mqtt_client->lock_write_buf); + + HAL_MutexDestroy(mqtt_client->lock_list_sub); + HAL_MutexDestroy(mqtt_client->lock_list_pub); + + list_destroy(mqtt_client->list_pub_wait_ack); + list_destroy(mqtt_client->list_sub_wait_ack); + + Log_i("release mqtt client resources"); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int qcloud_iot_mqtt_set_autoreconnect(Qcloud_IoT_Client *pClient, bool value) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + pClient->options.auto_connect_enable = (uint8_t)value; + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +bool qcloud_iot_mqtt_is_autoreconnect_enabled(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + bool is_enabled = false; + if (pClient->options.auto_connect_enable == 1) { + is_enabled = true; + } + + IOT_FUNC_EXIT_RC(is_enabled); +} + +int qcloud_iot_mqtt_get_network_disconnected_count(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + IOT_FUNC_EXIT_RC(pClient->counter_network_disconnected); +} + +int qcloud_iot_mqtt_reset_network_disconnected_count(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + pClient->counter_network_disconnected = 0; + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + + + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_common.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_common.c new file mode 100644 index 00000000..2a64fab0 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_common.c @@ -0,0 +1,1436 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Sergio R. Caprile - non-blocking packet read functions for stream + *transport + *******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "mqtt_client.h" +#include "qutils_list.h" + +/* remain waiting time after MQTT header is received (unit: ms) */ +#define QCLOUD_IOT_MQTT_MAX_REMAIN_WAIT_MS (2000) + +#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4 + +/* return: 0, identical; NOT 0, different. */ +static int _check_handle_is_identical(SubTopicHandle *sub_handle1, SubTopicHandle *sub_handle2) +{ + if (!sub_handle1 || !sub_handle2) { + return 1; + } + + int topic_name_Len = strlen(sub_handle1->topic_filter); + + if (topic_name_Len != strlen(sub_handle2->topic_filter)) { + return 1; + } + + if (0 != strncmp(sub_handle1->topic_filter, sub_handle2->topic_filter, topic_name_Len)) { + return 1; + } + + if (sub_handle1->message_handler != sub_handle2->message_handler) { + return 1; + } + + if (sub_handle1->sub_event_handler != sub_handle2->sub_event_handler) { + return 1; + } + + return 0; +} + +uint16_t get_next_packet_id(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + HAL_MutexLock(pClient->lock_generic); + pClient->next_packet_id = + (uint16_t)((MAX_PACKET_ID == pClient->next_packet_id) ? 1 : (pClient->next_packet_id + 1)); + HAL_MutexUnlock(pClient->lock_generic); + + IOT_FUNC_EXIT_RC(pClient->next_packet_id); +} + +void get_next_conn_id(char *conn_id) +{ + int i; + srand((unsigned)HAL_GetTimeMs()); + for (i = 0; i < MAX_CONN_ID_LEN - 1; i++) { + int flag = rand() % 3; + switch (flag) { + case 0: + conn_id[i] = (rand() % 26) + 'a'; + break; + case 1: + conn_id[i] = (rand() % 26) + 'A'; + break; + case 2: + conn_id[i] = (rand() % 10) + '0'; + break; + } + } + + conn_id[MAX_CONN_ID_LEN - 1] = '\0'; +} + +/** + * Encodes the message length according to the MQTT algorithm + * @param buf the buffer into which the encoded data is written + * @param length the length to be encoded + * @return the number of bytes written to buffer + */ +size_t mqtt_write_packet_rem_len(unsigned char *buf, uint32_t length) +{ + IOT_FUNC_ENTRY; + + size_t outLen = 0; + + do { + unsigned char encodeByte; + encodeByte = (unsigned char)(length % 128); + length /= 128; + /* if there are more digits to encode, set the top bit of this digit */ + if (length > 0) { + encodeByte |= 0x80; + } + buf[outLen++] = encodeByte; + } while (length > 0); + + IOT_FUNC_EXIT_RC((int)outLen); +} + +size_t get_mqtt_packet_len(size_t rem_len) +{ + rem_len += 1; /* header byte */ + + /* now remaining_length field */ + if (rem_len < 128) { + rem_len += 1; + } else if (rem_len < 16384) { + rem_len += 2; + } else if (rem_len < 2097151) { + rem_len += 3; + } else { + rem_len += 4; + } + + return rem_len; +} + +/** + * Decodes the message length according to the MQTT algorithm + * @param getcharfn pointer to function to read the next character from the data + * source + * @param value the decoded length returned + * @return the number of bytes read from the socket + */ +static int _decode_packet_rem_len_from_buf_read(unsigned char *bufptr, uint32_t *value, uint32_t *readBytesLen) +{ + IOT_FUNC_ENTRY; + + unsigned char c; + uint32_t multiplier = 1; + uint32_t len = 0; + *value = 0; + do { + if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) { + /* bad data */ + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_PACKET_READ); + } + c = *bufptr++; + *value += (c & 127) * multiplier; + multiplier *= 128; + } while ((c & 128) != 0); + + *readBytesLen = len; + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int mqtt_read_packet_rem_len_form_buf(unsigned char *buf, uint32_t *value, uint32_t *readBytesLen) +{ + return _decode_packet_rem_len_from_buf_read(buf, value, readBytesLen); +} + +/** + * Calculates uint16 packet id from two bytes read from the input buffer + * @param pptr pointer to the input buffer - incremented by the number of bytes + * used & returned + * @return the value calculated + */ +uint16_t mqtt_read_uint16_t(unsigned char **pptr) +{ + unsigned char *ptr = *pptr; + uint8_t firstByte = (uint8_t)(*ptr); + uint8_t secondByte = (uint8_t)(*(ptr + 1)); + uint16_t len = (uint16_t)(secondByte + (256 * firstByte)); + *pptr += 2; + return len; +} + +/** + * Reads one character from the input buffer. + * @param pptr pointer to the input buffer - incremented by the number of bytes + * used & returned + * @return the character read + */ +unsigned char mqtt_read_char(unsigned char **pptr) +{ + unsigned char c = **pptr; + (*pptr)++; + return c; +} + +/** + * Writes one character to an output buffer. + * @param pptr pointer to the output buffer - incremented by the number of bytes + * used & returned + * @param c the character to write + */ +void mqtt_write_char(unsigned char **pptr, unsigned char c) +{ + **pptr = c; + (*pptr)++; +} + +/** + * Writes an integer as 2 bytes to an output buffer. + * @param pptr pointer to the output buffer - incremented by the number of bytes + * used & returned + * @param anInt the integer to write + */ +void mqtt_write_uint_16(unsigned char **pptr, uint16_t anInt) +{ + **pptr = (unsigned char)(anInt / 256); + (*pptr)++; + **pptr = (unsigned char)(anInt % 256); + (*pptr)++; +} + +/** + * Writes a "UTF" string to an output buffer. Converts C string to + * length-delimited. + * @param pptr pointer to the output buffer - incremented by the number of bytes + * used & returned + * @param string the C string to write + */ +void mqtt_write_utf8_string(unsigned char **pptr, const char *string) +{ + size_t len = strlen(string); + mqtt_write_uint_16(pptr, (uint16_t)len); + memcpy(*pptr, string, len); + *pptr += len; +} + +/** + * Initialize the MQTT Header fixed byte. Used to ensure that Header bits are + */ +int mqtt_init_packet_header(unsigned char *header, MessageTypes message_type, QoS Qos, uint8_t dup, uint8_t retained) +{ + POINTER_SANITY_CHECK(header, QCLOUD_ERR_INVAL); + unsigned char type, qos; + + switch (message_type) { + case RESERVED: + /* Should never happen */ + return QCLOUD_ERR_MQTT_UNKNOWN; + case CONNECT: + type = 0x01; + break; + case CONNACK: + type = 0x02; + break; + case PUBLISH: + type = 0x03; + break; + case PUBACK: + type = 0x04; + break; + case PUBREC: + type = 0x05; + break; + case PUBREL: + type = 0x06; + break; + case PUBCOMP: + type = 0x07; + break; + case SUBSCRIBE: + type = 0x08; + break; + case SUBACK: + type = 0x09; + break; + case UNSUBSCRIBE: + type = 0x0A; + break; + case UNSUBACK: + type = 0x0B; + break; + case PINGREQ: + type = 0x0C; + break; + case PINGRESP: + type = 0x0D; + break; + case DISCONNECT: + type = 0x0E; + break; + default: + /* Should never happen */ + return QCLOUD_ERR_MQTT_UNKNOWN; + } + + switch (Qos) { + case QOS0: + qos = 0x00; + break; + case QOS1: + qos = 0x01; + break; + case QOS2: + qos = 0x02; + break; + default: + /* Using QOS0 as default */ + qos = 0x00; + break; + } + + /* Generate the final protocol header by using bitwise operator */ + *header = ((type << MQTT_HEADER_TYPE_SHIFT) & MQTT_HEADER_TYPE_MASK) | + ((dup << MQTT_HEADER_DUP_SHIFT) & MQTT_HEADER_DUP_MASK) | + ((qos << MQTT_HEADER_QOS_SHIFT) & MQTT_HEADER_QOS_MASK) | (retained & MQTT_HEADER_RETAIN_MASK); + + return QCLOUD_RET_SUCCESS; +} + +/** + * Deserializes the supplied (wire) buffer into an ack + * @param packet_type returned integer - the MQTT packet type + * @param dup returned integer - the MQTT dup flag + * @param packet_id returned integer - the MQTT packet identifier + * @param buf the raw buffer data, of the correct length determined by the + * remaining length field + * @param buf_len the length in bytes of the data in the supplied buffer + * @return error code. 1 is success, 0 is failure + */ +int deserialize_ack_packet(uint8_t *packet_type, uint8_t *dup, uint16_t *packet_id, unsigned char *buf, size_t buf_len) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(packet_type, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(dup, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(packet_id, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + + int rc; + unsigned char header = 0; + unsigned char *curdata = buf; + unsigned char *enddata = NULL; + uint32_t decodedLen = 0, readBytesLen = 0; + + /* PUBACK fixed header size is two bytes, variable header is 2 bytes, MQTT + * v3.1.1 Specification 3.4.1 */ + if (4 > buf_len) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + + header = mqtt_read_char(&curdata); + *packet_type = ((header & MQTT_HEADER_TYPE_MASK) >> MQTT_HEADER_TYPE_SHIFT); + *dup = ((header & MQTT_HEADER_DUP_MASK) >> MQTT_HEADER_DUP_SHIFT); + + /* read remaining length */ + rc = mqtt_read_packet_rem_len_form_buf(curdata, &decodedLen, &readBytesLen); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + curdata += (readBytesLen); + enddata = curdata + decodedLen; + + if (enddata - curdata < 2) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + *packet_id = mqtt_read_uint16_t(&curdata); + + if (enddata - curdata >= 1) { + unsigned char ack_code = mqtt_read_char(&curdata); + if (ack_code != 0) { + Log_e("deserialize_ack_packet failure! ack_code = 0x%02x", ack_code); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * Deserializes the supplied (wire) buffer into suback data + * @param packet_id returned integer - the MQTT packet identifier + * @param max_count - the maximum number of members allowed in the grantedQoSs + * array + * @param count returned integer - number of members in the grantedQoSs array + * @param grantedQoSs returned array of integers - the granted qualities of + * service + * @param buf the raw buffer data, of the correct length determined by the + * remaining length field + * @param buf_len the length in bytes of the data in the supplied buffer + * @return error code. 1 is success, 0 is failure + */ +int deserialize_suback_packet(uint16_t *packet_id, uint32_t max_count, uint32_t *count, QoS *grantedQoSs, + unsigned char *buf, size_t buf_len) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(packet_id, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(count, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(grantedQoSs, QCLOUD_ERR_INVAL); + + unsigned char header, type = 0; + unsigned char *curdata = buf; + unsigned char *enddata = NULL; + int decodeRc; + uint32_t decodedLen = 0; + uint32_t readBytesLen = 0; + + // 4 bytes of SUBACK header size and at least 1 byte(QoS) in payload + if (5 > buf_len) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + // read 1st byte in fixed header + header = mqtt_read_char(&curdata); + type = (header & MQTT_HEADER_TYPE_MASK) >> MQTT_HEADER_TYPE_SHIFT; + if (type != SUBACK) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + // read remain part in fixed header + decodeRc = mqtt_read_packet_rem_len_form_buf(curdata, &decodedLen, &readBytesLen); + if (decodeRc != QCLOUD_RET_SUCCESS) { + IOT_FUNC_EXIT_RC(decodeRc); + } + + curdata += (readBytesLen); + enddata = curdata + decodedLen; + if (enddata - curdata < 2) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + // read packet id from variable header + *packet_id = mqtt_read_uint16_t(&curdata); + + // read payload + *count = 0; + while (curdata < enddata) { + if (*count > max_count) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + grantedQoSs[(*count)++] = (QoS)mqtt_read_char(&curdata); + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * Deserializes the supplied (wire) buffer into unsuback data + * @param packet_id returned integer - the MQTT packet identifier + * @param buf the raw buffer data, of the correct length determined by the + * remaining length field + * @param buf_len the length in bytes of the data in the supplied buffer + * @return int indicating function execution status + */ +int deserialize_unsuback_packet(uint16_t *packet_id, unsigned char *buf, size_t buf_len) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(packet_id, QCLOUD_ERR_INVAL); + + unsigned char type = 0; + unsigned char dup = 0; + int rc; + + rc = deserialize_ack_packet(&type, &dup, packet_id, buf, buf_len); + if (QCLOUD_RET_SUCCESS == rc && UNSUBACK != type) { + rc = QCLOUD_ERR_FAILURE; + } + + IOT_FUNC_EXIT_RC(rc); +} + +/** + * Serializes a 0-length packet into the supplied buffer, ready for writing to a + * socket + * @param buf the buffer into which the packet will be serialized + * @param buf_len the length in bytes of the supplied buffer, to avoid overruns + * @param packettype the message type + * @param serialized length + * @return int indicating function execution status + */ +int serialize_packet_with_zero_payload(unsigned char *buf, size_t buf_len, MessageTypes packetType, + uint32_t *serialized_len) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL); + + unsigned char header = 0; + unsigned char *ptr = buf; + int rc; + + /* Buffer should have at least 2 bytes for the header */ + if (4 > buf_len) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + + rc = mqtt_init_packet_header(&header, packetType, QOS0, 0, 0); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + /* write header */ + mqtt_write_char(&ptr, header); + + /* write remaining length */ + ptr += mqtt_write_packet_rem_len(ptr, 0); + *serialized_len = (uint32_t)(ptr - buf); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int send_mqtt_packet(Qcloud_IoT_Client *pClient, size_t length, Timer *timer) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(timer, QCLOUD_ERR_INVAL); + + int rc = QCLOUD_ERR_FAILURE; + size_t sentLen = 0, sent = 0; + + if (length >= pClient->write_buf_size) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + + while (sent < length && !expired(timer)) { + rc = pClient->network_stack.write(&(pClient->network_stack), &pClient->write_buf[sent], length, left_ms(timer), + &sentLen); + if (rc != QCLOUD_RET_SUCCESS) { + /* there was an error writing the data */ + break; + } + sent = sent + sentLen; + } + + if (sent == length) { + /* record the fact that we have successfully sent the packet */ + // countdown(&c->ping_timer, c->keep_alive_interval); + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + } + + IOT_FUNC_EXIT_RC(rc); +} + +static int _decode_packet_rem_len_with_net_read(Qcloud_IoT_Client *pClient, uint32_t *value, uint32_t timeout) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(value, QCLOUD_ERR_INVAL); + + unsigned char i; + uint32_t multiplier = 1; + uint32_t len = 0; + size_t read_len = 0; + + *value = 0; + + do { + if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) { + /* bad data */ + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_PACKET_READ) + } + + if ((pClient->network_stack.read(&(pClient->network_stack), &i, 1, timeout, &read_len)) != QCLOUD_RET_SUCCESS) { + /* The value argument is the important value. len is just used temporarily + * and never used by the calling function for anything else */ + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + *value += ((i & 127) * multiplier); + multiplier *= 128; + } while ((i & 128) != 0); + + /* The value argument is the important value. len is just used temporarily + * and never used by the calling function for anything else */ + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * @brief Read MQTT packet from network stack + * + * 1. read 1st byte in fixed header and check if valid + * 2. read the remaining length + * 3. read payload according to remaining length + * + * @param pClient MQTT Client + * @param timer timeout timer + * @param packet_type MQTT packet type + * @return QCLOUD_RET_SUCCESS for success, or err code for failure + */ +static int _read_mqtt_packet(Qcloud_IoT_Client *pClient, Timer *timer, uint8_t *packet_type) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(timer, QCLOUD_ERR_INVAL); + + uint32_t len = 0; + uint32_t rem_len = 0; + size_t read_len = 0; + int rc; + int timer_left_ms = left_ms(timer); + + if (timer_left_ms <= 0) { + timer_left_ms = 1; + } + + // 1. read 1st byte in fixed header and check if valid + rc = pClient->network_stack.read(&(pClient->network_stack), pClient->read_buf, 1, timer_left_ms, &read_len); + if (rc == QCLOUD_ERR_SSL_NOTHING_TO_READ || rc == QCLOUD_ERR_TCP_NOTHING_TO_READ) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NOTHING_TO_READ); + } else if (rc != QCLOUD_RET_SUCCESS) { + IOT_FUNC_EXIT_RC(rc); + } + + len = 1; + + // 2. read the remaining length + timer_left_ms = left_ms(timer); + if (timer_left_ms <= 0) { + timer_left_ms = 1; + } + timer_left_ms += QCLOUD_IOT_MQTT_MAX_REMAIN_WAIT_MS; + + rc = _decode_packet_rem_len_with_net_read(pClient, &rem_len, timer_left_ms); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + // if read buffer is not enough to read the remaining length, discard the + // packet + if (rem_len >= pClient->read_buf_size) { + size_t total_bytes_read = 0; + size_t bytes_to_be_read; + int32_t ret_val = 0; + + timer_left_ms = left_ms(timer); + if (timer_left_ms <= 0) { + timer_left_ms = 1; + } + timer_left_ms += QCLOUD_IOT_MQTT_MAX_REMAIN_WAIT_MS; + + bytes_to_be_read = pClient->read_buf_size; + do { + ret_val = pClient->network_stack.read(&(pClient->network_stack), pClient->read_buf, bytes_to_be_read, + timer_left_ms, &read_len); + if (ret_val == QCLOUD_RET_SUCCESS) { + total_bytes_read += read_len; + if ((rem_len - total_bytes_read) >= pClient->read_buf_size) { + bytes_to_be_read = pClient->read_buf_size; + } else { + bytes_to_be_read = rem_len - total_bytes_read; + } + } + } while (total_bytes_read < rem_len && ret_val == QCLOUD_RET_SUCCESS); + + Log_e("MQTT Recv buffer not enough: %d < %d", pClient->read_buf_size, rem_len); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + + len += mqtt_write_packet_rem_len(pClient->read_buf + 1, rem_len); + + // 3. read payload according to remaining length + if (rem_len > 0 && ((len + rem_len) > pClient->read_buf_size)) { + timer_left_ms = left_ms(timer); + if (timer_left_ms <= 0) { + timer_left_ms = 1; + } + timer_left_ms += QCLOUD_IOT_MQTT_MAX_REMAIN_WAIT_MS; + + pClient->network_stack.read(&(pClient->network_stack), pClient->read_buf, rem_len, timer_left_ms, &read_len); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } else { + if (rem_len > 0) { + timer_left_ms = left_ms(timer); + if (timer_left_ms <= 0) { + timer_left_ms = 1; + } + timer_left_ms += QCLOUD_IOT_MQTT_MAX_REMAIN_WAIT_MS; + rc = pClient->network_stack.read(&(pClient->network_stack), pClient->read_buf + len, rem_len, timer_left_ms, + &read_len); + if (rc != QCLOUD_RET_SUCCESS) { + IOT_FUNC_EXIT_RC(rc); + } + } + } + + *packet_type = (pClient->read_buf[0] & MQTT_HEADER_TYPE_MASK) >> MQTT_HEADER_TYPE_SHIFT; + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * @brief Check if two topic equals + * + * @param topic_filter + * @param topicName + * @return + */ +static uint8_t _is_topic_equals(char *topic_filter, char *topicName) +{ + return (uint8_t)(strlen(topic_filter) == strlen(topicName) && !strcmp(topic_filter, topicName)); +} + +/** + * @brief Check if topic match + * + * assume topic filter and name is in correct format + * # can only be at end + * + and # can only be next to separator + * + * @param topic_filter topic name filter, wildcard is supported + * @param topicName topic name, no wildcard + * @param topicNameLen length of topic name + * @return + */ +static uint8_t _is_topic_matched(char *topic_filter, char *topicName, uint16_t topicNameLen) +{ + char *curf; + char *curn; + char *curn_end; + + curf = topic_filter; + curn = topicName; + curn_end = curn + topicNameLen; + + while (*curf && (curn < curn_end)) { + if (*curf == '+' && *curn == '/') { + curf++; + continue; + } + + if (*curn == '/' && *curf != '/') { + break; + } + + if (*curf != '+' && *curf != '#' && *curf != *curn) { + break; + } + + if (*curf == '+') { + /* skip until we meet the next separator, or end of string */ + char *nextpos = curn + 1; + while (nextpos < curn_end && *nextpos != '/') nextpos = ++curn + 1; + } else if (*curf == '#') { + /* skip until end of string */ + curn = curn_end - 1; + } + + curf++; + curn++; + } + + if (*curf == '\0') { + return (uint8_t)(curn == curn_end); + } else { + return (uint8_t)((*curf == '#') || *(curf + 1) == '#' || (*curf == '+' && *(curn - 1) == '/')); + } +} + +/** + * @brief deliver the message to user callback + * + * @param pClient + * @param topicName + * @param message + * @return + */ +static int _deliver_message(Qcloud_IoT_Client *pClient, char *topicName, uint16_t topicNameLen, MQTTMessage *message) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(topicName, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(message, QCLOUD_ERR_INVAL); + + message->ptopic = topicName; + message->topic_len = (size_t)topicNameLen; + + uint32_t i; + HAL_MutexLock(pClient->lock_generic); + for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) { + if ((pClient->sub_handles[i].topic_filter != NULL) && + (_is_topic_equals(topicName, (char *)pClient->sub_handles[i].topic_filter) || + _is_topic_matched((char *)pClient->sub_handles[i].topic_filter, topicName, topicNameLen))) { + HAL_MutexUnlock(pClient->lock_generic); + if (pClient->sub_handles[i].message_handler != NULL) { + pClient->sub_handles[i].message_handler(pClient, message, pClient->sub_handles[i].handler_user_data); + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + } + HAL_MutexLock(pClient->lock_generic); + } + } + + /* Message handler not found for topic */ + /* May be we do not care change FAILURE use SUCCESS*/ + HAL_MutexUnlock(pClient->lock_generic); + + Log_d("no matching any topic, call default handle function"); + + if (NULL != pClient->event_handle.h_fp) { + MQTTEventMsg msg; + msg.event_type = MQTT_EVENT_PUBLISH_RECVEIVED; + msg.msg = message; + pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg); + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * @brief remove node signed with msgId from publish ACK wait list + * + * @return 0, success; NOT 0, fail; + */ +static int _mask_pubInfo_from(Qcloud_IoT_Client *c, uint16_t msgId) +{ + IOT_FUNC_ENTRY; + + if (!c) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + HAL_MutexLock(c->lock_list_pub); + if (c->list_pub_wait_ack->len) { + ListIterator * iter; + ListNode * node = NULL; + QcloudIotPubInfo *repubInfo = NULL; + + if (NULL == (iter = list_iterator_new(c->list_pub_wait_ack, LIST_TAIL))) { + HAL_MutexUnlock(c->lock_list_pub); + return QCLOUD_RET_SUCCESS; + } + + for (;;) { + node = list_iterator_next(iter); + + if (NULL == node) { + break; + } + + repubInfo = (QcloudIotPubInfo *)node->val; + if (NULL == repubInfo) { + Log_e("node's value is invalid!"); + continue; + } + + if (repubInfo->msg_id == msgId) { + repubInfo->node_state = MQTT_NODE_STATE_INVALID; /* set as invalid node */ + } + } + + list_iterator_destroy(iter); + } + HAL_MutexUnlock(c->lock_list_pub); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * @brief remove node signed with msgId from subscribe ACK wait list, and return + * the msg handler + * + * @return 0, success; NOT 0, fail; + */ +static int _mask_sub_info_from(Qcloud_IoT_Client *c, unsigned int msgId, SubTopicHandle *messageHandler) +{ + IOT_FUNC_ENTRY; + + if (NULL == c || NULL == messageHandler) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + HAL_MutexLock(c->lock_list_sub); + if (c->list_sub_wait_ack->len) { + ListIterator * iter; + ListNode * node = NULL; + QcloudIotSubInfo *sub_info = NULL; + + if (NULL == (iter = list_iterator_new(c->list_sub_wait_ack, LIST_TAIL))) { + HAL_MutexUnlock(c->lock_list_sub); + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + } + + for (;;) { + node = list_iterator_next(iter); + if (NULL == node) { + break; + } + + sub_info = (QcloudIotSubInfo *)node->val; + if (NULL == sub_info) { + Log_e("node's value is invalid!"); + continue; + } + + if (sub_info->msg_id == msgId) { + *messageHandler = sub_info->handler; /* return handle */ + sub_info->node_state = MQTT_NODE_STATE_INVALID; /* mark as invalid node */ + } + } + + list_iterator_destroy(iter); + } + HAL_MutexUnlock(c->lock_list_sub); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +static int _handle_puback_packet(Qcloud_IoT_Client *pClient, Timer *timer) +{ + IOT_FUNC_ENTRY; + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(timer, QCLOUD_ERR_INVAL); + + uint16_t packet_id; + uint8_t dup, type; + int rc; + + rc = deserialize_ack_packet(&type, &dup, &packet_id, pClient->read_buf, pClient->read_buf_size); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + (void)_mask_pubInfo_from(pClient, packet_id); + + /* notify this event to user callback */ + if (NULL != pClient->event_handle.h_fp) { + MQTTEventMsg msg; + msg.event_type = MQTT_EVENT_PUBLISH_SUCCESS; + msg.msg = (void *)(uintptr_t)packet_id; + pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg); + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +static int _handle_suback_packet(Qcloud_IoT_Client *pClient, Timer *timer, QoS qos) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(timer, QCLOUD_ERR_INVAL); + + uint32_t count = 0; + uint16_t packet_id = 0; + QoS grantedQoS[3] = {QOS0, QOS0, QOS0}; + int rc; + bool sub_nack = false; + + rc = deserialize_suback_packet(&packet_id, 1, &count, grantedQoS, pClient->read_buf, pClient->read_buf_size); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + int flag_dup = 0, i_free = -1; + // check return code in SUBACK packet: 0x00(QOS0, SUCCESS),0x01(QOS1, + // SUCCESS),0x02(QOS2, SUCCESS),0x80(Failure) + if (grantedQoS[0] == 0x80) { + MQTTEventMsg msg; + + msg.event_type = MQTT_EVENT_SUBCRIBE_NACK; + msg.msg = (void *)(uintptr_t)packet_id; + pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg); + + sub_nack = true; + } + + HAL_MutexLock(pClient->lock_generic); + + SubTopicHandle sub_handle; + memset(&sub_handle, 0, sizeof(SubTopicHandle)); + (void)_mask_sub_info_from(pClient, (unsigned int)packet_id, &sub_handle); + + if (/*(NULL == sub_handle.message_handler) || */ (NULL == sub_handle.topic_filter)) { + Log_e("sub_handle is illegal, topic is null"); + HAL_MutexUnlock(pClient->lock_generic); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_SUB); + } + + if (sub_nack) { + HAL_MutexUnlock(pClient->lock_generic); + Log_e("MQTT SUBSCRIBE failed, packet_id: %u topic: %s", packet_id, sub_handle.topic_filter); + /* notify this event to topic subscriber */ + if (NULL != sub_handle.sub_event_handler) + sub_handle.sub_event_handler(pClient, MQTT_EVENT_SUBCRIBE_NACK, sub_handle.handler_user_data); + + HAL_Free((void *)sub_handle.topic_filter); + sub_handle.topic_filter = NULL; + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_SUB); + } + + int i; + for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) { + if ((NULL != pClient->sub_handles[i].topic_filter)) { + if (0 == _check_handle_is_identical(&pClient->sub_handles[i], &sub_handle)) { + flag_dup = 1; + Log_w("Identical topic found: %s", sub_handle.topic_filter); + if (pClient->sub_handles[i].handler_user_data != sub_handle.handler_user_data) { + Log_w("Update handler_user_data %p -> %p!", pClient->sub_handles[i].handler_user_data, + sub_handle.handler_user_data); + pClient->sub_handles[i].handler_user_data = sub_handle.handler_user_data; + } + HAL_Free((void *)sub_handle.topic_filter); + sub_handle.topic_filter = NULL; + break; + } + } else { + if (-1 == i_free) { + i_free = i; /* record available element */ + } + } + } + + if (0 == flag_dup) { + if (-1 == i_free) { + Log_e("NO more @sub_handles space!"); + HAL_MutexUnlock(pClient->lock_generic); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } else { + pClient->sub_handles[i_free].topic_filter = sub_handle.topic_filter; + pClient->sub_handles[i_free].message_handler = sub_handle.message_handler; + pClient->sub_handles[i_free].sub_event_handler = sub_handle.sub_event_handler; + pClient->sub_handles[i_free].qos = sub_handle.qos; + pClient->sub_handles[i_free].handler_user_data = sub_handle.handler_user_data; + } + } + + HAL_MutexUnlock(pClient->lock_generic); + + /* notify this event to user callback */ + if (NULL != pClient->event_handle.h_fp) { + MQTTEventMsg msg; + msg.event_type = MQTT_EVENT_SUBCRIBE_SUCCESS; + msg.msg = (void *)(uintptr_t)packet_id; + if (pClient->event_handle.h_fp != NULL) + pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg); + } + + /* notify this event to topic subscriber */ + if (NULL != sub_handle.sub_event_handler) + sub_handle.sub_event_handler(pClient, MQTT_EVENT_SUBCRIBE_SUCCESS, sub_handle.handler_user_data); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +static int _handle_unsuback_packet(Qcloud_IoT_Client *pClient, Timer *timer) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(timer, QCLOUD_ERR_INVAL); + + uint16_t packet_id = 0; + + int rc = deserialize_unsuback_packet(&packet_id, pClient->read_buf, pClient->read_buf_size); + if (rc != QCLOUD_RET_SUCCESS) { + IOT_FUNC_EXIT_RC(rc); + } + + SubTopicHandle messageHandler; + (void)_mask_sub_info_from(pClient, packet_id, &messageHandler); + + /* Remove from message handler array */ + HAL_MutexLock(pClient->lock_generic); + + /* Free the topic filter malloced in qcloud_iot_mqtt_unsubscribe */ + if (messageHandler.topic_filter) { + HAL_Free((void *)messageHandler.topic_filter); + messageHandler.topic_filter = NULL; + } + + if (NULL != pClient->event_handle.h_fp) { + MQTTEventMsg msg; + msg.event_type = MQTT_EVENT_UNSUBCRIBE_SUCCESS; + msg.msg = (void *)(uintptr_t)packet_id; + + pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg); + } + + HAL_MutexUnlock(pClient->lock_generic); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +#ifdef MQTT_RMDUP_MSG_ENABLED + +static int _get_packet_id_in_repeat_buf(Qcloud_IoT_Client *pClient, uint16_t packet_id) +{ + int i; + for (i = 0; i < MQTT_MAX_REPEAT_BUF_LEN; ++i) { + if (packet_id == pClient->repeat_packet_id_buf[i]) { + return packet_id; + } + } + return -1; +} + +static void _add_packet_id_to_repeat_buf(Qcloud_IoT_Client *pClient, uint16_t packet_id) +{ + if (_get_packet_id_in_repeat_buf(pClient, packet_id) > 0) + return; + + pClient->repeat_packet_id_buf[pClient->current_packet_id_cnt++] = packet_id; + + if (pClient->current_packet_id_cnt >= MQTT_MAX_REPEAT_BUF_LEN) + pClient->current_packet_id_cnt %= MQTT_MAX_REPEAT_BUF_LEN; +} + +void reset_repeat_packet_id_buffer(Qcloud_IoT_Client *pClient) +{ + int i; + for (i = 0; i < MQTT_MAX_REPEAT_BUF_LEN; ++i) { + pClient->repeat_packet_id_buf[i] = 0; + } + pClient->current_packet_id_cnt = 0; +} + +#endif + +static int _handle_publish_packet(Qcloud_IoT_Client *pClient, Timer *timer) +{ + IOT_FUNC_ENTRY; + char * topic_name; + uint16_t topic_len; + MQTTMessage msg; + int rc; + uint32_t len = 0; + + rc = deserialize_publish_packet(&msg.dup, &msg.qos, &msg.retained, &msg.id, &topic_name, &topic_len, + (unsigned char **)&msg.payload, &msg.payload_len, pClient->read_buf, + pClient->read_buf_size); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + // topicName from packet is NOT null terminated + char fix_topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0}; + + if (topic_len > MAX_SIZE_OF_CLOUD_TOPIC) { + topic_len = MAX_SIZE_OF_CLOUD_TOPIC - 1; + Log_e("topic len exceed buffer len"); + } + memcpy(fix_topic, topic_name, topic_len); + + if (QOS0 == msg.qos) { + rc = _deliver_message(pClient, fix_topic, topic_len, &msg); + if (QCLOUD_RET_SUCCESS != rc) + IOT_FUNC_EXIT_RC(rc); + + /* No further processing required for QOS0 */ + IOT_FUNC_EXIT_RC(rc); + + } else { +#ifdef MQTT_RMDUP_MSG_ENABLED + // check if packet_id has been received before + int repeat_id = _get_packet_id_in_repeat_buf(pClient, msg.id); + + // deliver to msg callback + if (repeat_id < 0) { +#endif + rc = _deliver_message(pClient, fix_topic, topic_len, &msg); + if (QCLOUD_RET_SUCCESS != rc) + IOT_FUNC_EXIT_RC(rc); +#ifdef MQTT_RMDUP_MSG_ENABLED + } + _add_packet_id_to_repeat_buf(pClient, msg.id); +#endif + } + + HAL_MutexLock(pClient->lock_write_buf); + if (QOS1 == msg.qos) { + rc = serialize_pub_ack_packet(pClient->write_buf, pClient->write_buf_size, PUBACK, 0, msg.id, &len); + } else { /* Message is not QOS0 or QOS1 means only option left is QOS2 */ + rc = serialize_pub_ack_packet(pClient->write_buf, pClient->write_buf_size, PUBREC, 0, msg.id, &len); + } + + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + + if (expired(timer)) { + /* send timeout */ + //Log_w("puback timer expired! left:%d, increase a bit", left_ms(timer)); + countdown_ms(timer, 100); + } + + rc = send_mqtt_packet(pClient, len, timer); + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +static int _handle_pubrec_packet(Qcloud_IoT_Client *pClient, Timer *timer) +{ + IOT_FUNC_ENTRY; + uint16_t packet_id; + unsigned char dup, type; + int rc; + uint32_t len; + + rc = deserialize_ack_packet(&type, &dup, &packet_id, pClient->read_buf, pClient->read_buf_size); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + HAL_MutexLock(pClient->lock_write_buf); + rc = serialize_pub_ack_packet(pClient->write_buf, pClient->write_buf_size, PUBREL, 0, packet_id, &len); + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + + if (expired(timer)) { + /* send timeout */ + //Log_w("pubrec timer expired! left:%d, increase a bit", left_ms(timer)); + countdown_ms(timer, 100); + } + + /* send the PUBREL packet */ + rc = send_mqtt_packet(pClient, len, timer); + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexUnlock(pClient->lock_write_buf); + /* there was a problem */ + IOT_FUNC_EXIT_RC(rc); + } + + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +static void _handle_pingresp_packet(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + + HAL_MutexLock(pClient->lock_generic); + pClient->is_ping_outstanding = 0; + countdown(&pClient->ping_timer, pClient->options.keep_alive_interval); + HAL_MutexUnlock(pClient->lock_generic); + + IOT_FUNC_EXIT; +} + +int cycle_for_read(Qcloud_IoT_Client *pClient, Timer *timer, uint8_t *packet_type, QoS qos) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(timer, QCLOUD_ERR_INVAL); + + int rc; + /* read the socket, see what work is due */ + rc = _read_mqtt_packet(pClient, timer, packet_type); + if (QCLOUD_ERR_MQTT_NOTHING_TO_READ == rc) { + /* Nothing to read, not a cycle failure */ + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + } + + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + switch (*packet_type) { + case CONNACK: + break; + case PUBACK: + rc = _handle_puback_packet(pClient, timer); + break; + case SUBACK: + rc = _handle_suback_packet(pClient, timer, qos); + break; + case UNSUBACK: + rc = _handle_unsuback_packet(pClient, timer); + break; + case PUBLISH: { + rc = _handle_publish_packet(pClient, timer); + break; + } + case PUBREC: { + rc = _handle_pubrec_packet(pClient, timer); + break; + } + case PUBREL: { + Log_e("Packet type PUBREL is currently NOT handled!"); + break; + } + case PUBCOMP: + break; + case PINGRESP: + break; + default: { + /* Either unknown packet type or Failure occurred + * Should not happen */ + + IOT_FUNC_EXIT_RC(QCLOUD_ERR_RX_MESSAGE_INVAL); + break; + } + } + + switch (*packet_type) { + /* Recv below msgs are all considered as PING OK */ + case PUBACK: + case SUBACK: + case UNSUBACK: + case PINGRESP: { + _handle_pingresp_packet(pClient); + break; + } + /* Recv downlink pub means link is OK but we still need to send PING request + */ + case PUBLISH: { + HAL_MutexLock(pClient->lock_generic); + pClient->is_ping_outstanding = 0; + HAL_MutexUnlock(pClient->lock_generic); + break; + } + } + + IOT_FUNC_EXIT_RC(rc); +} + +int wait_for_read(Qcloud_IoT_Client *pClient, uint8_t packet_type, Timer *timer, QoS qos) +{ + IOT_FUNC_ENTRY; + int rc; + uint8_t read_packet_type = 0; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(timer, QCLOUD_ERR_INVAL); + + do { + if (expired(timer)) { + rc = QCLOUD_ERR_MQTT_REQUEST_TIMEOUT; + break; + } + rc = cycle_for_read(pClient, timer, &read_packet_type, qos); + } while (QCLOUD_RET_SUCCESS == rc && read_packet_type != packet_type); + + IOT_FUNC_EXIT_RC(rc); +} + +void set_client_conn_state(Qcloud_IoT_Client *pClient, uint8_t connected) +{ + HAL_MutexLock(pClient->lock_generic); + pClient->is_connected = connected; + HAL_MutexUnlock(pClient->lock_generic); +} + +uint8_t get_client_conn_state(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + uint8_t is_connected = 0; + HAL_MutexLock(pClient->lock_generic); + is_connected = pClient->is_connected; + HAL_MutexUnlock(pClient->lock_generic); + IOT_FUNC_EXIT_RC(is_connected); +} + +/* + * @brief push node to subscribe(unsubscribe) ACK wait list + * + * return: 0, success; NOT 0, fail; + */ +int push_sub_info_to(Qcloud_IoT_Client *c, int len, unsigned short msgId, MessageTypes type, SubTopicHandle *handler, + ListNode **node) +{ + IOT_FUNC_ENTRY; + if (!c || !handler || !node) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL); + } + + HAL_MutexLock(c->lock_list_sub); + + if (c->list_sub_wait_ack->len >= MAX_MESSAGE_HANDLERS) { + HAL_MutexUnlock(c->lock_list_sub); + Log_e("number of sub_info more than max! size = %d", c->list_sub_wait_ack->len); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_MAX_SUBSCRIPTIONS); + } + + QcloudIotSubInfo *sub_info = (QcloudIotSubInfo *)HAL_Malloc(sizeof(QcloudIotSubInfo) + len); + if (NULL == sub_info) { + HAL_MutexUnlock(c->lock_list_sub); + Log_e("malloc failed!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + sub_info->node_state = MQTT_NODE_STATE_NORMANL; + sub_info->msg_id = msgId; + sub_info->len = len; + + InitTimer(&sub_info->sub_start_time); + countdown_ms(&sub_info->sub_start_time, c->command_timeout_ms); + + sub_info->type = type; + sub_info->handler = *handler; + sub_info->buf = (unsigned char *)sub_info + sizeof(QcloudIotSubInfo); + + memcpy(sub_info->buf, c->write_buf, len); + + *node = list_node_new(sub_info); + if (NULL == *node) { + HAL_MutexUnlock(c->lock_list_sub); + HAL_Free(sub_info); + Log_e("list_node_new failed!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + list_rpush(c->list_sub_wait_ack, *node); + + HAL_MutexUnlock(c->lock_list_sub); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_connect.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_connect.c new file mode 100644 index 00000000..7df20551 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_connect.c @@ -0,0 +1,481 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or + *initial documentation + *******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "mqtt_client.h" +#include "qcloud_iot_common.h" +#include "qutils_hmac.h" + +#define MQTT_CONNECT_FLAG_USERNAME 0x80 +#define MQTT_CONNECT_FLAG_PASSWORD 0x40 +#define MQTT_CONNECT_FLAG_WILL_RETAIN 0x20 +#define MQTT_CONNECT_FLAG_WILL_QOS2 0x18 +#define MQTT_CONNECT_FLAG_WILL_QOS1 0x08 +#define MQTT_CONNECT_FLAG_WILL_QOS0 0x00 +#define MQTT_CONNECT_FLAG_WILL_FLAG 0x04 +#define MQTT_CONNECT_FLAG_CLEAN_SES 0x02 + +#define MQTT_CONNACK_FLAG_SES_PRE 0x01 + +/** + * Connect return code + */ +typedef enum { + CONNACK_CONNECTION_ACCEPTED = 0, // connection accepted + CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = 1, // connection refused: unaccpeted protocol verison + CONNACK_IDENTIFIER_REJECTED_ERROR = 2, // connection refused: identifier rejected + CONNACK_SERVER_UNAVAILABLE_ERROR = 3, // connection refused: server unavailable + CONNACK_BAD_USERDATA_ERROR = 4, // connection refused: bad user name or password + CONNACK_NOT_AUTHORIZED_ERROR = 5 // connection refused: not authorized +} MQTTConnackReturnCodes; + +/** + * Determines the length of the MQTT connect packet that would be produced using + * the supplied connect options. + * @param options the options to be used to build the connect packet + * @param the length of buffer needed to contain the serialized version of the + * packet + * @return int indicating function execution status + */ +static uint32_t _get_packet_connect_rem_len(MQTTConnectParams *options) +{ + size_t len = 0; + /* variable depending on MQTT or MQIsdp */ + if (3 == options->mqtt_version) { + len = 12; + } else if (4 == options->mqtt_version) { + len = 10; + } + + len += strlen(options->client_id) + 2; + + if (options->username) { + len += strlen(options->username) + 2; + } + + if (options->password) { + len += strlen(options->password) + 2; + } + + return (uint32_t)len; +} + +static void _copy_connect_params(MQTTConnectParams *destination, MQTTConnectParams *source) +{ + POINTER_SANITY_CHECK_RTN(destination); + POINTER_SANITY_CHECK_RTN(source); + + /* In case of reconnecting, source == destination */ + if (source == destination) { + return; + } + + destination->mqtt_version = source->mqtt_version; + destination->client_id = source->client_id; + destination->username = source->username; + destination->keep_alive_interval = source->keep_alive_interval; + destination->clean_session = source->clean_session; + destination->auto_connect_enable = source->auto_connect_enable; +#ifdef AUTH_WITH_NOTLS + destination->device_secret = source->device_secret; + destination->device_secret_len = source->device_secret_len; +#endif +} + +/** + * Serializes the connect options into the buffer. + * @param buf the buffer into which the packet will be serialized + * @param len the length in bytes of the supplied buffer + * @param options the options to be used to build the connect packet + * @param serialized length + * @return int indicating function execution status + */ +static int _serialize_connect_packet(unsigned char *buf, size_t buf_len, MQTTConnectParams *options, + uint32_t *serialized_len) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(options, QCLOUD_ERR_INVAL); + STRING_PTR_SANITY_CHECK(options->client_id, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL); + + unsigned char *ptr = buf; + unsigned char header = 0; + unsigned char flags = 0; + uint32_t rem_len = 0; + int rc; + + long cur_timesec = HAL_Timer_current_sec() + MAX_ACCESS_EXPIRE_TIMEOUT / 1000; + if (cur_timesec <= 0 || MAX_ACCESS_EXPIRE_TIMEOUT <= 0) { + cur_timesec = LONG_MAX; + } + long cur_timesec_bak = cur_timesec; + int cur_timesec_len = 0; + while (cur_timesec_bak != 0) { + cur_timesec_bak /= 10; + ++cur_timesec_len; + } + + int username_len = + strlen(options->client_id) + strlen(QCLOUD_IOT_DEVICE_SDK_APPID) + MAX_CONN_ID_LEN + cur_timesec_len + 4; + options->username = (char *)HAL_Malloc(username_len); + if (options->username == NULL) { + Log_e("malloc username failed!"); + rc = QCLOUD_ERR_MALLOC; + goto err_exit; + } + + get_next_conn_id(options->conn_id); + HAL_Snprintf(options->username, username_len, "%s;%s;%s;%ld", options->client_id, QCLOUD_IOT_DEVICE_SDK_APPID, + options->conn_id, cur_timesec); + +#if defined(AUTH_WITH_NOTLS) && defined(AUTH_MODE_KEY) + if (options->device_secret != NULL && options->username != NULL) { + char sign[41] = {0}; + utils_hmac_sha1(options->username, strlen(options->username), sign, options->device_secret, + options->device_secret_len); + options->password = (char *)HAL_Malloc(51); + if (options->password == NULL) { + Log_e("malloc password failed!"); + rc = QCLOUD_ERR_MALLOC; + goto err_exit; + } + HAL_Snprintf(options->password, 51, "%s;hmacsha1", sign); + } +#endif + + rem_len = _get_packet_connect_rem_len(options); + if (get_mqtt_packet_len(rem_len) > buf_len) { + Log_e("get_mqtt_packet_len failed!"); + rc = QCLOUD_ERR_BUF_TOO_SHORT; + goto err_exit; + } + + rc = mqtt_init_packet_header(&header, CONNECT, QOS0, 0, 0); + if (QCLOUD_RET_SUCCESS != rc) { + Log_e("mqtt_init_packet_header failed!"); + goto err_exit; + } + + // 1st byte in fixed header + mqtt_write_char(&ptr, header); + + // remaining length + ptr += mqtt_write_packet_rem_len(ptr, rem_len); + + // MQTT protocol name and version in variable header + if (4 == options->mqtt_version) { + mqtt_write_utf8_string(&ptr, "MQTT"); + mqtt_write_char(&ptr, (unsigned char)4); + } else { + mqtt_write_utf8_string(&ptr, "MQIsdp"); + mqtt_write_char(&ptr, (unsigned char)3); + } + + // flags in variable header + flags |= (options->clean_session) ? MQTT_CONNECT_FLAG_CLEAN_SES : 0; + flags |= (options->username != NULL) ? MQTT_CONNECT_FLAG_USERNAME : 0; + +#if defined(AUTH_WITH_NOTLS) && defined(AUTH_MODE_KEY) + flags |= MQTT_CONNECT_FLAG_PASSWORD; +#endif + + mqtt_write_char(&ptr, flags); + + // keep alive interval (unit:ms) in variable header + mqtt_write_uint_16(&ptr, options->keep_alive_interval); + + // client id + mqtt_write_utf8_string(&ptr, options->client_id); + + if ((flags & MQTT_CONNECT_FLAG_USERNAME) && options->username != NULL) { + mqtt_write_utf8_string(&ptr, options->username); + HAL_Free(options->username); + options->username = NULL; + } + + if ((flags & MQTT_CONNECT_FLAG_PASSWORD) && options->password != NULL) { + mqtt_write_utf8_string(&ptr, options->password); + HAL_Free(options->password); + options->password = NULL; + } + + *serialized_len = (uint32_t)(ptr - buf); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + +err_exit: + HAL_Free(options->username); + options->username = NULL; + + HAL_Free(options->password); + options->password = NULL; + + IOT_FUNC_EXIT_RC(rc); +} + +/** + * Deserializes the supplied (wire) buffer into connack data - return code + * @param sessionPresent the session present flag returned (only for MQTT 3.1.1) + * @param connack_rc returned integer value of the connack return code + * @param buf the raw buffer data, of the correct length determined by the + * remaining length field + * @param buflen the length in bytes of the data in the supplied buffer + * @return int indicating function execution status + */ +static int _deserialize_connack_packet(uint8_t *sessionPresent, int *connack_rc, unsigned char *buf, size_t buflen) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(sessionPresent, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(connack_rc, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + + unsigned char header, type = 0; + unsigned char *curdata = buf; + unsigned char *enddata = NULL; + int rc; + uint32_t decodedLen = 0, readBytesLen = 0; + unsigned char flags = 0; + unsigned char connack_rc_char; + + // CONNACK: 2 bytes in fixed header and 2 bytes in variable header, no payload + if (4 > buflen) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + + header = mqtt_read_char(&curdata); + type = (header & MQTT_HEADER_TYPE_MASK) >> MQTT_HEADER_TYPE_SHIFT; + if (CONNACK != type) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + rc = mqtt_read_packet_rem_len_form_buf(curdata, &decodedLen, &readBytesLen); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + curdata += (readBytesLen); + enddata = curdata + decodedLen; + if (enddata - curdata != 2) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + // variable header - connack flag, refer to MQTT spec 3.2.2.1 + flags = mqtt_read_char(&curdata); + *sessionPresent = flags & MQTT_CONNACK_FLAG_SES_PRE; + + // variable header - return code, refer to MQTT spec 3.2.2.3 + connack_rc_char = mqtt_read_char(&curdata); + switch (connack_rc_char) { + case CONNACK_CONNECTION_ACCEPTED: + *connack_rc = QCLOUD_RET_MQTT_CONNACK_CONNECTION_ACCEPTED; + break; + case CONANCK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR: + *connack_rc = QCLOUD_ERR_MQTT_CONNACK_UNACCEPTABLE_PROTOCOL_VERSION; + break; + case CONNACK_IDENTIFIER_REJECTED_ERROR: + *connack_rc = QCLOUD_ERR_MQTT_CONNACK_IDENTIFIER_REJECTED; + break; + case CONNACK_SERVER_UNAVAILABLE_ERROR: + *connack_rc = QCLOUD_ERR_MQTT_CONNACK_SERVER_UNAVAILABLE; + break; + case CONNACK_BAD_USERDATA_ERROR: + *connack_rc = QCLOUD_ERR_MQTT_CONNACK_BAD_USERDATA; + break; + case CONNACK_NOT_AUTHORIZED_ERROR: + *connack_rc = QCLOUD_ERR_MQTT_CONNACK_NOT_AUTHORIZED; + break; + default: + *connack_rc = QCLOUD_ERR_MQTT_CONNACK_UNKNOWN; + break; + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * @brief Setup connection with MQTT server + * + * @param pClient + * @param options + * @return + */ +static int _mqtt_connect(Qcloud_IoT_Client *pClient, MQTTConnectParams *options) +{ + IOT_FUNC_ENTRY; + + Timer connect_timer; + int connack_rc = QCLOUD_ERR_FAILURE, rc = QCLOUD_ERR_FAILURE; + uint8_t sessionPresent = 0; + uint32_t len = 0; + + InitTimer(&connect_timer); + countdown_ms(&connect_timer, pClient->command_timeout_ms); + + if (NULL != options) { + _copy_connect_params(&(pClient->options), options); + } + + // TCP or TLS network connect + rc = pClient->network_stack.connect(&(pClient->network_stack)); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + HAL_MutexLock(pClient->lock_write_buf); + // serialize CONNECT packet + rc = _serialize_connect_packet(pClient->write_buf, pClient->write_buf_size, &(pClient->options), &len); + if (QCLOUD_RET_SUCCESS != rc || 0 == len) { + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + + // send CONNECT packet + rc = send_mqtt_packet(pClient, len, &connect_timer); + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + HAL_MutexUnlock(pClient->lock_write_buf); + + // wait for CONNACK + rc = wait_for_read(pClient, CONNACK, &connect_timer, QOS0); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + // deserialize CONNACK and check reture code + rc = _deserialize_connack_packet(&sessionPresent, &connack_rc, pClient->read_buf, pClient->read_buf_size); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + if (QCLOUD_RET_MQTT_CONNACK_CONNECTION_ACCEPTED != connack_rc) { + IOT_FUNC_EXIT_RC(connack_rc); + } + + set_client_conn_state(pClient, CONNECTED); + HAL_MutexLock(pClient->lock_generic); + pClient->was_manually_disconnected = 0; + pClient->is_ping_outstanding = 0; + countdown(&pClient->ping_timer, pClient->options.keep_alive_interval); + HAL_MutexUnlock(pClient->lock_generic); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int qcloud_iot_mqtt_connect(Qcloud_IoT_Client *pClient, MQTTConnectParams *pParams) +{ + IOT_FUNC_ENTRY; + int rc; + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL); + + // check connection state first + if (get_client_conn_state(pClient)) { + IOT_FUNC_EXIT_RC(QCLOUD_RET_MQTT_ALREADY_CONNECTED); + } + + rc = _mqtt_connect(pClient, pParams); + + // disconnect network if connect fail + if (rc != QCLOUD_RET_SUCCESS) { + pClient->network_stack.disconnect(&(pClient->network_stack)); + } + + IOT_FUNC_EXIT_RC(rc); +} + +int qcloud_iot_mqtt_attempt_reconnect(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + + int rc; + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Log_i("attempt to reconnect..."); + + if (get_client_conn_state(pClient)) { + IOT_FUNC_EXIT_RC(QCLOUD_RET_MQTT_ALREADY_CONNECTED); + } + + rc = qcloud_iot_mqtt_connect(pClient, &pClient->options); + + if (!get_client_conn_state(pClient)) { + IOT_FUNC_EXIT_RC(rc); + } + + rc = qcloud_iot_mqtt_resubscribe(pClient); + if (rc != QCLOUD_RET_SUCCESS) { + IOT_FUNC_EXIT_RC(rc); + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_MQTT_RECONNECTED); +} + +int qcloud_iot_mqtt_disconnect(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + + int rc; + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + Timer timer; + uint32_t serialized_len = 0; + + if (get_client_conn_state(pClient) == 0) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + HAL_MutexLock(pClient->lock_write_buf); + rc = serialize_packet_with_zero_payload(pClient->write_buf, pClient->write_buf_size, DISCONNECT, &serialized_len); + if (rc != QCLOUD_RET_SUCCESS) { + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + + InitTimer(&timer); + countdown_ms(&timer, pClient->command_timeout_ms); + + if (serialized_len > 0) { + rc = send_mqtt_packet(pClient, serialized_len, &timer); + if (rc != QCLOUD_RET_SUCCESS) { + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + } + HAL_MutexUnlock(pClient->lock_write_buf); + + pClient->network_stack.disconnect(&(pClient->network_stack)); + set_client_conn_state(pClient, NOTCONNECTED); + pClient->was_manually_disconnected = 1; + + Log_i("mqtt disconnect!"); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_net.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_net.c new file mode 100644 index 00000000..313bbc6d --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_net.c @@ -0,0 +1,66 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mqtt_client_net.h" + +// TODO: how to implement +/** + * @brief Check if TLS connection is valid + * + * @param pNetwork + * @return + */ +int qcloud_iot_mqtt_tls_is_connected(Network *pNetwork) +{ + return 1; +} + +/** + * @brief Init network stack + * + * @param pNetwork + * @param pConnectParams + * @return + */ +int qcloud_iot_mqtt_network_init(Network *pNetwork) +{ + int rc; + + /* first choice: TLS */ + pNetwork->type = NETWORK_TLS; + +#ifdef AUTH_WITH_NOTLS + pNetwork->type = NETWORK_TCP; +#endif + + rc = network_init(pNetwork); + pNetwork->is_connected = qcloud_iot_mqtt_tls_is_connected; + + return rc; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_publish.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_publish.c new file mode 100644 index 00000000..5bdc21fe --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_publish.c @@ -0,0 +1,390 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + * Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144 + *******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "mqtt_client.h" +#include "qutils_list.h" + +/** + * @param mqttstring the MQTTString structure into which the data is to be read + * @param pptr pointer to the output buffer - incremented by the number of bytes + * used & returned + * @param enddata pointer to the end of the data: do not read beyond + * @return SUCCESS if successful, FAILURE if not + */ +static int _read_string_with_len(char **string, uint16_t *stringLen, unsigned char **pptr, unsigned char *enddata) +{ + int rc = QCLOUD_ERR_FAILURE; + + /* the first two bytes are the length of the string */ + /* enough length to read the integer? */ + if (enddata - (*pptr) > 1) { + *stringLen = mqtt_read_uint16_t(pptr); /* increments pptr to point past length */ + + if (*stringLen > QCLOUD_IOT_MQTT_RX_BUF_LEN) { + Log_e("stringLen exceed QCLOUD_IOT_MQTT_RX_BUF_LEN"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + if (&(*pptr)[*stringLen] <= enddata) { + *string = (char *)*pptr; + *pptr += *stringLen; + rc = QCLOUD_RET_SUCCESS; + } + } + + return rc; +} + +/** + * Determines the length of the MQTT publish packet that would be produced using + * the supplied parameters + * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0) + * @param topicName the topic name to be used in the publish + * @param payload_len the length of the payload to be sent + * @return the length of buffer needed to contain the serialized version of the + * packet + */ +static uint32_t _get_publish_packet_len(uint8_t qos, char *topicName, size_t payload_len) +{ + size_t len = 0; + + len += 2 + strlen(topicName) + payload_len; + if (qos > 0) { + len += 2; /* packetid */ + } + return (uint32_t)len; +} + +static int _mask_push_pubInfo_to(Qcloud_IoT_Client *c, int len, unsigned short msgId, ListNode **node) +{ + IOT_FUNC_ENTRY; + + if (!c || !node) { + Log_e("invalid parameters!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_PUSH_TO_LIST_FAILED); + } + + if ((len < 0) || (len > c->write_buf_size)) { + Log_e("the param of len is error!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + HAL_MutexLock(c->lock_list_pub); + + if (c->list_pub_wait_ack->len >= MAX_REPUB_NUM) { + HAL_MutexUnlock(c->lock_list_pub); + Log_e("more than %u elements in republish list. List overflow!", c->list_pub_wait_ack->len); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + QcloudIotPubInfo *repubInfo = (QcloudIotPubInfo *)HAL_Malloc(sizeof(QcloudIotPubInfo) + len); + if (NULL == repubInfo) { + HAL_MutexUnlock(c->lock_list_pub); + Log_e("memory malloc failed!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + repubInfo->node_state = MQTT_NODE_STATE_NORMANL; + repubInfo->msg_id = msgId; + repubInfo->len = len; + InitTimer(&repubInfo->pub_start_time); + countdown_ms(&repubInfo->pub_start_time, c->command_timeout_ms); + + repubInfo->buf = (unsigned char *)repubInfo + sizeof(QcloudIotPubInfo); + + memcpy(repubInfo->buf, c->write_buf, len); + + *node = list_node_new(repubInfo); + if (NULL == *node) { + HAL_MutexUnlock(c->lock_list_pub); + HAL_Free(repubInfo); + Log_e("list_node_new failed!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + list_rpush(c->list_pub_wait_ack, *node); + + HAL_MutexUnlock(c->lock_list_pub); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * Deserializes the supplied (wire) buffer into publish data + * @param dup returned integer - the MQTT dup flag + * @param qos returned integer - the MQTT QoS value + * @param retained returned integer - the MQTT retained flag + * @param packet_id returned integer - the MQTT packet identifier + * @param topicName returned MQTTString - the MQTT topic in the publish + * @param payload returned byte buffer - the MQTT publish payload + * @param payload_len returned integer - the length of the MQTT payload + * @param buf the raw buffer data, of the correct length determined by the + * remaining length field + * @param buf_len the length in bytes of the data in the supplied buffer + * @return error code. 1 is success + */ +int deserialize_publish_packet(uint8_t *dup, QoS *qos, uint8_t *retained, uint16_t *packet_id, char **topicName, + uint16_t *topicNameLen, unsigned char **payload, size_t *payload_len, unsigned char *buf, + size_t buf_len) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(dup, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(qos, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(retained, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(packet_id, QCLOUD_ERR_INVAL); + + unsigned char header, type = 0; + unsigned char *curdata = buf; + unsigned char *enddata = NULL; + int rc; + uint32_t decodedLen = 0; + uint32_t readBytesLen = 0; + + /* Publish header size is at least four bytes. + * Fixed header is two bytes. + * Variable header size depends on QoS And Topic Name. + * QoS level 0 doesn't have a message identifier (0 - 2 bytes) + * Topic Name length fields decide size of topic name field (at least 2 bytes) + * MQTT v3.1.1 Specification 3.3.1 */ + if (4 > buf_len) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + + header = mqtt_read_char(&curdata); + type = (header & MQTT_HEADER_TYPE_MASK) >> MQTT_HEADER_TYPE_SHIFT; + *dup = (header & MQTT_HEADER_DUP_MASK) >> MQTT_HEADER_DUP_SHIFT; + *qos = (QoS)((header & MQTT_HEADER_QOS_MASK) >> MQTT_HEADER_QOS_SHIFT); + *retained = header & MQTT_HEADER_RETAIN_MASK; + + if (PUBLISH != type) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + /* read remaining length */ + rc = mqtt_read_packet_rem_len_form_buf(curdata, &decodedLen, &readBytesLen); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + curdata += (readBytesLen); + enddata = curdata + decodedLen; + + /* do we have enough data to read the protocol version byte? */ + if (QCLOUD_RET_SUCCESS != _read_string_with_len(topicName, topicNameLen, &curdata, enddata) || + (0 > (enddata - curdata))) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + if (QOS0 != *qos) { + *packet_id = mqtt_read_uint16_t(&curdata); + } + + *payload_len = (size_t)(enddata - curdata); + *payload = curdata; + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * Serializes the ack packet into the supplied buffer. + * @param buf the buffer into which the packet will be serialized + * @param buf_len the length in bytes of the supplied buffer + * @param packet_type the MQTT packet type: 1.PUBACK; 2.PUBREL; 3.PUBCOMP + * @param dup the MQTT dup flag + * @param packet_id the MQTT packet identifier + * @return serialized length, or error if 0 + */ +int serialize_pub_ack_packet(unsigned char *buf, size_t buf_len, MessageTypes packet_type, uint8_t dup, + uint16_t packet_id, uint32_t *serialized_len) +{ + IOT_FUNC_ENTRY; + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL); + + unsigned char header = 0; + unsigned char *ptr = buf; + QoS requestQoS = (PUBREL == packet_type) ? QOS1 : QOS0; // refer to MQTT spec 3.6.1 + int rc = mqtt_init_packet_header(&header, packet_type, requestQoS, dup, 0); + + /* Minimum byte length required by ACK headers is + * 2 for fixed and 2 for variable part */ + if (4 > buf_len) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + mqtt_write_char(&ptr, header); /* write header */ + + ptr += mqtt_write_packet_rem_len(ptr, 2); /* write remaining length */ + mqtt_write_uint_16(&ptr, packet_id); + *serialized_len = (uint32_t)(ptr - buf); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * Serializes the supplied publish data into the supplied buffer, ready for + * sending + * @param buf the buffer into which the packet will be serialized + * @param buf_len the length in bytes of the supplied buffer + * @param dup integer - the MQTT dup flag + * @param qos integer - the MQTT QoS value + * @param retained integer - the MQTT retained flag + * @param packet_id integer - the MQTT packet identifier + * @param topicName MQTTString - the MQTT topic in the publish + * @param payload byte buffer - the MQTT publish payload + * @param payload_len integer - the length of the MQTT payload + * @return the length of the serialized data. <= 0 indicates error + */ +static int _serialize_publish_packet(unsigned char *buf, size_t buf_len, uint8_t dup, QoS qos, uint8_t retained, + uint16_t packet_id, char *topicName, unsigned char *payload, size_t payload_len, + uint32_t *serialized_len) +{ + IOT_FUNC_ENTRY; + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(payload, QCLOUD_ERR_INVAL); + + unsigned char *ptr = buf; + unsigned char header = 0; + uint32_t rem_len = 0; + int rc; + + rem_len = _get_publish_packet_len(qos, topicName, payload_len); + if (get_mqtt_packet_len(rem_len) > buf_len) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + + rc = mqtt_init_packet_header(&header, PUBLISH, qos, dup, retained); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + mqtt_write_char(&ptr, header); /* write header */ + + ptr += mqtt_write_packet_rem_len(ptr, rem_len); /* write remaining length */ + ; + + mqtt_write_utf8_string(&ptr, topicName); /* Variable Header: Topic Name */ + + if (qos > 0) { + mqtt_write_uint_16(&ptr, packet_id); /* Variable Header: Topic Name */ + } + + memcpy(ptr, payload, payload_len); + ptr += payload_len; + + *serialized_len = (uint32_t)(ptr - buf); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int qcloud_iot_mqtt_publish(Qcloud_IoT_Client *pClient, char *topicName, PublishParams *pParams) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL); + STRING_PTR_SANITY_CHECK(topicName, QCLOUD_ERR_INVAL); + + Timer timer; + uint32_t len = 0; + int rc; + + ListNode *node = NULL; + + size_t topicLen = strlen(topicName); + if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_TOPIC_LENGTH); + } + + if (pParams->qos == QOS2) { + Log_e("QoS2 is not supported currently"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_QOS_NOT_SUPPORT); + } + + if (!get_client_conn_state(pClient)) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + InitTimer(&timer); + countdown_ms(&timer, pClient->command_timeout_ms); + + HAL_MutexLock(pClient->lock_write_buf); + if (pParams->qos == QOS1) { + pParams->id = get_next_packet_id(pClient); + if (IOT_Log_Get_Level() <= eLOG_DEBUG) { + Log_d("publish topic seq=%d|topicName=%s|payload=%s", pParams->id, topicName, + STRING_PTR_PRINT_SANITY_CHECK((char *)pParams->payload)); + } else { + Log_i("publish topic seq=%d|topicName=%s", pParams->id, topicName); + } + } else { + if (IOT_Log_Get_Level() <= eLOG_DEBUG) { + Log_d("publish packetID=%d|topicName=%s|payload=%s", pParams->id, topicName, + STRING_PTR_PRINT_SANITY_CHECK((char *)pParams->payload)); + } else { + Log_i("publish packetID=%d|topicName=%s", pParams->id, topicName); + } + } + + rc = _serialize_publish_packet(pClient->write_buf, pClient->write_buf_size, 0, pParams->qos, pParams->retained, + pParams->id, topicName, (unsigned char *)pParams->payload, pParams->payload_len, + &len); + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + + if (pParams->qos > QOS0) { + rc = _mask_push_pubInfo_to(pClient, len, pParams->id, &node); + if (QCLOUD_RET_SUCCESS != rc) { + Log_e("push publish into to pubInfolist failed!"); + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + } + + /* send the publish packet */ + rc = send_mqtt_packet(pClient, len, &timer); + if (QCLOUD_RET_SUCCESS != rc) { + if (pParams->qos > QOS0) { + HAL_MutexLock(pClient->lock_list_pub); + list_remove(pClient->list_pub_wait_ack, node); + HAL_MutexUnlock(pClient->lock_list_pub); + } + + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + + HAL_MutexUnlock(pClient->lock_write_buf); + + IOT_FUNC_EXIT_RC(pParams->id); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_subscribe.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_subscribe.c new file mode 100644 index 00000000..d05a8e2b --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_subscribe.c @@ -0,0 +1,256 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "mqtt_client.h" + +/** + * Determines the length of the MQTT subscribe packet that would be produced + * using the supplied parameters + * @param count the number of topic filter strings in topicFilters + * @param topicFilters the array of topic filter strings to be used in the + * publish + * @return the length of buffer needed to contain the serialized version of the + * packet + */ +static uint32_t _get_subscribe_packet_rem_len(uint32_t count, char **topicFilters) +{ + size_t i; + size_t len = 2; /* packetid */ + + for (i = 0; i < count; ++i) { + len += 2 + strlen(*topicFilters + i) + 1; /* length + topic + req_qos */ + } + + return (uint32_t)len; +} + +/** + * Serializes the supplied subscribe data into the supplied buffer, ready for + * sending + * @param buf the buffer into which the packet will be serialized + * @param buf_len the length in bytes of the supplied bufferr + * @param dup integer - the MQTT dup flag + * @param packet_id integer - the MQTT packet identifier + * @param count - number of members in the topicFilters and reqQos arrays + * @param topicFilters - array of topic filter names + * @param requestedQoSs - array of requested QoS + * @return the length of the serialized data. <= 0 indicates error + */ +static int _serialize_subscribe_packet(unsigned char *buf, size_t buf_len, uint8_t dup, uint16_t packet_id, + uint32_t count, char **topicFilters, QoS *requestedQoSs, + uint32_t *serialized_len) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL); + + unsigned char *ptr = buf; + unsigned char header = 0; + uint32_t rem_len = 0; + uint32_t i = 0; + int rc; + + // remaining length of SUBSCRIBE packet = packet type(2 byte) + count * + // (remaining length(2 byte) + topicLen + qos(1 + // byte)) + rem_len = _get_subscribe_packet_rem_len(count, topicFilters); + if (get_mqtt_packet_len(rem_len) > buf_len) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + // init header + rc = mqtt_init_packet_header(&header, SUBSCRIBE, QOS1, dup, 0); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + // 1st byte in fixed header + mqtt_write_char(&ptr, header); + // remaining length + ptr += mqtt_write_packet_rem_len(ptr, rem_len); + // variable header + mqtt_write_uint_16(&ptr, packet_id); + // payload + for (i = 0; i < count; ++i) { + mqtt_write_utf8_string(&ptr, *topicFilters + i); + mqtt_write_char(&ptr, (unsigned char)requestedQoSs[i]); + } + + *serialized_len = (uint32_t)(ptr - buf); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int qcloud_iot_mqtt_subscribe(Qcloud_IoT_Client *pClient, char *topicFilter, SubscribeParams *pParams) +{ + IOT_FUNC_ENTRY; + int rc; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL); + // POINTER_SANITY_CHECK(pParams->on_message_handler, QCLOUD_ERR_INVAL); + STRING_PTR_SANITY_CHECK(topicFilter, QCLOUD_ERR_INVAL); + + Timer timer; + uint32_t len = 0; + uint16_t packet_id = 0; + + ListNode *node = NULL; + + size_t topicLen = strlen(topicFilter); + if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_TOPIC_LENGTH); + } + + if (pParams->qos == QOS2) { + Log_e("QoS2 is not supported currently"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_QOS_NOT_SUPPORT); + } + + if (!get_client_conn_state(pClient)) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN) + } + + /* topic filter should be valid in the whole sub life */ + char *topic_filter_stored = HAL_Malloc(topicLen + 1); + if (topic_filter_stored == NULL) { + Log_e("malloc failed"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + strcpy(topic_filter_stored, topicFilter); + topic_filter_stored[topicLen] = 0; + + InitTimer(&timer); + countdown_ms(&timer, pClient->command_timeout_ms); + + HAL_MutexLock(pClient->lock_write_buf); + packet_id = get_next_packet_id(pClient); + Log_d("topicName=%s|packet_id=%d", topic_filter_stored, packet_id); + + rc = _serialize_subscribe_packet(pClient->write_buf, pClient->write_buf_size, 0, packet_id, 1, &topic_filter_stored, + &pParams->qos, &len); + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexUnlock(pClient->lock_write_buf); + HAL_Free(topic_filter_stored); + IOT_FUNC_EXIT_RC(rc); + } + + /* add node into sub ack wait list */ + SubTopicHandle sub_handle; + sub_handle.topic_filter = topic_filter_stored; + sub_handle.message_handler = pParams->on_message_handler; + sub_handle.sub_event_handler = pParams->on_sub_event_handler; + sub_handle.qos = pParams->qos; + sub_handle.handler_user_data = pParams->user_data; + + rc = push_sub_info_to(pClient, len, (unsigned int)packet_id, SUBSCRIBE, &sub_handle, &node); + if (QCLOUD_RET_SUCCESS != rc) { + Log_e("push publish into to pubInfolist failed!"); + HAL_MutexUnlock(pClient->lock_write_buf); + HAL_Free(topic_filter_stored); + IOT_FUNC_EXIT_RC(rc); + } + + // send SUBSCRIBE packet + rc = send_mqtt_packet(pClient, len, &timer); + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexLock(pClient->lock_list_sub); + list_remove(pClient->list_sub_wait_ack, node); + HAL_MutexUnlock(pClient->lock_list_sub); + + HAL_MutexUnlock(pClient->lock_write_buf); + HAL_Free(topic_filter_stored); + IOT_FUNC_EXIT_RC(rc); + } + + HAL_MutexUnlock(pClient->lock_write_buf); + + IOT_FUNC_EXIT_RC(packet_id); +} + +int qcloud_iot_mqtt_resubscribe(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + int rc; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + uint32_t itr = 0; + char * topic = NULL; + SubscribeParams temp_param; + + if (NULL == pClient) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL); + } + + if (!get_client_conn_state(pClient)) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + for (itr = 0; itr < MAX_MESSAGE_HANDLERS; itr++) { + topic = (char *)pClient->sub_handles[itr].topic_filter; + if (topic == NULL) { + continue; + } + temp_param.on_message_handler = pClient->sub_handles[itr].message_handler; + temp_param.on_sub_event_handler = pClient->sub_handles[itr].sub_event_handler; + temp_param.qos = pClient->sub_handles[itr].qos; + temp_param.user_data = pClient->sub_handles[itr].handler_user_data; + + rc = qcloud_iot_mqtt_subscribe(pClient, topic, &temp_param); + if (rc < 0) { + Log_e("resubscribe failed %d, topic: %s", rc, topic); + IOT_FUNC_EXIT_RC(rc); + } + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +bool qcloud_iot_mqtt_is_sub_ready(Qcloud_IoT_Client *pClient, char *topicFilter) +{ + IOT_FUNC_ENTRY; + POINTER_SANITY_CHECK(pClient, false); + STRING_PTR_SANITY_CHECK(topicFilter, false); + + size_t topicLen = strlen(topicFilter); + if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) { + return false; + } + + int i = 0; + HAL_MutexLock(pClient->lock_generic); + for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) { + if ((pClient->sub_handles[i].topic_filter != NULL && + !strcmp(pClient->sub_handles[i].topic_filter, topicFilter)) || + strstr(topicFilter, "/#") != NULL || strstr(topicFilter, "/+") != NULL) { + HAL_MutexUnlock(pClient->lock_generic); + return true; + } + } + HAL_MutexUnlock(pClient->lock_generic); + return false; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_unsubscribe.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_unsubscribe.c new file mode 100644 index 00000000..6ff260ee --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_unsubscribe.c @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "mqtt_client.h" + +/** + * Determines the length of the MQTT unsubscribe packet that would be produced + * using the supplied parameters + * @param count the number of topic filter strings in topicFilters + * @param topicFilters the array of topic filter strings to be used in the + * publish + * @return the length of buffer needed to contain the serialized version of the + * packet + */ +static uint32_t _get_unsubscribe_packet_rem_len(uint32_t count, char **topicFilters) +{ + size_t i; + size_t len = 2; /* packetid */ + + for (i = 0; i < count; ++i) { + len += 2 + strlen(*topicFilters + i); /* length + topic*/ + } + + return (uint32_t)len; +} + +/** + * Serializes the supplied unsubscribe data into the supplied buffer, ready for + * sending + * @param buf the raw buffer data, of the correct length determined by the + * remaining length field + * @param buf_len the length in bytes of the data in the supplied buffer + * @param dup integer - the MQTT dup flag + * @param packet_id integer - the MQTT packet identifier + * @param count - number of members in the topicFilters array + * @param topicFilters - array of topic filter names + * @param serialized_len - the length of the serialized data + * @return int indicating function execution status + */ +static int _serialize_unsubscribe_packet(unsigned char *buf, size_t buf_len, uint8_t dup, uint16_t packet_id, + uint32_t count, char **topicFilters, uint32_t *serialized_len) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(serialized_len, QCLOUD_ERR_INVAL); + + unsigned char *ptr = buf; + unsigned char header = 0; + uint32_t rem_len = 0; + uint32_t i = 0; + int rc; + + rem_len = _get_unsubscribe_packet_rem_len(count, topicFilters); + if (get_mqtt_packet_len(rem_len) > buf_len) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_BUF_TOO_SHORT); + } + + rc = mqtt_init_packet_header(&header, UNSUBSCRIBE, QOS1, dup, 0); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + mqtt_write_char(&ptr, header); /* write header */ + + ptr += mqtt_write_packet_rem_len(ptr, rem_len); /* write remaining length */ + + mqtt_write_uint_16(&ptr, packet_id); + + for (i = 0; i < count; ++i) { + mqtt_write_utf8_string(&ptr, *topicFilters + i); + } + + *serialized_len = (uint32_t)(ptr - buf); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int qcloud_iot_mqtt_unsubscribe(Qcloud_IoT_Client *pClient, char *topicFilter) +{ + IOT_FUNC_ENTRY; + int rc; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + STRING_PTR_SANITY_CHECK(topicFilter, QCLOUD_ERR_INVAL); + + int i = 0; + Timer timer; + uint32_t len = 0; + uint16_t packet_id = 0; + bool suber_exists = false; + + ListNode *node = NULL; + + size_t topicLen = strlen(topicFilter); + if (topicLen > MAX_SIZE_OF_CLOUD_TOPIC) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_TOPIC_LENGTH); + } + + /* Remove from message handler array */ + HAL_MutexLock(pClient->lock_generic); + for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) { + if ((pClient->sub_handles[i].topic_filter != NULL && + !strcmp(pClient->sub_handles[i].topic_filter, topicFilter)) || + strstr(topicFilter, "/#") != NULL || strstr(topicFilter, "/+") != NULL) { + /* notify this event to topic subscriber */ + if (NULL != pClient->sub_handles[i].sub_event_handler) + pClient->sub_handles[i].sub_event_handler(pClient, MQTT_EVENT_UNSUBSCRIBE, + pClient->sub_handles[i].handler_user_data); + + /* Free the topic filter malloced in qcloud_iot_mqtt_subscribe */ + HAL_Free((void *)pClient->sub_handles[i].topic_filter); + pClient->sub_handles[i].topic_filter = NULL; + + /* We don't want to break here, if the same topic is registered + * with 2 callbacks. Unlikely scenario */ + suber_exists = true; + } + } + HAL_MutexUnlock(pClient->lock_generic); + + if (suber_exists == false) { + Log_e("subscription does not exists: %s", topicFilter); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_UNSUB_FAIL); + } + + if (!get_client_conn_state(pClient)) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + /* topic filter should be valid in the whole sub life */ + char *topic_filter_stored = HAL_Malloc(topicLen + 1); + if (topic_filter_stored == NULL) { + Log_e("malloc failed"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + strcpy(topic_filter_stored, topicFilter); + topic_filter_stored[topicLen] = 0; + + InitTimer(&timer); + countdown_ms(&timer, pClient->command_timeout_ms); + + HAL_MutexLock(pClient->lock_write_buf); + packet_id = get_next_packet_id(pClient); + rc = _serialize_unsubscribe_packet(pClient->write_buf, pClient->write_buf_size, 0, packet_id, 1, + &topic_filter_stored, &len); + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexUnlock(pClient->lock_write_buf); + HAL_Free(topic_filter_stored); + IOT_FUNC_EXIT_RC(rc); + } + + SubTopicHandle sub_handle; + sub_handle.topic_filter = topic_filter_stored; + sub_handle.sub_event_handler = NULL; + sub_handle.message_handler = NULL; + sub_handle.handler_user_data = NULL; + + rc = push_sub_info_to(pClient, len, (unsigned int)packet_id, UNSUBSCRIBE, &sub_handle, &node); + if (QCLOUD_RET_SUCCESS != rc) { + Log_e("push publish into to pubInfolist failed: %d", rc); + HAL_MutexUnlock(pClient->lock_write_buf); + HAL_Free(topic_filter_stored); + IOT_FUNC_EXIT_RC(rc); + } + + /* send the unsubscribe packet */ + rc = send_mqtt_packet(pClient, len, &timer); + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexLock(pClient->lock_list_sub); + list_remove(pClient->list_sub_wait_ack, node); + HAL_MutexUnlock(pClient->lock_list_sub); + + HAL_MutexUnlock(pClient->lock_write_buf); + HAL_Free(topic_filter_stored); + IOT_FUNC_EXIT_RC(rc); + } + + HAL_MutexUnlock(pClient->lock_write_buf); + + IOT_FUNC_EXIT_RC(packet_id); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_yield.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_yield.c new file mode 100644 index 00000000..485b272a --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/mqtt_client_yield.c @@ -0,0 +1,484 @@ +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "log_upload.h" +#include "mqtt_client.h" +#include "qcloud_iot_import.h" + +static uint32_t _get_random_interval(void) +{ + srand((unsigned)HAL_GetTimeMs()); + /* range: 1000 - 2000 ms, in 10ms unit */ + return (rand() % 100 + 100) * 10; +} + +static void _iot_disconnect_callback(Qcloud_IoT_Client *pClient) +{ + if (NULL != pClient->event_handle.h_fp) { + MQTTEventMsg msg; + msg.event_type = MQTT_EVENT_DISCONNECT; + msg.msg = NULL; + + pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg); + } +} + +static void _reconnect_callback(Qcloud_IoT_Client *pClient) +{ + if (NULL != pClient->event_handle.h_fp) { + MQTTEventMsg msg; + msg.event_type = MQTT_EVENT_RECONNECT; + msg.msg = NULL; + + pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg); + } +} + +/** + * @brief handle exceptional disconnection + * + * @param pClient + * @return + */ +static int _handle_disconnect(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + int rc; + + if (0 == get_client_conn_state(pClient)) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + rc = qcloud_iot_mqtt_disconnect(pClient); + // disconnect network stack by force + if (rc != QCLOUD_RET_SUCCESS) { + pClient->network_stack.disconnect(&(pClient->network_stack)); + set_client_conn_state(pClient, NOTCONNECTED); + } + + Log_e("disconnect MQTT for some reasons.."); + + _iot_disconnect_callback(pClient); + + // exceptional disconnection + pClient->was_manually_disconnected = 0; + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); +} + +/** + * @brief handle reconnect + * + * @param pClient + * @return + */ +static int _handle_reconnect(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + + int8_t isPhysicalLayerConnected = 1; + int rc = QCLOUD_RET_MQTT_RECONNECTED; + + // reconnect control by delay timer (increase interval exponentially ) + if (!expired(&(pClient->reconnect_delay_timer))) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT); + } + + if (NULL != pClient->network_stack.is_connected) { + isPhysicalLayerConnected = + (int8_t)pClient->network_stack.is_connected(&(pClient->network_stack)); // always return 1 + } + + if (isPhysicalLayerConnected) { + rc = qcloud_iot_mqtt_attempt_reconnect(pClient); + if (rc == QCLOUD_RET_MQTT_RECONNECTED) { + Log_e("attempt to reconnect success."); + _reconnect_callback(pClient); +#ifdef LOG_UPLOAD + if (is_log_uploader_init()) { + int log_level; + if (qcloud_get_log_level(&log_level) < 0) { + Log_e("client get log topic failed: %d", rc); + } + } +#endif + IOT_FUNC_EXIT_RC(rc); + } else { + Log_e("attempt to reconnect failed, errCode: %d", rc); + rc = QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT; + } + } + + pClient->current_reconnect_wait_interval *= 2; + + if (MAX_RECONNECT_WAIT_INTERVAL < pClient->current_reconnect_wait_interval) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_RECONNECT_TIMEOUT); + } + countdown_ms(&(pClient->reconnect_delay_timer), pClient->current_reconnect_wait_interval); + + IOT_FUNC_EXIT_RC(rc); +} + +/** + * @brief handle MQTT keep alive (hearbeat with server) + * + * @param pClient + * @return + */ +static int _mqtt_keep_alive(Qcloud_IoT_Client *pClient) +{ +#define MQTT_PING_RETRY_TIMES 2 + + IOT_FUNC_ENTRY; + + int rc; + Timer timer; + uint32_t serialized_len = 0; + + if (0 == pClient->options.keep_alive_interval) { + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + } + + if (!expired(&pClient->ping_timer)) { + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + } + + if (pClient->is_ping_outstanding >= MQTT_PING_RETRY_TIMES) { + // Reaching here means we haven't received any MQTT packet for a long time (keep_alive_interval) + Log_e("Fail to recv MQTT msg. Something wrong with the connection."); + rc = _handle_disconnect(pClient); + IOT_FUNC_EXIT_RC(rc); + } + + /* there is no ping outstanding - send one */ + HAL_MutexLock(pClient->lock_write_buf); + rc = serialize_packet_with_zero_payload(pClient->write_buf, pClient->write_buf_size, PINGREQ, &serialized_len); + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexUnlock(pClient->lock_write_buf); + IOT_FUNC_EXIT_RC(rc); + } + + /* send the ping packet */ + int i = 0; + InitTimer(&timer); + do { + countdown_ms(&timer, pClient->command_timeout_ms); + rc = send_mqtt_packet(pClient, serialized_len, &timer); + } while (QCLOUD_RET_SUCCESS != rc && (i++ < 3)); + + if (QCLOUD_RET_SUCCESS != rc) { + HAL_MutexUnlock(pClient->lock_write_buf); + // If sending a PING fails, propably the connection is not OK and we decide to disconnect and begin reconnection + // attempts + Log_e("Fail to send PING request. Something wrong with the connection."); + rc = _handle_disconnect(pClient); + IOT_FUNC_EXIT_RC(rc); + } + HAL_MutexUnlock(pClient->lock_write_buf); + + HAL_MutexLock(pClient->lock_generic); + pClient->is_ping_outstanding++; + /* start a timer to wait for PINGRESP from server */ + countdown(&pClient->ping_timer, Min(5, pClient->options.keep_alive_interval / 2)); + HAL_MutexUnlock(pClient->lock_generic); + Log_d("PING request %u has been sent...", pClient->is_ping_outstanding); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * @brief Check connection and keep alive state, read/handle MQTT message in synchronized way + * + * @param pClient handle to MQTT client + * @param timeout_ms timeout value (unit: ms) for this operation + * + * @return QCLOUD_RET_SUCCESS when success, QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT when try reconnecing, or err code for + * failure + */ +int qcloud_iot_mqtt_yield(Qcloud_IoT_Client *pClient, uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + + int rc = QCLOUD_RET_SUCCESS; + Timer timer; + uint8_t packet_type; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL); + + // 1. check if manually disconnect + if (!get_client_conn_state(pClient) && pClient->was_manually_disconnected == 1) { + IOT_FUNC_EXIT_RC(QCLOUD_RET_MQTT_MANUALLY_DISCONNECTED); + } + + // 2. check connection state and if auto reconnect is enabled + if (!get_client_conn_state(pClient) && pClient->options.auto_connect_enable == 0) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN); + } + + InitTimer(&timer); + countdown_ms(&timer, timeout_ms); + + // 3. main loop for packet reading/handling and keep alive maintainance + while (!expired(&timer)) { + if (!get_client_conn_state(pClient)) { + if (pClient->current_reconnect_wait_interval > MAX_RECONNECT_WAIT_INTERVAL) { + rc = QCLOUD_ERR_MQTT_RECONNECT_TIMEOUT; + break; + } + rc = _handle_reconnect(pClient); + + continue; + } + + rc = cycle_for_read(pClient, &timer, &packet_type, QOS0); + + if (rc == QCLOUD_RET_SUCCESS) { + /* check list of wait publish ACK to remove node that is ACKED or timeout */ + qcloud_iot_mqtt_pub_info_proc(pClient); + + /* check list of wait subscribe(or unsubscribe) ACK to remove node that is ACKED or timeout */ + qcloud_iot_mqtt_sub_info_proc(pClient); + + rc = _mqtt_keep_alive(pClient); + } else if (rc == QCLOUD_ERR_SSL_READ_TIMEOUT || rc == QCLOUD_ERR_SSL_READ || + rc == QCLOUD_ERR_TCP_PEER_SHUTDOWN || rc == QCLOUD_ERR_TCP_READ_FAIL) { + Log_e("network read failed, rc: %d. MQTT Disconnect.", rc); + rc = _handle_disconnect(pClient); + } + + if (rc == QCLOUD_ERR_MQTT_NO_CONN) { + pClient->counter_network_disconnected++; + + if (pClient->options.auto_connect_enable == 1) { + pClient->current_reconnect_wait_interval = _get_random_interval(); + countdown_ms(&(pClient->reconnect_delay_timer), pClient->current_reconnect_wait_interval); + + // reconnect timeout + rc = QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT; + } else { + break; + } + } else if (rc != QCLOUD_RET_SUCCESS) { + break; + } + } + + IOT_FUNC_EXIT_RC(rc); +} + +/** + * @brief puback waiting timeout process + * + * @param pClient reference to MQTTClient + * + */ +int qcloud_iot_mqtt_pub_info_proc(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + + POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL); + + HAL_MutexLock(pClient->lock_list_pub); + do { + if (0 == pClient->list_pub_wait_ack->len) { + break; + } + + ListIterator *iter; + ListNode * node = NULL; + ListNode * temp_node = NULL; + + if (NULL == (iter = list_iterator_new(pClient->list_pub_wait_ack, LIST_TAIL))) { + Log_e("new list failed"); + break; + } + + for (;;) { + node = list_iterator_next(iter); + + if (NULL != temp_node) { + list_remove(pClient->list_pub_wait_ack, temp_node); + temp_node = NULL; + } + + if (NULL == node) { + break; /* end of list */ + } + + QcloudIotPubInfo *repubInfo = (QcloudIotPubInfo *)node->val; + if (NULL == repubInfo) { + Log_e("node's value is invalid!"); + temp_node = node; + continue; + } + + /* remove invalid node */ + if (MQTT_NODE_STATE_INVALID == repubInfo->node_state) { + temp_node = node; + continue; + } + + if (!pClient->is_connected) { + continue; + } + + /* check the request if timeout or not */ + if (left_ms(&repubInfo->pub_start_time) > 0) { + continue; + } + + HAL_MutexUnlock(pClient->lock_list_pub); + /* If wait ACK timeout, remove the node from list */ + /* It is up to user to do republishing or not */ + temp_node = node; + + countdown_ms(&repubInfo->pub_start_time, pClient->command_timeout_ms); + HAL_MutexLock(pClient->lock_list_pub); + + /* notify timeout event */ + if (NULL != pClient->event_handle.h_fp) { + MQTTEventMsg msg; + msg.event_type = MQTT_EVENT_PUBLISH_TIMEOUT; + msg.msg = (void *)(uintptr_t)repubInfo->msg_id; + pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg); + } + } + + list_iterator_destroy(iter); + + } while (0); + + HAL_MutexUnlock(pClient->lock_list_pub); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/** + * @brief suback waiting timeout process + * + * @param pClient reference to MQTTClient + * + */ +int qcloud_iot_mqtt_sub_info_proc(Qcloud_IoT_Client *pClient) +{ + IOT_FUNC_ENTRY; + int rc = QCLOUD_RET_SUCCESS; + + if (!pClient) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL); + } + + HAL_MutexLock(pClient->lock_list_sub); + do { + if (0 == pClient->list_sub_wait_ack->len) { + break; + } + + ListIterator *iter; + ListNode * node = NULL; + ListNode * temp_node = NULL; + uint16_t packet_id = 0; + MessageTypes msg_type; + + if (NULL == (iter = list_iterator_new(pClient->list_sub_wait_ack, LIST_TAIL))) { + Log_e("new list failed"); + HAL_MutexUnlock(pClient->lock_list_sub); + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + } + + for (;;) { + node = list_iterator_next(iter); + + if (NULL != temp_node) { + list_remove(pClient->list_sub_wait_ack, temp_node); + temp_node = NULL; + } + + if (NULL == node) { + break; /* end of list */ + } + + QcloudIotSubInfo *sub_info = (QcloudIotSubInfo *)node->val; + if (NULL == sub_info) { + Log_e("node's value is invalid!"); + temp_node = node; + continue; + } + + /* remove invalid node */ + if (MQTT_NODE_STATE_INVALID == sub_info->node_state) { + temp_node = node; + continue; + } + + if (pClient->is_connected <= 0) { + continue; + } + + /* check the request if timeout or not */ + if (left_ms(&sub_info->sub_start_time) > 0) { + continue; + } + + /* When arrive here, it means timeout to wait ACK */ + packet_id = sub_info->msg_id; + msg_type = sub_info->type; + + /* Wait MQTT SUBSCRIBE ACK timeout */ + if (NULL != pClient->event_handle.h_fp) { + MQTTEventMsg msg; + + if (SUBSCRIBE == msg_type) { + /* subscribe timeout */ + msg.event_type = MQTT_EVENT_SUBCRIBE_TIMEOUT; + msg.msg = (void *)(uintptr_t)packet_id; + + /* notify this event to topic subscriber */ + if (NULL != sub_info->handler.sub_event_handler) + sub_info->handler.sub_event_handler(pClient, MQTT_EVENT_SUBCRIBE_TIMEOUT, + sub_info->handler.handler_user_data); + + } else { + /* unsubscribe timeout */ + msg.event_type = MQTT_EVENT_UNSUBCRIBE_TIMEOUT; + msg.msg = (void *)(uintptr_t)packet_id; + } + + pClient->event_handle.h_fp(pClient, pClient->event_handle.context, &msg); + } + + if (NULL != sub_info->handler.topic_filter) + HAL_Free((void *)(sub_info->handler.topic_filter)); + + temp_node = node; + } + + list_iterator_destroy(iter); + + } while (0); + + HAL_MutexUnlock(pClient->lock_list_sub); + + IOT_FUNC_EXIT_RC(rc); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/network_interface.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/network_interface.c new file mode 100644 index 00000000..48f3ab50 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/network_interface.c @@ -0,0 +1,116 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "network_interface.h" + +#include "qcloud_iot_export_error.h" +#include "qutils_param_check.h" + +int is_network_connected(Network *pNetwork) +{ + return pNetwork->handle; +} + +#ifdef AT_TCP_ENABLED +int is_network_at_connected(Network *pNetwork) +{ + return pNetwork->handle == AT_NO_CONNECTED_FD ? 0 : pNetwork->handle == AT_NO_CONNECTED_FD; +} +#endif + +int network_init(Network *pNetwork) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + +// to avoid process crash when writing to a broken socket +#if defined(__linux__) + signal(SIGPIPE, SIG_IGN); +#endif + + switch (pNetwork->type) { + case NETWORK_TCP: +#ifdef AT_TCP_ENABLED + pNetwork->init = network_at_tcp_init; + pNetwork->connect = network_at_tcp_connect; + pNetwork->read = network_at_tcp_read; + pNetwork->write = network_at_tcp_write; + pNetwork->disconnect = network_at_tcp_disconnect; + pNetwork->is_connected = is_network_at_connected; + pNetwork->handle = AT_NO_CONNECTED_FD; +#else + pNetwork->init = network_tcp_init; + pNetwork->connect = network_tcp_connect; + pNetwork->read = network_tcp_read; + pNetwork->write = network_tcp_write; + pNetwork->disconnect = network_tcp_disconnect; + pNetwork->is_connected = is_network_connected; + pNetwork->handle = 0; +#endif + break; + +#ifndef AUTH_WITH_NOTLS + case NETWORK_TLS: + pNetwork->init = network_tls_init; + pNetwork->connect = network_tls_connect; + pNetwork->read = network_tls_read; + pNetwork->write = network_tls_write; + pNetwork->disconnect = network_tls_disconnect; + pNetwork->is_connected = is_network_connected; + pNetwork->handle = 0; + break; +#endif + +#ifdef COAP_COMM_ENABLED +#ifdef AUTH_WITH_NOTLS + case NETWORK_UDP: + pNetwork->init = network_udp_init; + pNetwork->connect = network_udp_connect; + pNetwork->read = network_udp_read; + pNetwork->write = network_udp_write; + pNetwork->disconnect = network_udp_disconnect; + pNetwork->is_connected = is_network_connected; + pNetwork->handle = 0; + break; +#else + case NETWORK_DTLS: + pNetwork->init = network_dtls_init; + pNetwork->connect = network_dtls_connect; + pNetwork->read = network_dtls_read; + pNetwork->write = network_dtls_write; + pNetwork->disconnect = network_dtls_disconnect; + pNetwork->is_connected = is_network_connected; + pNetwork->handle = 0; + break; +#endif +#endif + default: + Log_e("unknown network type: %d", pNetwork->type); + return QCLOUD_ERR_INVAL; + } + return pNetwork->init(pNetwork); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/network_socket.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/network_socket.c new file mode 100644 index 00000000..e2a22cda --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/network_socket.c @@ -0,0 +1,136 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include "network_interface.h" +#include "qcloud_iot_export_error.h" +#include "qcloud_iot_import.h" +#include "qutils_param_check.h" + +/* + * TCP/UDP socket API + */ + +int network_tcp_init(Network *pNetwork) +{ + return QCLOUD_RET_SUCCESS; +} + +int network_tcp_connect(Network *pNetwork) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + pNetwork->handle = HAL_TCP_Connect(pNetwork->host, pNetwork->port); + if (0 == pNetwork->handle) { + return -1; + } + + return 0; +} + +int network_tcp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + int rc = 0; + + rc = HAL_TCP_Read(pNetwork->handle, data, (uint32_t)datalen, timeout_ms, read_len); + + return rc; +} + +int network_tcp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + int rc = 0; + + rc = HAL_TCP_Write(pNetwork->handle, data, datalen, timeout_ms, written_len); + + return rc; +} + +void network_tcp_disconnect(Network *pNetwork) +{ + POINTER_SANITY_CHECK_RTN(pNetwork); + + if (0 == pNetwork->handle) { + return; + } + + HAL_TCP_Disconnect(pNetwork->handle); + pNetwork->handle = 0; + return; +} + +#if (defined COAP_COMM_ENABLED) && (defined AUTH_WITH_NOTLS) + +int network_udp_init(Network *pNetwork) +{ + return QCLOUD_RET_SUCCESS; +} + +int network_udp_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + int ret = HAL_UDP_ReadTimeout(pNetwork->handle, data, datalen, timeout_ms); + if (ret > 0) { + *read_len = ret; + ret = 0; + } + + return ret; +} + +int network_udp_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + int ret = HAL_UDP_Write(pNetwork->handle, data, datalen); + if (ret > 0) { + *written_len = ret; + ret = 0; + } + + return ret; +} + +void network_udp_disconnect(Network *pNetwork) +{ + POINTER_SANITY_CHECK_RTN(pNetwork); + + HAL_UDP_Disconnect(pNetwork->handle); + pNetwork->handle = 0; + + return; +} + +int network_udp_connect(Network *pNetwork) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + pNetwork->handle = HAL_UDP_Connect(pNetwork->host, pNetwork->port); + if (0 == pNetwork->handle) { + return -1; + } + return 0; +} + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/network_tls.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/network_tls.c new file mode 100644 index 00000000..5df16a48 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/network_tls.c @@ -0,0 +1,122 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include "network_interface.h" +#include "qcloud_iot_export_error.h" +#include "qcloud_iot_import.h" +#include "qutils_param_check.h" + +/* + * TLS/DTLS network API + */ +#ifndef AUTH_WITH_NOTLS + +int network_tls_init(Network *pNetwork) +{ + return QCLOUD_RET_SUCCESS; +} + +int network_tls_connect(Network *pNetwork) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + int ret = QCLOUD_ERR_FAILURE; + + pNetwork->handle = (uintptr_t)HAL_TLS_Connect(&(pNetwork->ssl_connect_params), pNetwork->host, pNetwork->port); + if (pNetwork->handle != 0) { + ret = QCLOUD_RET_SUCCESS; + } + + return ret; +} + +int network_tls_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + int rc = HAL_TLS_Read(pNetwork->handle, data, datalen, timeout_ms, read_len); + + return rc; +} + +int network_tls_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + int rc = HAL_TLS_Write(pNetwork->handle, data, datalen, timeout_ms, written_len); + + return rc; +} + +void network_tls_disconnect(Network *pNetwork) +{ + POINTER_SANITY_CHECK_RTN(pNetwork); + + HAL_TLS_Disconnect(pNetwork->handle); + pNetwork->handle = 0; +} + +#ifdef COAP_COMM_ENABLED + +int network_dtls_init(Network *pNetwork) +{ + return QCLOUD_RET_SUCCESS; +} + +int network_dtls_read(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *read_len) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + return HAL_DTLS_Read(pNetwork->handle, data, datalen, timeout_ms, read_len); +} + +int network_dtls_write(Network *pNetwork, unsigned char *data, size_t datalen, uint32_t timeout_ms, size_t *written_len) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + return HAL_DTLS_Write(pNetwork->handle, data, datalen, written_len); +} + +void network_dtls_disconnect(Network *pNetwork) +{ + POINTER_SANITY_CHECK_RTN(pNetwork); + + HAL_DTLS_Disconnect(pNetwork->handle); + pNetwork->handle = 0; + + return; +} + +int network_dtls_connect(Network *pNetwork) +{ + POINTER_SANITY_CHECK(pNetwork, QCLOUD_ERR_INVAL); + + int ret = QCLOUD_ERR_FAILURE; + + pNetwork->handle = (uintptr_t)HAL_DTLS_Connect(&(pNetwork->ssl_connect_params), pNetwork->host, pNetwork->port); + if (pNetwork->handle != 0) { + ret = QCLOUD_RET_SUCCESS; + } + + return ret; +} +#endif + +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_client.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_client.c new file mode 100644 index 00000000..33b911be --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_client.c @@ -0,0 +1,696 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ota_client.h" + +#include +#include +#include + +#include "ota_fetch.h" +#include "ota_lib.h" +#include "qcloud_iot_export.h" +#include "qutils_param_check.h" +#include "qutils_timer.h" + +#define OTA_VERSION_STR_LEN_MIN (1) +#define OTA_VERSION_STR_LEN_MAX (32) + +typedef struct { + const char *product_id; /* point to product id */ + const char *device_name; /* point to device name */ + + uint32_t id; /* message id */ + IOT_OTA_State_Code 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 *purl; /* point to URL */ + char *version; /* point to string */ + char md5sum[33]; /* 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 */ + + short current_signal_type; + + Timer report_timer; + +} OTA_Struct_t; + +/* check ota progress */ +/* return: true, valid progress state; false, invalid progress state. */ +static int _ota_check_progress(IOT_OTA_Progress_Code progress) +{ + return ((progress >= IOT_OTAP_BURN_FAILED) && (progress <= IOT_OTAP_FETCH_PERCENTAGE_MAX)); +} + +/* callback when OTA topic msg is received */ +static void _ota_callback(void *pcontext, const char *msg, uint32_t msg_len) +{ +#define OTA_JSON_TYPE_VALUE_LENGTH 64 + + char *json_type = NULL; + + OTA_Struct_t *h_ota = (OTA_Struct_t *)pcontext; + + if (h_ota->state >= IOT_OTAS_FETCHING) { + Log_i("In downloading or downloaded state"); + goto End; + } + + if (msg == NULL || msg_len <= 0) { + Log_e("OTA response message is NULL"); + return; + } + + if (qcloud_otalib_get_firmware_type(msg, &json_type) != QCLOUD_RET_SUCCESS) { + Log_e("Get firmware type failed!"); + goto End; + } + + if (!strcmp(json_type, REPORT_VERSION_RSP)) { + if (qcloud_otalib_get_report_version_result(msg) < QCLOUD_RET_SUCCESS) { + Log_e("Report version failed!"); + h_ota->err = IOT_OTA_ERR_REPORT_VERSION; + h_ota->state = IOT_OTAS_FETCHED; + } else { + Log_i("Report version success!"); + } + goto End; + } else { + if (strcmp(json_type, UPDATE_FIRMWARE) != 0) { + Log_e("Netheir Report version result nor update firmware! type: %s", + STRING_PTR_PRINT_SANITY_CHECK(json_type)); + goto End; + } + + if (NULL != json_type) { + HAL_Free(json_type); + json_type = NULL; + } + + if (0 != qcloud_otalib_get_params(msg, &json_type, &h_ota->purl, &h_ota->version, h_ota->md5sum, + &h_ota->size_file)) { + Log_e("Get firmware parameter failed"); + goto End; + } + + h_ota->state = IOT_OTAS_FETCHING; + } + +End: + if (json_type != NULL) + HAL_Free(json_type); + +#undef OTA_JSON_TYPE_VALUE_LENGTH +} + +static void IOT_OTA_ResetStatus(void *handle) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + Log_i("reset OTA state!"); + h_ota->state = IOT_OTAS_INITED; + h_ota->err = 0; + + if (NULL != h_ota->purl) { + HAL_Free(h_ota->purl); + h_ota->purl = NULL; + } + + if (NULL != h_ota->version) { + HAL_Free(h_ota->version); + h_ota->version = NULL; + } +} + +static int IOT_OTA_ReportProgress(void *handle, IOT_OTA_Progress_Code progress, IOT_OTAReportType reportType) +{ +#define MSG_REPORT_LEN (256) + + int ret = QCLOUD_ERR_FAILURE; + char * msg_reported; + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + + if (NULL == handle) { + Log_e("handle is NULL"); + return IOT_OTA_ERR_INVALID_PARAM; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + Log_e("handle is uninitialized"); + h_ota->err = IOT_OTA_ERR_INVALID_STATE; + return QCLOUD_ERR_FAILURE; + } + + if (!_ota_check_progress(progress)) { + Log_e("progress is a invalid parameter"); + h_ota->err = IOT_OTA_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } + + if (NULL == (msg_reported = HAL_Malloc(MSG_REPORT_LEN))) { + Log_e("allocate for msg_reported failed"); + h_ota->err = IOT_OTA_ERR_NOMEM; + return QCLOUD_ERR_FAILURE; + } + + ret = qcloud_otalib_gen_report_msg(msg_reported, MSG_REPORT_LEN, h_ota->id, h_ota->version, progress, reportType); + if (0 != ret) { + Log_e("generate reported message failed"); + h_ota->err = ret; + goto do_exit; + } + + ret = qcloud_osc_report_progress(h_ota->ch_signal, msg_reported); + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("Report progress failed"); + h_ota->err = ret; + goto do_exit; + } + + ret = QCLOUD_RET_SUCCESS; + +do_exit: + if (NULL != msg_reported) { + HAL_Free(msg_reported); + } + return ret; + +#undef MSG_REPORT_LEN +} + +static int IOT_OTA_ReportUpgradeResult(void *handle, const char *version, IOT_OTAReportType reportType) +{ +#define MSG_UPGPGRADE_LEN (256) + + POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM); + POINTER_SANITY_CHECK(version, IOT_OTA_ERR_INVALID_PARAM); + + int ret, len; + char * msg_upgrade; + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + + if (IOT_OTAS_UNINITED == h_ota->state) { + Log_e("handle is uninitialized"); + h_ota->err = IOT_OTA_ERR_INVALID_STATE; + return QCLOUD_ERR_FAILURE; + } + + len = strlen(version); + if ((len < OTA_VERSION_STR_LEN_MIN) || (len > OTA_VERSION_STR_LEN_MAX)) { + Log_e("version string is invalid: must be [1, 32] chars"); + h_ota->err = IOT_OTA_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } + + if (NULL == (msg_upgrade = HAL_Malloc(MSG_UPGPGRADE_LEN))) { + Log_e("allocate for msg_informed failed"); + h_ota->err = IOT_OTA_ERR_NOMEM; + return QCLOUD_ERR_FAILURE; + } + + ret = qcloud_otalib_gen_report_msg(msg_upgrade, MSG_UPGPGRADE_LEN, 1, version, 1, reportType); + if (ret != 0) { + Log_e("generate inform message failed"); + h_ota->err = ret; + ret = QCLOUD_ERR_FAILURE; + goto do_exit; + } + + ret = qcloud_osc_report_upgrade_result(h_ota->ch_signal, msg_upgrade); + if (0 > ret) { + Log_e("Report version failed"); + h_ota->err = ret; + ret = QCLOUD_ERR_FAILURE; + goto do_exit; + } + + if ((IOT_OTAR_UPGRADE_FAIL == reportType) || (IOT_OTAR_UPGRADE_SUCCESS == reportType) || + (IOT_OTAR_MD5_NOT_MATCH == reportType)) { + IOT_OTA_ResetStatus(h_ota); + } + +do_exit: + if (NULL != msg_upgrade) { + HAL_Free(msg_upgrade); + } + return ret; + +#undef MSG_UPGPGRADE_LEN +} + +/* Init OTA handle */ +void *IOT_OTA_Init(const char *product_id, const char *device_name, void *ch_signal) +{ + POINTER_SANITY_CHECK(product_id, NULL); + POINTER_SANITY_CHECK(device_name, NULL); + POINTER_SANITY_CHECK(ch_signal, NULL); + + OTA_Struct_t *h_ota = NULL; + + if (NULL == (h_ota = HAL_Malloc(sizeof(OTA_Struct_t)))) { + Log_e("allocate failed"); + return NULL; + } + memset(h_ota, 0, sizeof(OTA_Struct_t)); + h_ota->state = IOT_OTAS_UNINITED; + + h_ota->ch_signal = qcloud_osc_init(product_id, device_name, ch_signal, _ota_callback, h_ota); + if (NULL == h_ota->ch_signal) { + Log_e("initialize signal channel failed"); + goto do_exit; + } + + h_ota->md5 = qcloud_otalib_md5_init(); + if (NULL == h_ota->md5) { + Log_e("initialize md5 failed"); + goto do_exit; + } + + h_ota->product_id = product_id; + h_ota->device_name = device_name; + h_ota->state = IOT_OTAS_INITED; +#ifdef OTA_MQTT_CHANNEL + h_ota->current_signal_type = MQTT_CHANNEL; +#else + h_ota->current_signal_type = COAP_CHANNEL; +#endif + return h_ota; + +do_exit: + + if (NULL != h_ota->ch_signal) { + qcloud_osc_deinit(h_ota->ch_signal); + } + + if (NULL != h_ota->md5) { + qcloud_otalib_md5_deinit(h_ota->md5); + } + + if (NULL != h_ota) { + HAL_Free(h_ota); + } + + return NULL; + +#undef AOM_INFO_MSG_LEN +} + +/* Destroy OTA handle and resource */ +int IOT_OTA_Destroy(void *handle) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + + if (NULL == h_ota) { + Log_e("handle is NULL"); + return IOT_OTA_ERR_INVALID_PARAM; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + Log_e("handle is uninitialized"); + h_ota->err = IOT_OTA_ERR_INVALID_STATE; + return QCLOUD_ERR_FAILURE; + } + + qcloud_osc_deinit(h_ota->ch_signal); + qcloud_ofc_deinit(h_ota->ch_fetch); + qcloud_otalib_md5_deinit(h_ota->md5); + + if (NULL != h_ota->purl) { + HAL_Free(h_ota->purl); + h_ota->purl = NULL; + } + + if (NULL != h_ota->version) { + HAL_Free(h_ota->version); + h_ota->version = NULL; + } + + HAL_Free(h_ota); + return QCLOUD_RET_SUCCESS; +} + +/*support continuous transmission of breakpoints*/ +int IOT_OTA_StartDownload(void *handle, uint32_t offset, uint32_t size) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + int Ret; + + Log_d("to download FW from offset: %u, size: %u", offset, size); + h_ota->size_fetched = offset; + + // reset md5 for new download + if (offset == 0) { + Ret = IOT_OTA_ResetClientMD5(h_ota); + if (Ret) { + Log_e("initialize md5 failed"); + return QCLOUD_ERR_FAILURE; + } + } + + // reinit ofc + qcloud_ofc_deinit(h_ota->ch_fetch); + h_ota->ch_fetch = ofc_Init(h_ota->purl, offset, size); + if (NULL == h_ota->ch_fetch) { + Log_e("Initialize fetch module failed"); + return QCLOUD_ERR_FAILURE; + } + + Ret = qcloud_ofc_connect(h_ota->ch_fetch); + if (QCLOUD_RET_SUCCESS != Ret) { + Log_e("Connect fetch module failed"); + h_ota->state = IOT_OTAS_DISCONNECTED; + } + + return Ret; +} + +/*support continuous transmission of breakpoints*/ +void IOT_OTA_UpdateClientMd5(void *handle, char *buff, uint32_t size) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + + qcloud_otalib_md5_update(h_ota->md5, buff, size); +} + +/*support continuous transmission of breakpoints*/ +int IOT_OTA_ResetClientMD5(void *handle) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + + qcloud_otalib_md5_deinit(h_ota->md5); + h_ota->md5 = qcloud_otalib_md5_init(); + if (NULL == h_ota->md5) { + return QCLOUD_ERR_FAILURE; + } + + return QCLOUD_RET_SUCCESS; +} + +int IOT_OTA_ReportVersion(void *handle, const char *version) +{ +#define MSG_INFORM_LEN (128) + + int ret, len; + char * msg_informed; + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + + POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM); + POINTER_SANITY_CHECK(version, IOT_OTA_ERR_INVALID_PARAM); + + len = strlen(version); + if ((len < OTA_VERSION_STR_LEN_MIN) || (len > OTA_VERSION_STR_LEN_MAX)) { + Log_e("version string is invalid: must be [1, 32] chars"); + h_ota->err = IOT_OTA_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + Log_e("handle is uninitialized"); + h_ota->err = IOT_OTA_ERR_INVALID_STATE; + return QCLOUD_ERR_FAILURE; + } + + IOT_OTA_ResetStatus(h_ota); + + if (NULL == (msg_informed = HAL_Malloc(MSG_INFORM_LEN))) { + Log_e("allocate for msg_informed failed"); + h_ota->err = IOT_OTA_ERR_NOMEM; + return QCLOUD_ERR_FAILURE; + } + + ret = qcloud_otalib_gen_info_msg(msg_informed, MSG_INFORM_LEN, h_ota->id, version); + if (ret != 0) { + Log_e("generate inform message failed"); + h_ota->err = ret; + ret = QCLOUD_ERR_FAILURE; + goto do_exit; + } + + ret = qcloud_osc_report_version(h_ota->ch_signal, msg_informed); + if (0 > ret) { + Log_e("Report version failed"); + h_ota->err = ret; + ret = QCLOUD_ERR_FAILURE; + goto do_exit; + } + +do_exit: + if (NULL != msg_informed) { + HAL_Free(msg_informed); + } + return ret; + +#undef MSG_INFORM_LEN +} + +int IOT_OTA_ReportUpgradeBegin(void *handle) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + return IOT_OTA_ReportUpgradeResult(handle, h_ota->version, IOT_OTAR_UPGRADE_BEGIN); +} + +int IOT_OTA_ReportUpgradeSuccess(void *handle, const char *version) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + int ret; + + if (NULL == version) { + ret = IOT_OTA_ReportUpgradeResult(handle, h_ota->version, IOT_OTAR_UPGRADE_SUCCESS); + } else { + ret = IOT_OTA_ReportUpgradeResult(handle, version, IOT_OTAR_UPGRADE_SUCCESS); + } + + return ret; +} + +int IOT_OTA_ReportUpgradeFail(void *handle, const char *version) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + int ret; + + if (NULL == version) { + ret = IOT_OTA_ReportUpgradeResult(handle, h_ota->version, IOT_OTAR_UPGRADE_FAIL); + } else { + ret = IOT_OTA_ReportUpgradeResult(handle, version, IOT_OTAR_UPGRADE_FAIL); + } + + return ret; +} + +/* check whether is downloading */ +int IOT_OTA_IsFetching(void *handle) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + + if (NULL == handle) { + Log_e("handle is NULL"); + return 0; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + Log_e("handle is uninitialized"); + h_ota->err = IOT_OTA_ERR_INVALID_STATE; + return 0; + } + + return (IOT_OTAS_FETCHING == h_ota->state); +} + +/* check whether fetch over */ +int IOT_OTA_IsFetchFinish(void *handle) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + + if (NULL == handle) { + Log_e("handle is NULL"); + return 0; + } + + if (IOT_OTAS_UNINITED == h_ota->state) { + Log_e("handle is uninitialized"); + h_ota->err = IOT_OTA_ERR_INVALID_STATE; + return 0; + } + + return (IOT_OTAS_FETCHED == h_ota->state); +} + +int IOT_OTA_FetchYield(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_ms) +{ + int ret; + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + + POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM); + POINTER_SANITY_CHECK(buf, IOT_OTA_ERR_INVALID_PARAM); + NUMBERIC_SANITY_CHECK(buf_len, IOT_OTA_ERR_INVALID_PARAM); + + if (IOT_OTAS_FETCHING != h_ota->state) { + h_ota->err = IOT_OTA_ERR_INVALID_STATE; + return IOT_OTA_ERR_INVALID_STATE; + } + + ret = qcloud_ofc_fetch(h_ota->ch_fetch, buf, buf_len, timeout_ms); + if (ret < 0) { + h_ota->state = IOT_OTAS_FETCHED; + h_ota->err = IOT_OTA_ERR_FETCH_FAILED; + + if (ret == IOT_OTA_ERR_FETCH_AUTH_FAIL) { // OTA auth failed + IOT_OTA_ReportUpgradeResult(h_ota, h_ota->version, IOT_OTAR_AUTH_FAIL); + h_ota->err = ret; + } else if (ret == IOT_OTA_ERR_FETCH_NOT_EXIST) { // fetch not existed + IOT_OTA_ReportUpgradeResult(h_ota, h_ota->version, IOT_OTAR_FILE_NOT_EXIST); + h_ota->err = ret; + } else if (ret == IOT_OTA_ERR_FETCH_TIMEOUT) { // fetch timeout + IOT_OTA_ReportUpgradeResult(h_ota, h_ota->version, IOT_OTAR_DOWNLOAD_TIMEOUT); + h_ota->err = ret; + } + + return ret; + } else if (0 == h_ota->size_fetched) { + /* force report status in the first */ + IOT_OTA_ReportProgress(h_ota, IOT_OTAP_FETCH_PERCENTAGE_MIN, IOT_OTAR_DOWNLOAD_BEGIN); + + InitTimer(&h_ota->report_timer); + countdown(&h_ota->report_timer, 1); + } + + h_ota->size_last_fetched = ret; + h_ota->size_fetched += 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, IOT_OTAR_DOWNLOADING); + } else if (h_ota->size_last_fetched > 0 && expired(&h_ota->report_timer)) { + IOT_OTA_ReportProgress(h_ota, percent, IOT_OTAR_DOWNLOADING); + countdown(&h_ota->report_timer, 1); + } + + if (h_ota->size_fetched >= h_ota->size_file) { + h_ota->state = IOT_OTAS_FETCHED; + } + + qcloud_otalib_md5_update(h_ota->md5, buf, ret); + + 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_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM); + POINTER_SANITY_CHECK(buf, IOT_OTA_ERR_INVALID_PARAM); + NUMBERIC_SANITY_CHECK(buf_len, IOT_OTA_ERR_INVALID_PARAM); + + if (h_ota->state < IOT_OTAS_FETCHING) { + h_ota->err = IOT_OTA_ERR_INVALID_STATE; + return IOT_OTA_ERR_INVALID_STATE; + } + + switch (type) { + case IOT_OTAG_FETCHED_SIZE: + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + Log_e("Invalid parameter"); + h_ota->err = IOT_OTA_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } else { + *((uint32_t *)buf) = h_ota->size_fetched; + return 0; + } + + case IOT_OTAG_FILE_SIZE: + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + Log_e("Invalid parameter"); + h_ota->err = IOT_OTA_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } else { + *((uint32_t *)buf) = h_ota->size_file; + return 0; + } + + case IOT_OTAG_VERSION: + strncpy(buf, h_ota->version, buf_len); + ((char *)buf)[buf_len - 1] = '\0'; + break; + + case IOT_OTAG_MD5SUM: + strncpy(buf, h_ota->md5sum, buf_len); + ((char *)buf)[buf_len - 1] = '\0'; + break; + + case IOT_OTAG_CHECK_FIRMWARE: + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + Log_e("Invalid parameter"); + h_ota->err = IOT_OTA_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } else if (h_ota->state != IOT_OTAS_FETCHED) { + h_ota->err = IOT_OTA_ERR_INVALID_STATE; + Log_e("Firmware can be checked in IOT_OTAS_FETCHED state only"); + return QCLOUD_ERR_FAILURE; + } else { + char md5_str[33]; + qcloud_otalib_md5_finalize(h_ota->md5, md5_str); + Log_d("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; + // report MD5 inconsistent + IOT_OTA_ReportUpgradeResult(h_ota, h_ota->version, IOT_OTAR_MD5_NOT_MATCH); + } + return 0; + } + + default: + Log_e("invalid cmd type"); + h_ota->err = IOT_OTA_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } + + return 0; +} + +/* Get last error code */ +int IOT_OTA_GetLastError(void *handle) +{ + OTA_Struct_t *h_ota = (OTA_Struct_t *)handle; + + if (NULL == handle) { + Log_e("handle is NULL"); + return IOT_OTA_ERR_INVALID_PARAM; + } + + return h_ota->err; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_fetch.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_fetch.c new file mode 100644 index 00000000..f8e730c3 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_fetch.c @@ -0,0 +1,70 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ota_fetch.h" + +#include + +#include "qcloud_iot_ca.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_url_download.h" + +void *ofc_Init(const char *url, uint32_t offset, uint32_t size) +{ + return qcloud_url_download_init(url, offset, size); +} + +int32_t qcloud_ofc_connect(void *handle) +{ +#ifdef OTA_USE_HTTPS + return qcloud_url_download_connect(handle, 1); +#endif + return qcloud_url_download_connect(handle, 0); +} + +int32_t qcloud_ofc_fetch(void *handle, char *buf, uint32_t bufLen, uint32_t timeout_s) +{ + int rc = qcloud_url_download_fetch(handle, buf, bufLen, timeout_s); + if (QCLOUD_RET_SUCCESS != rc) { + if (rc == QCLOUD_ERR_HTTP_NOT_FOUND) + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FETCH_NOT_EXIST); + + if (rc == QCLOUD_ERR_HTTP_AUTH) + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FETCH_AUTH_FAIL); + + if (rc == QCLOUD_ERR_HTTP_TIMEOUT) + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FETCH_TIMEOUT); + } + IOT_FUNC_EXIT_RC(rc); +} + +int qcloud_ofc_deinit(void *handle) +{ + return qcloud_url_download_deinit(handle); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_lib.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_lib.c new file mode 100644 index 00000000..6033668c --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_lib.c @@ -0,0 +1,334 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ota_lib.h" + +#include +#include + +#include "lite-utils.h" +#include "ota_client.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_md5.h" + +/* Get the specific @key value, and copy to @dest */ +/* 0, successful; -1, failed */ +static int _qcloud_otalib_get_firmware_fixlen_para(const char *json_doc, const char *key, char *dest, size_t dest_len) +{ + IOT_FUNC_ENTRY; + + int ret = QCLOUD_RET_SUCCESS; + + char *key_bak = HAL_Malloc(strlen(key) + 1); + if (key_bak == NULL) { + Log_e("not enough memory for malloc key"); + ret = IOT_OTA_ERR_FAIL; + IOT_FUNC_EXIT_RC(ret); + } + + char *json_doc_bak = HAL_Malloc(strlen(json_doc) + 1); + if (json_doc_bak == NULL) { + Log_e("not enough memory for malloc json"); + HAL_Free(key_bak); + ret = IOT_OTA_ERR_FAIL; + IOT_FUNC_EXIT_RC(ret); + } + + strcpy(key_bak, key); + strcpy(json_doc_bak, json_doc); + + char *value = LITE_json_value_of(key_bak, json_doc_bak); + if (value == NULL) { + Log_e("Not '%s' key in json doc of OTA", STRING_PTR_PRINT_SANITY_CHECK(key)); + ret = IOT_OTA_ERR_FAIL; + } else { + uint32_t val_len = strlen(value); + if (val_len > dest_len) { + Log_e("value length of the key is too long"); + ret = IOT_OTA_ERR_FAIL; + } else { + memcpy(dest, value, val_len); + ret = QCLOUD_RET_SUCCESS; + } + + HAL_Free(value); + } + + if (key_bak != NULL) { + HAL_Free(key_bak); + } + if (json_doc_bak != NULL) { + HAL_Free(json_doc_bak); + } + + IOT_FUNC_EXIT_RC(ret); +} + +/* Get variant length parameter of firmware, and copy to @dest */ +/* 0, successful; -1, failed */ +static int _qcloud_otalib_get_firmware_varlen_para(const char *json_doc, const char *key, char **dest) +{ +#define OTA_FIRMWARE_JSON_VALUE_MAX_LENGTH (64) + + IOT_FUNC_ENTRY; + + int ret = QCLOUD_RET_SUCCESS; + + char *key_bak = HAL_Malloc(strlen(key) + 1); + if (key_bak == NULL) { + Log_e("not enough memory for malloc key"); + ret = IOT_OTA_ERR_FAIL; + IOT_FUNC_EXIT_RC(ret); + } + + char *json_doc_bak = HAL_Malloc(strlen(json_doc) + 1); + if (json_doc_bak == NULL) { + Log_e("not enough memory for malloc json"); + HAL_Free(key_bak); + ret = IOT_OTA_ERR_FAIL; + IOT_FUNC_EXIT_RC(ret); + } + + strcpy(key_bak, key); + strcpy(json_doc_bak, json_doc); + + *dest = LITE_json_value_of(key_bak, json_doc_bak); + if (*dest == NULL) { + Log_e("Not '%s' key in json '%s' doc of OTA", key_bak, json_doc_bak); + ret = IOT_OTA_ERR_FAIL; + } + + if (key_bak != NULL) { + HAL_Free(key_bak); + } + if (json_doc_bak != NULL) { + HAL_Free(json_doc_bak); + } + + IOT_FUNC_EXIT_RC(ret); + +#undef OTA_FIRMWARE_JSON_VALUE_MAX_LENGTH +} + +void *qcloud_otalib_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 qcloud_otalib_md5_update(void *md5, const char *buf, size_t buf_len) +{ + utils_md5_update(md5, (unsigned char *)buf, buf_len); +} + +void qcloud_otalib_md5_finalize(void *md5, char *output_str) +{ + int i; + unsigned char buf_out[16]; + utils_md5_finish(md5, buf_out); + + for (i = 0; i < 16; ++i) { + output_str[i * 2] = utils_hb2hex(buf_out[i] >> 4); + output_str[i * 2 + 1] = utils_hb2hex(buf_out[i]); + } + output_str[32] = '\0'; +} + +void qcloud_otalib_md5_deinit(void *md5) +{ + if (NULL != md5) { + HAL_Free(md5); + } +} + +int qcloud_otalib_get_firmware_type(const char *json, char **type) +{ + return _qcloud_otalib_get_firmware_varlen_para(json, TYPE_FIELD, type); +} + +int qcloud_otalib_get_report_version_result(const char *json) +{ + IOT_FUNC_ENTRY; + + char *result_code = NULL; + + int rc = _qcloud_otalib_get_firmware_varlen_para(json, RESULT_FIELD, &result_code); + if (rc != QCLOUD_RET_SUCCESS || strcmp(result_code, "0") != 0) { + if (NULL != result_code) + HAL_Free(result_code); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + } + + if (NULL != result_code) + HAL_Free(result_code); + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int qcloud_otalib_get_params(const char *json, char **type, char **url, char **version, char *md5, uint32_t *fileSize) +{ +#define OTA_FILESIZE_STR_LEN (16) + + IOT_FUNC_ENTRY; + + char file_size_str[OTA_FILESIZE_STR_LEN + 1] = {0}; + + /* get type */ + if (0 != _qcloud_otalib_get_firmware_varlen_para(json, TYPE_FIELD, type)) { + Log_e("get value of type key failed"); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + } + + /* get version */ + if (0 != _qcloud_otalib_get_firmware_varlen_para(json, VERSION_FIELD, version)) { + Log_e("get value of version key failed"); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + } + + /* get URL */ + if (0 != _qcloud_otalib_get_firmware_varlen_para(json, URL_FIELD, url)) { + Log_e("get value of url key failed"); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + } + + /* get md5 */ + if (0 != _qcloud_otalib_get_firmware_fixlen_para(json, MD5_FIELD, md5, 32)) { + Log_e("get value of md5 key failed"); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + } + + /* get file size */ + if (0 != _qcloud_otalib_get_firmware_fixlen_para(json, FILESIZE_FIELD, file_size_str, OTA_FILESIZE_STR_LEN)) { + Log_e("get value of size key failed"); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + } + + file_size_str[OTA_FILESIZE_STR_LEN] = '\0'; + *fileSize = atoi(file_size_str); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + +#undef OTA_FILESIZE_STR_LEN +} + +int qcloud_otalib_gen_info_msg(char *buf, size_t bufLen, uint32_t id, const char *version) +{ + IOT_FUNC_ENTRY; + + int ret; + ret = HAL_Snprintf(buf, bufLen, "{\"type\": \"report_version\", \"report\":{\"version\":\"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(version)); + + if (ret < 0) { + Log_e("HAL_Snprintf failed"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int qcloud_otalib_gen_report_msg(char *buf, size_t bufLen, uint32_t id, const char *version, int progress, + IOT_OTAReportType reportType) +{ + IOT_FUNC_ENTRY; + + int ret; + + switch (reportType) { + /* report OTA download begin */ + case IOT_OTAR_DOWNLOAD_BEGIN: + ret = HAL_Snprintf(buf, bufLen, + "{\"type\": \"report_progress\", \"report\": " + "{\"progress\": {\"state\":\"downloading\", " + "\"percent\":\"0\", \"result_code\":\"0\", " + "\"result_msg\":\"\"}, \"version\": \"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + /* report OTA download progress */ + case IOT_OTAR_DOWNLOADING: + ret = HAL_Snprintf(buf, bufLen, + "{\"type\": \"report_progress\", \"report\": " + "{\"progress\": {\"state\":\"downloading\", " + "\"percent\":\"%d\", \"result_code\":\"0\", " + "\"result_msg\":\"\"}, \"version\": \"%s\"}}", + progress, STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + case IOT_OTAR_DOWNLOAD_TIMEOUT: + case IOT_OTAR_FILE_NOT_EXIST: + case IOT_OTAR_MD5_NOT_MATCH: + case IOT_OTAR_AUTH_FAIL: + case IOT_OTAR_UPGRADE_FAIL: + ret = HAL_Snprintf(buf, bufLen, + "{\"type\": \"report_progress\", \"report\": " + "{\"progress\": {\"state\":\"fail\", " + "\"result_code\":\"%d\", \"result_msg\":\"time_out\"}, " + "\"version\": \"%s\"}}", + reportType, STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + /* report OTA upgrade begin */ + case IOT_OTAR_UPGRADE_BEGIN: + ret = HAL_Snprintf(buf, bufLen, + "{\"type\": \"report_progress\", " + "\"report\":{\"progress\":{\"state\":" + "\"burning\", \"result_code\":\"0\", " + "\"result_msg\":\"\"}, \"version\":\"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + + /* report OTA upgrade finish */ + case IOT_OTAR_UPGRADE_SUCCESS: + ret = HAL_Snprintf(buf, bufLen, + "{\"type\": \"report_progress\", " + "\"report\":{\"progress\":{\"state\":" + "\"done\", \"result_code\":\"0\", " + "\"result_msg\":\"\"}, \"version\":\"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + + default: + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + break; + } + + if (ret < 0) { + Log_e("HAL_Snprintf failed"); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + } else if (ret >= bufLen) { + Log_e("msg is too long"); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_STR_TOO_LONG); + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_mqtt.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_mqtt.c new file mode 100644 index 00000000..f313ee4e --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/ota_mqtt.c @@ -0,0 +1,249 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" + +#ifdef OTA_MQTT_CHANNEL + +#include + +#include "ota_client.h" + +/* OSC, OTA signal channel */ +typedef struct { + void *mqtt; // MQTT cient + + const char *product_id; + const char *device_name; + + char topic_upgrade[OTA_MAX_TOPIC_LEN]; // OTA MQTT Topic + OnOTAMessageCallback msg_callback; + + void *context; + bool topic_ready; +} OTA_MQTT_Struct_t; + +/* Generate topic name according to @OTATopicType, @productId, @deviceName */ +/* and then copy to @buf. */ +/* 0, successful; -1, failed */ +static int _otamqtt_gen_topic_name(char *buf, size_t bufLen, const char *OTATopicType, const char *productId, + const char *deviceName) +{ + IOT_FUNC_ENTRY; + + int ret; + + ret = HAL_Snprintf(buf, bufLen, "$ota/%s/%s/%s", STRING_PTR_PRINT_SANITY_CHECK(OTATopicType), + STRING_PTR_PRINT_SANITY_CHECK(productId), STRING_PTR_PRINT_SANITY_CHECK(deviceName)); + + if (ret >= bufLen) + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + + if (ret < 0) { + Log_e("HAL_Snprintf failed"); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +/* report progress of OTA */ +static int _otamqtt_publish(OTA_MQTT_Struct_t *handle, const char *topicType, int qos, const char *msg) +{ + IOT_FUNC_ENTRY; + + int ret; + char topic_name[OTA_MAX_TOPIC_LEN]; + PublishParams pub_params = DEFAULT_PUB_PARAMS; + + if (0 == qos) { + pub_params.qos = QOS0; + } else { + pub_params.qos = QOS1; + } + pub_params.payload = (void *)msg; + pub_params.payload_len = strlen(msg); + + /* inform OTA to topic: "/ota/device/progress/$(product_id)/$(device_name)" */ + ret = _otamqtt_gen_topic_name(topic_name, OTA_MAX_TOPIC_LEN, topicType, handle->product_id, handle->device_name); + if (ret < 0) { + Log_e("generate topic name of info failed"); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL); + } + + ret = IOT_MQTT_Publish(handle->mqtt, topic_name, &pub_params); + if (ret < 0) { + Log_e("publish to topic: %s failed", topic_name); + IOT_FUNC_EXIT_RC(IOT_OTA_ERR_OSC_FAILED); + } + + IOT_FUNC_EXIT_RC(ret); +} + +/* callback after OTA topic is subscribed */ +/* Parse firmware info (version/URL/file size/MD5) from JSON text */ +static void _otamqtt_upgrage_cb(void *pClient, MQTTMessage *message, void *pcontext) +{ + OTA_MQTT_Struct_t *handle = (OTA_MQTT_Struct_t *)pcontext; + + Log_d("topic=%.*s", message->topic_len, message->ptopic); + Log_i("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); + } +} + +static void _otamqtt_event_callback(void *pclient, MQTTEventType event_type, void *user_data) +{ + OTA_MQTT_Struct_t *h_osc = (OTA_MQTT_Struct_t *)user_data; + + switch (event_type) { + case MQTT_EVENT_SUBCRIBE_SUCCESS: + Log_d("OTA topic subscribe success"); + h_osc->topic_ready = true; + break; + + case MQTT_EVENT_SUBCRIBE_TIMEOUT: + Log_i("OTA topic subscribe timeout"); + h_osc->topic_ready = false; + break; + + case MQTT_EVENT_SUBCRIBE_NACK: + Log_i("OTA topic subscribe NACK"); + h_osc->topic_ready = false; + break; + case MQTT_EVENT_UNSUBSCRIBE: + Log_i("OTA topic has been unsubscribed"); + h_osc->topic_ready = false; + ; + break; + case MQTT_EVENT_CLIENT_DESTROY: + Log_i("mqtt client has been destroyed"); + h_osc->topic_ready = false; + ; + break; + default: + return; + } +} + +void *qcloud_osc_init(const char *productId, const char *deviceName, 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_e("allocate for h_osc failed"); + goto do_exit; + } + + memset(h_osc, 0, sizeof(OTA_MQTT_Struct_t)); + + /* subscribe the OTA topic: "$ota/update/$(product_id)/$(device_name)" */ + ret = _otamqtt_gen_topic_name(h_osc->topic_upgrade, OTA_MAX_TOPIC_LEN, "update", productId, deviceName); + if (ret < 0) { + Log_e("generate topic name of upgrade failed"); + goto do_exit; + } + + SubscribeParams sub_params = DEFAULT_SUB_PARAMS; + sub_params.on_message_handler = _otamqtt_upgrage_cb; + sub_params.on_sub_event_handler = _otamqtt_event_callback; + 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_e("ota mqtt subscribe failed!"); + goto do_exit; + } + + int wait_cnt = 10; + while (!h_osc->topic_ready && (wait_cnt > 0)) { + // wait for subscription result + IOT_MQTT_Yield(channel, 200); + wait_cnt--; + } + + if (wait_cnt == 0) { + Log_e("ota mqtt subscribe timeout!"); + goto do_exit; + } + + h_osc->mqtt = channel; + h_osc->product_id = productId; + h_osc->device_name = deviceName; + h_osc->msg_callback = callback; + h_osc->context = context; + + return h_osc; + +do_exit: + if (NULL != h_osc) { + HAL_Free(h_osc); + } + + return NULL; +} + +int qcloud_osc_deinit(void *handle) +{ + IOT_FUNC_ENTRY; + int ret = QCLOUD_RET_SUCCESS; + + if (NULL != handle) { + OTA_MQTT_Struct_t *h_osc = (OTA_MQTT_Struct_t *)handle; + ret = IOT_MQTT_Unsubscribe(h_osc->mqtt, h_osc->topic_upgrade); + HAL_Free(handle); + } + + IOT_FUNC_EXIT_RC(ret); +} + +/* report progress of OTA */ +int qcloud_osc_report_progress(void *handle, const char *msg) +{ + return _otamqtt_publish(handle, "report", QOS0, msg); +} + +/* report version of OTA firmware */ +int qcloud_osc_report_version(void *handle, const char *msg) +{ + return _otamqtt_publish(handle, "report", QOS1, msg); +} + +/* report upgrade begin of OTA firmware */ +int qcloud_osc_report_upgrade_result(void *handle, const char *msg) +{ + return _otamqtt_publish(handle, "report", QOS1, msg); +} + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qcloud_iot_ca.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qcloud_iot_ca.c new file mode 100644 index 00000000..cb96e3dc --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qcloud_iot_ca.c @@ -0,0 +1,227 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qcloud_iot_ca.h" + +#include + +#include "qcloud_iot_common.h" +#include "qcloud_iot_import.h" + +typedef struct _RegionDomain_ { + const char *region; + const char *domain; +} RegionDomain; + +/*mqtt domain*/ +static RegionDomain sg_iot_mqtt_domain[] = { + {.region = "china", .domain = QCLOUD_IOT_MQTT_DIRECT_DOMAIN}, /* China */ + {.region = "us-east", .domain = QCLOUD_IOT_MQTT_US_EAST_DOMAIN}, /* Eastern US*/ +}; + +/*dynreg domain*/ +static RegionDomain sg_iot_dyn_reg_domain[] = { + {.region = "china", .domain = DYN_REG_SERVER_URL}, /* China */ + {.region = "us-east", .domain = DYN_REG_SERVER_US_EAST_URL}, /* Eastern US*/ +}; + +/*log domain*/ +static RegionDomain sg_iot_log_domain[] = { + {.region = "china", .domain = LOG_UPLOAD_SERVER_DOMAIN}, /* China */ + {.region = "us-east", .domain = LOG_UPLOAD_SERVER_US_EAST_DOMAIN}, /* Eastern US*/ +}; + +#ifndef AUTH_WITH_NOTLS +static const char *iot_ca_crt = { + "-----BEGIN CERTIFICATE-----\r\n" + "MIIDxTCCAq2gAwIBAgIJALM1winYO2xzMA0GCSqGSIb3DQEBCwUAMHkxCzAJBgNV\r\n" + "BAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxETAPBgNVBAcMCFNoZW5aaGVuMRAw\r\n" + "DgYDVQQKDAdUZW5jZW50MRcwFQYDVQQLDA5UZW5jZW50IElvdGh1YjEYMBYGA1UE\r\n" + "AwwPd3d3LnRlbmNlbnQuY29tMB4XDTE3MTEyNzA0MjA1OVoXDTMyMTEyMzA0MjA1\r\n" + "OVoweTELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nRG9uZzERMA8GA1UEBwwI\r\n" + "U2hlblpoZW4xEDAOBgNVBAoMB1RlbmNlbnQxFzAVBgNVBAsMDlRlbmNlbnQgSW90\r\n" + "aHViMRgwFgYDVQQDDA93d3cudGVuY2VudC5jb20wggEiMA0GCSqGSIb3DQEBAQUA\r\n" + "A4IBDwAwggEKAoIBAQDVxwDZRVkU5WexneBEkdaKs4ehgQbzpbufrWo5Lb5gJ3i0\r\n" + "eukbOB81yAaavb23oiNta4gmMTq2F6/hAFsRv4J2bdTs5SxwEYbiYU1teGHuUQHO\r\n" + "iQsZCdNTJgcikga9JYKWcBjFEnAxKycNsmqsq4AJ0CEyZbo//IYX3czEQtYWHjp7\r\n" + "FJOlPPd1idKtFMVNG6LGXEwS/TPElE+grYOxwB7Anx3iC5ZpE5lo5tTioFTHzqbT\r\n" + "qTN7rbFZRytAPk/JXMTLgO55fldm4JZTP3GQsPzwIh4wNNKhi4yWG1o2u3hAnZDv\r\n" + "UVFV7al2zFdOfuu0KMzuLzrWrK16SPadRDd9eT17AgMBAAGjUDBOMB0GA1UdDgQW\r\n" + "BBQrr48jv4FxdKs3r0BkmJO7zH4ALzAfBgNVHSMEGDAWgBQrr48jv4FxdKs3r0Bk\r\n" + "mJO7zH4ALzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDRSjXnBc3T\r\n" + "d9VmtTCuALXrQELY8KtM+cXYYNgtodHsxmrRMpJofsPGiqPfb82klvswpXxPK8Xx\r\n" + "SuUUo74Fo+AEyJxMrRKlbJvlEtnpSilKmG6rO9+bFq3nbeOAfat4lPl0DIscWUx3\r\n" + "ajXtvMCcSwTlF8rPgXbOaSXZidRYNqSyUjC2Q4m93Cv+KlyB+FgOke8x4aKAkf5p\r\n" + "XR8i1BN1OiMTIRYhGSfeZbVRq5kTdvtahiWFZu9DGO+hxDZObYGIxGHWPftrhBKz\r\n" + "RT16Amn780rQLWojr70q7o7QP5tO0wDPfCdFSc6CQFq/ngOzYag0kJ2F+O5U6+kS\r\n" + "QVrcRBDxzx/G\r\n" + "-----END CERTIFICATE-----"}; + +#ifdef OTA_USE_HTTPS + +static const char *iot_https_ca_crt = { + "-----BEGIN CERTIFICATE-----\r\n" + "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" + "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" + "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" + "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" + "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" + "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" + "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" + "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" + "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" + "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" + "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" + "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" + "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" + "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" + "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" + "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" + "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" + "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" + "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" + "-----END CERTIFICATE-----\r\n" + "-----BEGIN CERTIFICATE-----\r\n" + "MIIEaTCCA1GgAwIBAgILBAAAAAABRE7wQkcwDQYJKoZIhvcNAQELBQAwVzELMAkG\r\n" + "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" + "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw\r\n" + "MDBaFw0yNDAyMjAxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" + "YWxTaWduIG52LXNhMTwwOgYDVQQDEzNHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBW\r\n" + "YWxpZGF0aW9uIENBIC0gU0hBMjU2IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB\r\n" + "DwAwggEKAoIBAQDHDmw/I5N/zHClnSDDDlM/fsBOwphJykfVI+8DNIV0yKMCLkZc\r\n" + "C33JiJ1Pi/D4nGyMVTXbv/Kz6vvjVudKRtkTIso21ZvBqOOWQ5PyDLzm+ebomchj\r\n" + "SHh/VzZpGhkdWtHUfcKc1H/hgBKueuqI6lfYygoKOhJJomIZeg0k9zfrtHOSewUj\r\n" + "mxK1zusp36QUArkBpdSmnENkiN74fv7j9R7l/tyjqORmMdlMJekYuYlZCa7pnRxt\r\n" + "Nw9KHjUgKOKv1CGLAcRFrW4rY6uSa2EKTSDtc7p8zv4WtdufgPDWi2zZCHlKT3hl\r\n" + "2pK8vjX5s8T5J4BO/5ZS5gIg4Qdz6V0rvbLxAgMBAAGjggElMIIBITAOBgNVHQ8B\r\n" + "Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUlt5h8b0cFilT\r\n" + "HMDMfTuDAEDmGnwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0\r\n" + "dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMDMGA1UdHwQsMCow\r\n" + "KKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwPQYIKwYB\r\n" + "BQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNv\r\n" + "bS9yb290cjEwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZI\r\n" + "hvcNAQELBQADggEBAEYq7l69rgFgNzERhnF0tkZJyBAW/i9iIxerH4f4gu3K3w4s\r\n" + "32R1juUYcqeMOovJrKV3UPfvnqTgoI8UV6MqX+x+bRDmuo2wCId2Dkyy2VG7EQLy\r\n" + "XN0cvfNVlg/UBsD84iOKJHDTu/B5GqdhcIOKrwbFINihY9Bsrk8y1658GEV1BSl3\r\n" + "30JAZGSGvip2CTFvHST0mdCF/vIhCPnG9vHQWe3WVjwIKANnuvD58ZAWR65n5ryA\r\n" + "SOlCdjSXVWkkDoPWoC209fN5ikkodBpBocLTJIg1MGCUF7ThBCIxPTsvFwayuJ2G\r\n" + "K1pp74P1S8SqtCr4fKGxhZSM9AyHDPSsQPhZSZg=\r\n" + "-----END CERTIFICATE-----"}; +#endif + +#endif + +const char *iot_ca_get() +{ +#ifndef AUTH_WITH_NOTLS + return iot_ca_crt; +#else + return NULL; +#endif +} + +const char *iot_https_ca_get() +{ +#if ((!defined(AUTH_WITH_NOTLS)) && (defined OTA_USE_HTTPS)) + return iot_https_ca_crt; +#else + return NULL; +#endif +} + +const char *iot_get_mqtt_domain(const char *region) +{ + const char *pDomain = NULL; + int i; + + if (!region) { + goto end; + } + + for (i = 0; i < sizeof(sg_iot_mqtt_domain) / sizeof(sg_iot_mqtt_domain[0]); i++) { + if (0 == strcmp(region, sg_iot_mqtt_domain[i].region)) { + pDomain = sg_iot_mqtt_domain[i].domain; + break; + } + } + +end: + if (!pDomain) { + pDomain = sg_iot_mqtt_domain[0].domain; + } + + return pDomain; +} + +const char *iot_get_dyn_reg_domain(const char *region) +{ + const char *pDomain = NULL; + int i; + + if (!region) { + goto end; + } + + for (i = 0; i < sizeof(sg_iot_dyn_reg_domain) / sizeof(sg_iot_dyn_reg_domain[0]); i++) { + if (0 == strcmp(region, sg_iot_dyn_reg_domain[i].region)) { + pDomain = sg_iot_dyn_reg_domain[i].domain; + break; + } + } + +end: + if (!pDomain) { + pDomain = sg_iot_dyn_reg_domain[0].domain; + } + + return pDomain; +} + +const char *iot_get_log_domain(const char *region) +{ + const char *pDomain = NULL; + int i; + + if (!region) { + goto end; + } + + for (i = 0; i < sizeof(sg_iot_log_domain) / sizeof(sg_iot_log_domain[0]); i++) { + if (0 == strcmp(region, sg_iot_log_domain[i].region)) { + pDomain = sg_iot_log_domain[i].domain; + break; + } + } + +end: + if (!pDomain) { + pDomain = sg_iot_log_domain[0].domain; + } + + return pDomain; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qcloud_iot_device.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qcloud_iot_device.c new file mode 100644 index 00000000..3a00c9df --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qcloud_iot_device.c @@ -0,0 +1,62 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif +#include "qcloud_iot_device.h" + +#include +#include + +#include "qcloud_iot_export.h" + +int iot_device_info_set(DeviceInfo *device_info, const char *product_id, const char *device_name) +{ + memset(device_info, 0x0, sizeof(DeviceInfo)); + if ((MAX_SIZE_OF_PRODUCT_ID) < strlen(product_id)) { + Log_e("product name(%s) length:(%lu) exceeding limitation", product_id, strlen(product_id)); + return QCLOUD_ERR_FAILURE; + } + if ((MAX_SIZE_OF_DEVICE_NAME) < strlen(device_name)) { + Log_e("device name(%s) length:(%lu) exceeding limitation", device_name, strlen(device_name)); + return QCLOUD_ERR_FAILURE; + } + + strncpy(device_info->product_id, product_id, MAX_SIZE_OF_PRODUCT_ID); + strncpy(device_info->device_name, device_name, MAX_SIZE_OF_DEVICE_NAME); + + /* construct device-id(@product_id+@device_name) */ + memset(device_info->client_id, 0x0, MAX_SIZE_OF_CLIENT_ID); + int ret = HAL_Snprintf(device_info->client_id, MAX_SIZE_OF_CLIENT_ID, "%s%s", + STRING_PTR_PRINT_SANITY_CHECK(product_id), STRING_PTR_PRINT_SANITY_CHECK(device_name)); + if ((ret < 0) || (ret >= MAX_SIZE_OF_CLIENT_ID)) { + Log_e("set device info failed"); + return QCLOUD_ERR_FAILURE; + } + + Log_i("SDK_Ver: %s, Product_ID: %s, Device_Name: %s", QCLOUD_IOT_DEVICE_SDK_VERSION, device_info->product_id, + device_info->device_name); + return QCLOUD_RET_SUCCESS; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qcloud_iot_log.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qcloud_iot_log.c new file mode 100644 index 00000000..88a2dffc --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qcloud_iot_log.c @@ -0,0 +1,161 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights + reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "log_upload.h" +#include "qcloud_iot_export_log.h" +#include "qcloud_iot_import.h" + +static char *level_str[] = {"DIS", "ERR", "WRN", "INF", "DBG"}; + +static LogMessageHandler sg_log_message_handler = NULL; + +LOG_LEVEL g_log_print_level = eLOG_INFO; + +#ifdef LOG_UPLOAD +LOG_LEVEL g_log_upload_level = eLOG_ERROR; +#else +LOG_LEVEL g_log_upload_level = eLOG_DISABLE; +#endif + +static const char *_get_filename(const char *p) +{ +#ifdef WIN32 + char ch = '\\'; +#else + char ch = '/'; +#endif + const char *q = strrchr(p, ch); + if (q == NULL) { + q = p; + } else { + q++; + } + return q; +} + +void IOT_Log_Set_Level(LOG_LEVEL logLevel) +{ + g_log_print_level = logLevel; +} + +LOG_LEVEL IOT_Log_Get_Level(void) +{ + return g_log_print_level; +} + +void IOT_Log_Set_MessageHandler(LogMessageHandler handler) +{ + sg_log_message_handler = handler; +} + +void IOT_Log_Set_Upload_Level(LOG_LEVEL logLevel) +{ + g_log_upload_level = logLevel; +} + +LOG_LEVEL IOT_Log_Get_Upload_Level(void) +{ + return g_log_upload_level; +} + +int IOT_Log_Init_Uploader(LogUploadInitParams *init_params) +{ +#ifdef LOG_UPLOAD + return init_log_uploader(init_params); +#else + return 0; +#endif +} + +void IOT_Log_Fini_Uploader(void) +{ +#ifdef LOG_UPLOAD + fini_log_uploader(); + return; +#else + return; +#endif +} + +int IOT_Log_Upload(bool force_upload) +{ +#ifdef LOG_UPLOAD + return do_log_upload(force_upload); +#else + return 0; +#endif +} + +void IOT_Log_Gen(const char *file, const char *func, const int line, const int level, const char *fmt, ...) +{ + if (level > g_log_print_level && level > g_log_upload_level) { + return; + } + + /* format log content */ + const char *file_name = _get_filename(file); + + char sg_text_buf[MAX_LOG_MSG_LEN + 1]; + char *tmp_buf = sg_text_buf; + char *o = tmp_buf; + memset(tmp_buf, 0, sizeof(sg_text_buf)); + char time_str[TIME_FORMAT_STR_LEN] = {0}; + + o += HAL_Snprintf(o, sizeof(sg_text_buf), "%s|%s|%s|%s(%d): ", level_str[level], + STRING_PTR_PRINT_SANITY_CHECK(HAL_Timer_current(time_str)), + STRING_PTR_PRINT_SANITY_CHECK(file_name), STRING_PTR_PRINT_SANITY_CHECK(func), line); + + va_list ap; + va_start(ap, fmt); + HAL_Vsnprintf(o, MAX_LOG_MSG_LEN - 2 - strlen(tmp_buf), fmt, ap); + va_end(ap); + + strcat(tmp_buf, "\r\n"); + +#ifdef LOG_UPLOAD + /* append to upload buffer */ + if (level <= g_log_upload_level) { + append_to_upload_buffer(tmp_buf, strlen(tmp_buf)); + } +#endif + + if (level <= g_log_print_level) { + /* customer defined log print handler */ + if (sg_log_message_handler != NULL && sg_log_message_handler(tmp_buf)) { + return; + } + + /* default log handler: print to console */ + HAL_Printf("%s", tmp_buf); + } + + return; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qstring_utils.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qstring_utils.c new file mode 100644 index 00000000..f36c9912 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qstring_utils.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2017-2019 Tencent Group. All rights reserved. + * License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/** + * Edit by shockcao@tencent.com 2018/3/15 + */ + +#include "lite-utils.h" +#include "qcloud_iot_export_log.h" +#include "qcloud_iot_import.h" + +char *LITE_format_string(const char *fmt, ...) +{ +#define TEMP_STRING_MAXLEN (512) + + va_list ap; + char * tmp = NULL; + char * dst; + int rc = -1; + + va_start(ap, fmt); + tmp = HAL_Malloc(TEMP_STRING_MAXLEN); + memset(tmp, 0, TEMP_STRING_MAXLEN); + rc = HAL_Vsnprintf(tmp, TEMP_STRING_MAXLEN, fmt, ap); + va_end(ap); + LITE_ASSERT(tmp); + LITE_ASSERT(rc < 1024); + + dst = LITE_strdup(tmp); + HAL_Free(tmp); + + return dst; + +#undef TEMP_STRING_MAXLEN +} + +char *LITE_format_nstring(const int len, const char *fmt, ...) +{ + va_list ap; + char * tmp = NULL; + char * dst; + int rc = -1; + + va_start(ap, fmt); + tmp = HAL_Malloc(len + 2); + if (NULL == tmp) { + return NULL; + } + memset(tmp, 0, len + 2); + rc = HAL_Vsnprintf(tmp, len + 1, fmt, ap); + va_end(ap); + LITE_ASSERT(tmp); + LITE_ASSERT(rc < 1024); + + dst = HAL_Malloc(len + 1); + if (NULL != dst) { + HAL_Snprintf(dst, (len + 1), "%s", tmp); + } + + HAL_Free(tmp); + + return dst; +} + +char *LITE_strdup(const char *src) +{ + int len = 0; + char *dst = NULL; + + if (!src) { + return NULL; + } + len = strlen(src) + 1; + if (len > 1024) { + Log_e("Too long string to duplicate, abort! len = %d", len); + return NULL; + } + + dst = (char *)HAL_Malloc(sizeof(char) * len); + if (!dst) { + return NULL; + } + strncpy(dst, src, len); + + return dst; +} + +void LITE_hexbuf_convert(unsigned char *digest, char *out, int in_len, int uppercase) +{ + static char *zEncode[] = {"0123456789abcdef", "0123456789ABCDEF"}; + int j = 0; + int i = 0; + int idx = uppercase ? 1 : 0; + + for (i = 0; i < in_len; i++) { + int a = digest[i]; + + out[j++] = zEncode[idx][(a >> 4) & 0xf]; + out[j++] = zEncode[idx][a & 0xf]; + } +} + +static uint8_t _hexval_of_char(char hex) +{ + if (LITE_isdigit(hex)) { + return (hex - '0'); + } + if (hex >= 'a' && hex <= 'f') { + return (hex - 'a' + 10); + } + if (hex >= 'A' && hex <= 'F') { + return (hex - 'A' + 10); + } + + return 0; +} + +void LITE_hexstr_convert(char *hexstr, uint8_t *out_buf, int in_len) +{ + int i = 0; + uint8_t ch0, ch1; + + if (in_len % 2 != 0) { + Log_e("hexstr length (%d) is not even", in_len); + return; + } + + while (i < in_len / 2) { + ch0 = _hexval_of_char((char)hexstr[2 * i]); + ch1 = _hexval_of_char((char)hexstr[2 * i + 1]); + out_buf[i] = (ch0 << 4 | ch1); + i++; + } +} + +void LITE_replace_substr(char originalString[], char key[], char swap[]) +{ + int lengthOfOriginalString, lengthOfKey, lengthOfSwap, i, j, flag; + char tmp[512]; + + lengthOfOriginalString = strlen(originalString); + lengthOfKey = strlen(key); + lengthOfSwap = strlen(swap); + + for (i = 0; i <= lengthOfOriginalString - lengthOfKey; i++) { + flag = 1; + for (j = 0; j < lengthOfKey; j++) { + if (originalString[i + j] != key[j]) { + flag = 0; + break; + } + } + + if (flag) { + strcpy(tmp, originalString); + strcpy(&tmp[i], swap); + strcpy(&tmp[i + lengthOfSwap], &originalString[i + lengthOfKey]); + strcpy(originalString, tmp); + i += lengthOfSwap - 1; + lengthOfOriginalString = strlen(originalString); + } + } +} + +void LITE_str_strip_char(char *src, char destCh) +{ + char *end = src + strlen(src) + 1; + + while (*src != '\0') { + if (*src == destCh) { + memmove(src, src + 1, end - src); + end--; + } + src++; + } +} diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_aes.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_aes.c new file mode 100644 index 00000000..3180ecad --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_aes.c @@ -0,0 +1,1343 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif +#include "qutils_aes.h" + +#include +#include + +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" + +#if defined(UTILS_AES_C) + +#include + +#if defined(UTILS_SELF_TEST) +#include +#define utils_printf Log_d +#endif /* UTILS_SELF_TEST */ + +//====================================// +#if !defined(UTILS_PLATFORM_ZEROIZE_ALT) +/* + * This implementation should never be optimized out by the compiler + * + * This implementation for utils_platform_zeroize() was inspired from Colin + * Percival's blog article at: + * + * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html + * + * It uses a volatile function pointer to the standard memset(). Because the + * pointer is volatile the compiler expects it to change at + * any time and will not optimize out the call that could potentially perform + * other operations on the input buffer instead of just setting it to 0. + * Nevertheless, as pointed out by davidtgoldblatt on Hacker News + * (refer to http://www.daemonology.net/blog/2014-09-05-erratum.html for + * details), optimizations of the following form are still possible: + * + * if( memset_func != memset ) + * memset_func( buf, 0, len ); + * + * Note that it is extremely difficult to guarantee that + * utils_platform_zeroize() will not be optimized out by aggressive compilers + * in a portable way. For this reason, Mbed TLS also provides the configuration + * option UTILS_PLATFORM_ZEROIZE_ALT, which allows users to configure + * utils_platform_zeroize() to use a suitable implementation for their + * platform and needs. + */ +static void *(*const volatile memset_func)(void *, int, size_t) = memset; + +void utils_platform_zeroize(void *buf, size_t len) +{ + memset_func(buf, 0, len); +} +#endif /* UTILS_PLATFORM_ZEROIZE_ALT */ + +//====================================// + +#if !defined(UTILS_AES_ALT) + +/* Parameter validation macros based on platform_util.h */ +#define AES_VALIDATE_RET(cond) UTILS_INTERNAL_VALIDATE_RET(cond, UTILS_ERR_AES_BAD_INPUT_DATA) +#define AES_VALIDATE(cond) UTILS_INTERNAL_VALIDATE(cond) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n, b, i) \ + \ + { \ + (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) | \ + ((uint32_t)(b)[(i) + 3] << 24); \ + } +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n, b, i) \ + \ + { \ + (b)[(i)] = (unsigned char)(((n)) & 0xFF); \ + (b)[(i) + 1] = (unsigned char)(((n) >> 8) & 0xFF); \ + (b)[(i) + 2] = (unsigned char)(((n) >> 16) & 0xFF); \ + (b)[(i) + 3] = (unsigned char)(((n) >> 24) & 0xFF); \ + } +#endif + +#if defined(UTILS_PADLOCK_C) && (defined(UTILS_HAVE_X86) || defined(UTILS_PADLOCK_ALIGN16)) +static int aes_padlock_ace = -1; +#endif + +#if defined(UTILS_AES_ROM_TABLES) +/* + * Forward S-box + */ +static const unsigned char FSb[256] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, + 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, + 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, + 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, + 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, + 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, + 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, + 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, + 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, + 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, + 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, + 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, + 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16}; + +/* + * Forward tables + */ +#define FT \ + \ + V(A5, 63, 63, C6) \ + , V(84, 7C, 7C, F8), V(99, 77, 77, EE), V(8D, 7B, 7B, F6), V(0D, F2, F2, FF), V(BD, 6B, 6B, D6), \ + V(B1, 6F, 6F, DE), V(54, C5, C5, 91), V(50, 30, 30, 60), V(03, 01, 01, 02), V(A9, 67, 67, CE), \ + V(7D, 2B, 2B, 56), V(19, FE, FE, E7), V(62, D7, D7, B5), V(E6, AB, AB, 4D), V(9A, 76, 76, EC), \ + V(45, CA, CA, 8F), V(9D, 82, 82, 1F), V(40, C9, C9, 89), V(87, 7D, 7D, FA), V(15, FA, FA, EF), \ + V(EB, 59, 59, B2), V(C9, 47, 47, 8E), V(0B, F0, F0, FB), V(EC, AD, AD, 41), V(67, D4, D4, B3), \ + V(FD, A2, A2, 5F), V(EA, AF, AF, 45), V(BF, 9C, 9C, 23), V(F7, A4, A4, 53), V(96, 72, 72, E4), \ + V(5B, C0, C0, 9B), V(C2, B7, B7, 75), V(1C, FD, FD, E1), V(AE, 93, 93, 3D), V(6A, 26, 26, 4C), \ + V(5A, 36, 36, 6C), V(41, 3F, 3F, 7E), V(02, F7, F7, F5), V(4F, CC, CC, 83), V(5C, 34, 34, 68), \ + V(F4, A5, A5, 51), V(34, E5, E5, D1), V(08, F1, F1, F9), V(93, 71, 71, E2), V(73, D8, D8, AB), \ + V(53, 31, 31, 62), V(3F, 15, 15, 2A), V(0C, 04, 04, 08), V(52, C7, C7, 95), V(65, 23, 23, 46), \ + V(5E, C3, C3, 9D), V(28, 18, 18, 30), V(A1, 96, 96, 37), V(0F, 05, 05, 0A), V(B5, 9A, 9A, 2F), \ + V(09, 07, 07, 0E), V(36, 12, 12, 24), V(9B, 80, 80, 1B), V(3D, E2, E2, DF), V(26, EB, EB, CD), \ + V(69, 27, 27, 4E), V(CD, B2, B2, 7F), V(9F, 75, 75, EA), V(1B, 09, 09, 12), V(9E, 83, 83, 1D), \ + V(74, 2C, 2C, 58), V(2E, 1A, 1A, 34), V(2D, 1B, 1B, 36), V(B2, 6E, 6E, DC), V(EE, 5A, 5A, B4), \ + V(FB, A0, A0, 5B), V(F6, 52, 52, A4), V(4D, 3B, 3B, 76), V(61, D6, D6, B7), V(CE, B3, B3, 7D), \ + V(7B, 29, 29, 52), V(3E, E3, E3, DD), V(71, 2F, 2F, 5E), V(97, 84, 84, 13), V(F5, 53, 53, A6), \ + V(68, D1, D1, B9), V(00, 00, 00, 00), V(2C, ED, ED, C1), V(60, 20, 20, 40), V(1F, FC, FC, E3), \ + V(C8, B1, B1, 79), V(ED, 5B, 5B, B6), V(BE, 6A, 6A, D4), V(46, CB, CB, 8D), V(D9, BE, BE, 67), \ + V(4B, 39, 39, 72), V(DE, 4A, 4A, 94), V(D4, 4C, 4C, 98), V(E8, 58, 58, B0), V(4A, CF, CF, 85), \ + V(6B, D0, D0, BB), V(2A, EF, EF, C5), V(E5, AA, AA, 4F), V(16, FB, FB, ED), V(C5, 43, 43, 86), \ + V(D7, 4D, 4D, 9A), V(55, 33, 33, 66), V(94, 85, 85, 11), V(CF, 45, 45, 8A), V(10, F9, F9, E9), \ + V(06, 02, 02, 04), V(81, 7F, 7F, FE), V(F0, 50, 50, A0), V(44, 3C, 3C, 78), V(BA, 9F, 9F, 25), \ + V(E3, A8, A8, 4B), V(F3, 51, 51, A2), V(FE, A3, A3, 5D), V(C0, 40, 40, 80), V(8A, 8F, 8F, 05), \ + V(AD, 92, 92, 3F), V(BC, 9D, 9D, 21), V(48, 38, 38, 70), V(04, F5, F5, F1), V(DF, BC, BC, 63), \ + V(C1, B6, B6, 77), V(75, DA, DA, AF), V(63, 21, 21, 42), V(30, 10, 10, 20), V(1A, FF, FF, E5), \ + V(0E, F3, F3, FD), V(6D, D2, D2, BF), V(4C, CD, CD, 81), V(14, 0C, 0C, 18), V(35, 13, 13, 26), \ + V(2F, EC, EC, C3), V(E1, 5F, 5F, BE), V(A2, 97, 97, 35), V(CC, 44, 44, 88), V(39, 17, 17, 2E), \ + V(57, C4, C4, 93), V(F2, A7, A7, 55), V(82, 7E, 7E, FC), V(47, 3D, 3D, 7A), V(AC, 64, 64, C8), \ + V(E7, 5D, 5D, BA), V(2B, 19, 19, 32), V(95, 73, 73, E6), V(A0, 60, 60, C0), V(98, 81, 81, 19), \ + V(D1, 4F, 4F, 9E), V(7F, DC, DC, A3), V(66, 22, 22, 44), V(7E, 2A, 2A, 54), V(AB, 90, 90, 3B), \ + V(83, 88, 88, 0B), V(CA, 46, 46, 8C), V(29, EE, EE, C7), V(D3, B8, B8, 6B), V(3C, 14, 14, 28), \ + V(79, DE, DE, A7), V(E2, 5E, 5E, BC), V(1D, 0B, 0B, 16), V(76, DB, DB, AD), V(3B, E0, E0, DB), \ + V(56, 32, 32, 64), V(4E, 3A, 3A, 74), V(1E, 0A, 0A, 14), V(DB, 49, 49, 92), V(0A, 06, 06, 0C), \ + V(6C, 24, 24, 48), V(E4, 5C, 5C, B8), V(5D, C2, C2, 9F), V(6E, D3, D3, BD), V(EF, AC, AC, 43), \ + V(A6, 62, 62, C4), V(A8, 91, 91, 39), V(A4, 95, 95, 31), V(37, E4, E4, D3), V(8B, 79, 79, F2), \ + V(32, E7, E7, D5), V(43, C8, C8, 8B), V(59, 37, 37, 6E), V(B7, 6D, 6D, DA), V(8C, 8D, 8D, 01), \ + V(64, D5, D5, B1), V(D2, 4E, 4E, 9C), V(E0, A9, A9, 49), V(B4, 6C, 6C, D8), V(FA, 56, 56, AC), \ + V(07, F4, F4, F3), V(25, EA, EA, CF), V(AF, 65, 65, CA), V(8E, 7A, 7A, F4), V(E9, AE, AE, 47), \ + V(18, 08, 08, 10), V(D5, BA, BA, 6F), V(88, 78, 78, F0), V(6F, 25, 25, 4A), V(72, 2E, 2E, 5C), \ + V(24, 1C, 1C, 38), V(F1, A6, A6, 57), V(C7, B4, B4, 73), V(51, C6, C6, 97), V(23, E8, E8, CB), \ + V(7C, DD, DD, A1), V(9C, 74, 74, E8), V(21, 1F, 1F, 3E), V(DD, 4B, 4B, 96), V(DC, BD, BD, 61), \ + V(86, 8B, 8B, 0D), V(85, 8A, 8A, 0F), V(90, 70, 70, E0), V(42, 3E, 3E, 7C), V(C4, B5, B5, 71), \ + V(AA, 66, 66, CC), V(D8, 48, 48, 90), V(05, 03, 03, 06), V(01, F6, F6, F7), V(12, 0E, 0E, 1C), \ + V(A3, 61, 61, C2), V(5F, 35, 35, 6A), V(F9, 57, 57, AE), V(D0, B9, B9, 69), V(91, 86, 86, 17), \ + V(58, C1, C1, 99), V(27, 1D, 1D, 3A), V(B9, 9E, 9E, 27), V(38, E1, E1, D9), V(13, F8, F8, EB), \ + V(B3, 98, 98, 2B), V(33, 11, 11, 22), V(BB, 69, 69, D2), V(70, D9, D9, A9), V(89, 8E, 8E, 07), \ + V(A7, 94, 94, 33), V(B6, 9B, 9B, 2D), V(22, 1E, 1E, 3C), V(92, 87, 87, 15), V(20, E9, E9, C9), \ + V(49, CE, CE, 87), V(FF, 55, 55, AA), V(78, 28, 28, 50), V(7A, DF, DF, A5), V(8F, 8C, 8C, 03), \ + V(F8, A1, A1, 59), V(80, 89, 89, 09), V(17, 0D, 0D, 1A), V(DA, BF, BF, 65), V(31, E6, E6, D7), \ + V(C6, 42, 42, 84), V(B8, 68, 68, D0), V(C3, 41, 41, 82), V(B0, 99, 99, 29), V(77, 2D, 2D, 5A), \ + V(11, 0F, 0F, 1E), V(CB, B0, B0, 7B), V(FC, 54, 54, A8), V(D6, BB, BB, 6D), V(3A, 16, 16, 2C) + +#define V(a, b, c, d) 0x##a##b##c##d +static const uint32_t FT0[256] = {FT}; +#undef V + +#if !defined(UTILS_AES_FEWER_TABLES) + +#define V(a, b, c, d) 0x##b##c##d##a +static const uint32_t FT1[256] = {FT}; +#undef V + +#define V(a, b, c, d) 0x##c##d##a##b +static const uint32_t FT2[256] = {FT}; +#undef V + +#define V(a, b, c, d) 0x##d##a##b##c +static const uint32_t FT3[256] = {FT}; +#undef V + +#endif /* !UTILS_AES_FEWER_TABLES */ + +#undef FT + +/* + * Reverse S-box + */ +static const unsigned char RSb[256] = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, + 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, + 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, + 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, + 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, + 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, + 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, + 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, + 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, + 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, + 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, + 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, + 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D}; + +/* + * Reverse tables + */ +#define RT \ + \ + V(50, A7, F4, 51) \ + , V(53, 65, 41, 7E), V(C3, A4, 17, 1A), V(96, 5E, 27, 3A), V(CB, 6B, AB, 3B), V(F1, 45, 9D, 1F), \ + V(AB, 58, FA, AC), V(93, 03, E3, 4B), V(55, FA, 30, 20), V(F6, 6D, 76, AD), V(91, 76, CC, 88), \ + V(25, 4C, 02, F5), V(FC, D7, E5, 4F), V(D7, CB, 2A, C5), V(80, 44, 35, 26), V(8F, A3, 62, B5), \ + V(49, 5A, B1, DE), V(67, 1B, BA, 25), V(98, 0E, EA, 45), V(E1, C0, FE, 5D), V(02, 75, 2F, C3), \ + V(12, F0, 4C, 81), V(A3, 97, 46, 8D), V(C6, F9, D3, 6B), V(E7, 5F, 8F, 03), V(95, 9C, 92, 15), \ + V(EB, 7A, 6D, BF), V(DA, 59, 52, 95), V(2D, 83, BE, D4), V(D3, 21, 74, 58), V(29, 69, E0, 49), \ + V(44, C8, C9, 8E), V(6A, 89, C2, 75), V(78, 79, 8E, F4), V(6B, 3E, 58, 99), V(DD, 71, B9, 27), \ + V(B6, 4F, E1, BE), V(17, AD, 88, F0), V(66, AC, 20, C9), V(B4, 3A, CE, 7D), V(18, 4A, DF, 63), \ + V(82, 31, 1A, E5), V(60, 33, 51, 97), V(45, 7F, 53, 62), V(E0, 77, 64, B1), V(84, AE, 6B, BB), \ + V(1C, A0, 81, FE), V(94, 2B, 08, F9), V(58, 68, 48, 70), V(19, FD, 45, 8F), V(87, 6C, DE, 94), \ + V(B7, F8, 7B, 52), V(23, D3, 73, AB), V(E2, 02, 4B, 72), V(57, 8F, 1F, E3), V(2A, AB, 55, 66), \ + V(07, 28, EB, B2), V(03, C2, B5, 2F), V(9A, 7B, C5, 86), V(A5, 08, 37, D3), V(F2, 87, 28, 30), \ + V(B2, A5, BF, 23), V(BA, 6A, 03, 02), V(5C, 82, 16, ED), V(2B, 1C, CF, 8A), V(92, B4, 79, A7), \ + V(F0, F2, 07, F3), V(A1, E2, 69, 4E), V(CD, F4, DA, 65), V(D5, BE, 05, 06), V(1F, 62, 34, D1), \ + V(8A, FE, A6, C4), V(9D, 53, 2E, 34), V(A0, 55, F3, A2), V(32, E1, 8A, 05), V(75, EB, F6, A4), \ + V(39, EC, 83, 0B), V(AA, EF, 60, 40), V(06, 9F, 71, 5E), V(51, 10, 6E, BD), V(F9, 8A, 21, 3E), \ + V(3D, 06, DD, 96), V(AE, 05, 3E, DD), V(46, BD, E6, 4D), V(B5, 8D, 54, 91), V(05, 5D, C4, 71), \ + V(6F, D4, 06, 04), V(FF, 15, 50, 60), V(24, FB, 98, 19), V(97, E9, BD, D6), V(CC, 43, 40, 89), \ + V(77, 9E, D9, 67), V(BD, 42, E8, B0), V(88, 8B, 89, 07), V(38, 5B, 19, E7), V(DB, EE, C8, 79), \ + V(47, 0A, 7C, A1), V(E9, 0F, 42, 7C), V(C9, 1E, 84, F8), V(00, 00, 00, 00), V(83, 86, 80, 09), \ + V(48, ED, 2B, 32), V(AC, 70, 11, 1E), V(4E, 72, 5A, 6C), V(FB, FF, 0E, FD), V(56, 38, 85, 0F), \ + V(1E, D5, AE, 3D), V(27, 39, 2D, 36), V(64, D9, 0F, 0A), V(21, A6, 5C, 68), V(D1, 54, 5B, 9B), \ + V(3A, 2E, 36, 24), V(B1, 67, 0A, 0C), V(0F, E7, 57, 93), V(D2, 96, EE, B4), V(9E, 91, 9B, 1B), \ + V(4F, C5, C0, 80), V(A2, 20, DC, 61), V(69, 4B, 77, 5A), V(16, 1A, 12, 1C), V(0A, BA, 93, E2), \ + V(E5, 2A, A0, C0), V(43, E0, 22, 3C), V(1D, 17, 1B, 12), V(0B, 0D, 09, 0E), V(AD, C7, 8B, F2), \ + V(B9, A8, B6, 2D), V(C8, A9, 1E, 14), V(85, 19, F1, 57), V(4C, 07, 75, AF), V(BB, DD, 99, EE), \ + V(FD, 60, 7F, A3), V(9F, 26, 01, F7), V(BC, F5, 72, 5C), V(C5, 3B, 66, 44), V(34, 7E, FB, 5B), \ + V(76, 29, 43, 8B), V(DC, C6, 23, CB), V(68, FC, ED, B6), V(63, F1, E4, B8), V(CA, DC, 31, D7), \ + V(10, 85, 63, 42), V(40, 22, 97, 13), V(20, 11, C6, 84), V(7D, 24, 4A, 85), V(F8, 3D, BB, D2), \ + V(11, 32, F9, AE), V(6D, A1, 29, C7), V(4B, 2F, 9E, 1D), V(F3, 30, B2, DC), V(EC, 52, 86, 0D), \ + V(D0, E3, C1, 77), V(6C, 16, B3, 2B), V(99, B9, 70, A9), V(FA, 48, 94, 11), V(22, 64, E9, 47), \ + V(C4, 8C, FC, A8), V(1A, 3F, F0, A0), V(D8, 2C, 7D, 56), V(EF, 90, 33, 22), V(C7, 4E, 49, 87), \ + V(C1, D1, 38, D9), V(FE, A2, CA, 8C), V(36, 0B, D4, 98), V(CF, 81, F5, A6), V(28, DE, 7A, A5), \ + V(26, 8E, B7, DA), V(A4, BF, AD, 3F), V(E4, 9D, 3A, 2C), V(0D, 92, 78, 50), V(9B, CC, 5F, 6A), \ + V(62, 46, 7E, 54), V(C2, 13, 8D, F6), V(E8, B8, D8, 90), V(5E, F7, 39, 2E), V(F5, AF, C3, 82), \ + V(BE, 80, 5D, 9F), V(7C, 93, D0, 69), V(A9, 2D, D5, 6F), V(B3, 12, 25, CF), V(3B, 99, AC, C8), \ + V(A7, 7D, 18, 10), V(6E, 63, 9C, E8), V(7B, BB, 3B, DB), V(09, 78, 26, CD), V(F4, 18, 59, 6E), \ + V(01, B7, 9A, EC), V(A8, 9A, 4F, 83), V(65, 6E, 95, E6), V(7E, E6, FF, AA), V(08, CF, BC, 21), \ + V(E6, E8, 15, EF), V(D9, 9B, E7, BA), V(CE, 36, 6F, 4A), V(D4, 09, 9F, EA), V(D6, 7C, B0, 29), \ + V(AF, B2, A4, 31), V(31, 23, 3F, 2A), V(30, 94, A5, C6), V(C0, 66, A2, 35), V(37, BC, 4E, 74), \ + V(A6, CA, 82, FC), V(B0, D0, 90, E0), V(15, D8, A7, 33), V(4A, 98, 04, F1), V(F7, DA, EC, 41), \ + V(0E, 50, CD, 7F), V(2F, F6, 91, 17), V(8D, D6, 4D, 76), V(4D, B0, EF, 43), V(54, 4D, AA, CC), \ + V(DF, 04, 96, E4), V(E3, B5, D1, 9E), V(1B, 88, 6A, 4C), V(B8, 1F, 2C, C1), V(7F, 51, 65, 46), \ + V(04, EA, 5E, 9D), V(5D, 35, 8C, 01), V(73, 74, 87, FA), V(2E, 41, 0B, FB), V(5A, 1D, 67, B3), \ + V(52, D2, DB, 92), V(33, 56, 10, E9), V(13, 47, D6, 6D), V(8C, 61, D7, 9A), V(7A, 0C, A1, 37), \ + V(8E, 14, F8, 59), V(89, 3C, 13, EB), V(EE, 27, A9, CE), V(35, C9, 61, B7), V(ED, E5, 1C, E1), \ + V(3C, B1, 47, 7A), V(59, DF, D2, 9C), V(3F, 73, F2, 55), V(79, CE, 14, 18), V(BF, 37, C7, 73), \ + V(EA, CD, F7, 53), V(5B, AA, FD, 5F), V(14, 6F, 3D, DF), V(86, DB, 44, 78), V(81, F3, AF, CA), \ + V(3E, C4, 68, B9), V(2C, 34, 24, 38), V(5F, 40, A3, C2), V(72, C3, 1D, 16), V(0C, 25, E2, BC), \ + V(8B, 49, 3C, 28), V(41, 95, 0D, FF), V(71, 01, A8, 39), V(DE, B3, 0C, 08), V(9C, E4, B4, D8), \ + V(90, C1, 56, 64), V(61, 84, CB, 7B), V(70, B6, 32, D5), V(74, 5C, 6C, 48), V(42, 57, B8, D0) + +#define V(a, b, c, d) 0x##a##b##c##d +static const uint32_t RT0[256] = {RT}; +#undef V + +#if !defined(UTILS_AES_FEWER_TABLES) + +#define V(a, b, c, d) 0x##b##c##d##a +static const uint32_t RT1[256] = {RT}; +#undef V + +#define V(a, b, c, d) 0x##c##d##a##b +static const uint32_t RT2[256] = {RT}; +#undef V + +#define V(a, b, c, d) 0x##d##a##b##c +static const uint32_t RT3[256] = {RT}; +#undef V + +#endif /* !UTILS_AES_FEWER_TABLES */ + +#undef RT + +/* + * Round constants + */ +static const uint32_t RCON[10] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, + 0x00000020, 0x00000040, 0x00000080, 0x0000001B, 0x00000036}; + +#else /* UTILS_AES_ROM_TABLES */ + +/* + * Forward S-box & tables + */ +static unsigned char FSb[256]; +static uint32_t FT0[256]; +#if !defined(UTILS_AES_FEWER_TABLES) +static uint32_t FT1[256]; +static uint32_t FT2[256]; +static uint32_t FT3[256]; +#endif /* !UTILS_AES_FEWER_TABLES */ + +/* + * Reverse S-box & tables + */ +static unsigned char RSb[256]; +static uint32_t RT0[256]; +#if !defined(UTILS_AES_FEWER_TABLES) +static uint32_t RT1[256]; +static uint32_t RT2[256]; +static uint32_t RT3[256]; +#endif /* !UTILS_AES_FEWER_TABLES */ + +/* + * Round constants + */ +static uint32_t RCON[10]; + +/* + * Tables generation code + */ +#define ROTL8(x) ((x << 8) & 0xFFFFFFFF) | (x >> 24) +#define XTIME(x) ((x << 1) ^ ((x & 0x80) ? 0x1B : 0x00)) +#define MUL(x, y) ((x && y) ? pow[(log[x] + log[y]) % 255] : 0) + +static int aes_init_done = 0; + +static void aes_gen_tables(void) +{ + int i, x, y, z; + int pow[256]; + int log[256]; + + /* + * compute pow and log tables over GF(2^8) + */ + for (i = 0, x = 1; i < 256; i++) { + pow[i] = x; + log[x] = i; + x = (x ^ XTIME(x)) & 0xFF; + } + + /* + * calculate the round constants + */ + for (i = 0, x = 1; i < 10; i++) { + RCON[i] = (uint32_t)x; + x = XTIME(x) & 0xFF; + } + + /* + * generate the forward and reverse S-boxes + */ + FSb[0x00] = 0x63; + RSb[0x63] = 0x00; + + for (i = 1; i < 256; i++) { + x = pow[255 - log[i]]; + + y = x; + y = ((y << 1) | (y >> 7)) & 0xFF; + x ^= y; + y = ((y << 1) | (y >> 7)) & 0xFF; + x ^= y; + y = ((y << 1) | (y >> 7)) & 0xFF; + x ^= y; + y = ((y << 1) | (y >> 7)) & 0xFF; + x ^= y ^ 0x63; + + FSb[i] = (unsigned char)x; + RSb[x] = (unsigned char)i; + } + + /* + * generate the forward and reverse tables + */ + for (i = 0; i < 256; i++) { + x = FSb[i]; + y = XTIME(x) & 0xFF; + z = (y ^ x) & 0xFF; + + FT0[i] = ((uint32_t)y) ^ ((uint32_t)x << 8) ^ ((uint32_t)x << 16) ^ ((uint32_t)z << 24); + +#if !defined(UTILS_AES_FEWER_TABLES) + FT1[i] = ROTL8(FT0[i]); + FT2[i] = ROTL8(FT1[i]); + FT3[i] = ROTL8(FT2[i]); +#endif /* !UTILS_AES_FEWER_TABLES */ + + x = RSb[i]; + + RT0[i] = ((uint32_t)MUL(0x0E, x)) ^ ((uint32_t)MUL(0x09, x) << 8) ^ ((uint32_t)MUL(0x0D, x) << 16) ^ + ((uint32_t)MUL(0x0B, x) << 24); + +#if !defined(UTILS_AES_FEWER_TABLES) + RT1[i] = ROTL8(RT0[i]); + RT2[i] = ROTL8(RT1[i]); + RT3[i] = ROTL8(RT2[i]); +#endif /* !UTILS_AES_FEWER_TABLES */ + } +} + +#undef ROTL8 + +#endif /* UTILS_AES_ROM_TABLES */ + +#if defined(UTILS_AES_FEWER_TABLES) + +#define ROTL8(x) ((uint32_t)((x) << 8) + (uint32_t)((x) >> 24)) +#define ROTL16(x) ((uint32_t)((x) << 16) + (uint32_t)((x) >> 16)) +#define ROTL24(x) ((uint32_t)((x) << 24) + (uint32_t)((x) >> 8)) + +#define AES_RT0(idx) RT0[idx] +#define AES_RT1(idx) ROTL8(RT0[idx]) +#define AES_RT2(idx) ROTL16(RT0[idx]) +#define AES_RT3(idx) ROTL24(RT0[idx]) + +#define AES_FT0(idx) FT0[idx] +#define AES_FT1(idx) ROTL8(FT0[idx]) +#define AES_FT2(idx) ROTL16(FT0[idx]) +#define AES_FT3(idx) ROTL24(FT0[idx]) + +#else /* UTILS_AES_FEWER_TABLES */ + +#define AES_RT0(idx) RT0[idx] +#define AES_RT1(idx) RT1[idx] +#define AES_RT2(idx) RT2[idx] +#define AES_RT3(idx) RT3[idx] + +#define AES_FT0(idx) FT0[idx] +#define AES_FT1(idx) FT1[idx] +#define AES_FT2(idx) FT2[idx] +#define AES_FT3(idx) FT3[idx] + +#endif /* UTILS_AES_FEWER_TABLES */ + +void utils_aes_init(utils_aes_context *ctx) +{ + AES_VALIDATE(ctx != NULL); + + memset(ctx, 0, sizeof(utils_aes_context)); +} + +void utils_aes_free(utils_aes_context *ctx) +{ + if (ctx == NULL) + return; + + utils_platform_zeroize(ctx, sizeof(utils_aes_context)); +} + +/* + * AES key schedule (encryption) + */ +#if !defined(UTILS_AES_SETKEY_ENC_ALT) +int utils_aes_setkey_enc(utils_aes_context *ctx, const unsigned char *key, unsigned int keybits) +{ + unsigned int i; + uint32_t * RK; + + AES_VALIDATE_RET(ctx != NULL); + AES_VALIDATE_RET(key != NULL); + + switch (keybits) { + case 128: + ctx->nr = 10; + break; + case 192: + ctx->nr = 12; + break; + case 256: + ctx->nr = 14; + break; + default: + return (UTILS_ERR_AES_INVALID_KEY_LENGTH); + } + +#if !defined(UTILS_AES_ROM_TABLES) + if (aes_init_done == 0) { + aes_gen_tables(); + aes_init_done = 1; + } +#endif + + ctx->rk = RK = ctx->buf; + + for (i = 0; i < (keybits >> 5); i++) { + GET_UINT32_LE(RK[i], key, i << 2); + } + + switch (ctx->nr) { + case 10: + + for (i = 0; i < 10; i++, RK += 4) { + RK[4] = RK[0] ^ RCON[i] ^ ((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^ + ((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^ ((uint32_t)FSb[(RK[3] >> 24) & 0xFF] << 16) ^ + ((uint32_t)FSb[(RK[3]) & 0xFF] << 24); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 12: + + for (i = 0; i < 8; i++, RK += 6) { + RK[6] = RK[0] ^ RCON[i] ^ ((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^ + ((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^ ((uint32_t)FSb[(RK[5] >> 24) & 0xFF] << 16) ^ + ((uint32_t)FSb[(RK[5]) & 0xFF] << 24); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 14: + + for (i = 0; i < 7; i++, RK += 8) { + RK[8] = RK[0] ^ RCON[i] ^ ((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^ + ((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^ ((uint32_t)FSb[(RK[7] >> 24) & 0xFF] << 16) ^ + ((uint32_t)FSb[(RK[7]) & 0xFF] << 24); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ ((uint32_t)FSb[(RK[11]) & 0xFF]) ^ ((uint32_t)FSb[(RK[11] >> 8) & 0xFF] << 8) ^ + ((uint32_t)FSb[(RK[11] >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(RK[11] >> 24) & 0xFF] << 24); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + } + + return (0); +} +#endif /* !UTILS_AES_SETKEY_ENC_ALT */ + +/* + * AES key schedule (decryption) + */ +#if !defined(UTILS_AES_SETKEY_DEC_ALT) +int utils_aes_setkey_dec(utils_aes_context *ctx, const unsigned char *key, unsigned int keybits) +{ + int i, j, ret; + utils_aes_context cty; + uint32_t * RK; + uint32_t * SK; + + AES_VALIDATE_RET(ctx != NULL); + AES_VALIDATE_RET(key != NULL); + + utils_aes_init(&cty); + + ctx->rk = RK = ctx->buf; + + /* Also checks keybits */ + if ((ret = utils_aes_setkey_enc(&cty, key, keybits)) != 0) + goto exit; + + ctx->nr = cty.nr; + + SK = cty.rk + cty.nr * 4; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for (i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8) { + for (j = 0; j < 4; j++, SK++) { + *RK++ = AES_RT0(FSb[(*SK) & 0xFF]) ^ AES_RT1(FSb[(*SK >> 8) & 0xFF]) ^ AES_RT2(FSb[(*SK >> 16) & 0xFF]) ^ + AES_RT3(FSb[(*SK >> 24) & 0xFF]); + } + } + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + utils_aes_free(&cty); + + return (ret); +} + +#endif /* !UTILS_AES_SETKEY_DEC_ALT */ + +#define AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ + \ + { \ + X0 = *RK++ ^ AES_FT0((Y0)&0xFF) ^ AES_FT1((Y1 >> 8) & 0xFF) ^ AES_FT2((Y2 >> 16) & 0xFF) ^ \ + AES_FT3((Y3 >> 24) & 0xFF); \ + \ + X1 = *RK++ ^ AES_FT0((Y1)&0xFF) ^ AES_FT1((Y2 >> 8) & 0xFF) ^ AES_FT2((Y3 >> 16) & 0xFF) ^ \ + AES_FT3((Y0 >> 24) & 0xFF); \ + \ + X2 = *RK++ ^ AES_FT0((Y2)&0xFF) ^ AES_FT1((Y3 >> 8) & 0xFF) ^ AES_FT2((Y0 >> 16) & 0xFF) ^ \ + AES_FT3((Y1 >> 24) & 0xFF); \ + \ + X3 = *RK++ ^ AES_FT0((Y3)&0xFF) ^ AES_FT1((Y0 >> 8) & 0xFF) ^ AES_FT2((Y1 >> 16) & 0xFF) ^ \ + AES_FT3((Y2 >> 24) & 0xFF); \ + } + +#define AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ + \ + { \ + X0 = *RK++ ^ AES_RT0((Y0)&0xFF) ^ AES_RT1((Y3 >> 8) & 0xFF) ^ AES_RT2((Y2 >> 16) & 0xFF) ^ \ + AES_RT3((Y1 >> 24) & 0xFF); \ + \ + X1 = *RK++ ^ AES_RT0((Y1)&0xFF) ^ AES_RT1((Y0 >> 8) & 0xFF) ^ AES_RT2((Y3 >> 16) & 0xFF) ^ \ + AES_RT3((Y2 >> 24) & 0xFF); \ + \ + X2 = *RK++ ^ AES_RT0((Y2)&0xFF) ^ AES_RT1((Y1 >> 8) & 0xFF) ^ AES_RT2((Y0 >> 16) & 0xFF) ^ \ + AES_RT3((Y3 >> 24) & 0xFF); \ + \ + X3 = *RK++ ^ AES_RT0((Y3)&0xFF) ^ AES_RT1((Y2 >> 8) & 0xFF) ^ AES_RT2((Y1 >> 16) & 0xFF) ^ \ + AES_RT3((Y0 >> 24) & 0xFF); \ + } + +/* + * AES-ECB block encryption + */ +#if !defined(UTILS_AES_ENCRYPT_ALT) +int utils_internal_aes_encrypt(utils_aes_context *ctx, const unsigned char input[16], unsigned char output[16]) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE(X0, input, 0); + X0 ^= *RK++; + GET_UINT32_LE(X1, input, 4); + X1 ^= *RK++; + GET_UINT32_LE(X2, input, 8); + X2 ^= *RK++; + GET_UINT32_LE(X3, input, 12); + X3 ^= *RK++; + + for (i = (ctx->nr >> 1) - 1; i > 0; i--) { + AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); + AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); + } + + AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); + + X0 = *RK++ ^ ((uint32_t)FSb[(Y0)&0xFF]) ^ ((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^ + ((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24); + + X1 = *RK++ ^ ((uint32_t)FSb[(Y1)&0xFF]) ^ ((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^ + ((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24); + + X2 = *RK++ ^ ((uint32_t)FSb[(Y2)&0xFF]) ^ ((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^ + ((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24); + + X3 = *RK++ ^ ((uint32_t)FSb[(Y3)&0xFF]) ^ ((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^ + ((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^ ((uint32_t)FSb[(Y2 >> 24) & 0xFF] << 24); + + PUT_UINT32_LE(X0, output, 0); + PUT_UINT32_LE(X1, output, 4); + PUT_UINT32_LE(X2, output, 8); + PUT_UINT32_LE(X3, output, 12); + + return (0); +} +#endif /* !UTILS_AES_ENCRYPT_ALT */ + +#if !defined(UTILS_DEPRECATED_REMOVED) +void utils_aes_encrypt(utils_aes_context *ctx, const unsigned char input[16], unsigned char output[16]) +{ + utils_internal_aes_encrypt(ctx, input, output); +} +#endif /* !UTILS_DEPRECATED_REMOVED */ + +/* + * AES-ECB block decryption + */ +#if !defined(UTILS_AES_DECRYPT_ALT) +int utils_internal_aes_decrypt(utils_aes_context *ctx, const unsigned char input[16], unsigned char output[16]) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE(X0, input, 0); + X0 ^= *RK++; + GET_UINT32_LE(X1, input, 4); + X1 ^= *RK++; + GET_UINT32_LE(X2, input, 8); + X2 ^= *RK++; + GET_UINT32_LE(X3, input, 12); + X3 ^= *RK++; + + for (i = (ctx->nr >> 1) - 1; i > 0; i--) { + AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); + AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); + } + + AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); + + X0 = *RK++ ^ ((uint32_t)RSb[(Y0)&0xFF]) ^ ((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^ + ((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24); + + X1 = *RK++ ^ ((uint32_t)RSb[(Y1)&0xFF]) ^ ((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^ + ((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24); + + X2 = *RK++ ^ ((uint32_t)RSb[(Y2)&0xFF]) ^ ((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^ + ((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24); + + X3 = *RK++ ^ ((uint32_t)RSb[(Y3)&0xFF]) ^ ((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^ + ((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^ ((uint32_t)RSb[(Y0 >> 24) & 0xFF] << 24); + + PUT_UINT32_LE(X0, output, 0); + PUT_UINT32_LE(X1, output, 4); + PUT_UINT32_LE(X2, output, 8); + PUT_UINT32_LE(X3, output, 12); + + return (0); +} +#endif /* !UTILS_AES_DECRYPT_ALT */ + +#if !defined(UTILS_DEPRECATED_REMOVED) +void utils_aes_decrypt(utils_aes_context *ctx, const unsigned char input[16], unsigned char output[16]) +{ + utils_internal_aes_decrypt(ctx, input, output); +} +#endif /* !UTILS_DEPRECATED_REMOVED */ + +/* + * AES-ECB block encryption/decryption + */ +int utils_aes_crypt_ecb(utils_aes_context *ctx, int mode, const unsigned char input[16], unsigned char output[16]) +{ + AES_VALIDATE_RET(ctx != NULL); + AES_VALIDATE_RET(input != NULL); + AES_VALIDATE_RET(output != NULL); + AES_VALIDATE_RET(mode == UTILS_AES_ENCRYPT || mode == UTILS_AES_DECRYPT); + + if (mode == UTILS_AES_ENCRYPT) + return (utils_internal_aes_encrypt(ctx, input, output)); + else + return (utils_internal_aes_decrypt(ctx, input, output)); +} + +#if defined(UTILS_CIPHER_MODE_CBC) +/* + * AES-CBC buffer encryption/decryption + */ +int utils_aes_crypt_cbc(utils_aes_context *ctx, int mode, size_t length, unsigned char iv[16], + const unsigned char *input, unsigned char *output) +{ + int i; + unsigned char temp[16]; + + AES_VALIDATE_RET(ctx != NULL); + AES_VALIDATE_RET(mode == UTILS_AES_ENCRYPT || mode == UTILS_AES_DECRYPT); + AES_VALIDATE_RET(iv != NULL); + AES_VALIDATE_RET(input != NULL); + AES_VALIDATE_RET(output != NULL); + + if (length % 16) + return (UTILS_ERR_AES_INVALID_INPUT_LENGTH); + + if (mode == UTILS_AES_DECRYPT) { + while (length > 0) { + memcpy(temp, input, 16); + utils_aes_crypt_ecb(ctx, mode, input, output); + + for (i = 0; i < 16; i++) output[i] = (unsigned char)(output[i] ^ iv[i]); + + memcpy(iv, temp, 16); + + input += 16; + output += 16; + length -= 16; + } + } else { + while (length > 0) { + for (i = 0; i < 16; i++) output[i] = (unsigned char)(input[i] ^ iv[i]); + + utils_aes_crypt_ecb(ctx, mode, output, output); + memcpy(iv, output, 16); + + input += 16; + output += 16; + length -= 16; + } + } + + return (0); +} + +int utils_aes_cbc(uint8_t *pInData, uint32_t datalen, uint8_t *pOutData, uint32_t outBuffLen, uint8_t mode, + uint8_t *pKey, uint16_t keybits, uint8_t *iv) +{ + int ret = QCLOUD_RET_SUCCESS; + int padlen; + utils_aes_context ctx; + + utils_aes_init(&ctx); + + if (UTILS_AES_ENCRYPT == mode) { + ret = utils_aes_setkey_enc(&ctx, pKey, keybits); + if (ret != 0) { + Log_e("Set encry key err,ret:%d", ret); + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + + /*zero padding*/ + if (outBuffLen < (datalen + UTILS_AES_BLOCK_LEN)) { + Log_e( + "Output buffer should not less than datalen+UTILS_AES_BLOCK_LEN " + "for padding"); + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + padlen = UTILS_AES_BLOCK_LEN - datalen % UTILS_AES_BLOCK_LEN; + memcpy(pOutData, pInData, datalen); + memset(pOutData + datalen, '\0', padlen); /*zero-padding*/ + datalen += padlen; + } else { + ret = utils_aes_setkey_dec(&ctx, pKey, keybits); + if (ret != 0) { + Log_e("Set dencry key err,ret:%d", ret); + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + } + + ret = utils_aes_crypt_cbc(&ctx, mode, datalen, iv, pInData, pOutData); + if (ret != 0) { + Log_e("encryt err,ret:%d", ret); + ret = QCLOUD_ERR_FAILURE; + goto exit; + } else { + ret = QCLOUD_RET_SUCCESS; + } + +exit: + + return ret; +} +#endif /* UTILS_CIPHER_MODE_CBC */ + +#endif /* !UTILS_AES_ALT */ + +#if defined(UTILS_SELF_TEST) +/* + * AES test vectors from: + * + * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip + */ +static const unsigned char aes_test_ecb_dec[3][16] = { + {0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0}, + {0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4}, + {0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE}}; + +static const unsigned char aes_test_ecb_enc[3][16] = { + {0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F}, + {0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14}, + {0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4}}; + +#if defined(UTILS_CIPHER_MODE_CBC) +static const unsigned char aes_test_cbc_dec[3][16] = { + {0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86}, + {0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B}, + {0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13}}; + +static const unsigned char aes_test_cbc_enc[3][16] = { + {0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D}, + {0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04}, + {0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0}}; +#endif /* UTILS_CIPHER_MODE_CBC */ + +/* + * Checkup routine + */ +int utils_aes_self_test(int verbose) +{ + int ret = 0, i, j, u, mode; + unsigned int keybits; + unsigned char key[32]; + unsigned char buf[64]; + const unsigned char *aes_tests; +#if defined(UTILS_CIPHER_MODE_CBC) || defined(UTILS_CIPHER_MODE_CFB) + unsigned char iv[16]; +#endif +#if defined(UTILS_CIPHER_MODE_CBC) + unsigned char prv[16]; +#endif +#if defined(UTILS_CIPHER_MODE_CTR) || defined(UTILS_CIPHER_MODE_CFB) || defined(UTILS_CIPHER_MODE_OFB) + size_t offset; +#endif +#if defined(UTILS_CIPHER_MODE_CTR) || defined(UTILS_CIPHER_MODE_XTS) + int len; +#endif +#if defined(UTILS_CIPHER_MODE_CTR) + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + utils_aes_context ctx; + + memset(key, 0, 32); + utils_aes_init(&ctx); + + /* + * ECB mode + */ + for (i = 0; i < 6; i++) { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if (verbose != 0) + utils_printf(" AES-ECB-%3d (%s): ", keybits, (mode == UTILS_AES_DECRYPT) ? "dec" : "enc"); + + memset(buf, 0, 16); + + if (mode == UTILS_AES_DECRYPT) { + ret = utils_aes_setkey_dec(&ctx, key, keybits); + aes_tests = aes_test_ecb_dec[u]; + } else { + ret = utils_aes_setkey_enc(&ctx, key, keybits); + aes_tests = aes_test_ecb_enc[u]; + } + + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * UTILS_AES_ALT is defined. + */ + if (ret == UTILS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) { + utils_printf("skipped\n"); + continue; + } else if (ret != 0) { + goto exit; + } + + for (j = 0; j < 10000; j++) { + ret = utils_aes_crypt_ecb(&ctx, mode, buf, buf); + if (ret != 0) + goto exit; + } + + if (memcmp(buf, aes_tests, 16) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) + utils_printf("passed\n"); + } + + if (verbose != 0) + utils_printf("\n"); + +#if defined(UTILS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for (i = 0; i < 6; i++) { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if (verbose != 0) + utils_printf(" AES-CBC-%3d (%s): ", keybits, (mode == UTILS_AES_DECRYPT) ? "dec" : "enc"); + + memset(iv, 0, 16); + memset(prv, 0, 16); + memset(buf, 0, 16); + + if (mode == UTILS_AES_DECRYPT) { + ret = utils_aes_setkey_dec(&ctx, key, keybits); + aes_tests = aes_test_cbc_dec[u]; + } else { + ret = utils_aes_setkey_enc(&ctx, key, keybits); + aes_tests = aes_test_cbc_enc[u]; + } + + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * UTILS_AES_ALT is defined. + */ + if (ret == UTILS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) { + utils_printf("skipped\n"); + continue; + } else if (ret != 0) { + goto exit; + } + + for (j = 0; j < 10000; j++) { + if (mode == UTILS_AES_ENCRYPT) { + unsigned char tmp[16]; + + memcpy(tmp, prv, 16); + memcpy(prv, buf, 16); + memcpy(buf, tmp, 16); + } + + ret = utils_aes_crypt_cbc(&ctx, mode, 16, iv, buf, buf); + if (ret != 0) + goto exit; + } + + if (memcmp(buf, aes_tests, 16) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) + utils_printf("passed\n"); + } + + if (verbose != 0) + utils_printf("\n"); +#endif /* UTILS_CIPHER_MODE_CBC */ + +#if defined(UTILS_CIPHER_MODE_CFB) + /* + * CFB128 mode + */ + for (i = 0; i < 6; i++) { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if (verbose != 0) + utils_printf(" AES-CFB128-%3d (%s): ", keybits, (mode == UTILS_AES_DECRYPT) ? "dec" : "enc"); + + memcpy(iv, aes_test_cfb128_iv, 16); + memcpy(key, aes_test_cfb128_key[u], keybits / 8); + + offset = 0; + ret = utils_aes_setkey_enc(&ctx, key, keybits); + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * UTILS_AES_ALT is defined. + */ + if (ret == UTILS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) { + utils_printf("skipped\n"); + continue; + } else if (ret != 0) { + goto exit; + } + + if (mode == UTILS_AES_DECRYPT) { + memcpy(buf, aes_test_cfb128_ct[u], 64); + aes_tests = aes_test_cfb128_pt; + } else { + memcpy(buf, aes_test_cfb128_pt, 64); + aes_tests = aes_test_cfb128_ct[u]; + } + + ret = utils_aes_crypt_cfb128(&ctx, mode, 64, &offset, iv, buf, buf); + if (ret != 0) + goto exit; + + if (memcmp(buf, aes_tests, 64) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) + utils_printf("passed\n"); + } + + if (verbose != 0) + utils_printf("\n"); +#endif /* UTILS_CIPHER_MODE_CFB */ + +#if defined(UTILS_CIPHER_MODE_OFB) + /* + * OFB mode + */ + for (i = 0; i < 6; i++) { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if (verbose != 0) + utils_printf(" AES-OFB-%3d (%s): ", keybits, (mode == UTILS_AES_DECRYPT) ? "dec" : "enc"); + + memcpy(iv, aes_test_ofb_iv, 16); + memcpy(key, aes_test_ofb_key[u], keybits / 8); + + offset = 0; + ret = utils_aes_setkey_enc(&ctx, key, keybits); + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * UTILS_AES_ALT is defined. + */ + if (ret == UTILS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192) { + utils_printf("skipped\n"); + continue; + } else if (ret != 0) { + goto exit; + } + + if (mode == UTILS_AES_DECRYPT) { + memcpy(buf, aes_test_ofb_ct[u], 64); + aes_tests = aes_test_ofb_pt; + } else { + memcpy(buf, aes_test_ofb_pt, 64); + aes_tests = aes_test_ofb_ct[u]; + } + + ret = utils_aes_crypt_ofb(&ctx, 64, &offset, iv, buf, buf); + if (ret != 0) + goto exit; + + if (memcmp(buf, aes_tests, 64) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) + utils_printf("passed\n"); + } + + if (verbose != 0) + utils_printf("\n"); +#endif /* UTILS_CIPHER_MODE_OFB */ + +#if defined(UTILS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for (i = 0; i < 6; i++) { + u = i >> 1; + mode = i & 1; + + if (verbose != 0) + utils_printf(" AES-CTR-128 (%s): ", (mode == UTILS_AES_DECRYPT) ? "dec" : "enc"); + + memcpy(nonce_counter, aes_test_ctr_nonce_counter[u], 16); + memcpy(key, aes_test_ctr_key[u], 16); + + offset = 0; + if ((ret = utils_aes_setkey_enc(&ctx, key, 128)) != 0) + goto exit; + + len = aes_test_ctr_len[u]; + + if (mode == UTILS_AES_DECRYPT) { + memcpy(buf, aes_test_ctr_ct[u], len); + aes_tests = aes_test_ctr_pt[u]; + } else { + memcpy(buf, aes_test_ctr_pt[u], len); + aes_tests = aes_test_ctr_ct[u]; + } + + ret = utils_aes_crypt_ctr(&ctx, len, &offset, nonce_counter, stream_block, buf, buf); + if (ret != 0) + goto exit; + + if (memcmp(buf, aes_tests, len) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) + utils_printf("passed\n"); + } + + if (verbose != 0) + utils_printf("\n"); +#endif /* UTILS_CIPHER_MODE_CTR */ + +#if defined(UTILS_CIPHER_MODE_XTS) + { + static const int num_tests = sizeof(aes_test_xts_key) / sizeof(*aes_test_xts_key); + utils_aes_xts_context ctx_xts; + + /* + * XTS mode + */ + utils_aes_xts_init(&ctx_xts); + + for (i = 0; i < num_tests << 1; i++) { + const unsigned char *data_unit; + u = i >> 1; + mode = i & 1; + + if (verbose != 0) + utils_printf(" AES-XTS-128 (%s): ", (mode == UTILS_AES_DECRYPT) ? "dec" : "enc"); + + memset(key, 0, sizeof(key)); + memcpy(key, aes_test_xts_key[u], 32); + data_unit = aes_test_xts_data_unit[u]; + + len = sizeof(*aes_test_xts_ct32); + + if (mode == UTILS_AES_DECRYPT) { + ret = utils_aes_xts_setkey_dec(&ctx_xts, key, 256); + if (ret != 0) + goto exit; + memcpy(buf, aes_test_xts_ct32[u], len); + aes_tests = aes_test_xts_pt32[u]; + } else { + ret = utils_aes_xts_setkey_enc(&ctx_xts, key, 256); + if (ret != 0) + goto exit; + memcpy(buf, aes_test_xts_pt32[u], len); + aes_tests = aes_test_xts_ct32[u]; + } + + ret = utils_aes_crypt_xts(&ctx_xts, mode, len, data_unit, buf, buf); + if (ret != 0) + goto exit; + + if (memcmp(buf, aes_tests, len) != 0) { + ret = 1; + goto exit; + } + + if (verbose != 0) + utils_printf("passed\n"); + } + + if (verbose != 0) + utils_printf("\n"); + + utils_aes_xts_free(&ctx_xts); + } +#endif /* UTILS_CIPHER_MODE_XTS */ + + ret = 0; + +exit: + if (ret != 0 && verbose != 0) + utils_printf("failed\n"); + + utils_aes_free(&ctx); + + return (ret); +} + +/*aes128-cbc*/ +int aes_sample(int verbose) +{ + int ret = 0, i; + unsigned int keybits; + unsigned char key[UTILS_AES_BLOCK_LEN] = "1234567890abcdef"; + char dataIn[1024] = {0}; + unsigned char iv[16]; + int sLen; + int datalen; + + utils_printf("\nAES-CBC-128 enc "); + keybits = AES_KEY_BITS_128; + memset(iv, '0', 16); + + sLen = strlen( + "{\"code\":0,\"message\":\"success\",\"encryptionType\":1," + "\"psk\":\"VI04Eh4N8VgM29U/dnu9cQ==\"}"); + strncpy(dataIn, + "{\"code\":0,\"message\":\"success\",\"encryptionType\":1," + "\"psk\":\"VI04Eh4N8VgM29U/dnu9cQ==\"}", + sLen); + + utils_printf("\nthe data to encrypt(%d):\n", sLen); + for (i = 0; i < sLen; i++) { + HAL_Printf("%02x ", (uint8_t)dataIn[i]); + } + + if (QCLOUD_RET_SUCCESS == utils_aes_cbc((uint8_t *)dataIn, sLen, (uint8_t *)dataIn, sLen + UTILS_AES_BLOCK_LEN, + UTILS_AES_ENCRYPT, key, keybits, iv)) { + utils_printf("\nThe encrypted data is:\n"); + for (i = 0; i < sLen; i++) { + HAL_Printf("%02x ", (uint8_t)dataIn[i]); + } + } + + datalen = sLen + (UTILS_AES_BLOCK_LEN - sLen % UTILS_AES_BLOCK_LEN); + keybits = AES_KEY_BITS_128; + memset(iv, '0', UTILS_AES_BLOCK_LEN); + if (QCLOUD_RET_SUCCESS == + utils_aes_cbc((uint8_t *)dataIn, datalen, (uint8_t *)dataIn, datalen, UTILS_AES_DECRYPT, key, keybits, iv)) { + utils_printf("\nThe decrypted data is:\n"); + for (i = 0; i < datalen; i++) { + // HAL_Printf("%02x ", (uint8_t)dataIn[i]); + if (dataIn[i] == '\0') { + Log_d("payload len:%d", i); + break; + } + HAL_Printf("%c", dataIn[i]); + } + } + + if (ret != 0 && verbose != 0) + utils_printf("failed\n"); + + return (ret); +} + +#endif /* UTILS_SELF_TEST */ + +#endif /* UTILS_AES_C */ + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_base64.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_base64.c new file mode 100644 index 00000000..97495da1 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_base64.c @@ -0,0 +1,183 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qutils_base64.h" + +#include +#include + +static const unsigned char base64_enc_map[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + +static const unsigned char base64_dec_map[128] = { + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 62, + 127, 127, 127, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, 127, 64, 127, 127, 127, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 127, 127, 127, 127, 127}; + +#define BASE64_SIZE_T_MAX ((size_t)-1) /* SIZE_T_MAX is not standard */ + +int qcloud_iot_utils_base64encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen) +{ + size_t i, n; + unsigned char *p; + + if (slen == 0) { + *olen = 0; + return (0); + } + + n = slen / 3 + (slen % 3 != 0); + + if (n > (BASE64_SIZE_T_MAX - 1) / 4) { + *olen = BASE64_SIZE_T_MAX; + return (QCLOUD_ERR_FAILURE); + } + + n *= 4; + + if ((dlen < n + 1) || (NULL == dst)) { + *olen = n + 1; + return (QCLOUD_ERR_FAILURE); + } + + n = (slen / 3) * 3; + + int C1, C2, C3; + for (i = 0, p = dst; i < n; i += 3) { + C1 = *src++; + C2 = *src++; + C3 = *src++; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; + *p++ = base64_enc_map[C3 & 0x3F]; + } + + if (i < slen) { + C1 = *src++; + C2 = ((i + 1) < slen) ? *src++ : 0; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + + if ((i + 1) < slen) + *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; + else + *p++ = '='; + + *p++ = '='; + } + + *olen = p - dst; + *p = 0; + + return (0); +} + +int qcloud_iot_utils_base64decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen) +{ + size_t i, n; + uint32_t j, x; + unsigned char *p; + + /* First pass: check for validity and get output length */ + for (i = n = j = 0; i < slen; i++) { + /* Skip spaces before checking for EOL */ + x = 0; + while (i < slen && src[i] == ' ') { + ++i; + ++x; + } + + /* Spaces at end of buffer are OK */ + if (i == slen) + break; + + if ((slen - i) >= 2 && src[i] == '\r' && src[i + 1] == '\n') + continue; + + if (src[i] == '\n') + continue; + + /* Space inside a line is an error */ + if (x != 0) + return (QCLOUD_ERR_FAILURE); + + if (src[i] == '=' && ++j > 2) + return (QCLOUD_ERR_FAILURE); + + if (src[i] > 127 || base64_dec_map[src[i]] == 127) + return (QCLOUD_ERR_FAILURE); + + if (base64_dec_map[src[i]] < 64 && j != 0) + return (QCLOUD_ERR_FAILURE); + + n++; + } + + if (n == 0) { + *olen = 0; + return (0); + } + + n = ((n * 6) + 7) >> 3; + n -= j; + + if (dst == NULL || dlen < n) { + *olen = n; + return (QCLOUD_ERR_FAILURE); + } + + for (j = 3, n = x = 0, p = dst; i > 0; i--, src++) { + if (*src == '\r' || *src == '\n' || *src == ' ') + continue; + + j -= (base64_dec_map[*src] == 64); + x = (x << 6) | (base64_dec_map[*src] & 0x3F); + + if (++n == 4) { + n = 0; + if (j > 0) + *p++ = (unsigned char)(x >> 16); + if (j > 1) + *p++ = (unsigned char)(x >> 8); + if (j > 2) + *p++ = (unsigned char)(x); + } + } + + *olen = p - dst; + + return (0); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_getopt.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_getopt.c new file mode 100644 index 00000000..fa3989a8 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_getopt.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017-2019 Tencent Group. All rights reserved. + * License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "qutils_getopt.h" + +#include +#include + +#include "qcloud_iot_import.h" + +static int utils_opterr = 1; /* if error message should be printed */ +static int utils_optind = 1; /* index into parent argv vector */ +static int utils_optopt; /* character checked for validity */ +static int utils_optreset = 1; /* reset getopt */ + +char *utils_optarg; /* argument associated with option */ + +int qutils_getopt(int nargc, char *const *nargv, const char *options) +{ +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + + static char *place = EMSG; /* option letter processing */ + const char * oli; /* option letter list index */ + + if (utils_optreset || !*place) { /* update scanning pointer */ + utils_optreset = 0; + + if (utils_optind >= nargc || *(place = nargv[utils_optind]) != '-') { + utils_optind = 1; + utils_optreset = 1; + place = EMSG; + return (-1); + } + + place++; + } + + /* option letter okay? */ + if ((utils_optopt = (int)*place++) == (int)':' || !(oli = strchr(options, utils_optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (utils_optopt == (int)'-') + return (-1); + + if (!*place) + ++utils_optind; + + if (utils_opterr && *options != ':') + HAL_Printf("illegal option - %c\n", utils_optopt); + + return (BADCH); + } + + if (*++oli != ':') { /* don't need argument */ + utils_optarg = NULL; + if (!*place) + ++utils_optind; + } else { + /* need an argument */ + if (*place) /* no white space */ + utils_optarg = place; + else if (nargc <= ++utils_optind) { /* no arg */ + place = EMSG; + if (*options == ':') + return (BADARG); + if (utils_opterr) + HAL_Printf("option requires an argument - %c\n", utils_optopt); + return (BADCH); + } else /* white space */ + utils_optarg = nargv[utils_optind]; + + place = EMSG; + ++utils_optind; + } + + /* dump back option letter */ + return (utils_optopt); +} diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_hmac.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_hmac.c new file mode 100644 index 00000000..3928d580 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_hmac.c @@ -0,0 +1,181 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include "qutils_hmac.h" + +#include + +#include "qcloud_iot_export_log.h" +#include "qutils_md5.h" +#include "qutils_sha1.h" + +#define KEY_IOPAD_SIZE 64 + +#define MD5_DIGEST_SIZE 16 +#define SHA1_DIGEST_SIZE 20 + +void utils_hmac_md5(const char *msg, int msg_len, char *digest, const char *key, int key_len) +{ + if ((NULL == msg) || (NULL == digest) || (NULL == key)) { + Log_e("parameter is Null,failed!"); + return; + } + + if (key_len > KEY_IOPAD_SIZE) { + Log_e("key_len > size(%d) of array", KEY_IOPAD_SIZE); + return; + } + + iot_md5_context context; + unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + unsigned char out[MD5_DIGEST_SIZE]; + int i; + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner MD5 */ + utils_md5_init(&context); /* init context for 1st pass */ + utils_md5_starts(&context); /* setup context for 1st pass */ + utils_md5_update(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */ + utils_md5_update(&context, (unsigned char *)msg, msg_len); /* then text of datagram */ + utils_md5_finish(&context, out); /* finish up 1st pass */ + + /* perform outer MD5 */ + utils_md5_init(&context); /* init context for 2nd pass */ + utils_md5_starts(&context); /* setup context for 2nd pass */ + utils_md5_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */ + utils_md5_update(&context, out, MD5_DIGEST_SIZE); /* then results of 1st hash */ + utils_md5_finish(&context, out); /* finish up 2nd pass */ + + for (i = 0; i < MD5_DIGEST_SIZE; ++i) { + digest[i * 2] = utils_hb2hex(out[i] >> 4); + digest[i * 2 + 1] = utils_hb2hex(out[i]); + } +} + +void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len) +{ + if ((NULL == msg) || (NULL == digest) || (NULL == key)) { + Log_e("parameter is Null,failed!"); + return; + } + + if (key_len > KEY_IOPAD_SIZE) { + Log_e("key_len > size(%d) of array", KEY_IOPAD_SIZE); + return; + } + + iot_sha1_context context; + unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + unsigned char out[SHA1_DIGEST_SIZE]; + int i; + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner SHA */ + utils_sha1_init(&context); /* init context for 1st pass */ + utils_sha1_starts(&context); /* setup context for 1st pass */ + utils_sha1_update(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */ + utils_sha1_update(&context, (unsigned char *)msg, msg_len); /* then text of datagram */ + utils_sha1_finish(&context, out); /* finish up 1st pass */ + + /* perform outer SHA */ + utils_sha1_init(&context); /* init context for 2nd pass */ + utils_sha1_starts(&context); /* setup context for 2nd pass */ + utils_sha1_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */ + utils_sha1_update(&context, out, SHA1_DIGEST_SIZE); /* then results of 1st hash */ + utils_sha1_finish(&context, out); /* finish up 2nd pass */ + + for (i = 0; i < SHA1_DIGEST_SIZE; ++i) { + digest[i * 2] = utils_hb2hex(out[i] >> 4); + digest[i * 2 + 1] = utils_hb2hex(out[i]); + } +} + +int utils_hmac_sha1_hex(const char *msg, int msg_len, char *digest, const char *key, int key_len) +{ + if ((NULL == msg) || (NULL == digest) || (NULL == key)) { + Log_e("parameter is Null,failed!"); + return 0; + } + + if (key_len > KEY_IOPAD_SIZE) { + Log_e("key_len > size(%d) of array", KEY_IOPAD_SIZE); + return 0; + } + + iot_sha1_context context; + unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + unsigned char out[SHA1_DIGEST_SIZE]; + int i; + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner SHA */ + utils_sha1_init(&context); /* init context for 1st pass */ + utils_sha1_starts(&context); /* setup context for 1st pass */ + utils_sha1_update(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */ + utils_sha1_update(&context, (unsigned char *)msg, msg_len); /* then text of datagram */ + utils_sha1_finish(&context, out); /* finish up 1st pass */ + + /* perform outer SHA */ + utils_sha1_init(&context); /* init context for 2nd pass */ + utils_sha1_starts(&context); /* setup context for 2nd pass */ + utils_sha1_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */ + utils_sha1_update(&context, out, SHA1_DIGEST_SIZE); /* then results of 1st hash */ + utils_sha1_finish(&context, out); /* finish up 2nd pass */ + + memcpy(digest, out, SHA1_DIGEST_SIZE); + + return SHA1_DIGEST_SIZE; +} diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_httpc.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_httpc.c new file mode 100644 index 00000000..b9c3ed2e --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_httpc.c @@ -0,0 +1,811 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qutils_httpc.h" + +#include +#include + +#include "qcloud_iot_ca.h" +#include "qcloud_iot_common.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_timer.h" + +#define HTTP_CLIENT_MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define HTTP_CLIENT_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +#define HTTP_CLIENT_AUTHB_SIZE 128 + +#define HTTP_CLIENT_CHUNK_SIZE 1025 +#define HTTP_CLIENT_SEND_BUF_SIZE 1024 + +#define HTTP_CLIENT_MAX_HOST_LEN 64 +#define HTTP_CLIENT_MAX_URL_LEN 1024 + +#define HTTP_RETRIEVE_MORE_DATA (1) + +#if defined(MBEDTLS_DEBUG_C) +#define DEBUG_LEVEL 2 +#endif + +static void _http_client_base64enc(char *out, const char *in) +{ + const char code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + int i = 0, x = 0, l = 0; + + for (; *in; in++) { + x = x << 8 | *in; + for (l += 8; l >= 6; l -= 6) { + out[i++] = code[(x >> (l - 6)) & 0x3f]; + } + } + if (l > 0) { + x <<= 6 - l; + out[i++] = code[x & 0x3f]; + } + for (; i % 4;) { + out[i++] = '='; + } + out[i] = '\0'; +} + +static int _http_client_parse_url(const char *url, char *scheme, uint32_t max_scheme_len, char *host, + uint32_t maxhost_len, int *port, char *path, uint32_t max_path_len) +{ + char * scheme_ptr = (char *)url; + char * host_ptr = (char *)strstr(url, "://"); + uint32_t host_len = 0; + uint32_t path_len; + + char *path_ptr; + char *fragment_ptr; + + if (host_ptr == NULL) { + Log_e("Could not find host"); + return QCLOUD_ERR_HTTP_PARSE; + } + + if (max_scheme_len < host_ptr - scheme_ptr + 1) { + Log_e("Scheme str is too small (%u >= %u)", max_scheme_len, (uint32_t)(host_ptr - scheme_ptr + 1)); + return QCLOUD_ERR_HTTP_PARSE; + } + memcpy(scheme, scheme_ptr, host_ptr - scheme_ptr); + scheme[host_ptr - scheme_ptr] = '\0'; + + host_ptr += 3; + + *port = 0; + + path_ptr = strchr(host_ptr, '/'); + if (NULL == path_ptr) { + path_ptr = scheme_ptr + (int)strlen(url); + host_len = path_ptr - host_ptr; + memcpy(host, host_ptr, host_len); + host[host_len] = '\0'; + + memcpy(path, "/", 1); + path[1] = '\0'; + + return QCLOUD_RET_SUCCESS; + } + + if (host_len == 0) { + host_len = path_ptr - host_ptr; + } + + if (maxhost_len < host_len + 1) { + Log_e("Host str is too long (host_len(%d) >= max_len(%d))", host_len + 1, maxhost_len); + return QCLOUD_ERR_HTTP_PARSE; + } + memcpy(host, host_ptr, host_len); + host[host_len] = '\0'; + + fragment_ptr = strchr(host_ptr, '#'); + if (fragment_ptr != NULL) { + path_len = fragment_ptr - path_ptr; + } else { + path_len = strlen(path_ptr); + } + + if (max_path_len < path_len + 1) { + Log_e("Path str is too small (%d >= %d)", max_path_len, path_len + 1); + return QCLOUD_ERR_HTTP_PARSE; + } + + memcpy(path, path_ptr, path_len); + + path[path_len] = '\0'; + + return QCLOUD_RET_SUCCESS; +} + +static int _http_client_parse_host(const char *url, char *host, uint32_t host_max_len) +{ + const char *host_ptr = (const char *)strstr(url, "://"); + uint32_t host_len = 0; + char * path_ptr; + + if (host_ptr == NULL) { + Log_e("Could not find host"); + return QCLOUD_ERR_HTTP_PARSE; + } + host_ptr += 3; + + uint32_t pro_len = 0; + pro_len = host_ptr - url; + + path_ptr = strchr(host_ptr, '/'); + if (path_ptr != NULL) + host_len = path_ptr - host_ptr; + else + host_len = strlen(url) - pro_len; + + if (host_max_len < host_len + 1) { + Log_e("Host str is too small (%d >= %d)", host_max_len, host_len + 1); + return QCLOUD_ERR_HTTP_PARSE; + } + memcpy(host, host_ptr, host_len); + host[host_len] = '\0'; + + return QCLOUD_RET_SUCCESS; +} + +static int _http_client_get_info(HTTPClient *client, unsigned char *send_buf, int *send_idx, char *buf, uint32_t len) +{ + int rc = QCLOUD_RET_SUCCESS; + int cp_len; + int idx = *send_idx; + + if (len == 0) { + len = strlen(buf); + } + + do { + if ((HTTP_CLIENT_SEND_BUF_SIZE - idx) >= len) { + cp_len = len; + } else { + cp_len = HTTP_CLIENT_SEND_BUF_SIZE - idx; + } + + memcpy(send_buf + idx, buf, cp_len); + idx += cp_len; + len -= cp_len; + + if (idx == HTTP_CLIENT_SEND_BUF_SIZE) { + size_t byte_written_len = 0; + rc = client->network_stack.write(&(client->network_stack), send_buf, HTTP_CLIENT_SEND_BUF_SIZE, 5000, + &byte_written_len); + if (byte_written_len) { + return (byte_written_len); + } + } + } while (len); + + *send_idx = idx; + return rc; +} + +static int _http_client_send_auth(HTTPClient *client, unsigned char *send_buf, int *send_idx) +{ + char b_auth[(int)((HTTP_CLIENT_AUTHB_SIZE + 3) * 4 / 3 + 1)]; + char base64buff[HTTP_CLIENT_AUTHB_SIZE + 3]; + + _http_client_get_info(client, send_buf, send_idx, "Authorization: Basic ", 0); + HAL_Snprintf(base64buff, sizeof(base64buff), "%s:%s", STRING_PTR_PRINT_SANITY_CHECK(client->auth_user), + STRING_PTR_PRINT_SANITY_CHECK(client->auth_password)); + + _http_client_base64enc(b_auth, base64buff); + b_auth[strlen(b_auth) + 1] = '\0'; + b_auth[strlen(b_auth)] = '\n'; + + _http_client_get_info(client, send_buf, send_idx, b_auth, 0); + + return QCLOUD_RET_SUCCESS; +} + +static int _http_client_send_header(HTTPClient *client, const char *url, HttpMethod method, HTTPClientData *client_data) +{ + char scheme[8] = {0}; + char host[HTTP_CLIENT_MAX_HOST_LEN] = {0}; + char path[HTTP_CLIENT_MAX_URL_LEN] = {0}; + int len; + unsigned char send_buf[HTTP_CLIENT_SEND_BUF_SIZE] = {0}; + char buf[HTTP_CLIENT_SEND_BUF_SIZE] = {0}; + char * meth = (method == HTTP_GET) + ? "GET" + : (method == HTTP_POST) + ? "POST" + : (method == HTTP_PUT) + ? "PUT" + : (method == HTTP_DELETE) ? "DELETE" : (method == HTTP_HEAD) ? "HEAD" : ""; + int rc; + int port; + + int res = _http_client_parse_url(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path)); + if (res != QCLOUD_RET_SUCCESS) { + Log_e("httpclient_parse_url returned %d", res); + return res; + } + + if (strcmp(scheme, "http") == 0) { + } else if (strcmp(scheme, "https") == 0) { + } + + memset(send_buf, 0, HTTP_CLIENT_SEND_BUF_SIZE); + len = 0; + + HAL_Snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); + rc = _http_client_get_info(client, send_buf, &len, buf, strlen(buf)); + if (rc) { + Log_e("Could not write request"); + return QCLOUD_ERR_HTTP_CONN; + } + + if (client->auth_user) { + _http_client_send_auth(client, send_buf, &len); + } + + if (client->header) { + _http_client_get_info(client, send_buf, &len, (char *)client->header, strlen(client->header)); + } + + if (client_data->post_buf != NULL) { + HAL_Snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", client_data->post_buf_len); + _http_client_get_info(client, send_buf, &len, buf, strlen(buf)); + + if (client_data->post_content_type != NULL) { + HAL_Snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", client_data->post_content_type); + _http_client_get_info(client, send_buf, &len, buf, strlen(buf)); + } + } + + _http_client_get_info(client, send_buf, &len, "\r\n", 0); + + // Log_d("REQUEST:\n%s", send_buf); + + size_t written_len = 0; + rc = client->network_stack.write(&client->network_stack, send_buf, len, 5000, &written_len); + if (written_len > 0) { + // Log_d("Written %lu bytes", written_len); + } else if (written_len == 0) { + Log_e("written_len == 0,Connection was closed by server"); + return QCLOUD_ERR_HTTP_CLOSED; /* Connection was closed by server */ + } else { + Log_e("Connection error (send returned %d)", rc); + return QCLOUD_ERR_HTTP_CONN; + } + + return QCLOUD_RET_SUCCESS; +} + +static int _http_client_send_userdata(HTTPClient *client, HTTPClientData *client_data, uint32_t timeout_ms) +{ + if (client_data->post_buf && client_data->post_buf_len) { + // Log_d("client_data->post_buf: %s", client_data->post_buf); + { + size_t written_len = 0; + int rc = client->network_stack.write(&client->network_stack, (unsigned char *)client_data->post_buf, + client_data->post_buf_len, timeout_ms, &written_len); + if (written_len > 0) { + // Log_d("Written %d bytes", written_len); + } else if (written_len == 0) { + Log_e("written_len == 0,Connection was closed by server"); + return QCLOUD_ERR_HTTP_CLOSED; + } else { + Log_e("Connection error (send returned %d)", rc); + return QCLOUD_ERR_HTTP_CONN; + } + } + } + + return QCLOUD_RET_SUCCESS; +} + +static int _http_client_recv(HTTPClient *client, char *buf, int min_len, int max_len, int *p_read_len, + uint32_t timeout_ms, HTTPClientData *client_data) +{ + IOT_FUNC_ENTRY; + + int rc = 0; + Timer timer; + size_t recv_size = 0; + + InitTimer(&timer); + countdown_ms(&timer, (unsigned int)timeout_ms); + + *p_read_len = 0; + + rc = client->network_stack.read(&client->network_stack, (unsigned char *)buf, max_len, (uint32_t)left_ms(&timer), + &recv_size); + *p_read_len = (int)recv_size; + if (rc == QCLOUD_ERR_SSL_NOTHING_TO_READ || rc == QCLOUD_ERR_TCP_NOTHING_TO_READ) { + Log_d("HTTP read nothing and timeout"); + rc = QCLOUD_RET_SUCCESS; + } else if (rc == QCLOUD_ERR_SSL_READ_TIMEOUT || rc == QCLOUD_ERR_TCP_READ_TIMEOUT) { + if (*p_read_len == client_data->retrieve_len || client_data->retrieve_len == 0) + rc = QCLOUD_RET_SUCCESS; + else + Log_e("network_stack read timeout"); + } else if (rc == QCLOUD_ERR_TCP_PEER_SHUTDOWN && *p_read_len > 0) { + /* HTTP server give response and close this connection */ + client->network_stack.disconnect(&client->network_stack); + rc = QCLOUD_RET_SUCCESS; + } else if (rc != QCLOUD_RET_SUCCESS) { + Log_e("Connection error rc = %d (recv returned %d)", rc, *p_read_len); + IOT_FUNC_EXIT_RC(rc); + } + + IOT_FUNC_EXIT_RC(rc); +} + +static int _http_client_retrieve_content(HTTPClient *client, char *data, int len, uint32_t timeout_ms, + HTTPClientData *client_data) +{ + IOT_FUNC_ENTRY; + + int count = 0; + int templen = 0; + int crlf_pos; + Timer timer; + + InitTimer(&timer); + countdown_ms(&timer, (unsigned int)timeout_ms); + + client_data->is_more = IOT_TRUE; + + if (client_data->response_content_len == -1 && client_data->is_chunked == IOT_FALSE) { + while (1) { + int rc, max_len; + if (count + len < client_data->response_buf_len - 1) { + memcpy(client_data->response_buf + count, data, len); + count += len; + client_data->response_buf[count] = '\0'; + } else { + memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count); + client_data->response_buf[client_data->response_buf_len - 1] = '\0'; + return HTTP_RETRIEVE_MORE_DATA; + } + + max_len = HTTP_CLIENT_MIN(HTTP_CLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - count); + rc = _http_client_recv(client, data, 1, max_len, &len, (uint32_t)left_ms(&timer), client_data); + + /* Receive data */ + // Log_d("data len: %d %d", len, count); + + if (rc != QCLOUD_RET_SUCCESS) { + IOT_FUNC_EXIT_RC(rc); + } + if (0 == left_ms(&timer)) { + Log_e("HTTP read timeout!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_TIMEOUT); + } + + if (len == 0) { + /* read no more data */ + Log_d("no more data, len == 0"); + client_data->is_more = IOT_FALSE; + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + } + } + } + + while (1) { + uint32_t readLen = 0; + if (client_data->is_chunked && client_data->retrieve_len <= 0) { + /* Read chunk header */ + bool foundCrlf; + int n; + do { + foundCrlf = IOT_FALSE; + crlf_pos = 0; + data[len] = 0; + if (len >= 2) { + for (; crlf_pos < len - 2; crlf_pos++) { + if (data[crlf_pos] == '\r' && data[crlf_pos + 1] == '\n') { + foundCrlf = IOT_TRUE; + break; + } + } + } + if (!foundCrlf) { + /* Try to read more */ + if (len < HTTP_CLIENT_CHUNK_SIZE) { + int new_trf_len, rc; + rc = _http_client_recv(client, data + len, 0, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len, + left_ms(&timer), client_data); + len += new_trf_len; + if (rc != QCLOUD_RET_SUCCESS) { + IOT_FUNC_EXIT_RC(rc); + } else { + continue; + } + } else { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP); + } + } + } while (!foundCrlf); + data[crlf_pos] = '\0'; + + // n = sscanf(data, "%x", &readLen);/* chunk length */ + readLen = strtoul(data, NULL, 16); + n = (0 == readLen) ? 0 : 1; + client_data->retrieve_len = readLen; + client_data->response_content_len += client_data->retrieve_len; + if (readLen == 0) { + client_data->is_more = IOT_FALSE; + Log_d("no more (last chunk)"); + } + + if (n != 1) { + Log_e("Could not read chunk length"); + return QCLOUD_ERR_HTTP_UNRESOLVED_DNS; + } + + memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2)); + len -= (crlf_pos + 2); + + } else { + readLen = client_data->retrieve_len; + } + + do { + templen = HTTP_CLIENT_MIN(len, readLen); + if (count + templen < client_data->response_buf_len - 1) { + memcpy(client_data->response_buf + count, data, templen); + count += templen; + client_data->response_buf[count] = '\0'; + client_data->retrieve_len -= templen; + } else { + memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count); + client_data->response_buf[client_data->response_buf_len - 1] = '\0'; + client_data->retrieve_len -= (client_data->response_buf_len - 1 - count); + IOT_FUNC_EXIT_RC(HTTP_RETRIEVE_MORE_DATA); + } + + if (len > readLen) { + Log_d("memmove %d %d %d\n", readLen, len, client_data->retrieve_len); + memmove(data, &data[readLen], len - readLen); /* chunk case, read between two chunks */ + len -= readLen; + readLen = 0; + client_data->retrieve_len = 0; + } else { + readLen -= len; + } + + if (readLen) { + int rc; + int max_len = HTTP_CLIENT_MIN(HTTP_CLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - count); + max_len = HTTP_CLIENT_MIN(max_len, readLen); + rc = _http_client_recv(client, data, 1, max_len, &len, left_ms(&timer), client_data); + if (rc != QCLOUD_RET_SUCCESS) { + IOT_FUNC_EXIT_RC(rc); + } + if (left_ms(&timer) == 0) { + Log_e("HTTP read timeout!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_TIMEOUT); + } + } + } while (readLen); + + if (client_data->is_chunked) { + if (len < 2) { + int new_trf_len, rc; + /* Read missing chars to find end of chunk */ + rc = _http_client_recv(client, data + len, 2 - len, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len, + left_ms(&timer), client_data); + if ((rc != QCLOUD_RET_SUCCESS) || (0 == left_ms(&timer))) { + IOT_FUNC_EXIT_RC(rc); + } + len += new_trf_len; + } + + if ((data[0] != '\r') || (data[1] != '\n')) { + Log_e("Format error, %s", data); /* after memmove, the beginning of next chunk */ + IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_UNRESOLVED_DNS); + } + memmove(data, &data[2], len - 2); /* remove the \r\n */ + len -= 2; + } else { + // Log_d("no more (content-length)"); + client_data->is_more = IOT_FALSE; + break; + } + } + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +static int _http_client_response_parse(HTTPClient *client, char *data, int len, uint32_t timeout_ms, + HTTPClientData *client_data) +{ + IOT_FUNC_ENTRY; + + int crlf_pos; + Timer timer; + char *tmp_ptr, *ptr_body_end; + + InitTimer(&timer); + countdown_ms(&timer, timeout_ms); + + client_data->response_content_len = -1; + + char *crlf_ptr = strstr(data, "\r\n"); + if (crlf_ptr == NULL) { + Log_e("\\r\\n not found"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_UNRESOLVED_DNS); + } + + crlf_pos = crlf_ptr - data; + data[crlf_pos] = '\0'; + +#if 0 + if (sscanf(data, "HTTP/%*d.%*d %d %*[^\r\n]", &(client->response_code)) != 1) { + Log_e("Not a correct HTTP answer : %s\n", data); + return QCLOUD_ERR_HTTP_UNRESOLVED_DNS; + } +#endif + + client->response_code = atoi(data + 9); + + if ((client->response_code < 200) || (client->response_code >= 400)) { + Log_w("Response code %d", client->response_code); + + if (client->response_code == 403) + IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_AUTH); + + if (client->response_code == 404) + IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_NOT_FOUND); + } + + // Log_d("Reading headers : %s", data); + + // remove null character + memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2) + 1); + len -= (crlf_pos + 2); + + client_data->is_chunked = IOT_FALSE; + + if (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) { + int new_trf_len, rc; + rc = _http_client_recv(client, data + len, 1, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len, left_ms(&timer), + client_data); + if (rc != QCLOUD_RET_SUCCESS) { + IOT_FUNC_EXIT_RC(rc); + } + len += new_trf_len; + data[len] = '\0'; + if (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) { + Log_e("parse error: no end of the request body"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + } + + if (NULL != (tmp_ptr = strstr(data, "Content-Length"))) { + client_data->response_content_len = atoi(tmp_ptr + strlen("Content-Length: ")); + client_data->retrieve_len = client_data->response_content_len; + } else if (NULL != (tmp_ptr = strstr(data, "Transfer-Encoding"))) { + int len_chunk = strlen("Chunked"); + char *chunk_value = data + strlen("Transfer-Encoding: "); + + if ((!memcmp(chunk_value, "Chunked", len_chunk)) || (!memcmp(chunk_value, "chunked", len_chunk))) { + client_data->is_chunked = IOT_TRUE; + client_data->response_content_len = 0; + client_data->retrieve_len = 0; + } + } else { + Log_e("Could not parse header"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP); + } + + len = len - (ptr_body_end + 4 - data); + memmove(data, ptr_body_end + 4, len + 1); + int rc = _http_client_retrieve_content(client, data, len, left_ms(&timer), client_data); + IOT_FUNC_EXIT_RC(rc); +} + +static int _http_client_connect(HTTPClient *client) +{ + if (QCLOUD_RET_SUCCESS != client->network_stack.connect(&client->network_stack)) { + return QCLOUD_ERR_HTTP_CONN; + } + + return QCLOUD_RET_SUCCESS; +} + +static int _http_client_send_request(HTTPClient *client, const char *url, HttpMethod method, + HTTPClientData *client_data) +{ + int rc; + + rc = _http_client_send_header(client, url, method, client_data); + if (rc != 0) { + Log_e("httpclient_send_header is error, rc = %d", rc); + return rc; + } + + if (method == HTTP_POST || method == HTTP_PUT) { + rc = _http_client_send_userdata(client, client_data, 5000); + } + + return rc; +} + +static int _http_client_recv_response(HTTPClient *client, uint32_t timeout_ms, HTTPClientData *client_data) +{ + IOT_FUNC_ENTRY; + + int reclen = 0, rc = QCLOUD_ERR_HTTP_CONN; + char buf[HTTP_CLIENT_CHUNK_SIZE] = {0}; + Timer timer; + + InitTimer(&timer); + countdown_ms(&timer, timeout_ms); + + if (0 == client->network_stack.handle) { + Log_e("Connection has not been established"); + IOT_FUNC_EXIT_RC(rc); + } + + if (client_data->is_more) { + client_data->response_buf[0] = '\0'; + rc = _http_client_retrieve_content(client, buf, reclen, left_ms(&timer), client_data); + } else { + client_data->is_more = IOT_TRUE; + rc = _http_client_recv(client, buf, 1, HTTP_CLIENT_CHUNK_SIZE - 1, &reclen, left_ms(&timer), client_data); + + if (rc != QCLOUD_RET_SUCCESS) { + IOT_FUNC_EXIT_RC(rc); + } + // else if(0 == left_ms(&timer)){ + // IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_TIMEOUT); + //} + + buf[reclen] = '\0'; + + if (reclen) { + // HAL_Printf("RESPONSE:\n%s", buf); + rc = _http_client_response_parse(client, buf, reclen, left_ms(&timer), client_data); + } + } + + IOT_FUNC_EXIT_RC(rc); +} + +static int _http_network_init(Network *pNetwork, const char *host, int port, const char *ca_crt_dir) +{ + int rc = QCLOUD_RET_SUCCESS; + if (pNetwork == NULL) { + return QCLOUD_ERR_INVAL; + } + pNetwork->type = NETWORK_TCP; +#ifndef AUTH_WITH_NOTLS + if (ca_crt_dir != NULL) { + pNetwork->ssl_connect_params.ca_crt = ca_crt_dir; + pNetwork->ssl_connect_params.ca_crt_len = strlen(pNetwork->ssl_connect_params.ca_crt); + pNetwork->ssl_connect_params.timeout_ms = 10000; + pNetwork->type = NETWORK_TLS; + } +#endif + pNetwork->host = host; + pNetwork->port = port; + + rc = network_init(pNetwork); + + return rc; +} + +int qcloud_http_client_connect(HTTPClient *client, const char *url, int port, const char *ca_crt) +{ + if (client->network_stack.handle != 0) { + Log_e("http client has connected to host!"); + return QCLOUD_ERR_HTTP_CONN; + } + + int rc; + char host[HTTP_CLIENT_MAX_HOST_LEN] = {0}; + rc = _http_client_parse_host(url, host, sizeof(host)); + if (rc != QCLOUD_RET_SUCCESS) + return rc; + + rc = _http_network_init(&client->network_stack, host, port, ca_crt); + if (rc != QCLOUD_RET_SUCCESS) + return rc; + + rc = _http_client_connect(client); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("http_client_connect is error,rc = %d", rc); + qcloud_http_client_close(client); + } else { + /* reduce log print due to frequent log server connect/disconnect */ + if (strstr(host, LOG_UPLOAD_SERVER_PATTEN)) + UPLOAD_DBG("http client connect success"); + else + Log_d("http client connect success"); + } + return rc; +} + +void qcloud_http_client_close(HTTPClient *client) +{ + if (client->network_stack.handle != 0) { + client->network_stack.disconnect(&client->network_stack); + } +} + +int qcloud_http_client_common(HTTPClient *client, const char *url, int port, const char *ca_crt, HttpMethod method, + HTTPClientData *client_data) +{ + int rc; + + if (client->network_stack.handle == 0) { + rc = qcloud_http_client_connect(client, url, port, ca_crt); + if (rc != QCLOUD_RET_SUCCESS) + return rc; + } + + rc = _http_client_send_request(client, url, method, client_data); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("http_client_send_request is error,rc = %d", rc); + qcloud_http_client_close(client); + return rc; + } + + return QCLOUD_RET_SUCCESS; +} + +int qcloud_http_recv_data(HTTPClient *client, uint32_t timeout_ms, HTTPClientData *client_data) +{ + IOT_FUNC_ENTRY; + + int rc = QCLOUD_RET_SUCCESS; + Timer timer; + + InitTimer(&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_e("http_client_recv_response is error,rc = %d", rc); + qcloud_http_client_close(client); + IOT_FUNC_EXIT_RC(rc); + } + } + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +int qcloud_http_send_data(HTTPClient *client, HttpMethod method, uint32_t timeout_ms, HTTPClientData *client_data) +{ + int rc = QCLOUD_ERR_INVAL; + if (method == HTTP_POST || method == HTTP_PUT) { + rc = _http_client_send_userdata(client, client_data, timeout_ms); + } + + return rc; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_list.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_list.c new file mode 100644 index 00000000..b99ff6cc --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_list.c @@ -0,0 +1,302 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qutils_list.h" + +#include "qcloud_iot_export_log.h" +#include "qcloud_iot_import.h" + +/* + * create list, return NULL if fail + */ +List *list_new(void) +{ + List *self; + self = (List *)HAL_Malloc(sizeof(List)); + if (!self) { + return NULL; + } + self->head = NULL; + self->tail = NULL; + self->free = NULL; + self->match = NULL; + self->len = 0; + return self; +} + +/* + * destroy list + */ +void list_destroy(List *self) +{ + unsigned int len = self->len; + ListNode * next; + ListNode * curr = self->head; + + while (len--) { + next = curr->next; + if (self->free) { + self->free(curr->val); + } + HAL_Free(curr); + curr = next; + } + + HAL_Free(self); +} + +/* + * push the node to list tail, return NULL if node invalid + */ +ListNode *list_rpush(List *self, ListNode *node) +{ + if (!node) { + return NULL; + } + + if (self->len) { + node->prev = self->tail; + node->next = NULL; + self->tail->next = node; + self->tail = node; + } else { + self->head = self->tail = node; + node->prev = node->next = NULL; + } + + ++self->len; + return node; +} + +/* + * pop the node from list tail, return NULL if list empty + */ +ListNode *list_rpop(List *self) +{ + ListNode *node = NULL; + if (!self->len) { + return NULL; + } + + node = self->tail; + + if (--self->len) { + (self->tail = node->prev)->next = NULL; + } else { + self->tail = self->head = NULL; + } + + node->next = node->prev = NULL; + return node; +} + +/* + * pop the node from list headl, return NULL if list empty + */ +ListNode *list_lpop(List *self) +{ + ListNode *node = NULL; + if (!self->len) { + return NULL; + } + + node = self->head; + + if (--self->len) { + (self->head = node->next)->prev = NULL; + } else { + self->head = self->tail = NULL; + } + + node->next = node->prev = NULL; + return node; +} + +/* + * push the node to list head, return NULL if node invalid + */ +ListNode *list_lpush(List *self, ListNode *node) +{ + if (!node) { + return NULL; + } + + if (self->len) { + node->next = self->head; + node->prev = NULL; + self->head->prev = node; + self->head = node; + } else { + self->head = self->tail = node; + node->prev = node->next = NULL; + } + + ++self->len; + return node; +} + +/* + * find the node via node value, return NULL if not found + */ +ListNode *list_find(List *self, void *val) +{ + ListIterator *it; + ListNode * node; + + if (NULL == (it = list_iterator_new(self, LIST_HEAD))) { + return NULL; + } + node = list_iterator_next(it); + while (node) { + if (self->match) { + if (self->match(val, node->val)) { + list_iterator_destroy(it); + return node; + } + } else { + if (val == node->val) { + list_iterator_destroy(it); + return node; + } + } + node = list_iterator_next(it); + } + + list_iterator_destroy(it); + return NULL; +} + +/* + * find the node via list index, return NULL if not found + */ +ListNode *list_at(List *self, int index) +{ + ListDirection direction = LIST_HEAD; + + if (index < 0) { + direction = LIST_TAIL; + index = ~index; + } + + if ((unsigned)index < self->len) { + ListIterator *it; + ListNode * node; + + if (NULL == (it = list_iterator_new(self, direction))) { + return NULL; + } + node = list_iterator_next(it); + + while (index--) { + node = list_iterator_next(it); + } + list_iterator_destroy(it); + return node; + } + + return NULL; +} + +/* + * delete the node in list and release the resource + */ +void list_remove(List *self, ListNode *node) +{ + node->prev ? (node->prev->next = node->next) : (self->head = node->next); + + node->next ? (node->next->prev = node->prev) : (self->tail = node->prev); + + if (self->free) { + self->free(node->val); + } + + HAL_Free(node); + if (self->len) + --self->len; +} + +/* + * create a new ListIterator and set the ListDirection. + */ +ListIterator *list_iterator_new(List *list, ListDirection direction) +{ + ListNode *node = direction == LIST_HEAD ? list->head : list->tail; + return list_iterator_new_from_node(node, direction); +} + +/* + * create a new ListIterator and set the ListDirection and node + */ +ListIterator *list_iterator_new_from_node(ListNode *node, ListDirection direction) +{ + ListIterator *self; + self = HAL_Malloc(sizeof(ListIterator)); + if (!self) { + return NULL; + } + self->next = node; + self->direction = direction; + return self; +} + +/* + * return next node + */ +ListNode *list_iterator_next(ListIterator *self) +{ + ListNode *curr = self->next; + if (curr) { + self->next = self->direction == LIST_HEAD ? curr->next : curr->prev; + } + return curr; +} + +/* + * release the ListIterator + */ +void list_iterator_destroy(ListIterator *self) +{ + HAL_Free(self); +} + +/* + * create a new node and set the value + */ +ListNode *list_node_new(void *val) +{ + ListNode *self; + self = HAL_Malloc(sizeof(ListNode)); + if (!self) { + return NULL; + } + + self->prev = NULL; + self->next = NULL; + self->val = val; + return self; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_md5.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_md5.c new file mode 100644 index 00000000..ada9accb --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_md5.c @@ -0,0 +1,375 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qutils_md5.h" + +#include +#include + +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" + +#define MD5_DIGEST_SIZE 16 + +/* Implementation that should never be optimized out by the compiler */ +static void _utils_md5_zeroize(void *v, size_t n) +{ + volatile unsigned char *p = v; + while (n--) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef IOT_MD5_GET_UINT32_LE +#define IOT_MD5_GET_UINT32_LE(n, b, i) \ + { \ + (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) | \ + ((uint32_t)(b)[(i) + 3] << 24); \ + } +#endif + +#ifndef IOT_MD5_PUT_UINT32_LE +#define IOT_MD5_PUT_UINT32_LE(n, b, i) \ + { \ + (b)[(i)] = (unsigned char)(((n)) & 0xFF); \ + (b)[(i) + 1] = (unsigned char)(((n) >> 8) & 0xFF); \ + (b)[(i) + 2] = (unsigned char)(((n) >> 16) & 0xFF); \ + (b)[(i) + 3] = (unsigned char)(((n) >> 24) & 0xFF); \ + } +#endif + +void utils_md5_init(iot_md5_context *ctx) +{ + memset(ctx, 0, sizeof(iot_md5_context)); +} + +void utils_md5_free(iot_md5_context *ctx) +{ + if (ctx == NULL) { + return; + } + + _utils_md5_zeroize(ctx, sizeof(iot_md5_context)); +} + +void utils_md5_clone(iot_md5_context *dst, const iot_md5_context *src) +{ + *dst = *src; +} + +/* + * MD5 context setup + */ +void utils_md5_starts(iot_md5_context *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64]) +{ + uint32_t X[16], A, B, C, D; + + IOT_MD5_GET_UINT32_LE(X[0], data, 0); + IOT_MD5_GET_UINT32_LE(X[1], data, 4); + IOT_MD5_GET_UINT32_LE(X[2], data, 8); + IOT_MD5_GET_UINT32_LE(X[3], data, 12); + IOT_MD5_GET_UINT32_LE(X[4], data, 16); + IOT_MD5_GET_UINT32_LE(X[5], data, 20); + IOT_MD5_GET_UINT32_LE(X[6], data, 24); + IOT_MD5_GET_UINT32_LE(X[7], data, 28); + IOT_MD5_GET_UINT32_LE(X[8], data, 32); + IOT_MD5_GET_UINT32_LE(X[9], data, 36); + IOT_MD5_GET_UINT32_LE(X[10], data, 40); + IOT_MD5_GET_UINT32_LE(X[11], data, 44); + IOT_MD5_GET_UINT32_LE(X[12], data, 48); + IOT_MD5_GET_UINT32_LE(X[13], data, 52); + IOT_MD5_GET_UINT32_LE(X[14], data, 56); + IOT_MD5_GET_UINT32_LE(X[15], data, 60); + +#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a, b, c, d, k, s, t) \ + { \ + a += F(b, c, d) + X[k] + t; \ + a = S(a, s) + b; \ + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x, y, z) (z ^ (x & (y ^ z))) + + P(A, B, C, D, 0, 7, 0xD76AA478); + P(D, A, B, C, 1, 12, 0xE8C7B756); + P(C, D, A, B, 2, 17, 0x242070DB); + P(B, C, D, A, 3, 22, 0xC1BDCEEE); + P(A, B, C, D, 4, 7, 0xF57C0FAF); + P(D, A, B, C, 5, 12, 0x4787C62A); + P(C, D, A, B, 6, 17, 0xA8304613); + P(B, C, D, A, 7, 22, 0xFD469501); + P(A, B, C, D, 8, 7, 0x698098D8); + P(D, A, B, C, 9, 12, 0x8B44F7AF); + P(C, D, A, B, 10, 17, 0xFFFF5BB1); + P(B, C, D, A, 11, 22, 0x895CD7BE); + P(A, B, C, D, 12, 7, 0x6B901122); + P(D, A, B, C, 13, 12, 0xFD987193); + P(C, D, A, B, 14, 17, 0xA679438E); + P(B, C, D, A, 15, 22, 0x49B40821); + +#undef F + +#define F(x, y, z) (y ^ (z & (x ^ y))) + + P(A, B, C, D, 1, 5, 0xF61E2562); + P(D, A, B, C, 6, 9, 0xC040B340); + P(C, D, A, B, 11, 14, 0x265E5A51); + P(B, C, D, A, 0, 20, 0xE9B6C7AA); + P(A, B, C, D, 5, 5, 0xD62F105D); + P(D, A, B, C, 10, 9, 0x02441453); + P(C, D, A, B, 15, 14, 0xD8A1E681); + P(B, C, D, A, 4, 20, 0xE7D3FBC8); + P(A, B, C, D, 9, 5, 0x21E1CDE6); + P(D, A, B, C, 14, 9, 0xC33707D6); + P(C, D, A, B, 3, 14, 0xF4D50D87); + P(B, C, D, A, 8, 20, 0x455A14ED); + P(A, B, C, D, 13, 5, 0xA9E3E905); + P(D, A, B, C, 2, 9, 0xFCEFA3F8); + P(C, D, A, B, 7, 14, 0x676F02D9); + P(B, C, D, A, 12, 20, 0x8D2A4C8A); + +#undef F + +#define F(x, y, z) (x ^ y ^ z) + + P(A, B, C, D, 5, 4, 0xFFFA3942); + P(D, A, B, C, 8, 11, 0x8771F681); + P(C, D, A, B, 11, 16, 0x6D9D6122); + P(B, C, D, A, 14, 23, 0xFDE5380C); + P(A, B, C, D, 1, 4, 0xA4BEEA44); + P(D, A, B, C, 4, 11, 0x4BDECFA9); + P(C, D, A, B, 7, 16, 0xF6BB4B60); + P(B, C, D, A, 10, 23, 0xBEBFBC70); + P(A, B, C, D, 13, 4, 0x289B7EC6); + P(D, A, B, C, 0, 11, 0xEAA127FA); + P(C, D, A, B, 3, 16, 0xD4EF3085); + P(B, C, D, A, 6, 23, 0x04881D05); + P(A, B, C, D, 9, 4, 0xD9D4D039); + P(D, A, B, C, 12, 11, 0xE6DB99E5); + P(C, D, A, B, 15, 16, 0x1FA27CF8); + P(B, C, D, A, 2, 23, 0xC4AC5665); + +#undef F + +#define F(x, y, z) (y ^ (x | ~z)) + + P(A, B, C, D, 0, 6, 0xF4292244); + P(D, A, B, C, 7, 10, 0x432AFF97); + P(C, D, A, B, 14, 15, 0xAB9423A7); + P(B, C, D, A, 5, 21, 0xFC93A039); + P(A, B, C, D, 12, 6, 0x655B59C3); + P(D, A, B, C, 3, 10, 0x8F0CCC92); + P(C, D, A, B, 10, 15, 0xFFEFF47D); + P(B, C, D, A, 1, 21, 0x85845DD1); + P(A, B, C, D, 8, 6, 0x6FA87E4F); + P(D, A, B, C, 15, 10, 0xFE2CE6E0); + P(C, D, A, B, 6, 15, 0xA3014314); + P(B, C, D, A, 13, 21, 0x4E0811A1); + P(A, B, C, D, 4, 6, 0xF7537E82); + P(D, A, B, C, 11, 10, 0xBD3AF235); + P(C, D, A, B, 2, 15, 0x2AD7D2BB); + P(B, C, D, A, 9, 21, 0xEB86D391); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +/* + * MD5 process buffer + */ +void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, size_t ilen) +{ + size_t fill; + uint32_t left; + + if (ilen == 0) { + return; + } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t)ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (uint32_t)ilen) { + ctx->total[1]++; + } + + if (left && ilen >= fill) { + memcpy((void *)(ctx->buffer + left), input, fill); + utils_md5_process(ctx, ctx->buffer); + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) { + utils_md5_process(ctx, input); + input += 64; + ilen -= 64; + } + + if (ilen > 0) { + memcpy((void *)(ctx->buffer + left), input, ilen); + } +} + +static const unsigned char iot_md5_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* + * MD5 final digest + */ +void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16]) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + IOT_MD5_PUT_UINT32_LE(low, msglen, 0); + IOT_MD5_PUT_UINT32_LE(high, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + utils_md5_update(ctx, iot_md5_padding, padn); + utils_md5_update(ctx, msglen, 8); + + IOT_MD5_PUT_UINT32_LE(ctx->state[0], output, 0); + IOT_MD5_PUT_UINT32_LE(ctx->state[1], output, 4); + IOT_MD5_PUT_UINT32_LE(ctx->state[2], output, 8); + IOT_MD5_PUT_UINT32_LE(ctx->state[3], output, 12); +} + +/* + * output = MD5( input buffer ) + */ +void utils_md5(const unsigned char *input, size_t ilen, unsigned char output[16]) +{ + iot_md5_context ctx; + + utils_md5_init(&ctx); + utils_md5_starts(&ctx); + utils_md5_update(&ctx, input, ilen); + utils_md5_finish(&ctx, output); + utils_md5_free(&ctx); +} + +int8_t utils_hb2hex(uint8_t hb) +{ + hb = hb & 0xF; + return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a'); +} + +void utils_md5_str(const unsigned char *input, size_t ilen, unsigned char *output) +{ + int i; + unsigned char buf_out[16]; + utils_md5(input, ilen, buf_out); + + // hex to string + for (i = 0; i < 16; ++i) { + output[i * 2] = utils_hb2hex(buf_out[i] >> 4); + output[i * 2 + 1] = utils_hb2hex(buf_out[i]); + } + output[32] = '\0'; +} + +/* + * MD5 create dynamicly + */ +void *utils_md5_create(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 utils_md5_finish_str(void *ctx, char *output_str) +{ + int i; + unsigned char buf_out[16]; + utils_md5_finish(ctx, buf_out); + + for (i = 0; i < 16; ++i) { + output_str[i * 2] = utils_hb2hex(buf_out[i] >> 4); + output_str[i * 2 + 1] = utils_hb2hex(buf_out[i]); + } + output_str[32] = '\0'; +} + +void utils_md5_delete(void *ctx) +{ + HAL_Free(ctx); +} + +void utils_md5_reset(void *ctx) +{ + iot_md5_context *pCtx = (iot_md5_context *)ctx; + + if (!pCtx) { + Log_e("invalid md5 pointer"); + return; + } + + utils_md5_init(pCtx); + utils_md5_starts(pCtx); + return; +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_ringbuff.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_ringbuff.c new file mode 100644 index 00000000..9bf5e14e --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_ringbuff.c @@ -0,0 +1,97 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include "qutils_ringbuff.h" + +#include +#include + +int ring_buff_init(sRingbuff *ring_buff, char *buff, uint32_t size) +{ + ring_buff->buffer = buff; + ring_buff->size = size; + ring_buff->readpoint = 0; + ring_buff->writepoint = 0; + memset(ring_buff->buffer, 0, ring_buff->size); + ring_buff->full = false; + + return RINGBUFF_OK; +} + +int ring_buff_flush(sRingbuff *ring_buff) +{ + ring_buff->readpoint = 0; + ring_buff->writepoint = 0; + memset(ring_buff->buffer, 0, ring_buff->size); + ring_buff->full = false; + + return RINGBUFF_OK; +} + +int ring_buff_push_data(sRingbuff *ring_buff, uint8_t *pData, int len) +{ + int i; + + if (len > ring_buff->size) { + return RINGBUFF_TOO_SHORT; + } + + for (i = 0; i < len; i++) { + if (((ring_buff->writepoint + 1) % ring_buff->size) == ring_buff->readpoint) { + ring_buff->full = true; + return RINGBUFF_FULL; + } else { + if (ring_buff->writepoint < (ring_buff->size - 1)) { + ring_buff->writepoint++; + } else { + ring_buff->writepoint = 0; + } + ring_buff->buffer[ring_buff->writepoint] = pData[i]; + } + } + + return RINGBUFF_OK; +} + +int ring_buff_pop_data(sRingbuff *ring_buff, uint8_t *pData, int len) +{ + int i; + + if (len > ring_buff->size) { + return RINGBUFF_TOO_SHORT; + } + + for (i = 0; i < len; i++) { + if (ring_buff->writepoint == ring_buff->readpoint) { + break; + } else { + if (ring_buff->readpoint == (ring_buff->size - 1)) { + ring_buff->readpoint = 0; + } + + else { + ring_buff->readpoint++; + } + pData[i] = ring_buff->buffer[ring_buff->readpoint]; + } + } + + return i; +} diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_sha1.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_sha1.c new file mode 100644 index 00000000..2976778d --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_sha1.c @@ -0,0 +1,331 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include "qutils_sha1.h" + +#include +#include + +#include "qcloud_iot_export_log.h" +#include "qcloud_iot_import.h" + +/* Implementation that should never be optimized out by the compiler */ +static void utils_sha1_zeroize(void *v, size_t n) +{ + volatile unsigned char *p = v; + while (n--) { + *p++ = 0; + } +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef IOT_SHA1_GET_UINT32_BE +#define IOT_SHA1_GET_UINT32_BE(n, b, i) \ + { \ + (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | \ + ((uint32_t)(b)[(i) + 3]); \ + } +#endif + +#ifndef IOT_SHA1_PUT_UINT32_BE +#define IOT_SHA1_PUT_UINT32_BE(n, b, i) \ + { \ + (b)[(i)] = (unsigned char)((n) >> 24); \ + (b)[(i) + 1] = (unsigned char)((n) >> 16); \ + (b)[(i) + 2] = (unsigned char)((n) >> 8); \ + (b)[(i) + 3] = (unsigned char)((n)); \ + } +#endif + +void utils_sha1_init(iot_sha1_context *ctx) +{ + memset(ctx, 0, sizeof(iot_sha1_context)); +} + +void utils_sha1_free(iot_sha1_context *ctx) +{ + if (ctx == NULL) { + return; + } + + utils_sha1_zeroize(ctx, sizeof(iot_sha1_context)); +} + +void utils_sha1_clone(iot_sha1_context *dst, const iot_sha1_context *src) +{ + *dst = *src; +} + +/* + * SHA-1 context setup + */ +void utils_sha1_starts(iot_sha1_context *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]) +{ + uint32_t temp, W[16], A, B, C, D, E; + + IOT_SHA1_GET_UINT32_BE(W[0], data, 0); + IOT_SHA1_GET_UINT32_BE(W[1], data, 4); + IOT_SHA1_GET_UINT32_BE(W[2], data, 8); + IOT_SHA1_GET_UINT32_BE(W[3], data, 12); + IOT_SHA1_GET_UINT32_BE(W[4], data, 16); + IOT_SHA1_GET_UINT32_BE(W[5], data, 20); + IOT_SHA1_GET_UINT32_BE(W[6], data, 24); + IOT_SHA1_GET_UINT32_BE(W[7], data, 28); + IOT_SHA1_GET_UINT32_BE(W[8], data, 32); + IOT_SHA1_GET_UINT32_BE(W[9], data, 36); + IOT_SHA1_GET_UINT32_BE(W[10], data, 40); + IOT_SHA1_GET_UINT32_BE(W[11], data, 44); + IOT_SHA1_GET_UINT32_BE(W[12], data, 48); + IOT_SHA1_GET_UINT32_BE(W[13], data, 52); + IOT_SHA1_GET_UINT32_BE(W[14], data, 56); + IOT_SHA1_GET_UINT32_BE(W[15], data, 60); + +#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ + (temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], (W[t & 0x0F] = S(temp, 1))) + +#define P(a, b, c, d, e, x) \ + { \ + e += S(a, 5) + F(b, c, d) + K + x; \ + b = S(b, 30); \ + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x, y, z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P(A, B, C, D, E, W[0]); + P(E, A, B, C, D, W[1]); + P(D, E, A, B, C, W[2]); + P(C, D, E, A, B, W[3]); + P(B, C, D, E, A, W[4]); + P(A, B, C, D, E, W[5]); + P(E, A, B, C, D, W[6]); + P(D, E, A, B, C, W[7]); + P(C, D, E, A, B, W[8]); + P(B, C, D, E, A, W[9]); + P(A, B, C, D, E, W[10]); + P(E, A, B, C, D, W[11]); + P(D, E, A, B, C, W[12]); + P(C, D, E, A, B, W[13]); + P(B, C, D, E, A, W[14]); + P(A, B, C, D, E, W[15]); + P(E, A, B, C, D, R(16)); + P(D, E, A, B, C, R(17)); + P(C, D, E, A, B, R(18)); + P(B, C, D, E, A, R(19)); + +#undef K +#undef F + +#define F(x, y, z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P(A, B, C, D, E, R(20)); + P(E, A, B, C, D, R(21)); + P(D, E, A, B, C, R(22)); + P(C, D, E, A, B, R(23)); + P(B, C, D, E, A, R(24)); + P(A, B, C, D, E, R(25)); + P(E, A, B, C, D, R(26)); + P(D, E, A, B, C, R(27)); + P(C, D, E, A, B, R(28)); + P(B, C, D, E, A, R(29)); + P(A, B, C, D, E, R(30)); + P(E, A, B, C, D, R(31)); + P(D, E, A, B, C, R(32)); + P(C, D, E, A, B, R(33)); + P(B, C, D, E, A, R(34)); + P(A, B, C, D, E, R(35)); + P(E, A, B, C, D, R(36)); + P(D, E, A, B, C, R(37)); + P(C, D, E, A, B, R(38)); + P(B, C, D, E, A, R(39)); + +#undef K +#undef F + +#define F(x, y, z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P(A, B, C, D, E, R(40)); + P(E, A, B, C, D, R(41)); + P(D, E, A, B, C, R(42)); + P(C, D, E, A, B, R(43)); + P(B, C, D, E, A, R(44)); + P(A, B, C, D, E, R(45)); + P(E, A, B, C, D, R(46)); + P(D, E, A, B, C, R(47)); + P(C, D, E, A, B, R(48)); + P(B, C, D, E, A, R(49)); + P(A, B, C, D, E, R(50)); + P(E, A, B, C, D, R(51)); + P(D, E, A, B, C, R(52)); + P(C, D, E, A, B, R(53)); + P(B, C, D, E, A, R(54)); + P(A, B, C, D, E, R(55)); + P(E, A, B, C, D, R(56)); + P(D, E, A, B, C, R(57)); + P(C, D, E, A, B, R(58)); + P(B, C, D, E, A, R(59)); + +#undef K +#undef F + +#define F(x, y, z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P(A, B, C, D, E, R(60)); + P(E, A, B, C, D, R(61)); + P(D, E, A, B, C, R(62)); + P(C, D, E, A, B, R(63)); + P(B, C, D, E, A, R(64)); + P(A, B, C, D, E, R(65)); + P(E, A, B, C, D, R(66)); + P(D, E, A, B, C, R(67)); + P(C, D, E, A, B, R(68)); + P(B, C, D, E, A, R(69)); + P(A, B, C, D, E, R(70)); + P(E, A, B, C, D, R(71)); + P(D, E, A, B, C, R(72)); + P(C, D, E, A, B, R(73)); + P(B, C, D, E, A, R(74)); + P(A, B, C, D, E, R(75)); + P(E, A, B, C, D, R(76)); + P(D, E, A, B, C, R(77)); + P(C, D, E, A, B, R(78)); + P(B, C, D, E, A, R(79)); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +/* + * SHA-1 process buffer + */ +void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen) +{ + size_t fill; + uint32_t left; + + if (ilen == 0) { + return; + } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t)ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (uint32_t)ilen) { + ctx->total[1]++; + } + + if (left && ilen >= fill) { + memcpy((void *)(ctx->buffer + left), input, fill); + utils_sha1_process(ctx, ctx->buffer); + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) { + utils_sha1_process(ctx, input); + input += 64; + ilen -= 64; + } + + if (ilen > 0) { + memcpy((void *)(ctx->buffer + left), input, ilen); + } +} + +static const unsigned char iot_sha1_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* + * SHA-1 final digest + */ +void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + IOT_SHA1_PUT_UINT32_BE(high, msglen, 0); + IOT_SHA1_PUT_UINT32_BE(low, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + utils_sha1_update(ctx, iot_sha1_padding, padn); + utils_sha1_update(ctx, msglen, 8); + + IOT_SHA1_PUT_UINT32_BE(ctx->state[0], output, 0); + IOT_SHA1_PUT_UINT32_BE(ctx->state[1], output, 4); + IOT_SHA1_PUT_UINT32_BE(ctx->state[2], output, 8); + IOT_SHA1_PUT_UINT32_BE(ctx->state[3], output, 12); + IOT_SHA1_PUT_UINT32_BE(ctx->state[4], output, 16); +} + +/* + * output = SHA-1( input buffer ) + */ +void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20]) +{ + iot_sha1_context ctx; + + utils_sha1_init(&ctx); + utils_sha1_starts(&ctx); + utils_sha1_update(&ctx, input, ilen); + utils_sha1_finish(&ctx, output); + utils_sha1_free(&ctx); +} diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_timer.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_timer.c new file mode 100644 index 00000000..feabeb9b --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_timer.c @@ -0,0 +1,54 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qutils_timer.h" + +bool expired(Timer *timer) +{ + return HAL_Timer_expired(timer); +} + +void countdown_ms(Timer *timer, unsigned int timeout_ms) +{ + HAL_Timer_countdown_ms(timer, timeout_ms); +} + +void countdown(Timer *timer, unsigned int timeout) +{ + HAL_Timer_countdown(timer, timeout); +} + +int left_ms(Timer *timer) +{ + return HAL_Timer_remain(timer); +} + +void InitTimer(Timer *timer) +{ + HAL_Timer_init(timer); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_url_download.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_url_download.c new file mode 100644 index 00000000..dc000aa9 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_url_download.c @@ -0,0 +1,143 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qutils_url_download.h" + +#include + +#include "qcloud_iot_ca.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_httpc.h" +#include "qutils_param_check.h" + +#define HTTP_HEAD_CONTENT_LEN 256 + +typedef struct { + const char * url; + HTTPClient http; /* http client */ + HTTPClientData http_data; /* http client data */ +} HTTPUrlDownloadHandle; + +void *qcloud_url_download_init(const char *url, uint32_t offset, uint32_t size) +{ + POINTER_SANITY_CHECK(url, NULL); + NUMBERIC_SANITY_CHECK(size, NULL); + + HTTPUrlDownloadHandle *handle = NULL; + + handle = HAL_Malloc(sizeof(HTTPUrlDownloadHandle)); + if (!handle) { + Log_e("allocate for url download handle failed!"); + return NULL; + } + memset(handle, 0, sizeof(HTTPUrlDownloadHandle)); + + handle->http.header = HAL_Malloc(HTTP_HEAD_CONTENT_LEN); + if (!handle->http.header) { + HAL_Free(handle); + Log_e("allocate for http header failed!"); + return NULL; + } + memset(handle->http.header, 0, HTTP_HEAD_CONTENT_LEN); + + HAL_Snprintf(handle->http.header, HTTP_HEAD_CONTENT_LEN, + "Accept: " + "text/html,application/xhtml+xml,application/xml;q=0.9,*/" + "*;q=0.8\r\n" + "Accept-Encoding: gzip, deflate\r\n" + "Range: bytes=%d-%d\r\n", + offset, size); + + Log_d("head_content:%s", handle->http.header); + + handle->url = url; + return handle; +} + +int32_t qcloud_url_download_connect(void *handle, int https_enabled) +{ + IOT_FUNC_ENTRY; + + if (!handle) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL); + } + + HTTPUrlDownloadHandle *pHandle = (HTTPUrlDownloadHandle *)handle; + + int port = 80; + const char *ca_crt = NULL; + + if (strstr(pHandle->url, "https") && https_enabled) { + port = 443; + ca_crt = iot_https_ca_get(); + } + + int32_t rc = qcloud_http_client_common(&pHandle->http, pHandle->url, port, ca_crt, HTTP_GET, &pHandle->http_data); + + IOT_FUNC_EXIT_RC(rc); +} + +int32_t qcloud_url_download_fetch(void *handle, char *buf, uint32_t bufLen, uint32_t timeout_s) +{ + IOT_FUNC_ENTRY; + + if (!handle) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL); + } + + HTTPUrlDownloadHandle *pHandle = (HTTPUrlDownloadHandle *)handle; + pHandle->http_data.response_buf = buf; + pHandle->http_data.response_buf_len = bufLen; + int diff = pHandle->http_data.response_content_len - pHandle->http_data.retrieve_len; + + int rc = qcloud_http_recv_data(&pHandle->http, timeout_s * 1000, &pHandle->http_data); + if (QCLOUD_RET_SUCCESS != rc) { + IOT_FUNC_EXIT_RC(rc); + } + + IOT_FUNC_EXIT_RC(pHandle->http_data.response_content_len - pHandle->http_data.retrieve_len - diff); +} + +int qcloud_url_download_deinit(void *handle) +{ + IOT_FUNC_ENTRY; + + if (!handle) { + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + } + + HTTPUrlDownloadHandle *pHandle = (HTTPUrlDownloadHandle *)handle; + if (pHandle->http.network_stack.is_connected(&pHandle->http.network_stack)) { + pHandle->http.network_stack.disconnect(&pHandle->http.network_stack); + } + HAL_Free(pHandle->http.header); + HAL_Free(pHandle); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_url_upload.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_url_upload.c new file mode 100644 index 00000000..08ada0ef --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/qutils_url_upload.c @@ -0,0 +1,153 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qutils_url_upload.h" + +#include + +#include "qcloud_iot_ca.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_httpc.h" +#include "qutils_param_check.h" + +#define HTTP_HEAD_CONTENT_LEN 256 + +typedef struct { + const char * url; + HTTPClient http; /* http client */ + HTTPClientData http_data; /* http client data */ +} HTTPUrlUploadHandle; + +void *qcloud_url_upload_init(const char *url, uint32_t content_len) +{ + POINTER_SANITY_CHECK(url, NULL); + + HTTPUrlUploadHandle *handle = NULL; + handle = HAL_Malloc(sizeof(HTTPUrlUploadHandle)); + if (!handle) { + Log_e("allocate for url download handle failed!"); + return NULL; + } + memset(handle, 0, sizeof(HTTPUrlUploadHandle)); + + handle->http.header = HAL_Malloc(HTTP_HEAD_CONTENT_LEN); + if (!handle->http.header) { + HAL_Free(handle); + Log_e("allocate for http header failed!"); + return NULL; + } + memset(handle->http.header, 0, HTTP_HEAD_CONTENT_LEN); + + HAL_Snprintf(handle->http.header, HTTP_HEAD_CONTENT_LEN, + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" + "Content-Type: image/jpeg\r\n" + "Content-Length: %d\r\n", + content_len); + + // Log_d("head_content:%s", handle->http.header); + + handle->url = url; + return handle; +} + +int32_t qcloud_url_upload_connect(void *handle, int method) +{ + IOT_FUNC_ENTRY; + + if (!handle) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL); + } + + HTTPUrlUploadHandle *pHandle = (HTTPUrlUploadHandle *)handle; + + int port = 80; + const char *ca_crt = NULL; + + if (strstr(pHandle->url, "https")) { + port = 443; + ca_crt = iot_https_ca_get(); + } + + pHandle->http_data.post_buf_len = 0; + pHandle->http_data.post_buf = NULL; // only send head + int rc = + qcloud_http_client_common(&pHandle->http, pHandle->url, port, ca_crt, (HttpMethod)method, &pHandle->http_data); + + IOT_FUNC_EXIT_RC(rc); +} + +int32_t qcloud_url_upload_body(void *handle, char *data_buf, uint32_t data_Len, uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + + if (!handle) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL); + } + + HTTPUrlUploadHandle *pHandle = (HTTPUrlUploadHandle *)handle; + pHandle->http_data.post_buf = data_buf; + pHandle->http_data.post_buf_len = data_Len; + int rc = qcloud_http_send_data(&pHandle->http, HTTP_PUT, timeout_ms, &pHandle->http_data); + + IOT_FUNC_EXIT_RC(rc); +} + +int32_t qcloud_url_upload_recv_response(void *handle, char *response_buf, uint32_t bufLen, uint32_t timeout_ms) +{ + IOT_FUNC_ENTRY; + + if (!handle) { + IOT_FUNC_EXIT_RC(QCLOUD_ERR_INVAL); + } + + HTTPUrlUploadHandle *pHandle = (HTTPUrlUploadHandle *)handle; + pHandle->http_data.response_buf = response_buf; + pHandle->http_data.response_buf_len = bufLen; + int rc = qcloud_http_recv_data(&pHandle->http, timeout_ms, &pHandle->http_data); + + IOT_FUNC_EXIT_RC(rc); +} + +int qcloud_url_upload_deinit(void *handle) +{ + IOT_FUNC_ENTRY; + + if (!handle) { + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); + } + + HTTPUrlUploadHandle *pHandle = (HTTPUrlUploadHandle *)handle; + if (pHandle->http.network_stack.is_connected(&pHandle->http.network_stack)) { + pHandle->http.network_stack.disconnect(&pHandle->http.network_stack); + } + HAL_Free(pHandle->http.header); + HAL_Free(pHandle); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/resource_client.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/resource_client.c new file mode 100644 index 00000000..a47b1d89 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/resource_client.c @@ -0,0 +1,1304 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "resource_client.h" +#include "service_mqtt.h" +#include "qcloud_iot_export.h" +#include "qutils_param_check.h" + +#include "qutils_timer.h" +#include "qutils_md5.h" +#include "qutils_list.h" +#include "qutils_url_download.h" +#include "qutils_url_upload.h" +#include "json_parser.h" + +#include "qutils_httpc.h" +#include "qcloud_iot_ca.h" + +#if ((defined(ASR_ENABLED)) && (!defined OTA_USE_HTTPS)) +#error ASR NEED HTTPS ENABLE +#endif + +#define FIELD_TYPE "type" +#define FIELD_MD5 "md5sum" +#define FIELD_VERSION "version" +#define FIELD_URL "url" +#define FIELD_FILE_SIZE "file_size" +#define FIELD_RESULT "result_code" +#define FIELD_RESOURCE_NAME "resource_name" +#define FIELD_FILE_TYPE "resource_type" +#define FIELD_RESOURCE_URL "resource_url" +#define FIELD_RESOURCE_TOKEN "resource_token" +#define FIELD_REQUEST_ID "request_id" + +#define MSG_REPORT_LEN (256) + +typedef struct { + const char *product_id; /* point to product id */ + const char *device_name; /* point to device name */ + + uint32_t id; /* message id */ + IOT_RES_StateCode state; /* 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 *url; /* point to URL */ + char *version; /* point to string */ + char *file_name; /* point to string */ + char *file_type; /* point to string */ + char md5sum[33]; /* MD5 string */ + + void *md5; /* MD5 handle */ + void *ch_signal; /* channel handle of signal exchanged with server */ + void *ch_fetch; /* channel handle of download */ + + int request_id; + void *mutex; + List *res_wait_post_list; + void *usr_context; + + int err; /* last error code */ + int report_rc; /* result of _resource_report_upgrade_result in IOT_Resource_FetchYield*/ + Timer report_timer; + + OnResourceEventUsrCallback usr_cb; +} ResourceHandle; + +typedef struct { + int request_id; + char *res_name; + char *res_version; + char *res_type; + Timer post_timer; +} ResPostInfo; + +/*====================funtion ===================*/ +char *strdup(const char *src) +{ + size_t len = strlen(src) + 1; + char * ret = HAL_Malloc(len); + if (ret != NULL) { + strcpy(ret, src); + } + + return ret; +} + +/* static function*/ +static int _gen_resource_ver_info(char *buf, size_t bufLen, uint16_t res_num, resInfo *res_list[]) +{ + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + + resInfo *pInfo = NULL; + + int ret; + int pos; + int i; + + ret = HAL_Snprintf(buf, bufLen, "{\"method\":\"report_version\",\"report\":{\"resource_list\":["); + if (ret < 0) { + Log_e("HAL_Snprintf failed"); + return QCLOUD_ERR_FAILURE; + } + + for (i = 0; i < res_num; i++) { + pInfo = res_list[i]; + if (!pInfo) { + Log_e("version list invalid"); + return QCLOUD_ERR_FAILURE; + } + + ret = + HAL_Snprintf(buf + strlen(buf), bufLen - strlen(buf), + "{\"resource_name\":\"%s\",\"version\":\"%s\",\"resource_type\":\"%s\"},", + STRING_PTR_PRINT_SANITY_CHECK(pInfo->res_name), STRING_PTR_PRINT_SANITY_CHECK(pInfo->res_ver), + STRING_PTR_PRINT_SANITY_CHECK(pInfo->res_type)); + if (ret < 0) { + Log_e("HAL_Snprintf failed"); + return QCLOUD_ERR_FAILURE; + } + } + + pos = (i > 0) ? 1 : 0; + + ret = HAL_Snprintf(buf + strlen(buf) - pos, bufLen - strlen(buf), "]}}"); + if (ret < 0) { + Log_e("HAL_Snprintf failed"); + return QCLOUD_ERR_FAILURE; + } + + return QCLOUD_RET_SUCCESS; +} + +static int _gen_resource_report_msg(char *buf, size_t bufLen, const char *file_name, const char *version, + const char *type, int progress, IOT_RES_ReportType reportType) +{ + IOT_FUNC_ENTRY; + + int ret; + + switch (reportType) { + /* report download begin */ + case IOT_RES_TYPE_DOWNLOAD_BEGIN: + ret = HAL_Snprintf(buf, bufLen, + "{\"method\": \"report_progress\", \"report\": {\"progress\": " + "{\"resource_name\":\"%s\",\"state\":\"downloading\", \"percent\":\"0\", " + "\"result_code\":\"0\", \"result_msg\":\"\"}, \"version\": \"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name), STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + /* report download progress */ + case IOT_RES_TYPE_DOWNLOADING: + ret = HAL_Snprintf(buf, bufLen, + "{\"method\": \"report_progress\", \"report\": {\"progress\": " + "{\"resource_name\":\"%s\",\"state\":\"downloading\", \"percent\":\"%d\", " + "\"result_code\":\"0\", \"result_msg\":\"\"}, \"version\": \"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name), progress, + STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + + case IOT_RES_TYPE_SPACE_NOT_ENOUGH: + ret = HAL_Snprintf(buf, bufLen, + "{\"method\": \"report_result\", \"report\": {\"progress\": " + "{\"resource_name\":\"%s\",\"state\":\"done\", \"result_code\":\"%d\", " + "\"result_msg\":\"space not enough\"}, \"version\": \"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name), reportType, + STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + + case IOT_RES_TYPE_MD5_NOT_MATCH: + ret = HAL_Snprintf(buf, bufLen, + "{\"method\": \"report_result\", \"report\": {\"progress\": " + "{\"resource_name\":\"%s\",\"state\":\"done\", \"result_code\":\"%d\", " + "\"result_msg\":\"md5 check fail\"}, \"version\": \"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name), reportType, + STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + + case IOT_RES_TYPE_DOWNLOAD_TIMEOUT: + case IOT_RES_TYPE_FILE_NOT_EXIST: + case IOT_RES_TYPE_AUTH_FAIL: + case IOT_RES_TYPE_UPGRADE_FAIL: + ret = HAL_Snprintf(buf, bufLen, + "{\"method\": \"report_result\", \"report\": {\"progress\": " + "{\"resource_name\":\"%s\",\"state\":\"done\", \"result_code\":\"%d\", " + "\"result_msg\":\"time_out\"}, \"version\": \"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name), reportType, + STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + + case IOT_RES_TYPE_UPGRADE_BEGIN: + ret = HAL_Snprintf(buf, bufLen, + "{\"method\": \"report_progress\", " + "\"report\":{\"progress\":{\"resource_name\":\"%s\",\"state\":\"burning\", " + "\"result_code\":\"0\", \"result_msg\":\"\"}, \"version\":\"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name), STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + + /* report OTA upgrade finish */ + case IOT_RES_TYPE_UPGRADE_SUCCESS: + ret = HAL_Snprintf(buf, bufLen, + "{\"method\":\"report_result\", " + "\"report\":{\"progress\":{\"resource_name\":\"%s\",\"state\":\"done\", " + "\"result_code\":\"0\",\"result_msg\":\"success\"}, \"version\":\"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name), STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + + case IOT_RES_TYPE_FILE_DEL_SUCCESS: + ret = HAL_Snprintf( + buf, bufLen, + "{\"method\": \"del_result\", \"report\":{\"progress\":{\"resource_name\":\"%s\",\"state\":\"done\", " + "\"result_code\":\"0\", \"result_msg\":\"success\"}, \"version\":\"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name), STRING_PTR_PRINT_SANITY_CHECK(version)); + break; + + case IOT_RES_TYPE_FILE_DEL_FAIL: + ret = HAL_Snprintf( + buf, bufLen, + "{\"method\": \"del_result\", \"report\":{\"progress\":{\"resource_name\":\"%s\",\"state\":\"done\", " + "\"result_code\":\"%d\", \"result_msg\":\"file del fail\"}, \"version\":\"%s\"}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name), reportType, STRING_PTR_PRINT_SANITY_CHECK(version)); + + break; + + case IOT_RES_TYPE_REQUEST_URL: + ret = HAL_Snprintf(buf, bufLen, + "{\"method\":\"request_url\",\"request_id\":\"%d\"," + "\"report\":{\"resource_name\":\"%s\",\"version\":\"%s\",\"resource_type\":\"%s\"}}", + progress, STRING_PTR_PRINT_SANITY_CHECK(file_name), + STRING_PTR_PRINT_SANITY_CHECK(version), STRING_PTR_PRINT_SANITY_CHECK(type)); + + break; + + case IOT_RES_TYPE_POST_SUCCESS: + ret = HAL_Snprintf(buf, bufLen, + "{\"method\":\"report_post_result\",\"report\":{\"progress\":{\"resource_token\":\"%s\"," + "\"state\":\"done\",\"result_code\":\"0\", \"result_msg\":\"success\"}}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name)); + + break; + + case IOT_RES_TYPE_POST_FAIL: + ret = HAL_Snprintf(buf, bufLen, + "{\"method\":\"report_post_result\",\"report\":{\"progress\":{\"resource_token\":\"%s\"," + "\"state\":\"done\",\"result_code\":\"-1\", \"result_msg\":\"post_fail\"}}}", + STRING_PTR_PRINT_SANITY_CHECK(file_name)); + break; + + default: + IOT_FUNC_EXIT_RC(IOT_RES_ERR_FAIL); + break; + } + + if (ret < 0) { + Log_e("HAL_Snprintf failed"); + IOT_FUNC_EXIT_RC(IOT_RES_ERR_FAIL); + } else if (ret >= bufLen) { + Log_e("msg is too long"); + IOT_FUNC_EXIT_RC(IOT_RES_ERR_STR_TOO_LONG); + } + + IOT_FUNC_EXIT_RC(IOT_RES_ERR_NONE); +} + +static void _reset_handle_status(void *handle) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + + Log_i("reset resource handle state!"); + + pHandle->state = IOT_RES_STATE_INITTED; + pHandle->err = 0; + + HAL_Free(pHandle->url); + pHandle->url = NULL; + + HAL_Free(pHandle->version); + pHandle->version = NULL; + + HAL_Free(pHandle->file_name); + pHandle->file_name = NULL; + + HAL_Free(pHandle->file_type); + pHandle->file_type = NULL; + + utils_md5_reset(pHandle->md5); +} + +static int _resource_report_progress(void *handle, int progress, IOT_RES_ReportType reportType) +{ + int ret = QCLOUD_ERR_FAILURE; + char * msg_reported = NULL; + ResourceHandle *pHandle = (ResourceHandle *)handle; + + if (IOT_RES_STATE_UNINITTED == pHandle->state) { + Log_e("handle is uninitialized"); + pHandle->err = IOT_OTA_ERR_INVALID_STATE; + return QCLOUD_ERR_FAILURE; + } + + if (NULL == (msg_reported = HAL_Malloc(MSG_REPORT_LEN))) { + Log_e("allocate for msg_reported failed"); + pHandle->err = IOT_OTA_ERR_NOMEM; + return QCLOUD_ERR_FAILURE; + } + + ret = _gen_resource_report_msg(msg_reported, MSG_REPORT_LEN, pHandle->file_name, pHandle->version, NULL, progress, + reportType); + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("generate resource inform message failed"); + pHandle->err = ret; + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + + ret = qcloud_service_mqtt_post_msg(pHandle->ch_signal, msg_reported, QOS0); + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("Report progress failed"); + pHandle->err = IOT_RES_ERR_REPORT_PROGRESS; + goto exit; + } + + ret = QCLOUD_RET_SUCCESS; + +exit: + + HAL_Free(msg_reported); + + return ret; +} + +static int _resource_report_upgrade_result(void *handle, const char *version, IOT_RES_ReportType reportType) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + + int ret, len; + char *msg_upgrade = NULL; + + if (IOT_RES_STATE_UNINITTED == pHandle->state) { + Log_e("handle is uninitialized"); + pHandle->err = IOT_RES_ERR_INVALID_STATE; + return QCLOUD_ERR_FAILURE; + } + + version = (version == NULL) ? pHandle->version : version; + + if (!version) { + Log_e("version is null!"); + pHandle->err = IOT_RES_ERR_INVALID_PARAM; + return QCLOUD_ERR_INVAL; + } + + len = strlen(version); + if ((len < RESOURCE_VERSION_STR_LEN_MIN) || (len > RESOURCE_VERSION_STR_LEN_MAX)) { + Log_e("version string is invalid: must be [1, 32] chars"); + pHandle->err = IOT_RES_ERR_INVALID_PARAM; + return QCLOUD_ERR_INVAL; + } + + if (NULL == (msg_upgrade = HAL_Malloc(MSG_REPORT_LEN))) { + Log_e("allocate for msg_informed failed"); + pHandle->err = IOT_OTA_ERR_NOMEM; + return QCLOUD_ERR_FAILURE; + } + + ret = _gen_resource_report_msg(msg_upgrade, MSG_REPORT_LEN, pHandle->file_name, version, NULL, 1, reportType); + if (ret != 0) { + Log_e("generate resource inform message failed"); + pHandle->err = ret; + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + + ret = qcloud_service_mqtt_post_msg(pHandle->ch_signal, msg_upgrade, QOS1); + if (0 > ret) { + Log_e("Report result failed"); + pHandle->err = IOT_RES_ERR_REPORT_UPGRADE_RESULT; + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + +exit: + if ((IOT_RES_TYPE_DOWNLOAD_BEGIN != reportType) && (IOT_RES_TYPE_DOWNLOADING != reportType) && + (IOT_RES_TYPE_UPGRADE_BEGIN != reportType) && (IOT_RES_TYPE_NONE != reportType)) { + _reset_handle_status(pHandle); + } + HAL_Free(msg_upgrade); + return ret; +} + +static int _resource_report_post_result(void *handle, const char *res_token, IOT_RES_ReportType reportType) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + int ret; + char * msg_post = NULL; + + if (IOT_RES_STATE_UNINITTED == pHandle->state) { + Log_e("handle is uninitialized"); + pHandle->err = IOT_RES_ERR_INVALID_STATE; + return QCLOUD_ERR_FAILURE; + } + + if (NULL == (msg_post = HAL_Malloc(MSG_REPORT_LEN))) { + Log_e("allocate for msg_informed failed"); + pHandle->err = IOT_OTA_ERR_NOMEM; + return QCLOUD_ERR_FAILURE; + } + + ret = _gen_resource_report_msg(msg_post, MSG_REPORT_LEN, res_token, NULL, NULL, 0, reportType); + if (ret != 0) { + Log_e("generate resource inform message failed"); + pHandle->err = ret; + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + + ret = qcloud_service_mqtt_post_msg(pHandle->ch_signal, msg_post, QOS1); + if (0 > ret) { + Log_e("Report result failed"); + pHandle->err = IOT_RES_ERR_REPORT_UPGRADE_RESULT; + ret = QCLOUD_ERR_FAILURE; + goto exit; + } + +exit: + if ((IOT_RES_TYPE_DOWNLOAD_BEGIN != reportType) && (IOT_RES_TYPE_DOWNLOADING != reportType) && + (IOT_RES_TYPE_UPGRADE_BEGIN != reportType) && (IOT_RES_TYPE_NONE != reportType) && + (IOT_RES_TYPE_POST_SUCCESS != reportType) && (IOT_RES_TYPE_POST_FAIL != reportType)) { + _reset_handle_status(pHandle); + } + HAL_Free(msg_post); + return ret; +} + +static int _add_resouce_info_to_post_list(void *handle, ResPostInfo *info) +{ + IOT_FUNC_ENTRY; + ResourceHandle *pHandle = (ResourceHandle *)handle; + + HAL_MutexLock(pHandle->mutex); + if (pHandle->res_wait_post_list->len >= MAX_RES_WAIT_POST) { + HAL_MutexUnlock(pHandle->mutex); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_APPENDING_REQUEST); + } + + ListNode *node = list_node_new(info); + if (NULL == node) { + HAL_MutexUnlock(pHandle->mutex); + Log_e("run list_node_new is error!"); + IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE); + } + list_rpush(pHandle->res_wait_post_list, node); + HAL_MutexUnlock(pHandle->mutex); + + IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS); +} + +static ResPostInfo *_get_resource_info_by_request_id(void *handle, int request_id) +{ + POINTER_SANITY_CHECK(handle, NULL); + + ResourceHandle *pHandle = (ResourceHandle *)handle; + ResPostInfo * info = NULL; + HAL_MutexLock(pHandle->mutex); + if (pHandle->res_wait_post_list->len) { + ListIterator *iter; + ListNode * node = NULL; + + if (NULL == (iter = list_iterator_new(pHandle->res_wait_post_list, LIST_TAIL))) { + HAL_MutexUnlock(pHandle->mutex); + return NULL; + } + + for (;;) { + node = list_iterator_next(iter); + if (NULL == node) { + break; + } + + if (NULL == node->val) { + Log_e("node's value is invalid!"); + list_remove(pHandle->res_wait_post_list, node); + continue; + } + info = (ResPostInfo *)node->val; + + if (info->request_id == request_id) { + break; + } else { + if (expired(&info->post_timer)) { + list_remove(pHandle->res_wait_post_list, node); + } + info = NULL; + } + } + + list_iterator_destroy(iter); + } + HAL_MutexUnlock(pHandle->mutex); + + return info; +} + +static int _post_resource_to_cos(const char *resource_url, ResPostInfo *info) +{ +#define PER_CHRUNK_READ_SIZE (6400) // 200ms/16K/16bit ~ 6.4KB +#define COS_REPLY_TIMEOUT_MS (500) + + int rc = QCLOUD_ERR_FAILURE; + char *data_buf = NULL; + void *pUploadHandle = NULL; + + Log_d("post %s(%d) %s to cos", STRING_PTR_PRINT_SANITY_CHECK(info->res_name), info->request_id, + STRING_PTR_PRINT_SANITY_CHECK(info->res_version)); + void *fp = HAL_FileOpen(info->res_name, "rb"); + if (NULL == fp) { + Log_e("can not open file %s!", STRING_PTR_PRINT_SANITY_CHECK(info->res_name)); + return QCLOUD_ERR_FAILURE; + } + + long file_size = HAL_FileSize(fp); + pUploadHandle = qcloud_url_upload_init(resource_url, file_size); + if (!pUploadHandle) { + Log_e("Initialize upload handle failed"); + goto exit; + } + + rc = qcloud_url_upload_connect(pUploadHandle, HTTP_PUT); + if (QCLOUD_RET_SUCCESS != rc) { + Log_e("upload handle connect failed"); + goto exit; + } + + data_buf = (char *)HAL_Malloc(PER_CHRUNK_READ_SIZE); + memset(data_buf, 0, PER_CHRUNK_READ_SIZE); + if (!data_buf) { + Log_e("malloc data_buff fail"); + goto exit; + } + + while (!HAL_FileEof(fp) && file_size > 0) { + int data_len = (file_size > PER_CHRUNK_READ_SIZE) ? PER_CHRUNK_READ_SIZE : file_size; + int read_len = HAL_FileRead(data_buf, 1, data_len, fp); + if (data_len != read_len) { + Log_e("Read file wrong, read_len %d(%d)", read_len, data_len); + rc = QCLOUD_ERR_FAILURE; + goto exit; + } + file_size -= read_len; + + rc = qcloud_url_upload_body(pUploadHandle, data_buf, read_len, 5000); + if (QCLOUD_RET_SUCCESS != rc) { + Log_e("send data failed"); + goto exit; + } + } + Log_d("post file to cos over!"); + + memset(data_buf, 0, PER_CHRUNK_READ_SIZE); + rc = qcloud_url_upload_recv_response(pUploadHandle, data_buf, PER_CHRUNK_READ_SIZE, COS_REPLY_TIMEOUT_MS); + if (QCLOUD_RET_SUCCESS != rc) { + Log_e("Failed to recv response %d", rc); + } + // Log_d("response:%s", data_buf); + +exit: + + if (fp) { + HAL_FileClose(fp); + } + + if (data_buf) { + HAL_Free(data_buf); + } + + if (pUploadHandle) { + qcloud_url_upload_deinit(pUploadHandle); + } + + return rc; + +#undef PER_CHRUNK_READ_SIZE +#undef COS_REPLY_TIMEOUT_MS +} + +/* callback when resource topic msg is received */ +static void _resource_msg_callback(void *handle, const char *msg, uint32_t msg_len) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + char * json_method = NULL; + char * json_str = (char *)msg; + int rc; + + if (pHandle->state >= IOT_RES_STATE_FETCHING) { + Log_i("In downloading or downloaded state(%d)", pHandle->state); + goto exit; + } + + if (json_str == NULL || msg_len <= 0) { + Log_e("OTA response message is NULL"); + return; + } + + json_method = LITE_json_value_of(FIELD_METHOD, json_str); + + if (!json_method) { + Log_e("Get resource method failed!"); + goto exit; + } + + Log_d("method: %s", json_method); + if (!strcmp(json_method, METHOD_RES_REPORT_VERSION_RSP)) { // report version resp + char *result_code = LITE_json_value_of(FIELD_RESULT, json_str); + + if (strcmp(result_code, "0") != 0 || !result_code) { + Log_e("Report resource version failed!"); + pHandle->err = IOT_RES_ERR_REPORT_VERSION; + pHandle->state = IOT_RES_STATE_FETCHED; + } else { + Log_i("Report resource version success!"); + pHandle->usr_cb(pHandle->usr_context, json_str, msg_len, IOT_RES_EVENT_REPORT_VERSION_RESP); + } + + HAL_Free(result_code); + goto exit; + } else if (strcmp(json_method, METHOD_RES_UPDATE_RESOURCE) == 0) { // update resource + pHandle->version = LITE_json_value_of(FIELD_VERSION, json_str); + pHandle->url = LITE_json_value_of(FIELD_URL, json_str); + pHandle->file_name = LITE_json_value_of(FIELD_RESOURCE_NAME, json_str); + pHandle->file_type = LITE_json_value_of(FIELD_FILE_TYPE, json_str); + + char *md5 = LITE_json_value_of(FIELD_MD5, json_str); + char *file_size = LITE_json_value_of(FIELD_FILE_SIZE, json_str); + + if (!pHandle->version || !pHandle->url || !pHandle->file_name || !pHandle->file_type || !md5 || !file_size) { + Log_e("Get resource parameter failed"); + HAL_Free(md5); + HAL_Free(file_size); + _resource_report_upgrade_result(pHandle, pHandle->version, IOT_RES_TYPE_FILE_NOT_EXIST); + goto exit; + } + + // copy md5sum + strncpy(pHandle->md5sum, md5, 33); + HAL_Free(md5); + + // copy file_size + pHandle->size_file = atoi(file_size); + HAL_Free(file_size); + + Log_d("res_para: file_name:%s, file_size:%d, md5:%s, version:%s, url:%s", pHandle->file_name, + pHandle->size_file, pHandle->md5sum, pHandle->version, pHandle->url); + pHandle->state = IOT_RES_STATE_FETCHING; + } else if (strcmp(json_method, METHOD_RES_DELETE_RESOURCE) == 0) { // delete resource + + pHandle->state = IOT_RES_STATE_DELETING; + + pHandle->version = LITE_json_value_of(FIELD_VERSION, json_str); + pHandle->file_type = LITE_json_value_of(FIELD_FILE_TYPE, json_str); + pHandle->file_name = LITE_json_value_of(FIELD_RESOURCE_NAME, json_str); + + if (!pHandle->version || !pHandle->file_type || !pHandle->file_name) { + Log_e("Get resource parameter failed"); + // this will call _reset_handle_status and free the memory + _resource_report_upgrade_result(pHandle, pHandle->version, IOT_RES_TYPE_FILE_DEL_FAIL); + goto exit; + } + rc = pHandle->usr_cb(pHandle->usr_context, pHandle->file_name, strlen(pHandle->file_name), + IOT_RES_EVENT_DEL_RESOURCE); + if (0 != rc) { + Log_e("Delete resource file(%s) fail", pHandle->file_name); + _resource_report_upgrade_result(pHandle, pHandle->version, IOT_RES_TYPE_FILE_DEL_FAIL); + goto exit; + } else { + _resource_report_upgrade_result(pHandle, pHandle->version, IOT_RES_TYPE_FILE_DEL_SUCCESS); + } + } else if (strcmp(json_method, METHOD_RES_REQ_URL_RESP) == 0) { + char *request_id = LITE_json_value_of(FIELD_REQUEST_ID, json_str); + if (!request_id) { + Log_e("no request_id found"); + goto exit; + } + uint32_t id = atoi(request_id); + ResPostInfo *info = _get_resource_info_by_request_id(handle, id); + if (info) { + char *res_token = LITE_json_value_of(FIELD_RESOURCE_TOKEN, json_str); + if (!res_token) { + Log_e("parse request_token fail"); + HAL_Free(request_id); + goto exit; + } + char *res_url = LITE_json_value_of(FIELD_RESOURCE_URL, json_str); + if (!res_url) { + Log_e("parse request_url fail"); + HAL_Free(request_id); + HAL_Free(res_url); + goto exit; + } + + int ret = _post_resource_to_cos(res_url, info); + if (ret == QCLOUD_RET_SUCCESS) { + _resource_report_post_result(pHandle, res_token, IOT_RES_TYPE_POST_SUCCESS); + } else { + _resource_report_post_result(pHandle, res_token, IOT_RES_TYPE_POST_FAIL); + } + + char res_msg[MSG_REPORT_LEN]; + HAL_Snprintf(res_msg, MSG_REPORT_LEN, + "{\"resource_token\": \"%s\",\"request_id\": \"%s\", \"result\": \"%d\"}", res_token, + request_id, ret); + Log_d("res_msg:%s", res_msg); + pHandle->usr_cb(pHandle->usr_context, json_str, msg_len, IOT_RES_EVENT_REQUEST_URL_RESP); + HAL_Free(res_token); + HAL_Free(res_url); + HAL_Free(info->res_name); + HAL_Free(info->res_version); + HAL_MutexLock(pHandle->mutex); + list_remove(pHandle->res_wait_post_list, list_find(pHandle->res_wait_post_list, info)); + HAL_MutexUnlock(pHandle->mutex); + } else { + Log_e("request_id %s not found", request_id); + } + + HAL_Free(request_id); + } else { + Log_e("invalid method:%s", json_method); + } + +exit: + HAL_Free(json_method); +} + +/* init & destroy */ +void *IOT_Resource_Init(const char *product_id, const char *device_name, void *mqtt_client, + OnResourceEventUsrCallback usr_cb, void *usr_context) +{ + POINTER_SANITY_CHECK(product_id, NULL); + POINTER_SANITY_CHECK(device_name, NULL); + POINTER_SANITY_CHECK(mqtt_client, NULL); + int rc; + + ResourceHandle *handle; + handle = HAL_Malloc(sizeof(ResourceHandle)); + if (!handle) { + Log_e("allocate failed"); + goto exit; + } + + memset(handle, 0, sizeof(ResourceHandle)); + handle->usr_cb = usr_cb; + handle->ch_signal = mqtt_client; + + // init service + rc = qcloud_service_mqtt_init(product_id, device_name, mqtt_client); + if (rc < 0) { + Log_e("service init failed: %d", rc); + goto exit; + } + + rc = qcloud_service_mqtt_event_register(eSERVICE_RESOURCE, _resource_msg_callback, handle); + if (QCLOUD_RET_SUCCESS != rc) { + Log_e("register service event %d fail", eSERVICE_RESOURCE); + goto exit; + } + + handle->md5 = utils_md5_create(); + if (!handle->md5) { + Log_e("initialize md5 failed"); + goto exit; + } + + handle->product_id = product_id; + handle->device_name = device_name; + handle->state = IOT_RES_STATE_INITTED; + handle->usr_context = usr_context; + handle->request_id = 0; + handle->res_wait_post_list = list_new(); + if (handle->res_wait_post_list) { + handle->res_wait_post_list->free = HAL_Free; + } else { + Log_e("create res_wait_post_list fail"); + goto exit; + } + + handle->mutex = HAL_MutexCreate(); + if (handle->mutex == NULL) { + Log_e("create res mutex fail"); + goto exit; + } + + return handle; + +exit: + qcloud_service_mqtt_event_register(eSERVICE_RESOURCE, NULL, NULL); + if (handle) { + if (handle->md5) { + utils_md5_delete(handle->md5); + } + + if (handle->res_wait_post_list) { + list_destroy(handle->res_wait_post_list); + } + + if (handle->mutex) { + HAL_MutexDestroy(handle->mutex); + } + + HAL_Free(handle); + } + return NULL; +} + +int IOT_Resource_Destroy(void *handle) +{ + POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL); + + ResourceHandle *pHandle = (ResourceHandle *)handle; + + if (!pHandle) { + Log_e("handle is NULL"); + return QCLOUD_ERR_INVAL; + } + + if (IOT_RES_STATE_UNINITTED == pHandle->state) { + Log_e("handle is uninitialized"); + pHandle->err = IOT_RES_ERR_INVALID_STATE; + return QCLOUD_ERR_FAILURE; + } + + qcloud_service_mqtt_event_register(eSERVICE_RESOURCE, NULL, NULL); + qcloud_url_download_deinit(pHandle->ch_fetch); + utils_md5_delete(pHandle->md5); + if (pHandle->res_wait_post_list) { + list_destroy(pHandle->res_wait_post_list); + } + + if (pHandle) { + HAL_Free(pHandle->url); + HAL_Free(pHandle->version); + HAL_Free(pHandle->file_name); + HAL_Free(pHandle->file_type); + HAL_Free(pHandle); + } + + return QCLOUD_RET_SUCCESS; +} + +/* md5 function */ +void IOT_Resource_UpdateClientMd5(void *handle, char *buff, uint32_t size) +{ + POINTER_SANITY_CHECK_RTN(handle); + POINTER_SANITY_CHECK_RTN(buff); + + ResourceHandle *pHandle = (ResourceHandle *)handle; + utils_md5_update(pHandle->md5, (const unsigned char *)buff, size); +} + +int IOT_Resource_ResetClientMD5(void *handle) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + + utils_md5_delete(pHandle->md5); + pHandle->md5 = utils_md5_create(); + if (!pHandle->md5) { + return QCLOUD_ERR_FAILURE; + } + return QCLOUD_RET_SUCCESS; +} + +/* download */ +int IOT_Resource_StartDownload(void *handle, uint32_t offset, uint32_t size) +{ + POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL); + + ResourceHandle *pHandle = (ResourceHandle *)handle; + + int ret; + + Log_d("to download FW from offset: %u, size: %u", offset, size); + pHandle->size_fetched = offset; + + if (offset == 0) { + ret = IOT_Resource_ResetClientMD5(pHandle); + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("initialize md5 failed"); + return QCLOUD_ERR_FAILURE; + } + } + + qcloud_url_download_deinit(pHandle->ch_fetch); + pHandle->ch_fetch = qcloud_url_download_init(pHandle->url, offset, size); + if (!pHandle->ch_fetch) { + Log_e("Initialize fetch module failed"); + return QCLOUD_ERR_FAILURE; + } + +#ifdef OTA_USE_HTTPS + ret = qcloud_url_download_connect(pHandle->ch_fetch, 1); +#else + ret = qcloud_url_download_connect(pHandle->ch_fetch, 0); +#endif + + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("Connect fetch module failed"); + pHandle->state = IOT_RES_STATE_DISCONNECTED; + } + + return ret; +} + +int IOT_Resource_IsFetching(void *handle) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + + if (!handle) { + Log_e("handle is NULL"); + return 0; + } + + if (IOT_RES_STATE_UNINITTED == pHandle->state) { + Log_e("handle is uninitialized"); + pHandle->err = IOT_RES_ERR_INVALID_STATE; + return 0; + } + + return (IOT_RES_STATE_FETCHING == pHandle->state); +} + +int IOT_Resource_IsFetchFinish(void *handle) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + + if (!handle) { + Log_e("handle is NULL"); + return 0; + } + + if (IOT_RES_STATE_UNINITTED == pHandle->state) { + Log_e("handle is uninitialized"); + pHandle->err = IOT_RES_ERR_INVALID_STATE; + return 0; + } + + return (IOT_RES_STATE_FETCHED == pHandle->state); +} + +int IOT_Resource_FetchYield(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s) +{ + int ret; + ResourceHandle *pHandle = (ResourceHandle *)handle; + + POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + NUMBERIC_SANITY_CHECK(buf_len, QCLOUD_ERR_INVAL); + + if (IOT_RES_STATE_FETCHING != pHandle->state) { + pHandle->err = IOT_RES_ERR_INVALID_STATE; + return QCLOUD_ERR_FAILURE; + } + + ret = qcloud_url_download_fetch(pHandle->ch_fetch, buf, buf_len, timeout_s); + if (ret < 0) { + pHandle->state = IOT_RES_STATE_FETCHED; + pHandle->err = IOT_RES_ERR_FETCH_FAILED; + if (ret == QCLOUD_ERR_HTTP_AUTH) { // OTA auth failed + pHandle->report_rc = _resource_report_upgrade_result(pHandle, pHandle->version, IOT_RES_TYPE_AUTH_FAIL); + pHandle->err = IOT_RES_ERR_FETCH_AUTH_FAIL; + } else if (ret == QCLOUD_ERR_HTTP_NOT_FOUND) { // fetch not existed + pHandle->report_rc = + _resource_report_upgrade_result(pHandle, pHandle->version, IOT_RES_TYPE_FILE_NOT_EXIST); + pHandle->err = IOT_RES_ERR_FETCH_NOT_EXIST; + } else if (ret == QCLOUD_ERR_HTTP_TIMEOUT) { // fetch timeout + pHandle->report_rc = + _resource_report_upgrade_result(pHandle, pHandle->version, IOT_RES_TYPE_DOWNLOAD_TIMEOUT); + pHandle->err = IOT_RES_ERR_FETCH_TIMEOUT; + } + return ret; + } else if (0 == pHandle->size_fetched) { + /* force report status in the first */ + _resource_report_progress(pHandle, 0, IOT_RES_TYPE_DOWNLOAD_BEGIN); + + InitTimer(&pHandle->report_timer); + countdown(&pHandle->report_timer, 1); + } + + pHandle->size_last_fetched = ret; + pHandle->size_fetched += ret; + + /* report percent every second. */ + uint32_t percent = (pHandle->size_fetched * 100) / pHandle->size_file; + if (percent == 100) { + _resource_report_progress(pHandle, percent, IOT_RES_TYPE_DOWNLOADING); + } else if (pHandle->size_last_fetched > 0 && expired(&pHandle->report_timer)) { + _resource_report_progress(pHandle, percent, IOT_RES_TYPE_DOWNLOADING); + countdown(&pHandle->report_timer, 1); + } + + if (pHandle->size_fetched >= pHandle->size_file) { + pHandle->state = IOT_RES_STATE_FETCHED; + } + + utils_md5_update(pHandle->md5, (const unsigned char *)buf, ret); + return ret; +} + +/* report */ +int IOT_Resource_ReportVersion(void *handle, uint16_t res_num, resInfo *res_list[]) +{ + POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL); + + ResourceHandle *pHandle = (ResourceHandle *)handle; + + int ret = QCLOUD_RET_SUCCESS; + int buff_len; + char *msg_informed = NULL; + + if (res_num && !res_list) { + Log_e("Invalid argument res_list"); + return QCLOUD_ERR_INVAL; + } + + if (IOT_RES_STATE_UNINITTED == pHandle->state) { + Log_e("handle is uninitialized"); + pHandle->err = IOT_RES_ERR_INVALID_STATE; + ret = QCLOUD_ERR_FAILURE; + goto do_exit; + } + + _reset_handle_status(pHandle); + + buff_len = res_num * RESOURCE_INFO_LEN_MAX + 128; + if (NULL == (msg_informed = HAL_Malloc(buff_len))) { + Log_e("allocate for msg_informed failed"); + pHandle->err = IOT_RES_ERR_MALLOC; + ret = QCLOUD_ERR_MALLOC; + goto do_exit; + } + + ret = _gen_resource_ver_info(msg_informed, buff_len, res_num, res_list); + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("generate inform message failed"); + pHandle->err = ret; + ret = QCLOUD_ERR_FAILURE; + goto do_exit; + } + + ret = qcloud_service_mqtt_post_msg(pHandle->ch_signal, msg_informed, QOS1); + if (0 > ret) { + Log_e("Report version failed"); + pHandle->err = IOT_RES_ERR_REPORT_VERSION; + ret = QCLOUD_ERR_FAILURE; + goto do_exit; + } + +do_exit: + HAL_Free(msg_informed); + + return ret; +} + +int IOT_Resource_ReportUpgradeBegin(void *handle) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + return _resource_report_upgrade_result(handle, pHandle->version, IOT_RES_TYPE_UPGRADE_BEGIN); +} + +int IOT_Resource_ReportUpgradeSuccess(void *handle, const char *version) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + int ret; + + if (!version) { + ret = _resource_report_upgrade_result(handle, pHandle->version, IOT_RES_TYPE_UPGRADE_SUCCESS); + } else { + ret = _resource_report_upgrade_result(handle, version, IOT_RES_TYPE_UPGRADE_SUCCESS); + } + + return ret; +} + +int IOT_Resource_ReportUpgradeFail(void *handle, const char *version) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + int ret; + + if (!version) { + ret = _resource_report_upgrade_result(handle, pHandle->version, IOT_RES_TYPE_UPGRADE_FAIL); + } else { + ret = _resource_report_upgrade_result(handle, version, IOT_RES_TYPE_UPGRADE_FAIL); + } + + return ret; +} + +int IOT_Resource_ReportSpaceNotEnough(void *handle, const char *version) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + int ret; + + if (!version) { + ret = _resource_report_upgrade_result(handle, pHandle->version, IOT_RES_TYPE_SPACE_NOT_ENOUGH); + } else { + ret = _resource_report_upgrade_result(handle, version, IOT_RES_TYPE_SPACE_NOT_ENOUGH); + } + + return ret; +} + +/* get status*/ +int IOT_Resource_Ioctl(void *handle, IOT_RES_CmdType type, void *buf, size_t buf_len) +{ + ResourceHandle *pHandle = (ResourceHandle *)handle; + + POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL); + POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL); + NUMBERIC_SANITY_CHECK(buf_len, QCLOUD_ERR_INVAL); + + if (pHandle->state < IOT_RES_STATE_FETCHING) { + pHandle->err = IOT_RES_ERR_INVALID_STATE; + return QCLOUD_ERR_FAILURE; + } + + switch (type) { + case IOT_RES_CMD_FETCHED_SIZE: + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + Log_e("Invalid parameter"); + pHandle->err = IOT_RES_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } else { + *((uint32_t *)buf) = pHandle->size_fetched; + return 0; + } + + case IOT_RES_CMD_FILE_SIZE: + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + Log_e("Invalid parameter"); + pHandle->err = IOT_RES_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } else { + *((uint32_t *)buf) = pHandle->size_file; + break; + } + + case IOT_RES_CMD_FILE_TYPE: + strncpy(buf, pHandle->file_type, buf_len); + ((char *)buf)[buf_len - 1] = '\0'; + break; + + case IOT_RES_CMD_VERSION: + strncpy(buf, pHandle->version, buf_len); + ((char *)buf)[buf_len - 1] = '\0'; + break; + + case IOT_RES_CMD_MD5SUM: + strncpy(buf, pHandle->md5sum, buf_len); + ((char *)buf)[buf_len - 1] = '\0'; + break; + + case IOT_RES_CMD_FILE_NAME: + strncpy(buf, pHandle->file_name, buf_len); + ((char *)buf)[buf_len - 1] = '\0'; + break; + + case IOT_RES_CMD_CHECK_FIRMWARE: + if ((4 != buf_len) || (0 != ((unsigned long)buf & 0x3))) { + Log_e("Invalid parameter"); + pHandle->err = IOT_RES_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } else if (pHandle->state != IOT_RES_STATE_FETCHED) { + pHandle->err = IOT_RES_ERR_INVALID_STATE; + Log_e("Firmware can be checked in IOT_RES_STATE_FETCHED state only"); + return QCLOUD_ERR_FAILURE; + } else { + char md5_str[33]; + utils_md5_finish_str(pHandle->md5, md5_str); + Log_d("origin=%s, now=%s", pHandle->md5sum, md5_str); + if (0 == strcmp(pHandle->md5sum, md5_str)) { + *((uint32_t *)buf) = 1; + } else { + *((uint32_t *)buf) = 0; + // report MD5 inconsistent + _resource_report_upgrade_result(pHandle, pHandle->version, IOT_RES_TYPE_MD5_NOT_MATCH); + } + return 0; + } + + default: + Log_e("invalid cmd type"); + pHandle->err = IOT_RES_ERR_INVALID_PARAM; + return QCLOUD_ERR_FAILURE; + } + + return 0; +} + +int IOT_Resource_GetLastError(void *handle) +{ + POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM); + ResourceHandle *pHandle = (ResourceHandle *)handle; + + return pHandle->err; +} + +int IOT_Resource_GetReportResult(void *handle) +{ + POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM); + ResourceHandle *pHandle = (ResourceHandle *)handle; + + return pHandle->report_rc; +} + +int IOT_Resource_Post_Request(void *handle, uint32_t timeout_ms, const char *res_name, char *res_version, + char *res_type) +{ + POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM); + ResourceHandle *pHandle = (ResourceHandle *)handle; + char * msg_reported = NULL; + int ret = QCLOUD_RET_SUCCESS; + + pHandle->request_id++; + + ResPostInfo *info = (ResPostInfo *)HAL_Malloc(sizeof(ResPostInfo)); + info->request_id = pHandle->request_id; + info->res_name = strdup(res_name); + info->res_version = strdup(res_version); + info->res_type = strdup(res_type); + InitTimer(&(info->post_timer)); + countdown(&(info->post_timer), timeout_ms); + ret = _add_resouce_info_to_post_list(handle, info); + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("add resource to post list fail,rc:%d", ret); + goto exit; + } + + if (NULL == (msg_reported = HAL_Malloc(MSG_REPORT_LEN))) { + Log_e("allocate for msg_reported failed"); + ret = QCLOUD_ERR_MALLOC; + goto exit; + } + + char *file_name_post = strrchr(res_name, '/'); + if (!file_name_post) { + file_name_post = (char *)res_name; + } else { + file_name_post += 1; + } + ret = _gen_resource_report_msg(msg_reported, MSG_REPORT_LEN, file_name_post, res_version, res_type, + pHandle->request_id, IOT_RES_TYPE_REQUEST_URL); + if (QCLOUD_RET_SUCCESS != ret) { + Log_e("generate resource inform message failed"); + goto exit; + } + Log_d("request:%s", msg_reported); + ret = qcloud_service_mqtt_post_msg(pHandle->ch_signal, msg_reported, QOS1); + if (ret < 0) { + Log_e("Request url msg publish failed"); + goto exit; + } + +exit: + + if (msg_reported) { + HAL_Free(msg_reported); + } + + return (ret < 0) ? ret : pHandle->request_id; +} + +int IOT_Resource_Report_Msg(void *handle, char *msg) +{ + POINTER_SANITY_CHECK(handle, IOT_OTA_ERR_INVALID_PARAM); + ResourceHandle *pHandle = (ResourceHandle *)handle; + + return qcloud_service_mqtt_post_msg(pHandle->ch_signal, msg, QOS0); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/service_mqtt.c b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/service_mqtt.c new file mode 100644 index 00000000..ac19313e --- /dev/null +++ b/customer_app/bl602_demo_qcloud/components/qcloud_iot_c_sdk/sdk_src/service_mqtt.c @@ -0,0 +1,250 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "mqtt_client.h" +#include "service_mqtt.h" +#include "json_parser.h" + + +typedef struct { + eServiceEvent eventid; + OnServiceMessageCallback callback; + void *context; +} Service_Event_Struct_t; + +static Service_Event_Struct_t sg_service_event_map[] = { + {eSERVICE_RESOURCE, NULL, NULL}, + {eSERVICE_FACE_AI, NULL, NULL} +}; + +static char sg_service_pub_topic[MAX_SIZE_OF_CLOUD_TOPIC]; + +/* gen service topic: "$thing/down/service/$(product_id)/$(device_name)" */ +static int _gen_service_mqtt_topic_info(const char *productId, const char *deviceName, char *sub_topic) +{ + int ret; + + memset(sg_service_pub_topic, '\0', MAX_SIZE_OF_CLOUD_TOPIC); + ret = HAL_Snprintf(sg_service_pub_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/up/service/%s/%s", + STRING_PTR_PRINT_SANITY_CHECK(productId), STRING_PTR_PRINT_SANITY_CHECK(deviceName)); + if (ret < 0) { + goto exit; + } + ret = HAL_Snprintf(sub_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$thing/down/service/%s/%s", + STRING_PTR_PRINT_SANITY_CHECK(productId), STRING_PTR_PRINT_SANITY_CHECK(deviceName)); + +exit: + + return ret; +} + +static char *_get_service_mqtt_topic_info(void) +{ + return sg_service_pub_topic; +} + +static Service_Event_Struct_t *_get_service_event_handle(eServiceEvent evt) +{ + if ( evt >= sizeof(sg_service_event_map) / sizeof(sg_service_event_map[0])) { + return NULL; + } + + return &sg_service_event_map[evt]; +} + +static int _set_service_event_handle(eServiceEvent evt, OnServiceMessageCallback callback, void *context) +{ + if (evt >= sizeof(sg_service_event_map) / sizeof(sg_service_event_map[0])) { + return QCLOUD_ERR_INVAL; + } + + sg_service_event_map[evt].callback = callback; + sg_service_event_map[evt].context = context; + + return QCLOUD_RET_SUCCESS; +} + +static eServiceEvent _service_mqtt_parse_event(char *method) +{ + eServiceEvent evt; + + if (!strcmp(method, METHOD_RES_REPORT_VERSION_RSP) || !strcmp(method, METHOD_RES_UPDATE_RESOURCE) || + !strcmp(method, METHOD_RES_DELETE_RESOURCE) || !strcmp(method, METHOD_RES_REQ_URL_RESP)) { + evt = eSERVICE_RESOURCE; + } else if (!strcmp(method, METHOD_FACE_AI_REPLY)) { + evt = eSERVICE_FACE_AI; + } else { + Log_i("not support service method %s", STRING_PTR_PRINT_SANITY_CHECK(method)); + evt = eSERVICE_DEFAULT; + } + + return evt; +} + +/* callback after resource topic is subscribed */ +static void _service_mqtt_cb(void *pClient, MQTTMessage *message, void *pContext) +{ + int len = message->payload_len; + + Log_d("topic=%.*s", message->topic_len, message->ptopic); + Log_d("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload); + + //parse msg and dispatch to event callback according to sg_service_event_map + char *recv_payload = HAL_Malloc(message->payload_len + 1); + if(!recv_payload){ + Log_e("malloc %dbytes mem fail", message->payload_len); + return; + } + memset(recv_payload, '\0', len + 1); + strncpy(recv_payload, message->payload, len); + char * json_method = LITE_json_value_of(FIELD_METHOD, recv_payload); + if(json_method){ + eServiceEvent event = _service_mqtt_parse_event(json_method); + Service_Event_Struct_t *handle = _get_service_event_handle(event); + if(handle->callback) { + handle->callback(handle->context, recv_payload, len); + } + HAL_Free(json_method); + }else{ + Log_e("no method found"); + } + + HAL_Free(recv_payload); +} + +static int _service_mqtt_publish(void *mqtt_client, int qos, const char *msg) +{ + int ret; + PublishParams pub_params = DEFAULT_PUB_PARAMS; + + if (0 == qos) { + pub_params.qos = QOS0; + } else { + pub_params.qos = QOS1; + } + pub_params.payload = (void *)msg; + pub_params.payload_len = strlen(msg); + ret = IOT_MQTT_Publish(mqtt_client, _get_service_mqtt_topic_info(), &pub_params); + if (ret < 0) { + Log_e("publish to topic: %s failed", _get_service_mqtt_topic_info()); + } + + return ret; +} + +static void _service_mqtt_sub_event_handler(void *pClient, MQTTEventType event_type, void *pUserData) +{ + switch (event_type) { + case MQTT_EVENT_SUBCRIBE_SUCCESS: + Log_d("resource topic subscribe success"); + break; + + case MQTT_EVENT_SUBCRIBE_TIMEOUT: + Log_i("resource topic subscribe timeout"); + break; + + case MQTT_EVENT_SUBCRIBE_NACK: + Log_i("resource topic subscribe NACK"); + break; + case MQTT_EVENT_UNSUBSCRIBE: + Log_i("resource topic has been unsubscribed"); + break; + case MQTT_EVENT_CLIENT_DESTROY: + Log_i("mqtt client has been destroyed"); + break; + + default: + return; + } +} + +int qcloud_service_mqtt_init(const char *productId, const char *deviceName, void *mqtt_client) +{ + int ret; + + char topic_name[MAX_SIZE_OF_CLOUD_TOPIC]; + memset(topic_name, '\0', MAX_SIZE_OF_CLOUD_TOPIC); + ret = _gen_service_mqtt_topic_info(productId, deviceName, topic_name); + if(ret < 0){ + Log_e("gen service topic fail"); + } + + if (IOT_MQTT_IsSubReady(mqtt_client, topic_name)) { + Log_d("%s has been already subscribed", topic_name); + return QCLOUD_RET_SUCCESS; + } + + SubscribeParams sub_params = DEFAULT_SUB_PARAMS; + sub_params.on_message_handler = _service_mqtt_cb; + sub_params.on_sub_event_handler = _service_mqtt_sub_event_handler; + sub_params.qos = QOS1; + + ret = IOT_MQTT_Subscribe(mqtt_client, topic_name, &sub_params); + if (ret < 0) { + Log_e("service topic subscribe failed!"); + return QCLOUD_ERR_FAILURE; + } + + int wait_cnt = 10; + while (!IOT_MQTT_IsSubReady(mqtt_client, topic_name) && (wait_cnt > 0)) { + // wait for subscription result + ret = IOT_MQTT_Yield(mqtt_client, 1000); + if (ret) { + Log_e("mqtt yield error: %d", ret); + return ret; + } + wait_cnt--; + } + + if (wait_cnt == 0) { + Log_e("service topic subscribe timeout!"); + return QCLOUD_ERR_FAILURE; + } + + return QCLOUD_RET_SUCCESS; +} + +void qcloud_service_mqtt_deinit(void *mqtt_client) +{ + if (mqtt_client) { + IOT_MQTT_Unsubscribe(mqtt_client, _get_service_mqtt_topic_info()); + } +} + +int qcloud_service_mqtt_post_msg(void *mqtt_client, const char *msg, int qos) +{ + return _service_mqtt_publish(mqtt_client, qos, msg); +} + +int qcloud_service_mqtt_event_register(eServiceEvent evt, OnServiceMessageCallback callback, void *context) +{ + return _set_service_event_handle(evt, callback, context); +} + +#ifdef __cplusplus +} +#endif diff --git a/customer_app/bl602_demo_qcloud/deviceinfo.jpg b/customer_app/bl602_demo_qcloud/deviceinfo.jpg new file mode 100644 index 00000000..72b8808e Binary files /dev/null and b/customer_app/bl602_demo_qcloud/deviceinfo.jpg differ diff --git a/customer_app/bl602_demo_qcloud/genromap b/customer_app/bl602_demo_qcloud/genromap new file mode 100644 index 00000000..31d3ab20 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/genromap @@ -0,0 +1,3 @@ +#!/bin/sh +make CONFIG_CHIP_NAME=BL602 CONFIG_LINK_ROM=1 -j +exit $? diff --git a/customer_app/bl602_demo_qcloud/logo.png b/customer_app/bl602_demo_qcloud/logo.png new file mode 100644 index 00000000..859f106d Binary files /dev/null and b/customer_app/bl602_demo_qcloud/logo.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image1.png b/customer_app/bl602_demo_qcloud/picture/image1.png new file mode 100644 index 00000000..da8004ed Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image1.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image10.png b/customer_app/bl602_demo_qcloud/picture/image10.png new file mode 100644 index 00000000..7aaa65f1 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image10.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image11.png b/customer_app/bl602_demo_qcloud/picture/image11.png new file mode 100644 index 00000000..436aab46 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image11.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image12.png b/customer_app/bl602_demo_qcloud/picture/image12.png new file mode 100644 index 00000000..05ded52b Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image12.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image13.png b/customer_app/bl602_demo_qcloud/picture/image13.png new file mode 100644 index 00000000..709c3be2 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image13.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image14.png b/customer_app/bl602_demo_qcloud/picture/image14.png new file mode 100644 index 00000000..df2f9e35 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image14.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image15.png b/customer_app/bl602_demo_qcloud/picture/image15.png new file mode 100644 index 00000000..1fbef494 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image15.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image16.png b/customer_app/bl602_demo_qcloud/picture/image16.png new file mode 100644 index 00000000..380c04ab Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image16.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image17.png b/customer_app/bl602_demo_qcloud/picture/image17.png new file mode 100644 index 00000000..2d346e65 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image17.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image18.png b/customer_app/bl602_demo_qcloud/picture/image18.png new file mode 100644 index 00000000..2c24587c Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image18.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image19.png b/customer_app/bl602_demo_qcloud/picture/image19.png new file mode 100644 index 00000000..aa1244a6 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image19.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image2.png b/customer_app/bl602_demo_qcloud/picture/image2.png new file mode 100644 index 00000000..13f7eae6 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image2.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image20.png b/customer_app/bl602_demo_qcloud/picture/image20.png new file mode 100644 index 00000000..ada0b589 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image20.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image21.png b/customer_app/bl602_demo_qcloud/picture/image21.png new file mode 100644 index 00000000..0a91540f Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image21.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image22.png b/customer_app/bl602_demo_qcloud/picture/image22.png new file mode 100644 index 00000000..6db43d4a Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image22.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image23.png b/customer_app/bl602_demo_qcloud/picture/image23.png new file mode 100644 index 00000000..7aaa65f1 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image23.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image24.png b/customer_app/bl602_demo_qcloud/picture/image24.png new file mode 100644 index 00000000..6fd1c145 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image24.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image25.png b/customer_app/bl602_demo_qcloud/picture/image25.png new file mode 100644 index 00000000..7138f410 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image25.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image26.png b/customer_app/bl602_demo_qcloud/picture/image26.png new file mode 100644 index 00000000..df2f9e35 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image26.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image27.png b/customer_app/bl602_demo_qcloud/picture/image27.png new file mode 100644 index 00000000..35a22c90 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image27.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image28.png b/customer_app/bl602_demo_qcloud/picture/image28.png new file mode 100644 index 00000000..68b0a392 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image28.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image29.png b/customer_app/bl602_demo_qcloud/picture/image29.png new file mode 100644 index 00000000..2d346e65 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image29.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image3.png b/customer_app/bl602_demo_qcloud/picture/image3.png new file mode 100644 index 00000000..77520128 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image3.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image30.png b/customer_app/bl602_demo_qcloud/picture/image30.png new file mode 100644 index 00000000..2c24587c Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image30.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image4.png b/customer_app/bl602_demo_qcloud/picture/image4.png new file mode 100644 index 00000000..ec245a93 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image4.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image5.png b/customer_app/bl602_demo_qcloud/picture/image5.png new file mode 100644 index 00000000..30ff6890 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image5.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image6.png b/customer_app/bl602_demo_qcloud/picture/image6.png new file mode 100644 index 00000000..0b32bc2b Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image6.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image7.png b/customer_app/bl602_demo_qcloud/picture/image7.png new file mode 100644 index 00000000..aa1244a6 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image7.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image8.png b/customer_app/bl602_demo_qcloud/picture/image8.png new file mode 100644 index 00000000..1edbf396 Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image8.png differ diff --git a/customer_app/bl602_demo_qcloud/picture/image9.png b/customer_app/bl602_demo_qcloud/picture/image9.png new file mode 100644 index 00000000..a844308e Binary files /dev/null and b/customer_app/bl602_demo_qcloud/picture/image9.png differ diff --git a/customer_app/bl602_demo_qcloud/proj_config.mk b/customer_app/bl602_demo_qcloud/proj_config.mk new file mode 100644 index 00000000..68e578d2 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/proj_config.mk @@ -0,0 +1,53 @@ +# +#compiler flag config domain +# +#CONFIG_TOOLPREFIX := +#CONFIG_OPTIMIZATION_LEVEL_RELEASE := 1 +#CONFIG_M4_SOFTFP := 1 + +# +#board config domain +# +CONFIG_BOARD_FLASH_SIZE := 2 + +#firmware config domain +# + +#set CONFIG_ENABLE_ACP to 1 to enable ACP, set to 0 or comment this line to disable +#CONFIG_ENABLE_ACP:=1 +CONFIG_BL_IOT_FW_AP:=1 +CONFIG_BL_IOT_FW_AMPDU:=0 +CONFIG_BL_IOT_FW_AMSDU:=0 +CONFIG_BL_IOT_FW_P2P:=0 +CONFIG_ENABLE_PSM_RAM:=1 +#CONFIG_ENABLE_CAMERA:=1 +CONFIG_ENABLE_BLSYNC:=1 +#CONFIG_ENABLE_VFS_SPI:=1 +CONFIG_ENABLE_VFS_ROMFS:=1 + +# set easyflash env psm size, only support 4K、8K、16K options +CONFIG_ENABLE_PSM_EF_SIZE:=16K + +CONFIG_FREERTOS_TICKLESS_MODE:=0 + +CONFIG_BT:=1 +CONFIG_BT_CENTRAL:=1 +CONFIG_BT_OBSERVER:=1 +CONFIG_BT_PERIPHERAL:=1 +CONFIG_BT_STACK_CLI:=1 +CONFIG_BT_WIFIPROV_SERVER:=1 +#CONFIG_BT_MESH := 1 +CONFIG_BLE_STACK_DBG_PRINT := 1 +CONFIG_BT_STACK_PTS := 0 +ifeq ($(CONFIG_BT_MESH),1) +CONFIG_BT_MESH_PB_ADV := 1 +CONFIG_BT_MESH_PB_GATT := 1 +CONFIG_BT_MESH_FRIEND := 1 +CONFIG_BT_MESH_LOW_POWER := 1 +CONFIG_BT_MESH_PROXY := 1 +CONFIG_BT_MESH_GATT_PROXY := 1 +endif + +#blog enable components format :=blog_testc cli vfs helper +LOG_ENABLED_COMPONENTS:=blog_testc hal_drv loopset looprt bloop blsync_ble +CFLAGS += -DMBEDTLS_KEY_EXCHANGE_PSK_ENABLED \ No newline at end of file diff --git a/customer_app/bl602_demo_qcloud/sdk_app_qcloud/bl602_sensor_data_template_sample.c b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/bl602_sensor_data_template_sample.c new file mode 100644 index 00000000..3adeefa5 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/bl602_sensor_data_template_sample.c @@ -0,0 +1,789 @@ +/* + * Tencent is pleased to support the open source community by making IoT Hub + available. + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + + * Licensed under the MIT License (the "License"); you may not use this file + except in + * compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + + * Unless required by applicable law or agreed to in writing, software + distributed under the License is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, + * either express or implied. See the License for the specific language + governing permissions and + * limitations under the License. + * + */ + +#include "lite-utils.h" +#include "qcloud_iot_export.h" +#include "qcloud_iot_import.h" +#include "qutils_timer.h" +#include "qutils_getopt.h" +#include +#include +#include +#include +#include +#include +#include + +#define GXHT3X_ADDR 0x45 + + + +#ifdef AUTH_MODE_CERT +static char sg_cert_file[PATH_MAX + 1]; // full path of device cert file +static char sg_key_file[PATH_MAX + 1]; // full path of device key file +#endif + +static DeviceInfo sg_devInfo; + + + +/* anis color control codes */ +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_BLUE "\x1b[34m" +#define ANSI_COLOR_RESET "\x1b[0m" + +static MQTTEventType sg_subscribe_event_result = MQTT_EVENT_UNDEF; +static bool sg_control_msg_arrived = false; +static char sg_data_report_buffer[2048]; +static size_t sg_data_report_buffersize = sizeof(sg_data_report_buffer) / sizeof(sg_data_report_buffer[0]); + +/*data_config.c can be generated by tools/codegen.py -c xx/product.json*/ +/*-----------------data config start -------------------*/ +#define TOTAL_PROPERTY_COUNT 2 + + +static sDataPoint sg_DataTemplate[TOTAL_PROPERTY_COUNT]; + + + +typedef struct _ProductDataDefine { + TYPE_DEF_TEMPLATE_FLOAT m_Temperature_DATA; + TYPE_DEF_TEMPLATE_FLOAT m_Humidity_DATA; +} ProductDataDefine; + +static ProductDataDefine sg_ProductData; + + + + +static void _init_data_template(void) +{ + memset((void *)&sg_ProductData, 0, sizeof(ProductDataDefine)); + + sg_ProductData.m_Temperature_DATA = 0; + sg_DataTemplate[0].data_property.data = &sg_ProductData.m_Temperature_DATA; + sg_DataTemplate[0].data_property.key = "Temperature_DATA"; + sg_DataTemplate[0].data_property.type = TYPE_TEMPLATE_FLOAT; + sg_DataTemplate[0].state = eCHANGED; + + sg_ProductData.m_Humidity_DATA = 0; + sg_DataTemplate[1].data_property.data = &sg_ProductData.m_Humidity_DATA; + sg_DataTemplate[1].data_property.key = "Humidity_DATA"; + sg_DataTemplate[1].data_property.type = TYPE_TEMPLATE_FLOAT; + sg_DataTemplate[1].state = eCHANGED; +}; + +void GXHT3X_GetData(void) +{ + + i2c_msg_t init_msg[2]; + uint8_t init_buf[2]; + uint8_t sensor_buf[6]; + + uint16_t tem; + uint16_t hum; + + float Temperature=0; + float Humidity=0; + + memset(sensor_buf, 0, 6); + init_buf[0]=0x2C; + init_buf[1]=0x10; + + + init_msg[0].addr = GXHT3X_ADDR; + init_msg[0].subflag = 0; + init_msg[0].subaddr = 0; + init_msg[0].buf = init_buf; + init_msg[0].direct = I2C_M_WRITE; + init_msg[0].block = I2C_M_NO_BLOCK; + init_msg[0].len = 2; + init_msg[0].idex = 0; + init_msg[0].sublen = 0; + init_msg[0].i2cx = 0; + i2c_transfer_msgs_block(init_msg, 1, 0); + + vTaskDelay(100); + + init_msg[0].addr = GXHT3X_ADDR; + init_msg[0].subflag = 0; + init_msg[0].subaddr = 0; + init_msg[0].buf = sensor_buf; + init_msg[0].direct = I2C_M_READ; + init_msg[0].block = I2C_M_NO_BLOCK; + init_msg[0].len = 6; + init_msg[0].idex = 0; + init_msg[0].sublen = 0; + init_msg[0].i2cx = 0; + i2c_transfer_msgs_block(init_msg, 1, 0); + + tem = ((sensor_buf[0]<<8) | sensor_buf[1]);//温度拼接 + hum = ((sensor_buf[3]<<8) | sensor_buf[4]);//湿度拼接 + + Temperature= (((175.0*(float)tem)/65535.0)-45.0) ;// T = -45 + 175 * tem / (2^16-1) + Humidity= ((100.0*(float)hum)/65535.0);// RH = hum*100 / (2^16-1) + + + + if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//过滤错误数据 + { + Log_i("sensor data ok\n"); + memset((void *)&sg_ProductData, 0, sizeof(ProductDataDefine)); + Log_i("Temperature:%6.2f*C Humidity%6.2f%% \n",Temperature,Humidity); + + memset((void *)&sg_ProductData, 0, sizeof(ProductDataDefine)); + + sg_ProductData.m_Temperature_DATA = Temperature; + sg_DataTemplate[0].data_property.data = &sg_ProductData.m_Temperature_DATA; + sg_DataTemplate[0].data_property.key = "Temperature_DATA"; + sg_DataTemplate[0].data_property.type = TYPE_TEMPLATE_FLOAT; + sg_DataTemplate[0].state = eCHANGED; + + sg_ProductData.m_Humidity_DATA = Humidity; + sg_DataTemplate[1].data_property.data = &sg_ProductData.m_Humidity_DATA; + sg_DataTemplate[1].data_property.key = "Humidity_DATA"; + sg_DataTemplate[1].data_property.type = TYPE_TEMPLATE_FLOAT; + sg_DataTemplate[1].state = eCHANGED; + + }else{ + + Log_e("sensor data error\n"); + } + + + +} +/*-----------------data config end -------------------*/ + +/*event_config.c can be generated by tools/codegen.py -c xx/product.json*/ +/*-----------------event config start -------------------*/ +#ifdef EVENT_POST_ENABLED +#define EVENT_COUNTS (3) +#define MAX_EVENT_STR_MESSAGE_LEN (64) +#define MAX_EVENT_STR_NAME_LEN (64) + +static TYPE_DEF_TEMPLATE_BOOL sg_status; +static TYPE_DEF_TEMPLATE_STRING sg_message[MAX_EVENT_STR_MESSAGE_LEN + 1]; +static DeviceProperty g_propertyEvent_status_report[] = { + + {.key = "status", .data = &sg_status, .type = TYPE_TEMPLATE_BOOL}, + {.key = "message", .data = sg_message, .type = TYPE_TEMPLATE_STRING}, +}; + +static TYPE_DEF_TEMPLATE_FLOAT sg_voltage; +static DeviceProperty g_propertyEvent_low_voltage[] = { + + {.key = "voltage", .data = &sg_voltage, .type = TYPE_TEMPLATE_FLOAT}, +}; + +static TYPE_DEF_TEMPLATE_STRING sg_name[MAX_EVENT_STR_NAME_LEN + 1]; +static TYPE_DEF_TEMPLATE_INT sg_error_code; +static DeviceProperty g_propertyEvent_hardware_fault[] = { + + {.key = "name", .data = sg_name, .type = TYPE_TEMPLATE_STRING}, + {.key = "error_code", .data = &sg_error_code, .type = TYPE_TEMPLATE_INT}, +}; + +static sEvent g_events[] = { + + { + .event_name = "status_report", + .type = "info", + .timestamp = 0, + .eventDataNum = sizeof(g_propertyEvent_status_report) / sizeof(g_propertyEvent_status_report[0]), + .pEventData = g_propertyEvent_status_report, + }, + { + .event_name = "low_voltage", + .type = "alert", + .timestamp = 0, + .eventDataNum = sizeof(g_propertyEvent_low_voltage) / sizeof(g_propertyEvent_low_voltage[0]), + .pEventData = g_propertyEvent_low_voltage, + }, + { + .event_name = "hardware_fault", + .type = "fault", + .timestamp = 0, + .eventDataNum = sizeof(g_propertyEvent_hardware_fault) / sizeof(g_propertyEvent_hardware_fault[0]), + .pEventData = g_propertyEvent_hardware_fault, + }, +}; + +/*-----------------event config end -------------------*/ + +static void update_events_timestamp(sEvent *pEvents, int count) +{ + int i; + + for (i = 0; i < count; i++) { + if (NULL == (&pEvents[i])) { + Log_e("null event pointer"); + return; + } +#ifdef EVENT_TIMESTAMP_USED + pEvents[i].timestamp = HAL_Timer_current_sec(); // should be UTC and + // accurate +#else + pEvents[i].timestamp = 0; +#endif + } +} + +static void event_post_cb(void *pClient, MQTTMessage *msg) +{ + Log_d("recv event reply, clear event"); + // IOT_Event_clearFlag(pClient, FLAG_EVENT0); +} + +// event check and post +static void eventPostCheck(void *client) +{ + int i; + int rc; + uint32_t eflag; + uint8_t EventCont; + sEvent * pEventList[EVENT_COUNTS]; + + eflag = IOT_Event_getFlag(client); + if ((EVENT_COUNTS > 0) && (eflag > 0)) { + EventCont = 0; + for (i = 0; i < EVENT_COUNTS; i++) { + if ((eflag & (1 << i)) & ALL_EVENTS_MASK) { + pEventList[EventCont++] = &(g_events[i]); + update_events_timestamp(&g_events[i], 1); + IOT_Event_clearFlag(client, (1 << i) & ALL_EVENTS_MASK); + } + } + + rc = IOT_Post_Event(client, sg_data_report_buffer, sg_data_report_buffersize, EventCont, pEventList, + event_post_cb); + if (rc < 0) { + Log_e("event post failed: %d", rc); + } + } +} + +#endif + +/*action_config.c can be generated by tools/codegen.py -c xx/product.json*/ +/*-----------------action config start -------------------*/ +#ifdef ACTION_ENABLED + +#define TOTAL_ACTION_COUNTS (1) + +static TYPE_DEF_TEMPLATE_INT sg_blink_in_period = 5; +static DeviceProperty g_actionInput_blink[] = { + {.key = "period", .data = &sg_blink_in_period, .type = TYPE_TEMPLATE_INT}}; +static TYPE_DEF_TEMPLATE_BOOL sg_blink_out_result = 0; +static DeviceProperty g_actionOutput_blink[] = { + + {.key = "result", .data = &sg_blink_out_result, .type = TYPE_TEMPLATE_BOOL}, +}; + +static DeviceAction g_actions[] = { + + { + .pActionId = "blink", + .timestamp = 0, + .input_num = sizeof(g_actionInput_blink) / sizeof(g_actionInput_blink[0]), + .output_num = sizeof(g_actionOutput_blink) / sizeof(g_actionOutput_blink[0]), + .pInput = g_actionInput_blink, + .pOutput = g_actionOutput_blink, + }, +}; +/*-----------------action config end -------------------*/ +static void OnActionCallback(void *pClient, const char *pClientToken, DeviceAction *pAction) +{ + int i; + sReplyPara replyPara; + + // control light blink + int period = 0; + DeviceProperty *pActionInput = pAction->pInput; + for (i = 0; i < pAction->input_num; i++) { + if (!strcmp(pActionInput[i].key, "period")) { + period = *((int *)pActionInput[i].data); + } else { + Log_e("no such input[%s]!", pActionInput[i].key); + } + } + + // do blink + HAL_Printf("%s[lighting blink][****]" ANSI_COLOR_RESET, ANSI_COLOR_RED); + HAL_SleepMs(period * 1000); + HAL_Printf("\r%s[lighting blink][****]" ANSI_COLOR_RESET, ANSI_COLOR_GREEN); + HAL_SleepMs(period * 1000); + HAL_Printf("\r%s[lighting blink][****]\n" ANSI_COLOR_RESET, ANSI_COLOR_RED); + + // construct output + memset((char *)&replyPara, 0, sizeof(sReplyPara)); + replyPara.code = eDEAL_SUCCESS; + replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT; + strcpy(replyPara.status_msg, + "action execute success!"); // add the message about the action resault + + DeviceProperty *pActionOutnput = pAction->pOutput; + *(int *)(pActionOutnput[0].data) = 0; // set result + + IOT_Action_Reply(pClient, pClientToken, sg_data_report_buffer, sg_data_report_buffersize, pAction, &replyPara); +} + +static int _register_data_template_action(void *pTemplate_client) +{ + int i, rc; + + for (i = 0; i < TOTAL_ACTION_COUNTS; i++) { + rc = IOT_Template_Register_Action(pTemplate_client, &g_actions[i], OnActionCallback); + if (rc != QCLOUD_RET_SUCCESS) { + rc = IOT_Template_Destroy(pTemplate_client); + Log_e("register device data template action failed, err: %d", rc); + return rc; + } else { + Log_i("data template action=%s registered.", g_actions[i].pActionId); + } + } + + return QCLOUD_RET_SUCCESS; +} +#endif + +static void event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg) +{ + uintptr_t packet_id = (uintptr_t)msg->msg; + + switch (msg->event_type) { + case MQTT_EVENT_UNDEF: + Log_i("undefined event occur."); + break; + + case MQTT_EVENT_DISCONNECT: + Log_i("MQTT disconnect."); + break; + + case MQTT_EVENT_RECONNECT: + Log_i("MQTT reconnect."); + break; + + case MQTT_EVENT_SUBCRIBE_SUCCESS: + sg_subscribe_event_result = msg->event_type; + Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id); + break; + + case MQTT_EVENT_SUBCRIBE_TIMEOUT: + sg_subscribe_event_result = msg->event_type; + Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id); + break; + + case MQTT_EVENT_SUBCRIBE_NACK: + sg_subscribe_event_result = msg->event_type; + Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id); + break; + + case MQTT_EVENT_PUBLISH_SUCCESS: + Log_i("publish success, packet-id=%u", (unsigned int)packet_id); + break; + + case MQTT_EVENT_PUBLISH_TIMEOUT: + Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id); + break; + + case MQTT_EVENT_PUBLISH_NACK: + Log_i("publish nack, packet-id=%u", (unsigned int)packet_id); + break; + default: + Log_i("Should NOT arrive here."); + break; + } +} + +/*add user init code, like sensor init*/ +static void _usr_init(void) +{ + Log_d("add your init code here"); +} + +// Setup MQTT construct parameters +static int _setup_connect_init_params(TemplateInitParams *initParams) +{ + int ret; + + ret = HAL_GetDevInfo((void *)&sg_devInfo); + if (QCLOUD_RET_SUCCESS != ret) { + return ret; + } + + initParams->region = sg_devInfo.region; + initParams->device_name = sg_devInfo.device_name; + initParams->product_id = sg_devInfo.product_id; + +#ifdef AUTH_MODE_CERT + /* TLS with certs*/ + char certs_dir[PATH_MAX + 1] = "certs"; + char current_path[PATH_MAX + 1]; + char *cwd = getcwd(current_path, sizeof(current_path)); + if (cwd == NULL) { + Log_e("getcwd return NULL"); + return QCLOUD_ERR_FAILURE; + } + sprintf(sg_cert_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_cert_file_name); + sprintf(sg_key_file, "%s/%s/%s", current_path, certs_dir, sg_devInfo.dev_key_file_name); + + initParams->cert_file = sg_cert_file; + initParams->key_file = sg_key_file; +#else + initParams->device_secret = sg_devInfo.device_secret; +#endif + + initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT; + initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL; + initParams->auto_connect_enable = 1; + initParams->event_handle.h_fp = event_handler; + initParams->usr_control_handle = NULL; + + return QCLOUD_RET_SUCCESS; +} + +#ifdef LOG_UPLOAD +// init log upload module +static int _init_log_upload(TemplateInitParams *init_params) +{ + LogUploadInitParams log_init_params; + memset(&log_init_params, 0, sizeof(LogUploadInitParams)); + + log_init_params.region = init_params->region; + log_init_params.product_id = init_params->product_id; + log_init_params.device_name = init_params->device_name; +#ifdef AUTH_MODE_CERT + log_init_params.sign_key = init_params->cert_file; +#else + log_init_params.sign_key = init_params->device_secret; +#endif + +#if defined(__linux__) || defined(WIN32) + log_init_params.read_func = HAL_Log_Read; + log_init_params.save_func = HAL_Log_Save; + log_init_params.del_func = HAL_Log_Del; + log_init_params.get_size_func = HAL_Log_Get_Size; +#endif + + return IOT_Log_Init_Uploader(&log_init_params); +} +#endif + +/*control msg from server will trigger this callback*/ +static void OnControlMsgCallback(void *pClient, const char *pJsonValueBuffer, uint32_t valueLength, + DeviceProperty *pProperty) +{ + int i = 0; + + for (i = 0; i < TOTAL_PROPERTY_COUNT; i++) { + /* handle self defined string/json here. Other properties are dealed in + * _handle_delta()*/ + if (strcmp(sg_DataTemplate[i].data_property.key, pProperty->key) == 0) { + sg_DataTemplate[i].state = eCHANGED; + Log_i("Property=%s changed", pProperty->key); + sg_control_msg_arrived = true; + return; + } + } + + Log_e("Property=%s changed no match", pProperty->key); +} + +static void OnReportReplyCallback(void *pClient, Method method, ReplyAck replyAck, const char *pJsonDocument, + void *pUserdata) +{ + Log_i("recv report_reply(ack=%d): %s", replyAck, pJsonDocument); +} + +// register data template properties +static int _register_data_template_property(void *pTemplate_client) +{ + int i, rc; + + for (i = 0; i < TOTAL_PROPERTY_COUNT; i++) { + rc = IOT_Template_Register_Property(pTemplate_client, &sg_DataTemplate[i].data_property, OnControlMsgCallback); + if (rc != QCLOUD_RET_SUCCESS) { + rc = IOT_Template_Destroy(pTemplate_client); + Log_e("register device data template property failed, err: %d", rc); + return rc; + } else { + Log_i("data template property=%s registered.", sg_DataTemplate[i].data_property.key); + } + } + + return QCLOUD_RET_SUCCESS; +} + +/*get property state, changed or not*/ +static eDataState get_property_state(void *pProperyData) +{ + int i; + + for (i = 0; i < TOTAL_PROPERTY_COUNT; i++) { + if (sg_DataTemplate[i].data_property.data == pProperyData) { + return sg_DataTemplate[i].state; + } + } + + Log_e("no property matched"); + return eNOCHANGE; +} + +/*set property state, changed or no change*/ +static void set_property_state(void *pProperyData, eDataState state) +{ + int i; + + for (i = 0; i < TOTAL_PROPERTY_COUNT; i++) { + if (sg_DataTemplate[i].data_property.data == pProperyData) { + sg_DataTemplate[i].state = state; + break; + } + } +} + +/* demo for light logic deal */ +static void deal_down_stream_user_logic(void *client, ProductDataDefine *light) +{ + +} + + +/*get local property data, like sensor data*/ +static void _refresh_local_property(void) +{ + GXHT3X_GetData(); + set_property_state(sg_DataTemplate[0].data_property.data, eCHANGED); + set_property_state(sg_DataTemplate[1].data_property.data, eCHANGED); + +} + +/*find propery need report*/ +static int find_wait_report_property(DeviceProperty *pReportDataList[]) +{ + int i, j; + + for (i = 0, j = 0; i < TOTAL_PROPERTY_COUNT; i++) { + if (eCHANGED == sg_DataTemplate[i].state) { + pReportDataList[j++] = &(sg_DataTemplate[i].data_property); + sg_DataTemplate[i].state = eNOCHANGE; + } + } + + return j; +} + +/* demo for up-stream code */ +static int deal_up_stream_user_logic(DeviceProperty *pReportDataList[], int *pCount) +{ + // refresh local property + _refresh_local_property(); + + /*find propery need report*/ + *pCount = find_wait_report_property(pReportDataList); + + return (*pCount > 0) ? QCLOUD_RET_SUCCESS : QCLOUD_ERR_FAILURE; +} + +/*You should get the real info for your device, here just for example*/ +static int _get_sys_info(void *handle, char *pJsonDoc, size_t sizeOfBuffer) +{ + /*platform info has at least one of module_hardinfo/module_softinfo/fw_ver + * property*/ + DeviceProperty plat_info[] = { + {.key = "module_hardinfo", .type = TYPE_TEMPLATE_STRING, .data = "BL602"}, + {.key = "module_softinfo", .type = TYPE_TEMPLATE_STRING, .data = "V1.0"}, + {.key = "fw_ver", .type = TYPE_TEMPLATE_STRING, .data = QCLOUD_IOT_DEVICE_SDK_VERSION}, + {.key = "imei", .type = TYPE_TEMPLATE_STRING, .data = "11-22-33-44"}, + {.key = "lat", .type = TYPE_TEMPLATE_STRING, .data = "22.546015"}, + {.key = "lon", .type = TYPE_TEMPLATE_STRING, .data = "113.941125"}, + {.key = "mac", .type = TYPE_TEMPLATE_STRING, .data = "11:22:33:44:55:66"}, + {.key = NULL, .data = NULL} // end + }; + + /*self define info*/ + DeviceProperty self_info[] = { + {.key = "append_info", .type = TYPE_TEMPLATE_STRING, .data = "your self define info"}, + {.key = NULL, .data = NULL} // end + }; + + return IOT_Template_JSON_ConstructSysInfo(handle, pJsonDoc, sizeOfBuffer, plat_info, self_info); +} + +int bl_qcloud_main(void *arg) +{ + DeviceProperty *pReportDataList[TOTAL_PROPERTY_COUNT]; + sReplyPara replyPara; + int ReportCont; + int rc; + + + // init log level + IOT_Log_Set_Level(eLOG_DEBUG); + + // init connection + TemplateInitParams init_params = DEFAULT_TEMPLATE_INIT_PARAMS; + rc = _setup_connect_init_params(&init_params); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("init params err,rc=%d", rc); + return rc; + } + +#ifdef LOG_UPLOAD + // _init_log_upload should be done after _setup_connect_init_params and before IOT_Template_Construct + rc = _init_log_upload(&init_params); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("init log upload error, rc = %d", rc); + } +#endif + + void *client = IOT_Template_Construct(&init_params, NULL); + if (client != NULL) { + Log_i("Cloud Device Construct Success"); + } else { + Log_e("Cloud Device Construct Failed"); + return QCLOUD_ERR_FAILURE; + } + +#ifdef MULTITHREAD_ENABLED + if (QCLOUD_RET_SUCCESS != IOT_Template_Start_Yield_Thread(client)) { + Log_e("start template yield thread fail"); + goto exit; + } +#endif + + // usr init + _usr_init(); + + // init data template + _init_data_template(); + + // register data template propertys here + rc = _register_data_template_property(client); + if (rc == QCLOUD_RET_SUCCESS) { + Log_i("Register data template propertys Success"); + } else { + Log_e("Register data template propertys Failed: %d", rc); + goto exit; + } + +// register data template actions here +#ifdef ACTION_ENABLED + rc = _register_data_template_action(client); + if (rc == QCLOUD_RET_SUCCESS) { + Log_i("Register data template actions Success"); + } else { + Log_e("Register data template actions Failed: %d", rc); + goto exit; + } +#endif + + // report device info, then you can manager your product by these info, like position + rc = _get_sys_info(client, sg_data_report_buffer, sg_data_report_buffersize); + if (QCLOUD_RET_SUCCESS == rc) { + rc = IOT_Template_Report_SysInfo_Sync(client, sg_data_report_buffer, sg_data_report_buffersize, + QCLOUD_IOT_MQTT_COMMAND_TIMEOUT); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("Report system info fail, err: %d", rc); + } + } else { + Log_e("Get system info fail, err: %d", rc); + } + + // get the property changed during offline + rc = IOT_Template_GetStatus_sync(client, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT); + if (rc != QCLOUD_RET_SUCCESS) { + Log_e("Get data status fail, err: %d", rc); + } else { + Log_d("Get data status success"); + } + + + + while (IOT_Template_IsConnected(client) || rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT || + rc == QCLOUD_RET_MQTT_RECONNECTED || QCLOUD_RET_SUCCESS == rc) { + rc = IOT_Template_Yield(client, 200); + if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) { + HAL_SleepMs(1000); + continue; + } else if (rc != QCLOUD_RET_SUCCESS) { + Log_e("Exit loop caused of errCode: %d", rc); + } + + /* handle control msg from server */ + if (sg_control_msg_arrived) { + deal_down_stream_user_logic(client, &sg_ProductData); + /* control msg should reply, otherwise server treat device didn't receive + * and retain the msg which would be get by get status*/ + memset((char *)&replyPara, 0, sizeof(sReplyPara)); + replyPara.code = eDEAL_SUCCESS; + replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT; + replyPara.status_msg[0] = '\0'; // add extra info to replyPara.status_msg when error occured + + rc = IOT_Template_ControlReply(client, sg_data_report_buffer, sg_data_report_buffersize, &replyPara); + if (rc == QCLOUD_RET_SUCCESS) { + Log_d("Contol msg reply success"); + sg_control_msg_arrived = false; + } else { + Log_e("Contol msg reply failed, err: %d", rc); + } + } + + /*report msg to server*/ + /*report the lastest properties's status*/ + if (QCLOUD_RET_SUCCESS == deal_up_stream_user_logic(pReportDataList, &ReportCont)) { + rc = IOT_Template_JSON_ConstructReportArray(client, sg_data_report_buffer, sg_data_report_buffersize, + ReportCont, pReportDataList); + if (rc == QCLOUD_RET_SUCCESS) { + rc = IOT_Template_Report(client, sg_data_report_buffer, sg_data_report_buffersize, + OnReportReplyCallback, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT); + if (rc == QCLOUD_RET_SUCCESS) { + Log_i("data template reporte success"); + } else { + Log_e("data template reporte failed, err: %d", rc); + } + } else { + Log_e("construct reporte data failed, err: %d", rc); + } + } + +#ifdef EVENT_POST_ENABLED + eventPostCheck(client); +#endif + HAL_SleepMs(1000); + } + +exit: + +#ifdef MULTITHREAD_ENABLED + IOT_Template_Stop_Yield_Thread(client); +#endif + rc = IOT_Template_Destroy(client); + +#ifdef LOG_UPLOAD + IOT_Log_Upload(true); + IOT_Log_Fini_Uploader(); +#endif + + return rc; +} diff --git a/customer_app/bl602_demo_qcloud/sdk_app_qcloud/blsync_ble_app.c b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/blsync_ble_app.c new file mode 100644 index 00000000..74858f03 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/blsync_ble_app.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2020 Bouffalolab. + * + * This file is part of + * *** Bouffalolab Software Dev Kit *** + * (see www.bouffalolab.com). + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Bouffalo Lab nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "blsync_ble_app.h" +#include "wifi_prov_api.h" +#include +#include +#include "blsync_ble.h" +#include "bluetooth.h" +#include "ble_cli_cmds.h" +#include "hci_driver.h" +#include "ble_lib_api.h" + +static bl_ble_sync_t *gp_index = NULL; + +static void wifiprov_connect_ap_ind(struct wifi_conn *info) +{ + extern int wifi_mgmr_status_code_clean_internal(); + wifi_mgmr_status_code_clean_internal(); + printf("Recevied indication to connect to AP\r\n"); + wifi_prov_api_event_trigger_connect(info); +} + +static void wifiprov_disc_from_ap_ind(void) +{ + printf("Recevied indication to disconnect to AP\r\n"); + wifi_prov_api_event_trigger_disconnect(); +} + +static void wifiprov_wifi_scan(void(*complete)(void *)) +{ + printf("Recevied indication to wifi scan\r\n"); + wifi_prov_api_event_trigger_scan(complete); +} + +static void wifiprov_api_state_get(void(*state_get)(void *)) +{ + printf("Recevied indication to wifi state get\r\n"); + wifi_prov_api_event_state_get(state_get); +} + +static void blesync_complete_cb (void *p_arg) +{ + bl_ble_sync_t *p_index = (bl_ble_sync_t *)p_arg; + bl_ble_sync_stop(p_index); + vPortFree(p_index); +} + +static struct blesync_wifi_func WifiProv_conn_callback = { + .local_connect_remote_ap = wifiprov_connect_ap_ind, + .local_disconnect_remote_ap = wifiprov_disc_from_ap_ind, + .local_wifi_scan = wifiprov_wifi_scan, + .local_wifi_state_get = wifiprov_api_state_get, +}; + +static void blsync_init(int err) +{ + if (err != 0) { + return; + } + if (gp_index != NULL) { + printf("blsync already started\r\n"); + return; + } + ble_cli_register(); + gp_index = pvPortMalloc(sizeof(bl_ble_sync_t)); + if (gp_index == NULL) { + return; + } + bl_ble_sync_start(gp_index, + &WifiProv_conn_callback, + blesync_complete_cb, + (void *)gp_index); +} + +static void ble_stack_start(void) +{ + // Initialize BLE controller + ble_controller_init(configMAX_PRIORITIES - 1); + // Initialize BLE Host stack + hci_driver_init(); + bt_enable(blsync_init); +} + +void blsync_ble_start (void) +{ + static uint8_t stack_started = 0; + + if (stack_started == 1) { + blsync_init(0); + return; + } + ble_stack_start(); + stack_started = 1; +} + +void blsync_ble_stop (void) +{ + bl_ble_sync_stop(gp_index); + vPortFree(gp_index); + gp_index = NULL; +} + diff --git a/customer_app/bl602_demo_qcloud/sdk_app_qcloud/blsync_ble_app.h b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/blsync_ble_app.h new file mode 100644 index 00000000..25f6d8a3 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/blsync_ble_app.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Bouffalolab. + * + * This file is part of + * *** Bouffalolab Software Dev Kit *** + * (see www.bouffalolab.com). + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Bouffalo Lab nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __BLE_SYNC_H_ +#define __BLE_SYNC_H_ + +void blsync_ble_start (void); + +void blsync_ble_stop (void); + +#endif diff --git a/customer_app/bl602_demo_qcloud/sdk_app_qcloud/bouffalo.mk b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/bouffalo.mk new file mode 100644 index 00000000..e12ff417 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/bouffalo.mk @@ -0,0 +1,26 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + +include $(BL60X_SDK_PATH)/components/network/ble/ble_common.mk + +ifeq ($(CONFIG_ENABLE_PSM_RAM),1) +CPPFLAGS += -DCONF_USER_ENABLE_PSRAM +endif + +ifeq ($(CONFIG_ENABLE_CAMERA),1) +CPPFLAGS += -DCONF_USER_ENABLE_CAMERA +endif + +ifeq ($(CONFIG_ENABLE_BLSYNC),1) +CPPFLAGS += -DCONF_USER_ENABLE_BLSYNC +endif + +ifeq ($(CONFIG_ENABLE_VFS_SPI),1) +CPPFLAGS += -DCONF_USER_ENABLE_VFS_SPI +endif + +ifeq ($(CONFIG_ENABLE_VFS_ROMFS),1) +CPPFLAGS += -DCONF_USER_ENABLE_VFS_ROMFS +endif diff --git a/customer_app/bl602_demo_qcloud/sdk_app_qcloud/main.c b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/main.c new file mode 100644 index 00000000..0161b143 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/main.c @@ -0,0 +1,943 @@ +/* + * Copyright (c) 2020 Bouffalolab. + * + * This file is part of + * *** Bouffalolab Software Dev Kit *** + * (see www.bouffalolab.com). + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Bouffalo Lab nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "blsync_ble_app.h" + +#define CODE_CLI_BLSYNC_START 0x01 +#define CODE_CLI_BLSYNC_STOP 0x02 + +#define TASK_PRIORITY_FW ( 30 ) +#define mainHELLO_TASK_PRIORITY ( 20 ) +#define UART_ID_2 (2) +#define WIFI_AP_PSM_INFO_SSID "conf_ap_ssid" +#define WIFI_AP_PSM_INFO_PASSWORD "conf_ap_psk" +#define WIFI_AP_PSM_INFO_PMK "conf_ap_pmk" +#define WIFI_AP_PSM_INFO_BSSID "conf_ap_bssid" +#define WIFI_AP_PSM_INFO_CHANNEL "conf_ap_channel" +#define WIFI_AP_PSM_INFO_IP "conf_ap_ip" +#define WIFI_AP_PSM_INFO_MASK "conf_ap_mask" +#define WIFI_AP_PSM_INFO_GW "conf_ap_gw" +#define WIFI_AP_PSM_INFO_DNS1 "conf_ap_dns1" +#define WIFI_AP_PSM_INFO_DNS2 "conf_ap_dns2" +#define WIFI_AP_PSM_INFO_IP_LEASE_TIME "conf_ap_ip_lease_time" +#define WIFI_AP_PSM_INFO_GW_MAC "conf_ap_gw_mac" +#define CLI_CMD_AUTOSTART1 "cmd_auto1" +#define CLI_CMD_AUTOSTART2 "cmd_auto2" + +static wifi_conf_t conf = +{ + .country_code = "CN", +}; +extern uint8_t _heap_start; +extern uint8_t _heap_size; // @suppress("Type cannot be resolved") +extern uint8_t _heap_wifi_start; +extern uint8_t _heap_wifi_size; // @suppress("Type cannot be resolved") +static HeapRegion_t xHeapRegions[] = +{ + { &_heap_start, (unsigned int) &_heap_size}, //set on runtime + { &_heap_wifi_start, (unsigned int) &_heap_wifi_size }, + { NULL, 0 }, /* Terminates the array. */ + { NULL, 0 } /* Terminates the array. */ +}; +static wifi_interface_t wifi_interface; + +void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName ) +{ + puts("Stack Overflow checked\r\n"); + while (1) { + /*empty here*/ + } +} + +void vApplicationMallocFailedHook(void) +{ + printf("Memory Allocate Failed. Current left size is %d bytes\r\n", + xPortGetFreeHeapSize() + ); + while (1) { + /*empty here*/ + } +} + +void vApplicationIdleHook(void) +{ + __asm volatile( + " wfi " + ); + /*empty*/ +} + +static unsigned char char_to_hex(char asccode) +{ + unsigned char ret; + + if('0'<=asccode && asccode<='9') + ret=asccode-'0'; + else if('a'<=asccode && asccode<='f') + ret=asccode-'a'+10; + else if('A'<=asccode && asccode<='F') + ret=asccode-'A'+10; + else + ret=0; + + return ret; +} + +static void _chan_str_to_hex(uint8_t *chan_band, uint16_t *chan_freq, char *chan) +{ + int i, freq_len, base=1; + uint8_t band; + uint16_t freq = 0; + char *p, *q; + + /*should have the following format + * 2412|0 + * */ + p = strchr(chan, '|') + 1; + if (NULL == p) { + return; + } + band = char_to_hex(p[0]); + (*chan_band) = band; + + freq_len = strlen(chan) - strlen(p) - 1; + q = chan; + q[freq_len] = '\0'; + for (i=0; i< freq_len; i++) { + freq = freq + char_to_hex(q[freq_len-1-i]) * base; + base = base * 10; + } + (*chan_freq) = freq; +} + +static void bssid_str_to_mac(uint8_t *hex, char *bssid, int len) +{ + unsigned char l4,h4; + int i,lenstr; + lenstr = len; + + if(lenstr%2) { + lenstr -= (lenstr%2); + } + + if(lenstr==0){ + return; + } + + for(i=0; i < lenstr; i+=2) { + h4=char_to_hex(bssid[i]); + l4=char_to_hex(bssid[i+1]); + hex[i/2]=(h4<<4)+l4; + } +} + +static void _connect_wifi() +{ + /*XXX caution for BIG STACK*/ + char pmk[66], bssid[32], chan[10]; + char ssid[33], password[66]; + char val_buf[66]; + char val_len = sizeof(val_buf) - 1; + uint8_t mac[6]; + uint8_t band = 0; + uint16_t freq = 0; + + wifi_interface = wifi_mgmr_sta_enable(); + printf("[APP] [WIFI] [T] %lld\r\n" + "[APP] Get STA %p from Wi-Fi Mgmr, pmk ptr %p, ssid ptr %p, password %p\r\n", + aos_now_ms(), + wifi_interface, + pmk, + ssid, + password + ); + memset(pmk, 0, sizeof(pmk)); + memset(ssid, 0, sizeof(ssid)); + memset(password, 0, sizeof(password)); + memset(bssid, 0, sizeof(bssid)); + memset(mac, 0, sizeof(mac)); + memset(chan, 0, sizeof(chan)); + + memset(val_buf, 0, sizeof(val_buf)); + ef_get_env_blob((const char *)WIFI_AP_PSM_INFO_SSID, val_buf, val_len, NULL); + if (val_buf[0]) { + /*We believe that when ssid is set, wifi_confi is OK*/ + strncpy(ssid, val_buf, sizeof(ssid) - 1); + } else { + /*Won't connect, since ssid config is empty*/ + puts("[APP] Empty Config\r\n"); + puts("[APP] Try to set the following ENV with psm_set command, then reboot\r\n"); + puts("[APP] NOTE: " WIFI_AP_PSM_INFO_PMK " MUST be psm_unset when conf is changed\r\n"); + puts("[APP] env: " WIFI_AP_PSM_INFO_SSID "\r\n"); + puts("[APP] env: " WIFI_AP_PSM_INFO_PASSWORD "\r\n"); + puts("[APP] env(optinal): " WIFI_AP_PSM_INFO_PMK "\r\n"); + return; + } + + memset(val_buf, 0, sizeof(val_buf)); + ef_get_env_blob((const char *)WIFI_AP_PSM_INFO_PASSWORD, val_buf, val_len, NULL); + if (val_buf[0]) { + strncpy(password, val_buf, sizeof(password) - 1); + } + + memset(val_buf, 0, sizeof(val_buf)); + ef_get_env_blob((const char *)WIFI_AP_PSM_INFO_PMK, val_buf, val_len, NULL); + if (val_buf[0]) { + strncpy(pmk, val_buf, sizeof(pmk) - 1); + } + if (0 == pmk[0]) { + printf("[APP] [WIFI] [T] %lld\r\n", + aos_now_ms() + ); + puts("[APP] Re-cal pmk\r\n"); + /*At lease pmk is not illegal, we re-cal now*/ + //XXX time consuming API, so consider lower-prirotiy for cal PSK to avoid sound glitch + wifi_mgmr_psk_cal( + password, + ssid, + strlen(ssid), + pmk + ); + ef_set_env(WIFI_AP_PSM_INFO_PMK, pmk); + ef_save_env(); + } + memset(val_buf, 0, sizeof(val_buf)); + ef_get_env_blob((const char *)WIFI_AP_PSM_INFO_CHANNEL, val_buf, val_len, NULL); + if (val_buf[0]) { + strncpy(chan, val_buf, sizeof(chan) - 1); + printf("connect wifi channel = %s\r\n", chan); + _chan_str_to_hex(&band, &freq, chan); + } + memset(val_buf, 0, sizeof(val_buf)); + ef_get_env_blob((const char *)WIFI_AP_PSM_INFO_BSSID, val_buf, val_len, NULL); + if (val_buf[0]) { + strncpy(bssid, val_buf, sizeof(bssid) - 1); + printf("connect wifi bssid = %s\r\n", bssid); + bssid_str_to_mac(mac, bssid, strlen(bssid)); + printf("mac = %02X:%02X:%02X:%02X:%02X:%02X\r\n", + mac[0], + mac[1], + mac[2], + mac[3], + mac[4], + mac[5] + ); + } + printf("[APP] [WIFI] [T] %lld\r\n" + "[APP] SSID %s\r\n" + "[APP] SSID len %d\r\n" + "[APP] password %s\r\n" + "[APP] password len %d\r\n" + "[APP] pmk %s\r\n" + "[APP] bssid %s\r\n" + "[APP] channel band %d\r\n" + "[APP] channel freq %d\r\n", + aos_now_ms(), + ssid, + strlen(ssid), + password, + strlen(password), + pmk, + bssid, + band, + freq + ); + //wifi_mgmr_sta_connect(wifi_interface, ssid, pmk, NULL); + wifi_mgmr_sta_connect(wifi_interface, ssid, password, pmk, mac, band, freq); +} + +typedef struct _wifi_item { + char ssid[32]; + uint32_t ssid_len; + uint8_t bssid[6]; + uint8_t channel; + uint8_t auth; + int8_t rssi; +} _wifi_item_t; + +struct _wifi_conn { + char ssid[32]; + char ssid_tail[1]; + char pask[64]; +}; + +struct _wifi_state { + char ip[16]; + char gw[16]; + char mask[16]; + char ssid[32]; + char ssid_tail[1]; + uint8_t bssid[6]; + uint8_t state; +}; + +static void wifi_sta_connect(char *ssid, char *password) +{ + wifi_interface_t wifi_interface; + + wifi_interface = wifi_mgmr_sta_enable(); + wifi_mgmr_sta_connect(wifi_interface, ssid, password, NULL, NULL, 0, 0); +} + +static void scan_item_cb(wifi_mgmr_ap_item_t *env, uint32_t *param1, wifi_mgmr_ap_item_t *item) +{ + _wifi_item_t wifi_item; + void (*complete)(void *) = (void (*)(void *))param1; + + wifi_item.auth = item->auth; + wifi_item.rssi = item->rssi; + wifi_item.channel = item->channel; + wifi_item.ssid_len = item->ssid_len; + memcpy(wifi_item.ssid, item->ssid, sizeof(wifi_item.ssid)); + memcpy(wifi_item.bssid, item->bssid, sizeof(wifi_item.bssid)); + + if (complete) { + complete(&wifi_item); + } +} + +static void scan_complete_cb(void *p_arg, void *param) +{ + wifi_mgmr_scan_ap_all(NULL, p_arg, scan_item_cb); +} + +static void wifiprov_scan(void *p_arg) +{ + wifi_mgmr_scan(p_arg, scan_complete_cb); +} + +static void wifiprov_wifi_state_get(void *p_arg) +{ + int tmp_state; + wifi_mgmr_sta_connect_ind_stat_info_t info; + ip4_addr_t ip, gw, mask; + struct _wifi_state state; + void (*state_get_cb)(void *) = (void (*)(void *))p_arg; + + memset(&state, 0, sizeof(state)); + memset(&info, 0, sizeof(info)); + wifi_mgmr_state_get(&tmp_state); + wifi_mgmr_sta_ip_get(&ip.addr, &gw.addr, &mask.addr); + wifi_mgmr_sta_connect_ind_stat_get(&info); + + state.state = tmp_state; + strcpy(state.ip, ip4addr_ntoa(&ip)); + strcpy(state.mask, ip4addr_ntoa(&mask)); + strcpy(state.gw, ip4addr_ntoa(&gw)); + memcpy(state.ssid, info.ssid, sizeof(state.ssid)); + memcpy(state.bssid, info.bssid, sizeof(state.bssid)); + state.ssid_tail[0] = 0; + + printf("IP :%s \r\n", state.ip); + printf("GW :%s \r\n", state.gw); + printf("MASK:%s \r\n", state.mask); + + if (state_get_cb) { + state_get_cb(&state); + } +} + +static void event_cb_i2c_event(input_event_t *event, void *private_data) +{ + switch (event->code) { + case CODE_I2C_END: + { + printf("TRANS FINISH %lld\r\n", aos_now_ms()); + } + break; + case CODE_I2C_ARB: + { + printf("TRANS ERROR ARB %lld\r\n", aos_now_ms()); + } + break; + case CODE_I2C_NAK: + { + printf("TRANS ERROR NAK %lld\r\n", aos_now_ms()); + } + break; + case CODE_I2C_FER: + { + printf("TRANS ERROR FER %lld\r\n", aos_now_ms()); + } + break; + default: + { + printf("[I2C] [EVT] Unknown code %u, %lld\r\n", event->code, aos_now_ms()); + + } + } +} +static void event_cb_wifi_event(input_event_t *event, void *private_data) +{ + struct _wifi_conn *conn_info; + + switch (event->code) { + case CODE_WIFI_ON_INIT_DONE: + { + printf("[APP] [EVT] INIT DONE %lld\r\n", aos_now_ms()); + wifi_mgmr_start_background(&conf); + } + break; + case CODE_WIFI_ON_MGMR_DONE: + { + printf("[APP] [EVT] MGMR DONE %lld\r\n", aos_now_ms()); + _connect_wifi(); + } + break; + case CODE_WIFI_ON_SCAN_DONE: + { + printf("[APP] [EVT] SCAN Done %lld, SCAN Result: %s\r\n", + aos_now_ms(), + WIFI_SCAN_DONE_EVENT_OK == event->value ? "OK" : "Busy now" + ); + wifi_mgmr_cli_scanlist(); + } + break; + case CODE_WIFI_ON_DISCONNECT: + { + printf("[APP] [EVT] disconnect %lld, Reason: %s\r\n", + aos_now_ms(), + wifi_mgmr_status_code_str(event->value) + ); + vTaskDelay(1000); + wifi_mgmr_sta_disable(NULL); + } + break; + case CODE_WIFI_ON_CONNECTING: + { + printf("[APP] [EVT] Connecting %lld\r\n", aos_now_ms()); + } + break; + case CODE_WIFI_CMD_RECONNECT: + { + printf("[APP] [EVT] Reconnect %lld\r\n", aos_now_ms()); + } + break; + case CODE_WIFI_ON_CONNECTED: + { + printf("[APP] [EVT] connected %lld\r\n", aos_now_ms()); + } + break; + case CODE_WIFI_ON_PRE_GOT_IP: + { + printf("[APP] [EVT] connected %lld\r\n", aos_now_ms()); + } + break; + case CODE_WIFI_ON_GOT_IP: + { + printf("[APP] [EVT] GOT IP %lld\r\n", aos_now_ms()); + printf("[SYS] Memory left is %d Bytes\r\n", xPortGetFreeHeapSize()); + + } + break; + case CODE_WIFI_ON_PROV_CONNECT: + { + printf("[APP] [EVT] [PROV] [CONNECT] %lld\r\n", aos_now_ms()); + conn_info = (struct _wifi_conn *)event->value; + wifi_sta_connect(conn_info->ssid, conn_info->pask); + } + break; + case CODE_WIFI_ON_PROV_DISCONNECT: + { + printf("[APP] [EVT] [PROV] [DISCONNECT] %lld\r\n", aos_now_ms()); + wifi_mgmr_sta_disconnect(); + vTaskDelay(1000); + wifi_mgmr_sta_disable(NULL); + + } + break; + case CODE_WIFI_ON_PROV_SCAN_START: + { + printf("[APP] [EVT] [PROV] [SCAN] %lld\r\n", aos_now_ms()); + wifiprov_scan((void *)event->value); + } + break; + case CODE_WIFI_ON_PROV_STATE_GET: + { + printf("[APP] [EVT] [PROV] [STATE] %lld\r\n", aos_now_ms()); + wifiprov_wifi_state_get((void *)event->value); + } + break; + default: + { + printf("[APP] [EVT] Unknown code %u, %lld\r\n", event->code, aos_now_ms()); + /*nothing*/ + } + } +} + +static void event_cb_cli(input_event_t *event, void *p_arg) +{ + char *cmd1 = "ble_init\r\n"; + char *cmd2 = "ble_start_adv 0 0 0x100 0x100\r\n"; + char *cmd3 = "ble_stop_adv\r\n"; + + switch (event->code) { + case CODE_CLI_BLSYNC_START : + aos_cli_input_direct(cmd1, strlen(cmd1)); + aos_cli_input_direct(cmd2, strlen(cmd2)); + break; + case CODE_CLI_BLSYNC_STOP : + aos_cli_input_direct(cmd3, strlen(cmd3)); + blsync_ble_stop(); + printf("blsync ble stop\r\n"); + break; + default : + break; + } +} + +static void __attribute__((unused)) cmd_aws(char *buf, int len, int argc, char **argv) +{ +void aws_main_entry(void *arg); + xTaskCreate(aws_main_entry, (char*)"aws_iot", 4096, NULL, 10, NULL); +} + +static void __attribute__((unused)) cmd_tencent(char *buf, int len, int argc, char **argv){ + + extern int bl_qcloud_main(void *arg); + xTaskCreate(bl_qcloud_main, (char*)"tencent cloud", 4096, NULL, 16, NULL); + //my_light_main(); +} +#define MAXBUF 128 +#define BUFFER_SIZE (12*1024) + +#define PORT 80 + +err_t cb_httpc_headers_done_fn(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len) +{ + printf("[HTTPC] hdr_len is %u, content_len is %lu\r\n", hdr_len, content_len); + return ERR_OK; +} + +static void stack_wifi(void) +{ + /*wifi fw stack and thread stuff*/ + static uint8_t stack_wifi_init = 0; + + + if (1 == stack_wifi_init) { + puts("Wi-Fi Stack Started already!!!\r\n"); + return; + } + stack_wifi_init = 1; + + hal_wifi_start_firmware_task(); + /*Trigger to start Wi-Fi*/ + aos_post_event(EV_WIFI, CODE_WIFI_ON_INIT_DONE, 0); + +} + +static void stack_ble (void) +{ + blsync_ble_start(); +} + +static void cmd_blsync_ble_start(char *buf, int len, int argc, char **argv) +{ + stack_wifi(); + vTaskDelay(1000); + stack_ble(); + vTaskDelay(1000); + + aos_post_event(EV_CLI, CODE_CLI_BLSYNC_START, 0); +} + +static void cmd_blsync_ble_stop(char *buf, int len, int argc, char **argv) +{ + aos_post_event(EV_CLI, CODE_CLI_BLSYNC_STOP, 0); +} + +const static struct cli_command cmds_user[] STATIC_CLI_CMD_ATTRIBUTE = { + { "blsync_ble_start", "blsync ble start", cmd_blsync_ble_start}, + { "blsync_ble_stop", "blsync ble stop", cmd_blsync_ble_stop}, + { "tencent" , "tencent test", cmd_tencent }, +}; + +static void _cli_init() +{ + wifi_mgmr_cli_init(); +} + +static int get_dts_addr(const char *name, uint32_t *start, uint32_t *off) +{ + uint32_t addr = hal_board_get_factory_addr(); + const void *fdt = (const void *)addr; + uint32_t offset; + + if (!name || !start || !off) { + return -1; + } + + offset = fdt_subnode_offset(fdt, 0, name); + if (offset <= 0) { + printf("%s NULL.\r\n", name); + return -1; + } + + *start = (uint32_t)fdt; + *off = offset; + + return 0; +} + +static void __opt_feature_init(void) +{ +#ifdef CONF_USER_ENABLE_VFS_ROMFS + romfs_register(); +#endif +} + +static void app_delayed_action_bleadv(void *arg) +{ + char *cmd1 = "ble_init\r\n"; + char *cmd2 = "ble_start_adv 0 0 0x100 0x100\r\n"; + + aos_cli_input_direct(cmd1, strlen(cmd1)); + aos_cli_input_direct(cmd2, strlen(cmd2)); +} + +static void app_delayed_action_wifi(void *arg) +{ + stack_wifi(); + aos_post_delayed_action(1000, app_delayed_action_bleadv, NULL); +} + +static void app_delayed_action_ble(void *arg) +{ + stack_ble(); + aos_post_delayed_action(1000, app_delayed_action_wifi, NULL); +} + +static void aos_loop_proc(void *pvParameters) +{ + int fd_console; + uint32_t fdt = 0, offset = 0; + static StackType_t proc_stack_looprt[512]; + static StaticTask_t proc_task_looprt; + + /*Init bloop stuff*/ + looprt_start(proc_stack_looprt, 512, &proc_task_looprt); + loopset_led_hook_on_looprt(); + loopset_i2c_hook_on_looprt(); + easyflash_init(); + vfs_init(); + vfs_device_init(); + + /* uart */ +#if 1 + if (0 == get_dts_addr("uart", &fdt, &offset)) { + vfs_uart_init(fdt, offset); + } +#else + vfs_uart_init_simple_mode(0, 7, 16, 2 * 1000 * 1000, "/dev/ttyS0"); +#endif + if (0 == get_dts_addr("gpio", &fdt, &offset)) { + hal_gpio_init_from_dts(fdt, offset); + } + + __opt_feature_init(); + aos_loop_init(); + + fd_console = aos_open("/dev/ttyS0", 0); + if (fd_console >= 0) { + printf("Init CLI with event Driven\r\n"); + aos_cli_init(0); + aos_poll_read_fd(fd_console, aos_cli_event_cb_read_get(), (void*)0x12345678); + _cli_init(); + } + + aos_register_event_filter(EV_WIFI, event_cb_wifi_event, NULL); + + aos_register_event_filter(EV_CLI, event_cb_cli, NULL); + + aos_post_delayed_action(1000, app_delayed_action_ble, NULL); + + + aos_register_event_filter(EV_I2C, event_cb_i2c_event, NULL); + hal_i2c_init(0, 500); + aos_loop_run(); + + puts("------------------------------------------\r\n"); + puts("+++++++++Critical Exit From Loop++++++++++\r\n"); + puts("******************************************\r\n"); + vTaskDelete(NULL); +} + +void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) +{ + /* If the buffers to be provided to the Idle task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} + +/* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) +{ + /* If the buffers to be provided to the Timer task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} + +void user_vAssertCalled(void) __attribute__ ((weak, alias ("vAssertCalled"))); +void vAssertCalled(void) +{ + volatile uint32_t ulSetTo1ToExitFunction = 0; + + taskDISABLE_INTERRUPTS(); + while( ulSetTo1ToExitFunction != 1 ) { + __asm volatile( "NOP" ); + } +} + +static void _dump_boot_info(void) +{ + char chip_feature[40]; + const char *banner; + + puts("Booting BL602 Chip...\r\n"); + + /*Display Banner*/ + if (0 == bl_chip_banner(&banner)) { + puts(banner); + } + puts("\r\n"); + /*Chip Feature list*/ + puts("\r\n"); + puts("------------------------------------------------------------\r\n"); + puts("RISC-V Core Feature:"); + bl_chip_info(chip_feature); + puts(chip_feature); + puts("\r\n"); + + puts("Build Version: "); + puts(BL_SDK_VER); // @suppress("Symbol is not resolved") + puts("\r\n"); + + puts("Build Version: "); + puts(BL_SDK_VER); // @suppress("Symbol is not resolved") + puts("\r\n"); + + puts("PHY Version: "); + puts(BL_SDK_PHY_VER); // @suppress("Symbol is not resolved") + puts("\r\n"); + + puts("RF Version: "); + puts(BL_SDK_RF_VER); // @suppress("Symbol is not resolved") + puts("\r\n"); + + puts("Build Date: "); + puts(__DATE__); + puts("\r\n"); + puts("Build Time: "); + puts(__TIME__); + puts("\r\n"); + puts("------------------------------------------------------------\r\n"); + +} + +static void system_init(void) +{ + blog_init(); + bl_irq_init(); + bl_sec_init(); + bl_sec_test(); + bl_dma_init(); + hal_boot2_init(); + + /* board config is set after system is init*/ + hal_board_cfg(0); +} + +static void testc(uint32_t e[4]){ + + printf("%d\n",sizeof(e)); + +} +static void system_thread_init() +{ + /*nothing here*/ + uint32_t a; + uint32_t b[2]; + char *c="Bouffalo Lab"; + char d[]="Bouffalo Lab"; + struct s_a + { + uint32_t mem1; + uint8_t mem2; + uint32_t mem3; + }; + struct s_b + { + uint32_t mem1; + uint8_t mem2; + uint16_t mem3; + }; + struct s_c + { + uint32_t mem1; + uint8_t mem2; + uint16_t mem3; + uint8_t mem4; + }; + testc(); + uint32_t ee[4]; + uint32_t *heap_ptr=NULL; + heap_ptr=pvPortMalloc(5); + printf("%d\n",sizeof(a)); + printf("%d\n",sizeof(b)); + printf("%d\n",sizeof(c)); + printf("%d\n",sizeof(d)); + printf("%d\n",sizeof(s_a)); + printf("%d\n",sizeof(s_b)); + printf("%d\n",sizeof(s_c)); + printf("%d\n",sizeof(heap_ptr)); + testc(ee); +} + + + +void bfl_main() +{ + static StackType_t aos_loop_proc_stack[1024]; + static StaticTask_t aos_loop_proc_task; + + bl_sys_early_init(); + + /*Init UART In the first place*/ + bl_uart_init(0, 16, 7, 255, 255, 2 * 1000 * 1000); + puts("Starting bl602 now....\r\n"); + + bl_sys_init(); + + _dump_boot_info(); + + vPortDefineHeapRegions(xHeapRegions); + printf("Heap %u@%p, %u@%p\r\n", + (unsigned int)&_heap_size, &_heap_start, + (unsigned int)&_heap_wifi_size, &_heap_wifi_start + ); + + system_init(); + system_thread_init(); + + puts("[OS] Starting aos_loop_proc task...\r\n"); + xTaskCreateStatic(aos_loop_proc, (char*)"event_loop", 1024, NULL, 15, aos_loop_proc_stack, &aos_loop_proc_task); + + puts("[OS] Starting TCP/IP Stack...\r\n"); + tcpip_init(NULL, NULL); + + puts("[OS] Starting OS Scheduler...\r\n"); + vTaskStartScheduler(); +} diff --git a/customer_app/bl602_demo_qcloud/sdk_app_qcloud/wifi_prov_api.c b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/wifi_prov_api.c new file mode 100644 index 00000000..45700ff3 --- /dev/null +++ b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/wifi_prov_api.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Bouffalolab. + * + * This file is part of + * *** Bouffalolab Software Dev Kit *** + * (see www.bouffalolab.com). + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Bouffalo Lab nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "wifi_prov_api.h" + +#include +#include +#include + +#include +#include +#include +#include + +int wifi_prov_api_event_trigger_connect(struct wifi_conn *info) +{ + if (aos_post_event(EV_WIFI, CODE_WIFI_ON_PROV_CONNECT, (unsigned long)info) >= 0) { + puts("[APP] [PROV] trigger CONNECT event OK\r\n"); + } else { + puts("[APP] [PROV] trigger CONNECT event failed\r\n"); + return -1; + } + + return 0; +} + +int wifi_prov_api_event_trigger_disconnect(void) +{ + if (aos_post_event(EV_WIFI, CODE_WIFI_ON_PROV_DISCONNECT, 0) >= 0) { + puts("[APP] [PROV] trigger DISCONNECT event OK\r\n"); + } else { + puts("[APP] [PROV] trigger DISCONNECT event failed\r\n"); + return -1; + } + + return 0; +} + +int wifi_prov_api_event_trigger_scan(void(*complete)(void *)) +{ + if (aos_post_event(EV_WIFI, CODE_WIFI_ON_PROV_SCAN_START, (unsigned long)complete) >= 0) { + puts("[APP] [PROV] trigger scan event OK\r\n"); + } else { + puts("[APP] [PROV] trigger scan event failed\r\n"); + return -1; + } + + return 0; +} + +int wifi_prov_api_event_state_get(void(*state_get)(void *)) +{ + if (aos_post_event(EV_WIFI, CODE_WIFI_ON_PROV_STATE_GET, (unsigned long)state_get) >= 0) { + puts("[APP] [PROV] trigger scan event OK\r\n"); + } else { + puts("[APP] [PROV] trigger scan event failed\r\n"); + return -1; + } + + return 0; +} diff --git a/customer_app/bl602_demo_qcloud/sdk_app_qcloud/wifi_prov_api.h b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/wifi_prov_api.h new file mode 100644 index 00000000..f396cbcc --- /dev/null +++ b/customer_app/bl602_demo_qcloud/sdk_app_qcloud/wifi_prov_api.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Bouffalolab. + * + * This file is part of + * *** Bouffalolab Software Dev Kit *** + * (see www.bouffalolab.com). + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Bouffalo Lab nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __WIFI_PROV_API_H__ +#define __WIFI_PROV_API_H__ +#include "blsync_ble.h" +int wifi_prov_api_event_trigger_connect(struct wifi_conn *info); +int wifi_prov_api_event_trigger_disconnect(void); +int wifi_prov_api_event_trigger_scan(void(*complete)(void *)); +int wifi_prov_api_event_state_get(void(*state_get)(void *)); +#endif