merge new qcloud sdk
1. qcloud has a great revolution, the protocol has been changed to implement data template, so the old TencentCloud_SDK developed by us will not work fine now(mqtt still works, but data template will not works fine for recently created product/devices). 2. I merge the official qlcoud sdk(include both the iot-hub and iot-explorer sdk) into the componet/conectivity to support new protocol of data template 3. iot-hub sdk, supply the fundamental iot protocol(like mqtt coap, etc.) iot-explorer sdk, supply the high level service like data template based on mqtt 4. To know how it works, see qcloud_iot_explorer_sdk_data_template、qcloud_iot_hub_sdk_mqtt example(keil project in board\TencentOS_tiny_EVB_MX_Plus\KEIL\qcloud_iot_explorer_sdk_data_template and board\TencentOS_tiny_EVB_MX_Plus\KEIL\qcloud_iot_hub_sdk_mqtt)
This commit is contained in:
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "utils_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!", 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!", 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_aciton(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;
|
||||
|
||||
char *type_str = NULL;
|
||||
char* client_token = NULL;
|
||||
char* action_id = NULL;
|
||||
char *pInput = NULL;
|
||||
int timestamp = 0;
|
||||
|
||||
Log_d("recv:%.*s",(int) message->payload_len, (char *) message->payload);
|
||||
|
||||
// prase_method
|
||||
if (!parse_template_method_type((char *) message->payload, &type_str))
|
||||
{
|
||||
Log_e("Fail to parse method!");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
if (strcmp(type_str, CALL_ACTION)) {
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
// prase client Token
|
||||
if (!parse_client_token((char *) message->payload, &client_token)) {
|
||||
Log_e("fail to parse client token!");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
// prase action ID
|
||||
if (!parse_action_id((char *) message->payload, &action_id)) {
|
||||
Log_e("fail to parse action id!");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
// prase timestamp
|
||||
if (!parse_time_stamp((char *) message->payload, ×tamp)) {
|
||||
Log_e("fail to parse timestamp!");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
// prase action input
|
||||
if (!parse_action_input((char *) message->payload, &pInput)) {
|
||||
Log_e("fail to parse action input!");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
//find action ID in register list and call handle
|
||||
if (template_client != NULL)
|
||||
_handle_aciton(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", iot_device_info_get()->product_id, iot_device_info_get()->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;
|
||||
|
||||
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, 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", iot_device_info_get()->product_id, iot_device_info_get()->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
|
@@ -0,0 +1,831 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
#include "utils_param_check.h"
|
||||
#include "data_template_client_json.h"
|
||||
#include "data_template_client.h"
|
||||
#include "data_template_action.h"
|
||||
#include "data_template_client_common.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 *handle, char *topicName, PublishParams *pParams)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)handle;
|
||||
|
||||
return qcloud_iot_mqtt_publish(template_client->mqtt, topicName, pParams);
|
||||
}
|
||||
|
||||
int IOT_Template_Subscribe(void *handle, char *topicFilter, SubscribeParams *pParams)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)handle;
|
||||
|
||||
return qcloud_iot_mqtt_subscribe(template_client->mqtt, topicFilter, pParams);
|
||||
}
|
||||
|
||||
int IOT_Template_Unsubscribe(void *handle, char *topicFilter)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)handle;
|
||||
|
||||
return qcloud_iot_mqtt_unsubscribe(template_client->mqtt, topicFilter);
|
||||
}
|
||||
|
||||
bool IOT_Template_IsConnected(void *handle)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
|
||||
|
||||
IOT_FUNC_EXIT_RC(IOT_MQTT_IsConnected(template_client->mqtt))
|
||||
}
|
||||
|
||||
int IOT_Template_Register_Property(void *handle, DeviceProperty *pProperty, OnPropRegCallback callback)
|
||||
{
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template*)handle;
|
||||
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 *handle, DeviceProperty *pProperty)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template*)handle;
|
||||
|
||||
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 *handle, DeviceAction *pAction, OnActionHandleCallback callback)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template*)handle;
|
||||
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 *handle, DeviceAction *pAction)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Template* ptemplate = (Qcloud_IoT_Template*)handle;
|
||||
|
||||
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->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");
|
||||
}
|
||||
|
||||
if (*((ReplyAck *)request->user_context) == ACK_ACCEPTED){
|
||||
Log_d("Received Json Document=%s", pReceivedJsonDocument);
|
||||
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)
|
||||
{
|
||||
uintptr_t packet_id = (uintptr_t)msg->msg;
|
||||
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)context;
|
||||
MQTTMessage* topic_info = (MQTTMessage*)msg->msg;
|
||||
|
||||
switch (msg->event_type) {
|
||||
case MQTT_EVENT_SUBCRIBE_SUCCESS:
|
||||
Log_d("template subscribe success, packet-id=%u", packet_id);
|
||||
if (template_client->inner_data.sync_status > 0)
|
||||
template_client->inner_data.sync_status = 0;
|
||||
break;
|
||||
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
|
||||
Log_d("template subscribe wait ack timeout, packet-id=%u", packet_id);
|
||||
if (template_client->inner_data.sync_status > 0)
|
||||
template_client->inner_data.sync_status = -1;
|
||||
break;
|
||||
case MQTT_EVENT_SUBCRIBE_NACK:
|
||||
Log_d("template subscribe nack, packet-id=%u", packet_id);
|
||||
if (template_client->inner_data.sync_status > 0)
|
||||
template_client->inner_data.sync_status = -1;
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISH_RECVEIVED:
|
||||
Log_d("template topic message arrived but without any related handle: 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 (template_client->event_handle.h_fp != NULL)
|
||||
{
|
||||
template_client->event_handle.h_fp(template_client, template_client->event_handle.context, msg);
|
||||
}
|
||||
}
|
||||
|
||||
int IOT_Template_JSON_ConstructReportArray(void *handle, 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*)handle;
|
||||
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);
|
||||
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->key, pJsonNode->data, pJsonNode->type);
|
||||
|
||||
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 *handle, char *pClientToken, OnReplyCallback callback, uint32_t timeout_ms)
|
||||
{
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc;
|
||||
char JsonDoc[MAX_CLEAE_DOC_LEN];
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pClientToken, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(template_client->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 (template_client->inner_data.sync_status < 0) {
|
||||
rc = subscribe_template_downstream_topic(template_client);
|
||||
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(template_client, &request_params, JsonDoc, MAX_CLEAE_DOC_LEN);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Template_Report(void *handle, char *pJsonDoc, size_t sizeOfBuffer, OnReplyCallback callback, void *userContext, uint32_t timeout_ms)
|
||||
{
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(template_client->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 (template_client->inner_data.sync_status < 0) {
|
||||
rc = subscribe_template_downstream_topic(template_client);
|
||||
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(template_client, &request_params, pJsonDoc, sizeOfBuffer);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Template_Report_Sync(void *handle, char *pJsonDoc, size_t sizeOfBuffer, uint32_t timeout_ms)
|
||||
{
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, 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*)handle;
|
||||
|
||||
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(handle, 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(handle, 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 *handle, 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*)handle;
|
||||
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);
|
||||
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->key, pJsonNode->data, pJsonNode->type);
|
||||
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->key, pJsonNode->data, pJsonNode->type);
|
||||
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 *handle, char *pJsonDoc, size_t sizeOfBuffer, OnReplyCallback callback, void *userContext, uint32_t timeout_ms)
|
||||
{
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(template_client->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 (template_client->inner_data.sync_status < 0) {
|
||||
rc = subscribe_template_downstream_topic(template_client);
|
||||
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(template_client, &request_params, pJsonDoc, sizeOfBuffer);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Template_Report_SysInfo_Sync(void *handle, char *pJsonDoc, size_t sizeOfBuffer, uint32_t timeout_ms)
|
||||
{
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, 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*)handle;
|
||||
|
||||
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(handle, 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(handle, 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 *handle, OnReplyCallback callback, void *userContext, uint32_t timeout_ms)
|
||||
{
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(callback, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(template_client->mqtt) == false) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
|
||||
// if topic $thing/down/property subscribe not success before, subsrcibe again
|
||||
if (template_client->inner_data.sync_status < 0) {
|
||||
rc = subscribe_template_downstream_topic(template_client);
|
||||
if (rc < 0)
|
||||
{
|
||||
Log_e("Subcribe $thing/down/property fail!");
|
||||
}
|
||||
}
|
||||
|
||||
char getRequestJsonDoc[MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN];
|
||||
build_empty_json(&(template_client->inner_data.token_num), getRequestJsonDoc);
|
||||
|
||||
//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(template_client, &request_params, getRequestJsonDoc, MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Template_GetStatus_sync(void *handle, uint32_t timeout_ms)
|
||||
{
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template* pTemplate = (Qcloud_IoT_Template*)handle;
|
||||
|
||||
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(handle, _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(handle, 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 *handle, char *pJsonDoc, size_t sizeOfBuffer, sReplyPara *replyPara)
|
||||
{
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(template_client->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 (template_client->inner_data.sync_status < 0) {
|
||||
rc = subscribe_template_downstream_topic(template_client);
|
||||
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(template_client, &request_params, pJsonDoc, sizeOfBuffer);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Template_Yield(void *handle, uint32_t timeout_ms) {
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(timeout_ms, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template *ptemplate = (Qcloud_IoT_Template *)handle;
|
||||
POINTER_SANITY_CHECK(ptemplate, QCLOUD_ERR_INVAL);
|
||||
|
||||
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_Construct(TemplateInitParams *pParams)
|
||||
{
|
||||
POINTER_SANITY_CHECK(pParams, NULL);
|
||||
int rc;
|
||||
|
||||
Qcloud_IoT_Template *template_client = NULL;
|
||||
if ((template_client = (Qcloud_IoT_Template *)HAL_Malloc(sizeof(Qcloud_IoT_Template))) == NULL) {
|
||||
Log_e("memory not enough to malloc TemplateClient");
|
||||
}
|
||||
|
||||
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 = template_client;
|
||||
|
||||
void *mqtt_client = NULL;
|
||||
if ((mqtt_client = IOT_MQTT_Construct(&mqtt_init_params)) == NULL) {
|
||||
HAL_Free(template_client);
|
||||
goto End;
|
||||
}
|
||||
|
||||
template_client->mqtt = mqtt_client;
|
||||
template_client->event_handle = pParams->event_handle;
|
||||
template_client->inner_data.upstream_topic = NULL;
|
||||
template_client->inner_data.downstream_topic = NULL;
|
||||
template_client->inner_data.token_num = 0;
|
||||
template_client->inner_data.eventflags = 0;
|
||||
|
||||
rc = qcloud_iot_template_init(template_client);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
IOT_MQTT_Destroy(&(template_client->mqtt));
|
||||
HAL_Free(template_client);
|
||||
goto End;
|
||||
}
|
||||
|
||||
rc = subscribe_template_downstream_topic(template_client);
|
||||
if (rc < 0)
|
||||
{
|
||||
Log_e("Subcribe $thing/down/property fail!");
|
||||
}
|
||||
else {
|
||||
template_client->inner_data.sync_status = rc;
|
||||
while (rc == template_client->inner_data.sync_status) {
|
||||
IOT_Template_Yield(template_client, 100);
|
||||
}
|
||||
if (0 == template_client->inner_data.sync_status) {
|
||||
Log_i("Sync device data successfully");
|
||||
} else {
|
||||
Log_e("Sync device data failed");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EVENT_POST_ENABLED
|
||||
rc = IOT_Event_Init(template_client);
|
||||
if (rc < 0)
|
||||
{
|
||||
Log_e("event init failed: %d", rc);
|
||||
IOT_Template_Destroy(&(template_client->mqtt));
|
||||
HAL_Free(template_client);
|
||||
goto End;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ACTION_ENABLED
|
||||
rc = IOT_Action_Init(template_client);
|
||||
if (rc < 0)
|
||||
{
|
||||
Log_e("action init failed: %d", rc);
|
||||
IOT_Template_Destroy(&(template_client->mqtt));
|
||||
HAL_Free(template_client);
|
||||
goto End;
|
||||
}
|
||||
#endif
|
||||
|
||||
return template_client;
|
||||
|
||||
End:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int IOT_Template_Destroy(void *handle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Template* template_client = (Qcloud_IoT_Template*)handle;
|
||||
qcloud_iot_template_reset(handle);
|
||||
|
||||
IOT_MQTT_Destroy(&template_client->mqtt);
|
||||
|
||||
if (NULL != template_client->mutex) {
|
||||
HAL_MutexDestroy(template_client->mutex);
|
||||
}
|
||||
|
||||
if (NULL != template_client->inner_data.downstream_topic) {
|
||||
HAL_Free(template_client->inner_data.downstream_topic);
|
||||
template_client->inner_data.downstream_topic = NULL;
|
||||
}
|
||||
|
||||
HAL_Free(handle);
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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
|
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "qcloud_iot_device.h"
|
||||
#include "lite-utils.h"
|
||||
#include "data_template_client_json.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;
|
||||
|
||||
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){
|
||||
Log_d("Json type wait to be deal,%s",value);
|
||||
}else{
|
||||
Log_e("pProperty type unknow,%d",pProperty->type);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* add field of client token into JSON
|
||||
*
|
||||
* @param pJsonDocument JSON string
|
||||
* @param maxSizeOfJsonDocument max size of JSON string
|
||||
* @return length after adding
|
||||
*/
|
||||
static int32_t _add_client_token(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint32_t *tokenNumber) {
|
||||
|
||||
int32_t rc_of_snprintf = HAL_Snprintf(pJsonDocument, maxSizeOfJsonDocument, "%s-%u", iot_device_info_get()->product_id, (*tokenNumber)++);
|
||||
|
||||
return rc_of_snprintf;
|
||||
}
|
||||
|
||||
int 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\":", 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, "%s,", (char *) (pData));
|
||||
}
|
||||
}
|
||||
|
||||
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\":", 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;
|
||||
}
|
||||
|
||||
int generate_client_token(char *pStrBuffer, size_t sizeOfBuffer, uint32_t *tokenNumber) {
|
||||
return _add_client_token(pStrBuffer, sizeOfBuffer, tokenNumber);
|
||||
}
|
||||
|
||||
void build_empty_json(uint32_t *tokenNumber, char *pJsonBuffer) {
|
||||
HAL_Snprintf(pJsonBuffer, MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN, "{\"clientToken\":\"%s-%u\"}", iot_device_info_get()->product_id, (*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))) {
|
||||
}
|
||||
else {
|
||||
_direct_update_value(property_data, pProperty);
|
||||
ret = true;
|
||||
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
|
@@ -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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "qcloud_iot_import.h"
|
||||
#include "utils_param_check.h"
|
||||
#include "utils_list.h"
|
||||
|
||||
#include "data_template_client.h"
|
||||
#include "data_template_client_json.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(void* pClient)
|
||||
{
|
||||
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", iot_device_info_get()->product_id, iot_device_info_get()->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(pClient, 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", iot_device_info_get()->product_id, iot_device_info_get()->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(void *pClient)
|
||||
{
|
||||
POINTER_SANITY_CHECK_RTN(pClient);
|
||||
|
||||
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template *)pClient;
|
||||
if (template_client->inner_data.property_handle_list) {
|
||||
list_destroy(template_client->inner_data.property_handle_list);
|
||||
}
|
||||
|
||||
_unsubscribe_template_downstream_topic(template_client->mqtt);
|
||||
|
||||
if (template_client->inner_data.reply_list)
|
||||
{
|
||||
list_destroy(template_client->inner_data.reply_list);
|
||||
}
|
||||
|
||||
if (template_client->inner_data.event_list)
|
||||
{
|
||||
list_destroy(template_client->inner_data.event_list);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
_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_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
|
||||
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template*)mqtt_client->event_handle.context;
|
||||
|
||||
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_d("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);
|
||||
_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", iot_device_info_get()->product_id, iot_device_info_get()->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;
|
||||
|
||||
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
|
@@ -0,0 +1,493 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
#include "utils_param_check.h"
|
||||
#include "lite-utils.h"
|
||||
#include "data_template_client.h"
|
||||
#include "data_template_event.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_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
|
||||
Qcloud_IoT_Template *template_client = (Qcloud_IoT_Template*)mqtt_client->event_handle.context;
|
||||
|
||||
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)){
|
||||
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 status:%s", client_token, code, status);
|
||||
|
||||
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(Request));
|
||||
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);
|
||||
HAL_Snprintf(pReply->client_token, EVENT_TOKEN_MAX_LEN, "%s-%u", iot_device_info_get()->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\":{",\
|
||||
pEvent->event_name, 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\":{",\
|
||||
pEvent->event_name, 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\":{",\
|
||||
pEvent->event_name, 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\":{",\
|
||||
pEvent->event_name, 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", iot_device_info_get()->product_id, iot_device_info_get()->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 = QOS0;
|
||||
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", iot_device_info_get()->product_id, iot_device_info_get()->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;
|
||||
|
||||
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
|
657
components/connectivity/qcloud-iot-explorer-sdk/3rdparty/sdk_src/services/ota/ota_client.c
vendored
Normal file
657
components/connectivity/qcloud-iot-explorer-sdk/3rdparty/sdk_src/services/ota/ota_client.c
vendored
Normal file
@@ -0,0 +1,657 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ota_client.h"
|
||||
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "utils_param_check.h"
|
||||
|
||||
#include "ota_lib.h"
|
||||
#include "ota_fetch.h"
|
||||
|
||||
#include "utils_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", 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;
|
||||
h_ota->state = IOT_OTAS_INITED;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (NULL != h_ota->version) {
|
||||
HAL_Free(h_ota->version);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
h_ota->size_fetched += offset;
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
153
components/connectivity/qcloud-iot-explorer-sdk/3rdparty/sdk_src/services/ota/ota_fetch.c
vendored
Normal file
153
components/connectivity/qcloud-iot-explorer-sdk/3rdparty/sdk_src/services/ota/ota_fetch.c
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ota_fetch.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
#include "qcloud_iot_ca.h"
|
||||
#include "utils_httpc.h"
|
||||
|
||||
|
||||
|
||||
#define OTA_HTTP_HEAD_CONTENT_LEN 256
|
||||
|
||||
/* ofc, OTA fetch channel */
|
||||
|
||||
typedef struct {
|
||||
|
||||
const char *url;
|
||||
HTTPClient http; /* http client */
|
||||
HTTPClientData http_data; /* http client data */
|
||||
|
||||
} OTAHTTPStruct;
|
||||
|
||||
static int is_begin_with(const char * str1,char *str2)
|
||||
{
|
||||
if(str1 == NULL || str2 == NULL)
|
||||
return -1;
|
||||
int len1 = strlen(str1);
|
||||
int len2 = strlen(str2);
|
||||
if((len1 < len2) || (len1 == 0 || len2 == 0))
|
||||
return -1;
|
||||
char *p = str2;
|
||||
int i = 0;
|
||||
while(*p != '\0')
|
||||
{
|
||||
if(*p != str1[i])
|
||||
return 0;
|
||||
p++;
|
||||
i++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static char sg_head_content[OTA_HTTP_HEAD_CONTENT_LEN];
|
||||
void *ofc_Init(const char *url, uint32_t offset, uint32_t size)
|
||||
{
|
||||
OTAHTTPStruct *h_odc;
|
||||
|
||||
if (NULL == (h_odc = HAL_Malloc(sizeof(OTAHTTPStruct)))) {
|
||||
Log_e("allocate for h_odc failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(h_odc, 0, sizeof(OTAHTTPStruct));
|
||||
memset(sg_head_content, 0, OTA_HTTP_HEAD_CONTENT_LEN);
|
||||
HAL_Snprintf(sg_head_content, OTA_HTTP_HEAD_CONTENT_LEN,\
|
||||
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"\
|
||||
"Accept-Encoding: gzip, deflate\r\n"\
|
||||
"Range: bytes=%d-%d\r\n",
|
||||
offset, size);
|
||||
|
||||
Log_d("head_content:%s", sg_head_content);
|
||||
/* set http request-header parameter */
|
||||
h_odc->http.header = sg_head_content;
|
||||
h_odc->url = url;
|
||||
|
||||
return h_odc;
|
||||
}
|
||||
|
||||
int32_t qcloud_ofc_connect(void *handle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
OTAHTTPStruct * h_odc = (OTAHTTPStruct *)handle;
|
||||
|
||||
int port = 80;
|
||||
const char *ca_crt = NULL;
|
||||
|
||||
if (is_begin_with(h_odc->url, "https"))
|
||||
{
|
||||
port = 443;
|
||||
ca_crt = iot_https_ca_get();
|
||||
}
|
||||
|
||||
int32_t rc = qcloud_http_client_common(&h_odc->http, h_odc->url, port, ca_crt, HTTP_GET, &h_odc->http_data);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
|
||||
int32_t qcloud_ofc_fetch(void *handle, char *buf, uint32_t bufLen, uint32_t timeout_s)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int diff;
|
||||
OTAHTTPStruct * h_odc = (OTAHTTPStruct *)handle;
|
||||
|
||||
h_odc->http_data.response_buf = buf;
|
||||
h_odc->http_data.response_buf_len = bufLen;
|
||||
diff = h_odc->http_data.response_content_len - h_odc->http_data.retrieve_len;
|
||||
|
||||
int rc = qcloud_http_recv_data(&h_odc->http, timeout_s * 1000, &h_odc->http_data);
|
||||
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);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(h_odc->http_data.response_content_len - h_odc->http_data.retrieve_len - diff);
|
||||
}
|
||||
|
||||
|
||||
int qcloud_ofc_deinit(void *handle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
if (NULL != handle) {
|
||||
HAL_Free(handle);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
324
components/connectivity/qcloud-iot-explorer-sdk/3rdparty/sdk_src/services/ota/ota_lib.c
vendored
Normal file
324
components/connectivity/qcloud-iot-explorer-sdk/3rdparty/sdk_src/services/ota/ota_lib.c
vendored
Normal file
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
#include "ota_client.h"
|
||||
|
||||
#include "utils_md5.h"
|
||||
#include "lite-utils.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", 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\"}}",
|
||||
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\"}}", 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, 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, 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\"}}",
|
||||
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\"}}",
|
||||
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
|
189
components/connectivity/qcloud-iot-explorer-sdk/3rdparty/sdk_src/services/ota/ota_mqtt.c
vendored
Normal file
189
components/connectivity/qcloud-iot-explorer-sdk/3rdparty/sdk_src/services/ota/ota_mqtt.c
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 "ota_client.h"
|
||||
|
||||
#include <string.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;
|
||||
} 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", OTATopicType, productId, 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);
|
||||
}
|
||||
}
|
||||
|
||||
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.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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (NULL != handle) {
|
||||
HAL_Free(handle);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
/* 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
|
213
components/connectivity/qcloud-iot-explorer-sdk/3rdparty/sdk_src/services/system/system_mqtt.c
vendored
Normal file
213
components/connectivity/qcloud-iot-explorer-sdk/3rdparty/sdk_src/services/system/system_mqtt.c
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud_iot_export.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
|
||||
#ifdef SYSTEM_COMM
|
||||
|
||||
#include "qcloud_iot_export_system.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "lite-utils.h"
|
||||
#include "device.h"
|
||||
|
||||
typedef struct _sys_mqtt_state {
|
||||
bool topic_sub_ok;
|
||||
bool result_recv_ok;
|
||||
long time;
|
||||
}SysMQTTState;
|
||||
|
||||
static SysMQTTState sg_state = {
|
||||
.topic_sub_ok = false,
|
||||
.result_recv_ok = false,
|
||||
.time = 0};
|
||||
|
||||
|
||||
static void _system_mqtt_message_callback(void *pClient, MQTTMessage *message, void *pUserData)
|
||||
{
|
||||
#define MAX_RECV_LEN (512)
|
||||
|
||||
POINTER_SANITY_CHECK_RTN(message);
|
||||
|
||||
static char rcv_buf[MAX_RECV_LEN + 1];
|
||||
size_t len = (message->payload_len > MAX_RECV_LEN)?MAX_RECV_LEN:(message->payload_len);
|
||||
|
||||
if(message->payload_len > MAX_RECV_LEN){
|
||||
Log_e("payload len oversize");
|
||||
}
|
||||
memcpy(rcv_buf, message->payload, len);
|
||||
rcv_buf[len] = '\0'; // jsmn_parse relies on a string
|
||||
SysMQTTState *state = (SysMQTTState *)pUserData;
|
||||
|
||||
Log_d("Recv Msg Topic:%s, payload:%s", message->ptopic, rcv_buf);
|
||||
|
||||
char* value = LITE_json_value_of("time", rcv_buf);
|
||||
if (value != NULL)
|
||||
state->time = atol(value);
|
||||
|
||||
state->result_recv_ok = true;
|
||||
HAL_Free(value);
|
||||
return;
|
||||
}
|
||||
|
||||
static void _system_mqtt_sub_event_handler(void *pclient, MQTTEventType event_type, void *pUserData)
|
||||
{
|
||||
SysMQTTState *state = (SysMQTTState *)pUserData;
|
||||
|
||||
switch(event_type) {
|
||||
case MQTT_EVENT_SUBCRIBE_SUCCESS:
|
||||
Log_d("mqtt sys topic subscribe success");
|
||||
state->topic_sub_ok = true;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
|
||||
Log_i("mqtt sys topic subscribe timeout");
|
||||
state->topic_sub_ok = false;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_NACK:
|
||||
Log_i("mqtt sys topic subscribe NACK");
|
||||
state->topic_sub_ok = false;
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBE:
|
||||
Log_i("mqtt sys topic has been unsubscribed");
|
||||
state->topic_sub_ok = false;;
|
||||
break;
|
||||
case MQTT_EVENT_CLIENT_DESTROY:
|
||||
Log_i("mqtt client has been destroyed");
|
||||
state->topic_sub_ok = false;;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int _iot_system_info_get_publish(void *pClient)
|
||||
{
|
||||
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
|
||||
DeviceInfo *dev_info = iot_device_info_get();
|
||||
POINTER_SANITY_CHECK(dev_info, QCLOUD_ERR_INVAL);
|
||||
|
||||
char topic_name[128] = {0};
|
||||
char payload_content[128] = {0};
|
||||
|
||||
HAL_Snprintf(topic_name, sizeof(topic_name), "$sys/operation/%s/%s", dev_info->product_id, dev_info->device_name);
|
||||
HAL_Snprintf(payload_content, sizeof(payload_content), "{\"type\": \"get\", \"resource\": [\"time\"]}");
|
||||
|
||||
PublishParams pub_params = DEFAULT_PUB_PARAMS;
|
||||
pub_params.qos = QOS0;
|
||||
pub_params.payload = payload_content;
|
||||
pub_params.payload_len = strlen(payload_content);
|
||||
|
||||
return IOT_MQTT_Publish(mqtt_client, topic_name, &pub_params);
|
||||
}
|
||||
|
||||
static int _iot_system_info_result_subscribe(void *pClient)
|
||||
{
|
||||
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
|
||||
|
||||
DeviceInfo *dev_info = iot_device_info_get();
|
||||
POINTER_SANITY_CHECK(dev_info, QCLOUD_ERR_INVAL);
|
||||
|
||||
char topic_name[128] = {0};
|
||||
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "$sys/operation/result/%s/%s", dev_info->product_id, dev_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 = _system_mqtt_message_callback;
|
||||
sub_params.on_sub_event_handler = _system_mqtt_sub_event_handler;
|
||||
sub_params.user_data = (void *)&sg_state;
|
||||
sub_params.qos = QOS0;
|
||||
|
||||
return IOT_MQTT_Subscribe(pClient, topic_name, &sub_params);
|
||||
}
|
||||
|
||||
int IOT_Get_SysTime(void* pClient, long *time)
|
||||
{
|
||||
int ret = 0;
|
||||
int cntSub = 0;
|
||||
int cntRev = 0;
|
||||
|
||||
POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
|
||||
|
||||
// subscribe sys topic: $sys/operation/get/${productid}/${devicename}
|
||||
// skip this if the subscription is done and valid
|
||||
if(!sg_state.topic_sub_ok){
|
||||
for(cntSub = 0; cntSub < 3; cntSub++){
|
||||
ret = _iot_system_info_result_subscribe(mqtt_client);
|
||||
if (ret < 0) {
|
||||
Log_w("_iot_system_info_result_subscribe failed: %d, cnt: %d", ret, cntSub);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* wait for sub ack */
|
||||
ret = qcloud_iot_mqtt_yield((Qcloud_IoT_Client *)pClient, 100);
|
||||
if(sg_state.topic_sub_ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return failure if subscribe failed
|
||||
if(!sg_state.topic_sub_ok){
|
||||
Log_e("Subscribe sys topic failed!");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
sg_state.result_recv_ok = false;
|
||||
// publish msg to get system timestamp
|
||||
ret = _iot_system_info_get_publish(mqtt_client);
|
||||
if (ret < 0) {
|
||||
Log_e("client publish sys topic failed :%d.", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
do {
|
||||
ret = qcloud_iot_mqtt_yield((Qcloud_IoT_Client *)pClient, 100);
|
||||
cntRev++;
|
||||
} while(!sg_state.result_recv_ok && cntRev < 20);
|
||||
|
||||
|
||||
if (sg_state.result_recv_ok) {
|
||||
*time = sg_state.time;
|
||||
ret = QCLOUD_RET_SUCCESS;
|
||||
} else {
|
||||
*time = 0;
|
||||
ret = QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user