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:
879
components/connectivity/qcloud-iot-hub-sdk-3.1.2/3rdparty/sdk_src/services/shadow/shadow_client.c
vendored
Normal file
879
components/connectivity/qcloud-iot-hub-sdk-3.1.2/3rdparty/sdk_src/services/shadow/shadow_client.c
vendored
Normal file
@@ -0,0 +1,879 @@
|
||||
/*
|
||||
* 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 "shadow_client.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils_param_check.h"
|
||||
#include "shadow_client_json.h"
|
||||
#include "shadow_client_common.h"
|
||||
|
||||
|
||||
static void _init_request_params(RequestParams *pParams, Method method, OnRequestCallback callback, void *userContext, uint8_t timeout_sec) {
|
||||
pParams->method = method;
|
||||
pParams->user_context = userContext;
|
||||
pParams->timeout_sec = timeout_sec;
|
||||
pParams->request_callback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check return value of snprintf
|
||||
*
|
||||
* @param returnCode return value of snprintf
|
||||
* @param maxSizeOfWrite max size of write buffer
|
||||
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
|
||||
*/
|
||||
static inline int _check_snprintf_return(int32_t returnCode, size_t maxSizeOfWrite) {
|
||||
|
||||
if (returnCode >= maxSizeOfWrite) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TRUNCATED;
|
||||
} else if (returnCode < 0) {
|
||||
return QCLOUD_ERR_JSON;
|
||||
}
|
||||
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static void _shadow_event_handler(void *pclient, void *context, MQTTEventMsg *msg) {
|
||||
uintptr_t packet_id = (uintptr_t)msg->msg;
|
||||
Qcloud_IoT_Shadow *shadow_client = (Qcloud_IoT_Shadow *)context;
|
||||
MQTTMessage* topic_info = (MQTTMessage*)msg->msg;
|
||||
|
||||
switch (msg->event_type) {
|
||||
case MQTT_EVENT_SUBCRIBE_SUCCESS:
|
||||
Log_d("shadow subscribe success, packet-id=%u", (unsigned int)packet_id);
|
||||
if (shadow_client->inner_data.sync_status > 0)
|
||||
shadow_client->inner_data.sync_status = 0;
|
||||
break;
|
||||
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
|
||||
Log_d("shadow subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
if (shadow_client->inner_data.sync_status > 0)
|
||||
shadow_client->inner_data.sync_status = -1;
|
||||
break;
|
||||
case MQTT_EVENT_SUBCRIBE_NACK:
|
||||
Log_d("shadow subscribe nack, packet-id=%u", (unsigned int)packet_id);
|
||||
if (shadow_client->inner_data.sync_status > 0)
|
||||
shadow_client->inner_data.sync_status = -1;
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISH_RECVEIVED:
|
||||
Log_d("shadow 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 (shadow_client->event_handle.h_fp != NULL)
|
||||
{
|
||||
shadow_client->event_handle.h_fp(shadow_client, shadow_client->event_handle.context, msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void _copy_shadow_init_params_to_mqtt(MQTTInitParams *pMqttInitParams, ShadowInitParams *shadowInitParams)
|
||||
{
|
||||
pMqttInitParams->device_name = shadowInitParams->device_name;
|
||||
pMqttInitParams->product_id = shadowInitParams->product_id;
|
||||
|
||||
#ifdef AUTH_MODE_CERT
|
||||
pMqttInitParams->cert_file = shadowInitParams->cert_file;
|
||||
pMqttInitParams->key_file = shadowInitParams->key_file;
|
||||
#else
|
||||
pMqttInitParams->device_secret = shadowInitParams->device_secret;
|
||||
#endif
|
||||
|
||||
pMqttInitParams->command_timeout = shadowInitParams->command_timeout;
|
||||
pMqttInitParams->keep_alive_interval_ms = shadowInitParams->keep_alive_interval_ms;
|
||||
pMqttInitParams->clean_session = shadowInitParams->clean_session;
|
||||
pMqttInitParams->auto_connect_enable = shadowInitParams->auto_connect_enable;
|
||||
}
|
||||
|
||||
static void _update_ack_cb(void *pClient, Method method, RequestAck requestAck, const char *pReceivedJsonDocument, void *pUserdata)
|
||||
{
|
||||
Log_d("requestAck=%d", requestAck);
|
||||
|
||||
if (NULL != pReceivedJsonDocument) {
|
||||
Log_d("Received Json Document=%s", pReceivedJsonDocument);
|
||||
} else {
|
||||
Log_d("Received Json Document is NULL");
|
||||
}
|
||||
|
||||
*((RequestAck *)pUserdata) = requestAck;
|
||||
}
|
||||
|
||||
void* IOT_Shadow_Construct(ShadowInitParams *pParams)
|
||||
{
|
||||
POINTER_SANITY_CHECK(pParams, NULL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow_client = NULL;
|
||||
if ((shadow_client = (Qcloud_IoT_Shadow *)HAL_Malloc(sizeof(Qcloud_IoT_Shadow))) == NULL) {
|
||||
Log_e("memory not enough to malloc ShadowClient");
|
||||
}
|
||||
|
||||
MQTTInitParams mqtt_init_params;
|
||||
_copy_shadow_init_params_to_mqtt(&mqtt_init_params, pParams);
|
||||
|
||||
mqtt_init_params.event_handle.h_fp = _shadow_event_handler;
|
||||
mqtt_init_params.event_handle.context = shadow_client;
|
||||
|
||||
void *mqtt_client = NULL;
|
||||
if ((mqtt_client = IOT_MQTT_Construct(&mqtt_init_params)) == NULL) {
|
||||
HAL_Free(shadow_client);
|
||||
goto End;
|
||||
}
|
||||
|
||||
shadow_client->mqtt = mqtt_client;
|
||||
shadow_client->shadow_type = pParams->shadow_type;
|
||||
shadow_client->event_handle = pParams->event_handle;
|
||||
shadow_client->inner_data.result_topic = NULL;
|
||||
shadow_client->inner_data.token_num = 0;
|
||||
|
||||
int rc;
|
||||
|
||||
rc = qcloud_iot_shadow_init(shadow_client);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
IOT_MQTT_Destroy(&(shadow_client->mqtt));
|
||||
HAL_Free(shadow_client);
|
||||
goto End;
|
||||
}
|
||||
|
||||
rc = subscribe_operation_result_to_cloud(shadow_client);
|
||||
if (rc < 0)
|
||||
{
|
||||
Log_e("Subcribe $shadow/operation/results fail!");
|
||||
}
|
||||
else {
|
||||
shadow_client->inner_data.sync_status = rc;
|
||||
while (rc == shadow_client->inner_data.sync_status) {
|
||||
IOT_Shadow_Yield(shadow_client, 100);
|
||||
}
|
||||
if (0 == shadow_client->inner_data.sync_status) {
|
||||
Log_i("Sync device data successfully");
|
||||
} else {
|
||||
Log_e("Sync device data failed");
|
||||
}
|
||||
}
|
||||
|
||||
return shadow_client;
|
||||
|
||||
End:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int IOT_Shadow_Publish(void *handle, char *topicName, PublishParams *pParams) {
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
return qcloud_iot_mqtt_publish(shadow->mqtt, topicName, pParams);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Subscribe(void *handle, char *topicFilter, SubscribeParams *pParams) {
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
return qcloud_iot_mqtt_subscribe(shadow->mqtt, topicFilter, pParams);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Unsubscribe(void *handle, char *topicFilter) {
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow = (Qcloud_IoT_Shadow *)handle;
|
||||
|
||||
return qcloud_iot_mqtt_unsubscribe(shadow->mqtt, topicFilter);
|
||||
}
|
||||
|
||||
bool IOT_Shadow_IsConnected(void *handle)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow* pshadow = (Qcloud_IoT_Shadow*)handle;
|
||||
|
||||
IOT_FUNC_EXIT_RC(IOT_MQTT_IsConnected(pshadow->mqtt))
|
||||
}
|
||||
|
||||
int IOT_Shadow_Destroy(void *handle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow* shadow_client = (Qcloud_IoT_Shadow*)handle;
|
||||
qcloud_iot_shadow_reset(handle);
|
||||
|
||||
IOT_MQTT_Destroy(&shadow_client->mqtt);
|
||||
|
||||
if (NULL != shadow_client->mutex) {
|
||||
HAL_MutexDestroy(shadow_client->mutex);
|
||||
}
|
||||
|
||||
if (NULL != shadow_client->inner_data.result_topic) {
|
||||
HAL_Free(shadow_client->inner_data.result_topic);
|
||||
shadow_client->inner_data.result_topic = NULL;
|
||||
}
|
||||
|
||||
HAL_Free(handle);
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS)
|
||||
}
|
||||
|
||||
int IOT_Shadow_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_Shadow *pshadow = (Qcloud_IoT_Shadow *)handle;
|
||||
POINTER_SANITY_CHECK(pshadow, QCLOUD_ERR_INVAL);
|
||||
|
||||
handle_expired_request(pshadow);
|
||||
|
||||
rc = IOT_MQTT_Yield(pshadow->mqtt, timeout_ms);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Register_Property(void *handle, DeviceProperty *pProperty, OnPropRegCallback callback) {
|
||||
|
||||
IOT_FUNC_ENTRY;
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
|
||||
Qcloud_IoT_Shadow* pshadow = (Qcloud_IoT_Shadow*)handle;
|
||||
int rc;
|
||||
|
||||
if (IOT_MQTT_IsConnected(pshadow->mqtt) == false) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
if (shadow_common_check_property_existence(pshadow, pProperty))
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_SHADOW_PROPERTY_EXIST);
|
||||
|
||||
rc = shadow_common_register_property_on_delta(pshadow, pProperty, callback);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_UnRegister_Property(void *handle, DeviceProperty *pProperty) {
|
||||
IOT_FUNC_ENTRY;
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Shadow* pshadow = (Qcloud_IoT_Shadow*)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(pshadow->mqtt) == false) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
if (!shadow_common_check_property_existence(pshadow, pProperty)) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_SHADOW_NOT_PROPERTY_EXIST);
|
||||
}
|
||||
int rc = shadow_common_remove_property(pshadow, pProperty);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Update(void *handle, char *pJsonDoc, size_t sizeOfBuffer, OnRequestCallback 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_Shadow* shadow = (Qcloud_IoT_Shadow*)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(shadow->mqtt) == false) {
|
||||
Log_e("shadow is disconnected");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
// subscribe topic $shadow/operation/result if not subscribed yet
|
||||
if (shadow->inner_data.sync_status < 0) {
|
||||
subscribe_operation_result_to_cloud(shadow);
|
||||
}
|
||||
|
||||
Log_d("UPDATE Request Document: %s", pJsonDoc);
|
||||
|
||||
RequestParams request_params = DEFAULT_REQUEST_PARAMS;
|
||||
_init_request_params(&request_params, UPDATE, callback, userContext, timeout_ms/1000);
|
||||
|
||||
rc = do_shadow_request(shadow, &request_params, pJsonDoc, sizeOfBuffer);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Update_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_Shadow* shadow = (Qcloud_IoT_Shadow*)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(shadow->mqtt) == false) {
|
||||
Log_e("shadow is disconnected");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
RequestAck ack_update = ACK_NONE;
|
||||
rc = IOT_Shadow_Update(handle, pJsonDoc, sizeOfBuffer, _update_ack_cb, &ack_update, timeout_ms);
|
||||
if (rc != QCLOUD_RET_SUCCESS) IOT_FUNC_EXIT_RC(rc);
|
||||
|
||||
while (ACK_NONE == ack_update) {
|
||||
IOT_Shadow_Yield(handle, 200);
|
||||
}
|
||||
|
||||
if (ACK_ACCEPTED == ack_update) {
|
||||
rc = QCLOUD_RET_SUCCESS;
|
||||
} else if (ACK_TIMEOUT == ack_update) {
|
||||
rc = QCLOUD_ERR_SHADOW_UPDATE_TIMEOUT;
|
||||
} else if (ACK_REJECTED == ack_update) {
|
||||
rc = QCLOUD_ERR_SHADOW_UPDATE_REJECTED;
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Get(void *handle, OnRequestCallback 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_Shadow* shadow = (Qcloud_IoT_Shadow*)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(shadow->mqtt) == false) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
// subscribe topic $shadow/operation/result if not subscribed yet
|
||||
if (shadow->inner_data.sync_status < 0) {
|
||||
subscribe_operation_result_to_cloud(shadow);
|
||||
}
|
||||
|
||||
char getRequestJsonDoc[MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN];
|
||||
build_empty_json(&(shadow->inner_data.token_num), getRequestJsonDoc);
|
||||
Log_d("GET Request Document: %s", getRequestJsonDoc);
|
||||
|
||||
RequestParams request_params = DEFAULT_REQUEST_PARAMS;
|
||||
_init_request_params(&request_params, GET, callback, userContext, timeout_ms/1000);
|
||||
|
||||
rc = do_shadow_request(shadow, &request_params, getRequestJsonDoc, MAX_SIZE_OF_JSON_WITH_CLIENT_TOKEN);
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int IOT_Shadow_Get_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_Shadow* shadow = (Qcloud_IoT_Shadow*)handle;
|
||||
|
||||
if (IOT_MQTT_IsConnected(shadow->mqtt) == false) {
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
RequestAck ack_update = ACK_NONE;
|
||||
rc = IOT_Shadow_Get(handle, _update_ack_cb, &ack_update, timeout_ms);
|
||||
if (rc != QCLOUD_RET_SUCCESS) IOT_FUNC_EXIT_RC(rc);
|
||||
|
||||
while (ACK_NONE == ack_update) {
|
||||
IOT_Shadow_Yield(handle, 200);
|
||||
}
|
||||
|
||||
if (ACK_ACCEPTED == ack_update) {
|
||||
rc = QCLOUD_RET_SUCCESS;
|
||||
} else if (ACK_TIMEOUT == ack_update) {
|
||||
rc = QCLOUD_ERR_SHADOW_GET_TIMEOUT;
|
||||
} else if (ACK_REJECTED == ack_update) {
|
||||
rc = QCLOUD_ERR_SHADOW_GET_REJECTED;
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Init a shadow JSON string, add the initial field of "{\"state\":{"
|
||||
*
|
||||
* @param jsonBuffer JSON string buffer
|
||||
* @param sizeOfBuffer buffer size
|
||||
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
|
||||
*/
|
||||
static int IOT_Shadow_JSON_Init(Qcloud_IoT_Shadow *pShadow, char *jsonBuffer, size_t sizeOfBuffer, bool overwrite) {
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
int32_t rc_of_snprintf = 0;
|
||||
if (overwrite) {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer, sizeOfBuffer, "{\"overwriteUpdate\":true, \"state\":{");
|
||||
}
|
||||
else {
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer, sizeOfBuffer, "{\"state\":{");
|
||||
}
|
||||
|
||||
return _check_snprintf_return(rc_of_snprintf, sizeOfBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finish a shadow JSON string, append the tail fields of clientToken and version
|
||||
*
|
||||
* @param jsonBuffer JSON string buffer
|
||||
* @param sizeOfBuffer buffer size
|
||||
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
|
||||
*/
|
||||
static int IOT_Shadow_JSON_Finalize(Qcloud_IoT_Shadow *pShadow, char *jsonBuffer, size_t sizeOfBuffer)
|
||||
{
|
||||
int rc;
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
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, "}, \"%s\":\"", CLIENT_TOKEN_FIELD);
|
||||
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;
|
||||
}
|
||||
|
||||
rc_of_snprintf = generate_client_token(jsonBuffer + strlen(jsonBuffer), remain_size, &(pShadow->inner_data.token_num));
|
||||
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;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"}");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int IOT_Shadow_JSON_ConstructReport(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, ...)
|
||||
{
|
||||
Qcloud_IoT_Shadow* pshadow = (Qcloud_IoT_Shadow*)handle;
|
||||
POINTER_SANITY_CHECK(pshadow, QCLOUD_ERR_INVAL);
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(pshadow, jsonBuffer, sizeOfBuffer, false);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
int8_t i;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
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), remain_size, "\"reported\":{");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
va_list pArgs;
|
||||
va_start(pArgs, count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
DeviceProperty *pJsonNode;
|
||||
pJsonNode = va_arg(pArgs, DeviceProperty *);
|
||||
if (pJsonNode != NULL && pJsonNode->key != NULL) {
|
||||
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
va_end(pArgs);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
va_end(pArgs);
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(pArgs);
|
||||
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("shadow json add report failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(pshadow, jsonBuffer, sizeOfBuffer);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int IOT_Shadow_JSON_ConstructReportArray(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, DeviceProperty *pDeviceProperties[])
|
||||
{
|
||||
Qcloud_IoT_Shadow* pshadow = (Qcloud_IoT_Shadow*)handle;
|
||||
POINTER_SANITY_CHECK(pshadow, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pDeviceProperties, QCLOUD_ERR_INVAL);
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(pshadow, jsonBuffer, sizeOfBuffer, false);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
int8_t i;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
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), remain_size, "\"reported\":{");
|
||||
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("shadow json add report failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(pshadow, jsonBuffer, sizeOfBuffer);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int IOT_Shadow_JSON_Construct_OverwriteReport(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, ...)
|
||||
{
|
||||
Qcloud_IoT_Shadow* pshadow = (Qcloud_IoT_Shadow*)handle;
|
||||
POINTER_SANITY_CHECK(pshadow, QCLOUD_ERR_INVAL);
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(pshadow, jsonBuffer, sizeOfBuffer, true);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
int8_t i;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
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), remain_size, "\"reported\":{");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
va_list pArgs;
|
||||
va_start(pArgs, count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
DeviceProperty *pJsonNode;
|
||||
pJsonNode = va_arg(pArgs, DeviceProperty *);
|
||||
if (pJsonNode != NULL && pJsonNode->key != NULL) {
|
||||
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
va_end(pArgs);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
va_end(pArgs);
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(pArgs);
|
||||
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("shadow json add report failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(pshadow, jsonBuffer, sizeOfBuffer);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int IOT_Shadow_JSON_ConstructReportAndDesireAllNull(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, ...)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Shadow* pshadow = (Qcloud_IoT_Shadow*)handle;
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(pshadow, jsonBuffer, sizeOfBuffer, false);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
int8_t i;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
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), remain_size, "\"reported\":{");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
va_list pArgs;
|
||||
va_start(pArgs, count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
DeviceProperty *pJsonNode;
|
||||
pJsonNode = va_arg(pArgs, DeviceProperty *);
|
||||
if (pJsonNode != NULL && pJsonNode->key != NULL) {
|
||||
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
va_end(pArgs);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
va_end(pArgs);
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(pArgs);
|
||||
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("shadow json add report failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_of_snprintf = HAL_Snprintf(jsonBuffer + strlen(jsonBuffer), remain_size, "\"desired\": null ");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(pshadow, jsonBuffer, sizeOfBuffer);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int IOT_Shadow_JSON_ConstructDesireAllNull(void *handle, char *jsonBuffer, size_t sizeOfBuffer)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Shadow* shadow = (Qcloud_IoT_Shadow*)handle;
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(shadow, jsonBuffer, sizeOfBuffer, false);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
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), remain_size, "\"desired\": null ");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(shadow, jsonBuffer, sizeOfBuffer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int IOT_Shadow_JSON_ConstructDesirePropNull(void *handle, char *jsonBuffer, size_t sizeOfBuffer, uint8_t count, ...)
|
||||
{
|
||||
POINTER_SANITY_CHECK(handle, QCLOUD_ERR_INVAL);
|
||||
Qcloud_IoT_Shadow* shadow = (Qcloud_IoT_Shadow*)handle;
|
||||
|
||||
int rc = IOT_Shadow_JSON_Init(shadow, jsonBuffer, sizeOfBuffer, false);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
Log_e("shadow json init failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t remain_size = 0;
|
||||
int32_t rc_of_snprintf = 0;
|
||||
int8_t i;
|
||||
|
||||
if (jsonBuffer == NULL) {
|
||||
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), remain_size, "\"desired\":{");
|
||||
rc = _check_snprintf_return(rc_of_snprintf, remain_size);
|
||||
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
va_list pArgs;
|
||||
va_start(pArgs, count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
DeviceProperty *pJsonNode;
|
||||
pJsonNode = va_arg (pArgs, DeviceProperty *);
|
||||
if (pJsonNode != NULL && pJsonNode->key != NULL) {
|
||||
rc = put_json_node(jsonBuffer, remain_size, pJsonNode->key, pJsonNode->data, pJsonNode->type);
|
||||
if (rc != QCLOUD_RET_SUCCESS) {
|
||||
va_end(pArgs);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
va_end(pArgs);
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(pArgs);
|
||||
if ((remain_size = sizeOfBuffer - strlen(jsonBuffer)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SMALL;
|
||||
}
|
||||
// strlen(jsonBuffer) - 1 to remove last comma
|
||||
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("shadow json add desired failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = IOT_Shadow_JSON_Finalize(shadow, jsonBuffer, sizeOfBuffer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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 "shadow_client_common.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
|
||||
static int _add_property_handle_to_list(Qcloud_IoT_Shadow *pShadow, 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(pShadow->inner_data.property_handle_list, node);
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
int shadow_common_check_property_existence(Qcloud_IoT_Shadow *pshadow, DeviceProperty *pProperty)
|
||||
{
|
||||
ListNode *node;
|
||||
|
||||
HAL_MutexLock(pshadow->mutex);
|
||||
node = list_find(pshadow->inner_data.property_handle_list, pProperty);
|
||||
HAL_MutexUnlock(pshadow->mutex);
|
||||
|
||||
return (NULL != node);
|
||||
}
|
||||
|
||||
int shadow_common_remove_property(Qcloud_IoT_Shadow *pshadow, DeviceProperty *pProperty)
|
||||
{
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
ListNode *node;
|
||||
HAL_MutexLock(pshadow->mutex);
|
||||
node = list_find(pshadow->inner_data.property_handle_list, pProperty);
|
||||
if (NULL == node) {
|
||||
rc = QCLOUD_ERR_SHADOW_NOT_PROPERTY_EXIST;
|
||||
Log_e("Try to remove a non-existent property.");
|
||||
} else {
|
||||
list_remove(pshadow->inner_data.property_handle_list, node);
|
||||
}
|
||||
HAL_MutexUnlock(pshadow->mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int shadow_common_register_property_on_delta(Qcloud_IoT_Shadow *pShadow, DeviceProperty *pProperty, OnPropRegCallback callback)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
POINTER_SANITY_CHECK(pShadow, 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(pShadow->mutex);
|
||||
rc = _add_property_handle_to_list(pShadow, pProperty, callback);
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* 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 "shadow_client_json.h"
|
||||
|
||||
#include "qcloud_iot_device.h"
|
||||
#include "shadow_client.h"
|
||||
#include "lite-utils.h"
|
||||
|
||||
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){
|
||||
//Log_d("string type wait to be deal,%s",value);
|
||||
}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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check return value of snprintf
|
||||
*
|
||||
* @param returnCode return value of snprintf
|
||||
* @param maxSizeOfWrite max size of write buffer
|
||||
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
|
||||
*/
|
||||
static inline int _check_snprintf_return(int32_t returnCode, size_t maxSizeOfWrite) {
|
||||
|
||||
if (returnCode >= maxSizeOfWrite) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TRUNCATED;
|
||||
} else if (returnCode < 0) {
|
||||
return QCLOUD_ERR_JSON;
|
||||
}
|
||||
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
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 event_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_version_num(char *pJsonDoc, uint32_t *pVersionNumber) {
|
||||
|
||||
bool ret = false;
|
||||
|
||||
char *version_num = LITE_json_value_of(PAYLOAD_VERSION, pJsonDoc);
|
||||
if (version_num == NULL) return false;
|
||||
|
||||
if (sscanf(version_num, "%" SCNu32, pVersionNumber) != 1) {
|
||||
Log_e("parse shadow version failed, errCode: %d", QCLOUD_ERR_JSON_PARSE);
|
||||
}
|
||||
else {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
HAL_Free(version_num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool parse_shadow_state(char *pJsonDoc, char **pState)
|
||||
{
|
||||
*pState = LITE_json_value_of(PAYLOAD_VERSION, pJsonDoc);
|
||||
return *pState == 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 parse_shadow_operation_type(char *pJsonDoc, char **pType)
|
||||
{
|
||||
*pType = LITE_json_value_of(TYPE_FIELD, pJsonDoc);
|
||||
return *pType == NULL ? false : true;
|
||||
}
|
||||
|
||||
bool parse_shadow_operation_result_code(char *pJsonDoc, int16_t *pResultCode)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
char *result_code = LITE_json_value_of(RESULT_FIELD, pJsonDoc);
|
||||
if (result_code == NULL) return false;
|
||||
|
||||
if (sscanf(result_code, "%" SCNi16, pResultCode) != 1) {
|
||||
Log_e("parse shadow result_code failed, errCode: %d", QCLOUD_ERR_JSON_PARSE);
|
||||
}
|
||||
else {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
HAL_Free(result_code);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool parse_shadow_operation_delta(char *pJsonDoc, char **pDelta)
|
||||
{
|
||||
*pDelta = LITE_json_value_of(PAYLOAD_STATE, pJsonDoc);
|
||||
return *pDelta == NULL ? false : true;
|
||||
}
|
||||
|
||||
bool parse_shadow_operation_get(char *pJsonDoc, char **pDelta)
|
||||
{
|
||||
*pDelta = LITE_json_value_of(PAYLOAD_STATE_DELTA, pJsonDoc);
|
||||
return *pDelta == 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;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
* 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 "shadow_client.h"
|
||||
|
||||
#include "utils_param_check.h"
|
||||
#include "qcloud_iot_import.h"
|
||||
|
||||
#include "shadow_client_json.h"
|
||||
|
||||
#include "utils_list.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief type for document request
|
||||
*/
|
||||
typedef struct {
|
||||
char client_token[MAX_SIZE_OF_CLIENT_TOKEN]; // clientToken
|
||||
Method method; // method type
|
||||
|
||||
void *user_context; // user context
|
||||
Timer timer; // timer for timeout
|
||||
|
||||
OnRequestCallback callback; // request response callback
|
||||
} Request;
|
||||
|
||||
|
||||
|
||||
static char cloud_rcv_buf[CLOUD_IOT_JSON_RX_BUF_LEN];
|
||||
|
||||
bool discard_old_delta_flag = true;
|
||||
|
||||
typedef void (*TraverseHandle)(Qcloud_IoT_Shadow *pShadow, ListNode **node, List *list, const char *pClientToken, const char *pType);
|
||||
|
||||
static void _on_operation_result_handler(void *pClient, MQTTMessage *message, void *pUserdata);
|
||||
|
||||
static void _handle_delta(Qcloud_IoT_Shadow *pShadow, char* delta_str);
|
||||
|
||||
static int _set_shadow_json_type(char *pJsonDoc, size_t sizeOfBuffer, Method method);
|
||||
|
||||
static int _publish_operation_to_cloud(Qcloud_IoT_Shadow *pShadow, Method method, char *pJsonDoc);
|
||||
|
||||
static int _add_request_to_list(Qcloud_IoT_Shadow *pShadow, const char *pClientToken, RequestParams *pParams);
|
||||
|
||||
static int _unsubscribe_operation_result_to_cloud(void *pClient);
|
||||
|
||||
static void _traverse_list(Qcloud_IoT_Shadow *pShadow, List *list, const char *pClientToken, const char *pType, TraverseHandle traverseHandle);
|
||||
|
||||
static void _handle_request_callback(Qcloud_IoT_Shadow *pShadow, ListNode **node, List *list, const char *pClientToken, const char *pType);
|
||||
|
||||
static void _handle_expired_request_callback(Qcloud_IoT_Shadow *pShadow, ListNode **node, List *list, const char *pClientToken, const char *pType);
|
||||
|
||||
int qcloud_iot_shadow_init(Qcloud_IoT_Shadow *pShadow) {
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
POINTER_SANITY_CHECK(pShadow, QCLOUD_ERR_INVAL);
|
||||
|
||||
pShadow->mutex = HAL_MutexCreate();
|
||||
if (pShadow->mutex == NULL)
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
|
||||
pShadow->inner_data.property_handle_list = list_new();
|
||||
if (pShadow->inner_data.property_handle_list)
|
||||
{
|
||||
pShadow->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);
|
||||
}
|
||||
|
||||
pShadow->inner_data.request_list = list_new();
|
||||
if (pShadow->inner_data.request_list)
|
||||
{
|
||||
pShadow->inner_data.request_list->free = HAL_Free;
|
||||
} else {
|
||||
Log_e("no memory to allocate request_list");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
void qcloud_iot_shadow_reset(void *pClient) {
|
||||
POINTER_SANITY_CHECK_RTN(pClient);
|
||||
|
||||
Qcloud_IoT_Shadow *shadow_client = (Qcloud_IoT_Shadow *)pClient;
|
||||
if (shadow_client->inner_data.property_handle_list) {
|
||||
list_destroy(shadow_client->inner_data.property_handle_list);
|
||||
}
|
||||
|
||||
_unsubscribe_operation_result_to_cloud(shadow_client->mqtt);
|
||||
|
||||
if (shadow_client->inner_data.request_list)
|
||||
{
|
||||
list_destroy(shadow_client->inner_data.request_list);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_expired_request(Qcloud_IoT_Shadow *pShadow) {
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
_traverse_list(pShadow, pShadow->inner_data.request_list, NULL, NULL, _handle_expired_request_callback);
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
int do_shadow_request(Qcloud_IoT_Shadow *pShadow, RequestParams *pParams, char *pJsonDoc, size_t sizeOfBuffer)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
POINTER_SANITY_CHECK(pShadow, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pJsonDoc, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(pParams, QCLOUD_ERR_INVAL);
|
||||
|
||||
char* client_token = NULL;
|
||||
|
||||
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_shadow_json_type(pJsonDoc, sizeOfBuffer, pParams->method);
|
||||
if (rc != QCLOUD_RET_SUCCESS)
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
|
||||
if (rc == QCLOUD_RET_SUCCESS) {
|
||||
rc = _publish_operation_to_cloud(pShadow, pParams->method, pJsonDoc);
|
||||
}
|
||||
|
||||
if (rc >= 0) {
|
||||
rc = _add_request_to_list(pShadow, client_token, pParams);
|
||||
}
|
||||
|
||||
HAL_Free(client_token);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
int subscribe_operation_result_to_cloud(Qcloud_IoT_Shadow *pShadow)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
int rc;
|
||||
int size;
|
||||
|
||||
if (pShadow->inner_data.result_topic == NULL) {
|
||||
char *operation_result_topic = (char *)HAL_Malloc(MAX_SIZE_OF_CLOUD_TOPIC * sizeof(char));
|
||||
if (operation_result_topic == NULL) IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
|
||||
memset(operation_result_topic, 0x0, MAX_SIZE_OF_CLOUD_TOPIC);
|
||||
if(eTEMPLATE == pShadow->shadow_type){
|
||||
size = HAL_Snprintf(operation_result_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$template/operation/result/%s/%s", iot_device_info_get()->product_id, iot_device_info_get()->device_name);
|
||||
}else{
|
||||
size = HAL_Snprintf(operation_result_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$shadow/operation/result/%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(operation_result_topic);
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
pShadow->inner_data.result_topic = operation_result_topic;
|
||||
}
|
||||
|
||||
SubscribeParams subscribe_params = DEFAULT_SUB_PARAMS;
|
||||
subscribe_params.on_message_handler = _on_operation_result_handler;
|
||||
subscribe_params.qos = QOS0;
|
||||
|
||||
rc = IOT_MQTT_Subscribe(pShadow->mqtt, pShadow->inner_data.result_topic, &subscribe_params);
|
||||
if (rc < 0) {
|
||||
Log_e("subscribe topic: %s failed: %d.", pShadow->inner_data.result_topic, rc);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief publish operation to server
|
||||
*
|
||||
* @param pClient Qcloud_IoT_Client
|
||||
* @param method method type
|
||||
* @param pJsonDoc JSON to publish
|
||||
* @return QCLOUD_RET_SUCCESS for success, or err code for failure
|
||||
*/
|
||||
static int _publish_operation_to_cloud(Qcloud_IoT_Shadow *pShadow, Method method, char *pJsonDoc)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
char topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
|
||||
int size;
|
||||
|
||||
if(eTEMPLATE == pShadow->shadow_type){
|
||||
size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, "$template/operation/%s/%s", iot_device_info_get()->product_id, iot_device_info_get()->device_name);
|
||||
}else{
|
||||
size = HAL_Snprintf(topic, MAX_SIZE_OF_CLOUD_TOPIC, "$shadow/operation/%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(pShadow->mqtt, topic, &pubParams);
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief callback when msg of operation result arrives
|
||||
*/
|
||||
static void _on_operation_result_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_Shadow *shadow_client = (Qcloud_IoT_Shadow*)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);
|
||||
memcpy(cloud_rcv_buf, message->payload, cloud_rcv_len + 1);
|
||||
cloud_rcv_buf[cloud_rcv_len] = '\0'; // jsmn_parse relies on a string
|
||||
|
||||
if (!parse_shadow_operation_type(cloud_rcv_buf, &type_str))
|
||||
{
|
||||
Log_e("Fail to parse type!");
|
||||
goto End;
|
||||
}
|
||||
Log_d("type:%s", type_str);
|
||||
// non-delta msg push is triggered by device side, parse client token first
|
||||
if (strcmp(type_str, OPERATION_DELTA) && !parse_client_token(cloud_rcv_buf, &client_token)) {
|
||||
Log_e("Fail to parse client token! Json=%s", cloud_rcv_buf);
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (!strcmp(type_str, OPERATION_DELTA)) {
|
||||
HAL_MutexLock(shadow_client->mutex);
|
||||
char* delta_str = NULL;
|
||||
if (parse_shadow_operation_delta(cloud_rcv_buf, &delta_str)) {
|
||||
Log_d("dlta:%s", delta_str);
|
||||
_handle_delta(shadow_client, delta_str);
|
||||
HAL_Free(delta_str);
|
||||
}
|
||||
|
||||
HAL_MutexUnlock(shadow_client->mutex);
|
||||
goto End;
|
||||
}
|
||||
|
||||
if (shadow_client != NULL)
|
||||
_traverse_list(shadow_client, shadow_client->inner_data.request_list, client_token, type_str, _handle_request_callback);
|
||||
|
||||
End:
|
||||
HAL_Free(type_str);
|
||||
HAL_Free(client_token);
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
static void _handle_delta(Qcloud_IoT_Shadow *pShadow, char* delta_str)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
if (pShadow->inner_data.property_handle_list->len) {
|
||||
ListIterator *iter;
|
||||
ListNode *node = NULL;
|
||||
PropertyHandler *property_handle = NULL;
|
||||
|
||||
if (NULL == (iter = list_iterator_new(pShadow->inner_data.property_handle_list, LIST_TAIL))) {
|
||||
HAL_MutexUnlock(pShadow->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(delta_str, property_handle->property))
|
||||
{
|
||||
if (property_handle->callback != NULL)
|
||||
{
|
||||
property_handle->callback(pShadow, delta_str, strlen(delta_str), property_handle->property);
|
||||
}
|
||||
node = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
list_iterator_destroy(iter);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
static void _insert(char *str, char *pch, int pos) {
|
||||
int len = strlen(str);
|
||||
int nlen = strlen(pch);
|
||||
int i;
|
||||
for (i = len - 1; i >= pos; --i) {
|
||||
*(str + i + nlen) = *(str + i);
|
||||
}
|
||||
|
||||
int n;
|
||||
for (n = 0; n < nlen; n++)
|
||||
*(str + pos + n) = *pch++;
|
||||
*(str + len + nlen) = 0;
|
||||
}
|
||||
|
||||
|
||||
static int _set_shadow_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 *type_str = NULL;
|
||||
switch (method) {
|
||||
case GET:
|
||||
type_str = OPERATION_GET;
|
||||
break;
|
||||
case UPDATE:
|
||||
type_str = OPERATION_UPDATE;
|
||||
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, "\"type\":\"%s\", ", type_str);
|
||||
|
||||
size_t json_node_len = strlen(json_node_str);
|
||||
if (json_node_len >= remain_size - 1) {
|
||||
rc = QCLOUD_ERR_INVAL;
|
||||
} else {
|
||||
_insert(pJsonDoc, json_node_str, 1);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief unsubsribe topic: $shadow/operation/result/{ProductId}/{DeviceName}
|
||||
*/
|
||||
static int _unsubscribe_operation_result_to_cloud(void* pClient)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
int rc = QCLOUD_RET_SUCCESS;
|
||||
|
||||
char operation_result_topic[MAX_SIZE_OF_CLOUD_TOPIC] = {0};
|
||||
int size = HAL_Snprintf(operation_result_topic, MAX_SIZE_OF_CLOUD_TOPIC, "$shadow/operation/result/%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, operation_result_topic);
|
||||
if (rc < 0) {
|
||||
Log_e("unsubscribe topic: %s failed: %d.", operation_result_topic, rc);
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
|
||||
static int _add_request_to_list(Qcloud_IoT_Shadow *pShadow, const char *pClientToken, RequestParams *pParams)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
HAL_MutexLock(pShadow->mutex);
|
||||
if (pShadow->inner_data.request_list->len >= MAX_APPENDING_REQUEST_AT_ANY_GIVEN_TIME)
|
||||
{
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MAX_APPENDING_REQUEST);
|
||||
}
|
||||
|
||||
Request *request = (Request *)HAL_Malloc(sizeof(Request));
|
||||
if (NULL == request) {
|
||||
HAL_MutexUnlock(pShadow->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(pShadow->mutex);
|
||||
Log_e("run list_node_new is error!");
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
list_rpush(pShadow->inner_data.request_list, node);
|
||||
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
|
||||
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief iterator list and call traverseHandle for each node
|
||||
*/
|
||||
static void _traverse_list(Qcloud_IoT_Shadow *pShadow, List *list, const char *pClientToken, const char *pType, TraverseHandle traverseHandle)
|
||||
{
|
||||
IOT_FUNC_ENTRY;
|
||||
|
||||
HAL_MutexLock(pShadow->mutex);
|
||||
|
||||
if (list->len) {
|
||||
ListIterator *iter;
|
||||
ListNode *node = NULL;
|
||||
|
||||
if (NULL == (iter = list_iterator_new(list, LIST_TAIL))) {
|
||||
HAL_MutexUnlock(pShadow->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(pShadow, &node, list, pClientToken, pType);
|
||||
}
|
||||
|
||||
list_iterator_destroy(iter);
|
||||
}
|
||||
HAL_MutexUnlock(pShadow->mutex);
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
static void _handle_request_callback(Qcloud_IoT_Shadow *pShadow, 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)
|
||||
{
|
||||
RequestAck status = ACK_NONE;
|
||||
|
||||
// result field in payload tell us if operation success or not
|
||||
// result = 0 for success, result != 0 for fail
|
||||
int16_t result_code = 0;
|
||||
|
||||
bool parse_success = parse_shadow_operation_result_code(cloud_rcv_buf, &result_code);
|
||||
if (parse_success) {
|
||||
if (result_code == 0) {
|
||||
status = ACK_ACCEPTED;
|
||||
} else {
|
||||
status = ACK_REJECTED;
|
||||
}
|
||||
|
||||
if ((strcmp(pType, "get") == 0 && status == ACK_ACCEPTED) ||
|
||||
(strcmp(pType, "update") && status == ACK_REJECTED))
|
||||
{
|
||||
char* delta_str = NULL;
|
||||
if (parse_shadow_operation_get(cloud_rcv_buf, &delta_str)) {
|
||||
_handle_delta(pShadow, delta_str);
|
||||
HAL_Free(delta_str);
|
||||
}
|
||||
}
|
||||
|
||||
if (request->callback != NULL) {
|
||||
request->callback(pShadow, request->method, status, cloud_rcv_buf, request->user_context);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log_e("parse shadow operation result code failed.");
|
||||
}
|
||||
|
||||
list_remove(list, *node);
|
||||
*node = NULL;
|
||||
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
|
||||
static void _handle_expired_request_callback(Qcloud_IoT_Shadow *pShadow, 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(pShadow, request->method, ACK_TIMEOUT, cloud_rcv_buf, request->user_context);
|
||||
}
|
||||
|
||||
list_remove(list, *node);
|
||||
*node = NULL;
|
||||
}
|
||||
|
||||
IOT_FUNC_EXIT;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user