Merge pull request #46 from shchen-Lab/master

Tencent Cloud
This commit is contained in:
Yafei 2021-04-09 19:09:07 +08:00 committed by GitHub
commit e782cb276c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
153 changed files with 28556 additions and 0 deletions

Binary file not shown.

Binary file not shown.

View File

@ -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。(\ `下载链接 <https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html>`__\)
.. 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.exechip 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. 打开配网APPAPP自动搜索蓝牙设备需手机蓝牙已开启)搜索到设备名“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

View File

@ -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

View File

@ -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/

Binary file not shown.

View File

@ -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)

View File

@ -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

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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 <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#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_ */

View File

@ -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_ */

View File

@ -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 <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/**
* @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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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

View File

@ -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 <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_PLATFORM_IS_LINUX_)
#include <assert.h>
#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__ */

View File

@ -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 <Windows.h>
#include <direct.h>
#include <limits.h>
typedef unsigned long ssize_t;
#define getcwd(buffer, len) _getcwd(buffer, len)
#endif
#if defined(__linux__)
#include <fcntl.h>
#include <pthread.h>
//#include <sys/time.h>
#include <assert.h>
#include <limits.h>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#endif
#ifdef __cplusplus
}
#endif
#endif /* PLATFORM_H_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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 <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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_ */

View File

@ -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

View File

@ -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 <errno.h>
#include <stdint.h>
#include <string.h>
#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

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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

View File

@ -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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#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 *)&params->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

View File

@ -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 <errno.h>
#include <stdio.h>
#include <string.h>
#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;
}

View File

@ -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 <errno.h>
#include <stdint.h>
#include <string.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 "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

View File

@ -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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <timers.h>
#include "qcloud_iot_import.h"
//#define PLATFORM_HAS_TIME_FUNCS
//#define PLATFORM_HAS_CMSIS
#ifdef PLATFORM_HAS_TIME_FUNCS
#include <sys/time.h>
#include <time.h>
#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

View File

@ -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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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, &timestamp)) {
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

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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

View File

@ -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

View File

@ -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 <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#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&timestamp=%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

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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 <stdint.h>
#include <stdio.h>
#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

View File

@ -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__ */

View File

@ -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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#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

View File

@ -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 <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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_

View File

@ -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 <stdbool.h>
#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_ */

View File

@ -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_

View File

@ -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_ */

View File

@ -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 <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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_

View File

@ -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_ */

View File

@ -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__ */

View File

@ -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_

View File

@ -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 <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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_

View File

@ -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_

View File

@ -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 <stddef.h>
#include <stdint.h>
#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_ */

View File

@ -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 <stdint.h>
/* 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_ */

View File

@ -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 <stdint.h>
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_ */

View File

@ -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 <stdint.h>
#include <sys/types.h>
#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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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 <stddef.h>
#include <stdint.h>
//========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:
<ul><li>Alignment if VIA padlock is
used.</li>
<li>Simplifying key expansion in the 256-bit
case by generating an extra round key.
</li></ul> */
} 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:
* <ul><li>128 bits</li>
* <li>192 bits</li>
* <li>256 bits</li></ul>
*
* \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:
* <ul><li>128 bits</li>
* <li>192 bits</li>
* <li>256 bits</li></ul>
*
* \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

View File

@ -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 <stdio.h>
#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_ */

View File

@ -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 <string.h>
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

View File

@ -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 <stdbool.h>
#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_ */

View File

@ -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 <stdlib.h>
/*
* 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_

View File

@ -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

View File

@ -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_ */

View File

@ -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__

View File

@ -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

View File

@ -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_

View File

@ -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 <stdint.h>
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_ */

View File

@ -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 <stdint.h>
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_ */

View File

@ -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 <stdint.h>
#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_ */

View File

@ -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 <stdint.h>
#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_ */

View File

@ -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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

View File

@ -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;
}

View File

@ -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 <ctype.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#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

View File

@ -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 <limits.h>
#include <string.h>
#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

View File

@ -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

View File

@ -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 <string.h>
#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

View File

@ -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 <string.h>
#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

View File

@ -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 <string.h>
#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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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

View File

@ -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 <string.h>
#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

View File

@ -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 <stdio.h>
#include <string.h>
#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

View File

@ -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 <string.h>
#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

View File

@ -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 <stdlib.h>
#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

View File

@ -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 <stdbool.h>
#include <string.h>
#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

View File

@ -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 <string.h>
#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

View File

@ -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++;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 <stdint.h>
#include <stdlib.h>
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

Some files were not shown because too many files have changed in this diff Show More