add new qloud-c-sdk component
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
file(GLOB src_system_mqtt ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
|
||||
set(inc_system_mqtt ${CMAKE_CURRENT_SOURCE_DIR}/inc/)
|
||||
|
||||
set(src_services ${src_services} ${src_system_mqtt} PARENT_SCOPE)
|
||||
set(inc_services ${inc_services} ${inc_system_mqtt} PARENT_SCOPE)
|
||||
|
||||
file(GLOB src_data_template_sample ${CMAKE_CURRENT_SOURCE_DIR}/sample/data_template_sample.c)
|
||||
add_executable(data_template_sample ${src_data_template_sample})
|
||||
target_link_libraries(data_template_sample ${libsdk})
|
||||
|
||||
if( ${CONFIG_IOT_TEST} STREQUAL "ON")
|
||||
file(GLOB src_unit_test ${CMAKE_CURRENT_SOURCE_DIR}/test/*.cc)
|
||||
set(src_test ${src_test} ${src_unit_test} PARENT_SCOPE)
|
||||
endif()
|
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file data_template.h
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-08-23
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-08-23 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifndef IOT_HUB_DEVICE_C_SDK_SERVICES_EXPLORER_DATA_TEMPLATE_INC_DATA_TEMPLATE_H_
|
||||
#define IOT_HUB_DEVICE_C_SDK_SERVICES_EXPLORER_DATA_TEMPLATE_INC_DATA_TEMPLATE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud_iot_common.h"
|
||||
#include "qcloud_iot_data_template.h"
|
||||
|
||||
/**************************************************************************************
|
||||
* common
|
||||
**************************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Type of data template(property/event/action).
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
DATA_TEMPLATE_TYPE_PROPERTY = 0,
|
||||
DATA_TEMPLATE_TYPE_EVENT,
|
||||
DATA_TEMPLATE_TYPE_ACTION,
|
||||
} DataTemplateType;
|
||||
|
||||
/**
|
||||
* @brief Context of data template, callback and user data.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
PropertyMessageCallback property_callback;
|
||||
EventMessageCallback event_callback;
|
||||
ActionMessageCallback action_callback;
|
||||
};
|
||||
void *usr_data;
|
||||
} DataTemplateContext;
|
||||
|
||||
/**
|
||||
* @brief Check if topic already subscribed, if not then subscribe.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] type @see DataTemplateType
|
||||
* @param[in] on_message_handler message handle of topic
|
||||
* @param[in] context @see DataTemplateContext
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int data_template_topic_check_and_sub(void *client, DataTemplateType type, OnMessageHandler on_message_handler,
|
||||
DataTemplateContext context);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe data template topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] type @see DataTemplateType
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int data_template_topic_unsubscribe(void *client, DataTemplateType type);
|
||||
|
||||
/**
|
||||
* @brief Publish to data template topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] type @see DataTemplateType
|
||||
* @param[in] qos @see QoS
|
||||
* @param[in] payload payload of mqtt packet
|
||||
* @param[in] payload_len payload len
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int data_template_publish(void *client, DataTemplateType type, QoS qos, const char *payload, int payload_len);
|
||||
|
||||
/**************************************************************************************
|
||||
* property
|
||||
**************************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
PROPERTY_UP_METHOD_TYPE_REPORT = 0,
|
||||
PROPERTY_UP_METHOD_TYPE_REPORT_INFO,
|
||||
PROPERTY_UP_METHOD_TYPE_GET_STATUS,
|
||||
PROPERTY_UP_METHOD_TYPE_CLEAR_CONTROL,
|
||||
PROPERTY_UP_METHOD_TYPE_CONTROL_REPLY,
|
||||
} PropertyUpMethodType;
|
||||
|
||||
typedef union {
|
||||
const char *json;
|
||||
int code;
|
||||
struct {
|
||||
int code;
|
||||
UtilsJsonValue client_token;
|
||||
} control_reply;
|
||||
} PropertyPublishParams;
|
||||
|
||||
/**
|
||||
* @brief Mqtt message callback for property topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] message message from topic
|
||||
* @param[in,out] usr_data pointer to @see DataTemplateContext
|
||||
*/
|
||||
void data_template_property_message_handler(void *client, const MQTTMessage *message, void *usr_data);
|
||||
|
||||
/**
|
||||
* @brief Publish message to property topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] publish_type @see PropertyUpMethodType
|
||||
* @param[out] buf publish message buffer
|
||||
* @param[in] buf_len buffer len
|
||||
* @param[in] params @see PropertyPublishParams
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int data_template_property_publish(void *client, PropertyUpMethodType publish_type, char *buf, int buf_len,
|
||||
PropertyPublishParams params);
|
||||
|
||||
/**************************************************************************************
|
||||
* event
|
||||
**************************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Mqtt message callback for event topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] message message from topic
|
||||
* @param[in,out] usr_data pointer to @see DataTemplateContext
|
||||
*/
|
||||
void data_template_event_message_handler(void *client, const MQTTMessage *message, void *usr_data);
|
||||
|
||||
/**
|
||||
* @brief Publish message to event topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[out] buf publish message buffer
|
||||
* @param[in] buf_len buffer len
|
||||
* @param[in] data @see IotDataTemplateEventData
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int data_template_event_reply_publish(void *client, char *buf, int buf_len, IotDataTemplateEventData data);
|
||||
|
||||
/**************************************************************************************
|
||||
* action
|
||||
**************************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Mqtt message callback for action topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] message message from topic
|
||||
* @param[in,out] usr_data pointer to @see DataTemplateContext
|
||||
*/
|
||||
void data_template_action_message_handler(void *client, const MQTTMessage *message, void *usr_data);
|
||||
|
||||
/**
|
||||
* @brief Publish message to event topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[out] buf publish message buffer
|
||||
* @param[in] buf_len buffer len
|
||||
* @param[in] reply @see IotDataTemplateActionReply
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int data_template_action_reply_publish(void *client, char *buf, int buf_len, IotDataTemplateActionReply reply);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // IOT_HUB_DEVICE_C_SDK_SERVICES_EXPLORER_DATA_TEMPLATE_INC_DATA_TEMPLATE_H_
|
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file data_template_sample.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-09-27
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-09-27 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qcloud_iot_common.h"
|
||||
#include "qcloud_iot_explorer.h"
|
||||
|
||||
#include "utils_log.h"
|
||||
|
||||
/**
|
||||
* @brief MQTT event callback, @see MQTTEventHandleFun
|
||||
*
|
||||
* @param[in] client pointer to mqtt client
|
||||
* @param[in] handle_context context
|
||||
* @param[in] msg msg
|
||||
*/
|
||||
static void _mqtt_event_handler(void *client, void *handle_context, MQTTEventMsg *msg)
|
||||
{
|
||||
MQTTMessage *mqtt_message = (MQTTMessage *)msg->msg;
|
||||
uintptr_t packet_id = (uintptr_t)msg->msg;
|
||||
|
||||
switch (msg->event_type) {
|
||||
case MQTT_EVENT_UNDEF:
|
||||
Log_i("undefined event occur.");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_DISCONNECT:
|
||||
Log_i("MQTT disconnect.");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_RECONNECT:
|
||||
Log_i("MQTT reconnect.");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_RECEIVED:
|
||||
Log_i("topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
|
||||
mqtt_message->topic_len, STRING_PTR_PRINT_SANITY_CHECK(mqtt_message->topic_name),
|
||||
mqtt_message->payload_len, STRING_PTR_PRINT_SANITY_CHECK((char *)mqtt_message->payload));
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBE_SUCCESS:
|
||||
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBE_TIMEOUT:
|
||||
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBE_NACK:
|
||||
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_UNSUBSCRIBE_SUCCESS:
|
||||
Log_i("unsubscribe success, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_UNSUBSCRIBE_TIMEOUT:
|
||||
Log_i("unsubscribe timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_UNSUBSCRIBE_NACK:
|
||||
Log_i("unsubscribe nack, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_SUCCESS:
|
||||
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_TIMEOUT:
|
||||
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_NACK:
|
||||
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
Log_i("Should NOT arrive here.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setup MQTT construct parameters.
|
||||
*
|
||||
* @param[in,out] initParams @see MQTTInitParams
|
||||
* @param[in] device_info @see DeviceInfo
|
||||
*/
|
||||
static void _setup_connect_init_params(MQTTInitParams *init_params, DeviceInfo *device_info)
|
||||
{
|
||||
init_params->device_info = device_info;
|
||||
init_params->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
|
||||
init_params->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
|
||||
init_params->auto_connect_enable = 1;
|
||||
init_params->event_handle.h_fp = _mqtt_event_handler;
|
||||
init_params->event_handle.context = NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Data template callback
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static void _method_control_callback(UtilsJsonValue client_token, UtilsJsonValue params, void *usr_data)
|
||||
{
|
||||
char buf[256];
|
||||
Log_i("recv msg[%.*s]: params=%.*s", client_token.value_len, client_token.value, params.value_len, params.value);
|
||||
IOT_DataTemplate_PropertyControlReply(usr_data, buf, sizeof(buf), 0, client_token);
|
||||
}
|
||||
|
||||
static void _method_report_reply_callback(UtilsJsonValue client_token, int code, void *usr_data)
|
||||
{
|
||||
Log_i("recv msg[%.*s]: code=%d", client_token.value_len, client_token.value, code);
|
||||
}
|
||||
|
||||
static void _method_get_status_reply_callback(UtilsJsonValue client_token, int code, UtilsJsonValue reported,
|
||||
UtilsJsonValue control, void *usr_data)
|
||||
{
|
||||
char buf[256];
|
||||
Log_i("recv msg[%.*s]: code=%d|reported=%.*s|control=%.*s", client_token.value_len, client_token.value, code,
|
||||
reported.value_len, STRING_PTR_PRINT_SANITY_CHECK(reported.value), control.value_len,
|
||||
STRING_PTR_PRINT_SANITY_CHECK(control.value));
|
||||
IOT_DataTemplate_PropertyClearControl(usr_data, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static void _method_report_info_reply_callback(UtilsJsonValue client_token, int code, void *usr_data)
|
||||
{
|
||||
Log_i("recv msg[%.*s]: code=%d", client_token.value_len, client_token.value, code);
|
||||
}
|
||||
|
||||
static void _method_clear_control_reply_callback(UtilsJsonValue client_token, int code, void *usr_data)
|
||||
{
|
||||
Log_i("recv msg[%.*s]: code=%d", client_token.value_len, client_token.value, code);
|
||||
}
|
||||
|
||||
static void _method_event_reply_callback(UtilsJsonValue client_token, int code, void *usr_data)
|
||||
{
|
||||
Log_i("recv msg[%.*s]: code=%d", client_token.value_len, client_token.value, code);
|
||||
}
|
||||
|
||||
static void _method_action_callback(UtilsJsonValue client_token, UtilsJsonValue action_id, UtilsJsonValue params,
|
||||
void *usr_data)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
Log_i("recv msg[%.*s]: action_id=%.*s|params=%.*s", client_token.value_len, client_token.value, action_id.value_len,
|
||||
action_id.value, params.value_len, params.value);
|
||||
IotDataTemplateActionReply reply = {
|
||||
.code = 0,
|
||||
.client_token = client_token,
|
||||
.response = "{\"err_code\":0}",
|
||||
};
|
||||
IOT_DataTemplate_ActionReply(usr_data, buf, sizeof(buf), reply);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Data template upstream
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static void _cycle_report(void *client)
|
||||
{
|
||||
char buf[256];
|
||||
const char *report_property = "{\"power_switch\":0}";
|
||||
|
||||
IotDataTemplateEventData event_data = {
|
||||
.event_id = "status_report",
|
||||
.type = IOT_DATA_TEMPLATE_EVENT_TYPE_INFO,
|
||||
.params = "{\"status\":0,\"message\":\"ok\"}",
|
||||
|
||||
};
|
||||
|
||||
static Timer sg_cycle_report_timer;
|
||||
if (HAL_Timer_Expired(&sg_cycle_report_timer)) {
|
||||
IOT_DataTemplate_PropertyReport(client, buf, sizeof(buf), report_property);
|
||||
IOT_DataTemplate_EventPost(client, buf, sizeof(buf), event_data);
|
||||
HAL_Timer_Countdown(&sg_cycle_report_timer, 500);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Main
|
||||
// ----------------------------------------------------------------------------
|
||||
static int sg_main_exit = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void _main_exit(int sig)
|
||||
{
|
||||
Log_e("demo exit by signal:%d\n", sig);
|
||||
sg_main_exit = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef __linux__
|
||||
signal(SIGINT, _main_exit);
|
||||
#endif
|
||||
|
||||
int rc;
|
||||
|
||||
char buf[1024];
|
||||
|
||||
// init log level
|
||||
LogHandleFunc func = {0};
|
||||
|
||||
func.log_malloc = HAL_Malloc;
|
||||
func.log_free = HAL_Free;
|
||||
func.log_get_current_time_str = HAL_Timer_Current;
|
||||
func.log_printf = HAL_Printf;
|
||||
utils_log_init(func, LOG_LEVEL_DEBUG, 2048);
|
||||
|
||||
DeviceInfo device_info;
|
||||
|
||||
rc = HAL_GetDevInfo((void *)&device_info);
|
||||
if (rc) {
|
||||
Log_e("get device info failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// init connection
|
||||
MQTTInitParams init_params = DEFAULT_MQTT_INIT_PARAMS;
|
||||
_setup_connect_init_params(&init_params, &device_info);
|
||||
|
||||
// create MQTT client and connect with server
|
||||
void *client = IOT_MQTT_Construct(&init_params);
|
||||
if (client) {
|
||||
Log_i("Cloud Device Construct Success");
|
||||
} else {
|
||||
Log_e("MQTT Construct failed!");
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
// subscribe normal topics and wait result
|
||||
IotDataTemplateCallback callback = {
|
||||
.property_callback = {.method_control_callback = _method_control_callback,
|
||||
.method_clear_control_reply_callback = _method_clear_control_reply_callback,
|
||||
.method_get_status_reply_callback = _method_get_status_reply_callback,
|
||||
.method_report_info_reply_callback = _method_report_info_reply_callback,
|
||||
.method_report_reply_callback = _method_report_reply_callback},
|
||||
.event_callback = {.method_event_reply_callback = _method_event_reply_callback},
|
||||
.action_callback = {.method_action_callback = _method_action_callback},
|
||||
};
|
||||
|
||||
rc = IOT_DataTemplate_Init(client, callback, client);
|
||||
if (rc) {
|
||||
Log_e("Client Subscribe Topic Failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
const char *report_info =
|
||||
"{\"module_hardinfo\":\"ESP8266\",\"module_softinfo\":\"V1.0\", \"fw_ver\":\"4.0.0\", "
|
||||
"\"imei\":\"11-22-33-44\",\"lat\":\"22.546015\",\"lon\":\"113.941125\",\"mac\":\"11:22:33:44:55:66\",\"device_"
|
||||
"label\":{\"append_"
|
||||
"info\":\"your self defined info\"}}";
|
||||
|
||||
IOT_DataTemplate_PropertyReportInfo(client, buf, sizeof(buf), report_info);
|
||||
IOT_DataTemplate_PropertyGetStatus(client, buf, sizeof(buf));
|
||||
|
||||
do {
|
||||
rc = IOT_MQTT_Yield(client, QCLOUD_IOT_MQTT_YIELD_TIMEOUT);
|
||||
switch (rc) {
|
||||
case QCLOUD_RET_SUCCESS:
|
||||
break;
|
||||
case QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT:
|
||||
continue;
|
||||
case QCLOUD_RET_MQTT_RECONNECTED:
|
||||
IOT_DataTemplate_PropertyGetStatus(client, buf, sizeof(buf));
|
||||
break;
|
||||
default:
|
||||
Log_e("Exit loop caused of errCode:%d", rc);
|
||||
goto exit;
|
||||
}
|
||||
_cycle_report(client);
|
||||
} while (!sg_main_exit);
|
||||
|
||||
exit:
|
||||
IOT_DataTemplate_Deinit(client);
|
||||
rc |= IOT_MQTT_Destroy(&client);
|
||||
utils_log_deinit();
|
||||
return rc;
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file data_template_action.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-09-26
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-09-26 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "data_template.h"
|
||||
|
||||
/**
|
||||
* @brief Mqtt message callback for action topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] message message from topic
|
||||
* @param[in,out] usr_data pointer to @see DataTemplateContext
|
||||
*/
|
||||
void data_template_action_message_handler(void *client, const MQTTMessage *message, void *usr_data)
|
||||
{
|
||||
DataTemplateContext *data_template_context = (DataTemplateContext *)usr_data;
|
||||
|
||||
int rc = 0;
|
||||
UtilsJsonValue method, client_token, action_id, params;
|
||||
|
||||
Log_d("receive action message:%.*s", message->payload_len, message->payload_str);
|
||||
|
||||
rc = utils_json_value_get("method", strlen("method"), message->payload_str, message->payload_len, &method);
|
||||
if (rc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strncmp(method.value, "action", method.value_len)) {
|
||||
if (data_template_context->action_callback.method_action_callback) {
|
||||
rc = utils_json_value_get("clientToken", strlen("clientToken"), message->payload_str, message->payload_len,
|
||||
&client_token);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = utils_json_value_get("actionId", strlen("actionId"), message->payload_str, message->payload_len,
|
||||
&action_id);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = utils_json_value_get("params", strlen("params"), message->payload_str, message->payload_len, ¶ms);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
data_template_context->action_callback.method_action_callback(client_token, action_id, params,
|
||||
data_template_context->usr_data);
|
||||
}
|
||||
}
|
||||
return;
|
||||
error:
|
||||
Log_e("invalid format of payload!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Publish message to event topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[out] buf publish message buffer
|
||||
* @param[in] buf_len buffer len
|
||||
* @param[in] reply @see IotDataTemplateActionReply
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int data_template_action_reply_publish(void *client, char *buf, int buf_len, IotDataTemplateActionReply reply)
|
||||
{
|
||||
int len =
|
||||
HAL_Snprintf(buf, buf_len, "{\"method\":\"action_reply\",\"clientToken\":\"%.*s\",\"code\":%d,\"response\":%s}",
|
||||
reply.client_token.value_len, reply.client_token.value, reply.code, reply.response);
|
||||
return data_template_publish(client, DATA_TEMPLATE_TYPE_ACTION, QOS0, buf, len);
|
||||
}
|
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file data_template.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-08-22
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-08-22 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "qcloud_iot_data_template.h"
|
||||
|
||||
#include "data_template.h"
|
||||
|
||||
/**
|
||||
* @brief Check and subscribe data template topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] callback @see IotDataTemplateCallback
|
||||
* @param[in] usr_data usr data used in callback
|
||||
* @return 0 for success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_DataTemplate_Init(void *client, IotDataTemplateCallback callback, void *usr_data)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
int rc = 0;
|
||||
|
||||
DataTemplateContext data_tempale_context;
|
||||
data_tempale_context.usr_data = usr_data;
|
||||
|
||||
data_tempale_context.property_callback = callback.property_callback;
|
||||
rc |= data_template_topic_check_and_sub(client, DATA_TEMPLATE_TYPE_PROPERTY, data_template_property_message_handler,
|
||||
data_tempale_context);
|
||||
|
||||
// if (callback.event_callback.method_event_reply_callback) {
|
||||
// data_tempale_context.event_callback = callback.event_callback;
|
||||
// rc |= data_template_topic_check_and_sub(client, DATA_TEMPLATE_TYPE_EVENT, data_template_event_message_handler,
|
||||
// data_tempale_context);
|
||||
// }
|
||||
|
||||
// if (callback.action_callback.method_action_callback) {
|
||||
// data_tempale_context.action_callback = callback.action_callback;
|
||||
// rc |= data_template_topic_check_and_sub(client, DATA_TEMPLATE_TYPE_ACTION, data_template_action_message_handler,
|
||||
// data_tempale_context);
|
||||
// }
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe data template topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
*/
|
||||
void IOT_DataTemplate_Deinit(void *client)
|
||||
{
|
||||
POINTER_SANITY_CHECK_RTN(client);
|
||||
|
||||
data_template_topic_unsubscribe(client, DATA_TEMPLATE_TYPE_PROPERTY);
|
||||
data_template_topic_unsubscribe(client, DATA_TEMPLATE_TYPE_EVENT);
|
||||
data_template_topic_unsubscribe(client, DATA_TEMPLATE_TYPE_ACTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report property.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] buf buffer for message
|
||||
* @param[in] buf_len buffer length
|
||||
* @param[in] params params constructed with property
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_DataTemplate_PropertyReport(void *client, char *buf, int buf_len, const char *params)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
|
||||
|
||||
PropertyPublishParams publish_params = {.json = params};
|
||||
return data_template_property_publish(client, PROPERTY_UP_METHOD_TYPE_REPORT, buf, buf_len, publish_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get control message offline.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] buf buffer for message
|
||||
* @param[in] buf_len buffer length
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_DataTemplate_PropertyGetStatus(void *client, char *buf, int buf_len)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
|
||||
|
||||
PropertyPublishParams publish_params = {0};
|
||||
return data_template_property_publish(client, PROPERTY_UP_METHOD_TYPE_GET_STATUS, buf, buf_len, publish_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report device info.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] buf buffer for message
|
||||
* @param[in] buf_len buffer length
|
||||
* @param[in] params params constructed with device info
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_DataTemplate_PropertyReportInfo(void *client, char *buf, int buf_len, const char *params)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
|
||||
|
||||
PropertyPublishParams publish_params = {.json = params};
|
||||
return data_template_property_publish(client, PROPERTY_UP_METHOD_TYPE_REPORT_INFO, buf, buf_len, publish_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear control message offline.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] buf buffer for message
|
||||
* @param[in] buf_len buffer length
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_DataTemplate_PropertyClearControl(void *client, char *buf, int buf_len)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
|
||||
|
||||
PropertyPublishParams publish_params = {0};
|
||||
return data_template_property_publish(client, PROPERTY_UP_METHOD_TYPE_CLEAR_CONTROL, buf, buf_len, publish_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reply control message.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] buf buffer for message
|
||||
* @param[in] buf_len buffer length
|
||||
* @param[in] code 0 for success
|
||||
* @param[in] client_token client token of control message
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_DataTemplate_PropertyControlReply(void *client, char *buf, int buf_len, int code, UtilsJsonValue client_token)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
|
||||
|
||||
PropertyPublishParams publish_params = {.control_reply.code = code, .control_reply.client_token = client_token};
|
||||
return data_template_property_publish(client, PROPERTY_UP_METHOD_TYPE_CONTROL_REPLY, buf, buf_len, publish_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Post event.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] buf buffer for message
|
||||
* @param[in] buf_len buffer length
|
||||
* @param[in] data @see IotDataTemplateEventData
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_DataTemplate_EventPost(void *client, char *buf, int buf_len, IotDataTemplateEventData data)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
|
||||
|
||||
return data_template_event_reply_publish(client, buf, buf_len, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reply action message.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] buf buffer for message
|
||||
* @param[in] buf_len buffer length
|
||||
* @param[in] reply @see IotDataTemplateActionReply
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_DataTemplate_ActionReply(void *client, char *buf, int buf_len, IotDataTemplateActionReply reply)
|
||||
{
|
||||
return data_template_action_reply_publish(client, buf, buf_len, reply);
|
||||
}
|
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file data_template_event.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-09-26
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-09-26 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "data_template.h"
|
||||
|
||||
/**
|
||||
* @brief Mqtt message callback for event topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] message message from topic
|
||||
* @param[in,out] usr_data pointer to @see DataTemplateContext
|
||||
*/
|
||||
void data_template_event_message_handler(void *client, const MQTTMessage *message, void *usr_data)
|
||||
{
|
||||
DataTemplateContext *data_template_context = (DataTemplateContext *)usr_data;
|
||||
|
||||
int rc, code = 0;
|
||||
UtilsJsonValue method, client_token, value_code;
|
||||
|
||||
Log_d("receive event message:%.*s", message->payload_len, message->payload_str);
|
||||
|
||||
rc = utils_json_value_get("method", strlen("method"), message->payload_str, message->payload_len, &method);
|
||||
if (rc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strncmp(method.value, "event_reply", method.value_len)) {
|
||||
if (data_template_context->event_callback.method_event_reply_callback) {
|
||||
rc = utils_json_value_get("clientToken", strlen("clientToken"), message->payload_str, message->payload_len,
|
||||
&client_token);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = utils_json_value_get("code", strlen("code"), message->payload_str, message->payload_len, &value_code);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
rc = utils_json_value_data_get(value_code, UTILS_JSON_VALUE_TYPE_INT32, &code);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
data_template_context->event_callback.method_event_reply_callback(client_token, code,
|
||||
data_template_context->usr_data);
|
||||
}
|
||||
}
|
||||
return;
|
||||
error:
|
||||
Log_e("invalid format of payload!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Publish message to event topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[out] buf publish message buffer
|
||||
* @param[in] buf_len buffer len
|
||||
* @param[in] data @see IotDataTemplateEventData
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int data_template_event_reply_publish(void *client, char *buf, int buf_len, IotDataTemplateEventData data)
|
||||
{
|
||||
const char *event_type[] = {
|
||||
"info", // IOT_DATA_TEMPLATE_EVENT_TYPE_INFO
|
||||
"alert", // IOT_DATA_TEMPLATE_EVENT_TYPE_ALERT
|
||||
"fault", // IOT_DATA_TEMPLATE_EVENT_TYPE_FAULT
|
||||
};
|
||||
|
||||
static uint32_t token_num = 0;
|
||||
|
||||
int len = HAL_Snprintf(
|
||||
buf, buf_len,
|
||||
"{\"method\":\"event_post\",\"clientToken\":\"event-%u\",\"eventId\":\"%s\",\"type\":\"%s\",\"params\":%s}",
|
||||
token_num++, data.event_id, event_type[data.type], data.params);
|
||||
return data_template_publish(client, DATA_TEMPLATE_TYPE_EVENT, QOS0, buf, len);
|
||||
}
|
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file data_template_mqtt.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-10-18
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-10-18 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "qcloud_iot_data_template.h"
|
||||
|
||||
#include "data_template.h"
|
||||
|
||||
/**
|
||||
* @brief Direction(upstream/downstream) for topic.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
DATA_TEMPLATE_DIRECTION_UP = 0,
|
||||
DATA_TEMPLATE_DIRECTION_DOWN,
|
||||
} DataTemplateDirection;
|
||||
|
||||
/**
|
||||
* @brief Generate topic string.
|
||||
*
|
||||
* @param[out] buf buffer for topic name
|
||||
* @param[in] buf_len buffer length
|
||||
* @param[in] direction @see DataTemplateDirection
|
||||
* @param[in] type @see DataTemplateType
|
||||
* @param[in] product_id product id of device
|
||||
* @param[in] device_name device name of device
|
||||
* @return > 0 for length of topic name, others for fail.
|
||||
*/
|
||||
static int _data_template_topic_generate(char *buf, int buf_len, DataTemplateDirection direction, DataTemplateType type,
|
||||
const char *product_id, const char *device_name)
|
||||
{
|
||||
const char *topic_method[] = {"property", "event", "action"};
|
||||
// $thing/down/property/C283SMY3W3/test1
|
||||
return HAL_Snprintf(buf, buf_len, "$thing/%s/%s/%s/%s", direction ? "down" : "up", topic_method[type],
|
||||
STRING_PTR_PRINT_SANITY_CHECK(product_id), STRING_PTR_PRINT_SANITY_CHECK(device_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if topic already subscribed, if not then subscribe.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] type @see DataTemplateType
|
||||
* @param[in] on_message_handler message handle of topic
|
||||
* @param[in] context @see DataTemplateContext
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int data_template_topic_check_and_sub(void *client, DataTemplateType type, OnMessageHandler on_message_handler,
|
||||
DataTemplateContext context)
|
||||
{
|
||||
char data_template_topic[MAX_SIZE_OF_CLOUD_TOPIC];
|
||||
_data_template_topic_generate(data_template_topic, MAX_SIZE_OF_CLOUD_TOPIC, DATA_TEMPLATE_DIRECTION_DOWN, type,
|
||||
IOT_MQTT_GetDeviceInfo(client)->product_id,
|
||||
IOT_MQTT_GetDeviceInfo(client)->device_name);
|
||||
|
||||
int rc = 0;
|
||||
|
||||
DataTemplateContext *data_template_context = HAL_Malloc(sizeof(DataTemplateContext));
|
||||
if (!data_template_context) {
|
||||
return QCLOUD_ERR_MALLOC;
|
||||
}
|
||||
*data_template_context = context;
|
||||
|
||||
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
|
||||
sub_params.on_message_handler = on_message_handler;
|
||||
sub_params.qos = QOS1;
|
||||
sub_params.user_data = data_template_context;
|
||||
sub_params.user_data_free = HAL_Free;
|
||||
|
||||
rc = IOT_MQTT_SubscribeSync(client, data_template_topic, &sub_params);
|
||||
if (rc) {
|
||||
Log_e("subscribe topic %s failed!", data_template_topic);
|
||||
HAL_Free(data_template_context);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe data template topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] type @see DataTemplateType
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int data_template_topic_unsubscribe(void *client, DataTemplateType type)
|
||||
{
|
||||
char data_template_topic[MAX_SIZE_OF_CLOUD_TOPIC];
|
||||
_data_template_topic_generate(data_template_topic, MAX_SIZE_OF_CLOUD_TOPIC, DATA_TEMPLATE_DIRECTION_DOWN, type,
|
||||
IOT_MQTT_GetDeviceInfo(client)->product_id,
|
||||
IOT_MQTT_GetDeviceInfo(client)->device_name);
|
||||
return IOT_MQTT_Unsubscribe(client, data_template_topic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Publish to data template topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] type @see DataTemplateType
|
||||
* @param[in] qos @see QoS
|
||||
* @param[in] payload payload of mqtt packet
|
||||
* @param[in] payload_len payload len
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int data_template_publish(void *client, DataTemplateType type, QoS qos, const char *payload, int payload_len)
|
||||
{
|
||||
NUMBERIC_SANITY_CHECK(payload_len, QCLOUD_ERR_BUF_TOO_SHORT);
|
||||
|
||||
char data_template_topic[MAX_SIZE_OF_CLOUD_TOPIC];
|
||||
_data_template_topic_generate(data_template_topic, MAX_SIZE_OF_CLOUD_TOPIC, DATA_TEMPLATE_DIRECTION_UP, type,
|
||||
IOT_MQTT_GetDeviceInfo(client)->product_id,
|
||||
IOT_MQTT_GetDeviceInfo(client)->device_name);
|
||||
|
||||
PublishParams pub_params = DEFAULT_PUB_PARAMS;
|
||||
pub_params.qos = qos;
|
||||
pub_params.payload = (void *)payload;
|
||||
pub_params.payload_len = payload_len;
|
||||
return IOT_MQTT_Publish(client, data_template_topic, &pub_params);
|
||||
}
|
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file data_template_property.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-08-23
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-08-23 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "qcloud_iot_data_template.h"
|
||||
#include "data_template.h"
|
||||
|
||||
/**
|
||||
* @brief Down method type.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
PROPERTY_DOWN_METHOD_TYPE_CONTROL = 0,
|
||||
PROPERTY_DOWN_METHOD_TYPE_REPORT_REPLY,
|
||||
PROPERTY_DOWN_METHOD_TYPE_GET_STATUS_REPLY,
|
||||
PROPERTY_DOWN_METHOD_TYPE_REPORT_INFO_REPLY,
|
||||
PROPERTY_DOWN_METHOD_TYPE_CLEAR_CONTROL_REPLY,
|
||||
} PropertyDownMethodType;
|
||||
|
||||
/**
|
||||
* @brief Parse payload and callback.
|
||||
*
|
||||
* @param[in] type @see PropertyDownMethodType
|
||||
* @param[in] message message from cloud
|
||||
* @param[in] callback callback for user
|
||||
* @param[in,out] usr_data user data used in callback
|
||||
*/
|
||||
static void _parse_method_payload_and_callback(PropertyDownMethodType type, const MQTTMessage *message,
|
||||
const PropertyMessageCallback *callback, void *usr_data)
|
||||
{
|
||||
int rc = 0, code;
|
||||
UtilsJsonValue client_token, value_code, params, reported, control;
|
||||
|
||||
// get client token
|
||||
rc = utils_json_value_get("clientToken", strlen("clientToken"), message->payload_str, message->payload_len,
|
||||
&client_token);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// get code
|
||||
if (PROPERTY_DOWN_METHOD_TYPE_REPORT_REPLY == type || PROPERTY_DOWN_METHOD_TYPE_GET_STATUS_REPLY == type ||
|
||||
PROPERTY_DOWN_METHOD_TYPE_REPORT_INFO_REPLY == type || PROPERTY_DOWN_METHOD_TYPE_CLEAR_CONTROL_REPLY == type) {
|
||||
rc = utils_json_value_get("code", strlen("code"), message->payload_str, message->payload_len, &value_code);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = utils_json_value_data_get(value_code, UTILS_JSON_VALUE_TYPE_INT32, &code);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// callback
|
||||
switch (type) {
|
||||
case PROPERTY_DOWN_METHOD_TYPE_CONTROL:
|
||||
if (callback->method_control_callback) {
|
||||
rc = utils_json_value_get("params", strlen("params"), message->payload_str, message->payload_len,
|
||||
¶ms);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
callback->method_control_callback(client_token, params, usr_data);
|
||||
}
|
||||
break;
|
||||
case PROPERTY_DOWN_METHOD_TYPE_REPORT_REPLY:
|
||||
if (callback->method_report_reply_callback) {
|
||||
callback->method_report_reply_callback(client_token, code, usr_data);
|
||||
}
|
||||
break;
|
||||
case PROPERTY_DOWN_METHOD_TYPE_GET_STATUS_REPLY:
|
||||
if (callback->method_get_status_reply_callback) {
|
||||
reported.value = NULL;
|
||||
reported.value_len = 0;
|
||||
control.value = NULL;
|
||||
control.value_len = 0;
|
||||
rc = utils_json_value_get("data.reported", strlen("data.reported"), message->payload_str,
|
||||
message->payload_len, &reported);
|
||||
rc &= utils_json_value_get("data.control", strlen("data.control"), message->payload_str,
|
||||
message->payload_len, &control);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
callback->method_get_status_reply_callback(client_token, code, reported, control, usr_data);
|
||||
}
|
||||
break;
|
||||
case PROPERTY_DOWN_METHOD_TYPE_REPORT_INFO_REPLY:
|
||||
if (callback->method_report_info_reply_callback) {
|
||||
callback->method_report_info_reply_callback(client_token, code, usr_data);
|
||||
}
|
||||
break;
|
||||
case PROPERTY_DOWN_METHOD_TYPE_CLEAR_CONTROL_REPLY:
|
||||
if (callback->method_clear_control_reply_callback) {
|
||||
callback->method_clear_control_reply_callback(client_token, code, usr_data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
error:
|
||||
Log_e("invalid format of payload!");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mqtt message callback for property topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] message message from topic
|
||||
* @param[in,out] usr_data pointer to @see DataTemplateContext
|
||||
*/
|
||||
void data_template_property_message_handler(void *client, const MQTTMessage *message, void *usr_data)
|
||||
{
|
||||
const char *property_down_method_str[] = {
|
||||
"control", // PROPERTY_DOWN_METHOD_TYPE_CONTROL
|
||||
"report_reply", // PROPERTY_DOWN_METHOD_TYPE_REPORT_REPLY
|
||||
"get_status_reply", // PROPERTY_DOWN_METHOD_TYPE_GET_STATUS_REPLY
|
||||
"report_info_reply", // PROPERTY_DOWN_METHOD_TYPE_REPORT_INFO_REPLY
|
||||
"clear_control_reply", // PROPERTY_DOWN_METHOD_TYPE_CLEAR_CONTROL_REPLY
|
||||
};
|
||||
|
||||
int rc, i = 0;
|
||||
|
||||
DataTemplateContext *data_template_context = (DataTemplateContext *)usr_data;
|
||||
UtilsJsonValue method;
|
||||
|
||||
Log_d("receive property message:%.*s", message->payload_len, message->payload_str);
|
||||
|
||||
rc = utils_json_value_get("method", strlen("method"), message->payload_str, message->payload_len, &method);
|
||||
if (rc) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = PROPERTY_DOWN_METHOD_TYPE_CONTROL; i <= PROPERTY_DOWN_METHOD_TYPE_CLEAR_CONTROL_REPLY; i++) {
|
||||
if (!strncmp(method.value, property_down_method_str[i], method.value_len)) {
|
||||
_parse_method_payload_and_callback(i, message, &data_template_context->property_callback,
|
||||
data_template_context->usr_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Publish message to property topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] publish_type @see PropertyUpMethodType
|
||||
* @param[out] buf publish message buffer
|
||||
* @param[in] buf_len buffer len
|
||||
* @param[in] params @see PropertyPublishParams
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int data_template_property_publish(void *client, PropertyUpMethodType publish_type, char *buf, int buf_len,
|
||||
PropertyPublishParams params)
|
||||
{
|
||||
static uint32_t token_num = 0;
|
||||
|
||||
int len = 0;
|
||||
|
||||
switch (publish_type) {
|
||||
case PROPERTY_UP_METHOD_TYPE_REPORT:
|
||||
len = HAL_Snprintf(buf, buf_len, "{\"method\":\"report\",\"clientToken\":\"property-%u\",\"params\":%s}",
|
||||
token_num++, params.json);
|
||||
break;
|
||||
case PROPERTY_UP_METHOD_TYPE_REPORT_INFO:
|
||||
len =
|
||||
HAL_Snprintf(buf, buf_len, "{\"method\":\"report_info\",\"clientToken\":\"property-%u\",\"params\":%s}",
|
||||
token_num++, params.json);
|
||||
break;
|
||||
case PROPERTY_UP_METHOD_TYPE_GET_STATUS:
|
||||
len =
|
||||
HAL_Snprintf(buf, buf_len, "{\"method\":\"get_status\",\"clientToken\":\"property-%u\"}", token_num++);
|
||||
break;
|
||||
case PROPERTY_UP_METHOD_TYPE_CLEAR_CONTROL:
|
||||
len = HAL_Snprintf(buf, buf_len, "{\"method\":\"clear_control\",\"clientToken\":\"property-%u\"}",
|
||||
token_num++);
|
||||
break;
|
||||
case PROPERTY_UP_METHOD_TYPE_CONTROL_REPLY:
|
||||
len = HAL_Snprintf(buf, buf_len, "{\"method\":\"control_reply\",\"clientToken\":\"%.*s\",\"code\":%d}",
|
||||
params.control_reply.client_token.value_len, params.control_reply.client_token.value,
|
||||
params.control_reply.code);
|
||||
break;
|
||||
default:
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
return data_template_publish(client, DATA_TEMPLATE_TYPE_PROPERTY, QOS0, buf, len);
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 120
|
||||
DerivePointerAlignment: true
|
||||
PointerAlignment: Left
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Preserve
|
||||
IndentPPDirectives: AfterHash
|
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file test_data_template.cc
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-09-29
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-09-29 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "mqtt_client_test.h"
|
||||
#include "qcloud_iot_common.h"
|
||||
#include "qcloud_iot_explorer.h"
|
||||
|
||||
namespace mqtt_client_unittest {
|
||||
|
||||
static void _method_control_callback(UtilsJsonValue client_token, UtilsJsonValue params, void *usr_data) {
|
||||
char buf[256];
|
||||
Log_i("recv msg[%.*s]: params=%.*s", client_token.value_len, client_token.value, params.value_len, params.value);
|
||||
IOT_DataTemplate_PropertyControlReply(usr_data, buf, sizeof(buf), 0, client_token);
|
||||
}
|
||||
|
||||
static void _method_report_reply_callback(UtilsJsonValue client_token, int code, void *usr_data) {
|
||||
Log_i("recv msg[%.*s]: code=%d", client_token.value_len, client_token.value, code);
|
||||
}
|
||||
|
||||
static void _method_get_status_reply_callback(UtilsJsonValue client_token, int code, UtilsJsonValue reported,
|
||||
UtilsJsonValue control, void *usr_data) {
|
||||
char buf[256];
|
||||
Log_i("recv msg[%.*s]: code=%d|reported=%.*s|control=%.*s", client_token.value_len, client_token.value, code,
|
||||
reported.value_len, STRING_PTR_PRINT_SANITY_CHECK(reported.value), control.value_len,
|
||||
STRING_PTR_PRINT_SANITY_CHECK(control.value));
|
||||
IOT_DataTemplate_PropertyClearControl(usr_data, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static void _method_report_info_reply_callback(UtilsJsonValue client_token, int code, void *usr_data) {
|
||||
Log_i("recv msg[%.*s]: code=%d", client_token.value_len, client_token.value, code);
|
||||
}
|
||||
|
||||
static void _method_clear_control_reply_callback(UtilsJsonValue client_token, int code, void *usr_data) {
|
||||
Log_i("recv msg[%.*s]: code=%d", client_token.value_len, client_token.value, code);
|
||||
}
|
||||
|
||||
static void _method_event_reply_callback(UtilsJsonValue client_token, int code, void *usr_data) {
|
||||
Log_i("recv msg[%.*s]: code=%d", client_token.value_len, client_token.value, code);
|
||||
}
|
||||
|
||||
static void _method_action_callback(UtilsJsonValue client_token, UtilsJsonValue action_id, UtilsJsonValue params,
|
||||
void *usr_data) {
|
||||
char buf[256];
|
||||
|
||||
Log_i("recv msg[%.*s]: action_id=%.*s|params=%.*s", client_token.value_len, client_token.value, action_id.value_len,
|
||||
action_id.value, params.value_len, params.value);
|
||||
|
||||
IotDataTemplateActionReply reply = {
|
||||
.client_token = client_token,
|
||||
.code = 0,
|
||||
.response = "{\"err_code\":0}",
|
||||
};
|
||||
|
||||
ASSERT_GE(IOT_DataTemplate_ActionReply(usr_data, buf, sizeof(buf), reply), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test data template property.
|
||||
*
|
||||
*/
|
||||
TEST_F(MqttClientTest, data_template_property) {
|
||||
char buf[1024];
|
||||
|
||||
IotDataTemplateCallback callback = {
|
||||
.property_callback = {.method_control_callback = _method_control_callback,
|
||||
.method_report_reply_callback = _method_report_reply_callback,
|
||||
.method_get_status_reply_callback = _method_get_status_reply_callback,
|
||||
.method_report_info_reply_callback = _method_report_info_reply_callback,
|
||||
.method_clear_control_reply_callback = _method_clear_control_reply_callback},
|
||||
.event_callback = {.method_event_reply_callback = NULL},
|
||||
.action_callback = {.method_action_callback = NULL},
|
||||
};
|
||||
|
||||
const char *report_info =
|
||||
"{\"module_hardinfo\":\"ESP8266\",\"module_softinfo\":\"V1.0\", \"fw_ver\":\"4.0.0\", "
|
||||
"\"imei\":\"11-22-33-44\",\"lat\":\"22.546015\",\"lon\":\"113.941125\",\"mac\":\"11:22:33:44:55:66\",\"device_"
|
||||
"label\":{\"append_"
|
||||
"info\":\"your self defined info\"}}";
|
||||
|
||||
ASSERT_EQ(IOT_DataTemplate_Init(client, callback, client), 0);
|
||||
ASSERT_EQ(IOT_DataTemplate_PropertyReportInfo(client, buf, sizeof(buf), report_info), 0);
|
||||
ASSERT_EQ(IOT_DataTemplate_PropertyGetStatus(client, buf, sizeof(buf)), 0);
|
||||
IOT_DataTemplate_Deinit(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test data template event.
|
||||
*
|
||||
*/
|
||||
TEST_F(MqttClientTest, data_template_event) {
|
||||
char buf[1024];
|
||||
IotDataTemplateCallback callback = {
|
||||
.property_callback = {0},
|
||||
.event_callback = {.method_event_reply_callback = _method_event_reply_callback},
|
||||
.action_callback = {.method_action_callback = _method_action_callback},
|
||||
};
|
||||
|
||||
const char *report_property = "{\"power_switch\":0}";
|
||||
|
||||
IotDataTemplateEventData event_data = {
|
||||
.event_id = "status_report",
|
||||
.type = IOT_DATA_TEMPLATE_EVENT_TYPE_INFO,
|
||||
.params = "{\"status\":0,\"message\":\"ok\"}",
|
||||
};
|
||||
|
||||
ASSERT_EQ(IOT_DataTemplate_Init(client, callback, client), 0);
|
||||
ASSERT_GE(IOT_DataTemplate_EventPost(client, buf, sizeof(buf), event_data), 0);
|
||||
IOT_DataTemplate_Deinit(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test data template action.
|
||||
*
|
||||
*/
|
||||
TEST_F(MqttClientTest, data_template_action) {
|
||||
char buf[1024];
|
||||
IotDataTemplateCallback callback = {
|
||||
.property_callback = {0},
|
||||
.event_callback = {.method_event_reply_callback = NULL},
|
||||
.action_callback = {.method_action_callback = _method_action_callback},
|
||||
};
|
||||
|
||||
ASSERT_EQ(IOT_DataTemplate_Init(client, callback, client), 0);
|
||||
IOT_DataTemplate_Deinit(client);
|
||||
}
|
||||
|
||||
} // namespace mqtt_client_unittest
|
@@ -0,0 +1,17 @@
|
||||
file(GLOB src_service_mqtt
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/*.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/file_manage/*.c
|
||||
)
|
||||
set(inc_service_mqtt ${CMAKE_CURRENT_SOURCE_DIR}/inc/)
|
||||
|
||||
set(src_services ${src_services} ${src_service_mqtt} PARENT_SCOPE)
|
||||
set(inc_services ${inc_services} ${inc_service_mqtt} PARENT_SCOPE)
|
||||
|
||||
file(GLOB src_file_manage_sample ${CMAKE_CURRENT_SOURCE_DIR}/sample/file_manage_sample.c)
|
||||
add_executable(file_manage_sample ${src_file_manage_sample})
|
||||
target_link_libraries(file_manage_sample ${libsdk})
|
||||
|
||||
if( ${CONFIG_IOT_TEST} STREQUAL "ON")
|
||||
file(GLOB src_unit_test ${CMAKE_CURRENT_SOURCE_DIR}/test/*.cc)
|
||||
set(src_test ${src_test} ${src_unit_test} PARENT_SCOPE)
|
||||
endif()
|
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2022 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.
|
||||
*
|
||||
* @file service_mqtt.h
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2022-01-11
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-01-11 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifndef IOT_HUB_DEVICE_C_SDK_SERVICES_EXPLORER_SERVICE_MQTT_INC_SERVICE_MQTT_H_
|
||||
#define IOT_HUB_DEVICE_C_SDK_SERVICES_EXPLORER_SERVICE_MQTT_INC_SERVICE_MQTT_H_
|
||||
|
||||
#include "qcloud_iot_common.h"
|
||||
#include "utils_list.h"
|
||||
|
||||
/**
|
||||
* @brief Service type, only file manage supportted now.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
SERVICE_TYPE_FILE_MANAGE = 0,
|
||||
} ServiceType;
|
||||
|
||||
/**
|
||||
* @brief Register to server list.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
ServiceType type;
|
||||
const char ** method_list;
|
||||
int method_num;
|
||||
OnMessageHandler message_handle;
|
||||
void * usr_data;
|
||||
void (*user_data_free)(void *);
|
||||
} ServiceRegisterParams;
|
||||
|
||||
/**
|
||||
* @brief Subscribe service mqtt.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int service_mqtt_init(void *client);
|
||||
|
||||
/**
|
||||
* @brief If no service in the service list, then unsubscribe.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
*/
|
||||
void service_mqtt_deinit(void *client);
|
||||
|
||||
/**
|
||||
* @brief Publish to service mqtt topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] qos @see QoS
|
||||
* @param[in] payload payload of mqtt packet
|
||||
* @param[in] payload_len payload len
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int service_mqtt_publish(void *client, QoS qos, const char *payload, int payload_len);
|
||||
|
||||
/**
|
||||
* @brief Register server handler to server list.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] params @see ServiceRegisterParams
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int service_mqtt_service_register(void *client, const ServiceRegisterParams *params);
|
||||
|
||||
/**
|
||||
* @brief Unregister server handler from server list.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] type @see ServiceType
|
||||
*/
|
||||
void service_mqtt_service_unregister(void *client, ServiceType type);
|
||||
|
||||
#endif // IOT_HUB_DEVICE_C_SDK_SERVICES_EXPLORER_SERVICE_MQTT_INC_SERVICE_MQTT_H_
|
@@ -0,0 +1,349 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 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.
|
||||
*
|
||||
* @file broadcast_sample.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-07-18
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-07-18 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qcloud_iot_explorer.h"
|
||||
|
||||
#include "utils_log.h"
|
||||
|
||||
/**
|
||||
* @brief MQTT event callback, @see MQTTEventHandleFun
|
||||
*
|
||||
* @param[in] client pointer to mqtt client
|
||||
* @param[in] handle_context context
|
||||
* @param[in] msg msg
|
||||
*/
|
||||
static void _mqtt_event_handler(void *client, void *handle_context, MQTTEventMsg *msg)
|
||||
{
|
||||
MQTTMessage *mqtt_message = (MQTTMessage *)msg->msg;
|
||||
uintptr_t packet_id = (uintptr_t)msg->msg;
|
||||
|
||||
switch (msg->event_type) {
|
||||
case MQTT_EVENT_UNDEF:
|
||||
Log_i("undefined event occur.");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_DISCONNECT:
|
||||
Log_i("MQTT disconnect.");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_RECONNECT:
|
||||
Log_i("MQTT reconnect.");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_RECEIVED:
|
||||
Log_i("topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
|
||||
mqtt_message->topic_len, STRING_PTR_PRINT_SANITY_CHECK(mqtt_message->topic_name),
|
||||
mqtt_message->payload_len, STRING_PTR_PRINT_SANITY_CHECK((char *)mqtt_message->payload));
|
||||
break;
|
||||
case MQTT_EVENT_SUBSCRIBE_SUCCESS:
|
||||
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBE_TIMEOUT:
|
||||
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBE_NACK:
|
||||
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_UNSUBSCRIBE_SUCCESS:
|
||||
Log_i("unsubscribe success, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_UNSUBSCRIBE_TIMEOUT:
|
||||
Log_i("unsubscribe timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_UNSUBSCRIBE_NACK:
|
||||
Log_i("unsubscribe nack, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_SUCCESS:
|
||||
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_TIMEOUT:
|
||||
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_NACK:
|
||||
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
|
||||
break;
|
||||
default:
|
||||
Log_i("Should NOT arrive here.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setup MQTT construct parameters.
|
||||
*
|
||||
* @param[in,out] initParams @see MQTTInitParams
|
||||
* @param[in] device_info @see DeviceInfo
|
||||
*/
|
||||
static void _setup_connect_init_params(MQTTInitParams *init_params, DeviceInfo *device_info)
|
||||
{
|
||||
init_params->device_info = device_info;
|
||||
init_params->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
|
||||
init_params->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
|
||||
init_params->auto_connect_enable = 1;
|
||||
init_params->event_handle.h_fp = _mqtt_event_handler;
|
||||
init_params->event_handle.context = NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// file list function
|
||||
// ----------------------------------------------------------------------------
|
||||
static IotFileManageFileInfo sg_file_list[5];
|
||||
|
||||
static void _file_info_init(IotFileManageFileInfo *file_info, UtilsJsonValue file_name, UtilsJsonValue file_type,
|
||||
UtilsJsonValue version)
|
||||
{
|
||||
strncpy(file_info->file_name, file_name.value, file_name.value_len);
|
||||
strncpy(file_info->file_version, version.value, version.value_len);
|
||||
file_info->file_type = IOT_FileManage_GetFileType(file_type.value, file_type.value_len);
|
||||
}
|
||||
|
||||
static void _add_file_info_to_list(IotFileManageFileInfo *file_info)
|
||||
{
|
||||
int i_free = -1;
|
||||
for (int i = 0; i < sizeof(sg_file_list) / sizeof(sg_file_list[0]); i++) {
|
||||
if (!strcmp(sg_file_list[i].file_name, file_info->file_name)) {
|
||||
memcpy(sg_file_list + i, file_info, sizeof(IotFileManageFileInfo));
|
||||
return;
|
||||
}
|
||||
|
||||
if (sg_file_list[i].file_name[0] == '\0' && i_free == -1) {
|
||||
i_free = i;
|
||||
}
|
||||
}
|
||||
if (i_free != -1) {
|
||||
memcpy(sg_file_list + i_free, file_info, sizeof(IotFileManageFileInfo));
|
||||
}
|
||||
}
|
||||
|
||||
static void _del_file_info_to_list(IotFileManageFileInfo *file_info)
|
||||
{
|
||||
for (int i = 0; i < sizeof(sg_file_list) / sizeof(sg_file_list[0]); i++) {
|
||||
if (!strcmp(sg_file_list[i].file_name, file_info->file_name)) {
|
||||
sg_file_list[i].file_name[0] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// file function
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static int _file_download(void *client, char *buf, int buf_len, UtilsJsonValue url, UtilsJsonValue md5sum,
|
||||
uint32_t file_size, IotFileManageFileInfo *file_info)
|
||||
{
|
||||
Log_i("downloading file:url=%.*s|md5sum=%.*s|file_size=%u", url.value_len, url.value, md5sum.value_len,
|
||||
md5sum.value, file_size);
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOADING, 0, file_info->file_name,
|
||||
file_info->file_version);
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOADING, 50, file_info->file_name,
|
||||
file_info->file_version);
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOADING, 100, file_info->file_name,
|
||||
file_info->file_version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _file_upgrade(void *client, char *buf, int buf_len, IotFileManageFileInfo *file_info)
|
||||
{
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_BEGIN, 0, file_info->file_name,
|
||||
file_info->file_version);
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_SUCCESS, 0, file_info->file_name,
|
||||
file_info->file_version);
|
||||
_add_file_info_to_list(file_info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _file_del(void *client, char *buf, int buf_len, IotFileManageFileInfo *file_info)
|
||||
{
|
||||
_del_file_info_to_list(file_info);
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_DEL_SUCCESS, 0, file_info->file_name,
|
||||
file_info->file_version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// OTA callback
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static void _file_manage_update_file_callback(UtilsJsonValue file_name, UtilsJsonValue file_type,
|
||||
UtilsJsonValue version, UtilsJsonValue url, UtilsJsonValue md5sum,
|
||||
uint32_t file_size, void *usr_data)
|
||||
{
|
||||
IotFileManageFileInfo file_info = {0};
|
||||
|
||||
char buf[256];
|
||||
int buf_len = sizeof(buf);
|
||||
|
||||
Log_i("recv file: file_name=%.*s|type=%.*s|version=%.*s|url=%.*s|md5sum=%.*s|file_size=%u", file_name.value_len,
|
||||
file_name.value, file_type.value_len, file_type.value, version.value_len, version.value, url.value_len,
|
||||
url.value, md5sum.value_len, md5sum.value, file_size);
|
||||
|
||||
_file_info_init(&file_info, file_name, file_type, version);
|
||||
|
||||
int rc = _file_download(usr_data, buf, buf_len, url, md5sum, file_size, &file_info);
|
||||
if (rc) {
|
||||
IOT_FileManage_Report(usr_data, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_FAIL, 0, file_info.file_name,
|
||||
file_info.file_version);
|
||||
return;
|
||||
}
|
||||
_file_upgrade(usr_data, buf, buf_len, &file_info);
|
||||
IOT_FileManage_ReportFileList(usr_data, buf, buf_len, sg_file_list, sizeof(sg_file_list) / sizeof(sg_file_list[0]));
|
||||
}
|
||||
|
||||
static void _file_manage_del_file_callback(UtilsJsonValue file_name, UtilsJsonValue file_type, UtilsJsonValue version,
|
||||
void *usr_data)
|
||||
{
|
||||
char buf[256];
|
||||
int buf_len = sizeof(buf);
|
||||
|
||||
IotFileManageFileInfo file_info = {0};
|
||||
_file_info_init(&file_info, file_name, file_type, version);
|
||||
_file_del(usr_data, buf, buf_len, &file_info);
|
||||
IOT_FileManage_ReportFileList(usr_data, buf, buf_len, sg_file_list, sizeof(sg_file_list) / sizeof(sg_file_list[0]));
|
||||
}
|
||||
|
||||
static void _file_manage_report_file_version_reponse_callback(UtilsJsonValue file_list, int result_code, void *usr_data)
|
||||
{
|
||||
Log_i("recv file_list=%.*s|result_code=%d", file_list.value_len, file_list.value, result_code);
|
||||
}
|
||||
|
||||
static void _file_manage_request_file_url_response_callback(UtilsJsonValue url, UtilsJsonValue file_token,
|
||||
int result_code, void *usr_data)
|
||||
{
|
||||
Log_i("recv response: url=%.*s|file_token=%.*s|result_code=%d", url.value_len, url.value, file_token.value_len,
|
||||
file_token.value, result_code);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Main
|
||||
// ----------------------------------------------------------------------------
|
||||
static int sg_main_exit = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void _main_exit(int sig)
|
||||
{
|
||||
Log_e("demo exit by signal:%d\n", sig);
|
||||
sg_main_exit = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef __linux__
|
||||
signal(SIGINT, _main_exit);
|
||||
#endif
|
||||
|
||||
int rc;
|
||||
|
||||
char buf[1024];
|
||||
|
||||
// init log level
|
||||
LogHandleFunc func = {0};
|
||||
|
||||
func.log_malloc = HAL_Malloc;
|
||||
func.log_free = HAL_Free;
|
||||
func.log_get_current_time_str = HAL_Timer_Current;
|
||||
func.log_printf = HAL_Printf;
|
||||
utils_log_init(func, LOG_LEVEL_DEBUG, 2048);
|
||||
|
||||
DeviceInfo device_info;
|
||||
rc = HAL_GetDevInfo((void *)&device_info);
|
||||
if (rc) {
|
||||
Log_e("get device info failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// init connection
|
||||
MQTTInitParams init_params = DEFAULT_MQTT_INIT_PARAMS;
|
||||
_setup_connect_init_params(&init_params, &device_info);
|
||||
|
||||
// create MQTT client and connect with server
|
||||
void *client = IOT_MQTT_Construct(&init_params);
|
||||
if (client) {
|
||||
Log_i("Cloud Device Construct Success");
|
||||
} else {
|
||||
Log_e("MQTT Construct failed!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
IotFileManageCallback file_manage_callback = {
|
||||
.update_file_callback = _file_manage_update_file_callback,
|
||||
.del_file_callback = _file_manage_del_file_callback,
|
||||
.report_file_version_reponse_callback = _file_manage_report_file_version_reponse_callback,
|
||||
.request_file_url_response_callback = _file_manage_request_file_url_response_callback,
|
||||
};
|
||||
rc = IOT_FileManage_Init(client, file_manage_callback, client);
|
||||
if (rc) {
|
||||
Log_e("OTA init failed!, rc=%d", rc);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = IOT_FileManage_ReportFileList(client, buf, sizeof(buf), sg_file_list,
|
||||
sizeof(sg_file_list) / sizeof(sg_file_list[0]));
|
||||
if (rc) {
|
||||
Log_e("OTA report version failed!, rc=%d", rc);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
do {
|
||||
rc = IOT_MQTT_Yield(client, QCLOUD_IOT_MQTT_YIELD_TIMEOUT);
|
||||
switch (rc) {
|
||||
case QCLOUD_RET_SUCCESS:
|
||||
break;
|
||||
case QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT:
|
||||
continue;
|
||||
case QCLOUD_RET_MQTT_RECONNECTED:
|
||||
break;
|
||||
default:
|
||||
Log_e("Exit loop caused of errCode:%d", rc);
|
||||
goto exit;
|
||||
}
|
||||
} while (!sg_main_exit);
|
||||
exit:
|
||||
IOT_FileManage_Deinit(client);
|
||||
rc = IOT_MQTT_Destroy(&client);
|
||||
utils_log_deinit();
|
||||
return rc;
|
||||
}
|
@@ -0,0 +1,435 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2022 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.
|
||||
*
|
||||
* @file file_manage.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2022-01-11
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-01-11 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "qcloud_iot_file_manage.h"
|
||||
|
||||
#include "service_mqtt.h"
|
||||
|
||||
/**
|
||||
* @brief Context of file manage, callback and user data.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
IotFileManageCallback callback;
|
||||
void *usr_data;
|
||||
} FileManageContext;
|
||||
|
||||
/**
|
||||
* @brief File manage down stream message type.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
FILE_MANAGE_DOWN_MESSAGE_TYPE_UPDATE = 0,
|
||||
FILE_MANAGE_DOWN_MESSAGE_TYPE_DEL,
|
||||
FILE_MANAGE_DOWN_MESSAGE_TYPE_REPORT_VERSION_RESPONSE,
|
||||
FILE_MANAGE_DOWN_MESSAGE_TYPE_POST_REQUEST_RESPONSE,
|
||||
} FileManageDownMessageType;
|
||||
|
||||
/**
|
||||
* @brief Method string of down stream message. Order @see FileManageDownMessageType.
|
||||
*
|
||||
*/
|
||||
static const char *sg_file_manage_method_str[] = {
|
||||
"update_resource", // FILE_MANAGE_DOWN_MESSAGE_TYPE_UPDATE
|
||||
"del_resource", // FILE_MANAGE_DOWN_MESSAGE_TYPE_DEL
|
||||
"report_version_rsp", // FILE_MANAGE_DOWN_MESSAGE_TYPE_REPORT_VERSION_RESPONSE
|
||||
"request_url_resp", // FILE_MANAGE_DOWN_MESSAGE_TYPE_POST_REQUEST_RESPONSE
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Method string of down stream message. Order @see IotFileManageFileType.
|
||||
*
|
||||
*/
|
||||
static const char *sg_file_manage_file_type_str[] = {
|
||||
"FILE", // IOT_FILE_MANAGE_FILE_TYPE_FILE
|
||||
"AUDIO", // IOT_FILE_MANAGE_FILE_TYPE_AUDIO
|
||||
"VOICE", // IOT_FILE_MANAGE_FILE_TYPE_VOICE
|
||||
"VIDEO", // IOT_FILE_MANAGE_FILE_TYPE_VIDEO
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Handle file mange down stream message.
|
||||
*
|
||||
* @param[in] type @see FileManageDownMessageType
|
||||
* @param[in] message @see MQTTMessage
|
||||
* @param[in] callback @see IotFileManageCallback
|
||||
* @param[in,out] usr_data user define in IOT_FileManage_Init
|
||||
*/
|
||||
static void _parse_update_payload_and_callback(FileManageDownMessageType type, const MQTTMessage *message,
|
||||
const IotFileManageCallback *callback, void *usr_data)
|
||||
{
|
||||
int rc, result_code;
|
||||
uint32_t file_size = 0;
|
||||
UtilsJsonValue file_name, file_type, version, md5sum, url, value_result_code, file_token, file_list = {0};
|
||||
|
||||
// callback
|
||||
switch (type) {
|
||||
case FILE_MANAGE_DOWN_MESSAGE_TYPE_UPDATE:
|
||||
if (!callback->update_file_callback) {
|
||||
return;
|
||||
}
|
||||
rc = utils_json_value_get("resource_name", sizeof("resource_name") - 1, message->payload_str,
|
||||
message->payload_len, &file_name);
|
||||
rc |= utils_json_value_get("resource_type", sizeof("resource_type") - 1, message->payload_str,
|
||||
message->payload_len, &file_type);
|
||||
rc |= utils_json_value_get("version", sizeof("version") - 1, message->payload_str, message->payload_len,
|
||||
&version);
|
||||
rc |= utils_json_value_get("url", sizeof("url") - 1, message->payload_str, message->payload_len, &url);
|
||||
rc |= utils_json_value_get("md5sum", sizeof("md5sum") - 1, message->payload_str, message->payload_len,
|
||||
&md5sum);
|
||||
rc |= utils_json_get_uint32("file_size", sizeof("file_size") - 1, message->payload_str,
|
||||
message->payload_len, &file_size);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
callback->update_file_callback(file_name, file_type, version, url, md5sum, file_size, usr_data);
|
||||
break;
|
||||
case FILE_MANAGE_DOWN_MESSAGE_TYPE_DEL:
|
||||
if (!callback->del_file_callback) {
|
||||
return;
|
||||
}
|
||||
rc = utils_json_value_get("resource_name", sizeof("resource_name") - 1, message->payload_str,
|
||||
message->payload_len, &file_name);
|
||||
rc |= utils_json_value_get("resource_type", sizeof("resource_type") - 1, message->payload_str,
|
||||
message->payload_len, &file_type);
|
||||
rc |= utils_json_value_get("version", sizeof("version") - 1, message->payload_str, message->payload_len,
|
||||
&version);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
callback->del_file_callback(file_name, file_type, version, usr_data);
|
||||
break;
|
||||
case FILE_MANAGE_DOWN_MESSAGE_TYPE_REPORT_VERSION_RESPONSE:
|
||||
if (!callback->report_file_version_reponse_callback) {
|
||||
return;
|
||||
}
|
||||
// maybe no resource
|
||||
utils_json_value_get("resource_list", sizeof("resource_list") - 1, message->payload_str,
|
||||
message->payload_len, &file_list);
|
||||
rc = utils_json_value_get("result_code", sizeof("result_code") - 1, message->payload_str,
|
||||
message->payload_len, &value_result_code);
|
||||
rc |= utils_json_value_data_get(value_result_code, UTILS_JSON_VALUE_TYPE_INT32, &result_code);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
callback->report_file_version_reponse_callback(file_list, result_code, usr_data);
|
||||
break;
|
||||
case FILE_MANAGE_DOWN_MESSAGE_TYPE_POST_REQUEST_RESPONSE:
|
||||
if (!callback->request_file_url_response_callback) {
|
||||
return;
|
||||
}
|
||||
rc = utils_json_value_get("resource_url", sizeof("resource_url") - 1, message->payload_str,
|
||||
message->payload_len, &url);
|
||||
rc |= utils_json_value_get("resource_token", sizeof("resource_token") - 1, message->payload_str,
|
||||
message->payload_len, &file_token);
|
||||
rc |= utils_json_value_get("result_code", sizeof("result_code") - 1, message->payload_str,
|
||||
message->payload_len, &value_result_code);
|
||||
rc |= utils_json_value_data_get(value_result_code, UTILS_JSON_VALUE_TYPE_INT32, &result_code);
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
callback->request_file_url_response_callback(file_list, file_token, result_code, usr_data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
error:
|
||||
Log_e("invalid format of payload!");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mqtt message callback for file manage.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] message message from topic
|
||||
* @param[in,out] usr_data pointer to @see FileManageContext
|
||||
*/
|
||||
static void _file_manage_message_callback(void *client, const MQTTMessage *message, void *usr_data)
|
||||
{
|
||||
const char *file_manage_method_str[] = {
|
||||
"update_resource", // FILE_MANAGE_DOWN_MESSAGE_TYPE_UPDATE
|
||||
"del_resource", // FILE_MANAGE_DOWN_MESSAGE_TYPE_DEL
|
||||
"report_version_rsp", // FILE_MANAGE_DOWN_MESSAGE_TYPE_REPORT_VERSION_RESPONSE
|
||||
"request_url_resp", // FILE_MANAGE_DOWN_MESSAGE_TYPE_POST_REQUEST_RESPONSE
|
||||
};
|
||||
|
||||
int rc, i = 0;
|
||||
|
||||
FileManageContext *file_manage_context = (FileManageContext *)usr_data;
|
||||
UtilsJsonValue method;
|
||||
|
||||
Log_d("receive file manage message:%.*s", message->payload_len, message->payload_str);
|
||||
|
||||
rc = utils_json_value_get("method", sizeof("method") - 1, message->payload_str, message->payload_len, &method);
|
||||
if (rc) {
|
||||
Log_e("invalid file manage message!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = FILE_MANAGE_DOWN_MESSAGE_TYPE_UPDATE; i <= FILE_MANAGE_DOWN_MESSAGE_TYPE_POST_REQUEST_RESPONSE; i++) {
|
||||
if (!strncmp(method.value, file_manage_method_str[i], method.value_len)) {
|
||||
Log_d("callback file manage message!");
|
||||
_parse_update_payload_and_callback(i, message, &file_manage_context->callback,
|
||||
file_manage_context->usr_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief File manage init, register handler to server list.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] callback @see IotFileManageCallback
|
||||
* @param[in] usr_data usr data used in callback
|
||||
* @return 0 for success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_FileManage_Init(void *client, IotFileManageCallback callback, void *usr_data)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
|
||||
int rc = service_mqtt_init(client);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
FileManageContext *file_manage_context = (FileManageContext *)HAL_Malloc(sizeof(FileManageContext));
|
||||
if (!file_manage_context) {
|
||||
return QCLOUD_ERR_MALLOC;
|
||||
}
|
||||
file_manage_context->callback = callback;
|
||||
file_manage_context->usr_data = usr_data;
|
||||
|
||||
ServiceRegisterParams params = {
|
||||
.type = SERVICE_TYPE_FILE_MANAGE,
|
||||
.method_list = sg_file_manage_method_str,
|
||||
.method_num = sizeof(sg_file_manage_method_str) / sizeof(sg_file_manage_method_str[0]),
|
||||
.message_handle = _file_manage_message_callback,
|
||||
.usr_data = file_manage_context,
|
||||
.user_data_free = HAL_Free,
|
||||
};
|
||||
|
||||
rc = service_mqtt_service_register(client, ¶ms);
|
||||
if (rc) {
|
||||
HAL_Free(file_manage_context);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief File manage deinit, unregister handler from server list.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
*/
|
||||
void IOT_FileManage_Deinit(void *client)
|
||||
{
|
||||
POINTER_SANITY_CHECK_RTN(client);
|
||||
|
||||
service_mqtt_service_unregister(client, SERVICE_TYPE_FILE_MANAGE);
|
||||
service_mqtt_deinit(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report file manage message.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[out] buf publish message buffer
|
||||
* @param[in] buf_len buffer len
|
||||
* @param[in] report_type @see IotFileManageReportType
|
||||
* @param[in] progress progress using in IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOADING
|
||||
* @param[in] file_name_or_token token using in post event;file name using in other event
|
||||
* @param[in] version file version
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_FileManage_Report(void *client, char *buf, int buf_len, IotFileManageReportType report_type, int progress,
|
||||
const char *file_name_or_token, const char *version)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(buf_len, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(file_name_or_token, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(version, QCLOUD_ERR_INVAL);
|
||||
|
||||
/**
|
||||
* @brief order @see IotOTAReportType
|
||||
*
|
||||
*/
|
||||
const char *state_string[] = {
|
||||
"downloading", "burning", "done", "fail", "fail", "fail", "fail",
|
||||
"fail", "fail", "done", "fail", "done", "fail",
|
||||
};
|
||||
|
||||
int result_code[] = {0, 0, 0, -1, -2, -3, -4, -5, -6, 0, -7, 0, -8};
|
||||
|
||||
const char *result_msg[] = {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"timeout",
|
||||
"file not exit",
|
||||
"auth fail",
|
||||
"md5 not match",
|
||||
"upgrade fail",
|
||||
"space not enough",
|
||||
"",
|
||||
"del fail",
|
||||
"",
|
||||
"post fail",
|
||||
};
|
||||
|
||||
int len;
|
||||
switch (report_type) {
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOADING:
|
||||
len = HAL_Snprintf(
|
||||
buf, buf_len,
|
||||
"{\"method\":\"report_progress\",\"report\":{\"progress\":{\"resource_name\":\"%s\",\"state\":\"%s\","
|
||||
"\"percent\":\"%d\",\"result_code\":\"%d\",\"result_msg\":\"\"},\"version\":\"%s\"}}",
|
||||
file_name_or_token, state_string[report_type], progress, result_code[report_type], version);
|
||||
break;
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_BEGIN:
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_SUCCESS:
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOAD_TIMEOUT:
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_FILE_NOT_EXIST:
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_AUTH_FAIL:
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_MD5_NOT_MATCH:
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_FAIL:
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_SPACE_NOT_ENOUGH:
|
||||
len = HAL_Snprintf(buf, buf_len,
|
||||
"{\"method\":\"report_result\",\"report\":{\"progress\":{\"resource_name\":\"%s\","
|
||||
"\"state\":\"%s\",\"result_code\":\"%d\",\"result_msg\":\"%s\"},\"version\":\"%s\"}}",
|
||||
file_name_or_token, state_string[report_type], result_code[report_type],
|
||||
result_msg[report_type], version);
|
||||
break;
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_DEL_SUCCESS:
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_DEL_FAIL:
|
||||
len = HAL_Snprintf(buf, buf_len,
|
||||
"{\"method\":\"del_result\",\"report\":{\"progress\":{\"resource_name\":\"%s\","
|
||||
"\"state\":\"%s\",\"result_code\":\"%d\", \"result_msg\":\"%s\"}, \"version\":\"%s\"}}",
|
||||
file_name_or_token, state_string[report_type], result_code[report_type],
|
||||
result_msg[report_type], version);
|
||||
break;
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_POST_SUCCESS:
|
||||
case IOT_FILE_MANAGE_REPORT_TYPE_POST_FAIL:
|
||||
len = HAL_Snprintf(buf, buf_len,
|
||||
"{\"method\":\"report_post_result\",\"report\":{\"progress\":{\"resource_token\":\"%s\","
|
||||
"\"state\":\"%s\",\"result_code\":\"%d\", \"result_msg\":\"%s\"}}}",
|
||||
file_name_or_token, state_string[report_type], result_code[report_type],
|
||||
result_msg[report_type]);
|
||||
break;
|
||||
default:
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
return service_mqtt_publish(client, QOS0, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Report file list to server mqtt topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[out] buf publish message buffer
|
||||
* @param[in] buf_len buffer len
|
||||
* @param[in] file_list file list of @see IotFileManageFileInfo; file name which is "\0" means invalid.
|
||||
* @param[in] max_num max num of file list.
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_FileManage_ReportFileList(void *client, char *buf, int buf_len, const IotFileManageFileInfo file_list[],
|
||||
int max_num)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(buf_len, QCLOUD_ERR_INVAL);
|
||||
|
||||
int len = HAL_Snprintf(buf, buf_len, "{\"method\":\"report_version\",\"report\":{\"resource_list\":[");
|
||||
for (int i = 0; i < max_num; i++) {
|
||||
if (file_list[i].file_type == IOT_FILE_MANAGE_FILE_TYPE_UNKOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file_list[i].file_name[0] != '\0') {
|
||||
len += HAL_Snprintf(buf + len, buf_len - len,
|
||||
"{\"resource_name\":\"%s\",\"version\":\"%s\",\"resource_type\":\"%s\"},",
|
||||
file_list[i].file_name, file_list[i].file_version,
|
||||
sg_file_manage_file_type_str[file_list[i].file_type]);
|
||||
}
|
||||
}
|
||||
if (buf[len - 1] != '[') {
|
||||
len--; // remove the last ','
|
||||
}
|
||||
len += HAL_Snprintf(buf + len, buf_len - len, "]}}");
|
||||
return service_mqtt_publish(client, QOS0, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request url to upload.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[out] buf publish message buffer
|
||||
* @param[in] buf_len buffer len
|
||||
* @param[in] file_info file to upload, @see IotFileManageFileInfo
|
||||
* @param[in] request_id user defined, to keep unique.
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int IOT_FileManage_PostRequest(void *client, char *buf, int buf_len, const IotFileManageFileInfo *file_info,
|
||||
int request_id)
|
||||
{
|
||||
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(buf_len, QCLOUD_ERR_INVAL);
|
||||
POINTER_SANITY_CHECK(file_info, QCLOUD_ERR_INVAL);
|
||||
NUMBERIC_SANITY_CHECK(file_info->file_type, QCLOUD_ERR_INVAL);
|
||||
|
||||
int len = HAL_Snprintf(buf, buf_len,
|
||||
"{\"method\":\"request_url\",\"request_id\":\"%d\","
|
||||
"\"report\":{\"resource_name\":\"%s\",\"version\":\"%s\",\"resource_type\":\"%s\"}}",
|
||||
request_id, file_info->file_name, file_info->file_version,
|
||||
sg_file_manage_file_type_str[file_info->file_type]);
|
||||
return service_mqtt_publish(client, QOS0, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get file type according to string. @see sg_file_manage_file_type_str.
|
||||
*
|
||||
* @param[in] file_type file type string
|
||||
* @param[in] len string length
|
||||
* @return @see IotFileManageFileType
|
||||
*/
|
||||
IotFileManageFileType IOT_FileManage_GetFileType(const char *file_type, int len)
|
||||
{
|
||||
for (int i = 0; i < sizeof(sg_file_manage_file_type_str) / sizeof(sg_file_manage_file_type_str[0]); i++) {
|
||||
if (len != strlen(sg_file_manage_file_type_str[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(file_type, sg_file_manage_file_type_str[i], len)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return IOT_FILE_MANAGE_FILE_TYPE_UNKOWN;
|
||||
}
|
@@ -0,0 +1,364 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2022 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.
|
||||
*
|
||||
* @file sevice_mqtt.c
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2022-01-11
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-01-11 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "service_mqtt.h"
|
||||
|
||||
/**
|
||||
* @brief Direction(upstream/downstream) for topic.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
SERVICE_TOPIC_DIRECTION_UP = 0,
|
||||
SERVICE_TOPIC_DIRECTION_DOWN,
|
||||
} ServiceTopicDirection;
|
||||
|
||||
/**
|
||||
* @brief Context of service mqtt, callback and user data.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
void *service_list;
|
||||
void *usr_data;
|
||||
} ServiceMqttContext;
|
||||
|
||||
/**
|
||||
* @brief Service list conext.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
const char *method;
|
||||
int method_len;
|
||||
const MQTTMessage *message;
|
||||
} ServiceListContext;
|
||||
|
||||
/**
|
||||
* @brief Generate topic string.
|
||||
*
|
||||
* @param[out] buf buffer for topic name
|
||||
* @param[in] buf_len buffer length
|
||||
* @param[in] direction @see ServiceTopicDirection
|
||||
* @param[in] product_id product id of device
|
||||
* @param[in] device_name device name of device
|
||||
* @return > 0 for length of topic name, others for fail.
|
||||
*/
|
||||
static int _service_mqtt_topic_generate(char *buf, int buf_len, ServiceTopicDirection direction, const char *product_id,
|
||||
const char *device_name)
|
||||
{
|
||||
return HAL_Snprintf(buf, buf_len, "$thing/%s/service/%s/%s", direction ? "down" : "up",
|
||||
STRING_PTR_PRINT_SANITY_CHECK(product_id), STRING_PTR_PRINT_SANITY_CHECK(device_name));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// server mqtt context
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Malloc service context and service list.
|
||||
*
|
||||
* @return @see ServiceMqttContext
|
||||
*/
|
||||
static ServiceMqttContext *_service_mqtt_context_malloc(void)
|
||||
{
|
||||
ServiceMqttContext *context = (ServiceMqttContext *)HAL_Malloc(sizeof(ServiceMqttContext));
|
||||
if (!context) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UtilsListFunc func = {
|
||||
.list_malloc = HAL_Malloc,
|
||||
.list_free = HAL_Free,
|
||||
.list_lock_init = HAL_MutexCreate,
|
||||
.list_lock = HAL_MutexLock,
|
||||
.list_unlock = HAL_MutexUnlock,
|
||||
.list_lock_deinit = HAL_MutexDestroy,
|
||||
};
|
||||
context->service_list = utils_list_create(func, 10);
|
||||
if (!context->service_list) {
|
||||
HAL_Free(context);
|
||||
context = NULL;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free service context and service list.
|
||||
*
|
||||
* @param usr_data @see ServiceMqttContext
|
||||
*/
|
||||
static void _service_mqtt_context_free(void *usr_data)
|
||||
{
|
||||
ServiceMqttContext *context = (ServiceMqttContext *)usr_data;
|
||||
utils_list_destroy(context->service_list);
|
||||
HAL_Free(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get service mqtt context from client.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @return @see ServiceMqttContext
|
||||
*/
|
||||
static ServiceMqttContext *_service_mqtt_context_get(void *client)
|
||||
{
|
||||
char service_mqtt_topic[MAX_SIZE_OF_CLOUD_TOPIC];
|
||||
_service_mqtt_topic_generate(service_mqtt_topic, MAX_SIZE_OF_CLOUD_TOPIC, SERVICE_TOPIC_DIRECTION_DOWN,
|
||||
IOT_MQTT_GetDeviceInfo(client)->product_id,
|
||||
IOT_MQTT_GetDeviceInfo(client)->device_name);
|
||||
return (ServiceMqttContext *)IOT_MQTT_GetSubUsrData(client, service_mqtt_topic);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// server list
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Unregister server from server list.
|
||||
*
|
||||
* @param[in] list pointer to server list
|
||||
* @param[in] node pointer tot server list node
|
||||
* @param[in] val @see ServiceRegisterParams
|
||||
* @param[in] usr_data @see ServiceType
|
||||
* @return @see UtilsListResult
|
||||
*/
|
||||
static UtilsListResult _server_list_unregister_callback(void *list, void *node, void *val, void *usr_data)
|
||||
{
|
||||
ServiceRegisterParams *params = (ServiceRegisterParams *)val;
|
||||
|
||||
ServiceType type = *(ServiceType *)usr_data;
|
||||
if (params->type == type) {
|
||||
if (params->user_data_free) {
|
||||
params->user_data_free(params->usr_data);
|
||||
}
|
||||
utils_list_remove(list, node);
|
||||
return LIST_TRAVERSE_BREAK;
|
||||
}
|
||||
return LIST_TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback server handler from server list.
|
||||
*
|
||||
* @param[in] list pointer to server list
|
||||
* @param[in] node pointer tot server list node
|
||||
* @param[in] val @see ServiceRegisterParams
|
||||
* @param[in] usr_data @see ServiceListContext
|
||||
* @return @see UtilsListResult
|
||||
*/
|
||||
static UtilsListResult _server_list_process_message_callback(void *list, void *node, void *val, void *usr_data)
|
||||
{
|
||||
ServiceRegisterParams *params = (ServiceRegisterParams *)val;
|
||||
ServiceListContext *context = (ServiceListContext *)usr_data;
|
||||
|
||||
for (int i = 0; i < params->method_num; i++) {
|
||||
int len = strlen(params->method_list[i]);
|
||||
if (len == context->method_len && !strncmp(context->method, params->method_list[i], len)) {
|
||||
params->message_handle(usr_data, context->message, params->usr_data);
|
||||
return LIST_TRAVERSE_BREAK;
|
||||
}
|
||||
}
|
||||
return LIST_TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// mqtt
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Handle server mqtt topic down stream message.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] message @see MQTTMessage
|
||||
* @param[in] usr_data @see ServiceMqttContext
|
||||
*/
|
||||
static void _service_mqtt_message_handle(void *client, const MQTTMessage *message, void *usr_data)
|
||||
{
|
||||
Log_d("receive service message:%.*s", message->payload_len, message->payload_str);
|
||||
|
||||
UtilsJsonValue method;
|
||||
|
||||
int rc = utils_json_value_get("method", sizeof("method") - 1, message->payload_str, message->payload_len, &method);
|
||||
if (rc) {
|
||||
return;
|
||||
}
|
||||
|
||||
// process list
|
||||
ServiceListContext server_list_context = {
|
||||
.method = method.value,
|
||||
.method_len = method.value_len,
|
||||
.message = message,
|
||||
};
|
||||
void *list = ((ServiceMqttContext *)usr_data)->service_list;
|
||||
utils_list_process(list, LIST_HEAD, _server_list_process_message_callback, &server_list_context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if topic already subscribed, if not then subscribe.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int _service_mqtt_topic_check_and_sub(void *client)
|
||||
{
|
||||
char service_mqtt_topic[MAX_SIZE_OF_CLOUD_TOPIC];
|
||||
_service_mqtt_topic_generate(service_mqtt_topic, MAX_SIZE_OF_CLOUD_TOPIC, SERVICE_TOPIC_DIRECTION_DOWN,
|
||||
IOT_MQTT_GetDeviceInfo(client)->product_id,
|
||||
IOT_MQTT_GetDeviceInfo(client)->device_name);
|
||||
|
||||
int rc = 0;
|
||||
|
||||
ServiceMqttContext *context = _service_mqtt_context_malloc();
|
||||
if (!context) {
|
||||
return QCLOUD_ERR_MALLOC;
|
||||
}
|
||||
|
||||
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
|
||||
sub_params.on_message_handler = _service_mqtt_message_handle;
|
||||
sub_params.qos = QOS1;
|
||||
sub_params.user_data = context;
|
||||
sub_params.user_data_free = _service_mqtt_context_free;
|
||||
|
||||
rc = IOT_MQTT_SubscribeSync(client, service_mqtt_topic, &sub_params);
|
||||
if (rc) {
|
||||
_service_mqtt_context_free(context);
|
||||
Log_e("subscribe topic %s failed!", service_mqtt_topic);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe service mqtt topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int _service_mqtt_unsubscribe(void *client)
|
||||
{
|
||||
char service_mqtt_topic[MAX_SIZE_OF_CLOUD_TOPIC];
|
||||
_service_mqtt_topic_generate(service_mqtt_topic, MAX_SIZE_OF_CLOUD_TOPIC, SERVICE_TOPIC_DIRECTION_DOWN,
|
||||
IOT_MQTT_GetDeviceInfo(client)->product_id,
|
||||
IOT_MQTT_GetDeviceInfo(client)->device_name);
|
||||
return IOT_MQTT_Unsubscribe(client, service_mqtt_topic);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// api
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Subscribe service mqtt.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int service_mqtt_init(void *client)
|
||||
{
|
||||
return _service_mqtt_topic_check_and_sub(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If no service in the service list, then unsubscribe.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
*/
|
||||
void service_mqtt_deinit(void *client)
|
||||
{
|
||||
ServiceMqttContext *context = _service_mqtt_context_get(client);
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!utils_list_len_get(context->service_list)) {
|
||||
_service_mqtt_unsubscribe(client);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Publish to service mqtt topic.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] qos @see QoS
|
||||
* @param[in] payload payload of mqtt packet
|
||||
* @param[in] payload_len payload len
|
||||
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
|
||||
*/
|
||||
int service_mqtt_publish(void *client, QoS qos, const char *payload, int payload_len)
|
||||
{
|
||||
char service_mqtt_topic[MAX_SIZE_OF_CLOUD_TOPIC];
|
||||
_service_mqtt_topic_generate(service_mqtt_topic, MAX_SIZE_OF_CLOUD_TOPIC, SERVICE_TOPIC_DIRECTION_UP,
|
||||
IOT_MQTT_GetDeviceInfo(client)->product_id,
|
||||
IOT_MQTT_GetDeviceInfo(client)->device_name);
|
||||
|
||||
PublishParams pub_params = DEFAULT_PUB_PARAMS;
|
||||
pub_params.qos = qos;
|
||||
pub_params.payload = (void *)payload;
|
||||
pub_params.payload_len = payload_len;
|
||||
return IOT_MQTT_Publish(client, service_mqtt_topic, &pub_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Register server handler to server list.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] params @see ServiceRegisterParams
|
||||
* @return @see IotReturnCode
|
||||
*/
|
||||
int service_mqtt_service_register(void *client, const ServiceRegisterParams *params)
|
||||
{
|
||||
ServiceMqttContext *context = _service_mqtt_context_get(client);
|
||||
if (!context) {
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
ServiceRegisterParams *register_params = (ServiceRegisterParams *)HAL_Malloc(sizeof(ServiceRegisterParams));
|
||||
if (!register_params) {
|
||||
return QCLOUD_ERR_MALLOC;
|
||||
}
|
||||
memcpy(register_params, params, sizeof(ServiceRegisterParams));
|
||||
|
||||
void *node = utils_list_push(context->service_list, register_params);
|
||||
if (!node) {
|
||||
HAL_Free(register_params);
|
||||
return QCLOUD_ERR_MALLOC;
|
||||
}
|
||||
return QCLOUD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unregister server handler from server list.
|
||||
*
|
||||
* @param[in,out] client pointer to mqtt client
|
||||
* @param[in] type @see ServiceType
|
||||
*/
|
||||
void service_mqtt_service_unregister(void *client, ServiceType type)
|
||||
{
|
||||
ServiceMqttContext *context = _service_mqtt_context_get(client);
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
utils_list_process(context->service_list, LIST_HEAD, _server_list_unregister_callback, &type);
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 120
|
||||
DerivePointerAlignment: true
|
||||
PointerAlignment: Left
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Preserve
|
||||
IndentPPDirectives: AfterHash
|
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2022 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.
|
||||
*
|
||||
* @file test_ota_mqtt.cc
|
||||
* @brief
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2022-01-18
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-01-18 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "mqtt_client_test.h"
|
||||
#include "qcloud_iot_explorer.h"
|
||||
|
||||
namespace mqtt_client_unittest {
|
||||
|
||||
static void _file_manage_update_file_callback(UtilsJsonValue file_name, UtilsJsonValue file_type,
|
||||
UtilsJsonValue version, UtilsJsonValue url, UtilsJsonValue md5sum,
|
||||
uint32_t file_size, void *usr_data) {
|
||||
Log_i("recv update file: file_name=%.*s|type=%.*s|version=%.*s|url=%.*s|md5sum=%.*s|file_size=%u",
|
||||
file_name.value_len, file_name.value, file_type.value_len, file_type.value, version.value_len, version.value,
|
||||
url.value_len, url.value, md5sum.value_len, md5sum.value, file_size);
|
||||
}
|
||||
|
||||
static void _file_manage_del_file_callback(UtilsJsonValue file_name, UtilsJsonValue file_type, UtilsJsonValue version,
|
||||
void *usr_data) {
|
||||
Log_i("recv del file: file_name=%.*s|type=%.*s|version=%.*s|", file_name.value_len, file_name.value,
|
||||
file_type.value_len, file_type.value, version.value_len, version.value);
|
||||
}
|
||||
|
||||
static void _file_manage_report_file_version_reponse_callback(UtilsJsonValue file_list, int result_code,
|
||||
void *usr_data) {
|
||||
Log_i("recv file version: file_list=%.*s|result_code=%d", file_list, result_code);
|
||||
}
|
||||
|
||||
static void _file_manage_request_file_url_response_callback(UtilsJsonValue url, UtilsJsonValue file_token,
|
||||
int result_code, void *usr_data) {
|
||||
Log_i("recv request response: url=%.*s|file_token=%.*s|result_code=%d", url.value_len, url.value,
|
||||
file_token.value_len, file_token.value, result_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test file manage.
|
||||
*
|
||||
*/
|
||||
TEST_F(MqttClientTest, file_manage) {
|
||||
char buf[256];
|
||||
int buf_len = sizeof(buf);
|
||||
|
||||
IotFileManageFileInfo file_info = {0};
|
||||
|
||||
const char *file_name = "test.txt";
|
||||
const char *version = "1.0.0";
|
||||
|
||||
strncpy(file_info.file_name, file_name, strlen(file_name));
|
||||
strncpy(file_info.file_version, version, strlen(version));
|
||||
file_info.file_type = IOT_FILE_MANAGE_FILE_TYPE_FILE;
|
||||
|
||||
IotFileManageCallback file_manage_callback = {
|
||||
.update_file_callback = _file_manage_update_file_callback,
|
||||
.del_file_callback = _file_manage_del_file_callback,
|
||||
.report_file_version_reponse_callback = _file_manage_report_file_version_reponse_callback,
|
||||
.request_file_url_response_callback = _file_manage_request_file_url_response_callback,
|
||||
};
|
||||
|
||||
ASSERT_EQ(IOT_FileManage_Init(client, file_manage_callback, client), 0);
|
||||
ASSERT_GE(IOT_FileManage_ReportFileList(client, buf, buf_len, NULL, 0), 0);
|
||||
ASSERT_GE(IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOADING, 0, file_name, version),
|
||||
0);
|
||||
ASSERT_GE(
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_BEGIN, 100, file_name, version),
|
||||
0);
|
||||
ASSERT_GE(
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_SUCCESS, 0, file_name, version),
|
||||
0);
|
||||
ASSERT_GE(
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOAD_TIMEOUT, 0, file_name, version),
|
||||
0);
|
||||
ASSERT_GE(
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_FILE_NOT_EXIST, 0, file_name, version),
|
||||
0);
|
||||
ASSERT_GE(IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_AUTH_FAIL, 0, file_name, version),
|
||||
0);
|
||||
ASSERT_GE(
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_MD5_NOT_MATCH, 0, file_name, version), 0);
|
||||
ASSERT_GE(
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_FAIL, 0, file_name, version), 0);
|
||||
ASSERT_GE(
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_SPACE_NOT_ENOUGH, 0, file_name, version),
|
||||
0);
|
||||
ASSERT_GE(IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_DEL_SUCCESS, 0, file_name, version),
|
||||
0);
|
||||
ASSERT_GE(IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_DEL_FAIL, 0, file_name, version),
|
||||
0);
|
||||
ASSERT_GE(IOT_FileManage_PostRequest(client, buf, buf_len, &file_info, 0), 0);
|
||||
ASSERT_EQ(IOT_MQTT_Yield(client, QCLOUD_IOT_MQTT_YIELD_TIMEOUT), 0);
|
||||
ASSERT_GE(
|
||||
IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_POST_SUCCESS, 0, file_name, version), 0);
|
||||
ASSERT_GE(IOT_FileManage_Report(client, buf, buf_len, IOT_FILE_MANAGE_REPORT_TYPE_POST_FAIL, 0, file_name, version),
|
||||
0);
|
||||
|
||||
ASSERT_EQ(IOT_FileManage_GetFileType("FILE", sizeof("FILE") - 1), IOT_FILE_MANAGE_FILE_TYPE_FILE);
|
||||
ASSERT_EQ(IOT_FileManage_GetFileType("AUDIO", sizeof("AUDIO") - 1), IOT_FILE_MANAGE_FILE_TYPE_AUDIO);
|
||||
ASSERT_EQ(IOT_FileManage_GetFileType("VOICE", sizeof("VOICE") - 1), IOT_FILE_MANAGE_FILE_TYPE_VOICE);
|
||||
ASSERT_EQ(IOT_FileManage_GetFileType("VIDEO", sizeof("VIDEO") - 1), IOT_FILE_MANAGE_FILE_TYPE_VIDEO);
|
||||
ASSERT_EQ(IOT_FileManage_GetFileType("TEXT", sizeof("TEXT") - 1), IOT_FILE_MANAGE_FILE_TYPE_UNKOWN);
|
||||
|
||||
IOT_FileManage_Deinit(client);
|
||||
}
|
||||
|
||||
} // namespace mqtt_client_unittest
|
Reference in New Issue
Block a user