mirror of
https://gitee.com/beecue/fastbee.git
synced 2025-12-21 10:25:54 +08:00
更新硬件SDK
This commit is contained in:
2
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/data-model/README.md
vendored
Normal file
2
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/data-model/README.md
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Name: 物模型模块
|
||||
Data-Model Component for Link SDK V4.0.0
|
||||
834
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/data-model/aiot_dm_api.c
vendored
Normal file
834
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/data-model/aiot_dm_api.c
vendored
Normal file
@@ -0,0 +1,834 @@
|
||||
/**
|
||||
* @file aiot_dm_api.c
|
||||
* @brief 数据模型模块接口实现文件, 包含了支持物模型数据格式通信的所有接口实现
|
||||
* @date 2020-01-20
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dm_private.h"
|
||||
|
||||
|
||||
static int32_t _dm_send_property_post(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
static int32_t _dm_send_event_post(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
static int32_t _dm_send_property_set_reply(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
static int32_t _dm_send_async_service_reply(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
static int32_t _dm_send_sync_service_reply(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
static int32_t _dm_send_raw_data(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
static int32_t _dm_send_raw_service_reply(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
static int32_t _dm_send_desired_get(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
static int32_t _dm_send_desired_delete(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
static int32_t _dm_send_property_batch_post(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
|
||||
static void _dm_recv_generic_reply_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
static void _dm_recv_property_set_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
static void _dm_recv_async_service_invoke_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
static void _dm_recv_sync_service_invoke_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
static void _dm_recv_raw_data_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
static void _dm_recv_raw_sync_service_invoke_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
static void _dm_recv_up_raw_reply_data_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
|
||||
static const dm_send_topic_map_t g_dm_send_topic_mapping[AIOT_DMMSG_MAX] = {
|
||||
{
|
||||
"/sys/%s/%s/thing/event/property/post",
|
||||
_dm_send_property_post
|
||||
},
|
||||
{
|
||||
"/sys/%s/%s/thing/event/%s/post",
|
||||
_dm_send_event_post
|
||||
},
|
||||
{
|
||||
"/sys/%s/%s/thing/service/property/set_reply",
|
||||
_dm_send_property_set_reply
|
||||
},
|
||||
{
|
||||
"/sys/%s/%s/thing/service/%s_reply",
|
||||
_dm_send_async_service_reply
|
||||
},
|
||||
{
|
||||
"/ext/rrpc/%s/sys/%s/%s/thing/service/%s",
|
||||
_dm_send_sync_service_reply
|
||||
},
|
||||
{
|
||||
"/sys/%s/%s/thing/model/up_raw",
|
||||
_dm_send_raw_data
|
||||
},
|
||||
{
|
||||
"/ext/rrpc/%s/sys/%s/%s/thing/model/down_raw",
|
||||
_dm_send_raw_service_reply
|
||||
},
|
||||
{
|
||||
"/sys/%s/%s/thing/property/desired/get",
|
||||
_dm_send_desired_get
|
||||
},
|
||||
{
|
||||
"/sys/%s/%s/thing/property/desired/delete",
|
||||
_dm_send_desired_delete
|
||||
},
|
||||
{
|
||||
"/sys/%s/%s/thing/event/property/batch/post",
|
||||
_dm_send_property_batch_post
|
||||
},
|
||||
};
|
||||
|
||||
static const dm_recv_topic_map_t g_dm_recv_topic_mapping[] = {
|
||||
{
|
||||
"/sys/+/+/thing/event/+/post_reply",
|
||||
_dm_recv_generic_reply_handler,
|
||||
},
|
||||
{
|
||||
"/sys/+/+/thing/service/property/set",
|
||||
_dm_recv_property_set_handler,
|
||||
},
|
||||
{
|
||||
"/sys/+/+/thing/service/+",
|
||||
_dm_recv_async_service_invoke_handler,
|
||||
},
|
||||
{
|
||||
"/ext/rrpc/+/sys/+/+/thing/service/+",
|
||||
_dm_recv_sync_service_invoke_handler,
|
||||
},
|
||||
{
|
||||
"/sys/+/+/thing/model/down_raw",
|
||||
_dm_recv_raw_data_handler,
|
||||
},
|
||||
{
|
||||
"/sys/+/+/thing/model/up_raw_reply",
|
||||
_dm_recv_up_raw_reply_data_handler,
|
||||
},
|
||||
{
|
||||
"/ext/rrpc/+/sys/+/+/thing/model/down_raw",
|
||||
_dm_recv_raw_sync_service_invoke_handler,
|
||||
},
|
||||
{
|
||||
"/sys/+/+/thing/property/desired/get_reply",
|
||||
_dm_recv_generic_reply_handler,
|
||||
},
|
||||
{
|
||||
"/sys/+/+/thing/property/desired/delete_reply",
|
||||
_dm_recv_generic_reply_handler,
|
||||
},
|
||||
{
|
||||
"/sys/+/+/thing/event/property/batch/post_reply",
|
||||
_dm_recv_generic_reply_handler,
|
||||
},
|
||||
};
|
||||
|
||||
static void _append_diag_data(dm_handle_t *dm_handle, uint8_t msg_type, int32_t msg_id)
|
||||
{
|
||||
/* append diagnose data */
|
||||
uint8_t diag_data[] = { 0x00, 0x30, 0x01, 0x00, 0x00, 0x31, 0x04, 0x00, 0x00, 0x00, 0x00 };
|
||||
diag_data[3] = msg_type;
|
||||
diag_data[7] = (msg_id >> 24) & 0xFF;
|
||||
diag_data[8] = (msg_id >> 16) & 0xFF;
|
||||
diag_data[9] = (msg_id >> 8) & 0xFF;
|
||||
diag_data[10] = msg_id & 0xFF;
|
||||
core_diag(dm_handle->sysdep, STATE_DM_BASE, diag_data, sizeof(diag_data));
|
||||
}
|
||||
|
||||
static int32_t _dm_setup_topic_mapping(void *mqtt_handle, void *dm_handle)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
for (i = 0; i < sizeof(g_dm_recv_topic_mapping) / sizeof(dm_recv_topic_map_t); i++) {
|
||||
aiot_mqtt_topic_map_t topic_mapping;
|
||||
topic_mapping.topic = g_dm_recv_topic_mapping[i].topic;
|
||||
topic_mapping.handler = g_dm_recv_topic_mapping[i].func;
|
||||
topic_mapping.userdata = dm_handle;
|
||||
|
||||
res = aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_APPEND_TOPIC_MAP, &topic_mapping);
|
||||
if (res < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t _dm_prepare_send_topic(dm_handle_t *dm_handle, const aiot_dm_msg_t *msg, char **topic)
|
||||
{
|
||||
char *src[4];
|
||||
uint8_t src_count = 0;
|
||||
char *pk = NULL;
|
||||
char *dn = NULL;
|
||||
|
||||
if (NULL == msg->product_key && NULL == core_mqtt_get_product_key(dm_handle->mqtt_handle)) {
|
||||
return STATE_USER_INPUT_MISSING_PRODUCT_KEY;
|
||||
}
|
||||
if (NULL == msg->device_name && NULL == core_mqtt_get_device_name(dm_handle->mqtt_handle)) {
|
||||
return STATE_USER_INPUT_MISSING_DEVICE_NAME;
|
||||
}
|
||||
|
||||
pk = (msg->product_key != NULL) ? msg->product_key : core_mqtt_get_product_key(dm_handle->mqtt_handle);
|
||||
dn = (msg->device_name != NULL) ? msg->device_name : core_mqtt_get_device_name(dm_handle->mqtt_handle);
|
||||
|
||||
switch (msg->type) {
|
||||
case AIOT_DMMSG_PROPERTY_POST:
|
||||
case AIOT_DMMSG_PROPERTY_BATCH_POST:
|
||||
case AIOT_DMMSG_PROPERTY_SET_REPLY:
|
||||
case AIOT_DMMSG_GET_DESIRED:
|
||||
case AIOT_DMMSG_DELETE_DESIRED:
|
||||
case AIOT_DMMSG_RAW_DATA: {
|
||||
src[0] = pk;
|
||||
src[1] = dn;
|
||||
src_count = 2;
|
||||
}
|
||||
break;
|
||||
case AIOT_DMMSG_EVENT_POST: {
|
||||
if (msg->data.event_post.event_id == NULL) {
|
||||
return STATE_DM_EVENT_ID_IS_NULL;
|
||||
}
|
||||
src[0] = pk;
|
||||
src[1] = dn;
|
||||
src[2] = msg->data.event_post.event_id;
|
||||
src_count = 3;
|
||||
}
|
||||
break;
|
||||
case AIOT_DMMSG_ASYNC_SERVICE_REPLY: {
|
||||
if (msg->data.async_service_reply.service_id == NULL) {
|
||||
return STATE_DM_SERVICE_ID_IS_NULL;
|
||||
}
|
||||
src[0] = pk;
|
||||
src[1] = dn;
|
||||
src[2] = msg->data.async_service_reply.service_id;
|
||||
src_count = 3;
|
||||
}
|
||||
break;
|
||||
case AIOT_DMMSG_SYNC_SERVICE_REPLY: {
|
||||
if (msg->data.sync_service_reply.rrpc_id == NULL) {
|
||||
return STATE_DM_RRPC_ID_IS_NULL;
|
||||
}
|
||||
if (msg->data.sync_service_reply.service_id == NULL) {
|
||||
return STATE_DM_SERVICE_ID_IS_NULL;
|
||||
}
|
||||
src[0] = msg->data.sync_service_reply.rrpc_id;
|
||||
src[1] = pk;
|
||||
src[2] = dn;
|
||||
src[3] = msg->data.sync_service_reply.service_id;
|
||||
src_count = 4;
|
||||
}
|
||||
break;
|
||||
case AIOT_DMMSG_RAW_SERVICE_REPLY: {
|
||||
if (msg->data.raw_service_reply.rrpc_id == NULL) {
|
||||
return STATE_DM_RRPC_ID_IS_NULL;
|
||||
}
|
||||
src[0] = msg->data.raw_service_reply.rrpc_id;
|
||||
src[1] = pk;
|
||||
src[2] = dn;
|
||||
src_count = 3;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
return core_sprintf(dm_handle->sysdep, topic, g_dm_send_topic_mapping[msg->type].topic, src, src_count,
|
||||
DATA_MODEL_MODULE_NAME);
|
||||
}
|
||||
|
||||
|
||||
static int32_t _dm_send_alink_req(dm_handle_t *handle, const char *topic, char *params)
|
||||
{
|
||||
char *payload = NULL;
|
||||
int32_t id = 0;
|
||||
char id_string[11] = { 0 };
|
||||
char *src[3] = { NULL };
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == params) {
|
||||
return STATE_DM_MSG_PARAMS_IS_NULL;
|
||||
}
|
||||
|
||||
core_global_alink_id_next(handle->sysdep, &id);
|
||||
core_int2str(id, id_string, NULL);
|
||||
|
||||
_append_diag_data(handle, DM_DIAG_MSG_TYPE_REQ, id);
|
||||
|
||||
src[0] = id_string;
|
||||
src[1] = params;
|
||||
src[2] = (0 == handle->post_reply) ? "0" : "1";
|
||||
|
||||
res = core_sprintf(handle->sysdep, &payload, ALINK_REQUEST_FMT, src, sizeof(src) / sizeof(char *),
|
||||
DATA_MODEL_MODULE_NAME);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(handle->mqtt_handle, (char *)topic, (uint8_t *)payload, strlen(payload), 0);
|
||||
handle->sysdep->core_sysdep_free(payload);
|
||||
|
||||
if (STATE_SUCCESS == res) {
|
||||
return id;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t _dm_send_alink_rsp(dm_handle_t *handle, const char *topic, uint64_t msg_id, uint32_t code,
|
||||
char *data)
|
||||
{
|
||||
char *payload = NULL;
|
||||
char id_string[21] = { 0 };
|
||||
char code_string[11] = { 0 };
|
||||
char *src[3] = { NULL };
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == data) {
|
||||
return STATE_DM_MSG_DATA_IS_NULL;
|
||||
}
|
||||
|
||||
core_uint642str(msg_id, id_string, NULL);
|
||||
core_uint2str(code, code_string, NULL);
|
||||
|
||||
src[0] = id_string;
|
||||
src[1] = code_string;
|
||||
src[2] = data;
|
||||
|
||||
res = core_sprintf(handle->sysdep, &payload, ALINK_RESPONSE_FMT, src, sizeof(src) / sizeof(char *),
|
||||
DATA_MODEL_MODULE_NAME);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(handle->mqtt_handle, (char *)topic, (uint8_t *)payload, strlen(payload), 0);
|
||||
handle->sysdep->core_sysdep_free(payload);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*** dm send function start ***/
|
||||
static int32_t _dm_send_property_post(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
return _dm_send_alink_req(handle, topic, msg->data.property_post.params);
|
||||
}
|
||||
|
||||
static int32_t _dm_send_event_post(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
return _dm_send_alink_req(handle, topic, msg->data.event_post.params);
|
||||
}
|
||||
|
||||
static int32_t _dm_send_property_set_reply(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
return _dm_send_alink_rsp(handle, topic, msg->data.property_set_reply.msg_id,
|
||||
msg->data.property_set_reply.code,
|
||||
msg->data.property_set_reply.data);
|
||||
}
|
||||
|
||||
static int32_t _dm_send_async_service_reply(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
return _dm_send_alink_rsp(handle, topic, msg->data.async_service_reply.msg_id,
|
||||
msg->data.async_service_reply.code,
|
||||
msg->data.async_service_reply.data);
|
||||
}
|
||||
|
||||
static int32_t _dm_send_sync_service_reply(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
return _dm_send_alink_rsp(handle, topic, msg->data.sync_service_reply.msg_id,
|
||||
msg->data.sync_service_reply.code,
|
||||
msg->data.sync_service_reply.data);
|
||||
}
|
||||
|
||||
static int32_t _dm_send_raw_data(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
return aiot_mqtt_pub(handle->mqtt_handle, (char *)topic, msg->data.raw_data.data, msg->data.raw_data.data_len, 0);
|
||||
}
|
||||
|
||||
static int32_t _dm_send_raw_service_reply(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
return aiot_mqtt_pub(handle->mqtt_handle, (char *)topic, msg->data.raw_service_reply.data,
|
||||
msg->data.raw_service_reply.data_len, 0);
|
||||
}
|
||||
|
||||
static int32_t _dm_send_desired_get(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
return _dm_send_alink_req(handle, topic, msg->data.get_desired.params);
|
||||
}
|
||||
|
||||
static int32_t _dm_send_desired_delete(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
return _dm_send_alink_req(handle, topic, msg->data.delete_desired.params);
|
||||
}
|
||||
|
||||
static int32_t _dm_send_property_batch_post(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
return _dm_send_alink_req(handle, topic, msg->data.property_post.params);
|
||||
}
|
||||
/*** dm send function end ***/
|
||||
|
||||
/*** dm recv handler functions start ***/
|
||||
static int32_t _dm_get_topic_level(aiot_sysdep_portfile_t *sysdep, char *topic, uint32_t topic_len, uint8_t level,
|
||||
char **level_name)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint16_t level_curr = 0;
|
||||
char *p_open = NULL;
|
||||
char *p_close = NULL;
|
||||
char *p_name = NULL;
|
||||
uint16_t name_len = 0;
|
||||
|
||||
for (i = 0; i < (topic_len - 1); i++) {
|
||||
if (topic[i] == '/') {
|
||||
level_curr++;
|
||||
if (level_curr == level && p_open == NULL) {
|
||||
p_open = topic + i + 1;
|
||||
}
|
||||
|
||||
if (level_curr == (level + 1) && p_close == NULL) {
|
||||
p_close = topic + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p_open == NULL) {
|
||||
return STATE_DM_INTERNAL_TOPIC_ERROR;
|
||||
}
|
||||
if (p_close == NULL) {
|
||||
p_close = topic + topic_len;
|
||||
}
|
||||
|
||||
name_len = p_close - p_open;
|
||||
p_name = sysdep->core_sysdep_malloc(name_len + 1, DATA_MODEL_MODULE_NAME);
|
||||
if (p_name == NULL) {
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
memset(p_name, 0, name_len + 1);
|
||||
memcpy(p_name, p_open, name_len);
|
||||
*level_name = p_name;
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t _dm_parse_alink_request(const char *payload, uint32_t payload_len, uint64_t *msg_id, char **params,
|
||||
uint32_t *params_len)
|
||||
{
|
||||
char *value = NULL;
|
||||
uint32_t value_len = 0;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if ((res = core_json_value((char *)payload, payload_len, ALINK_JSON_KEY_ID, strlen(ALINK_JSON_KEY_ID),
|
||||
&value, &value_len)) < 0 ||
|
||||
((res = core_str2uint64(value, value_len, msg_id)) < 0)) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if ((res = core_json_value((char *)payload, payload_len, ALINK_JSON_KEY_PARAMS, strlen(ALINK_JSON_KEY_PARAMS),
|
||||
&value, &value_len)) < 0) {
|
||||
return res;
|
||||
}
|
||||
*params = value;
|
||||
*params_len = value_len;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _dm_recv_generic_reply_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
dm_handle_t *dm_handle = (dm_handle_t *)userdata;
|
||||
aiot_dm_recv_t recv;
|
||||
char *value = NULL;
|
||||
uint32_t value_len = 0;
|
||||
|
||||
if (NULL == dm_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* construct recv message */
|
||||
memset(&recv, 0, sizeof(aiot_dm_recv_t));
|
||||
recv.type = AIOT_DMRECV_GENERIC_REPLY;
|
||||
|
||||
core_log(dm_handle->sysdep, STATE_DM_LOG_RECV, "DM recv generic reply\r\n");
|
||||
|
||||
do {
|
||||
if (_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 2, &recv.product_key) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 3, &recv.device_name) < 0) {
|
||||
break; /* must be malloc failed */
|
||||
}
|
||||
|
||||
if ((core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
ALINK_JSON_KEY_ID, strlen(ALINK_JSON_KEY_ID), &value, &value_len)) < 0 ||
|
||||
(core_str2uint(value, value_len, &recv.data.generic_reply.msg_id)) < 0 ||
|
||||
(core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
ALINK_JSON_KEY_CODE, strlen(ALINK_JSON_KEY_CODE), &value, &value_len)) < 0 ||
|
||||
(core_str2uint(value, value_len, &recv.data.generic_reply.code)) < 0 ||
|
||||
(core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
ALINK_JSON_KEY_DATA, strlen(ALINK_JSON_KEY_DATA),
|
||||
&recv.data.generic_reply.data,
|
||||
&recv.data.generic_reply.data_len)) < 0) {
|
||||
|
||||
core_log(dm_handle->sysdep, SATAE_DM_LOG_PARSE_RECV_MSG_FAILED, "DM parse generic reply failed\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
ALINK_JSON_KEY_MESSAGE, strlen(ALINK_JSON_KEY_MESSAGE),
|
||||
&recv.data.generic_reply.message,
|
||||
&recv.data.generic_reply.message_len);
|
||||
|
||||
_append_diag_data(dm_handle, DM_DIAG_MSG_TYPE_RSP, recv.data.generic_reply.msg_id);
|
||||
dm_handle->recv_handler(dm_handle, &recv, dm_handle->userdata);
|
||||
} while (0);
|
||||
|
||||
DM_FREE(recv.product_key);
|
||||
DM_FREE(recv.device_name);
|
||||
}
|
||||
|
||||
static void _dm_recv_property_set_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
dm_handle_t *dm_handle = (dm_handle_t *)userdata;
|
||||
aiot_dm_recv_t recv;
|
||||
|
||||
if (NULL == dm_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* construct recv message */
|
||||
memset(&recv, 0, sizeof(aiot_dm_recv_t));
|
||||
recv.type = AIOT_DMRECV_PROPERTY_SET;
|
||||
|
||||
core_log(dm_handle->sysdep, STATE_DM_LOG_RECV, "DM recv property set\r\n");
|
||||
|
||||
do {
|
||||
if (_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 2, &recv.product_key) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 3, &recv.device_name) < 0) {
|
||||
break; /* must be malloc failed */
|
||||
}
|
||||
|
||||
if ((_dm_parse_alink_request((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
&recv.data.property_set.msg_id,
|
||||
&recv.data.property_set.params,
|
||||
&recv.data.property_set.params_len)) < 0) {
|
||||
|
||||
core_log(dm_handle->sysdep, SATAE_DM_LOG_PARSE_RECV_MSG_FAILED, "DM parse property set failed\r\n");
|
||||
break;
|
||||
}
|
||||
dm_handle->recv_handler(dm_handle, &recv, dm_handle->userdata);
|
||||
} while (0);
|
||||
|
||||
DM_FREE(recv.product_key);
|
||||
DM_FREE(recv.device_name);
|
||||
}
|
||||
|
||||
static void _dm_recv_async_service_invoke_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
dm_handle_t *dm_handle = (dm_handle_t *)userdata;
|
||||
aiot_dm_recv_t recv;
|
||||
|
||||
if (NULL == dm_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_dm_recv_t));
|
||||
recv.type = AIOT_DMRECV_ASYNC_SERVICE_INVOKE;
|
||||
|
||||
core_log(dm_handle->sysdep, STATE_DM_LOG_RECV, "DM recv async service invoke\r\n");
|
||||
|
||||
do {
|
||||
if (_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 2, &recv.product_key) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 3, &recv.device_name) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 6,
|
||||
&recv.data.async_service_invoke.service_id) < 0) {
|
||||
break;
|
||||
}
|
||||
if ((_dm_parse_alink_request((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
&recv.data.async_service_invoke.msg_id,
|
||||
&recv.data.async_service_invoke.params,
|
||||
&recv.data.async_service_invoke.params_len)) < 0) {
|
||||
|
||||
/* core_log(dm_handle->sysdep, SATAE_DM_LOG_PARSE_RECV_MSG_FAILED, "DM parse async servicey failed\r\n"); */
|
||||
break;
|
||||
}
|
||||
|
||||
dm_handle->recv_handler(dm_handle, &recv, dm_handle->userdata);
|
||||
} while (0);
|
||||
|
||||
DM_FREE(recv.product_key);
|
||||
DM_FREE(recv.device_name);
|
||||
DM_FREE(recv.data.async_service_invoke.service_id);
|
||||
}
|
||||
|
||||
static void _dm_recv_sync_service_invoke_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
dm_handle_t *dm_handle = (dm_handle_t *)userdata;
|
||||
aiot_dm_recv_t recv;
|
||||
|
||||
if (NULL == dm_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_dm_recv_t));
|
||||
recv.type = AIOT_DMRECV_SYNC_SERVICE_INVOKE;
|
||||
|
||||
core_log(dm_handle->sysdep, STATE_DM_LOG_RECV, "DM recv sync service invoke\r\n");
|
||||
|
||||
do {
|
||||
if (_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 5, &recv.product_key) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 6, &recv.device_name) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 3,
|
||||
&recv.data.sync_service_invoke.rrpc_id) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 9,
|
||||
&recv.data.sync_service_invoke.service_id) < 0) {
|
||||
break;
|
||||
}
|
||||
if ((_dm_parse_alink_request((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
&recv.data.sync_service_invoke.msg_id,
|
||||
&recv.data.sync_service_invoke.params,
|
||||
&recv.data.sync_service_invoke.params_len)) < 0) {
|
||||
|
||||
core_log(dm_handle->sysdep, SATAE_DM_LOG_PARSE_RECV_MSG_FAILED, "DM parse sync service failed\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
dm_handle->recv_handler(dm_handle, &recv, dm_handle->userdata);
|
||||
} while (0);
|
||||
|
||||
DM_FREE(recv.data.sync_service_invoke.rrpc_id);
|
||||
DM_FREE(recv.product_key);
|
||||
DM_FREE(recv.device_name);
|
||||
DM_FREE(recv.data.sync_service_invoke.service_id);
|
||||
}
|
||||
|
||||
static void _dm_recv_raw_data_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
dm_handle_t *dm_handle = (dm_handle_t *)userdata;
|
||||
aiot_dm_recv_t recv;
|
||||
|
||||
if (NULL == dm_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_dm_recv_t));
|
||||
recv.type = AIOT_DMRECV_RAW_DATA;
|
||||
|
||||
core_log(dm_handle->sysdep, STATE_DM_LOG_RECV, "DM recv raw data\r\n");
|
||||
|
||||
do {
|
||||
if (_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 2, &recv.product_key) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 3, &recv.device_name) < 0) {
|
||||
break;
|
||||
}
|
||||
recv.data.raw_data.data = msg->data.pub.payload;
|
||||
recv.data.raw_data.data_len = msg->data.pub.payload_len;
|
||||
|
||||
dm_handle->recv_handler(dm_handle, &recv, dm_handle->userdata);
|
||||
} while (0);
|
||||
|
||||
DM_FREE(recv.product_key);
|
||||
DM_FREE(recv.device_name);
|
||||
}
|
||||
|
||||
static void _dm_recv_up_raw_reply_data_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
dm_handle_t *dm_handle = (dm_handle_t *)userdata;
|
||||
aiot_dm_recv_t recv;
|
||||
|
||||
if (NULL == dm_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_dm_recv_t));
|
||||
recv.type = AIOT_DMRECV_RAW_DATA_REPLY;
|
||||
|
||||
core_log(dm_handle->sysdep, STATE_DM_LOG_RECV, "DM recv raw data\r\n");
|
||||
|
||||
do {
|
||||
if (_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 2, &recv.product_key) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 3, &recv.device_name) < 0) {
|
||||
break;
|
||||
}
|
||||
recv.data.raw_data.data = msg->data.pub.payload;
|
||||
recv.data.raw_data.data_len = msg->data.pub.payload_len;
|
||||
|
||||
dm_handle->recv_handler(dm_handle, &recv, dm_handle->userdata);
|
||||
} while (0);
|
||||
|
||||
DM_FREE(recv.product_key);
|
||||
DM_FREE(recv.device_name);
|
||||
}
|
||||
|
||||
static void _dm_recv_raw_sync_service_invoke_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
dm_handle_t *dm_handle = (dm_handle_t *)userdata;
|
||||
aiot_dm_recv_t recv;
|
||||
|
||||
if (NULL == dm_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_dm_recv_t));
|
||||
recv.type = AIOT_DMRECV_RAW_SYNC_SERVICE_INVOKE;
|
||||
|
||||
core_log(dm_handle->sysdep, STATE_DM_LOG_RECV, "DM recv raw sync service invoke\r\n");
|
||||
|
||||
do {
|
||||
if (_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 3,
|
||||
&recv.data.raw_service_invoke.rrpc_id) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 5, &recv.product_key) < 0 ||
|
||||
_dm_get_topic_level(dm_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, 6, &recv.device_name) < 0) {
|
||||
break;
|
||||
}
|
||||
recv.data.raw_service_invoke.data = msg->data.pub.payload;
|
||||
recv.data.raw_service_invoke.data_len = msg->data.pub.payload_len;
|
||||
|
||||
dm_handle->recv_handler(dm_handle, &recv, dm_handle->userdata);
|
||||
} while (0);
|
||||
|
||||
DM_FREE(recv.data.raw_service_invoke.rrpc_id);
|
||||
DM_FREE(recv.product_key);
|
||||
DM_FREE(recv.device_name);
|
||||
}
|
||||
|
||||
static void _dm_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
|
||||
{
|
||||
dm_handle_t *dm_handle = (dm_handle_t *)context;
|
||||
|
||||
if (core_event != NULL) {
|
||||
switch (core_event->type) {
|
||||
case CORE_MQTTEVT_DEINIT: {
|
||||
dm_handle->mqtt_handle = NULL;
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _dm_core_mqtt_operate_process_handler(dm_handle_t *dm_handle, core_mqtt_option_t option)
|
||||
{
|
||||
core_mqtt_process_data_t process_data;
|
||||
|
||||
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
|
||||
process_data.handler = _dm_core_mqtt_process_handler;
|
||||
process_data.context = dm_handle;
|
||||
|
||||
return core_mqtt_setopt(dm_handle->mqtt_handle, option, &process_data);
|
||||
}
|
||||
|
||||
void *aiot_dm_init(void)
|
||||
{
|
||||
aiot_sysdep_portfile_t *sysdep = aiot_sysdep_get_portfile();
|
||||
dm_handle_t *dm_handle = NULL;
|
||||
|
||||
if (NULL == sysdep) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dm_handle = sysdep->core_sysdep_malloc(sizeof(dm_handle_t), DATA_MODEL_MODULE_NAME);
|
||||
if (NULL == dm_handle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(dm_handle, 0, sizeof(dm_handle_t));
|
||||
dm_handle->sysdep = sysdep;
|
||||
dm_handle->post_reply = 1;
|
||||
|
||||
core_global_init(sysdep);
|
||||
return dm_handle;
|
||||
}
|
||||
|
||||
int32_t aiot_dm_setopt(void *handle, aiot_dm_option_t option, void *data)
|
||||
{
|
||||
dm_handle_t *dm_handle;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == handle || NULL == data) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
if (option >= AIOT_DMOPT_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
dm_handle = (dm_handle_t *)handle;
|
||||
|
||||
switch (option) {
|
||||
case AIOT_DMOPT_MQTT_HANDLE: {
|
||||
dm_handle->mqtt_handle = data;
|
||||
/* setup mqtt topic mapping */
|
||||
res = _dm_setup_topic_mapping(data, dm_handle);
|
||||
if (res >= STATE_SUCCESS) {
|
||||
res = _dm_core_mqtt_operate_process_handler(dm_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AIOT_DMOPT_RECV_HANDLER: {
|
||||
dm_handle->recv_handler = (aiot_dm_recv_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DMOPT_USERDATA: {
|
||||
dm_handle->userdata = data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DMOPT_POST_REPLY: {
|
||||
dm_handle->post_reply = *(uint8_t *)data;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_dm_send(void *handle, const aiot_dm_msg_t *msg)
|
||||
{
|
||||
dm_handle_t *dm_handle = NULL;
|
||||
char *topic = NULL;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == handle || NULL == msg) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (msg->type >= AIOT_DMMSG_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
dm_handle = (dm_handle_t *)handle;
|
||||
if (NULL == dm_handle->mqtt_handle) {
|
||||
return STATE_DM_MQTT_HANDLE_IS_NULL;
|
||||
}
|
||||
|
||||
res = _dm_prepare_send_topic(dm_handle, msg, &topic);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = g_dm_send_topic_mapping[msg->type].func(dm_handle, topic, msg);
|
||||
dm_handle->sysdep->core_sysdep_free(topic);
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_dm_deinit(void **p_handle)
|
||||
{
|
||||
dm_handle_t *dm_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
uint8_t i = 0;
|
||||
|
||||
if (NULL == p_handle || NULL == *p_handle) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
dm_handle = *p_handle;
|
||||
sysdep = dm_handle->sysdep;
|
||||
*p_handle = NULL;
|
||||
|
||||
_dm_core_mqtt_operate_process_handler(dm_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER);
|
||||
|
||||
/* remove mqtt topic mapping */
|
||||
for (i = 0; i < sizeof(g_dm_recv_topic_mapping) / sizeof(dm_recv_topic_map_t); i++) {
|
||||
aiot_mqtt_topic_map_t topic_mapping;
|
||||
memset(&topic_mapping, 0, sizeof(aiot_mqtt_topic_map_t));
|
||||
topic_mapping.topic = g_dm_recv_topic_mapping[i].topic;
|
||||
topic_mapping.handler = g_dm_recv_topic_mapping[i].func;
|
||||
|
||||
aiot_mqtt_setopt(dm_handle->mqtt_handle, AIOT_MQTTOPT_REMOVE_TOPIC_MAP, &topic_mapping);
|
||||
}
|
||||
|
||||
sysdep->core_sysdep_free(dm_handle);
|
||||
|
||||
core_global_deinit(sysdep);
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
681
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/data-model/aiot_dm_api.h
vendored
Normal file
681
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/data-model/aiot_dm_api.h
vendored
Normal file
@@ -0,0 +1,681 @@
|
||||
/**
|
||||
* @file aiot_dm_api.h
|
||||
* @brief 数据模型模块头文件, 提供了物模型数据格式的上云能力, 包括属性, 事件, 服务和物模型二进制格式的数据上下行能力
|
||||
* @date 2020-01-20
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 请按照以下流程使用API
|
||||
*
|
||||
* 1. 在使用物模型模块前, 用户应首先创建好一个MQTT实例
|
||||
*
|
||||
* 2. 调用`aiot_dm_init`创建一个物模型实例, 保存实例句柄
|
||||
*
|
||||
* 3. 调用`aiot_dm_setopt`配置`AIOT_DMOPT_MQTT_HANDLE`选项以设置MQTT句柄, 此选项为强制配置选项
|
||||
*
|
||||
* 4. 调用`aiot_dm_setopt`配置`AIOT_DMOPT_RECV_HANDLER`和`AIOT_DMOPT_USERDATA`选项以注册数据接受回调函数和用户上下文数据指针
|
||||
*
|
||||
* 5. 在使用`aiot_dm_send`发送消息前, 应先完成MQTT实例的建连
|
||||
*
|
||||
* 6. 调动`aiot_dm_send`发送不同类型的消息到云平台, 在注册的回调函数中处理各种类型的云平台下行消息
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AIOT_DM_API_H__
|
||||
#define __AIOT_DM_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief -0x0A00~-0x0AFF表达SDK在data-model模块内的状态码
|
||||
*/
|
||||
#define STATE_DM_BASE (-0x0A00)
|
||||
|
||||
/**
|
||||
* @brief 用户发送@ref AIOT_DMMSG_EVENT_POST 消息时, 消息数据中的event_id为NULL
|
||||
*/
|
||||
#define STATE_DM_EVENT_ID_IS_NULL (-0x0A01)
|
||||
|
||||
/**
|
||||
* @brief 用户发送@ref AIOT_DMMSG_ASYNC_SERVICE_REPLY 或@ref AIOT_DMMSG_SYNC_SERVICE_REPLY 消息时, 消息数据中的event_id为NULL
|
||||
*/
|
||||
#define STATE_DM_SERVICE_ID_IS_NULL (-0x0A02)
|
||||
|
||||
/**
|
||||
* @brief 用户发送@ref AIOT_DMMSG_SYNC_SERVICE_REPLY 消息时, 消息数据中的rrpc_id为NULL
|
||||
*/
|
||||
#define STATE_DM_RRPC_ID_IS_NULL (-0x0A03)
|
||||
|
||||
/**
|
||||
* @brief 用户发送请求类消息时, 消息数据中的param为NULL
|
||||
*/
|
||||
#define STATE_DM_MSG_PARAMS_IS_NULL (-0X0A04)
|
||||
|
||||
/**
|
||||
* @brief 用户发送应答类消息时, 消息数据中的data为NULL
|
||||
*/
|
||||
#define STATE_DM_MSG_DATA_IS_NULL (-0X0A05)
|
||||
|
||||
/**
|
||||
* @brief 解析下行数据对应的topic时发生错误
|
||||
*/
|
||||
#define STATE_DM_INTERNAL_TOPIC_ERROR (-0x0A06)
|
||||
|
||||
/**
|
||||
* @brief 用户未调用@ref aiot_dm_setopt 配置MQTT句柄
|
||||
*/
|
||||
#define STATE_DM_MQTT_HANDLE_IS_NULL (-0x0A07)
|
||||
|
||||
/**
|
||||
* @brief 接收到服务器下行消息时的日志状态码
|
||||
*/
|
||||
#define STATE_DM_LOG_RECV (-0x0A08)
|
||||
|
||||
/**
|
||||
* @brief 解析服务器下行消息失败时的日志状态码
|
||||
*/
|
||||
#define SATAE_DM_LOG_PARSE_RECV_MSG_FAILED (-0x0A09)
|
||||
|
||||
|
||||
/**
|
||||
* @brief data-model模块的配置选项枚举类型定义. @ref aiot_dm_setopt 函数入数data的数据类型根据不同的选项而不同
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 模块依赖的MQTT句柄
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* data-model模块依赖底层的MQTT模块, 用户必需配置正确的MQTT句柄, 否则无法正常工作
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_DMOPT_MQTT_HANDLE,
|
||||
|
||||
/**
|
||||
* @brief 数据接收回调函数, data-model接收物联网平台的下行消息后调用此回调函数
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (aiot_dm_recv_handler_t), 详细查看@ref aiot_dm_recv_handler_t 回调函数原型
|
||||
*/
|
||||
AIOT_DMOPT_RECV_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief 指向用户上下文数据的指针
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 在用户注册的@ref aiot_dm_recv_handler_t 数据接收回调函数中会同过userdata参数将此指针返回给用户
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_DMOPT_USERDATA,
|
||||
|
||||
/**
|
||||
* @brief 用户是否希望接收post消息后的reply
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 是否要接收云端的reply消息. 1表示要接收, 0表示不要.
|
||||
*
|
||||
* 数据类型: (uint8_t) *)
|
||||
*/
|
||||
AIOT_DMOPT_POST_REPLY,
|
||||
|
||||
/**
|
||||
* @brief 配置选项数量最大值, 不可用作配置参数
|
||||
*/
|
||||
AIOT_DMOPT_MAX,
|
||||
} aiot_dm_option_t;
|
||||
|
||||
/**
|
||||
* @brief data-model模块发送消息类型
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 这个枚举类型包括了dm模块支持发送的所有数据类型, 不同的消息类型将对于不同的消息结构体
|
||||
* 用户可查看网页文档<a href="https://help.aliyun.com/document_detail/89301.html">设备属性/事件/服务</a>进一步了解各种数据类型
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 属性上报, 消息结构体参考@ref aiot_dm_msg_property_post_t \n
|
||||
* 成功发送此消息后, 将会收到@ref AIOT_DMRECV_GENERIC_REPLY 类型的应答消息
|
||||
*/
|
||||
AIOT_DMMSG_PROPERTY_POST,
|
||||
|
||||
/**
|
||||
* @brief 事件上报, 消息结构体参考@ref aiot_dm_msg_event_post_t \n
|
||||
* 成功发送此消息后, 将会收到@ref AIOT_DMRECV_GENERIC_REPLY 类型的应答消息
|
||||
*/
|
||||
AIOT_DMMSG_EVENT_POST,
|
||||
|
||||
/**
|
||||
* @brief 属性设置应答, 消息结构体参考@ref aiot_dm_msg_property_set_reply_t
|
||||
*/
|
||||
AIOT_DMMSG_PROPERTY_SET_REPLY,
|
||||
|
||||
/**
|
||||
* @brief 异步服务应答, 消息结构体参考@ref aiot_dm_msg_async_service_reply_t
|
||||
*/
|
||||
AIOT_DMMSG_ASYNC_SERVICE_REPLY,
|
||||
|
||||
/**
|
||||
* @brief 同步服务应答, 消息结构体参考@ref aiot_dm_msg_sync_service_reply_t
|
||||
*/
|
||||
AIOT_DMMSG_SYNC_SERVICE_REPLY,
|
||||
|
||||
/**
|
||||
* @brief 二进制格式的物模型上行数据, 消息结构体参考@ref aiot_dm_msg_raw_data_t
|
||||
*/
|
||||
AIOT_DMMSG_RAW_DATA,
|
||||
|
||||
/**
|
||||
* @brief 二进制格式的同步服务应答, 消息结构体参考@ref aiot_dm_msg_raw_service_reply_t
|
||||
*/
|
||||
AIOT_DMMSG_RAW_SERVICE_REPLY,
|
||||
|
||||
/**
|
||||
* @brief 获取期望属性值, 消息结构体请参考@ref aiot_dm_msg_get_desired_t, \n
|
||||
* 成功发送此消息后, 将会收到@ref AIOT_DMRECV_GENERIC_REPLY 类型的应答消息
|
||||
*/
|
||||
AIOT_DMMSG_GET_DESIRED,
|
||||
|
||||
/**
|
||||
* @brief 清除指定的期望值, 消息结构体请参考@ref aiot_dm_msg_delete_desired_t \n
|
||||
* 成功发送此消息后, 将会收到@ref AIOT_DMRECV_GENERIC_REPLY 类型的应答消息
|
||||
*/
|
||||
AIOT_DMMSG_DELETE_DESIRED,
|
||||
|
||||
/**
|
||||
* @brief 清除指定的期望值, 消息结构体请参考@ref aiot_dm_msg_delete_desired_t \n
|
||||
* 成功发送此消息后, 将会收到@ref AIOT_DMRECV_GENERIC_REPLY 类型的应答消息
|
||||
*/
|
||||
AIOT_DMMSG_PROPERTY_BATCH_POST,
|
||||
|
||||
/**
|
||||
* @brief 消息数量最大值, 不可用作消息类型
|
||||
*/
|
||||
AIOT_DMMSG_MAX,
|
||||
} aiot_dm_msg_type_t;
|
||||
|
||||
/**
|
||||
* @brief <b>物模型属性上报</b>消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>. 包含用户要上报的属性数据, 如<i>"{\"LightSwitch\":0}"</i>
|
||||
*/
|
||||
char *params;
|
||||
} aiot_dm_msg_property_post_t;
|
||||
|
||||
/**
|
||||
* @brief <b>物模型事件上报</b>消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 事件标示符, <b>必须为以结束符'\0'结尾的字符串</b>
|
||||
*/
|
||||
char *event_id;
|
||||
/**
|
||||
* @brief 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>. 包含用户要上报的事件数据, 如<i>"{\"ErrorNum\":0}"</i>
|
||||
*/
|
||||
char *params;
|
||||
} aiot_dm_msg_event_post_t;
|
||||
|
||||
/**
|
||||
* @brief <b>属性设置应答</b>消息结构体, 用户在收到@ref AIOT_DMRECV_PROPERTY_SET 类型的属性设置后, 可发送此消息进行回复
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息标识符, uint64_t类型的整数, <b>必须与属性设置的消息标示符一致</b>
|
||||
*/
|
||||
uint64_t msg_id;
|
||||
/**
|
||||
* @brief 设备端状态码, 200-请求成功, 更多状态码查看<a href="https://help.aliyun.com/document_detail/89309.html">设备端通用code</a>
|
||||
*/
|
||||
uint32_t code;
|
||||
/**
|
||||
* @brief 设备端应答数据, 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>, 如<i>"{}"</i>表示应答数据为空
|
||||
*/
|
||||
char *data;
|
||||
} aiot_dm_msg_property_set_reply_t;
|
||||
|
||||
/**
|
||||
* @brief <b>异步服务应答</b>消息结构体, 用户在收到@ref AIOT_DMRECV_ASYNC_SERVICE_INVOKE 类型的异步服务调用消息后, 应发送此消息进行应答
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息标识符, uint64_t类型的整数, <b>必须与异步服务调用的消息标示符一致</b>
|
||||
*/
|
||||
uint64_t msg_id;
|
||||
/**
|
||||
* @brief 服务标示符, 标识了要响应服务
|
||||
*/
|
||||
char *service_id;
|
||||
/**
|
||||
* @brief 设备端状态码, 200-请求成功, 更多状态码查看<a href="https://help.aliyun.com/document_detail/89309.html">设备端通用code</a>
|
||||
*/
|
||||
uint32_t code;
|
||||
/**
|
||||
* @brief 设备端应答数据, 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>, 如<i>"{}"</i>表示应答数据为空
|
||||
*/
|
||||
char *data;
|
||||
} aiot_dm_msg_async_service_reply_t;
|
||||
|
||||
/**
|
||||
* @brief <b>同步服务应答</b>消息结构体, 用户在收到@ref AIOT_DMRECV_SYNC_SERVICE_INVOKE 类型的同步服务调用消息后, 应在超时时间(默认7s)内进行应答
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息标识符, uint64_t类型的整数, <b>必须与同步服务调用的消息标示符一致</b>
|
||||
*/
|
||||
uint64_t msg_id;
|
||||
/**
|
||||
* @brief RRPC标示符, 用于唯一标识每一个同步服务的字符串, <b>必须与同步服务调用消息的RRPC标示符一致</b>
|
||||
*/
|
||||
char *rrpc_id;
|
||||
/**
|
||||
* @brief 服务标示符, 标识了要响应服务
|
||||
*/
|
||||
char *service_id;
|
||||
/**
|
||||
* @brief 设备端状态码, 200-请求成功, 更多状态码查看<a href="https://help.aliyun.com/document_detail/89309.html">设备端通用code</a>
|
||||
*/
|
||||
uint32_t code;
|
||||
/**
|
||||
* @brief 设备端应答数据, 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>, 如<i>"{}"</i>表示应答数据为空
|
||||
*/
|
||||
char *data;
|
||||
} aiot_dm_msg_sync_service_reply_t;
|
||||
|
||||
/**
|
||||
* @brief <b>物模型二进制数据</b>消息结构体, 发送的二进制数据将通过物联网平台的JavaScript脚本转化为JSON格式数据, 用户发送此消息前应确保已正确启用云端解析脚本
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 指向待发送二进制数据的指针
|
||||
*/
|
||||
uint8_t *data;
|
||||
/**
|
||||
* @brief 待发送数据的长度
|
||||
*/
|
||||
uint32_t data_len;
|
||||
} aiot_dm_msg_raw_data_t;
|
||||
|
||||
/**
|
||||
* @brief <b>二进制格式的同步服务应答</b>消息结构体, 用户在收到@ref AIOT_DMRECV_RAW_SYNC_SERVICE_INVOKE 类型消息后, 应在超时时间(默认7s)内进行应答\n
|
||||
* 用户在使用此消息前应确保已启用云端解析脚本, 并且脚本工作正常
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief RRPC标示符, 特殊字符串, <b>必须与同步服务调用消息的RRPC标示符一致</b>
|
||||
*/
|
||||
char *rrpc_id;
|
||||
/**
|
||||
* @brief 指向待发送二进制数据的指针
|
||||
*/
|
||||
uint8_t *data;
|
||||
/**
|
||||
* @brief 待发送数据的长度
|
||||
*/
|
||||
uint32_t data_len;
|
||||
} aiot_dm_msg_raw_service_reply_t;
|
||||
|
||||
/**
|
||||
* @brief <b>获取期望属性值</b>消息结构体, 发送
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 字符串形式的JSON<b>数组</b>, <b>必须以结束符'\0'结尾</b>. 应包含用户要获取的期望属性的ID, 如<i>"[\"LightSwitch\"]"</i>
|
||||
*/
|
||||
char *params;
|
||||
} aiot_dm_msg_get_desired_t;
|
||||
|
||||
/**
|
||||
* @brief <b>删除指定期望值</b>消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>. 应包含用户要删除的期望属性的ID和期望值版本号, 如<i>"{\"LightSwitch\":{\"version\":1},\"Color\":{}}"</i>
|
||||
*/
|
||||
char *params;
|
||||
} aiot_dm_msg_delete_desired_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief <b>物模型属性上报</b>消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 字符串形式的JSON结构体, <b>必须以结束符'\0'结尾</b>. 包含用户要批量上报的属性和事件数据, 如 {"properties":{"Power": [ { "value": "on", "time": 1524448722000 },
|
||||
* { "value": "off", "time": 1524448722001 } ], "WF": [ { "value": 3, "time": 1524448722000 }]}, "events": {"alarmEvent": [{ "value": { "Power": "on", "WF": "2"},
|
||||
* "time": 1524448722000}]}}
|
||||
*/
|
||||
char *params;
|
||||
} aiot_dm_msg_property_batch_post_t;
|
||||
|
||||
/**
|
||||
* @brief data-model模块发送消息的消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息所属设备的product_key, 若为NULL则使用通过aiot_dm_setopt配置的product_key\n
|
||||
* 在网关子设备场景下, 可通过指定为子设备的product_key来发送子设备的消息到云端
|
||||
*/
|
||||
char *product_key;
|
||||
/**
|
||||
* @brief 消息所属设备的device_name, 若为NULL则使用通过aiot_dm_setopt配置的device_name\n
|
||||
* 在网关子设备场景下, 可通过指定为子设备的product_key来发送子设备的消息到云端
|
||||
*/
|
||||
char *device_name;
|
||||
/**
|
||||
* @brief 消息类型, 可参考@ref aiot_dm_msg_type_t
|
||||
*/
|
||||
aiot_dm_msg_type_t type;
|
||||
/**
|
||||
* @brief 消息数据联合体, 不同的消息类型将使用不同的消息结构体
|
||||
*/
|
||||
union {
|
||||
aiot_dm_msg_property_post_t property_post;
|
||||
aiot_dm_msg_event_post_t event_post;
|
||||
aiot_dm_msg_property_set_reply_t property_set_reply;
|
||||
aiot_dm_msg_sync_service_reply_t sync_service_reply;
|
||||
aiot_dm_msg_async_service_reply_t async_service_reply;
|
||||
aiot_dm_msg_raw_data_t raw_data;
|
||||
aiot_dm_msg_raw_service_reply_t raw_service_reply;
|
||||
aiot_dm_msg_get_desired_t get_desired;
|
||||
aiot_dm_msg_delete_desired_t delete_desired;
|
||||
} data;
|
||||
} aiot_dm_msg_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief data-model模块接受消息类型枚举
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 这个枚举类型包括了dm模块支持接收的所有数据类型, 不同的消息类型将对于不同的消息结构体
|
||||
* 用户可查看网页文档<a href="https://help.aliyun.com/document_detail/89301.html">设备属性/事件/服务</a>进一步了解各种数据类型
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 上报属性/实践后服务器返回的应答消息, 消息数据结构体参考@ref aiot_dm_recv_generic_reply_t
|
||||
*/
|
||||
AIOT_DMRECV_GENERIC_REPLY,
|
||||
|
||||
/**
|
||||
* @brief 服务器下发的属性设置消息, 消息数据结构体参考@ref aiot_dm_recv_property_set_t
|
||||
*/
|
||||
AIOT_DMRECV_PROPERTY_SET,
|
||||
|
||||
/**
|
||||
* @brief 服务器下发的异步服务调用消息, 消息数据结构体参考@ref aiot_dm_recv_async_service_invoke_t
|
||||
*/
|
||||
AIOT_DMRECV_ASYNC_SERVICE_INVOKE,
|
||||
|
||||
/**
|
||||
* @brief 服务器下发的同步服务调用消息, 消息数据结构体参考@ref aiot_dm_recv_sync_service_invoke_t
|
||||
*/
|
||||
AIOT_DMRECV_SYNC_SERVICE_INVOKE,
|
||||
|
||||
/**
|
||||
* @brief 服务器对设备上报的二进制数据应答, 消息数据结构体参考@ref aiot_dm_recv_raw_data_t
|
||||
*/
|
||||
AIOT_DMRECV_RAW_DATA_REPLY,
|
||||
|
||||
/**
|
||||
* @brief 服务器下发的物模型二进制数据, 消息数据结构体参考@ref aiot_dm_recv_raw_data_t
|
||||
*/
|
||||
AIOT_DMRECV_RAW_DATA,
|
||||
|
||||
/**
|
||||
* @brief 服务器下发的二进制格式的同步服务调用消息, 消息数据结构体参考@ref aiot_dm_recv_raw_service_invoke_t
|
||||
*/
|
||||
AIOT_DMRECV_RAW_SYNC_SERVICE_INVOKE,
|
||||
|
||||
/**
|
||||
* @brief 消息数量最大值, 不可用作消息类型
|
||||
*/
|
||||
AIOT_DMRECV_MAX,
|
||||
} aiot_dm_recv_type_t;
|
||||
|
||||
/**
|
||||
* @brief <b>云端通用应答</b>消息结构体, 设备端上报@ref AIOT_DMMSG_PROPERTY_POST, @ref AIOT_DMMSG_EVENT_POST 或者@ref AIOT_DMMSG_GET_DESIRED 等消息后, 服务器会应答此消息
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息标识符, uint64_t类型的整数, 与属性上报或事件上报的消息标示符一致
|
||||
*/
|
||||
uint32_t msg_id;
|
||||
/**
|
||||
* @brief 设备端错误码, 200-请求成功, 更多错误码码查看<a href="https://help.aliyun.com/document_detail/120329.html">设备端错误码</a>
|
||||
*/
|
||||
uint32_t code;
|
||||
/**
|
||||
* @brief 指向云端应答数据的指针
|
||||
*/
|
||||
char *data;
|
||||
/**
|
||||
* @brief 云端应答数据的长度
|
||||
*/
|
||||
uint32_t data_len;
|
||||
/**
|
||||
* @brief 指向状态消息字符串的指针, 当设备端上报请求成功时对应的应答消息为"success", 若请求失败则应答消息中包含错误信息
|
||||
*/
|
||||
char *message;
|
||||
/**
|
||||
* @brief 消息字符串的长度
|
||||
*/
|
||||
uint32_t message_len;
|
||||
} aiot_dm_recv_generic_reply_t;
|
||||
|
||||
/**
|
||||
* @brief <b>属性设置</b>消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息标识符, uint64_t类型的整数
|
||||
*/
|
||||
uint64_t msg_id;
|
||||
/**
|
||||
* @brief 服务器下发的属性数据, 为字符串形式的JSON结构体, 此字符串<b>不</b>以结束符'\0'结尾, 如<i>"{\"LightSwitch\":0}"</i>
|
||||
*/
|
||||
char *params;
|
||||
/**
|
||||
* @brief 属性数据的字符串长度
|
||||
*/
|
||||
uint32_t params_len;
|
||||
} aiot_dm_recv_property_set_t;
|
||||
|
||||
/**
|
||||
* @brief <b>同步服务调用</b>消息结构体, 用户收到同步服务后, 必须在超时时间(默认7s)内进行应答
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息标识符, uint64_t类型的整数
|
||||
*/
|
||||
uint64_t msg_id;
|
||||
/**
|
||||
* @brief RRPC标识符, 用于唯一标识每一个同步服务的特殊字符串
|
||||
*/
|
||||
char *rrpc_id;
|
||||
/**
|
||||
* @brief 服务标示符, 字符串内容由用户定义的物模型决定
|
||||
*/
|
||||
char *service_id;
|
||||
/**
|
||||
* @brief 服务调用的输入参数数据, 为字符串形式的JSON结构体, 此字符串<b>不</b>以结束符'\0'结尾, 如<i>"{\"LightSwitch\":0}"</i>
|
||||
*/
|
||||
char *params;
|
||||
/**
|
||||
* @brief 输入参数的字符串长度
|
||||
*/
|
||||
uint32_t params_len;
|
||||
} aiot_dm_recv_sync_service_invoke_t;
|
||||
|
||||
/**
|
||||
* @brief <b>同步服务调用</b>消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息标识符, uint64_t类型的整数
|
||||
*/
|
||||
uint64_t msg_id;
|
||||
/**
|
||||
* @brief 服务标示符, 字符串内容由用户定义的物模型决定
|
||||
*/
|
||||
char *service_id;
|
||||
/**
|
||||
* @brief 服务调用的输入参数数据, 为字符串形式的JSON结构体, 此字符串<b>不</b>以结束符'\0'结尾, 如<i>"{\"LightSwitch\":0}"</i>
|
||||
*/
|
||||
char *params;
|
||||
/**
|
||||
* @brief 输入参数的字符串长度
|
||||
*/
|
||||
uint32_t params_len;
|
||||
} aiot_dm_recv_async_service_invoke_t;
|
||||
|
||||
/**
|
||||
* @brief <b>物模型二进制数据</b>消息结构体, 服务器的JSON格式物模型数据将通过物联网平台的JavaScript脚本转化为二进制数据, 用户在接收此消息前应确保已正确启用云端解析脚本
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 指向接受数据缓冲区的指针
|
||||
*/
|
||||
uint8_t *data;
|
||||
/**
|
||||
* @brief 二进制数据的长度
|
||||
*/
|
||||
uint32_t data_len;
|
||||
} aiot_dm_recv_raw_data_t;
|
||||
|
||||
/**
|
||||
* @brief <b>二进制数据的同步服务调用</b>消息结构体, 服务器的JSON格式物模型数据将通过物联网平台的JavaScript脚本转化为二进制数据, 用户在接收此消息前应确保已正确启用云端解析脚本
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief RRPC标识符, 用于唯一标识每一个同步服务的特殊字符串
|
||||
*/
|
||||
char *rrpc_id;
|
||||
/**
|
||||
* @brief 指向接受数据缓冲区的指针
|
||||
*/
|
||||
uint8_t *data;
|
||||
/**
|
||||
* @brief 二进制数据的长度
|
||||
*/
|
||||
uint32_t data_len;
|
||||
} aiot_dm_recv_raw_service_invoke_t;
|
||||
|
||||
/**
|
||||
* @brief data-model模块接收消息的结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息所属设备的product_key, 不配置则默认使用MQTT模块配置的product_key
|
||||
*/
|
||||
char *product_key;
|
||||
/**
|
||||
* @brief 消息所属设备的device_name, 不配置则默认使用MQTT模块配置的device_name
|
||||
*/
|
||||
char *device_name;
|
||||
/**
|
||||
* @brief 接收消息的类型, 可参考@ref aiot_dm_recv_type_t
|
||||
*/
|
||||
aiot_dm_recv_type_t type;
|
||||
/**
|
||||
* @brief 消息数据联合体, 不同的消息类型将使用不同的消息结构体
|
||||
*/
|
||||
union {
|
||||
aiot_dm_recv_generic_reply_t generic_reply;
|
||||
aiot_dm_recv_property_set_t property_set;
|
||||
aiot_dm_recv_async_service_invoke_t async_service_invoke;
|
||||
aiot_dm_recv_sync_service_invoke_t sync_service_invoke;
|
||||
aiot_dm_recv_raw_data_t raw_data;
|
||||
aiot_dm_recv_raw_service_invoke_t raw_service_invoke;
|
||||
} data;
|
||||
} aiot_dm_recv_t;
|
||||
|
||||
/**
|
||||
* @brief data-model模块消息接收回调函数的函数原型定义, 当模块接收到服务器下行数据后将调用此回调函数, 并将消息数据通过<i>recv</i>参数输入给用户, \n
|
||||
* 同时将用户上下文数据指针通过<i>userdata</i>参数返回给用户
|
||||
*
|
||||
* @param[in] handle data-model实例句柄
|
||||
* @param[in] recv 服务下发的消息数据, <b>消息结构体中的所有数据指针在离开回调函数后将失效, 保存消息数据必须使用内存复制的方式</b>
|
||||
* @param[in] userdata 指向用户上下文数据的指针, 这个指针由用户通过调用@ref aiot_dm_setopt 配置@ref AIOT_DMOPT_USERDATA 选项设置
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (*aiot_dm_recv_handler_t)(void *handle, const aiot_dm_recv_t *recv, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief 初始化data-model实例
|
||||
*
|
||||
* @return void*
|
||||
* @retval 非NULL data-model实例句柄
|
||||
* @retval NULL 初始化失败, 一般是内存分配失败导致
|
||||
*/
|
||||
void *aiot_dm_init(void);
|
||||
|
||||
/**
|
||||
* @brief 设置data-model参数
|
||||
*
|
||||
* @param[in] handle data-model实例句柄
|
||||
* @param[in] option 配置选项, 更多信息请查看@ref aiot_dm_option_t
|
||||
* @param[in] data 配置数据, 更多信息请查看@ref aiot_dm_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 参数配置成功
|
||||
* @retval STATE_USER_INPUT_NULL_POINTER 入参handle或data为NULL
|
||||
* @retval STATE_USER_INPUT_OUT_RANGE 入参optioin的枚举值>=AIOT_DMOPT_MAX
|
||||
* @retval others 参考@ref aiot_state_api.h
|
||||
*
|
||||
*/
|
||||
int32_t aiot_dm_setopt(void *handle, aiot_dm_option_t option, void *data);
|
||||
|
||||
/**
|
||||
* @brief 发送一条data-model消息到物联网平台, 消息类型和消息数据由msg入参决定
|
||||
*
|
||||
* @param[in] handle data-model实例句柄
|
||||
* @param[in] msg 消息结构体, 可指定发送消息的设备<i>productKey</i>, <i>deviceName</i>; 消息类型, 消息数据等, 更多信息请参考@ref aiot_dm_msg_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval >=STATE_SUCCESS 消息发送成功, 对于@ref AIOT_DMMSG_PROPERTY_POST, @ref AIOT_DMMSG_EVENT_POST, @ref AIOT_DMMSG_GET_DESIRED 和@ref AIOT_DMMSG_DELETE_DESIRED 消息, \n
|
||||
* 发送成功返回值为>STATE_SUCCESS的消息标示符<i>msg_id</i>值
|
||||
* @retval STATE_USER_INPUT_NULL_POINTER 入参<i>handle</i>或<i>msg</i>为NULL
|
||||
* @retval STATE_USER_INPUT_OUT_RANGE 入参<i>msg</i>的结构体成员<i>type</i> >= AIOT_DMMSG_MAX
|
||||
* @retval STATE_SYS_DEPEND_MALLOC_FAILED 内存分配失败
|
||||
* @retval STATE_DM_MQTT_HANDLE_IS_NULL 用户未调用@ref aiot_dm_setopt 配置MQTT句柄
|
||||
* @retval others 参考@ref aiot_state_api.h 或@ref STATE_DM_BASE 中对应的错误码说明
|
||||
*
|
||||
*/
|
||||
int32_t aiot_dm_send(void *handle, const aiot_dm_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief 销毁data-model实例, 释放资源
|
||||
*
|
||||
* @param[in] p_handle 指向data-model实例句柄的指针
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 执行成功
|
||||
* @retval <STATE_SUCCESS 执行失败
|
||||
*
|
||||
*/
|
||||
int32_t aiot_dm_deinit(void **p_handle);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef __AIOT_DM_API_H__ */
|
||||
|
||||
78
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/data-model/dm_private.h
vendored
Normal file
78
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/data-model/dm_private.h
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @file dm_private.h
|
||||
* @brief 数据模型模块内部头文件
|
||||
* @date 2020-01-20
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DM_PRIVATE_H__
|
||||
#define __DM_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_stdinc.h"
|
||||
#include "core_string.h"
|
||||
#include "core_log.h"
|
||||
#include "core_diag.h"
|
||||
#include "core_global.h"
|
||||
#include "core_mqtt.h"
|
||||
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_state_api.h"
|
||||
#include "aiot_mqtt_api.h"
|
||||
#include "aiot_dm_api.h"
|
||||
|
||||
/* 模块内部名 */
|
||||
#define DATA_MODEL_MODULE_NAME "dm"
|
||||
|
||||
/* ALINK请求的JSON格式 */
|
||||
#define ALINK_REQUEST_FMT "{\"id\":\"%s\",\"version\":\"1.0\",\"params\":%s,\"sys\":{\"ack\":%s}}"
|
||||
/* ALINK应答的JSON格式 */
|
||||
#define ALINK_RESPONSE_FMT "{\"id\":\"%s\",\"code\":%s,\"data\":%s}"
|
||||
#define ALINK_JSON_KEY_ID "id"
|
||||
#define ALINK_JSON_KEY_CODE "code"
|
||||
#define ALINK_JSON_KEY_PARAMS "params"
|
||||
#define ALINK_JSON_KEY_DATA "data"
|
||||
#define ALINK_JSON_KEY_MESSAGE "message"
|
||||
|
||||
/* 诊断消息类型 */
|
||||
#define DM_DIAG_MSG_TYPE_REQ (0x00)
|
||||
#define DM_DIAG_MSG_TYPE_RSP (0x01)
|
||||
|
||||
#define DM_FREE(ptr) do {if (ptr) {dm_handle->sysdep->core_sysdep_free(ptr); ptr = NULL;}} while (0)
|
||||
|
||||
/* data-model模块的上下文结构体定义 */
|
||||
typedef struct {
|
||||
aiot_sysdep_portfile_t *sysdep;
|
||||
void *mqtt_handle;
|
||||
|
||||
aiot_dm_recv_handler_t recv_handler;
|
||||
void *userdata;
|
||||
uint8_t post_reply;
|
||||
} dm_handle_t;
|
||||
|
||||
/* data-model内部发送函数原型定义 */
|
||||
typedef int32_t (*dm_msg_send_func_t)(dm_handle_t *handle, const char *topic, const aiot_dm_msg_t *msg);
|
||||
|
||||
/* 包含上行topic和对应处理函数的结构体定义 */
|
||||
typedef struct {
|
||||
char *topic;
|
||||
dm_msg_send_func_t func;
|
||||
} dm_send_topic_map_t;
|
||||
|
||||
/* 包含下行topic和对应处理函数的结构体定义 */
|
||||
typedef struct {
|
||||
char *topic;
|
||||
aiot_mqtt_recv_handler_t func;
|
||||
} dm_recv_topic_map_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef __DM_PRIVATE_H__ */
|
||||
|
||||
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/devinfo/README.md
vendored
Normal file
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/devinfo/README.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Name: 设备标签模块
|
||||
DEVINFO Component for Link SDK V4.0.0
|
||||
|
||||
424
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/devinfo/aiot_devinfo_api.c
vendored
Normal file
424
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/devinfo/aiot_devinfo_api.c
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
/**
|
||||
* @file aiot_devinfo_api.c
|
||||
* @brief devinfo模块的API接口实现, 提供更新和删除设备标签的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
#include "devinfo_private.h"
|
||||
|
||||
#include "core_string.h"
|
||||
#include "core_log.h"
|
||||
#include "core_global.h"
|
||||
#include "core_mqtt.h"
|
||||
|
||||
static void _core_devinfo_exec_inc(devinfo_handle_t *devinfo_handle)
|
||||
{
|
||||
devinfo_handle->sysdep->core_sysdep_mutex_lock(devinfo_handle->data_mutex);
|
||||
devinfo_handle->exec_count++;
|
||||
devinfo_handle->sysdep->core_sysdep_mutex_unlock(devinfo_handle->data_mutex);
|
||||
}
|
||||
|
||||
static void _core_devinfo_exec_dec(devinfo_handle_t *devinfo_handle)
|
||||
{
|
||||
devinfo_handle->sysdep->core_sysdep_mutex_lock(devinfo_handle->data_mutex);
|
||||
devinfo_handle->exec_count--;
|
||||
devinfo_handle->sysdep->core_sysdep_mutex_unlock(devinfo_handle->data_mutex);
|
||||
}
|
||||
|
||||
static void _devinfo_find_pk_dn(devinfo_handle_t *devinfo_handle, char *topic, uint16_t topic_len, char **product_key,
|
||||
char **device_name)
|
||||
{
|
||||
uint16_t idx = 0, prev_slash = 0, slash = 0, pk_len = 0, dn_len = 0;
|
||||
char *pk_pos = NULL, *dn_pos = NULL, *tmp_pk = NULL, *tmp_dn = NULL;
|
||||
|
||||
for (idx = 0; idx < topic_len; idx++) {
|
||||
if (topic[idx] == '/') {
|
||||
slash++;
|
||||
if (slash == 2) {
|
||||
pk_pos = &topic[idx + 1];
|
||||
prev_slash = idx;
|
||||
} else if (slash == 3) {
|
||||
dn_pos = &topic[idx + 1];
|
||||
pk_len = idx - prev_slash - 1;
|
||||
prev_slash = idx;
|
||||
} else if (slash == 4) {
|
||||
dn_len = idx - prev_slash - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pk_len == 0 || dn_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
tmp_pk = devinfo_handle->sysdep->core_sysdep_malloc(pk_len + 1, DEVINFO_MODULE_NAME);
|
||||
if (tmp_pk == NULL) {
|
||||
return;
|
||||
}
|
||||
memset(tmp_pk, 0, pk_len + 1);
|
||||
memcpy(tmp_pk, pk_pos, pk_len);
|
||||
|
||||
tmp_dn = devinfo_handle->sysdep->core_sysdep_malloc(dn_len + 1, DEVINFO_MODULE_NAME);
|
||||
if (tmp_dn == NULL) {
|
||||
devinfo_handle->sysdep->core_sysdep_free(tmp_pk);
|
||||
return;
|
||||
}
|
||||
memset(tmp_dn, 0, dn_len + 1);
|
||||
memcpy(tmp_dn, dn_pos, dn_len);
|
||||
|
||||
*product_key = tmp_pk;
|
||||
*device_name = tmp_dn;
|
||||
}
|
||||
|
||||
static void _devinfo_mqtt_recv_handler(void *handle, const aiot_mqtt_recv_t *packet, void *userdata)
|
||||
{
|
||||
devinfo_handle_t *devinfo_handle = (devinfo_handle_t *)userdata;
|
||||
aiot_devinfo_event_t event;
|
||||
char *product_key = NULL, *device_name = NULL;
|
||||
char *code_key = "code", *id_key = "id", *data_key = "data", *message_key = "message";
|
||||
char *code_value = NULL, *id_value = NULL, *data_value = NULL, *message_value = NULL;
|
||||
uint32_t code_value_len = 0, id_value_len = 0, data_value_len = 0, message_value_len = 0;
|
||||
|
||||
if (devinfo_handle->recv_handler == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
_devinfo_find_pk_dn(devinfo_handle, packet->data.pub.topic, packet->data.pub.topic_len, &product_key, &device_name);
|
||||
if (product_key == NULL || device_name == NULL) {
|
||||
if (devinfo_handle->event_handler != NULL) {
|
||||
memset(&event, 0, sizeof(aiot_devinfo_event_t));
|
||||
event.type = AIOT_DEVINFOEVT_INVALID_DEVINFO;
|
||||
devinfo_handle->event_handler(devinfo_handle, &event, devinfo_handle->userdata);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len,
|
||||
code_key, (uint32_t)strlen(code_key), &code_value, &code_value_len) == STATE_SUCCESS &&
|
||||
core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len,
|
||||
id_key, (uint32_t)strlen(id_key), &id_value, &id_value_len) == STATE_SUCCESS &&
|
||||
core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len,
|
||||
data_key, (uint32_t)strlen(data_key), &data_value, &data_value_len) == STATE_SUCCESS &&
|
||||
core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len,
|
||||
message_key, (uint32_t)strlen(message_key), &message_value, &message_value_len) == STATE_SUCCESS) {
|
||||
uint32_t code = 0, id = 0;
|
||||
if (core_str2uint(code_value, code_value_len, &code) == STATE_SUCCESS &&
|
||||
core_str2uint(id_value, id_value_len, &id) == STATE_SUCCESS) {
|
||||
aiot_devinfo_recv_t recv;
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_devinfo_recv_t));
|
||||
recv.product_key = product_key;
|
||||
recv.device_name = device_name;
|
||||
recv.type = AIOT_DEVINFORECV_GENERIC_REPLY;
|
||||
recv.data.generic_reply.code = code;
|
||||
recv.data.generic_reply.msg_id = id;
|
||||
recv.data.generic_reply.data = data_value;
|
||||
recv.data.generic_reply.data_len = data_value_len;
|
||||
recv.data.generic_reply.message = message_value;
|
||||
recv.data.generic_reply.message_len = message_value_len;
|
||||
|
||||
devinfo_handle->recv_handler(devinfo_handle, &recv, devinfo_handle->userdata);
|
||||
} else {
|
||||
if (devinfo_handle->event_handler != NULL) {
|
||||
memset(&event, 0, sizeof(aiot_devinfo_event_t));
|
||||
event.type = AIOT_DEVINFOEVT_INVALID_RESPONSE_FORMAT;
|
||||
devinfo_handle->event_handler(devinfo_handle, &event, devinfo_handle->userdata);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (devinfo_handle->event_handler != NULL) {
|
||||
memset(&event, 0, sizeof(aiot_devinfo_event_t));
|
||||
event.type = AIOT_DEVINFOEVT_INVALID_RESPONSE;
|
||||
devinfo_handle->event_handler(devinfo_handle, &event, devinfo_handle->userdata);
|
||||
}
|
||||
}
|
||||
devinfo_handle->sysdep->core_sysdep_free(product_key);
|
||||
devinfo_handle->sysdep->core_sysdep_free(device_name);
|
||||
}
|
||||
|
||||
static int32_t _devinfo_operate_topic_map(devinfo_handle_t *devinfo_handle, aiot_mqtt_option_t option)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
aiot_mqtt_topic_map_t map;
|
||||
if (option != AIOT_MQTTOPT_APPEND_TOPIC_MAP && option != AIOT_MQTTOPT_REMOVE_TOPIC_MAP) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
memset(&map, 0, sizeof(aiot_mqtt_topic_map_t));
|
||||
map.topic = DEVINFO_UPDATE_REPLY_TOPIC;
|
||||
map.handler = _devinfo_mqtt_recv_handler;
|
||||
map.userdata = devinfo_handle;
|
||||
|
||||
res = aiot_mqtt_setopt(devinfo_handle->mqtt_handle, option, &map);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
map.topic = DEVINFO_DELETE_REPLY_TOPIC;
|
||||
map.handler = _devinfo_mqtt_recv_handler;
|
||||
map.userdata = devinfo_handle;
|
||||
|
||||
res = aiot_mqtt_setopt(devinfo_handle->mqtt_handle, option, &map);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t _devinfo_send(devinfo_handle_t *devinfo_handle, char *product_key, char *device_name,
|
||||
aiot_devinfo_msg_data_t *data, char *topic_fmt)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS, alink_id = 0;
|
||||
char *topic = NULL, *payload = NULL;
|
||||
char *topic_src[] = { product_key, device_name };
|
||||
char alink_id_str[11] = {0}, *payload_src[] = { alink_id_str, data->params };
|
||||
char *payload_fmt = "{\"id\":\"%s\",\"version\":\"1.0\",\"params\":%s}";
|
||||
|
||||
res = core_global_alink_id_next(devinfo_handle->sysdep, &alink_id);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = core_int2str(alink_id, alink_id_str, NULL);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = core_sprintf(devinfo_handle->sysdep, &topic, topic_fmt, topic_src, sizeof(topic_src) / sizeof(char *),
|
||||
DEVINFO_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = core_sprintf(devinfo_handle->sysdep, &payload, payload_fmt, payload_src, sizeof(payload_src) / sizeof(char *),
|
||||
DEVINFO_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
devinfo_handle->sysdep->core_sysdep_free(topic);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(devinfo_handle->mqtt_handle, topic, (uint8_t *)payload, (uint32_t)strlen(payload), 0);
|
||||
devinfo_handle->sysdep->core_sysdep_free(topic);
|
||||
devinfo_handle->sysdep->core_sysdep_free(payload);
|
||||
|
||||
if (res >= STATE_SUCCESS) {
|
||||
res = alink_id;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _devinfo_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
|
||||
{
|
||||
devinfo_handle_t *devinfo_handle = (devinfo_handle_t *)context;
|
||||
|
||||
if (core_event != NULL) {
|
||||
switch (core_event->type) {
|
||||
case CORE_MQTTEVT_DEINIT: {
|
||||
devinfo_handle->mqtt_handle = NULL;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _devinfo_core_mqtt_operate_process_handler(devinfo_handle_t *devinfo_handle, core_mqtt_option_t option)
|
||||
{
|
||||
core_mqtt_process_data_t process_data;
|
||||
|
||||
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
|
||||
process_data.handler = _devinfo_core_mqtt_process_handler;
|
||||
process_data.context = devinfo_handle;
|
||||
|
||||
return core_mqtt_setopt(devinfo_handle->mqtt_handle, option, &process_data);
|
||||
}
|
||||
|
||||
void *aiot_devinfo_init(void)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
devinfo_handle_t *devinfo_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if (sysdep == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = core_global_init(sysdep);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
devinfo_handle = sysdep->core_sysdep_malloc(sizeof(devinfo_handle_t), DEVINFO_MODULE_NAME);
|
||||
if (devinfo_handle == NULL) {
|
||||
core_global_deinit(sysdep);
|
||||
return NULL;
|
||||
}
|
||||
memset(devinfo_handle, 0, sizeof(devinfo_handle_t));
|
||||
|
||||
devinfo_handle->sysdep = sysdep;
|
||||
devinfo_handle->deinit_timeout_ms = DEVINFO_DEFAULT_DEINIT_TIMEOUT_MS;
|
||||
|
||||
devinfo_handle->data_mutex = sysdep->core_sysdep_mutex_init();
|
||||
|
||||
devinfo_handle->exec_enabled = 1;
|
||||
|
||||
return devinfo_handle;
|
||||
}
|
||||
|
||||
int32_t aiot_devinfo_setopt(void *handle, aiot_devinfo_option_t option, void *data)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
devinfo_handle_t *devinfo_handle = (devinfo_handle_t *)handle;
|
||||
|
||||
if (handle == NULL || data == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (option >= AIOT_DEVINFOOPT_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
if (devinfo_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
_core_devinfo_exec_inc(devinfo_handle);
|
||||
|
||||
devinfo_handle->sysdep->core_sysdep_mutex_lock(devinfo_handle->data_mutex);
|
||||
switch (option) {
|
||||
case AIOT_DEVINFOOPT_MQTT_HANDLE: {
|
||||
devinfo_handle->mqtt_handle = data;
|
||||
devinfo_handle->sysdep->core_sysdep_mutex_unlock(devinfo_handle->data_mutex);
|
||||
res = _devinfo_operate_topic_map(devinfo_handle, AIOT_MQTTOPT_APPEND_TOPIC_MAP);
|
||||
if (res >= STATE_SUCCESS) {
|
||||
res = _devinfo_core_mqtt_operate_process_handler(devinfo_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER);
|
||||
}
|
||||
devinfo_handle->sysdep->core_sysdep_mutex_lock(devinfo_handle->data_mutex);
|
||||
}
|
||||
break;
|
||||
case AIOT_DEVINFOOPT_RECV_HANDLER: {
|
||||
devinfo_handle->recv_handler = (aiot_devinfo_recv_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DEVINFOOPT_EVENT_HANDLER: {
|
||||
devinfo_handle->event_handler = (aiot_devinfo_event_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DEVINFOOPT_USERDATA: {
|
||||
devinfo_handle->userdata = data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DEVINFOOPT_DEINIT_TIMEOUT_MS: {
|
||||
devinfo_handle->deinit_timeout_ms = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
res = STATE_USER_INPUT_UNKNOWN_OPTION;
|
||||
}
|
||||
}
|
||||
devinfo_handle->sysdep->core_sysdep_mutex_unlock(devinfo_handle->data_mutex);
|
||||
|
||||
_core_devinfo_exec_dec(devinfo_handle);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_devinfo_deinit(void **handle)
|
||||
{
|
||||
uint64_t deinit_timestart = 0;
|
||||
devinfo_handle_t *devinfo_handle = NULL;
|
||||
|
||||
if (handle == NULL || *handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
devinfo_handle = *(devinfo_handle_t **)handle;
|
||||
|
||||
if (devinfo_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
devinfo_handle->exec_enabled = 0;
|
||||
|
||||
_devinfo_core_mqtt_operate_process_handler(devinfo_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER);
|
||||
_devinfo_operate_topic_map(devinfo_handle, AIOT_MQTTOPT_REMOVE_TOPIC_MAP);
|
||||
|
||||
deinit_timestart = devinfo_handle->sysdep->core_sysdep_time();
|
||||
do {
|
||||
if (devinfo_handle->exec_count == 0) {
|
||||
break;
|
||||
}
|
||||
devinfo_handle->sysdep->core_sysdep_sleep(DEVINFO_DEINIT_INTERVAL_MS);
|
||||
} while ((devinfo_handle->sysdep->core_sysdep_time() - deinit_timestart) < devinfo_handle->deinit_timeout_ms);
|
||||
|
||||
if (devinfo_handle->exec_count != 0) {
|
||||
return STATE_MQTT_DEINIT_TIMEOUT;
|
||||
}
|
||||
|
||||
*handle = NULL;
|
||||
|
||||
devinfo_handle->sysdep->core_sysdep_mutex_deinit(&devinfo_handle->data_mutex);
|
||||
|
||||
core_global_deinit(devinfo_handle->sysdep);
|
||||
|
||||
devinfo_handle->sysdep->core_sysdep_free(devinfo_handle);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t aiot_devinfo_send(void *handle, aiot_devinfo_msg_t *msg)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
devinfo_handle_t *devinfo_handle = (devinfo_handle_t *)handle;
|
||||
|
||||
if (handle == NULL || msg == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (devinfo_handle->mqtt_handle == NULL) {
|
||||
return STATE_DEVINFO_MISSING_MQTT_HANDLE;
|
||||
}
|
||||
|
||||
if (msg->product_key == NULL) {
|
||||
return STATE_USER_INPUT_MISSING_PRODUCT_KEY;
|
||||
}
|
||||
|
||||
if (msg->device_name == NULL) {
|
||||
return STATE_USER_INPUT_MISSING_DEVICE_NAME;
|
||||
}
|
||||
|
||||
switch (msg->type) {
|
||||
case AIOT_DEVINFO_MSG_UPDATE: {
|
||||
if (msg->data.update.params == NULL) {
|
||||
res = STATE_USER_INPUT_NULL_POINTER;
|
||||
} else {
|
||||
res = _devinfo_send(devinfo_handle, msg->product_key, msg->device_name, &msg->data.update, DEVINFO_UPDATE_TOPIC_FMT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AIOT_DEVINFO_MSG_DELETE: {
|
||||
if (msg->data.delete.params == NULL) {
|
||||
res = STATE_USER_INPUT_NULL_POINTER;
|
||||
} else {
|
||||
res = _devinfo_send(devinfo_handle, msg->product_key, msg->device_name, &msg->data.delete, DEVINFO_DELETE_TOPIC_FMT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
res = STATE_USER_INPUT_UNKNOWN_OPTION;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
315
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/devinfo/aiot_devinfo_api.h
vendored
Normal file
315
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/devinfo/aiot_devinfo_api.h
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
/**
|
||||
* @file aiot_devinfo_api.h
|
||||
* @brief devinfo模块头文件, 提供更新和删除设备标签的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* Devinfo模块用于向阿里云物联网平台更新或删除设备的标签, API的使用流程如下:
|
||||
*
|
||||
* 1. 首先参考 @ref aiot_mqtt_api.h 的说明, 保证成功建立与物联网平台的`MQTT`连接
|
||||
*
|
||||
* 2. 调用 @ref aiot_devinfo_init 初始化devinfo会话, 获取会话句柄
|
||||
*
|
||||
* 3. 调用 @ref aiot_devinfo_setopt 配置devinfo会话的参数, 常用配置项见 @ref aiot_devinfo_setopt 的说明
|
||||
*
|
||||
* 4. 调用 @ref aiot_devinfo_send 发送标签变更的请求, 比如更新或删除
|
||||
*
|
||||
* 5. 收到的应答经SDK处理后会调用由 @ref aiot_devinfo_setopt 配置的 @ref AIOT_DEVINFOOPT_RECV_HANDLER 回调函数, 通知用户云端的应答
|
||||
*
|
||||
*/
|
||||
#ifndef __AIOT_DEVINFO_API_H__
|
||||
#define __AIOT_DEVINFO_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief -0x1200~-0x12FF表达SDK在devinfo模块内的状态码
|
||||
*/
|
||||
#define STATE_DEVINFO_BASE (-0x1200)
|
||||
|
||||
/**
|
||||
* @brief MQTT会话句柄未设置, 请通过 @ref aiot_devinfo_setopt 设置MQTT会话句柄
|
||||
*/
|
||||
#define STATE_DEVINFO_MISSING_MQTT_HANDLE (-0x1201)
|
||||
|
||||
/**
|
||||
* @brief devinfo模块收到从网络上来的报文时, 通知用户的报文类型
|
||||
*/
|
||||
typedef enum {
|
||||
AIOT_DEVINFORECV_GENERIC_REPLY,
|
||||
} aiot_devinfo_recv_type_t;
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息标识符, uint64_t类型的整数, 与属性上报或事件上报的消息标示符一致
|
||||
*/
|
||||
uint32_t msg_id;
|
||||
/**
|
||||
* @brief 设备端错误码, 200-请求成功, 更多错误码码查看<a href="https://help.aliyun.com/document_detail/120329.html">设备端错误码</a>
|
||||
*/
|
||||
uint32_t code;
|
||||
/**
|
||||
* @brief 指向云端应答数据的指针
|
||||
*/
|
||||
char *data;
|
||||
/**
|
||||
* @brief 云端应答数据的长度
|
||||
*/
|
||||
uint32_t data_len;
|
||||
/**
|
||||
* @brief 指向状态消息字符串的指针, 当设备端上报请求成功时对应的应答消息为"success", 若请求失败则应答消息中包含错误信息
|
||||
*/
|
||||
char *message;
|
||||
/**
|
||||
* @brief 消息字符串的长度
|
||||
*/
|
||||
uint32_t message_len;
|
||||
} aiot_devinfo_recv_generic_reply_t;
|
||||
|
||||
/**
|
||||
* @brief devinfo模块收到从网络上来的报文时, 通知用户的报文内容
|
||||
*/
|
||||
typedef struct {
|
||||
char *product_key;
|
||||
char *device_name;
|
||||
/**
|
||||
* @brief 报文内容所对应的报文类型, 更多信息请参考@ref aiot_devinfo_recv_type_t
|
||||
*/
|
||||
aiot_devinfo_recv_type_t type;
|
||||
union {
|
||||
/**
|
||||
* @brief 从云端收到的更新或删除设备标签的应答
|
||||
*/
|
||||
aiot_devinfo_recv_generic_reply_t generic_reply;
|
||||
} data;
|
||||
} aiot_devinfo_recv_t;
|
||||
|
||||
/**
|
||||
* @brief devinfo模块收到从网络上来的报文时, 通知用户所调用的数据回调函数
|
||||
*
|
||||
* @param[in] handle devinfo会话句柄
|
||||
* @param[in] packet devinfo消息结构体, 存放收到的devinfo报文内容
|
||||
* @param[in] userdata 用户上下文
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (* aiot_devinfo_recv_handler_t)(void *handle, const aiot_devinfo_recv_t *packet, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief devinfo模块内部发生值得用户关注的状态变化时, 通知用户的事件类型
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 收到的应答中设备信息不合法, 无法获取product key和device name
|
||||
*/
|
||||
AIOT_DEVINFOEVT_INVALID_DEVINFO,
|
||||
/**
|
||||
* @brief 收到的应答中字段不合法
|
||||
*/
|
||||
AIOT_DEVINFOEVT_INVALID_RESPONSE,
|
||||
/**
|
||||
* @brief 收到的应答中字段格式错误
|
||||
*/
|
||||
AIOT_DEVINFOEVT_INVALID_RESPONSE_FORMAT,
|
||||
} aiot_devinfo_event_type_t;
|
||||
|
||||
/**
|
||||
* @brief devinfo模块内部发生值得用户关注的状态变化时, 通知用户的事件内容
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 事件内容所对应的事件类型, 更多信息请参考@ref aiot_devinfo_event_type_t
|
||||
*/
|
||||
aiot_devinfo_event_type_t type;
|
||||
} aiot_devinfo_event_t;
|
||||
|
||||
/**
|
||||
* @brief devinfo模块内部发生值得用户关注的状态变化时, 通知用户所调用的事件回调函数
|
||||
*
|
||||
* @param[in] handle, devinfo会话句柄
|
||||
* @param[in] event, devinfo模块中发生的事件的内容
|
||||
* @param[in] userdata, 用户上下文
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (*aiot_devinfo_event_handler_t)(void *handle, const aiot_devinfo_event_t *event, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief @ref aiot_devinfo_msg_t 中的发送消息类型
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 消息类型有两个, 分别是更新设备标签和删除设备标签
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 更新设备标签
|
||||
*/
|
||||
AIOT_DEVINFO_MSG_UPDATE,
|
||||
/**
|
||||
* @brief 删除设备标签
|
||||
*/
|
||||
AIOT_DEVINFO_MSG_DELETE
|
||||
} aiot_devinfo_msg_type_t;
|
||||
|
||||
/**
|
||||
* @brief 更新或删除设备标签的params内容
|
||||
*/
|
||||
typedef struct {
|
||||
char *params;
|
||||
} aiot_devinfo_msg_data_t;
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 设备的product key
|
||||
*/
|
||||
char *product_key;
|
||||
/**
|
||||
* @brief 设备的device name
|
||||
*/
|
||||
char *device_name;
|
||||
/**
|
||||
* @brief 消息类型, 更多信息请参考@ref aiot_devinfo_msg_type_t
|
||||
*/
|
||||
aiot_devinfo_msg_type_t type;
|
||||
union {
|
||||
/**
|
||||
* @brief 更新设备标签, 格式:"[{\"attrKey\":\"xxx\",\"attrValue\":\"yyy\"}]"
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 从上述格式可以看出,更新设备标签的格式是一个JSON数组,一次可按attrKey和attrValue上报多组设备标签
|
||||
*/
|
||||
aiot_devinfo_msg_data_t update;
|
||||
/**
|
||||
* @brief 删除设备标签, 格式:"[{\"attrKey\":\"xxx\"}]"
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 从上述格式可以看出,删除设备标签的格式是一个JSON数组,一次可按attrKey删除多组设备标签
|
||||
*/
|
||||
aiot_devinfo_msg_data_t delete;
|
||||
} data;
|
||||
} aiot_devinfo_msg_t;
|
||||
|
||||
/**
|
||||
* @brief @ref aiot_devinfo_setopt 接口的option参数可选值.
|
||||
*
|
||||
* @details 下文每个选项中的数据类型, 指的是@ref aiot_devinfo_setopt 中, data参数的数据类型
|
||||
*
|
||||
* 1. data的数据类型是void *时, 以配置@ref AIOT_DEVINFOOPT_MQTT_HANDLE 为例:
|
||||
*
|
||||
* void *mqtt_handle = aiot_mqtt_init();
|
||||
* aiot_devinfo_setopt(devinfo_handle, AIOT_DEVINFOOPT_MQTT_HANDLE, mqtt_handle);
|
||||
*
|
||||
* 2. data的数据类型是其他数据类型时, 以配置@ref AIOT_DEVINFOOPT_DEINIT_TIMEOUT_MS 为例:
|
||||
*
|
||||
* uint32_t deinit_timeout_ms = 443;
|
||||
* aiot_devinfo_setopt(devinfo_handle, AIOT_DEVINFOOPT_DEINIT_TIMEOUT_MS, (void *)&deinit_timeout_ms);
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief devinfo会话 需要的MQTT句柄, 需要先建立MQTT连接, 再设置MQTT句柄
|
||||
*/
|
||||
AIOT_DEVINFOOPT_MQTT_HANDLE,
|
||||
|
||||
/**
|
||||
* @brief 设置回调, 它在SDK收到网络报文的时候被调用, 告知用户
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: ( @ref aiot_devinfo_recv_handler_t)
|
||||
*/
|
||||
AIOT_DEVINFOOPT_RECV_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief 设置回调, 它在SDK发生内部状态变更时被调用, 告知用户
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: ( @ref aiot_devinfo_event_handler_t)
|
||||
*/
|
||||
AIOT_DEVINFOOPT_EVENT_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief 用户需要SDK暂存的上下文, 数据类型为(void *)
|
||||
*
|
||||
* @details 这个上下文指针会在 AIOT_DEVINFOOPT_RECV_HANDLER 和 AIOT_DEVINFOOPT_EVENT_HANDLER 设置的回调被调用时, 由SDK传给用户
|
||||
*/
|
||||
AIOT_DEVINFOOPT_USERDATA,
|
||||
|
||||
/**
|
||||
* @brief 销毁devinfo实例时, 等待其他api执行完毕的时间
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 当调用@ref aiot_devinfo_deinit 销毁devinfo实例时, 若继续调用其他aiot_devinfo_xxx API, API会返回@ref STATE_USER_INPUT_EXEC_DISABLED 错误
|
||||
*
|
||||
* 此时, 用户应该停止调用其他aiot_devinfo_xxx API
|
||||
*
|
||||
* 数据类型: (uint32_t *) 默认值: (2 * 1000) ms
|
||||
*/
|
||||
AIOT_DEVINFOOPT_DEINIT_TIMEOUT_MS,
|
||||
AIOT_DEVINFOOPT_MAX
|
||||
} aiot_devinfo_option_t;
|
||||
|
||||
/**
|
||||
* @brief 创建devinfo会话实例, 并以默认值配置会话参数
|
||||
*
|
||||
* @return void *
|
||||
* @retval 非NULL devinfo实例的句柄
|
||||
* @retval NULL 初始化失败, 一般是内存分配失败导致
|
||||
*
|
||||
*/
|
||||
void *aiot_devinfo_init(void);
|
||||
|
||||
/**
|
||||
* @brief 配置devinfo会话
|
||||
*
|
||||
* @param[in] handle devinfo会话句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_devinfo_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_devinfo_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 参数配置失败
|
||||
* @retval >=STATE_SUCCESS 参数配置成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_devinfo_setopt(void *handle, aiot_devinfo_option_t option, void *data);
|
||||
|
||||
/**
|
||||
* @brief 结束devinfo会话, 销毁实例并回收资源
|
||||
*
|
||||
* @param[in] handle 指向devinfo会话句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 执行失败
|
||||
* @retval >=STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_devinfo_deinit(void **handle);
|
||||
|
||||
/**
|
||||
* @brief 向devinfo服务器发送devinfo消息请求
|
||||
*
|
||||
* @param handle devinfo会话句柄
|
||||
* @param msg devinfo发送给云端的删除/更新设备标签信息的报文
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 请求发送失败
|
||||
* @retval >=STATE_SUCCESS 请求发送成功
|
||||
*/
|
||||
int32_t aiot_devinfo_send(void *handle, aiot_devinfo_msg_t *msg);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AIOT_DEVINFO_API_H__ */
|
||||
|
||||
57
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/devinfo/devinfo_private.h
vendored
Normal file
57
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/devinfo/devinfo_private.h
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file devinfo_private.h
|
||||
* @brief devinfo模块内部的宏定义和数据结构声明, 不面向其它模块, 更不面向用户
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __DEVINFO_PRIVATE_H__
|
||||
#define __DEVINFO_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_stdinc.h"
|
||||
|
||||
/* TODO: 这一段列出需要包含SDK其它模块头文件, 与上一段落以1个空行隔开 */
|
||||
#include "aiot_state_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_mqtt_api.h"
|
||||
#include "aiot_devinfo_api.h" /* 内部头文件是用户可见头文件的超集 */
|
||||
|
||||
typedef struct {
|
||||
aiot_sysdep_portfile_t *sysdep; /* 底层依赖回调合集的引用指针 */
|
||||
void *mqtt_handle;
|
||||
|
||||
aiot_devinfo_event_handler_t event_handler; /* 组件内部运行状态变更时, 通知用户的回调 */
|
||||
aiot_devinfo_recv_handler_t recv_handler; /* 组件从协议栈读到内容时, 通知用户的回调 */
|
||||
void *userdata; /* 组件调用以上2个 devinfo_handler 时的入参之一 */
|
||||
|
||||
uint32_t deinit_timeout_ms;
|
||||
|
||||
/*---- 以上都是用户在API可配 ----*/
|
||||
|
||||
/*---- 以下都是DEVINFO在内部使用, 用户无感知 ----*/
|
||||
|
||||
void *data_mutex; /* 保护本地的数据结构 */
|
||||
uint8_t exec_enabled;
|
||||
uint32_t exec_count;
|
||||
} devinfo_handle_t;
|
||||
|
||||
#define DEVINFO_MODULE_NAME "devinfo" /* 用于内存统计的模块名字符串 */
|
||||
|
||||
#define DEVINFO_DEFAULT_DEINIT_TIMEOUT_MS (2 * 1000)
|
||||
|
||||
#define DEVINFO_UPDATE_TOPIC_FMT "/sys/%s/%s/thing/deviceinfo/update"
|
||||
#define DEVINFO_UPDATE_REPLY_TOPIC "/sys/+/+/thing/deviceinfo/update_reply"
|
||||
#define DEVINFO_DELETE_TOPIC_FMT "/sys/%s/%s/thing/deviceinfo/delete"
|
||||
#define DEVINFO_DELETE_REPLY_TOPIC "/sys/+/+/thing/deviceinfo/delete_reply"
|
||||
|
||||
#define DEVINFO_DEINIT_INTERVAL_MS (100)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* __DEVINFO_PRIVATE_H__ */
|
||||
|
||||
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/diag/README.md
vendored
Normal file
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/diag/README.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Name: 设备诊断模块
|
||||
DIAG Component for Link SDK V4.0.0
|
||||
|
||||
763
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/diag/aiot_diag_api.c
vendored
Normal file
763
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/diag/aiot_diag_api.c
vendored
Normal file
@@ -0,0 +1,763 @@
|
||||
/**
|
||||
* @file aiot_diag_api.c
|
||||
* @brief diag模块的API接口实现, 提供诊断SDK的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
#include "diag_private.h"
|
||||
|
||||
#include "core_string.h"
|
||||
#include "core_log.h"
|
||||
#include "core_global.h"
|
||||
#include "core_mqtt.h"
|
||||
#include "core_diag.h"
|
||||
|
||||
static void _diag_mqtt_conn_hb_extra_clean(void *handle, void *extra_data);
|
||||
static int32_t _diag_mqtt_conn_hb_extra_stop(void *handle, diag_running_state_node_t *node, uint32_t stat_idx,
|
||||
uint32_t stat_number, void *extra_data);
|
||||
static int32_t _diag_mqtt_conn_report_desc_append(void *handle, diag_running_state_t *running_state,
|
||||
diag_running_state_node_t *node, char **desc);
|
||||
static int32_t _diag_mqtt_hb_report_desc_append(void *handle, diag_running_state_t *running_state,
|
||||
diag_running_state_node_t *node, char **desc);
|
||||
static void _diag_alink_uplink_extra_clean(void *handle, void *extra_data);
|
||||
static int32_t _diag_alink_uplink_extra_stop(void *handle, diag_running_state_node_t *node, uint32_t stat_idx,
|
||||
uint32_t stat_number, void *extra_data);
|
||||
static int32_t _diag_alink_uplink_report_desc_append(void *handle, diag_running_state_t *running_state,
|
||||
diag_running_state_node_t *node, char **desc);
|
||||
|
||||
static diag_config_t g_diag_config[] = {
|
||||
{
|
||||
DIAG_MQTT_CONNECTION_STAT_INDEX,
|
||||
DIAG_MQTT_CONNECTION_NAME_STR,
|
||||
DIAG_TLV_MQTT_CONNECTION,
|
||||
{
|
||||
DIAG_DEFAULT_MQTT_CONN_ENABLED,
|
||||
DIAG_DEFAULT_MQTT_CONN_INTERVAL_MS,
|
||||
DIAG_DEFAULT_MQTT_CONN_WARNING_THRESHOLD,
|
||||
DIAG_DEFAULT_MQTT_CONN_FATAL_THRESHOLD,
|
||||
},
|
||||
DIAG_DEFAULT_MQTT_CONN_MAX_STAT_NUMBER,
|
||||
{
|
||||
_diag_mqtt_conn_hb_extra_clean,
|
||||
_diag_mqtt_conn_hb_extra_stop,
|
||||
_diag_mqtt_conn_report_desc_append
|
||||
},
|
||||
1
|
||||
},
|
||||
{
|
||||
DIAG_MQTT_HEARTBEAT_STAT_INDEX,
|
||||
DIAG_MQTT_HEARTBEAT_NAME_STR,
|
||||
DIAG_TLV_MQTT_HEARTBEAT,
|
||||
{
|
||||
DIAG_DEFAULT_MQTT_HB_ENABLED,
|
||||
DIAG_DEFAULT_MQTT_HB_INTERVAL_MS,
|
||||
DIAG_DEFAULT_MQTT_HB_WARNING_THRESHOLD,
|
||||
DIAG_DEFAULT_MQTT_HB_FATAL_THRESHOLD
|
||||
},
|
||||
DIAG_DEFAULT_MQTT_HB_MAX_STAT_NUMBER,
|
||||
{
|
||||
_diag_mqtt_conn_hb_extra_clean,
|
||||
_diag_mqtt_conn_hb_extra_stop,
|
||||
_diag_mqtt_hb_report_desc_append,
|
||||
},
|
||||
0
|
||||
},
|
||||
{
|
||||
DIAG_ALINK_UPLINK_STAT_INDEX,
|
||||
DIAG_ALINK_UPLINK_NAME_STR,
|
||||
DIAG_TLV_ALINK_UPLINK,
|
||||
{
|
||||
DIAG_DEFAULT_ALINK_UPLINK_ENABLED,
|
||||
DIAG_DEFAULT_ALINK_UPLINK_INTERVAL_MS,
|
||||
DIAG_DEFAULT_ALINK_UPLINK_WARNING_THRESHOLD,
|
||||
DIAG_DEFAULT_ALINK_UPLINK_FATAL_THRESHOLD
|
||||
},
|
||||
DIAG_DEFAULT_ALINK_UPLINK_MAX_STAT_NUMBER,
|
||||
{
|
||||
_diag_alink_uplink_extra_clean,
|
||||
_diag_alink_uplink_extra_stop,
|
||||
_diag_alink_uplink_report_desc_append
|
||||
},
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
static void _core_diag_exec_inc(diag_handle_t *diag_handle)
|
||||
{
|
||||
diag_handle->sysdep->core_sysdep_mutex_lock(diag_handle->data_mutex);
|
||||
diag_handle->exec_count++;
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(diag_handle->data_mutex);
|
||||
}
|
||||
|
||||
static void _core_diag_exec_dec(diag_handle_t *diag_handle)
|
||||
{
|
||||
diag_handle->sysdep->core_sysdep_mutex_lock(diag_handle->data_mutex);
|
||||
diag_handle->exec_count--;
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(diag_handle->data_mutex);
|
||||
}
|
||||
|
||||
static void _diag_desc_list_append(diag_handle_t *diag_handle, diag_stat_t *stat,
|
||||
diag_running_state_node_t *running_state_node, struct core_list_head *desc_list)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *desc = NULL;
|
||||
diag_desc_node_t *node = NULL;
|
||||
|
||||
res = stat->stat_cb.desc_append_cb(diag_handle, &stat->running_state, running_state_node, &desc);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
node = diag_handle->sysdep->core_sysdep_malloc(sizeof(diag_desc_node_t), DIAG_MODULE_NAME);
|
||||
if (node == NULL) {
|
||||
diag_handle->sysdep->core_sysdep_free(desc);
|
||||
return;
|
||||
}
|
||||
memset(node, 0, sizeof(diag_desc_node_t));
|
||||
node->timestamp = core_log_get_timestamp(diag_handle->sysdep);
|
||||
node->code = stat->running_state.code;
|
||||
node->module_name = stat->running_state.name;
|
||||
node->level = (stat->running_state.is_reported == 0) ? (running_state_node->level) : (DIAG_REPORT_LEVEL_WARNING_STR);
|
||||
node->desc = desc;
|
||||
node->qos = stat->running_state.qos;
|
||||
CORE_INIT_LIST_HEAD(&node->linked_node);
|
||||
|
||||
core_list_add_tail(&node->linked_node, desc_list);
|
||||
}
|
||||
|
||||
static void _diag_desc_list_send(diag_handle_t *diag_handle, struct core_list_head *desc_list)
|
||||
{
|
||||
diag_desc_node_t *node = NULL;
|
||||
|
||||
core_list_for_each_entry(node, desc_list, linked_node, diag_desc_node_t) {
|
||||
/* local event notify */
|
||||
if ((diag_handle->event_handler != NULL) && (diag_handle->local_report_enabled == 1)) {
|
||||
aiot_diag_event_t event;
|
||||
|
||||
memset(&event, 0, sizeof(aiot_diag_event_t));
|
||||
event.type = AIOT_DIAGEVT_ALERT;
|
||||
event.data.alert.module_name = node->module_name;
|
||||
event.data.alert.level = node->level;
|
||||
event.data.alert.desc = node->desc;
|
||||
|
||||
diag_handle->event_handler(diag_handle, &event, diag_handle->userdata);
|
||||
}
|
||||
|
||||
/* cloud event report */
|
||||
if (diag_handle->cloud_report_enabled == 1) {
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *topic = NULL, *topic_fmt = DIAG_REPORT_TOPIC_FMT;
|
||||
char *topic_src[] = { core_mqtt_get_product_key(diag_handle->mqtt_handle), core_mqtt_get_device_name(diag_handle->mqtt_handle) };
|
||||
int32_t alink_id = 0;
|
||||
char alink_id_str[11] = {0}, utc_time_str[21] = {0}, code_str[11] = {0};
|
||||
char *payload = NULL, *payload_fmt = DIAG_REPORT_PAYLOAD_FMT;
|
||||
char *payload_src[] = { alink_id_str, utc_time_str, node->level, node->module_name, code_str, alink_id_str, node->desc };
|
||||
|
||||
res = core_sprintf(diag_handle->sysdep, &topic, topic_fmt, topic_src, sizeof(topic_src) / sizeof(char *),
|
||||
DIAG_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
core_global_alink_id_next(diag_handle->sysdep, &alink_id);
|
||||
core_int2str(alink_id, alink_id_str, NULL);
|
||||
core_uint642str(node->timestamp, utc_time_str, NULL);
|
||||
core_uint2str(node->code, code_str, NULL);
|
||||
res = core_sprintf(diag_handle->sysdep, &payload, payload_fmt, payload_src, sizeof(payload_src) / sizeof(char *),
|
||||
DIAG_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
diag_handle->sysdep->core_sysdep_free(topic);
|
||||
continue;
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(diag_handle->mqtt_handle, topic, (uint8_t *)payload, (uint32_t)strlen(payload), node->qos);
|
||||
if (res < STATE_SUCCESS) {
|
||||
core_log(diag_handle->sysdep, STATE_DIAG_PUB_FAILED, "pub failed\r\n");
|
||||
}
|
||||
|
||||
diag_handle->sysdep->core_sysdep_free(topic);
|
||||
diag_handle->sysdep->core_sysdep_free(payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _diag_desc_list_destroy(diag_handle_t *diag_handle, struct core_list_head *desc_list)
|
||||
{
|
||||
diag_desc_node_t *node = NULL, *next = NULL;
|
||||
|
||||
core_list_for_each_entry_safe(node, next, desc_list, linked_node, diag_desc_node_t) {
|
||||
core_list_del(&node->linked_node);
|
||||
diag_handle->sysdep->core_sysdep_free(node->desc);
|
||||
diag_handle->sysdep->core_sysdep_free(node);
|
||||
}
|
||||
}
|
||||
|
||||
static void _diag_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
|
||||
{
|
||||
uint32_t stat_idx = 0;
|
||||
diag_handle_t *diag_handle = (diag_handle_t *)context;
|
||||
uint64_t timenow_ms = core_log_get_timestamp(diag_handle->sysdep);
|
||||
|
||||
if (core_event != NULL) {
|
||||
switch (core_event->type) {
|
||||
case CORE_MQTTEVT_DEINIT: {
|
||||
diag_handle->mqtt_handle = NULL;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (diag_handle->mqtt_process.last_check_time > timenow_ms) {
|
||||
diag_handle->mqtt_process.last_check_time = timenow_ms;
|
||||
}
|
||||
|
||||
if (timenow_ms - diag_handle->mqtt_process.last_check_time >= DIAG_MQTT_PROCESS_CHECK_INTERVAL_MS) {
|
||||
diag_running_state_node_t *node = NULL;
|
||||
struct core_list_head desc_list;
|
||||
|
||||
CORE_INIT_LIST_HEAD(&desc_list);
|
||||
|
||||
for (stat_idx = 0; stat_idx < DIAG_STAT_ITEM_NUMBER; stat_idx++) {
|
||||
diag_handle->sysdep->core_sysdep_mutex_lock(diag_handle->diag_stat[stat_idx].running_state.mutex);
|
||||
diag_handle->diag_stat[stat_idx].running_state.alert_counts = 0;
|
||||
core_list_for_each_entry(node, &diag_handle->diag_stat[stat_idx].running_state.linked_list,
|
||||
linked_node, diag_running_state_node_t) {
|
||||
if ((node->stop_time != 0) && (node->start_time > node->stop_time)) {
|
||||
node->start_time = node->stop_time;
|
||||
}
|
||||
if (node->is_diag == 1) {
|
||||
if (node->start_time > timenow_ms) {
|
||||
node->start_time = timenow_ms;
|
||||
}
|
||||
if (node->stop_time == 0
|
||||
&& (timenow_ms - node->start_time >= diag_handle->diag_stat[stat_idx].config.fatal_threshold)) {
|
||||
node->stop_time = node->start_time + diag_handle->diag_stat[stat_idx].config.fatal_threshold;
|
||||
}
|
||||
if (node->stop_time != 0) {
|
||||
if ((node->stop_time - node->start_time >= diag_handle->diag_stat[stat_idx].config.warning_threashold) &&
|
||||
(node->stop_time - node->start_time < diag_handle->diag_stat[stat_idx].config.fatal_threshold)) {
|
||||
node->level = DIAG_REPORT_LEVEL_WARNING_STR;
|
||||
} else if (node->stop_time - node->start_time >= diag_handle->diag_stat[stat_idx].config.fatal_threshold) {
|
||||
node->level = DIAG_REPORT_LEVEL_FATAL_STR;
|
||||
}
|
||||
node->is_diag = 0;
|
||||
}
|
||||
if ((diag_handle->diag_stat[stat_idx].running_state.is_reported == 0) && (node->level != NULL)) {
|
||||
/* report first in current period*/
|
||||
_diag_desc_list_append(diag_handle, &diag_handle->diag_stat[stat_idx], node, &desc_list);
|
||||
diag_handle->diag_stat[stat_idx].running_state.is_reported = 1;
|
||||
diag_handle->diag_stat[stat_idx].running_state.report_start_time = timenow_ms;
|
||||
}
|
||||
}
|
||||
if ((node->start_time >= diag_handle->diag_stat[stat_idx].running_state.report_start_time) && node->level != NULL) {
|
||||
diag_handle->diag_stat[stat_idx].running_state.alert_counts++;
|
||||
}
|
||||
if (diag_handle->diag_stat[stat_idx].running_state.report_start_time > timenow_ms) {
|
||||
diag_handle->diag_stat[stat_idx].running_state.report_start_time = timenow_ms;
|
||||
}
|
||||
if ((diag_handle->diag_stat[stat_idx].running_state.is_reported == 1) &&
|
||||
(timenow_ms - diag_handle->diag_stat[stat_idx].running_state.report_start_time >=
|
||||
diag_handle->diag_stat[stat_idx].config.interval_ms) &&
|
||||
(node->linked_node.next == &diag_handle->diag_stat[stat_idx].running_state.linked_list)) {
|
||||
/* report alert counts in this period */
|
||||
if (diag_handle->diag_stat[stat_idx].running_state.alert_counts > 0) {
|
||||
_diag_desc_list_append(diag_handle, &diag_handle->diag_stat[stat_idx], node, &desc_list);
|
||||
}
|
||||
diag_handle->diag_stat[stat_idx].running_state.is_reported = 0;
|
||||
diag_handle->diag_stat[stat_idx].running_state.report_start_time = timenow_ms;
|
||||
}
|
||||
}
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(diag_handle->diag_stat[stat_idx].running_state.mutex);
|
||||
}
|
||||
|
||||
_diag_desc_list_send(diag_handle, &desc_list);
|
||||
_diag_desc_list_destroy(diag_handle, &desc_list);
|
||||
|
||||
diag_handle->mqtt_process.last_check_time = timenow_ms;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _diag_core_mqtt_operate_process_handler(diag_handle_t *diag_handle, core_mqtt_option_t option)
|
||||
{
|
||||
core_mqtt_process_data_t process_data;
|
||||
|
||||
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
|
||||
process_data.handler = _diag_core_mqtt_process_handler;
|
||||
process_data.context = diag_handle;
|
||||
|
||||
return core_mqtt_setopt(diag_handle->mqtt_handle, option, &process_data);
|
||||
}
|
||||
|
||||
static void _diag_mqtt_conn_hb_extra_clean(void *handle, void *extra_data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int32_t _diag_mqtt_conn_hb_extra_stop(void *handle, diag_running_state_node_t *node, uint32_t stat_idx,
|
||||
uint32_t stat_number, void *extra_data)
|
||||
{
|
||||
if (node->stop_time != 0) {
|
||||
return STATE_DIAG_STOP_NODE_NOT_MATCH;
|
||||
}
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t _diag_mqtt_conn_report_desc_append(void *handle, diag_running_state_t *running_state,
|
||||
diag_running_state_node_t *node, char **desc)
|
||||
{
|
||||
char *tmp_desc = NULL;
|
||||
diag_handle_t *diag_handle = (diag_handle_t *)handle;
|
||||
uint64_t timenow_ms = core_log_get_timestamp(diag_handle->sysdep);
|
||||
|
||||
if (running_state->is_reported == 0) {
|
||||
/* report first time */
|
||||
uint64_t time_elapsed = node->stop_time - node->start_time;
|
||||
char time_elapsed_str[21] = {0};
|
||||
char *desc_fmt = "MQTT connection establish time %s ms";
|
||||
char *desc_src[] = { time_elapsed_str };
|
||||
|
||||
core_uint642str(time_elapsed, time_elapsed_str, NULL);
|
||||
core_sprintf(diag_handle->sysdep, &tmp_desc, desc_fmt, desc_src, sizeof(desc_src) / sizeof(char *), DIAG_MODULE_NAME);
|
||||
} else if (running_state->is_reported == 1) {
|
||||
/* report period stat data */
|
||||
uint64_t time_elapsed = timenow_ms - running_state->report_start_time;
|
||||
char time_elapsed_str[21] = {0};
|
||||
char alert_counts_str[11] = {0};
|
||||
char *desc_fmt = "MQTT connection has been alert extra %s times in past %s ms";
|
||||
char *desc_src[] = { alert_counts_str, time_elapsed_str };
|
||||
|
||||
core_uint642str(time_elapsed, time_elapsed_str, NULL);
|
||||
core_uint2str(running_state->alert_counts, alert_counts_str, NULL);
|
||||
core_sprintf(diag_handle->sysdep, &tmp_desc, desc_fmt, desc_src, sizeof(desc_src) / sizeof(char *), DIAG_MODULE_NAME);
|
||||
}
|
||||
|
||||
if (tmp_desc == NULL) {
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
*desc = tmp_desc;
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t _diag_mqtt_hb_report_desc_append(void *handle, diag_running_state_t *running_state,
|
||||
diag_running_state_node_t *node, char **desc)
|
||||
{
|
||||
char *tmp_desc = NULL;
|
||||
diag_handle_t *diag_handle = (diag_handle_t *)handle;
|
||||
uint64_t timenow_ms = core_log_get_timestamp(diag_handle->sysdep);
|
||||
|
||||
if (running_state->is_reported == 0) {
|
||||
/* report first time */
|
||||
uint64_t time_elapsed = node->stop_time - node->start_time;
|
||||
char time_elapsed_str[21] = {0};
|
||||
char *desc_fmt = "MQTT lost heartbeat 1 times in %s ms";
|
||||
char *desc_src[] = { time_elapsed_str };
|
||||
|
||||
core_uint642str(time_elapsed, time_elapsed_str, NULL);
|
||||
core_sprintf(diag_handle->sysdep, &tmp_desc, desc_fmt, desc_src, sizeof(desc_src) / sizeof(char *), DIAG_MODULE_NAME);
|
||||
} else if (running_state->is_reported == 1) {
|
||||
/* report period stat data */
|
||||
uint64_t time_elapsed = timenow_ms - running_state->report_start_time;
|
||||
char time_elapsed_str[21] = {0};
|
||||
char alert_counts_str[11] = {0};
|
||||
char *desc_fmt = "MQTT lost heartbeat has been alert extra %s times in past %s ms";
|
||||
char *desc_src[] = { alert_counts_str, time_elapsed_str };
|
||||
|
||||
core_uint642str(time_elapsed, time_elapsed_str, NULL);
|
||||
core_uint2str(running_state->alert_counts, alert_counts_str, NULL);
|
||||
core_sprintf(diag_handle->sysdep, &tmp_desc, desc_fmt, desc_src, sizeof(desc_src) / sizeof(char *), DIAG_MODULE_NAME);
|
||||
}
|
||||
|
||||
if (tmp_desc == NULL) {
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
*desc = tmp_desc;
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static void _diag_alink_uplink_extra_clean(void *handle, void *extra_data)
|
||||
{
|
||||
diag_handle_t *diag_handle = (diag_handle_t *)handle;
|
||||
|
||||
diag_handle->sysdep->core_sysdep_free(extra_data);
|
||||
}
|
||||
|
||||
static int32_t _diag_alink_uplink_extra_stop(void *handle, diag_running_state_node_t *node, uint32_t stat_idx,
|
||||
uint32_t stat_number, void *extra_data)
|
||||
{
|
||||
if (*(uint32_t *)node->extra_data != *(uint32_t *)extra_data) {
|
||||
return STATE_DIAG_STOP_NODE_NOT_MATCH;
|
||||
}
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t _diag_alink_uplink_report_desc_append(void *handle, diag_running_state_t *running_state,
|
||||
diag_running_state_node_t *node, char **desc)
|
||||
{
|
||||
char *tmp_desc = NULL;
|
||||
diag_handle_t *diag_handle = (diag_handle_t *)handle;
|
||||
uint64_t timenow_ms = core_log_get_timestamp(diag_handle->sysdep);
|
||||
|
||||
if (running_state->is_reported == 0) {
|
||||
/* report first time */
|
||||
char alink_id_str[11] = {0};
|
||||
uint64_t time_elapsed = node->stop_time - node->start_time;
|
||||
char time_elapsed_str[21] = {0};
|
||||
char *desc_fmt = "Alink message %s waiting for reply has already exceed %s ms";
|
||||
char *desc_src[] = { alink_id_str, time_elapsed_str };
|
||||
|
||||
core_uint2str(*(uint32_t *)node->extra_data, alink_id_str, NULL);
|
||||
core_uint642str(time_elapsed, time_elapsed_str, NULL);
|
||||
core_sprintf(diag_handle->sysdep, &tmp_desc, desc_fmt, desc_src, sizeof(desc_src) / sizeof(char *), DIAG_MODULE_NAME);
|
||||
} else if (running_state->is_reported == 1) {
|
||||
/* report period stat data */
|
||||
uint64_t time_elapsed = timenow_ms - running_state->report_start_time;
|
||||
char time_elapsed_str[21] = {0};
|
||||
char alert_counts_str[11] = {0};
|
||||
char *desc_fmt = "Alink message reply too slow has been alert extra %s times in past %s ms";
|
||||
char *desc_src[] = { alert_counts_str, time_elapsed_str };
|
||||
|
||||
core_uint642str(time_elapsed, time_elapsed_str, NULL);
|
||||
core_uint2str(running_state->alert_counts, alert_counts_str, NULL);
|
||||
core_sprintf(diag_handle->sysdep, &tmp_desc, desc_fmt, desc_src, sizeof(desc_src) / sizeof(char *), DIAG_MODULE_NAME);
|
||||
}
|
||||
|
||||
if (tmp_desc == NULL) {
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
*desc = tmp_desc;
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static void _diag_running_state_start(diag_handle_t *diag_handle, diag_stat_t *stat, uint64_t timestamp,
|
||||
void *extra_data)
|
||||
{
|
||||
diag_running_state_node_t *node = NULL;
|
||||
|
||||
diag_handle->sysdep->core_sysdep_mutex_lock(stat->running_state.mutex);
|
||||
if (stat->running_state.stat_number == stat->running_state.max_stat_number) {
|
||||
node = core_list_entry(stat->running_state.linked_list.next, diag_running_state_node_t, linked_node);
|
||||
core_list_del(&node->linked_node);
|
||||
stat->running_state.stat_number--;
|
||||
stat->stat_cb.extra_clean_cb(diag_handle, node->extra_data);
|
||||
diag_handle->sysdep->core_sysdep_free(node);
|
||||
}
|
||||
|
||||
node = diag_handle->sysdep->core_sysdep_malloc(sizeof(diag_running_state_node_t), DIAG_MODULE_NAME);
|
||||
if (node == NULL) {
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(stat->running_state.mutex);
|
||||
return;
|
||||
}
|
||||
memset(node, 0, sizeof(diag_running_state_node_t));
|
||||
node->is_diag = 1;
|
||||
node->start_time = timestamp;
|
||||
node->extra_data = extra_data;
|
||||
CORE_INIT_LIST_HEAD(&node->linked_node);
|
||||
|
||||
core_list_add_tail(&node->linked_node, &stat->running_state.linked_list);
|
||||
stat->running_state.stat_number++;
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(stat->running_state.mutex);
|
||||
}
|
||||
|
||||
static void _diag_running_state_stop(diag_handle_t *diag_handle, diag_stat_t *stat, uint64_t timestamp,
|
||||
void *extra_data)
|
||||
{
|
||||
uint32_t stat_idx = 0;
|
||||
diag_running_state_node_t *node = NULL;
|
||||
|
||||
diag_handle->sysdep->core_sysdep_mutex_lock(stat->running_state.mutex);
|
||||
core_list_for_each_entry(node, &stat->running_state.linked_list,
|
||||
linked_node, diag_running_state_node_t) {
|
||||
if (stat->stat_cb.extra_stop_cb(diag_handle, node,
|
||||
stat_idx, stat->running_state.stat_number, extra_data) >= STATE_SUCCESS) {
|
||||
node->stop_time = timestamp;
|
||||
break;
|
||||
}
|
||||
stat_idx++;
|
||||
}
|
||||
stat->stat_cb.extra_clean_cb(diag_handle, extra_data);
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(stat->running_state.mutex);
|
||||
}
|
||||
|
||||
static int32_t _diag_get_extra_data(diag_handle_t *diag_handle, diag_raw_data_t *raw_data, uint32_t code,
|
||||
void **out_extra_data)
|
||||
{
|
||||
if (code == DIAG_TLV_ALINK_UPLINK) {
|
||||
uint32_t tlv_sub_type1 = (raw_data->data[4] << 8) | (raw_data->data[5]);
|
||||
if (tlv_sub_type1 == DIAG_TLV_ALINK_MSGID) {
|
||||
uint32_t *extra_data = NULL;
|
||||
extra_data = diag_handle->sysdep->core_sysdep_malloc(sizeof(uint32_t), DIAG_MODULE_NAME);
|
||||
if (extra_data == NULL) {
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
memset(extra_data, 0, sizeof(uint32_t));
|
||||
*extra_data = ((raw_data->data[7] << 24) | (raw_data->data[8] << 16) | (raw_data->data[9] << 8) | (raw_data->data[10]));
|
||||
*(uint32_t **)out_extra_data = extra_data;
|
||||
}
|
||||
}
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static void _diag_raw_data(diag_handle_t *diag_handle, diag_raw_data_t *raw_data)
|
||||
{
|
||||
uint32_t code = (raw_data->data[0] << 8) | (raw_data->data[1]);
|
||||
uint32_t stat_idx = 0;
|
||||
void *extra_data = NULL;
|
||||
|
||||
for (stat_idx = 0; stat_idx < DIAG_STAT_ITEM_NUMBER; stat_idx++) {
|
||||
if (g_diag_config[stat_idx].code == code) {
|
||||
if (_diag_get_extra_data(diag_handle, raw_data, code, &extra_data) < STATE_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
if (raw_data->data[3] == 0x00) {
|
||||
_diag_running_state_start(diag_handle, &diag_handle->diag_stat[stat_idx], raw_data->timestamp, extra_data);
|
||||
} else if (raw_data->data[3] == 0x01) {
|
||||
_diag_running_state_stop(diag_handle, &diag_handle->diag_stat[stat_idx], raw_data->timestamp, extra_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _diag_core_diag_callback(void *handle, uint64_t timestamp, int32_t code, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
diag_raw_data_t raw_data;
|
||||
|
||||
memset(&raw_data, 0, sizeof(diag_raw_data_t));
|
||||
raw_data.timestamp = timestamp;
|
||||
raw_data.code = code;
|
||||
raw_data.data = data;
|
||||
raw_data.data_len = data_len;
|
||||
|
||||
_diag_raw_data((diag_handle_t *)handle, &raw_data);
|
||||
}
|
||||
|
||||
static void _diag_running_state_clean(diag_handle_t *diag_handle)
|
||||
{
|
||||
uint32_t stat_idx = 0;
|
||||
diag_running_state_node_t *node = NULL, *next = NULL;
|
||||
|
||||
for (stat_idx = 0; stat_idx < DIAG_STAT_ITEM_NUMBER; stat_idx++) {
|
||||
diag_handle->sysdep->core_sysdep_mutex_lock(diag_handle->diag_stat[stat_idx].running_state.mutex);
|
||||
core_list_for_each_entry_safe(node, next, &diag_handle->diag_stat[stat_idx].running_state.linked_list,
|
||||
linked_node, diag_running_state_node_t) {
|
||||
core_list_del(&node->linked_node);
|
||||
diag_handle->diag_stat[stat_idx].stat_cb.extra_clean_cb(diag_handle, node->extra_data);
|
||||
diag_handle->sysdep->core_sysdep_free(node);
|
||||
}
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(diag_handle->diag_stat[stat_idx].running_state.mutex);
|
||||
diag_handle->sysdep->core_sysdep_mutex_deinit(&diag_handle->diag_stat[stat_idx].running_state.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void *aiot_diag_init(void)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
uint32_t stat_idx = 0;
|
||||
diag_handle_t *diag_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if (sysdep == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = core_global_init(sysdep);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
diag_handle = sysdep->core_sysdep_malloc(sizeof(diag_handle_t), DIAG_MODULE_NAME);
|
||||
if (diag_handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(diag_handle, 0, sizeof(diag_handle_t));
|
||||
|
||||
diag_handle->sysdep = sysdep;
|
||||
diag_handle->local_report_enabled = DIAG_DAFAULT_LOCAL_REPORT_ENABLED;
|
||||
diag_handle->cloud_report_enabled = DIAG_DAFAULT_CLOUD_REPORT_ENABLED;
|
||||
|
||||
for (stat_idx = 0; stat_idx < DIAG_STAT_ITEM_NUMBER; stat_idx++) {
|
||||
diag_handle->diag_stat[stat_idx].running_state.code = g_diag_config[stat_idx].code;
|
||||
diag_handle->diag_stat[stat_idx].running_state.name = g_diag_config[stat_idx].name;
|
||||
memcpy(&diag_handle->diag_stat[stat_idx].config, &g_diag_config[stat_idx].def_config, sizeof(aiot_diag_config_t));
|
||||
diag_handle->diag_stat[stat_idx].running_state.max_stat_number = g_diag_config[stat_idx].def_max_stat_number;
|
||||
memcpy(&diag_handle->diag_stat[stat_idx].stat_cb, &g_diag_config[stat_idx].def_stat_cb, sizeof(diag_stat_callback_t));
|
||||
diag_handle->diag_stat[stat_idx].running_state.qos = g_diag_config[stat_idx].qos;
|
||||
CORE_INIT_LIST_HEAD(&diag_handle->diag_stat[stat_idx].running_state.linked_list);
|
||||
diag_handle->diag_stat[stat_idx].running_state.mutex = diag_handle->sysdep->core_sysdep_mutex_init();
|
||||
}
|
||||
|
||||
diag_handle->deinit_timeout_ms = DIAG_DEFAULT_DEINIT_TIMEOUT_MS;
|
||||
|
||||
diag_handle->data_mutex = sysdep->core_sysdep_mutex_init();
|
||||
|
||||
diag_handle->exec_enabled = 1;
|
||||
|
||||
core_diag_set_cb(diag_handle, _diag_core_diag_callback);
|
||||
|
||||
return diag_handle;
|
||||
}
|
||||
|
||||
int32_t aiot_diag_setopt(void *handle, aiot_diag_option_t option, void *data)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
diag_handle_t *diag_handle = (diag_handle_t *)handle;
|
||||
|
||||
if (diag_handle == NULL || data == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (option >= AIOT_DIAGOPT_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
if (diag_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
_core_diag_exec_inc(diag_handle);
|
||||
|
||||
diag_handle->sysdep->core_sysdep_mutex_lock(diag_handle->data_mutex);
|
||||
switch (option) {
|
||||
case AIOT_DIAGOPT_MQTT_HANDLE: {
|
||||
diag_handle->mqtt_handle = data;
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(diag_handle->data_mutex);
|
||||
res = _diag_core_mqtt_operate_process_handler(diag_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER);
|
||||
diag_handle->sysdep->core_sysdep_mutex_lock(diag_handle->data_mutex);
|
||||
}
|
||||
break;
|
||||
case AIOT_DIAGOPT_LOCAL_REPORT_ENABLED: {
|
||||
diag_handle->local_report_enabled = *(uint8_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DIAGOPT_CLOUD_REPORT_ENABLED: {
|
||||
diag_handle->cloud_report_enabled = *(uint8_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DIAGOPT_MQTT_CONNECTION: {
|
||||
memcpy(&diag_handle->diag_stat[DIAG_MQTT_CONNECTION_STAT_INDEX].config, (aiot_diag_config_t *)data,
|
||||
sizeof(aiot_diag_config_t));
|
||||
}
|
||||
break;
|
||||
case AIOT_DIAGOPT_MQTT_HEARTBEAT: {
|
||||
memcpy(&diag_handle->diag_stat[DIAG_MQTT_HEARTBEAT_STAT_INDEX].config, (aiot_diag_config_t *)data,
|
||||
sizeof(aiot_diag_config_t));
|
||||
}
|
||||
break;
|
||||
case AIOT_DIAGOPT_ALINK_UPLINK: {
|
||||
memcpy(&diag_handle->diag_stat[DIAG_ALINK_UPLINK_STAT_INDEX].config, (aiot_diag_config_t *)data,
|
||||
sizeof(aiot_diag_config_t));
|
||||
}
|
||||
break;
|
||||
case AIOT_DIAGOPT_RECV_HANDLER: {
|
||||
diag_handle->recv_handler = (aiot_diag_recv_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DIAGOPT_EVENT_HANDLER: {
|
||||
diag_handle->event_handler = (aiot_diag_event_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DIAGOPT_USERDATA: {
|
||||
diag_handle->userdata = data;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
res = STATE_USER_INPUT_UNKNOWN_OPTION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(diag_handle->data_mutex);
|
||||
|
||||
_core_diag_exec_dec(diag_handle);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_diag_deinit(void **handle)
|
||||
{
|
||||
uint64_t deinit_timestart = 0;
|
||||
diag_handle_t *diag_handle = NULL;
|
||||
|
||||
if (handle == NULL || *handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
diag_handle = *(diag_handle_t **)handle;
|
||||
|
||||
if (diag_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
core_diag_set_cb(diag_handle, NULL);
|
||||
|
||||
_diag_core_mqtt_operate_process_handler(diag_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER);
|
||||
|
||||
diag_handle->exec_enabled = 0;
|
||||
deinit_timestart = diag_handle->sysdep->core_sysdep_time();
|
||||
do {
|
||||
if (diag_handle->exec_count == 0) {
|
||||
break;
|
||||
}
|
||||
diag_handle->sysdep->core_sysdep_sleep(DIAG_DEINIT_INTERVAL_MS);
|
||||
} while ((diag_handle->sysdep->core_sysdep_time() - deinit_timestart) < diag_handle->deinit_timeout_ms);
|
||||
|
||||
if (diag_handle->exec_count != 0) {
|
||||
return STATE_MQTT_DEINIT_TIMEOUT;
|
||||
}
|
||||
|
||||
*handle = NULL;
|
||||
|
||||
_diag_running_state_clean(diag_handle);
|
||||
|
||||
diag_handle->sysdep->core_sysdep_mutex_deinit(&diag_handle->data_mutex);
|
||||
|
||||
core_global_deinit(diag_handle->sysdep);
|
||||
|
||||
diag_handle->sysdep->core_sysdep_free(diag_handle);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t aiot_diag_start(void *handle)
|
||||
{
|
||||
diag_handle_t *diag_handle = (diag_handle_t *)handle;
|
||||
|
||||
if (diag_handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
diag_handle->sysdep->core_sysdep_mutex_lock(diag_handle->data_mutex);
|
||||
diag_handle->diag_status = 1;
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(diag_handle->data_mutex);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t aiot_diag_stop(void *handle)
|
||||
{
|
||||
diag_handle_t *diag_handle = (diag_handle_t *)handle;
|
||||
|
||||
if (diag_handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
diag_handle->sysdep->core_sysdep_mutex_lock(diag_handle->data_mutex);
|
||||
diag_handle->diag_status = 0;
|
||||
diag_handle->sysdep->core_sysdep_mutex_unlock(diag_handle->data_mutex);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
315
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/diag/aiot_diag_api.h
vendored
Normal file
315
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/diag/aiot_diag_api.h
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
/**
|
||||
* @file aiot_diag_api.h
|
||||
* @brief diag模块头文件, 提供诊断SDK的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __AIOT_DIAG_API_H__
|
||||
#define __AIOT_DIAG_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief -0x0.00~-0x0.FF表达SDK在diag模块内的状态码
|
||||
*/
|
||||
#define STATE_DIAG_BASE (-0x1400)
|
||||
|
||||
/**
|
||||
* @brief STATE_DIAG_CODE1的说明
|
||||
*/
|
||||
#define STATE_DIAG_LOG_UNKNOWN_STATE_CODE_BASE (-0x1401)
|
||||
|
||||
/**
|
||||
* @brief STATE_DIAG_CODE2的说明
|
||||
*/
|
||||
#define STATE_DIAG_CODE2 (-0x1402)
|
||||
|
||||
/**
|
||||
* @brief STATE_DIAG_PUB_FAILED的说明
|
||||
*/
|
||||
#define STATE_DIAG_PUB_FAILED (-0x1403)
|
||||
|
||||
/**
|
||||
* @brief diag模块收到从网络上来的报文时, 通知用户的报文类型
|
||||
*/
|
||||
typedef enum {
|
||||
AIOT_DIAGRECV_DIAG_CONTROL
|
||||
} aiot_diag_recv_type_t;
|
||||
|
||||
/**
|
||||
* @brief diag模块收到从网络上来的报文时, 通知用户的报文内容
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 报文内容所对应的报文类型, 更多信息请参考@ref aiot_diag_recv_type_t
|
||||
*/
|
||||
aiot_diag_recv_type_t type;
|
||||
union {
|
||||
/**
|
||||
* @brief 收到的云端控制指令
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* @brief 0: 关闭诊断功能,1: 打开诊断功能
|
||||
*/
|
||||
uint32_t data;
|
||||
} diag_control;
|
||||
} data;
|
||||
} aiot_diag_recv_t;
|
||||
|
||||
/**
|
||||
* @brief diag模块收到从网络上来的报文时, 通知用户所调用的数据回调函数
|
||||
*
|
||||
* @param[in] handle diag会话句柄
|
||||
* @param[in] packet diag消息结构体, 存放收到的diag报文内容
|
||||
* @param[in] userdata 用户上下文
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (* aiot_diag_recv_handler_t)(void *handle, const aiot_diag_recv_t *packet, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief diag模块内部发生值得用户关注的状态变化时, 通知用户的事件类型
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 诊断模块产生的告警信息
|
||||
*/
|
||||
AIOT_DIAGEVT_ALERT
|
||||
} aiot_diag_event_type_t;
|
||||
|
||||
/**
|
||||
* @brief diag模块内部发生值得用户关注的状态变化时, 通知用户的事件内容
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 事件内容所对应的事件类型, 更多信息请参考@ref aiot_diag_event_type_t
|
||||
*/
|
||||
aiot_diag_event_type_t type;
|
||||
union {
|
||||
struct {
|
||||
/**
|
||||
* @brief 告警模块名
|
||||
*/
|
||||
char *module_name;
|
||||
/**
|
||||
* @brief 告警级别
|
||||
*/
|
||||
char *level;
|
||||
/**
|
||||
* @brief 告警信息描述字符串
|
||||
*/
|
||||
char *desc;
|
||||
} alert;
|
||||
} data;
|
||||
} aiot_diag_event_t;
|
||||
|
||||
/**
|
||||
* @brief diag模块内部发生值得用户关注的状态变化时, 通知用户所调用的事件回调函数
|
||||
*
|
||||
* @param[in] handle, diag会话句柄
|
||||
* @param[in] event, diag模块中发生的事件的内容
|
||||
* @param[in] userdata, 用户上下文
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (*aiot_diag_event_handler_t)(void *handle, const aiot_diag_event_t *event, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief 诊断项的配置参数
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 对当前诊断项是否进行诊断的开关
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 0: 关闭对当前诊断项的诊断, 1: 打开对当前诊断项的诊断
|
||||
*/
|
||||
uint8_t enabled;
|
||||
/**
|
||||
* @brief 对当前诊断项连续两次告警的最小时间间隔
|
||||
*/
|
||||
uint32_t interval_ms;
|
||||
/**
|
||||
* @brief warning级别告警的阈值
|
||||
*/
|
||||
int64_t warning_threashold;
|
||||
/**
|
||||
* @brief fatal级别告警的阈值
|
||||
*/
|
||||
int64_t fatal_threshold;
|
||||
} aiot_diag_config_t;
|
||||
|
||||
/**
|
||||
* @brief @ref aiot_diag_setopt 接口的option参数可选值.
|
||||
*
|
||||
* @details 下文每个选项中的数据类型, 指的是@ref aiot_diag_setopt 中, data参数的数据类型
|
||||
*
|
||||
* 1. data的数据类型是void *时, 以配置@ref AIOT_DIAGOPT_MQTT_HANDLE 为例:
|
||||
*
|
||||
* void *mqtt_handle = aiot_mqtt_init();
|
||||
* aiot_diag_setopt(diag_handle, AIOT_DIAGOPT_MQTT_HANDLE, mqtt_handle);
|
||||
*
|
||||
* 2. data的数据类型是其他数据类型时, 以配置@ref AIOT_DIAGOPT_LOCAL_REPORT_ENABLED 为例:
|
||||
*
|
||||
* uint8_t local_report_enabled = 1;
|
||||
* aiot_mqtt_setopt(diag_handle, AIOT_DIAGOPT_LOCAL_REPORT_ENABLED, (void *)&local_report_enabled);
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief diag会话 需要的MQTT句柄, 需要先建立MQTT连接, 再设置MQTT句柄
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_DIAGOPT_MQTT_HANDLE,
|
||||
|
||||
/**
|
||||
* @brief 是否需要从事件回调函数中输出告警信息
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 0: 不从事件回调函数中输出告警信息, 1: 从事件回调函数中输出告警信息
|
||||
*
|
||||
* 数据类型: (uint8_t *)
|
||||
*/
|
||||
AIOT_DIAGOPT_LOCAL_REPORT_ENABLED,
|
||||
|
||||
/**
|
||||
* @brief 是否需要上报告警信息至云端
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 0: 不上报告警信息至云端, 1: 上报告警信息至云端
|
||||
*
|
||||
* 数据类型: (uint8_t *)
|
||||
*/
|
||||
AIOT_DIAGOPT_CLOUD_REPORT_ENABLED,
|
||||
|
||||
/**
|
||||
* @brief MQTT建联时长告警配置
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: ( @ref aiot_diag_config_t )
|
||||
*/
|
||||
AIOT_DIAGOPT_MQTT_CONNECTION,
|
||||
|
||||
/**
|
||||
* @brief MQTT心跳丢失告警配置
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: ( @ref aiot_diag_config_t )
|
||||
*/
|
||||
AIOT_DIAGOPT_MQTT_HEARTBEAT,
|
||||
|
||||
/**
|
||||
* @brief Alink协议上行报文的回复速度告警配置
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: ( @ref aiot_diag_config_t )
|
||||
*/
|
||||
AIOT_DIAGOPT_ALINK_UPLINK,
|
||||
|
||||
/**
|
||||
* @brief 设置回调, 它在SDK收到网络报文的时候被调用, 告知用户
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: ( @ref aiot_diag_recv_handler_t )
|
||||
*/
|
||||
AIOT_DIAGOPT_RECV_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief diag内部发生的事件会从此回调函数进行通知
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: ( @ref aiot_diag_event_handler_t )
|
||||
*/
|
||||
AIOT_DIAGOPT_EVENT_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief 用户需要SDK暂存的上下文
|
||||
*
|
||||
* @details 这个上下文指针会在 AIOT_DIAGOPT_RECV_HANDLER 和 AIOT_DIAGOPT_EVENT_HANDLER 设置的回调被调用时, 由SDK传给用户
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_DIAGOPT_USERDATA,
|
||||
AIOT_DIAGOPT_MAX
|
||||
} aiot_diag_option_t;
|
||||
|
||||
/**
|
||||
* @brief 创建diag会话实例, 并以默认值配置会话参数
|
||||
*
|
||||
* @return void *
|
||||
* @retval 非NULL diag实例的句柄
|
||||
* @retval NULL 初始化失败, 一般是内存分配失败导致
|
||||
*
|
||||
*/
|
||||
void *aiot_diag_init(void);
|
||||
|
||||
/**
|
||||
* @brief 配置diag会话
|
||||
*
|
||||
* @param[in] handle diag会话句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_diag_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_diag_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 参数配置失败
|
||||
* @retval >=STATE_SUCCESS 参数配置成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_diag_setopt(void *handle, aiot_diag_option_t option, void *data);
|
||||
|
||||
/**
|
||||
* @brief 结束diag会话, 销毁实例并回收资源
|
||||
*
|
||||
* @param[in] handle 指向diag会话句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 执行失败
|
||||
* @retval >=STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_diag_deinit(void **handle);
|
||||
|
||||
/**
|
||||
* @brief 开始诊断SDK内部信息
|
||||
*
|
||||
* @param handle diag会话句柄
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 请求发送失败
|
||||
* @retval >=STATE_SUCCESS 请求发送成功
|
||||
*/
|
||||
int32_t aiot_diag_start(void *handle);
|
||||
|
||||
/**
|
||||
* @brief 停止诊断SDK内部信息
|
||||
*
|
||||
* @param handle diag会话句柄
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 数据接收失败
|
||||
* @retval >=STATE_SUCCESS 数据接收成功
|
||||
*/
|
||||
int32_t aiot_diag_stop(void *handle);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AIOT_DIAG_API_H__ */
|
||||
|
||||
191
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/diag/diag_private.h
vendored
Normal file
191
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/diag/diag_private.h
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* @file diag_private.h
|
||||
* @brief diag模块内部的宏定义和数据结构声明, 不面向其它模块, 更不面向用户
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __DIAG_PRIVATE_H__
|
||||
#define __DIAG_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_stdinc.h"
|
||||
#include "core_list.h"
|
||||
|
||||
#include "aiot_state_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_diag_api.h"
|
||||
|
||||
typedef struct {
|
||||
uint64_t last_check_time;
|
||||
} diag_mqtt_process_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t timestamp;
|
||||
int32_t code;
|
||||
uint8_t *data;
|
||||
uint32_t data_len;
|
||||
} diag_raw_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t timestamp;
|
||||
uint16_t code;
|
||||
char *module_name;
|
||||
char *level;
|
||||
char *desc;
|
||||
uint8_t qos;
|
||||
struct core_list_head linked_node;
|
||||
} diag_desc_node_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t is_diag; /* 该诊断项是否处于诊断状态 */
|
||||
char *level; /* 告警级别 */
|
||||
uint64_t start_time; /* 统计开始时间 */
|
||||
uint64_t stop_time; /* 统计结束时间 */
|
||||
void *extra_data; /* 统计节点附加数据 */
|
||||
struct core_list_head linked_node;
|
||||
} diag_running_state_node_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t code; /* 诊断项代号 */
|
||||
char *name; /* 诊断项名 */
|
||||
uint8_t is_reported; /* 当前统计周期内是否上报过 */
|
||||
uint64_t report_start_time; /* 当前统计周期开始时间 */
|
||||
uint32_t alert_counts; /* 当前统计周期累计产生告警次数 */
|
||||
uint32_t stat_number; /* 当前节点数量 */
|
||||
uint32_t max_stat_number; /* 统计节点最大数量 */
|
||||
uint8_t qos; /* 使用MQTT发送告警报文至云端时,使用的QoS值 */
|
||||
void *mutex; /* 数据保护锁 */
|
||||
struct core_list_head linked_list;
|
||||
} diag_running_state_t;
|
||||
|
||||
typedef void (*diag_running_state_node_extra_clean_t)(void *handle, void *extra_data);
|
||||
typedef int32_t (*diag_running_state_node_extra_stop_t)(void *handle, diag_running_state_node_t *node, uint32_t stat_idx, uint32_t stat_number, void *extra_data);
|
||||
typedef int32_t (*diag_report_desc_append_t)(void *handle, diag_running_state_t *running_state, diag_running_state_node_t *node, char **desc);
|
||||
|
||||
typedef struct {
|
||||
diag_running_state_node_extra_clean_t extra_clean_cb;
|
||||
diag_running_state_node_extra_stop_t extra_stop_cb;
|
||||
diag_report_desc_append_t desc_append_cb;
|
||||
} diag_stat_callback_t;
|
||||
|
||||
typedef struct {
|
||||
aiot_diag_config_t config;
|
||||
diag_running_state_t running_state;
|
||||
diag_stat_callback_t stat_cb;
|
||||
} diag_stat_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t msgid;
|
||||
} diag_alink_uplink_extra_data_t;
|
||||
|
||||
#define DIAG_STAT_ITEM_NUMBER (3)
|
||||
|
||||
typedef struct {
|
||||
aiot_sysdep_portfile_t *sysdep; /* 底层依赖回调合集的引用指针 */
|
||||
void *mqtt_handle;
|
||||
|
||||
uint8_t local_report_enabled;
|
||||
uint8_t cloud_report_enabled;
|
||||
|
||||
diag_stat_t diag_stat[DIAG_STAT_ITEM_NUMBER];
|
||||
|
||||
uint32_t deinit_timeout_ms;
|
||||
|
||||
aiot_diag_event_handler_t event_handler; /* 组件内部运行状态变更时, 通知用户的回调 */
|
||||
aiot_diag_recv_handler_t recv_handler; /* 组件从协议栈读到内容时, 通知用户的回调 */
|
||||
void *userdata; /* 组件调用以上2个 diag_handler 时的入参之一 */
|
||||
|
||||
/*---- 以上都是用户在API可配 ----*/
|
||||
|
||||
/*---- 以下都是DIAG在内部使用, 用户无感知 ----*/
|
||||
|
||||
void *data_mutex; /* 保护本地的数据结构 */
|
||||
|
||||
uint8_t diag_status; /* 本地诊断模块状态, 0: stop, 1: start */
|
||||
uint8_t cloud_switch;
|
||||
|
||||
diag_mqtt_process_t mqtt_process;
|
||||
|
||||
uint8_t exec_enabled;
|
||||
uint32_t exec_count;
|
||||
|
||||
} diag_handle_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t stat_idx;
|
||||
char *name;
|
||||
uint32_t code;
|
||||
aiot_diag_config_t def_config;
|
||||
uint32_t def_max_stat_number;
|
||||
diag_stat_callback_t def_stat_cb;
|
||||
uint8_t qos;
|
||||
} diag_config_t;
|
||||
|
||||
#define DIAG_MODULE_NAME "diag" /* 用于内存统计的模块名字符串 */
|
||||
|
||||
#define DIAG_DAFAULT_LOCAL_REPORT_ENABLED (1)
|
||||
#define DIAG_DAFAULT_CLOUD_REPORT_ENABLED (1)
|
||||
#define DIAG_DEFAULT_DEINIT_TIMEOUT_MS (2 * 1000)
|
||||
|
||||
/* MQTT connection diag default configuration */
|
||||
#define DIAG_DEFAULT_MQTT_CONN_ENABLED (1)
|
||||
#define DIAG_DEFAULT_MQTT_CONN_INTERVAL_MS (30 * 1000)
|
||||
#define DIAG_DEFAULT_MQTT_CONN_WARNING_THRESHOLD (200)
|
||||
#define DIAG_DEFAULT_MQTT_CONN_FATAL_THRESHOLD (500)
|
||||
#define DIAG_DEFAULT_MQTT_CONN_MAX_STAT_NUMBER (20)
|
||||
|
||||
/* MQTT heartbeag diag default configuration */
|
||||
#define DIAG_DEFAULT_MQTT_HB_ENABLED (1)
|
||||
#define DIAG_DEFAULT_MQTT_HB_INTERVAL_MS (30 * 1000)
|
||||
#define DIAG_DEFAULT_MQTT_HB_WARNING_THRESHOLD (800)
|
||||
#define DIAG_DEFAULT_MQTT_HB_FATAL_THRESHOLD (1500)
|
||||
#define DIAG_DEFAULT_MQTT_HB_MAX_STAT_NUMBER (20)
|
||||
|
||||
/* MQTT alink uplink default configuration */
|
||||
#define DIAG_DEFAULT_ALINK_UPLINK_ENABLED (1)
|
||||
#define DIAG_DEFAULT_ALINK_UPLINK_INTERVAL_MS (30 * 1000)
|
||||
#define DIAG_DEFAULT_ALINK_UPLINK_WARNING_THRESHOLD (600)
|
||||
#define DIAG_DEFAULT_ALINK_UPLINK_FATAL_THRESHOLD (1000)
|
||||
#define DIAG_DEFAULT_ALINK_UPLINK_MAX_STAT_NUMBER (20)
|
||||
|
||||
#define DIAG_REPORT_TOPIC_FMT "/sys/%s/%s/thing/log/post"
|
||||
#define DIAG_REPORT_PAYLOAD_FMT "{\"id\":\"%s\",\"version\":\"1.0\",\"params\":[{\"utcTime\":\"%s\"," \
|
||||
"\"logLevel\":\"%s\",\"module\":\"%s\",\"code\":\"%s\",\"traceContext\":\"%s\",\"logContent\":\"%s\"}]}"
|
||||
|
||||
#define DIAG_DEINIT_INTERVAL_MS (100)
|
||||
#define DIAG_MQTT_PROCESS_CHECK_INTERVAL_MS (2000)
|
||||
#define DIAG_REPORT_LEVEL_WARNING_STR "WARN"
|
||||
#define DIAG_REPORT_LEVEL_FATAL_STR "FATAL"
|
||||
|
||||
#define DIAG_STATE_MQTT_BASE (STATE_MQTT_BASE)
|
||||
#define DIAG_STATE_DM_BASE (-0x0A00)
|
||||
|
||||
/* MQTT connection diag constant */
|
||||
#define DIAG_MQTT_CONNECTION_STAT_INDEX (0)
|
||||
#define DIAG_MQTT_CONNECTION_NAME_STR "DiagMqttConnection"
|
||||
#define DIAG_TLV_MQTT_CONNECTION (0x0010)
|
||||
|
||||
/* MQTT heartbeat diag constant */
|
||||
#define DIAG_MQTT_HEARTBEAT_STAT_INDEX (1)
|
||||
#define DIAG_MQTT_HEARTBEAT_NAME_STR "DiagMqttHeartbeat"
|
||||
#define DIAG_TLV_MQTT_HEARTBEAT (0x0020)
|
||||
|
||||
/* MQTT alink uplink diag constant */
|
||||
#define DIAG_ALINK_UPLINK_STAT_INDEX (2)
|
||||
#define DIAG_ALINK_UPLINK_NAME_STR "DiagAlinkUplink"
|
||||
#define DIAG_TLV_ALINK_UPLINK (0x0030)
|
||||
#define DIAG_TLV_ALINK_MSGID (0x0031)
|
||||
|
||||
|
||||
/* internal state code */
|
||||
#define STATE_DIAG_STOP_NODE_NOT_MATCH (-0x14FF)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* __DIAG_PRIVATE_H__ */
|
||||
|
||||
2
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg-mqtt/README.md
vendored
Normal file
2
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg-mqtt/README.md
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Name: 基于MQTT的动态注册
|
||||
MQTT-dynreg Component for Link Kit SDK V4.0.0
|
||||
543
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg-mqtt/aiot_dynregmq_api.c
vendored
Normal file
543
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg-mqtt/aiot_dynregmq_api.c
vendored
Normal file
@@ -0,0 +1,543 @@
|
||||
/**
|
||||
* @file aiot_dynregmq_api.c
|
||||
* @brief dynregmq模块的API接口实现, 提供获取设备信息的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#include "dynregmq_private.h"
|
||||
|
||||
#include "core_string.h"
|
||||
#include "core_log.h"
|
||||
#include "core_auth.h"
|
||||
|
||||
|
||||
static void _dynregmq_exec_inc(dynregmq_handle_t *dynregmq_handle)
|
||||
{
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_lock(dynregmq_handle->data_mutex);
|
||||
dynregmq_handle->exec_count++;
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
|
||||
}
|
||||
|
||||
static void _dynregmq_exec_dec(dynregmq_handle_t *dynregmq_handle)
|
||||
{
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_lock(dynregmq_handle->data_mutex);
|
||||
dynregmq_handle->exec_count--;
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
|
||||
}
|
||||
|
||||
static void _dynregmq_recv_handler(void *handle, const aiot_mqtt_recv_t *packet, void *userdata)
|
||||
{
|
||||
dynregmq_handle_t *dynregmq_handle = (dynregmq_handle_t *)userdata;
|
||||
|
||||
if (dynregmq_handle->recv_handler == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (packet->type) {
|
||||
case AIOT_MQTTRECV_PUB: {
|
||||
char *topic = packet->data.pub.topic;
|
||||
uint32_t topic_len = packet->data.pub.topic_len;
|
||||
char *payload = (char *)packet->data.pub.payload;
|
||||
uint32_t payload_len = packet->data.pub.payload_len;
|
||||
const char *topic_register = "/ext/register";
|
||||
const char *topic_regnwl = "/ext/regnwl";
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (strlen(topic_register) == topic_len && !memcmp(topic_register, topic, topic_len)) {
|
||||
const char *key_ds = "deviceSecret";
|
||||
char *ds = NULL;
|
||||
uint32_t ds_len = 0;
|
||||
|
||||
res = core_json_value(payload, payload_len, key_ds, strlen(key_ds),
|
||||
&ds, &ds_len);
|
||||
|
||||
if (res != STATE_SUCCESS || ds == NULL || ds_len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
dynregmq_handle->flag_completed = 1;
|
||||
|
||||
if (dynregmq_handle->recv_handler) {
|
||||
aiot_dynregmq_recv_t recv_data;
|
||||
memset(&recv_data, 0, sizeof(aiot_dynregmq_recv_t));
|
||||
|
||||
*(ds + ds_len) = 0;
|
||||
recv_data.type = AIOT_DYNREGMQRECV_DEVICEINFO_WL;
|
||||
recv_data.data.deviceinfo_wl.device_secret = ds;
|
||||
dynregmq_handle->recv_handler(dynregmq_handle, &recv_data, dynregmq_handle->userdata);
|
||||
}
|
||||
} else if (strlen(topic_regnwl) == topic_len && !memcmp(topic_regnwl, topic, topic_len)) {
|
||||
const char *key_clientid = "clientId";
|
||||
const char *key_devicetoken = "deviceToken";
|
||||
char *client_id = NULL;
|
||||
char *device_token = NULL;
|
||||
uint32_t client_id_len = 0;
|
||||
uint32_t device_token_len = 0;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if ((res = core_json_value(payload, payload_len, key_clientid, strlen(key_clientid), &client_id,
|
||||
&client_id_len)) != STATE_SUCCESS ||
|
||||
(res = core_json_value(payload, payload_len, key_devicetoken, strlen(key_devicetoken), &device_token,
|
||||
&device_token_len)) != STATE_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (client_id == NULL || device_token == NULL || client_id_len == 0 || device_token_len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
dynregmq_handle->flag_completed = 1;
|
||||
|
||||
if (dynregmq_handle->recv_handler) {
|
||||
aiot_dynregmq_recv_t recv_data;
|
||||
char *conn_clientid = NULL;
|
||||
char *conn_username = NULL;
|
||||
char *conn_username_fmt[] = { dynregmq_handle->device_name, dynregmq_handle->product_key };
|
||||
|
||||
*(client_id + client_id_len) = 0;
|
||||
*(device_token + device_token_len) = 0;
|
||||
core_sprintf(dynregmq_handle->sysdep, &conn_clientid,
|
||||
"%s|authType=connwl,securemode=-2,_ss=1,ext=3,_v="CORE_AUTH_SDK_VERSION"|",
|
||||
&client_id, 1, DYNREGMQ_MODULE_NAME);
|
||||
core_sprintf(dynregmq_handle->sysdep, &conn_username, "%s&%s",
|
||||
conn_username_fmt, sizeof(conn_username_fmt) / sizeof(char *), DYNREGMQ_MODULE_NAME);
|
||||
|
||||
memset(&recv_data, 0, sizeof(aiot_dynregmq_recv_t));
|
||||
recv_data.type = AIOT_DYNREGMQRECV_DEVICEINFO_NWL;
|
||||
recv_data.data.deviceinfo_nwl.clientid = conn_clientid;
|
||||
recv_data.data.deviceinfo_nwl.username = conn_username;
|
||||
recv_data.data.deviceinfo_nwl.password = device_token;
|
||||
dynregmq_handle->recv_handler(dynregmq_handle, &recv_data, dynregmq_handle->userdata);
|
||||
|
||||
dynregmq_handle->sysdep->core_sysdep_free(conn_clientid);
|
||||
dynregmq_handle->sysdep->core_sysdep_free(conn_username);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void *aiot_dynregmq_init(void)
|
||||
{
|
||||
dynregmq_handle_t *dynregmq_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if (sysdep == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dynregmq_handle = sysdep->core_sysdep_malloc(sizeof(dynregmq_handle_t), DYNREGMQ_MODULE_NAME);
|
||||
if (dynregmq_handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(dynregmq_handle, 0, sizeof(dynregmq_handle_t));
|
||||
|
||||
dynregmq_handle->sysdep = sysdep;
|
||||
dynregmq_handle->timeout_ms = DYNREGMQ_DEFAULT_TIMEOUT_MS;
|
||||
dynregmq_handle->deinit_timeout_ms = DYNREGMQ_DEFAULT_DEINIT_TIMEOUT_MS;
|
||||
dynregmq_handle->send_timeout_ms = DYNREGMQ_DEFAULT_SEND_TIMEOUT;
|
||||
dynregmq_handle->recv_timeout_ms = DYNREGMQ_DEFAULT_RECV_TIMEOUT;
|
||||
dynregmq_handle->data_mutex = dynregmq_handle->sysdep->core_sysdep_mutex_init();
|
||||
|
||||
dynregmq_handle->exec_enabled = 1;
|
||||
|
||||
return dynregmq_handle;
|
||||
}
|
||||
|
||||
int32_t aiot_dynregmq_setopt(void *handle, aiot_dynregmq_option_t option, void *data)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
dynregmq_handle_t *dynregmq_handle = (dynregmq_handle_t *)handle;
|
||||
|
||||
if (dynregmq_handle == NULL || data == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (option >= AIOT_DYNREGMQOPT_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
if (dynregmq_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
_dynregmq_exec_inc(dynregmq_handle);
|
||||
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_lock(dynregmq_handle->data_mutex);
|
||||
switch (option) {
|
||||
case AIOT_DYNREGMQOPT_NETWORK_CRED: {
|
||||
if (dynregmq_handle->cred != NULL) {
|
||||
dynregmq_handle->sysdep->core_sysdep_free(dynregmq_handle->cred);
|
||||
dynregmq_handle->cred = NULL;
|
||||
}
|
||||
dynregmq_handle->cred = dynregmq_handle->sysdep->core_sysdep_malloc(sizeof(aiot_sysdep_network_cred_t),
|
||||
DYNREGMQ_MODULE_NAME);
|
||||
if (dynregmq_handle->cred != NULL) {
|
||||
memset(dynregmq_handle->cred, 0, sizeof(aiot_sysdep_network_cred_t));
|
||||
memcpy(dynregmq_handle->cred, data, sizeof(aiot_sysdep_network_cred_t));
|
||||
} else {
|
||||
res = STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_HOST: {
|
||||
res = core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->host, data, DYNREGMQ_MODULE_NAME);
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_PORT: {
|
||||
dynregmq_handle->port = *(uint16_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_PRODUCT_KEY: {
|
||||
res = core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->product_key, data, DYNREGMQ_MODULE_NAME);
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_PRODUCT_SECRET: {
|
||||
res = core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->product_secret, data, DYNREGMQ_MODULE_NAME);
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_DEVICE_NAME: {
|
||||
res = core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->device_name, data, DYNREGMQ_MODULE_NAME);
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_SEND_TIMEOUT_MS: {
|
||||
dynregmq_handle->send_timeout_ms = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_RECV_TIMEOUT_MS: {
|
||||
dynregmq_handle->recv_timeout_ms = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_RECV_HANDLER: {
|
||||
dynregmq_handle->recv_handler = (aiot_dynregmq_recv_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_USERDATA: {
|
||||
dynregmq_handle->userdata = data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_TIMEOUT_MS: {
|
||||
dynregmq_handle->timeout_ms = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_DEINIT_TIMEOUT_MS: {
|
||||
dynregmq_handle->deinit_timeout_ms = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_NO_WHITELIST: {
|
||||
dynregmq_handle->flag_nowhitelist = *(uint8_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGMQOPT_INSTANCE_ID: {
|
||||
res = core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->instance_id, data, DYNREGMQ_MODULE_NAME);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
res = STATE_USER_INPUT_UNKNOWN_OPTION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
|
||||
|
||||
_dynregmq_exec_dec(dynregmq_handle);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_dynregmq_deinit(void **handle)
|
||||
{
|
||||
uint32_t deinit_timeout_ms = 0;
|
||||
dynregmq_handle_t *dynregmq_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
|
||||
if (handle == NULL || *handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
dynregmq_handle = *(dynregmq_handle_t **)handle;
|
||||
sysdep = dynregmq_handle->sysdep;
|
||||
|
||||
if (dynregmq_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
dynregmq_handle->exec_enabled = 0;
|
||||
deinit_timeout_ms = dynregmq_handle->deinit_timeout_ms;
|
||||
do {
|
||||
if (dynregmq_handle->exec_count == 0) {
|
||||
break;
|
||||
}
|
||||
dynregmq_handle->sysdep->core_sysdep_sleep(DYNREGMQ_DEINIT_INTERVAL_MS);
|
||||
} while ((deinit_timeout_ms > DYNREGMQ_DEINIT_INTERVAL_MS) && (deinit_timeout_ms - DYNREGMQ_DEINIT_INTERVAL_MS > 0));
|
||||
|
||||
if (dynregmq_handle->exec_count != 0) {
|
||||
return STATE_DYNREGMQ_DEINIT_TIMEOUT;
|
||||
}
|
||||
|
||||
*handle = NULL;
|
||||
|
||||
if (dynregmq_handle->mqtt_handle != NULL) {
|
||||
aiot_mqtt_deinit(&dynregmq_handle->mqtt_handle);
|
||||
}
|
||||
|
||||
if (dynregmq_handle->host != NULL) {
|
||||
sysdep->core_sysdep_free(dynregmq_handle->host);
|
||||
}
|
||||
|
||||
if (dynregmq_handle->product_key != NULL) {
|
||||
sysdep->core_sysdep_free(dynregmq_handle->product_key);
|
||||
}
|
||||
|
||||
if (dynregmq_handle->product_secret != NULL) {
|
||||
sysdep->core_sysdep_free(dynregmq_handle->product_secret);
|
||||
}
|
||||
|
||||
if (dynregmq_handle->device_name != NULL) {
|
||||
sysdep->core_sysdep_free(dynregmq_handle->device_name);
|
||||
}
|
||||
|
||||
if (dynregmq_handle->cred != NULL) {
|
||||
sysdep->core_sysdep_free(dynregmq_handle->cred);
|
||||
}
|
||||
|
||||
if (dynregmq_handle->instance_id != NULL) {
|
||||
sysdep->core_sysdep_free(dynregmq_handle->instance_id);
|
||||
}
|
||||
|
||||
sysdep->core_sysdep_mutex_deinit(&dynregmq_handle->data_mutex);
|
||||
|
||||
sysdep->core_sysdep_free(dynregmq_handle);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static void _core_append_instance_id(dynregmq_handle_t *dynregmq_handle)
|
||||
{
|
||||
const char *INSTANCE_PATTERN = ".mqtt.iothub.aliyuncs.com";
|
||||
char *host = NULL;
|
||||
char *ptr = NULL;
|
||||
int total_len = 0;
|
||||
int instance_id_len = 0;
|
||||
void *content = NULL;
|
||||
if (NULL == dynregmq_handle || NULL == dynregmq_handle->host) {
|
||||
return;
|
||||
}
|
||||
|
||||
host = dynregmq_handle->host;
|
||||
if (NULL == host) {
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = strstr(host, INSTANCE_PATTERN);
|
||||
if (NULL == ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
total_len = ptr - host + 1;
|
||||
instance_id_len = ptr - host;
|
||||
if (instance_id_len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
content = dynregmq_handle->sysdep->core_sysdep_malloc(total_len, DYNREGMQ_MODULE_NAME);
|
||||
if (content == NULL) {
|
||||
return;
|
||||
}
|
||||
memset(content, 0, total_len);
|
||||
memcpy(content, host, instance_id_len);
|
||||
if (NULL == dynregmq_handle->instance_id) {
|
||||
core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->instance_id, content, DYNREGMQ_MODULE_NAME);
|
||||
}
|
||||
|
||||
dynregmq_handle->sysdep->core_sysdep_free(content);
|
||||
}
|
||||
|
||||
|
||||
int32_t aiot_dynregmq_send_request(void *handle)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
dynregmq_handle_t *dynregmq_handle = (dynregmq_handle_t *)handle;
|
||||
char *auth_clientid = NULL;
|
||||
char *auth_username = NULL;
|
||||
char auth_password[65] = {0};
|
||||
char *sign_input = NULL;
|
||||
uint32_t random_num = 0;
|
||||
char random[11] = {0};
|
||||
char *auth_type = NULL;
|
||||
uint8_t reconnect = 0;
|
||||
|
||||
if (dynregmq_handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (dynregmq_handle->host == NULL) {
|
||||
return STATE_USER_INPUT_MISSING_HOST;
|
||||
}
|
||||
|
||||
if (dynregmq_handle->product_key == NULL) {
|
||||
return STATE_USER_INPUT_MISSING_PRODUCT_KEY;
|
||||
}
|
||||
|
||||
if (dynregmq_handle->product_secret == NULL) {
|
||||
return STATE_USER_INPUT_MISSING_PRODUCT_SECRET;
|
||||
}
|
||||
|
||||
if (dynregmq_handle->device_name == NULL) {
|
||||
return STATE_USER_INPUT_MISSING_DEVICE_NAME;
|
||||
}
|
||||
|
||||
if (dynregmq_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
_dynregmq_exec_inc(dynregmq_handle);
|
||||
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_lock(dynregmq_handle->data_mutex);
|
||||
|
||||
if (dynregmq_handle->mqtt_handle != NULL) {
|
||||
aiot_mqtt_deinit(&dynregmq_handle->mqtt_handle);
|
||||
}
|
||||
|
||||
dynregmq_handle->mqtt_handle = aiot_mqtt_init();
|
||||
if (dynregmq_handle->mqtt_handle == NULL) {
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
|
||||
_dynregmq_exec_dec(dynregmq_handle);
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
/* setup auth_type */
|
||||
auth_type = (dynregmq_handle->flag_nowhitelist) ? "regnwl" : "register";
|
||||
|
||||
/* generate random string */
|
||||
dynregmq_handle->sysdep->core_sysdep_rand((uint8_t *)&random_num, 4);
|
||||
core_uint2str(random_num, random, NULL);
|
||||
|
||||
/* assamble clientid, username and password */
|
||||
{
|
||||
/* generate client_id automatically */
|
||||
_core_append_instance_id(dynregmq_handle);
|
||||
|
||||
uint8_t has_instance_id = (dynregmq_handle->instance_id != NULL) ? 1 : 0;
|
||||
char *client_fmt = (has_instance_id) ?
|
||||
"%s.%s|random=%s,authType=%s,securemode=2,signmethod=hmacsha256,instanceId=%s|" :
|
||||
"%s.%s|random=%s,authType=%s,securemode=2,signmethod=hmacsha256|";
|
||||
char *client_src[] = { dynregmq_handle->device_name, dynregmq_handle->product_key,
|
||||
random, auth_type, dynregmq_handle->instance_id
|
||||
};
|
||||
char *username_fmt = "%s&%s";
|
||||
char *username_src[] = { dynregmq_handle->device_name, dynregmq_handle->product_key };
|
||||
char *sign_input_fmt = "deviceName%sproductKey%srandom%s";
|
||||
uint8_t sign_output[32] = {0};
|
||||
|
||||
core_sprintf(dynregmq_handle->sysdep, &auth_clientid, client_fmt, client_src,
|
||||
has_instance_id ? 5 : 4, DYNREGMQ_MODULE_NAME);
|
||||
|
||||
core_sprintf(dynregmq_handle->sysdep, &auth_username, username_fmt, username_src,
|
||||
sizeof(username_src) / sizeof(char *), DYNREGMQ_MODULE_NAME);
|
||||
core_sprintf(dynregmq_handle->sysdep, &sign_input, sign_input_fmt, client_src,
|
||||
3, DYNREGMQ_MODULE_NAME);
|
||||
core_hmac_sha256((const uint8_t *)sign_input, (uint32_t)strlen(sign_input),
|
||||
(const uint8_t *)dynregmq_handle->product_secret,
|
||||
(uint32_t)strlen(dynregmq_handle->product_secret), sign_output);
|
||||
core_hex2str(sign_output, sizeof(sign_output), auth_password, 0);
|
||||
}
|
||||
|
||||
if (((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_HOST,
|
||||
(void *)dynregmq_handle->host)) < STATE_SUCCESS) ||
|
||||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_PORT,
|
||||
(void *)&dynregmq_handle->port)) < STATE_SUCCESS) ||
|
||||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_CLIENTID,
|
||||
(void *)auth_clientid)) < STATE_SUCCESS) ||
|
||||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_USERNAME,
|
||||
(void *)auth_username)) < STATE_SUCCESS) ||
|
||||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_PASSWORD,
|
||||
(void *)auth_password)) < STATE_SUCCESS) ||
|
||||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_NETWORK_CRED,
|
||||
(void *)dynregmq_handle->cred)) < STATE_SUCCESS) ||
|
||||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_SEND_TIMEOUT_MS,
|
||||
(void *)&dynregmq_handle->send_timeout_ms)) < STATE_SUCCESS) ||
|
||||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_RECV_TIMEOUT_MS,
|
||||
(void *)&dynregmq_handle->recv_timeout_ms)) < STATE_SUCCESS) ||
|
||||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_RECV_HANDLER,
|
||||
(void *)_dynregmq_recv_handler)) < STATE_SUCCESS) ||
|
||||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_USERDATA,
|
||||
(void *)dynregmq_handle)) < STATE_SUCCESS) ||
|
||||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_RECONN_ENABLED,
|
||||
(void *)&reconnect)) < STATE_SUCCESS)) {
|
||||
aiot_mqtt_deinit(&dynregmq_handle->mqtt_handle);
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
|
||||
_dynregmq_exec_dec(dynregmq_handle);
|
||||
|
||||
dynregmq_handle->sysdep->core_sysdep_free(auth_clientid);
|
||||
dynregmq_handle->sysdep->core_sysdep_free(auth_username);
|
||||
dynregmq_handle->sysdep->core_sysdep_free(sign_input);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = aiot_mqtt_connect(dynregmq_handle->mqtt_handle);
|
||||
if (res < STATE_SUCCESS) {
|
||||
aiot_mqtt_deinit(&dynregmq_handle->mqtt_handle);
|
||||
}
|
||||
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
|
||||
_dynregmq_exec_dec(dynregmq_handle);
|
||||
|
||||
dynregmq_handle->sysdep->core_sysdep_free(auth_clientid);
|
||||
dynregmq_handle->sysdep->core_sysdep_free(auth_username);
|
||||
dynregmq_handle->sysdep->core_sysdep_free(sign_input);
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_dynregmq_recv(void *handle)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
uint64_t timenow_ms = 0;
|
||||
dynregmq_handle_t *dynregmq_handle = (dynregmq_handle_t *)handle;
|
||||
|
||||
if (dynregmq_handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (dynregmq_handle->mqtt_handle == NULL) {
|
||||
return STATE_DYNREGMQ_NEED_SEND_REQUEST;
|
||||
}
|
||||
|
||||
if (dynregmq_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
_dynregmq_exec_inc(dynregmq_handle);
|
||||
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_lock(dynregmq_handle->data_mutex);
|
||||
timenow_ms = dynregmq_handle->sysdep->core_sysdep_time();
|
||||
while (1) {
|
||||
if (timenow_ms >= dynregmq_handle->sysdep->core_sysdep_time()) {
|
||||
timenow_ms = dynregmq_handle->sysdep->core_sysdep_time();
|
||||
}
|
||||
if (dynregmq_handle->sysdep->core_sysdep_time() - timenow_ms >= dynregmq_handle->timeout_ms) {
|
||||
res = STATE_DYNREGMQ_AUTH_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
res = aiot_mqtt_recv(dynregmq_handle->mqtt_handle);
|
||||
if (res < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (dynregmq_handle->flag_completed == 1) {
|
||||
dynregmq_handle->flag_completed = 0;
|
||||
res = STATE_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
|
||||
_dynregmq_exec_dec(dynregmq_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
336
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg-mqtt/aiot_dynregmq_api.h
vendored
Normal file
336
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg-mqtt/aiot_dynregmq_api.h
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
/**
|
||||
* @file aiot_dynregmq_api.h
|
||||
* @brief dynregmq模块头文件, 提供了基于MQTT的设备信息动态注册能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __AIOT_DYNREGMQ_API_H__
|
||||
#define __AIOT_DYNREGMQ_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief -0x0500~-0x05FF表达SDK在dynregmq模块内的状态码
|
||||
*/
|
||||
#define STATE_DYNREGMQ_BASE (-0x0500)
|
||||
|
||||
/**
|
||||
* @brief 执行@ref aiot_dynregmq_deinit 时, 等待其他API执行结束的超过设定的超时时间, DYNREGMQ实例销毁失败
|
||||
*/
|
||||
#define STATE_DYNREGMQ_DEINIT_TIMEOUT (-0x0501)
|
||||
|
||||
/**
|
||||
* @brief 需要首先执行@ref aiot_dynregmq_send_request 发送动态注册请求
|
||||
*/
|
||||
#define STATE_DYNREGMQ_NEED_SEND_REQUEST (-0x0502)
|
||||
|
||||
/**
|
||||
* @brief 接收服务器应答超时
|
||||
*/
|
||||
#define STATE_DYNREGMQ_AUTH_TIMEOUT (-0x0503)
|
||||
|
||||
/**
|
||||
* @brief @ref aiot_dynregmq_setopt 接口的option参数可选值.
|
||||
*
|
||||
* @details 下文每个选项中的数据类型, 指的是@ref aiot_dynregmq_setopt 中, data参数的数据类型
|
||||
*
|
||||
* 1. data的数据类型是char *时, 以配置@ref AIOT_DYNREGMQOPT_HOST 为例:
|
||||
*
|
||||
* char *host = "xxx";
|
||||
* aiot_dynregmq_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_HOST, host);
|
||||
*
|
||||
* 2. data的数据类型是其他数据类型时, 以配置@ref AIOT_DYNREGMQOPT_PORT 为例:
|
||||
*
|
||||
* uint16_t port = 443;
|
||||
* aiot_mqtt_setopt(dynregmq_handle, AIOT_DYNREGMQOPT_PORT, (void *)&port);
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief mqtt动态注册 服务器建联时, 网络使用的安全凭据, 动态注册必需使用TLS方式建连
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 该配置项用于为底层网络配置@ref aiot_sysdep_network_cred_t 安全凭据数据
|
||||
*
|
||||
* 应当把 @ref aiot_sysdep_network_cred_t 中option配置为@ref AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA , 以tls方式建联
|
||||
*
|
||||
* 数据类型: (aiot_sysdep_network_cred_t *)
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_NETWORK_CRED,
|
||||
|
||||
/**
|
||||
* @brief mqtt动态注册 服务器的域名地址或者ip地址
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 阿里云物联网平台域名地址列表(必须使用自己的product key替换${pk}):
|
||||
*
|
||||
* 使用tls证书方式建联:
|
||||
*
|
||||
* | 域名地址 | 区域 | 端口号
|
||||
* |-------------------------------------------------|---------|---------
|
||||
* | ${pk}.iot-as-mqtt.cn-shanghai.aliyuncs.com | 上海 | 443
|
||||
* | ${pk}.iot-as-mqtt.ap-southeast-1.aliyuncs.com | 新加坡 | 443
|
||||
* | ${pk}.iot-as-mqtt.ap-northeast-1.aliyuncs.com | 日本 | 443
|
||||
* | ${pk}.iot-as-mqtt.us-west-1.aliyuncs.com | 美西 | 443
|
||||
* | ${pk}.iot-as-mqtt.eu-central-1.aliyuncs.com | 德国 | 443
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_HOST,
|
||||
|
||||
/**
|
||||
* @brief mqtt动态注册 服务器的端口号
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 连接阿里云物联网平台 mqtt动态注册 服务器时:
|
||||
*
|
||||
* 必须使用tls方式建联, 端口号设置为443
|
||||
*
|
||||
* 数据类型: (uint16_t *)
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_PORT,
|
||||
|
||||
/**
|
||||
* @brief 设备的productKey, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_PRODUCT_KEY,
|
||||
|
||||
/**
|
||||
* @brief 设备的productSecret, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_PRODUCT_SECRET,
|
||||
|
||||
/**
|
||||
* @brief 设备的deviceName, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_DEVICE_NAME,
|
||||
|
||||
/**
|
||||
* @brief dynregmq会话发送消息时可消费的最长时间间隔
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (uint32_t) 默认值: (5 * 1000) ms
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_SEND_TIMEOUT_MS,
|
||||
|
||||
/**
|
||||
* @brief dynregmq会话接收消息时可消费的最长时间间隔
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (uint32_t) 默认值: (5 * 1000) ms
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_RECV_TIMEOUT_MS,
|
||||
|
||||
/**
|
||||
* @brief 设置回调, 它在SDK收到网络报文的时候被调用, 告知用户
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (aiot_dynregmq_http_recv_handler_t)
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_RECV_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief 用户需要SDK暂存的上下文
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 这个上下文指针会在 AIOT_DYNREGMQOPT_RECV_HANDLER 和 AIOT_DYNREGMQOPT_EVENT_HANDLER 设置的回调被调用时, 由SDK传给用户
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_USERDATA,
|
||||
|
||||
/**
|
||||
* @brief dynregmq模块接收消息的超时时间
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (uint32_t) 默认值: (5 * 1000) ms
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_TIMEOUT_MS,
|
||||
|
||||
/**
|
||||
* @brief 销毁dynregmq实例时, 等待其他api执行完毕的时间
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 当调用@ref aiot_dynregmq_deinit 销毁MQTT实例时, 若继续调用其他aiot_dynregmq_xxx API, API会返回@ref STATE_USER_INPUT_EXEC_DISABLED 错误
|
||||
*
|
||||
* 此时, 用户应该停止调用其他aiot_dynregmq_xxx API
|
||||
*
|
||||
* 数据类型: (uint32_t *) 默认值: (2 * 1000) ms
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_DEINIT_TIMEOUT_MS,
|
||||
|
||||
/**
|
||||
* @brief 是否使用免白名单功能
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 1. 配置为 0 则为白名单模式, 使用这种模式用户必须提前在控制台录入deviceName, 动态注册完成后服务会返回deviceSecret, 用户可通过
|
||||
* AIOT_DYNREGMQRECV_DEVICEINFO_WL类型数据回调获取到deviceSecret.
|
||||
* 2. 配置为 1 则为免白名单模式, 使用这种模式用户无需提前在控制台录入deviceName, 动态注册完成后服务会返回MQTT建连信息, 用户可通过
|
||||
* AIOT_DYNREGMQRECV_DEVICEINFO_NWL类型数据回调获取到clientid, username, password. 用户需要将这三个参数通过
|
||||
* aiot_mqtt_setopt接口以AIOT_MQTTOPT_CLIENTID, AIOT_MQTTOPT_USERNAME, AIOT_MQTTOPT_PASSWORD配置选项
|
||||
* 配置到MQTT句柄中。
|
||||
*
|
||||
* 数据类型: (uint8_t *) 默认值: (0)
|
||||
*
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_NO_WHITELIST,
|
||||
|
||||
/**
|
||||
* @brief 用户购买的物联网平台实例ID. 当用户使用自购实例, 且使用免白名单方式时, 必须设置实例ID
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*
|
||||
*/
|
||||
AIOT_DYNREGMQOPT_INSTANCE_ID,
|
||||
|
||||
AIOT_DYNREGMQOPT_MAX
|
||||
} aiot_dynregmq_option_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief dynregmq模块收到从网络上来的报文时, 通知用户的报文类型
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 白名单模式下服务器返回的设备信息
|
||||
*/
|
||||
AIOT_DYNREGMQRECV_DEVICEINFO_WL,
|
||||
|
||||
/**
|
||||
* @brief 免白名单模式下服务器返回的设备信息
|
||||
*/
|
||||
AIOT_DYNREGMQRECV_DEVICEINFO_NWL,
|
||||
} aiot_dynregmq_recv_type_t;
|
||||
|
||||
/**
|
||||
* @brief dynregmq模块收到从网络上来的报文时, 通知用户的报文内容
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 报文内容所对应的报文类型, 更多信息请参考@ref aiot_dynregmq_recv_type_t
|
||||
*/
|
||||
aiot_dynregmq_recv_type_t type;
|
||||
union {
|
||||
/**
|
||||
* @brief 白名单模式下服务器返回的设备信息
|
||||
*/
|
||||
struct {
|
||||
char *device_secret;
|
||||
} deviceinfo_wl;
|
||||
|
||||
/**
|
||||
* @brief 免白名单模式下服务器返回的设备信息
|
||||
*/
|
||||
struct {
|
||||
char *clientid;
|
||||
char *username;
|
||||
char *password;
|
||||
} deviceinfo_nwl;
|
||||
} data;
|
||||
} aiot_dynregmq_recv_t;
|
||||
|
||||
/**
|
||||
* @brief dynregmq模块收到从网络上来的报文时, 通知用户所调用的数据回调函数
|
||||
*
|
||||
* @param[in] handle dynregmq会话句柄
|
||||
* @param[in] packet dynregmq消息结构体, 存放收到的dynregmq报文内容
|
||||
* @param[in] userdata 用户上下文
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (* aiot_dynregmq_recv_handler_t)(void *handle,
|
||||
const aiot_dynregmq_recv_t *packet, void *userdata);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 创建dynregmq会话实例, 并以默认值配置会话参数
|
||||
*
|
||||
* @return void *
|
||||
* @retval 非NULL dynregmq实例的句柄
|
||||
* @retval NULL 初始化失败, 一般是内存分配失败导致
|
||||
*
|
||||
*/
|
||||
void *aiot_dynregmq_init(void);
|
||||
|
||||
/**
|
||||
* @brief 配置dynregmq会话
|
||||
*
|
||||
* @param[in] handle dynregmq会话句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_dynregmq_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_dynregmq_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 参数配置失败
|
||||
* @retval >=STATE_SUCCESS 参数配置成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_dynregmq_setopt(void *handle, aiot_dynregmq_option_t option, void *data);
|
||||
|
||||
/**
|
||||
* @brief 结束dynregmq会话, 销毁实例并回收资源
|
||||
*
|
||||
* @param[in] handle 指向dynregmq会话句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 执行失败
|
||||
* @retval >=STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_dynregmq_deinit(void **handle);
|
||||
|
||||
/**
|
||||
* @brief 向dynregmq服务器发送dynregmq消息请求
|
||||
*
|
||||
* @param handle dynregmq会话句柄
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 请求发送失败
|
||||
* @retval >=STATE_SUCCESS 请求发送成功
|
||||
*/
|
||||
int32_t aiot_dynregmq_send_request(void *handle);
|
||||
|
||||
/**
|
||||
* @brief 从网络上收取dynregmq消息
|
||||
*
|
||||
* @param handle dynregmq会话句柄
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 数据接收失败
|
||||
* @retval >=STATE_SUCCESS 数据接收成功
|
||||
*/
|
||||
int32_t aiot_dynregmq_recv(void *handle);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AIOT_DYNREGMQMQ_API_H__ */
|
||||
|
||||
78
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg-mqtt/dynregmq_private.h
vendored
Normal file
78
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg-mqtt/dynregmq_private.h
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @file dynregmq_private.h
|
||||
* @brief dynregmq模块内部的宏定义和数据结构声明, 不面向其它模块, 更不面向用户
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __DYNREGMQ_PRIVATE_H__
|
||||
#define __DYNREGMQ_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 用这种方式包含标准C库的头文件 */
|
||||
#include "core_stdinc.h"
|
||||
|
||||
#include "aiot_state_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_mqtt_api.h"
|
||||
#include "aiot_dynregmq_api.h" /* 内部头文件是用户可见头文件的超集 */
|
||||
|
||||
typedef struct {
|
||||
uint32_t code;
|
||||
uint8_t *content;
|
||||
uint32_t content_len;
|
||||
uint32_t content_total_len;
|
||||
} core_mqtt_response_t;
|
||||
|
||||
/* 定义dynregmq模块内部的会话句柄结构体, SDK用户不可见, 只能得到void *handle类型的指针 */
|
||||
typedef struct {
|
||||
|
||||
aiot_sysdep_portfile_t *sysdep; /* 底层依赖回调合集的引用指针 */
|
||||
aiot_sysdep_network_cred_t *cred; /* 指向当前连接使用的安全凭据 */
|
||||
|
||||
char *host; /* 会话目标服务器域名 */
|
||||
uint16_t port; /* 会话目标服务器端口 */
|
||||
char *product_key;
|
||||
char *product_secret;
|
||||
char *device_name;
|
||||
uint8_t flag_nowhitelist; /* 是否使用免白名单功能 */
|
||||
char
|
||||
*instance_id; /* 实例ID,当用户使用自购实例,且使用免白名单方式时,需设置实例ID */
|
||||
|
||||
aiot_dynregmq_recv_handler_t recv_handler; /* 组件从协议栈读到内容时, 通知用户的回调 */
|
||||
void *userdata; /* 组件调用以上2个 dynregmq_handler 时的入参之一 */
|
||||
|
||||
uint32_t recv_timeout_ms; /* 从协议栈收包时最长等待时间 */
|
||||
uint32_t send_timeout_ms; /* 向协议栈写入时最长花费时间 */
|
||||
uint32_t timeout_ms;
|
||||
uint32_t deinit_timeout_ms;
|
||||
|
||||
/*---- 以上都是用户在API可配 ----*/
|
||||
|
||||
/*---- 以下都是DYNREGMQ在内部使用, 用户无感知 ----*/
|
||||
void *mqtt_handle;
|
||||
uint8_t flag_completed;
|
||||
|
||||
uint8_t exec_enabled;
|
||||
uint32_t exec_count;
|
||||
void *data_mutex; /* 保护本地的数据结构 */
|
||||
|
||||
} dynregmq_handle_t;
|
||||
|
||||
#define DYNREGMQ_MODULE_NAME "dynregmq" /* 用于内存统计的模块名字符串 */
|
||||
|
||||
#define DYNREGMQ_DEFAULT_TIMEOUT_MS (5 * 1000)
|
||||
#define DYNREGMQ_DEFAULT_DEINIT_TIMEOUT_MS (2 * 1000)
|
||||
#define DYNREGMQ_DEFAULT_RECV_TIMEOUT (5 * 1000)
|
||||
#define DYNREGMQ_DEFAULT_SEND_TIMEOUT (5 * 1000)
|
||||
|
||||
#define DYNREGMQ_DEINIT_INTERVAL_MS (100)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* __DYNREGMQ_PRIVATE_H__ */
|
||||
|
||||
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg/README.md
vendored
Normal file
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg/README.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Name: 动态注册
|
||||
DYNREG Component for Link SDK V4.0.0
|
||||
|
||||
522
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg/aiot_dynreg_api.c
vendored
Normal file
522
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg/aiot_dynreg_api.c
vendored
Normal file
@@ -0,0 +1,522 @@
|
||||
/**
|
||||
* @file aiot_dynreg_api.c
|
||||
* @brief dynreg模块的API接口实现, 提供获取设备信息的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#include "dynreg_private.h"
|
||||
|
||||
#include "core_string.h"
|
||||
#include "core_log.h"
|
||||
#include "core_auth.h"
|
||||
|
||||
static void _dynreg_exec_inc(dynreg_handle_t *dynreg_handle)
|
||||
{
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_lock(dynreg_handle->data_mutex);
|
||||
dynreg_handle->exec_count++;
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
}
|
||||
|
||||
static void _dynreg_exec_dec(dynreg_handle_t *dynreg_handle)
|
||||
{
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_lock(dynreg_handle->data_mutex);
|
||||
dynreg_handle->exec_count--;
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
}
|
||||
|
||||
static int32_t _dynreg_sign(dynreg_handle_t *dynreg_handle, char *random, char sign_str[65])
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
uint8_t sign_hex[32] = {0};
|
||||
char *src_fmt = "deviceName%sproductKey%srandom%s";
|
||||
char *src[] = {dynreg_handle->device_name, dynreg_handle->product_key, random};
|
||||
char *plain_text = NULL;
|
||||
|
||||
res = core_sprintf(dynreg_handle->sysdep, &plain_text, src_fmt, src, sizeof(src) / sizeof(char *), DYNREG_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
core_hmac_sha256((const uint8_t *)plain_text, (uint32_t)strlen(plain_text),
|
||||
(const uint8_t *)dynreg_handle->product_secret, (uint32_t)strlen(dynreg_handle->product_secret), sign_hex);
|
||||
core_hex2str(sign_hex, 32, sign_str, 0);
|
||||
|
||||
dynreg_handle->sysdep->core_sysdep_free(plain_text);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static void _dynreg_recv_handler(void *handle, const aiot_http_recv_t *packet, void *userdata)
|
||||
{
|
||||
dynreg_handle_t *dynreg_handle = (dynreg_handle_t *)userdata;
|
||||
|
||||
if (dynreg_handle->recv_handler == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (packet->type) {
|
||||
case AIOT_HTTPRECV_STATUS_CODE: {
|
||||
dynreg_handle->response.code = packet->data.status_code.code;
|
||||
}
|
||||
break;
|
||||
case AIOT_HTTPRECV_HEADER: {
|
||||
if ((strlen(packet->data.header.key) == strlen("Content-Length")) &&
|
||||
(memcmp(packet->data.header.key, "Content-Length", strlen(packet->data.header.key)) == 0)) {
|
||||
core_str2uint(packet->data.header.value, (uint8_t)strlen(packet->data.header.value),
|
||||
&dynreg_handle->response.content_total_len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AIOT_HTTPRECV_BODY: {
|
||||
uint8_t *content = dynreg_handle->sysdep->core_sysdep_malloc(dynreg_handle->response.content_len + packet->data.body.len
|
||||
+ 1,
|
||||
CORE_HTTP_MODULE_NAME);
|
||||
if (content == NULL) {
|
||||
return;
|
||||
}
|
||||
memset(content, 0, dynreg_handle->response.content_len + packet->data.body.len + 1);
|
||||
if (content != NULL) {
|
||||
memcpy(content, dynreg_handle->response.content, dynreg_handle->response.content_len);
|
||||
dynreg_handle->sysdep->core_sysdep_free(dynreg_handle->response.content);
|
||||
}
|
||||
memcpy(content + dynreg_handle->response.content_len, packet->data.body.buffer, packet->data.body.len);
|
||||
dynreg_handle->response.content = content;
|
||||
dynreg_handle->response.content_len = dynreg_handle->response.content_len + packet->data.body.len;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _dynreg_device_info(dynreg_handle_t *dynreg_handle, char **device_secret)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *tmp_ds = NULL, *ds_key = "deviceSecret";
|
||||
char *ds_value = NULL;
|
||||
uint32_t ds_value_len = 0;
|
||||
|
||||
if (dynreg_handle->response.code != 200) {
|
||||
return STATE_DYNREG_INVALID_STATUS_CODE;
|
||||
}
|
||||
|
||||
if ((res = core_json_value((char *)dynreg_handle->response.content, dynreg_handle->response.content_len, ds_key,
|
||||
strlen(ds_key), &ds_value, &ds_value_len)) < STATE_SUCCESS) {
|
||||
return STATE_DYNREG_INVALID_DEVICE_SECRET;
|
||||
}
|
||||
|
||||
tmp_ds = dynreg_handle->sysdep->core_sysdep_malloc(ds_value_len + 1, DYNREG_MODULE_NAME);
|
||||
if (tmp_ds == NULL) {
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
memset(tmp_ds, 0, ds_value_len + 1);
|
||||
memcpy(tmp_ds, ds_value, ds_value_len);
|
||||
|
||||
*device_secret = tmp_ds;
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
void *aiot_dynreg_init(void)
|
||||
{
|
||||
dynreg_handle_t *dynreg_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if (sysdep == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dynreg_handle = sysdep->core_sysdep_malloc(sizeof(dynreg_handle_t), DYNREG_MODULE_NAME);
|
||||
if (dynreg_handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(dynreg_handle, 0, sizeof(dynreg_handle_t));
|
||||
|
||||
dynreg_handle->sysdep = sysdep;
|
||||
dynreg_handle->response_body_len = DYNREG_RESPONSE_BODY_LEN;
|
||||
dynreg_handle->timeout_ms = DYNREG_DEFAULT_TIMEOUT_MS;
|
||||
dynreg_handle->deinit_timeout_ms = DYNREG_DEFAULT_DEINIT_TIMEOUT_MS;
|
||||
dynreg_handle->send_timeout_ms = DYNREG_DEFAULT_SEND_TIMEOUT;
|
||||
dynreg_handle->recv_timeout_ms = DYNREG_DEFAULT_RECV_TIMEOUT;
|
||||
dynreg_handle->data_mutex = dynreg_handle->sysdep->core_sysdep_mutex_init();
|
||||
|
||||
dynreg_handle->exec_enabled = 1;
|
||||
|
||||
return dynreg_handle;
|
||||
}
|
||||
|
||||
int32_t aiot_dynreg_setopt(void *handle, aiot_dynreg_option_t option, void *data)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
dynreg_handle_t *dynreg_handle = (dynreg_handle_t *)handle;
|
||||
|
||||
if (dynreg_handle == NULL || data == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (option >= AIOT_DYNREGOPT_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
if (dynreg_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
_dynreg_exec_inc(dynreg_handle);
|
||||
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_lock(dynreg_handle->data_mutex);
|
||||
switch (option) {
|
||||
case AIOT_DYNREGOPT_NETWORK_CRED: {
|
||||
if (dynreg_handle->cred != NULL) {
|
||||
dynreg_handle->sysdep->core_sysdep_free(dynreg_handle->cred);
|
||||
dynreg_handle->cred = NULL;
|
||||
}
|
||||
dynreg_handle->cred = dynreg_handle->sysdep->core_sysdep_malloc(sizeof(aiot_sysdep_network_cred_t), DYNREG_MODULE_NAME);
|
||||
if (dynreg_handle->cred != NULL) {
|
||||
memset(dynreg_handle->cred, 0, sizeof(aiot_sysdep_network_cred_t));
|
||||
memcpy(dynreg_handle->cred, data, sizeof(aiot_sysdep_network_cred_t));
|
||||
} else {
|
||||
res = STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_HOST: {
|
||||
res = core_strdup(dynreg_handle->sysdep, &dynreg_handle->host, data, DYNREG_MODULE_NAME);
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_PORT: {
|
||||
dynreg_handle->port = *(uint16_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_PRODUCT_KEY: {
|
||||
res = core_strdup(dynreg_handle->sysdep, &dynreg_handle->product_key, data, DYNREG_MODULE_NAME);
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_PRODUCT_SECRET: {
|
||||
res = core_strdup(dynreg_handle->sysdep, &dynreg_handle->product_secret, data, DYNREG_MODULE_NAME);
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_DEVICE_NAME: {
|
||||
res = core_strdup(dynreg_handle->sysdep, &dynreg_handle->device_name, data, DYNREG_MODULE_NAME);
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_SEND_TIMEOUT_MS: {
|
||||
dynreg_handle->send_timeout_ms = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_RECV_TIMEOUT_MS: {
|
||||
dynreg_handle->recv_timeout_ms = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_RECV_HANDLER: {
|
||||
dynreg_handle->recv_handler = (aiot_dynreg_recv_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_USERDATA: {
|
||||
dynreg_handle->userdata = data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_TIMEOUT_MS: {
|
||||
dynreg_handle->timeout_ms = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_DYNREGOPT_DEINIT_TIMEOUT_MS: {
|
||||
dynreg_handle->deinit_timeout_ms = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
res = STATE_USER_INPUT_UNKNOWN_OPTION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_dynreg_deinit(void **handle)
|
||||
{
|
||||
uint64_t deinit_timestart = 0;
|
||||
dynreg_handle_t *dynreg_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
|
||||
if (handle == NULL || *handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
dynreg_handle = *(dynreg_handle_t **)handle;
|
||||
sysdep = dynreg_handle->sysdep;
|
||||
|
||||
if (dynreg_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
dynreg_handle->exec_enabled = 0;
|
||||
deinit_timestart = dynreg_handle->sysdep->core_sysdep_time();
|
||||
do {
|
||||
if (dynreg_handle->exec_count == 0) {
|
||||
break;
|
||||
}
|
||||
dynreg_handle->sysdep->core_sysdep_sleep(DYNREG_DEINIT_INTERVAL_MS);
|
||||
} while ((dynreg_handle->sysdep->core_sysdep_time() - deinit_timestart) < dynreg_handle->deinit_timeout_ms);
|
||||
|
||||
if (dynreg_handle->exec_count != 0) {
|
||||
return STATE_DYNREG_DEINIT_TIMEOUT;
|
||||
}
|
||||
|
||||
*handle = NULL;
|
||||
|
||||
if (dynreg_handle->response.content != NULL) {
|
||||
sysdep->core_sysdep_free(dynreg_handle->response.content);
|
||||
}
|
||||
memset(&dynreg_handle->response, 0, sizeof(core_http_response_t));
|
||||
|
||||
if (dynreg_handle->http_handle != NULL) {
|
||||
core_http_deinit(&dynreg_handle->http_handle);
|
||||
}
|
||||
|
||||
if (dynreg_handle->host != NULL) {
|
||||
sysdep->core_sysdep_free(dynreg_handle->host);
|
||||
}
|
||||
|
||||
if (dynreg_handle->product_key != NULL) {
|
||||
sysdep->core_sysdep_free(dynreg_handle->product_key);
|
||||
}
|
||||
|
||||
if (dynreg_handle->product_secret != NULL) {
|
||||
sysdep->core_sysdep_free(dynreg_handle->product_secret);
|
||||
}
|
||||
|
||||
if (dynreg_handle->device_name != NULL) {
|
||||
sysdep->core_sysdep_free(dynreg_handle->device_name);
|
||||
}
|
||||
|
||||
if (dynreg_handle->cred != NULL) {
|
||||
sysdep->core_sysdep_free(dynreg_handle->cred);
|
||||
}
|
||||
|
||||
sysdep->core_sysdep_mutex_deinit(&dynreg_handle->data_mutex);
|
||||
|
||||
sysdep->core_sysdep_free(dynreg_handle);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t aiot_dynreg_send_request(void *handle)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
dynreg_handle_t *dynreg_handle = (dynreg_handle_t *)handle;
|
||||
|
||||
if (dynreg_handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (dynreg_handle->host == NULL) {
|
||||
return STATE_USER_INPUT_MISSING_HOST;
|
||||
}
|
||||
|
||||
if (dynreg_handle->product_key == NULL) {
|
||||
return STATE_USER_INPUT_MISSING_PRODUCT_KEY;
|
||||
}
|
||||
|
||||
if (dynreg_handle->product_secret == NULL) {
|
||||
return STATE_USER_INPUT_MISSING_PRODUCT_SECRET;
|
||||
}
|
||||
|
||||
if (dynreg_handle->device_name == NULL) {
|
||||
return STATE_USER_INPUT_MISSING_DEVICE_NAME;
|
||||
}
|
||||
|
||||
if (dynreg_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
_dynreg_exec_inc(dynreg_handle);
|
||||
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_lock(dynreg_handle->data_mutex);
|
||||
if (dynreg_handle->response.content != NULL) {
|
||||
dynreg_handle->sysdep->core_sysdep_free(dynreg_handle->response.content);
|
||||
}
|
||||
memset(&dynreg_handle->response, 0, sizeof(core_http_response_t));
|
||||
|
||||
if (dynreg_handle->http_handle != NULL) {
|
||||
core_http_deinit(&dynreg_handle->http_handle);
|
||||
}
|
||||
|
||||
dynreg_handle->http_handle = core_http_init();
|
||||
if (dynreg_handle->http_handle == NULL) {
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
if (((res = core_http_setopt(dynreg_handle->http_handle, CORE_HTTPOPT_HOST,
|
||||
(void *)dynreg_handle->host)) < STATE_SUCCESS) ||
|
||||
((res = core_http_setopt(dynreg_handle->http_handle, CORE_HTTPOPT_PORT, (void *)&dynreg_handle->port)) < STATE_SUCCESS)
|
||||
||
|
||||
((res = core_http_setopt(dynreg_handle->http_handle, CORE_HTTPOPT_NETWORK_CRED,
|
||||
(void *)dynreg_handle->cred)) < STATE_SUCCESS) ||
|
||||
((res = core_http_setopt(dynreg_handle->http_handle, CORE_HTTPOPT_SEND_TIMEOUT_MS,
|
||||
(void *)&dynreg_handle->send_timeout_ms)) < STATE_SUCCESS) ||
|
||||
((res = core_http_setopt(dynreg_handle->http_handle, CORE_HTTPOPT_RECV_TIMEOUT_MS,
|
||||
(void *)&dynreg_handle->recv_timeout_ms)) < STATE_SUCCESS) ||
|
||||
((res = core_http_setopt(dynreg_handle->http_handle, CORE_HTTPOPT_BODY_BUFFER_MAX_LEN,
|
||||
(void *)&dynreg_handle->response_body_len)) < STATE_SUCCESS) ||
|
||||
((res = core_http_setopt(dynreg_handle->http_handle, CORE_HTTPOPT_RECV_HANDLER,
|
||||
(void *)_dynreg_recv_handler)) < STATE_SUCCESS) ||
|
||||
((res = core_http_setopt(dynreg_handle->http_handle, CORE_HTTPOPT_USERDATA, (void *)dynreg_handle)) < STATE_SUCCESS)) {
|
||||
core_http_deinit(&dynreg_handle->http_handle);
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = core_http_connect(dynreg_handle->http_handle);
|
||||
if (res < STATE_SUCCESS) {
|
||||
core_http_deinit(&dynreg_handle->http_handle);
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t random_num = 0;
|
||||
char random[11] = {0};
|
||||
char sign_str[65] = {0};
|
||||
char *content = NULL;
|
||||
char *content_fmt = "productKey=%s&deviceName=%s&random=%s&sign=%s&signMethod=hmacsha256";
|
||||
char *content_src[] = { dynreg_handle->product_key, dynreg_handle->device_name, (char *)random, sign_str };
|
||||
core_http_request_t request;
|
||||
|
||||
dynreg_handle->sysdep->core_sysdep_rand((uint8_t *)&random_num, 4);
|
||||
core_uint2str(random_num, random, NULL);
|
||||
|
||||
res = _dynreg_sign(dynreg_handle, (char *)random, sign_str);
|
||||
if (res < STATE_SUCCESS) {
|
||||
core_http_deinit(&dynreg_handle->http_handle);
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
memset(&request, 0, sizeof(core_http_request_t));
|
||||
res = core_sprintf(dynreg_handle->sysdep, &content, content_fmt, content_src, sizeof(content_src) / sizeof(char *),
|
||||
DYNREG_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
core_http_deinit(&dynreg_handle->http_handle);
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
return res;
|
||||
}
|
||||
request.method = "POST";
|
||||
request.path = DYNREG_PATH;
|
||||
request.header = "Accept: text/xml,text/javascript,text/html,application/json\r\n" \
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n";
|
||||
request.content = (uint8_t *)content;
|
||||
request.content_len = (uint32_t)strlen(content);
|
||||
|
||||
res = core_http_send(dynreg_handle->http_handle, &request);
|
||||
dynreg_handle->sysdep->core_sysdep_free(content);
|
||||
if (res < STATE_SUCCESS) {
|
||||
core_http_deinit(&dynreg_handle->http_handle);
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_dynreg_recv(void *handle)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
uint64_t timenow_ms = 0;
|
||||
dynreg_handle_t *dynreg_handle = (dynreg_handle_t *)handle;
|
||||
char *device_secret = NULL;
|
||||
aiot_dynreg_recv_t packet;
|
||||
|
||||
if (dynreg_handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (dynreg_handle->http_handle == NULL) {
|
||||
return STATE_DYNREG_NEED_SEND_REQUEST;
|
||||
}
|
||||
|
||||
if (dynreg_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
_dynreg_exec_inc(dynreg_handle);
|
||||
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_lock(dynreg_handle->data_mutex);
|
||||
timenow_ms = dynreg_handle->sysdep->core_sysdep_time();
|
||||
while (1) {
|
||||
if (timenow_ms >= dynreg_handle->sysdep->core_sysdep_time()) {
|
||||
timenow_ms = dynreg_handle->sysdep->core_sysdep_time();
|
||||
}
|
||||
if (dynreg_handle->sysdep->core_sysdep_time() - timenow_ms >= dynreg_handle->timeout_ms) {
|
||||
break;
|
||||
}
|
||||
|
||||
res = core_http_recv(dynreg_handle->http_handle);
|
||||
if (res < STATE_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res < STATE_SUCCESS) {
|
||||
if (res != STATE_HTTP_READ_BODY_FINISHED) {
|
||||
if (dynreg_handle->response.content != NULL) {
|
||||
dynreg_handle->sysdep->core_sysdep_free(dynreg_handle->response.content);
|
||||
memset(&dynreg_handle->response, 0, sizeof(core_http_response_t));
|
||||
}
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
return res;
|
||||
} else {
|
||||
res = STATE_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
return STATE_HTTP_RECV_NOT_FINISHED;
|
||||
}
|
||||
|
||||
if (dynreg_handle->recv_handler != NULL) {
|
||||
packet.type = AIOT_DYNREGRECV_STATUS_CODE;
|
||||
packet.data.status_code.code = dynreg_handle->response.code;
|
||||
|
||||
dynreg_handle->recv_handler(dynreg_handle, &packet, dynreg_handle->userdata);
|
||||
}
|
||||
|
||||
res = _dynreg_device_info(dynreg_handle, &device_secret);
|
||||
dynreg_handle->sysdep->core_sysdep_mutex_unlock(dynreg_handle->data_mutex);
|
||||
if (res < STATE_SUCCESS) {
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
memset(&packet, 0, sizeof(aiot_dynreg_recv_t));
|
||||
if (dynreg_handle->recv_handler != NULL) {
|
||||
packet.type = AIOT_DYNREGRECV_DEVICE_INFO;
|
||||
packet.data.device_info.device_secret = device_secret;
|
||||
|
||||
dynreg_handle->recv_handler(dynreg_handle, &packet, dynreg_handle->userdata);
|
||||
}
|
||||
dynreg_handle->sysdep->core_sysdep_free(device_secret);
|
||||
|
||||
_dynreg_exec_dec(dynreg_handle);
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
302
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg/aiot_dynreg_api.h
vendored
Normal file
302
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg/aiot_dynreg_api.h
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
/**
|
||||
* @file aiot_dynreg_api.h
|
||||
* @brief dynreg模块头文件, 提供获取设备信息的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __AIOT_DYNREG_API_H__
|
||||
#define __AIOT_DYNREG_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief -0x0600~-0x06FF表达SDK在dynreg模块内的状态码
|
||||
*/
|
||||
#define STATE_DYNREG_BASE (-0x0600)
|
||||
|
||||
/**
|
||||
* @brief 执行@ref aiot_dynreg_deinit 时, 等待其他API执行结束的超过设定的超时时间, MQTT实例销毁失败
|
||||
*/
|
||||
#define STATE_DYNREG_DEINIT_TIMEOUT (-0x0601)
|
||||
|
||||
/**
|
||||
* @brief 需要首先执行@ref aiot_dynreg_send_request 发送dynreg请求
|
||||
*/
|
||||
#define STATE_DYNREG_NEED_SEND_REQUEST (-0x0602)
|
||||
|
||||
/**
|
||||
* @brief dynreg模块返回了错误的http status code
|
||||
*/
|
||||
#define STATE_DYNREG_INVALID_STATUS_CODE (-0x0603)
|
||||
|
||||
/**
|
||||
* @brief 收到非法的device secret
|
||||
*/
|
||||
#define STATE_DYNREG_INVALID_DEVICE_SECRET (-0x0604)
|
||||
|
||||
/**
|
||||
* @brief dynreg模块收到从网络上来的报文时, 通知用户的报文类型
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief dynreg模块返回的http status code
|
||||
*/
|
||||
AIOT_DYNREGRECV_STATUS_CODE,
|
||||
/**
|
||||
* @brief dynreg模块返回的设备信息
|
||||
*/
|
||||
AIOT_DYNREGRECV_DEVICE_INFO,
|
||||
} aiot_dynreg_recv_type_t;
|
||||
|
||||
/**
|
||||
* @brief dynreg模块收到从网络上来的报文时, 通知用户的报文内容
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 报文内容所对应的报文类型, 更多信息请参考@ref aiot_dynreg_recv_type_t
|
||||
*/
|
||||
aiot_dynreg_recv_type_t type;
|
||||
union {
|
||||
/**
|
||||
* @brief dynreg模块返回的http status code
|
||||
*/
|
||||
struct {
|
||||
uint32_t code;
|
||||
} status_code;
|
||||
/**
|
||||
* @brief dynreg模块返回的设备信息
|
||||
*/
|
||||
struct {
|
||||
char *device_secret;
|
||||
} device_info;
|
||||
} data;
|
||||
} aiot_dynreg_recv_t;
|
||||
|
||||
/**
|
||||
* @brief dynreg模块收到从网络上来的报文时, 通知用户所调用的数据回调函数
|
||||
*
|
||||
* @param[in] handle dynreg会话句柄
|
||||
* @param[in] packet dynreg消息结构体, 存放收到的dynreg报文内容
|
||||
* @param[in] userdata 用户上下文
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (* aiot_dynreg_recv_handler_t)(void *handle,
|
||||
const aiot_dynreg_recv_t *packet, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief @ref aiot_dynreg_setopt 接口的option参数可选值.
|
||||
*
|
||||
* @details 下文每个选项中的数据类型, 指的是@ref aiot_dynreg_setopt 中, data参数的数据类型
|
||||
*
|
||||
* 1. data的数据类型是char *时, 以配置@ref AIOT_DYNREGOPT_HOST 为例:
|
||||
*
|
||||
* char *host = "xxx";
|
||||
* aiot_dynreg_setopt(dynreg_handle, AIOT_DYNREGOPT_HOST, host);
|
||||
*
|
||||
* 2. data的数据类型是其他数据类型时, 以配置@ref AIOT_DYNREGOPT_PORT 为例:
|
||||
*
|
||||
* uint16_t port = 443;
|
||||
* aiot_mqtt_setopt(dynreg_handle, AIOT_DYNREGOPT_PORT, (void *)&port);
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief http动态注册 服务器建联时, 网络使用的安全凭据
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 该配置项用于为底层网络配置@ref aiot_sysdep_network_cred_t 安全凭据数据
|
||||
*
|
||||
* 应当把 @ref aiot_sysdep_network_cred_t 中option配置为@ref AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA , 以tls方式建联
|
||||
*
|
||||
* 数据类型: (aiot_sysdep_network_cred_t *)
|
||||
*/
|
||||
AIOT_DYNREGOPT_NETWORK_CRED,
|
||||
|
||||
/**
|
||||
* @brief http动态注册 服务器的域名地址或者ip地址
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 阿里云物联网平台 http动态注册 服务器域名地址列表:
|
||||
*
|
||||
* | 域名地址 | 区域 | 端口号
|
||||
* |-------------------------------------------------|---------|---------
|
||||
* | iot-auth.cn-shanghai.aliyuncs.com | 国内 | 443
|
||||
* | iot-auth.ap-southeast-1.aliyuncs.com | 海外 | 443
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*/
|
||||
AIOT_DYNREGOPT_HOST,
|
||||
|
||||
/**
|
||||
* @brief http动态注册 服务器的端口号
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 连接阿里云物联网平台 http动态注册 服务器时:
|
||||
*
|
||||
* 必须使用tls方式建联, 端口号设置为443
|
||||
*
|
||||
* 数据类型: (uint16_t *)
|
||||
*/
|
||||
AIOT_DYNREGOPT_PORT,
|
||||
|
||||
/**
|
||||
* @brief 设备的productKey, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*/
|
||||
AIOT_DYNREGOPT_PRODUCT_KEY,
|
||||
|
||||
/**
|
||||
* @brief 设备的productSecret, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*/
|
||||
AIOT_DYNREGOPT_PRODUCT_SECRET,
|
||||
|
||||
/**
|
||||
* @brief 设备的deviceName, 可从<a href="http://iot.console.aliyun.com/">阿里云物联网平台控制台</a>获取
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*/
|
||||
AIOT_DYNREGOPT_DEVICE_NAME,
|
||||
|
||||
/**
|
||||
* @brief dynreg会话发送消息时可消费的最长时间间隔
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (uint32_t) 默认值: (5 * 1000) ms
|
||||
*/
|
||||
AIOT_DYNREGOPT_SEND_TIMEOUT_MS,
|
||||
|
||||
/**
|
||||
* @brief dynreg会话接收消息时可消费的最长时间间隔
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (uint32_t) 默认值: (5 * 1000) ms
|
||||
*/
|
||||
AIOT_DYNREGOPT_RECV_TIMEOUT_MS,
|
||||
|
||||
/**
|
||||
* @brief 设置回调, 它在SDK收到网络报文的时候被调用, 告知用户
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (aiot_dynreg_http_recv_handler_t)
|
||||
*/
|
||||
AIOT_DYNREGOPT_RECV_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief 用户需要SDK暂存的上下文
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 这个上下文指针会在 AIOT_DYNREGOPT_RECV_HANDLER 和 AIOT_DYNREGOPT_EVENT_HANDLER 设置的回调被调用时, 由SDK传给用户
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_DYNREGOPT_USERDATA,
|
||||
|
||||
/**
|
||||
* @brief dynreg模块接收消息的超时时间
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (uint32_t) 默认值: (5 * 1000) ms
|
||||
*/
|
||||
AIOT_DYNREGOPT_TIMEOUT_MS,
|
||||
|
||||
/**
|
||||
* @brief 销毁dynreg实例时, 等待其他api执行完毕的时间
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 当调用@ref aiot_dynreg_deinit 销毁MQTT实例时, 若继续调用其他aiot_dynreg_xxx API, API会返回@ref STATE_USER_INPUT_EXEC_DISABLED 错误
|
||||
*
|
||||
* 此时, 用户应该停止调用其他aiot_dynreg_xxx API
|
||||
*
|
||||
* 数据类型: (uint32_t *) 默认值: (2 * 1000) ms
|
||||
*/
|
||||
AIOT_DYNREGOPT_DEINIT_TIMEOUT_MS,
|
||||
AIOT_DYNREGOPT_MAX
|
||||
} aiot_dynreg_option_t;
|
||||
|
||||
/**
|
||||
* @brief 创建dynreg会话实例, 并以默认值配置会话参数
|
||||
*
|
||||
* @return void *
|
||||
* @retval 非NULL dynreg实例的句柄
|
||||
* @retval NULL 初始化失败, 一般是内存分配失败导致
|
||||
*
|
||||
*/
|
||||
void *aiot_dynreg_init(void);
|
||||
|
||||
/**
|
||||
* @brief 配置dynreg会话
|
||||
*
|
||||
* @param[in] handle dynreg会话句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_dynreg_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_dynreg_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 参数配置失败
|
||||
* @retval >=STATE_SUCCESS 参数配置成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_dynreg_setopt(void *handle, aiot_dynreg_option_t option, void *data);
|
||||
|
||||
/**
|
||||
* @brief 结束dynreg会话, 销毁实例并回收资源
|
||||
*
|
||||
* @param[in] handle 指向dynreg会话句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 执行失败
|
||||
* @retval >=STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_dynreg_deinit(void **handle);
|
||||
|
||||
/**
|
||||
* @brief 向dynreg服务器发送dynreg消息请求
|
||||
*
|
||||
* @param handle dynreg会话句柄
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 请求发送失败
|
||||
* @retval >=STATE_SUCCESS 请求发送成功
|
||||
*/
|
||||
int32_t aiot_dynreg_send_request(void *handle);
|
||||
|
||||
/**
|
||||
* @brief 从网络上收取dynreg消息
|
||||
*
|
||||
* @param handle dynreg会话句柄
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 数据接收失败
|
||||
* @retval >=STATE_SUCCESS 数据接收成功
|
||||
*/
|
||||
int32_t aiot_dynreg_recv(void *handle);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AIOT_DYNREG_API_H__ */
|
||||
|
||||
73
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg/dynreg_private.h
vendored
Normal file
73
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/dynreg/dynreg_private.h
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @file dynreg_private.h
|
||||
* @brief dynreg模块内部的宏定义和数据结构声明, 不面向其它模块, 更不面向用户
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __DYNREG_PRIVATE_H__
|
||||
#define __DYNREG_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 用这种方式包含标准C库的头文件 */
|
||||
#include "core_stdinc.h"
|
||||
|
||||
/* TODO: 这一段列出需要包含SDK其它模块头文件, 与上一段落以1个空行隔开 */
|
||||
#include "aiot_state_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "core_http.h"
|
||||
#include "aiot_dynreg_api.h" /* 内部头文件是用户可见头文件的超集 */
|
||||
|
||||
/* TODO: 定义dynreg模块内部的会话句柄结构体, SDK用户不可见, 只能得到void *handle类型的指针 */
|
||||
typedef struct {
|
||||
|
||||
aiot_sysdep_portfile_t *sysdep; /* 底层依赖回调合集的引用指针 */
|
||||
aiot_sysdep_network_cred_t *cred; /* 指向当前连接使用的安全凭据 */
|
||||
|
||||
char *host; /* 会话目标服务器域名 */
|
||||
uint16_t port; /* 会话目标服务器端口 */
|
||||
char *product_key;
|
||||
char *product_secret;
|
||||
char *device_name;
|
||||
|
||||
aiot_dynreg_recv_handler_t recv_handler; /* 组件从协议栈读到内容时, 通知用户的回调 */
|
||||
void *userdata; /* 组件调用以上2个 dynreg_handler 时的入参之一 */
|
||||
|
||||
uint32_t recv_timeout_ms; /* 从协议栈收包时最长等待时间 */
|
||||
uint32_t send_timeout_ms; /* 向协议栈写入时最长花费时间 */
|
||||
uint32_t timeout_ms;
|
||||
uint32_t deinit_timeout_ms;
|
||||
|
||||
/*---- 以上都是用户在API可配 ----*/
|
||||
|
||||
/*---- 以下都是DYNREG在内部使用, 用户无感知 ----*/
|
||||
void *http_handle;
|
||||
core_http_response_t response;
|
||||
uint32_t response_body_len;
|
||||
uint8_t exec_enabled;
|
||||
uint32_t exec_count;
|
||||
|
||||
void *data_mutex; /* 保护本地的数据结构 */
|
||||
|
||||
} dynreg_handle_t;
|
||||
|
||||
#define DYNREG_MODULE_NAME "dynreg" /* 用于内存统计的模块名字符串 */
|
||||
|
||||
#define DYNREG_DEFAULT_TIMEOUT_MS (5 * 1000)
|
||||
#define DYNREG_DEFAULT_DEINIT_TIMEOUT_MS (2 * 1000)
|
||||
#define DYNREG_DEFAULT_RECV_TIMEOUT (5 * 1000)
|
||||
#define DYNREG_DEFAULT_SEND_TIMEOUT (5 * 1000)
|
||||
|
||||
#define DYNREG_PATH "/auth/register/device"
|
||||
|
||||
#define DYNREG_DEINIT_INTERVAL_MS (100)
|
||||
#define DYNREG_RESPONSE_BODY_LEN (192)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* __DYNREG_PRIVATE_H__ */
|
||||
|
||||
65
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_fs_api.h
vendored
Normal file
65
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_fs_api.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @file aiot_fs_api.h
|
||||
* @brief SDK linkspeech依赖的文件操作,所有依赖的文件操作将在此列出
|
||||
* @date 2019-12-27
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2025 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AIOT_FS_API_H_
|
||||
#define _AIOT_FS_API_H_
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief 用以向SDK描述其运行硬件平台的资源如何使用的方法结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 查询文件大小
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval -1 文件不存在
|
||||
* @retval >=0 实际文件大小
|
||||
*/
|
||||
int32_t (*file_size)(char *path);
|
||||
/**
|
||||
* @brief 删除文件
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval 0 文件删除成功
|
||||
* @retval -1 文件修改失败
|
||||
*/
|
||||
int32_t (*file_delete)(char *path);
|
||||
/**
|
||||
* @brief 写文件数据
|
||||
*
|
||||
* @details 如果文件不存在,则创建新文件
|
||||
* @return int32_t
|
||||
* @retval 成功,返回写入的文件长度
|
||||
* @retval 失败,返回-1
|
||||
*/
|
||||
int32_t (*file_write)(char *path, uint32_t offset, uint8_t *data, uint32_t len);
|
||||
/**
|
||||
* @brief 写文件数据
|
||||
*
|
||||
* @details open操作需用户执行
|
||||
* @return int32_t
|
||||
* @retval 成功,返回读取到的文件长度
|
||||
* @retval 失败,返回-1
|
||||
*/
|
||||
int32_t (*file_read)(char *path, uint32_t offset, uint8_t *data, uint32_t len);
|
||||
} aiot_fs_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
948
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_linkspeech_api.c
vendored
Normal file
948
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_linkspeech_api.c
vendored
Normal file
@@ -0,0 +1,948 @@
|
||||
#include "aiot_linkspeech_api.h"
|
||||
#include "aiot_fs_api.h"
|
||||
#include "aiot_dm_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_state_api.h"
|
||||
#include <stdio.h>
|
||||
#include <cJSON.h>
|
||||
#include <string.h>
|
||||
#include "core_string.h"
|
||||
#include "http_download.h"
|
||||
#include "core_list.h"
|
||||
#include "speech_trans.h"
|
||||
#include "core_log.h"
|
||||
|
||||
#define TAG "LINKSPEECH"
|
||||
|
||||
/* 文件系统抽象接口 */
|
||||
static aiot_fs_t *fs = NULL;
|
||||
/* 操作系统抽象接口*/
|
||||
static aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
#define AIOT_LSOPT_SPEECH_BUFFER_SIZE_DEFAULT 10
|
||||
#define AIOT_SPEECH_DUPLICATE_SIZE_DEFAULT 15
|
||||
|
||||
typedef struct {
|
||||
char *jobcode;
|
||||
char *json_url;
|
||||
struct core_list_head linked_node;
|
||||
} core_download_node_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t msg_id;
|
||||
char *rrpc_id;
|
||||
char *id;
|
||||
char *format;
|
||||
char *speechs;
|
||||
struct core_list_head play_list;
|
||||
struct core_list_head linked_node;
|
||||
} core_speech_task_t;
|
||||
|
||||
typedef struct {
|
||||
/* 物模型对象*/
|
||||
void *dm_handle;
|
||||
/* 音频播放接口 */
|
||||
player_cb_t player;
|
||||
/* 用户设置工作目录 */
|
||||
char *work_dir;
|
||||
int32_t https_enable;
|
||||
int32_t speech_buffer_size;
|
||||
|
||||
/* 以上内容为用户配置,以下为运行时状态 */
|
||||
|
||||
/* 下载任务管理 */
|
||||
void *download_mutex;
|
||||
struct core_list_head download_task_list;
|
||||
/* 播报任务管理 */
|
||||
void *speech_task_mutex;
|
||||
int32_t speech_task_num;
|
||||
struct core_list_head speech_task_list;
|
||||
/* 用于判断是否需要退出千里传音 */
|
||||
int8_t running;
|
||||
/* 正在播报的任务 */
|
||||
core_speech_task_t *playing_task;
|
||||
/* 播放音频回调参数 */
|
||||
play_param_t play_param;
|
||||
/* 防止重复播放 */
|
||||
char *dup_id[AIOT_SPEECH_DUPLICATE_SIZE_DEFAULT];
|
||||
int8_t write_pos;
|
||||
} linkspeech_handle_t;
|
||||
|
||||
typedef struct {
|
||||
linkspeech_handle_t *linkspeech;
|
||||
char *file_name;
|
||||
} download_userdata_t;
|
||||
|
||||
static int32_t file_write(uint32_t offset, uint8_t *data, uint32_t data_len, void *userdata) {
|
||||
char *file_name = (char *)userdata;
|
||||
if(userdata == NULL || data == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
core_log3(sysdep, 0, "file %s, offset %d, len %d\r\n", file_name, &offset, &data_len);
|
||||
|
||||
return fs->file_write(file_name, offset, data, data_len);
|
||||
}
|
||||
|
||||
/* 下载文件到本地文件系统 */
|
||||
static int32_t core_download_file(const char *remote_url, const char *local_url, int32_t tls) {
|
||||
http_download_params_t params;
|
||||
core_log2(sysdep, 0, "[http] remote %s, local %s\r\n", (char *)remote_url, (char *)local_url);
|
||||
|
||||
if(tls == 0) {
|
||||
return core_http_download_request((char *)remote_url, NULL, file_write, (void *)local_url);
|
||||
} else {
|
||||
memset(¶ms, 0, sizeof(http_download_params_t));
|
||||
params.https_enable = 1;
|
||||
return core_http_download_request((char *)remote_url, ¶ms, file_write, (void *)local_url);
|
||||
}
|
||||
}
|
||||
|
||||
/* 事件上报函数演示 */
|
||||
static int32_t core_send_event_post(void *dm_handle, char *event_id, char *params)
|
||||
{
|
||||
aiot_dm_msg_t msg;
|
||||
|
||||
memset(&msg, 0, sizeof(aiot_dm_msg_t));
|
||||
msg.type = AIOT_DMMSG_EVENT_POST;
|
||||
msg.data.event_post.event_id = event_id;
|
||||
msg.data.event_post.params = params;
|
||||
|
||||
return aiot_dm_send(dm_handle, &msg);
|
||||
}
|
||||
|
||||
static int32_t core_delete_speech_task(core_speech_task_t *speech_task)
|
||||
{
|
||||
play_node_t *node = NULL, *next = NULL;
|
||||
if(speech_task == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(speech_task->rrpc_id != NULL) {
|
||||
sysdep->core_sysdep_free(speech_task->rrpc_id);
|
||||
}
|
||||
|
||||
if(speech_task->id != NULL) {
|
||||
sysdep->core_sysdep_free(speech_task->id);
|
||||
}
|
||||
|
||||
if(speech_task->format != NULL) {
|
||||
sysdep->core_sysdep_free(speech_task->format);
|
||||
}
|
||||
|
||||
if(speech_task->speechs != NULL) {
|
||||
sysdep->core_sysdep_free(speech_task->speechs);
|
||||
}
|
||||
|
||||
core_list_for_each_entry_safe(node, next, &speech_task->play_list, linked_node, play_node_t) {
|
||||
core_list_del(&node->linked_node);
|
||||
if(node->filename != NULL) {
|
||||
sysdep->core_sysdep_free(node->filename);
|
||||
}
|
||||
sysdep->core_sysdep_free(node);
|
||||
}
|
||||
|
||||
sysdep->core_sysdep_free(speech_task);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
/* 将语料信息转换为语料文件路径 */
|
||||
static int32_t core_speech_task_prepare(core_speech_task_t *speech_task)
|
||||
{
|
||||
cJSON *speechs = cJSON_Parse(speech_task->speechs);
|
||||
char *value = NULL;
|
||||
/* 如果是否json格式数据 */
|
||||
if (speechs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 将语料信息加入到播放列表中 */
|
||||
CORE_INIT_LIST_HEAD(&speech_task->play_list);
|
||||
for (int i = 0; i < cJSON_GetArraySize(speechs); i++)
|
||||
{
|
||||
value = cJSON_GetArrayItem(speechs, i)->valuestring;
|
||||
if(*value == '{' && *(value + 1)== '$') {
|
||||
money_to_speech(value + 2, speech_task->format, &speech_task->play_list);
|
||||
} else {
|
||||
name_to_speech(value, speech_task->format, &speech_task->play_list);
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(speechs);
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
/* 检查是否重复播放,如果不是重复播放,添加进查重播报列表 */
|
||||
static int32_t core_speech_duplicate_check(linkspeech_handle_t *linkspeech, core_speech_task_t *speech_task)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* 查重 */
|
||||
for(i = 0; i < AIOT_SPEECH_DUPLICATE_SIZE_DEFAULT; i++) {
|
||||
if(linkspeech->dup_id[i] != NULL && 0 == strcmp(speech_task->id, linkspeech->dup_id[i])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 添加 */
|
||||
if(linkspeech->dup_id[linkspeech->write_pos] != NULL) {
|
||||
sysdep->core_sysdep_free(linkspeech->dup_id[linkspeech->write_pos]);
|
||||
linkspeech->dup_id[linkspeech->write_pos] = NULL;
|
||||
}
|
||||
|
||||
core_strdup(sysdep, &linkspeech->dup_id[linkspeech->write_pos], speech_task->id, TAG);
|
||||
linkspeech->write_pos++;
|
||||
if(linkspeech->write_pos >= AIOT_SPEECH_DUPLICATE_SIZE_DEFAULT) {
|
||||
linkspeech->write_pos = 0;
|
||||
}
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
/* 检查语料文件是否存在 */
|
||||
static int32_t core_speech_task_file_check(linkspeech_handle_t *linkspeech, core_speech_task_t *speech_task)
|
||||
{
|
||||
play_node_t *node = NULL, *next = NULL;
|
||||
char *path = NULL;
|
||||
char *src[2] = { NULL, NULL};
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
res = core_speech_task_prepare(speech_task);
|
||||
if(res != STATE_SUCCESS ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
core_list_for_each_entry_safe(node, next, &speech_task->play_list, linked_node, play_node_t) {
|
||||
src[0] = linkspeech->work_dir;
|
||||
src[1] = node->filename;
|
||||
path = NULL;
|
||||
core_sprintf(sysdep, &path, "%s/%s", src, sizeof(src)/sizeof(char *), TAG);
|
||||
sysdep->core_sysdep_free(node->filename);
|
||||
node->filename = path;
|
||||
if(fs->file_size(node->filename) <= 0) {
|
||||
core_log1(sysdep, 0, "loss file %s\r\n", node->filename);
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t send_speech_task_result(linkspeech_handle_t *linkspeech, core_speech_task_t* speech_task, int32_t code)
|
||||
{
|
||||
aiot_dm_msg_t msg;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *data = NULL;
|
||||
char *src[] = { NULL, NULL, NULL };
|
||||
|
||||
if(linkspeech == NULL || speech_task == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(code){
|
||||
case 1:{
|
||||
src[0] = "1";
|
||||
src[1] = "duplicate speechbroad id";
|
||||
}
|
||||
break;
|
||||
case 2:{
|
||||
src[0] = "2";
|
||||
src[1] = "speechs file not found";
|
||||
}
|
||||
break;
|
||||
default:{
|
||||
src[0] = "0";
|
||||
src[1] = "success";
|
||||
}
|
||||
break;
|
||||
}
|
||||
src[2] = speech_task->id;
|
||||
core_sprintf(sysdep, &data, "{\"result\":%s,\"error_message\":\"%s\",\"task_id\":\"%s\"}", src, sizeof(src) / sizeof(char *), TAG );
|
||||
|
||||
memset(&msg, 0, sizeof(aiot_dm_msg_t));
|
||||
if(speech_task->rrpc_id != NULL) {
|
||||
msg.type = AIOT_DMMSG_SYNC_SERVICE_REPLY;
|
||||
msg.data.sync_service_reply.rrpc_id = speech_task->rrpc_id;
|
||||
msg.data.sync_service_reply.msg_id = speech_task->msg_id;
|
||||
msg.data.sync_service_reply.service_id = "SyncSpeechBroadcast";
|
||||
msg.data.sync_service_reply.code = 200;
|
||||
msg.data.sync_service_reply.data = data;
|
||||
} else {
|
||||
memset(&msg, 0, sizeof(aiot_dm_msg_t));
|
||||
msg.type = AIOT_DMMSG_ASYNC_SERVICE_REPLY;
|
||||
msg.data.async_service_reply.msg_id = speech_task->msg_id;
|
||||
msg.data.async_service_reply.code = 200;
|
||||
msg.data.async_service_reply.service_id = "SpeechBroadcast";
|
||||
msg.data.async_service_reply.data = data;
|
||||
}
|
||||
|
||||
res = aiot_dm_send(linkspeech->dm_handle, &msg);
|
||||
sysdep->core_sysdep_free(data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static core_speech_task_t* core_speech_update_task(linkspeech_handle_t *linkspeech)
|
||||
{
|
||||
core_speech_task_t* speech_task = NULL;
|
||||
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->speech_task_mutex);
|
||||
if(core_list_empty(&linkspeech->speech_task_list)) {
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
speech_task = core_list_first_entry(&linkspeech->speech_task_list, core_speech_task_t, linked_node);
|
||||
core_list_del(&speech_task->linked_node);
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
|
||||
return speech_task;
|
||||
}
|
||||
|
||||
static int32_t core_check_play_task(linkspeech_handle_t *linkspeech)
|
||||
{
|
||||
play_node_t *node = NULL;
|
||||
|
||||
if( linkspeech->playing_task == NULL ) {
|
||||
linkspeech->playing_task = core_speech_update_task(linkspeech);
|
||||
if(linkspeech->playing_task == NULL || core_list_empty(&linkspeech->playing_task->play_list)) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* 播放完单个文件,删除 */
|
||||
node = core_list_first_entry(&linkspeech->playing_task->play_list, play_node_t, linked_node);
|
||||
core_list_del(&node->linked_node);
|
||||
sysdep->core_sysdep_free(node->filename);
|
||||
sysdep->core_sysdep_free(node);
|
||||
|
||||
/* 查询任务是否播放完成 */
|
||||
if(core_list_empty(&linkspeech->playing_task->play_list)) {
|
||||
/* 异步回复任务播放完成 */
|
||||
if(linkspeech->playing_task->rrpc_id == NULL) {
|
||||
send_speech_task_result(linkspeech, linkspeech->playing_task, 0);
|
||||
}
|
||||
/* 回收任务资源 */
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->speech_task_mutex);
|
||||
core_list_del(&linkspeech->playing_task->linked_node);
|
||||
core_delete_speech_task(linkspeech->playing_task);
|
||||
linkspeech->speech_task_num--;
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
|
||||
/* 更新下个播报任务 */
|
||||
linkspeech->playing_task = core_speech_update_task(linkspeech);
|
||||
if(linkspeech->playing_task == NULL || core_list_empty(&linkspeech->playing_task->play_list)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( linkspeech->playing_task != NULL && linkspeech->player != NULL ) {
|
||||
node = core_list_first_entry(&linkspeech->playing_task->play_list, play_node_t, linked_node);
|
||||
linkspeech->player(node->filename, &linkspeech->play_param);
|
||||
}
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static core_speech_task_t *core_speech_broadcast_parse(linkspeech_handle_t *linkspeech, char *data, int datalen)
|
||||
{
|
||||
cJSON *speechs = NULL, *format = NULL, *id = NULL;
|
||||
core_speech_task_t *speech_task = NULL;
|
||||
cJSON *root = cJSON_Parse(data);
|
||||
|
||||
/* 如果是否json格式数据 */
|
||||
if (root == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
speechs = cJSON_GetObjectItem(root, "speechs");
|
||||
if (speechs == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
format = cJSON_GetObjectItem(root, "format");
|
||||
if (format == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
id = cJSON_GetObjectItem(root, "id");
|
||||
if (id == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
speech_task = sysdep->core_sysdep_malloc(sizeof(core_speech_task_t), TAG);
|
||||
if(speech_task == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return NULL;
|
||||
}
|
||||
memset(speech_task, 0, sizeof(*speech_task));
|
||||
CORE_INIT_LIST_HEAD(&speech_task->play_list);
|
||||
|
||||
core_strdup(sysdep, &speech_task->format, format->valuestring, TAG);
|
||||
core_strdup(sysdep, &speech_task->id, id->valuestring, TAG);
|
||||
speech_task->speechs = cJSON_Print(speechs);
|
||||
cJSON_Delete(root);
|
||||
|
||||
return speech_task;
|
||||
}
|
||||
|
||||
/* 解析语料下载任务,并执行 */
|
||||
static int32_t core_speech_download_parse(linkspeech_handle_t *linkspeech, char *data, int datalen)
|
||||
{
|
||||
char *jobcode = NULL;
|
||||
char *value = NULL;
|
||||
uint32_t value_len = 0;
|
||||
core_download_node_t *node = NULL;
|
||||
|
||||
/* 解析下载jobcode*/
|
||||
int res = core_json_value(data, datalen,
|
||||
"jobcode", strlen("jobcode"), &value, &value_len);
|
||||
if (res != STATE_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
jobcode = sysdep->core_sysdep_malloc(value_len + 1, TAG);
|
||||
memcpy(jobcode, value, value_len);
|
||||
jobcode[value_len] = 0;
|
||||
|
||||
res = core_json_value(data, datalen,
|
||||
"url", strlen("url"), &value, &value_len);
|
||||
if (res != STATE_SUCCESS) {
|
||||
sysdep->core_sysdep_free(jobcode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 记录下载的url及jobcode,插入下载任务列表中 */
|
||||
node = (core_download_node_t *)sysdep->core_sysdep_malloc(sizeof(core_download_node_t), TAG);
|
||||
memset(node, 0, sizeof(*node));
|
||||
node->json_url = sysdep->core_sysdep_malloc(value_len + 1, TAG);
|
||||
memcpy(node->json_url, value, value_len);
|
||||
*(node->json_url + value_len) = 0;
|
||||
node->jobcode = jobcode;
|
||||
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->download_mutex);
|
||||
core_list_add_tail(&node->linked_node, &linkspeech->download_task_list);
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->download_mutex);
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
/* 批量删除语料 */
|
||||
static int32_t core_speech_delete_parse(linkspeech_handle_t *linkspeech, char *data, uint32_t datalen)
|
||||
{
|
||||
cJSON *root = NULL, *speechs = NULL, *speech = NULL;
|
||||
cJSON *formart, *id;
|
||||
char *filename = NULL;
|
||||
char *src[3] = {NULL, NULL, NULL};
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
//如果是否json格式数据
|
||||
root = cJSON_Parse(data);
|
||||
if (root == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
speechs = cJSON_GetObjectItem(root, "speechs");
|
||||
if (speechs == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cJSON_GetArraySize(speechs); i++)
|
||||
{
|
||||
speech = cJSON_GetArrayItem(speechs, i);
|
||||
if(speech != NULL) {
|
||||
formart = cJSON_GetObjectItem(speech, "format");
|
||||
id = cJSON_GetObjectItem(speech, "id");
|
||||
src[0] = linkspeech->work_dir;
|
||||
src[1] = id->valuestring;
|
||||
src[2] = formart->valuestring;
|
||||
core_sprintf(sysdep, &filename, "%s/%s.%s", src, sizeof(src) / sizeof(char *), TAG );
|
||||
/* 存在该文件就删除 */
|
||||
if(fs->file_size(filename) > 0) {
|
||||
fs->file_delete(filename);
|
||||
}
|
||||
sysdep->core_sysdep_free(filename);
|
||||
}
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* 物模型服务调用处理 */
|
||||
static void core_dm_recv_async_service_invoke(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = (linkspeech_handle_t *)userdata;
|
||||
core_speech_task_t *speech_task = NULL;
|
||||
aiot_dm_msg_t msg;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if(linkspeech == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 消息回复 */
|
||||
memset(&msg, 0, sizeof(aiot_dm_msg_t));
|
||||
msg.type = AIOT_DMMSG_ASYNC_SERVICE_REPLY;
|
||||
msg.data.async_service_reply.msg_id = recv->data.async_service_invoke.msg_id;
|
||||
msg.data.async_service_reply.code = 200;
|
||||
msg.data.async_service_reply.service_id = recv->data.async_service_invoke.service_id;
|
||||
msg.data.async_service_reply.data = "{}";
|
||||
|
||||
if(0 == strcmp(recv->data.async_service_invoke.service_id, "SpeechPost")) {
|
||||
/* 语料下发 */
|
||||
core_speech_download_parse(linkspeech, recv->data.async_service_invoke.params, recv->data.async_service_invoke.params_len);
|
||||
res = aiot_dm_send(dm_handle, &msg);
|
||||
if (res < 0) {
|
||||
core_log(sysdep, 0, "aiot_dm_send failed\r\n");
|
||||
}
|
||||
} else if(0 == strcmp(recv->data.async_service_invoke.service_id, "DeleteSpeech")) {
|
||||
/* 语料批量删除 */
|
||||
core_speech_delete_parse(linkspeech, recv->data.async_service_invoke.params, recv->data.async_service_invoke.params_len);
|
||||
res = aiot_dm_send(dm_handle, &msg);
|
||||
if (res < 0) {
|
||||
core_log(sysdep, 0, "aiot_dm_send failed\r\n");
|
||||
}
|
||||
}
|
||||
else if(0 == strcmp(recv->data.async_service_invoke.service_id, "SpeechBroadcast")) {
|
||||
if(linkspeech->speech_task_num > linkspeech->speech_buffer_size) {
|
||||
core_log2(sysdep, 0, "SpeechBroadcast task buff full [%d] > [%d]\r\n", &linkspeech->speech_task_num, &linkspeech->speech_buffer_size);
|
||||
return;
|
||||
}
|
||||
/* 语料组合播报 */
|
||||
speech_task = core_speech_broadcast_parse(linkspeech, recv->data.async_service_invoke.params, recv->data.async_service_invoke.params_len);
|
||||
if(speech_task != NULL) {
|
||||
speech_task->rrpc_id = NULL;
|
||||
speech_task->msg_id = recv->data.async_service_invoke.msg_id;
|
||||
if(STATE_SUCCESS != core_speech_duplicate_check(linkspeech, speech_task)) {
|
||||
core_log1(sysdep, 0, "SpeechBroadcast duplicate id [%s]\r\n", speech_task->id);
|
||||
send_speech_task_result(linkspeech, speech_task, 1);
|
||||
core_delete_speech_task(speech_task);
|
||||
return;
|
||||
} else if(STATE_SUCCESS != core_speech_task_file_check(linkspeech, speech_task)){
|
||||
send_speech_task_result(linkspeech, speech_task, 2);
|
||||
core_delete_speech_task(speech_task);
|
||||
return;
|
||||
} else {
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->speech_task_mutex);
|
||||
core_list_add_tail(&speech_task->linked_node, &linkspeech->speech_task_list);
|
||||
linkspeech->speech_task_num++;
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
if( linkspeech->playing_task == NULL ) {
|
||||
core_check_play_task(linkspeech);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 物模型同步服务调用处理 */
|
||||
static void core_dm_recv_sync_service_invoke(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = (linkspeech_handle_t *)userdata;
|
||||
core_speech_task_t *speech_task = NULL;
|
||||
|
||||
if(0 == strcmp(recv->data.sync_service_invoke.service_id, "SyncSpeechBroadcast")) {
|
||||
if(linkspeech->speech_task_num > linkspeech->speech_buffer_size) {
|
||||
core_log2(sysdep, 0, "SpeechBroadcast task buff full [%d] > [%d]\r\n", &linkspeech->speech_task_num, &linkspeech->speech_buffer_size);
|
||||
return;
|
||||
}
|
||||
/* 语料组合播报 */
|
||||
speech_task = core_speech_broadcast_parse(linkspeech, recv->data.sync_service_invoke.params, recv->data.sync_service_invoke.params_len);
|
||||
if(speech_task != NULL) {
|
||||
speech_task->rrpc_id = NULL;
|
||||
core_strdup(sysdep, &speech_task->rrpc_id, recv->data.sync_service_invoke.rrpc_id, TAG);
|
||||
speech_task->msg_id = recv->data.async_service_invoke.msg_id;
|
||||
if(STATE_SUCCESS != core_speech_duplicate_check(linkspeech, speech_task)) {
|
||||
core_log1(sysdep, 0, "SpeechBroadcast duplicate id [%s]\r\n", speech_task->id);
|
||||
send_speech_task_result(linkspeech, speech_task, 1);
|
||||
core_delete_speech_task(speech_task);
|
||||
return;
|
||||
} else if(STATE_SUCCESS != core_speech_task_file_check(linkspeech, speech_task)){
|
||||
send_speech_task_result(linkspeech, speech_task, 2);
|
||||
core_delete_speech_task(speech_task);
|
||||
return;
|
||||
} else {
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->speech_task_mutex);
|
||||
core_list_add_tail(&speech_task->linked_node, &linkspeech->speech_task_list);
|
||||
linkspeech->speech_task_num++;
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
/* 同步调用需要立即返回立即返回 */
|
||||
send_speech_task_result(linkspeech, speech_task, 0);
|
||||
if( linkspeech->playing_task == NULL ) {
|
||||
core_check_play_task(linkspeech);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 用户数据接收处理回调函数 */
|
||||
static void core_dm_recv_handler(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata)
|
||||
{
|
||||
switch (recv->type) {
|
||||
/* 异步服务调用 */
|
||||
case AIOT_DMRECV_ASYNC_SERVICE_INVOKE: {
|
||||
core_dm_recv_async_service_invoke(dm_handle, recv, userdata);
|
||||
}
|
||||
break;
|
||||
|
||||
/* 同步服务调用 */
|
||||
case AIOT_DMRECV_SYNC_SERVICE_INVOKE: {
|
||||
core_dm_recv_sync_service_invoke(dm_handle, recv, userdata);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void core_play_finished(char *filename, void *userdata)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = (linkspeech_handle_t *)userdata;
|
||||
if(linkspeech == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
core_log1(sysdep, 0, "core_play_finished file %s\r\n", filename);
|
||||
core_check_play_task(linkspeech);
|
||||
}
|
||||
|
||||
void *aiot_linkspeech_init()
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = NULL;
|
||||
int i = 0;
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if (NULL == sysdep) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
linkspeech = sysdep->core_sysdep_malloc(sizeof(linkspeech_handle_t), TAG);
|
||||
if(linkspeech == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(linkspeech, 0, sizeof(linkspeech_handle_t));
|
||||
/* 配置项设置为空 */
|
||||
linkspeech->dm_handle = NULL;
|
||||
linkspeech->player = NULL;
|
||||
linkspeech->work_dir = NULL;
|
||||
linkspeech->speech_buffer_size = AIOT_LSOPT_SPEECH_BUFFER_SIZE_DEFAULT;
|
||||
|
||||
/* 下载管理初始化 */
|
||||
linkspeech->download_mutex = sysdep->core_sysdep_mutex_init();
|
||||
CORE_INIT_LIST_HEAD(&linkspeech->download_task_list);
|
||||
|
||||
/* 语音播报任务初始化 */
|
||||
linkspeech->speech_task_mutex = sysdep->core_sysdep_mutex_init();
|
||||
linkspeech->speech_task_num = 0;
|
||||
CORE_INIT_LIST_HEAD(&linkspeech->speech_task_list);
|
||||
|
||||
linkspeech->play_param.on_finish = core_play_finished;
|
||||
linkspeech->play_param.userdata = linkspeech;
|
||||
linkspeech->playing_task = NULL;
|
||||
linkspeech->https_enable = 0;
|
||||
|
||||
for(i = 0; i < sizeof(linkspeech->dup_id) / sizeof(char *); i++){
|
||||
linkspeech->dup_id[i] = NULL;
|
||||
}
|
||||
linkspeech->write_pos = 0;
|
||||
|
||||
return linkspeech;
|
||||
}
|
||||
|
||||
int32_t aiot_linkspeech_deinit(void **handle)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = NULL;
|
||||
core_download_node_t *down_node = NULL, *down_next = NULL;
|
||||
core_speech_task_t *speech_node = NULL, *speech_next = NULL;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
int i = 0;
|
||||
|
||||
if (NULL == handle || NULL == *handle) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
linkspeech = (linkspeech_handle_t *)*handle;
|
||||
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->speech_task_mutex);
|
||||
/* 删除播报任务列表 */
|
||||
core_list_for_each_entry_safe(speech_node, speech_next, &linkspeech->speech_task_list, linked_node, core_speech_task_t) {
|
||||
core_list_del(&speech_node->linked_node);
|
||||
core_delete_speech_task(speech_node);
|
||||
speech_node = NULL;
|
||||
}
|
||||
linkspeech->speech_task_num = 0;
|
||||
/* 删除正在播报的任务 */
|
||||
if(linkspeech->playing_task != NULL) {
|
||||
core_delete_speech_task(linkspeech->playing_task);
|
||||
linkspeech->playing_task = NULL;
|
||||
}
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
sysdep->core_sysdep_mutex_deinit(&linkspeech->speech_task_mutex);
|
||||
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->download_mutex);
|
||||
core_list_for_each_entry_safe(down_node, down_next, &linkspeech->download_task_list, linked_node, core_download_node_t) {
|
||||
core_list_del(&down_node->linked_node);
|
||||
sysdep->core_sysdep_free(down_node->jobcode);
|
||||
sysdep->core_sysdep_free(down_node->json_url);
|
||||
sysdep->core_sysdep_free(down_node);
|
||||
}
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->download_mutex);
|
||||
sysdep->core_sysdep_mutex_deinit(&linkspeech->download_mutex);
|
||||
|
||||
if(linkspeech->work_dir != NULL) {
|
||||
sysdep->core_sysdep_free(linkspeech->work_dir);
|
||||
}
|
||||
|
||||
if(linkspeech->dm_handle != NULL) {
|
||||
/* 销毁DATA-MODEL实例, 一般不会运行到这里 */
|
||||
res = aiot_dm_deinit(&linkspeech->dm_handle);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < sizeof(linkspeech->dup_id) / sizeof(char *); i++){
|
||||
if(linkspeech->dup_id[i] != NULL) {
|
||||
sysdep->core_sysdep_free(linkspeech->dup_id[i]);
|
||||
}
|
||||
linkspeech->dup_id[i] = NULL;
|
||||
}
|
||||
linkspeech->write_pos = 0;
|
||||
|
||||
sysdep->core_sysdep_free(linkspeech);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t aiot_linkspeech_setopt(void *handle, aiot_linkspeech_option_t option, void *data)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = NULL;
|
||||
uint8_t post_reply = 1;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == handle || NULL == data) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
if (option >= AIOT_LSOPT_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
linkspeech = (linkspeech_handle_t *)handle;
|
||||
|
||||
switch(option) {
|
||||
case AIOT_LSOPT_MQTT_HANDLE: {
|
||||
if(linkspeech->dm_handle != NULL) {
|
||||
return -1;
|
||||
}
|
||||
/* 创建DATA-MODEL实例 */
|
||||
linkspeech->dm_handle = aiot_dm_init();
|
||||
if (linkspeech->dm_handle == NULL) {
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
/* 配置MQTT实例句柄 */
|
||||
aiot_dm_setopt(linkspeech->dm_handle, AIOT_DMOPT_MQTT_HANDLE, data );
|
||||
/* 配置消息接收处理回调函数 */
|
||||
aiot_dm_setopt(linkspeech->dm_handle, AIOT_DMOPT_RECV_HANDLER, (void *)core_dm_recv_handler);
|
||||
/* 配置回调函数的userdata */
|
||||
aiot_dm_setopt(linkspeech->dm_handle, AIOT_DMOPT_USERDATA, (void *)linkspeech);
|
||||
/* 配置是云端否需要回复post_reply给设备. 如果为1, 表示需要云端回复, 否则表示不回复 */
|
||||
aiot_dm_setopt(linkspeech->dm_handle, AIOT_DMOPT_POST_REPLY, (void *)&post_reply);
|
||||
}
|
||||
break;
|
||||
|
||||
case AIOT_LSOPT_FILE_OPS: {
|
||||
fs = (aiot_fs_t *)data;
|
||||
}
|
||||
break;
|
||||
|
||||
case AIOT_LSOPT_PLAYER_CALLBACK: {
|
||||
linkspeech->player = (player_cb_t)data;
|
||||
}
|
||||
break;
|
||||
|
||||
case AIOT_LSOPT_WORK_DIR: {
|
||||
if (linkspeech->work_dir != NULL) {
|
||||
sysdep->core_sysdep_free(linkspeech->work_dir);
|
||||
linkspeech->work_dir = NULL;
|
||||
}
|
||||
|
||||
core_strdup(sysdep, &linkspeech->work_dir, (char *)data, TAG);
|
||||
}
|
||||
break;
|
||||
|
||||
case AIOT_LSOPT_HTTPS_ENABLE: {
|
||||
if(*(int32_t *)data != 0 && *(int32_t *)data != 1) {
|
||||
return -1;
|
||||
}
|
||||
linkspeech->https_enable = *(int32_t *)data;
|
||||
}
|
||||
break;
|
||||
|
||||
case AIOT_LSOPT_SPEECH_BUFFER_SIZE: {
|
||||
if(*(int32_t *)data <= 0 || *(int32_t *)data > 255) {
|
||||
return -1;
|
||||
}
|
||||
linkspeech->speech_buffer_size = *(int32_t *)data;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* 语料下载url.json文件解析并下载语料 */
|
||||
static int32_t core_speech_download_file_parse(linkspeech_handle_t *linkspeech, char *data, uint32_t datalen)
|
||||
{
|
||||
cJSON *root = NULL, *audios = NULL, *audio = NULL;
|
||||
cJSON *formart, *id, *url;
|
||||
char *local_file = NULL;
|
||||
char *src[3] = {NULL, NULL, NULL};
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
//如果是否json格式数据
|
||||
root = cJSON_Parse(data);
|
||||
if (root == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
audios = cJSON_GetObjectItem(root, "audios");
|
||||
if (audios == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cJSON_GetArraySize(audios); i++)
|
||||
{
|
||||
audio = cJSON_GetArrayItem(audios, i);
|
||||
if(audio != NULL) {
|
||||
formart = cJSON_GetObjectItem(audio,"format");
|
||||
id = cJSON_GetObjectItem(audio,"id");
|
||||
url = cJSON_GetObjectItem(audio,"url");
|
||||
src[0] = linkspeech->work_dir;
|
||||
src[1] = id->valuestring;
|
||||
src[2] = formart->valuestring;
|
||||
core_sprintf(sysdep, &local_file, "%s/%s.%s", src, sizeof(src) / sizeof(char *), TAG );
|
||||
if(fs->file_size(local_file) > 0) {
|
||||
fs->file_delete(local_file);
|
||||
}
|
||||
res = core_download_file(url->valuestring, local_file, linkspeech->https_enable);
|
||||
if(res != STATE_SUCCESS) {
|
||||
sysdep->core_sysdep_free(local_file);
|
||||
break;
|
||||
}
|
||||
sysdep->core_sysdep_free(local_file);
|
||||
}
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_linkspeech_start(void *handle)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = (linkspeech_handle_t *)handle;
|
||||
char *data = NULL;
|
||||
char *response = NULL;
|
||||
char *response_src[2] = {NULL};
|
||||
char *json_file = NULL;
|
||||
char *json_file_src[2] = { NULL, NULL };
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *result_success = "0";
|
||||
char *result_error = "255";
|
||||
int32_t file_len = 0, read_len = 0;
|
||||
core_download_node_t *node = NULL;
|
||||
|
||||
if (NULL == handle || fs == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if(linkspeech->work_dir == NULL || linkspeech->player == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
linkspeech->running = 1;
|
||||
|
||||
while(linkspeech->running) {
|
||||
/* 读取下载任务 */
|
||||
node = NULL;
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->download_mutex);
|
||||
node = core_list_first_entry(&linkspeech->download_task_list, core_download_node_t, linked_node);
|
||||
if(&node->linked_node != &linkspeech->download_task_list) {
|
||||
core_list_del(&node->linked_node);
|
||||
} else {
|
||||
node = NULL;
|
||||
}
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->download_mutex);
|
||||
|
||||
/* 处理单个下载任务 */
|
||||
if(node != NULL) {
|
||||
/* 生成本地文件名 */
|
||||
json_file_src[0] = linkspeech->work_dir;
|
||||
json_file_src[1] = node->jobcode;
|
||||
core_sprintf(sysdep, &json_file, "%s/%s.json", json_file_src, sizeof(json_file_src) / sizeof(char *), TAG);
|
||||
|
||||
/* 下载包含语料url的json文件至本地 */
|
||||
core_download_file(node->json_url, json_file, linkspeech->https_enable);
|
||||
|
||||
/* 读取文件内容,拷贝至data */
|
||||
file_len = fs->file_size(json_file);
|
||||
data = sysdep->core_sysdep_malloc(file_len + 1, TAG);
|
||||
read_len = fs->file_read(json_file, 0, (uint8_t *)data, file_len);
|
||||
core_log3(sysdep, 0, "[%s] read_len %d, file_len %d \r\n", json_file, &read_len, &file_len);
|
||||
/* 删除不使用的记录语料地址的json文件 */
|
||||
fs->file_delete(json_file);
|
||||
sysdep->core_sysdep_free(json_file);
|
||||
|
||||
if(read_len == file_len) {
|
||||
/* 解析语料文件内容,并触发下载 */
|
||||
res = core_speech_download_file_parse(linkspeech, data, read_len);
|
||||
if(res == STATE_SUCCESS) {
|
||||
response_src[1] = result_success;
|
||||
} else {
|
||||
response_src[1] = result_error;
|
||||
}
|
||||
} else {
|
||||
response_src[1] = result_error;
|
||||
}
|
||||
|
||||
/* 删除文件相关内容 */
|
||||
sysdep->core_sysdep_free(data);
|
||||
|
||||
/* 回复云端下载完成 */
|
||||
response_src[0] = node->jobcode;
|
||||
core_sprintf(sysdep, &response, "{\"jobcode\":\"%s\", \"result\":%s}", response_src, sizeof(response_src) / sizeof(char *), TAG);
|
||||
core_send_event_post(linkspeech->dm_handle, "SpeechUpdateResponse", response);
|
||||
sysdep->core_sysdep_free(response);
|
||||
|
||||
/* 删除下载任务节点 */
|
||||
sysdep->core_sysdep_free(node->json_url);
|
||||
sysdep->core_sysdep_free(node->jobcode);
|
||||
sysdep->core_sysdep_free(node);
|
||||
} else {
|
||||
sysdep->core_sysdep_sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_linkspeech_stop(void *handle)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = NULL;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == handle) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
linkspeech = (linkspeech_handle_t *)handle;
|
||||
linkspeech->running = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
161
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_linkspeech_api.h
vendored
Normal file
161
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_linkspeech_api.h
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @file aiot_linkspeech_api.h
|
||||
* @brief LinkSpeech模块头文件, 提供设备千里传音的能力
|
||||
* @date 2019-12-27
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||
*
|
||||
* @details
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AIOT_LINKSPEECH_API_H__
|
||||
#define __AIOT_LINKSPEECH_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
/* 当音频播报结束后执行该回调, 需要带userdata */
|
||||
void (*on_finish)(char *filename, void *userdata);
|
||||
void *userdata;
|
||||
} play_param_t;
|
||||
|
||||
/* 设置音频播放回调,该接口不能长时间阻塞 */
|
||||
typedef int32_t (*player_cb_t)(char *filename, play_param_t *ext_params);
|
||||
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 模块依赖的MQTT句柄
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 千里传音模块依赖底层的MQTT模块, 用户必需配置正确的MQTT句柄, 否则无法正常工作
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_LSOPT_MQTT_HANDLE,
|
||||
/**
|
||||
* @brief 模块依赖的文件系统操作
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 千里传音模块依赖文件系统接口,需要用户实现并设置
|
||||
*
|
||||
* 数据类型: (aiot_fs_t *)
|
||||
*/
|
||||
AIOT_LSOPT_FILE_OPS,
|
||||
/**
|
||||
* @brief 模块依赖的语音播放的接口设置
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 千里传音模块依赖音频播放接口
|
||||
*
|
||||
* 数据类型: (player_cb_t *)
|
||||
*/
|
||||
AIOT_LSOPT_PLAYER_CALLBACK,
|
||||
/**
|
||||
* @brief 设置千里传音文件保存的文件夹路径
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*/
|
||||
AIOT_LSOPT_WORK_DIR,
|
||||
/**
|
||||
* @brief 是否使能https下载,默认为http下载
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (int32_t *) 0:http下载 1:https下载
|
||||
*/
|
||||
AIOT_LSOPT_HTTPS_ENABLE,
|
||||
/**
|
||||
* @brief 组合播报任务大缓存个数
|
||||
*
|
||||
* @details
|
||||
* 当组合播报的速度小于下发的速度时,SDK会缓存播报任务,该参数用于设置缓存播报任务的个数
|
||||
*
|
||||
* 数据类型: (int32_t *) 1~255, 默认为10
|
||||
*/
|
||||
AIOT_LSOPT_SPEECH_BUFFER_SIZE,
|
||||
|
||||
AIOT_LSOPT_MAX,
|
||||
} aiot_linkspeech_option_t;
|
||||
|
||||
/**
|
||||
* @brief 创建一个LinkSpeech实例
|
||||
*
|
||||
* @return void*
|
||||
* @retval 非NULL linkspeech实例句柄
|
||||
* @retval NULL 初始化失败, 或者是因为没有设置portfile, 或者是内存分配失败导致
|
||||
*
|
||||
*/
|
||||
void *aiot_linkspeech_init();
|
||||
|
||||
/**
|
||||
* @brief 销毁LinkSpeech实例句柄
|
||||
*
|
||||
* @param[in] handle 指向linkspeech实例句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_linkspeech_deinit(void **handle);
|
||||
|
||||
/**
|
||||
* @brief 设置LinkSpeech句柄的参数
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 对LinkSpeech会话进行配置, 常见的配置选项包括
|
||||
*
|
||||
* + `AIOT_LSOPT_MQTT_HANDLE`: 把 @ref aiot_mqtt_init 返回的MQTT会话句柄跟OTA会话关联起来
|
||||
* + `AIOT_LSOPT_RECV_HANDLER`: 设置OTA消息的数据处理回调, 这个用户回调在有OTA消息的时候, 会被 @ref aiot_mqtt_recv 调用到
|
||||
*
|
||||
* @param[in] handle linkspeech句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_linkspeech_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_linkspeech_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_USER_INPUT_UNKNOWN_OPTION option不支持
|
||||
* @retval STATE_SUCCESS 参数设置成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_linkspeech_setopt(void *handle, aiot_linkspeech_option_t option, void *data);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 启动linkspeech(千里传音)服务,会一直阻塞
|
||||
*
|
||||
* @param[in] handle 指向linkspeech实例句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_linkspeech_start(void *handle);
|
||||
|
||||
/**
|
||||
* @brief 关闭linkspeech(千里传音)服务,执行后aiot_linkspeech_start会退出
|
||||
*
|
||||
* @param[in] handle 指向linkspeech实例句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_linkspeech_stop(void *handle);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef __AIOT_LINKSPEECH_API_H__ */
|
||||
|
||||
400
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/http_download.c
vendored
Normal file
400
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/http_download.c
vendored
Normal file
@@ -0,0 +1,400 @@
|
||||
#include <stdio.h>
|
||||
#include "http_download.h"
|
||||
#include "aiot_state_api.h"
|
||||
#include "core_http.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
|
||||
#define HTTP_DOWNLOAD_HOST_MAX_LEN 512
|
||||
#define HTTP_DOWNLOAD_PATH_MAX_LEN 512
|
||||
#define HTTP_DOWNLOAD_DEFAULT_TLS_PORT 80
|
||||
#define HTTP_DOWNLOAD_BUFFER_LEN (2 * 1024)
|
||||
#define HTTP_DOWNLOAD_RECV_TIMEOUT_MS (5 * 1000)
|
||||
|
||||
#define HTTP_DOWNLOAD_HTTPCLIENT_MAX_URL_LEN (256)
|
||||
#define HTTP_DOWNLOAD_MAX_DIGIT_NUM_OF_UINT32 (20)
|
||||
#define HTTP_DOWNLOAD_RESPONSE_PARTIAL (206)
|
||||
#define HTTP_DOWNLOAD_RESPONSE_OK (200)
|
||||
|
||||
static const uint64_t crc64_table[256] = {
|
||||
0x0000000000000000, 0xb32e4cbe03a75f6f, 0xf4843657a840a05b, 0x47aa7ae9abe7ff34,
|
||||
0x7bd0c384ff8f5e33, 0xc8fe8f3afc28015c, 0x8f54f5d357cffe68, 0x3c7ab96d5468a107,
|
||||
0xf7a18709ff1ebc66, 0x448fcbb7fcb9e309, 0x0325b15e575e1c3d, 0xb00bfde054f94352,
|
||||
0x8c71448d0091e255, 0x3f5f08330336bd3a, 0x78f572daa8d1420e, 0xcbdb3e64ab761d61,
|
||||
0x7d9ba13851336649, 0xceb5ed8652943926, 0x891f976ff973c612, 0x3a31dbd1fad4997d,
|
||||
0x064b62bcaebc387a, 0xb5652e02ad1b6715, 0xf2cf54eb06fc9821, 0x41e11855055bc74e,
|
||||
0x8a3a2631ae2dda2f, 0x39146a8fad8a8540, 0x7ebe1066066d7a74, 0xcd905cd805ca251b,
|
||||
0xf1eae5b551a2841c, 0x42c4a90b5205db73, 0x056ed3e2f9e22447, 0xb6409f5cfa457b28,
|
||||
0xfb374270a266cc92, 0x48190ecea1c193fd, 0x0fb374270a266cc9, 0xbc9d3899098133a6,
|
||||
0x80e781f45de992a1, 0x33c9cd4a5e4ecdce, 0x7463b7a3f5a932fa, 0xc74dfb1df60e6d95,
|
||||
0x0c96c5795d7870f4, 0xbfb889c75edf2f9b, 0xf812f32ef538d0af, 0x4b3cbf90f69f8fc0,
|
||||
0x774606fda2f72ec7, 0xc4684a43a15071a8, 0x83c230aa0ab78e9c, 0x30ec7c140910d1f3,
|
||||
0x86ace348f355aadb, 0x3582aff6f0f2f5b4, 0x7228d51f5b150a80, 0xc10699a158b255ef,
|
||||
0xfd7c20cc0cdaf4e8, 0x4e526c720f7dab87, 0x09f8169ba49a54b3, 0xbad65a25a73d0bdc,
|
||||
0x710d64410c4b16bd, 0xc22328ff0fec49d2, 0x85895216a40bb6e6, 0x36a71ea8a7ace989,
|
||||
0x0adda7c5f3c4488e, 0xb9f3eb7bf06317e1, 0xfe5991925b84e8d5, 0x4d77dd2c5823b7ba,
|
||||
0x64b62bcaebc387a1, 0xd7986774e864d8ce, 0x90321d9d438327fa, 0x231c512340247895,
|
||||
0x1f66e84e144cd992, 0xac48a4f017eb86fd, 0xebe2de19bc0c79c9, 0x58cc92a7bfab26a6,
|
||||
0x9317acc314dd3bc7, 0x2039e07d177a64a8, 0x67939a94bc9d9b9c, 0xd4bdd62abf3ac4f3,
|
||||
0xe8c76f47eb5265f4, 0x5be923f9e8f53a9b, 0x1c4359104312c5af, 0xaf6d15ae40b59ac0,
|
||||
0x192d8af2baf0e1e8, 0xaa03c64cb957be87, 0xeda9bca512b041b3, 0x5e87f01b11171edc,
|
||||
0x62fd4976457fbfdb, 0xd1d305c846d8e0b4, 0x96797f21ed3f1f80, 0x2557339fee9840ef,
|
||||
0xee8c0dfb45ee5d8e, 0x5da24145464902e1, 0x1a083bacedaefdd5, 0xa9267712ee09a2ba,
|
||||
0x955cce7fba6103bd, 0x267282c1b9c65cd2, 0x61d8f8281221a3e6, 0xd2f6b4961186fc89,
|
||||
0x9f8169ba49a54b33, 0x2caf25044a02145c, 0x6b055fede1e5eb68, 0xd82b1353e242b407,
|
||||
0xe451aa3eb62a1500, 0x577fe680b58d4a6f, 0x10d59c691e6ab55b, 0xa3fbd0d71dcdea34,
|
||||
0x6820eeb3b6bbf755, 0xdb0ea20db51ca83a, 0x9ca4d8e41efb570e, 0x2f8a945a1d5c0861,
|
||||
0x13f02d374934a966, 0xa0de61894a93f609, 0xe7741b60e174093d, 0x545a57dee2d35652,
|
||||
0xe21ac88218962d7a, 0x5134843c1b317215, 0x169efed5b0d68d21, 0xa5b0b26bb371d24e,
|
||||
0x99ca0b06e7197349, 0x2ae447b8e4be2c26, 0x6d4e3d514f59d312, 0xde6071ef4cfe8c7d,
|
||||
0x15bb4f8be788911c, 0xa6950335e42fce73, 0xe13f79dc4fc83147, 0x521135624c6f6e28,
|
||||
0x6e6b8c0f1807cf2f, 0xdd45c0b11ba09040, 0x9aefba58b0476f74, 0x29c1f6e6b3e0301b,
|
||||
0xc96c5795d7870f42, 0x7a421b2bd420502d, 0x3de861c27fc7af19, 0x8ec62d7c7c60f076,
|
||||
0xb2bc941128085171, 0x0192d8af2baf0e1e, 0x4638a2468048f12a, 0xf516eef883efae45,
|
||||
0x3ecdd09c2899b324, 0x8de39c222b3eec4b, 0xca49e6cb80d9137f, 0x7967aa75837e4c10,
|
||||
0x451d1318d716ed17, 0xf6335fa6d4b1b278, 0xb199254f7f564d4c, 0x02b769f17cf11223,
|
||||
0xb4f7f6ad86b4690b, 0x07d9ba1385133664, 0x4073c0fa2ef4c950, 0xf35d8c442d53963f,
|
||||
0xcf273529793b3738, 0x7c0979977a9c6857, 0x3ba3037ed17b9763, 0x888d4fc0d2dcc80c,
|
||||
0x435671a479aad56d, 0xf0783d1a7a0d8a02, 0xb7d247f3d1ea7536, 0x04fc0b4dd24d2a59,
|
||||
0x3886b22086258b5e, 0x8ba8fe9e8582d431, 0xcc0284772e652b05, 0x7f2cc8c92dc2746a,
|
||||
0x325b15e575e1c3d0, 0x8175595b76469cbf, 0xc6df23b2dda1638b, 0x75f16f0cde063ce4,
|
||||
0x498bd6618a6e9de3, 0xfaa59adf89c9c28c, 0xbd0fe036222e3db8, 0x0e21ac88218962d7,
|
||||
0xc5fa92ec8aff7fb6, 0x76d4de52895820d9, 0x317ea4bb22bfdfed, 0x8250e80521188082,
|
||||
0xbe2a516875702185, 0x0d041dd676d77eea, 0x4aae673fdd3081de, 0xf9802b81de97deb1,
|
||||
0x4fc0b4dd24d2a599, 0xfceef8632775faf6, 0xbb44828a8c9205c2, 0x086ace348f355aad,
|
||||
0x34107759db5dfbaa, 0x873e3be7d8faa4c5, 0xc094410e731d5bf1, 0x73ba0db070ba049e,
|
||||
0xb86133d4dbcc19ff, 0x0b4f7f6ad86b4690, 0x4ce50583738cb9a4, 0xffcb493d702be6cb,
|
||||
0xc3b1f050244347cc, 0x709fbcee27e418a3, 0x3735c6078c03e797, 0x841b8ab98fa4b8f8,
|
||||
0xadda7c5f3c4488e3, 0x1ef430e13fe3d78c, 0x595e4a08940428b8, 0xea7006b697a377d7,
|
||||
0xd60abfdbc3cbd6d0, 0x6524f365c06c89bf, 0x228e898c6b8b768b, 0x91a0c532682c29e4,
|
||||
0x5a7bfb56c35a3485, 0xe955b7e8c0fd6bea, 0xaeffcd016b1a94de, 0x1dd181bf68bdcbb1,
|
||||
0x21ab38d23cd56ab6, 0x9285746c3f7235d9, 0xd52f0e859495caed, 0x6601423b97329582,
|
||||
0xd041dd676d77eeaa, 0x636f91d96ed0b1c5, 0x24c5eb30c5374ef1, 0x97eba78ec690119e,
|
||||
0xab911ee392f8b099, 0x18bf525d915feff6, 0x5f1528b43ab810c2, 0xec3b640a391f4fad,
|
||||
0x27e05a6e926952cc, 0x94ce16d091ce0da3, 0xd3646c393a29f297, 0x604a2087398eadf8,
|
||||
0x5c3099ea6de60cff, 0xef1ed5546e415390, 0xa8b4afbdc5a6aca4, 0x1b9ae303c601f3cb,
|
||||
0x56ed3e2f9e224471, 0xe5c372919d851b1e, 0xa26908783662e42a, 0x114744c635c5bb45,
|
||||
0x2d3dfdab61ad1a42, 0x9e13b115620a452d, 0xd9b9cbfcc9edba19, 0x6a978742ca4ae576,
|
||||
0xa14cb926613cf817, 0x1262f598629ba778, 0x55c88f71c97c584c, 0xe6e6c3cfcadb0723,
|
||||
0xda9c7aa29eb3a624, 0x69b2361c9d14f94b, 0x2e184cf536f3067f, 0x9d36004b35545910,
|
||||
0x2b769f17cf112238, 0x9858d3a9ccb67d57, 0xdff2a94067518263, 0x6cdce5fe64f6dd0c,
|
||||
0x50a65c93309e7c0b, 0xe388102d33392364, 0xa4226ac498dedc50, 0x170c267a9b79833f,
|
||||
0xdcd7181e300f9e5e, 0x6ff954a033a8c131, 0x28532e49984f3e05, 0x9b7d62f79be8616a,
|
||||
0xa707db9acf80c06d, 0x14299724cc279f02, 0x5383edcd67c06036, 0xe0ada17364673f59
|
||||
};
|
||||
|
||||
|
||||
uint64_t crc64_update(uint64_t crc, const unsigned char *s, uint64_t l) {
|
||||
|
||||
crc = ~crc;
|
||||
while (l != 0) {
|
||||
crc = crc64_table[*s++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--l;
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char host[HTTP_DOWNLOAD_HOST_MAX_LEN];
|
||||
char path[HTTP_DOWNLOAD_PATH_MAX_LEN];
|
||||
uint16_t port;
|
||||
file_save_func_t save_func;
|
||||
void *userdata;
|
||||
uint32_t range_start;
|
||||
uint32_t range_end;
|
||||
int32_t https_enable;
|
||||
|
||||
|
||||
/* 运行时参数 */
|
||||
void *http_handle;
|
||||
uint32_t size_fetched;
|
||||
uint32_t content_len;
|
||||
int32_t http_rsp_status_code;
|
||||
int32_t result;
|
||||
uint64_t content_crc64;
|
||||
uint64_t calc_crc64;
|
||||
} http_download_t;
|
||||
|
||||
/* 位于external/ali_ca_cert.c中的服务器证书 */
|
||||
extern const char *ali_ca_cert;
|
||||
extern aiot_sysdep_portfile_t g_aiot_sysdep_portfile;
|
||||
|
||||
/* 解析URL, 从中解出来host, path */
|
||||
static int32_t _download_parse_url(const char *url, char *host, uint32_t max_host_len, char *path,
|
||||
uint32_t max_path_len)
|
||||
{
|
||||
char *host_ptr = (char *) strstr(url, "://");
|
||||
uint32_t host_len = 0;
|
||||
uint32_t path_len;
|
||||
char *path_ptr;
|
||||
char *fragment_ptr;
|
||||
|
||||
if (host_ptr == NULL) {
|
||||
return HTTP_DOWNLOAD_ERR_URL_INVALID;
|
||||
}
|
||||
host_ptr += 3;
|
||||
|
||||
path_ptr = strchr(host_ptr, '/');
|
||||
if (NULL == path_ptr) {
|
||||
return HTTP_DOWNLOAD_ERR_URL_INVALID;
|
||||
}
|
||||
|
||||
if (host_len == 0) {
|
||||
host_len = path_ptr - host_ptr;
|
||||
}
|
||||
|
||||
memcpy(host, host_ptr, host_len);
|
||||
host[host_len] = '\0';
|
||||
fragment_ptr = strchr(host_ptr, '#');
|
||||
if (fragment_ptr != NULL) {
|
||||
path_len = fragment_ptr - path_ptr;
|
||||
} else {
|
||||
path_len = strlen(path_ptr);
|
||||
}
|
||||
|
||||
memcpy(path, path_ptr, path_len);
|
||||
path[path_len] = '\0';
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static http_download_t *_http_download_init()
|
||||
{
|
||||
http_download_t *download = g_aiot_sysdep_portfile.core_sysdep_malloc(sizeof(http_download_t), "");
|
||||
if(download == NULL) {
|
||||
return download;
|
||||
}
|
||||
|
||||
memset(download, 0, sizeof(http_download_t));
|
||||
download->port = HTTP_DOWNLOAD_DEFAULT_TLS_PORT;
|
||||
download->result = STATE_SUCCESS;
|
||||
download->https_enable = 0;
|
||||
|
||||
return download;
|
||||
}
|
||||
|
||||
static void _http_download_deinit(http_download_t *download)
|
||||
{
|
||||
if(download->http_handle != NULL) {
|
||||
core_http_deinit(&download->http_handle);
|
||||
}
|
||||
g_aiot_sysdep_portfile.core_sysdep_free(download);
|
||||
}
|
||||
/* 对于收到的http报文进行处理的回调函数, 内部处理完后再调用用户的回调函数 */
|
||||
void _http_download_recv_handler(void *handle, const aiot_http_recv_t *packet, void *userdata)
|
||||
{
|
||||
http_download_t *download = (http_download_t *)userdata;
|
||||
if (NULL == download || NULL == packet) {
|
||||
return;
|
||||
}
|
||||
switch (packet->type) {
|
||||
case AIOT_HTTPRECV_STATUS_CODE : {
|
||||
download->http_rsp_status_code = packet->data.status_code.code;
|
||||
}
|
||||
break;
|
||||
case AIOT_HTTPRECV_HEADER: {
|
||||
if ((strlen(packet->data.header.key) == strlen("Content-Length")) &&
|
||||
(memcmp(packet->data.header.key, "Content-Length", strlen(packet->data.header.key)) == 0)) {
|
||||
uint32_t size = 0;
|
||||
|
||||
/* 在用户指定的range并非全部固件的情况下, content_len < size_total, 所以不能简单替换 */
|
||||
core_str2uint(packet->data.header.value, (uint8_t)strlen(packet->data.header.value), &size);
|
||||
|
||||
/* 该字段表示用户期望总共下载多少字节. 如果字段为0, 表示未设置过, 则设置为总共的字节数 */
|
||||
download->content_len = (download->content_len > 0) ? download->content_len : size;
|
||||
}
|
||||
|
||||
/* 只有整个文件下载触发校验 */
|
||||
if(download->range_start == 0 && download->range_end == 0) {
|
||||
if ((strlen(packet->data.header.key) == strlen("x-oss-hash-crc64ecma")) &&
|
||||
(memcmp(packet->data.header.key, "x-oss-hash-crc64ecma", strlen(packet->data.header.key)) == 0)) {
|
||||
core_str2uint64(packet->data.header.value, (uint8_t)strlen(packet->data.header.value), &download->content_crc64);
|
||||
download->calc_crc64 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AIOT_HTTPRECV_BODY: {
|
||||
if (HTTP_DOWNLOAD_RESPONSE_OK != download->http_rsp_status_code
|
||||
/* HTTP回复报文的code应该是200或者206, 否则这个下载链接不可用 */
|
||||
&& HTTP_DOWNLOAD_RESPONSE_PARTIAL != download->http_rsp_status_code) {
|
||||
download->result = HTTP_DOWNLOAD_ERR_FETCH_FAILED;
|
||||
core_log(NULL, 0, "wrong http respond code\r\n");
|
||||
} else if (0 == download->content_len) {
|
||||
/* HTTP回复报文的header里面应该有Content-Length, 否则这个下载链接为trunked编码, 不可用 */
|
||||
download->result = HTTP_DOWNLOAD_ERR_FETCH_FAILED;
|
||||
core_log(NULL, 0, "wrong http respond header\r\n");
|
||||
} else {
|
||||
/* 正常的固件的报文 */
|
||||
/* 在按照多个range分片下载的情况下, 判断用户下载到的固件的累计大小是否超过了整体的值 */
|
||||
if (download->size_fetched > download->content_len) {
|
||||
core_log(NULL, 0, "downloaded exceeds expected\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if(download->result >= 0) {
|
||||
int32_t offset = download->size_fetched + download->range_start;
|
||||
download->save_func(offset, packet->data.body.buffer, packet->data.body.len, download->userdata);
|
||||
}
|
||||
|
||||
/* 该字段表示累计下载了多少字节, 不区分range */
|
||||
download->size_fetched += packet->data.body.len;
|
||||
|
||||
/* 计算digest, 如果下载完成, 还要看看是否与云端计算出来的一致 */
|
||||
download->calc_crc64 = crc64_update(download->calc_crc64, packet->data.body.buffer, packet->data.body.len);
|
||||
if (download->size_fetched == download->content_len) {
|
||||
/* 不需要校验或者校验成功 */
|
||||
if(download->content_crc64 == 0) {
|
||||
/* 不需要校验 */
|
||||
download->result = STATE_SUCCESS;
|
||||
}
|
||||
else if(download->content_crc64 == download->calc_crc64) {
|
||||
download->result = STATE_SUCCESS;
|
||||
core_log(NULL, 0, "crc64 matched\r\n");
|
||||
} else {
|
||||
download->result = HTTP_DOWNLOAD_ERR_CHECKSUM_MISMATCH;
|
||||
core_log(NULL, 0, "crc64 mismatch\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _http_download_connect(http_download_t *download)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
uint32_t default_body_max_len = HTTP_DOWNLOAD_BUFFER_LEN;
|
||||
uint32_t default_timeout_ms = HTTP_DOWNLOAD_RECV_TIMEOUT_MS;
|
||||
void *http_handle = core_http_init();
|
||||
if(http_handle == NULL) {
|
||||
return STATE_PORT_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
aiot_sysdep_network_cred_t cred;
|
||||
memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t));
|
||||
if(download->https_enable == 0) {
|
||||
download->port = 80;
|
||||
} else {
|
||||
download->port = 443;
|
||||
cred.option = AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA; /* 使用RSA证书校验MQTT服务端 */
|
||||
cred.max_tls_fragment = 16384; /* 最大的分片长度为16K, 其它可选值还有4K, 2K, 1K, 0.5K */
|
||||
cred.sni_enabled = 1; /* TLS建连时, 支持Server Name Indicator */
|
||||
cred.x509_server_cert = ali_ca_cert; /* 用来验证MQTT服务端的RSA根证书 */
|
||||
cred.x509_server_cert_len = strlen(ali_ca_cert); /* 用来验证MQTT服务端的RSA根证书长度 */
|
||||
}
|
||||
|
||||
if ((STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_RECV_HANDLER, _http_download_recv_handler)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_USERDATA, (void *)download)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_BODY_BUFFER_MAX_LEN, (void *)&default_body_max_len)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_NETWORK_CRED, (void *)&cred)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_HOST, (void *)download->host)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_PORT, (void *)&download->port)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_RECV_TIMEOUT_MS, (void *)&default_timeout_ms))) {
|
||||
core_http_deinit(&http_handle);
|
||||
return STATE_PORT_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
res = core_http_connect(http_handle);
|
||||
if (res != STATE_SUCCESS) {
|
||||
core_http_deinit(&http_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
download->http_handle = http_handle;
|
||||
return res;
|
||||
}
|
||||
static char header[1024];
|
||||
static int32_t _http_download_send_request(http_download_t *download)
|
||||
{
|
||||
int32_t pos = 0;
|
||||
core_http_request_t request = {
|
||||
.method = "GET",
|
||||
.path = download->path,
|
||||
.header = header,
|
||||
.content = NULL,
|
||||
.content_len = 0
|
||||
};
|
||||
|
||||
memset(header, 0, sizeof(header));
|
||||
pos += sprintf(header + pos, "Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8\r\n");
|
||||
if(download->range_end != 0) {
|
||||
pos += sprintf(header + pos, "Range: bytes=%d-%d\r\n", download->range_start, download->range_end);
|
||||
} else {
|
||||
pos += sprintf(header + pos, "Range: bytes=%d-\r\n", download->range_start);
|
||||
}
|
||||
if(pos < 0) {
|
||||
return HTTP_DOWNLOAD_ERR_UNKOWN;
|
||||
}
|
||||
|
||||
return core_http_send(download->http_handle, &request);
|
||||
}
|
||||
|
||||
static int32_t _http_download_recv(http_download_t *download)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
while(1) {
|
||||
res = core_http_recv(download->http_handle);
|
||||
if(res < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(res == STATE_HTTP_READ_BODY_FINISHED) {
|
||||
res = STATE_SUCCESS;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t core_http_download_request(char *url, http_download_params_t *extra_params, file_save_func_t save_func, void* userdata)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
http_download_t *download = NULL;
|
||||
|
||||
if(url == NULL || save_func == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
download = _http_download_init();
|
||||
if(download == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = _download_parse_url(url, download->host, HTTP_DOWNLOAD_HOST_MAX_LEN, download->path,
|
||||
HTTP_DOWNLOAD_PATH_MAX_LEN);
|
||||
if (res != STATE_SUCCESS) {
|
||||
_http_download_deinit(download);
|
||||
return HTTP_DOWNLOAD_ERR_URL_INVALID;
|
||||
}
|
||||
|
||||
if(extra_params != NULL) {
|
||||
download->range_start = extra_params->range_start;
|
||||
download->range_end = extra_params->range_end;
|
||||
download->https_enable = extra_params->https_enable;
|
||||
}
|
||||
download->save_func = save_func;
|
||||
download->userdata = userdata;
|
||||
|
||||
/* 建立连接 */
|
||||
res = _http_download_connect(download);
|
||||
if(res < STATE_SUCCESS) {
|
||||
_http_download_deinit(download);
|
||||
return HTTP_DOWNLOAD_ERR_URL_INVALID;
|
||||
}
|
||||
|
||||
/* 发送请求 */
|
||||
res = _http_download_send_request(download);
|
||||
if(res != STATE_SUCCESS) {
|
||||
_http_download_deinit(download);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* 接收数据 */
|
||||
res = _http_download_recv(download);
|
||||
res = download->result;
|
||||
|
||||
_http_download_deinit(download);
|
||||
return res;
|
||||
}
|
||||
54
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/http_download.h
vendored
Normal file
54
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/http_download.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef _HTTP_DOWNLOAD_H_
|
||||
#define _HTTP_DOWNLOAD_H_
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define HTTP_DOWNLOAD_ERR_URL_INVALID -0x8001
|
||||
#define HTTP_DOWNLOAD_ERR_UNKOWN -0x8002
|
||||
#define HTTP_DOWNLOAD_ERR_FETCH_FAILED -0x8003
|
||||
#define HTTP_DOWNLOAD_ERR_CHECKSUM_MISMATCH -0x8004
|
||||
|
||||
/**
|
||||
* @brief 文件下载的额外参数
|
||||
*/
|
||||
typedef struct {
|
||||
/* 文件区间下载,起始偏移地址, 默认为0 */
|
||||
uint32_t range_start;
|
||||
/* 文件区间下载,终止偏移地址,如若不设置,置为0即可 */
|
||||
uint32_t range_end;
|
||||
/* 1: 使用https下载 0:使用http下载,默认为0 */
|
||||
int32_t https_enable;
|
||||
} http_download_params_t;
|
||||
|
||||
/**
|
||||
* @brief 文件数据保存回调函数类型定义
|
||||
* @details
|
||||
* 文件正常保存时,返回写入的数据长度
|
||||
* 文件保存异常时,返回-1, 会中断下载流程
|
||||
*/
|
||||
typedef int32_t (*file_save_func_t)(uint32_t offset, uint8_t *data, uint32_t data_len, void *userdata);
|
||||
|
||||
|
||||
/**
|
||||
* @brief http下载文件
|
||||
*
|
||||
* @param[in] url 文件下载地址
|
||||
* @param[in] extra_params 其它扩展参数,没有时可填NULL
|
||||
* @param[in] save_func 文件数据保存回调函数
|
||||
* @param[in] userdata 执行回调时返回的用户指针
|
||||
*
|
||||
* @return http_download_result_t
|
||||
* @retval <HTTP_DOWNLOAD_SUCCESS 执行失败
|
||||
* @retval HTTP_DOWNLOAD_SUCCESS 执行成功
|
||||
*/
|
||||
int32_t core_http_download_request(char *url, http_download_params_t *extra_params, file_save_func_t save_func, void* userdata);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef _CORE_HTTP_H_ */
|
||||
166
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/speech_trans.c
vendored
Normal file
166
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/speech_trans.c
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "speech_trans.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "core_string.h"
|
||||
|
||||
/* 系统默认的数字语音路径 */
|
||||
static const char *sys_tone_number[] = {
|
||||
"SYS_TONE_0",
|
||||
"SYS_TONE_1",
|
||||
"SYS_TONE_2",
|
||||
"SYS_TONE_3",
|
||||
"SYS_TONE_4",
|
||||
"SYS_TONE_5",
|
||||
"SYS_TONE_6",
|
||||
"SYS_TONE_7",
|
||||
"SYS_TONE_8",
|
||||
"SYS_TONE_9",
|
||||
};
|
||||
|
||||
/* 系统默认的单元路径*/
|
||||
static const char *sys_tone_measure[] = {
|
||||
"SYS_TONE_MONETARY_fen",
|
||||
"SYS_TONE_MONETARY_jiao",
|
||||
"SYS_TONE_MONETARY_yuan",
|
||||
"SYS_TONE_MEASURE_WORD_shi",
|
||||
"SYS_TONE_MEASURE_WORD_bai",
|
||||
"SYS_TONE_MEASURE_WORD_qian",
|
||||
"SYS_TONE_MEASURE_WORD_wan",
|
||||
"SYS_TONE_MEASURE_WORD_yi",
|
||||
};
|
||||
|
||||
/* 语料名字转换成文件添加进链表 */
|
||||
void name_to_speech(const char *value, char *format, struct core_list_head *list)
|
||||
{
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
play_node_t *node = NULL;
|
||||
char *src[] = { (char *)value, format };
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if(sysdep == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
node = sysdep->core_sysdep_malloc(sizeof(play_node_t), "");
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
memset(node, 0, sizeof(play_node_t));
|
||||
CORE_INIT_LIST_HEAD(&node->linked_node);
|
||||
|
||||
core_sprintf(sysdep, &node->filename, "%s.%s", src, sizeof(src) / sizeof(char *), "");
|
||||
if (node->filename == NULL) {
|
||||
sysdep->core_sysdep_free(node);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("add name %s\r\n", node->filename);
|
||||
core_list_add_tail(&node->linked_node, list);
|
||||
}
|
||||
|
||||
/* 转换整形数字 */
|
||||
void play_integer_number(uint64_t integer, char *format, struct core_list_head *list)
|
||||
{
|
||||
uint64_t quotient = 0, remain = 0;
|
||||
if(integer >= 100000000ul) {
|
||||
quotient = integer / 100000000ul;
|
||||
remain = integer % 100000000ul;
|
||||
play_integer_number(quotient, format, list);
|
||||
name_to_speech(sys_tone_measure[7], format, list);
|
||||
if(remain > 0 && 100000000ul / remain > 10) {
|
||||
name_to_speech(sys_tone_number[0], format, list);
|
||||
}
|
||||
play_integer_number(remain, format, list);
|
||||
} else if (integer >= 10000ul) {
|
||||
quotient = integer / 10000ul;
|
||||
remain = integer % 10000ul;
|
||||
play_integer_number(quotient, format, list);
|
||||
name_to_speech(sys_tone_measure[6], format, list);
|
||||
if(remain > 0 && 10000ul / remain > 10) {
|
||||
name_to_speech(sys_tone_number[0], format, list);
|
||||
}
|
||||
play_integer_number(remain, format, list);
|
||||
} else if (integer >= 1000ul) {
|
||||
quotient = integer / 1000ul;
|
||||
remain = integer % 1000ul;
|
||||
play_integer_number(quotient, format, list);
|
||||
name_to_speech(sys_tone_measure[5], format, list);
|
||||
if(remain > 0 && 1000ul / remain > 10) {
|
||||
name_to_speech(sys_tone_number[0], format, list);
|
||||
}
|
||||
play_integer_number(remain, format, list);
|
||||
} else if (integer >= 100ul) {
|
||||
quotient = integer / 100ul;
|
||||
remain = integer % 100ul;
|
||||
play_integer_number(quotient, format, list);
|
||||
name_to_speech(sys_tone_measure[4], format, list);
|
||||
if(remain > 0 && 100ul / remain > 10) {
|
||||
name_to_speech(sys_tone_number[0], format, list);
|
||||
}
|
||||
play_integer_number(remain, format, list);
|
||||
} else if (integer >= 10ul) {
|
||||
quotient = integer / 10ul;
|
||||
remain = integer % 10ul;
|
||||
play_integer_number(quotient, format, list);
|
||||
name_to_speech(sys_tone_measure[3], format, list);
|
||||
play_integer_number(remain, format, list);
|
||||
} else {
|
||||
quotient = integer % 10ul;
|
||||
if(quotient > 0) {
|
||||
name_to_speech(sys_tone_number[quotient], format, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 将金钱转换成语料文件添加进链表 */
|
||||
void money_to_speech(const char *value, char *format, struct core_list_head *list)
|
||||
{
|
||||
uint64_t integer = 0;
|
||||
uint32_t decimal = 0;
|
||||
uint32_t tmp_int = 0;
|
||||
char *dot = NULL, *end = NULL;
|
||||
|
||||
end = strstr(value, "}");
|
||||
if(end == NULL){
|
||||
return;
|
||||
}
|
||||
|
||||
dot = strstr(value, ".");
|
||||
if(dot != NULL){
|
||||
core_str2uint64((char *)value, dot - value, &integer);
|
||||
} else {
|
||||
core_str2uint64((char *)value, end - value, &integer);
|
||||
}
|
||||
|
||||
/*读取分数:分*/
|
||||
if(dot != NULL && dot[1] >= '0' && dot[1] <= '9') {
|
||||
decimal = (dot[1] - '0') * 10;
|
||||
if(dot[2] >= '0' && dot[2] <= '9') {
|
||||
decimal += (dot[2] - '0');
|
||||
}
|
||||
}
|
||||
|
||||
//元
|
||||
if(integer > 0) {
|
||||
play_integer_number(integer, format, list);
|
||||
name_to_speech(sys_tone_measure[2], format, list);
|
||||
}
|
||||
|
||||
if(decimal > 0) {
|
||||
//角
|
||||
tmp_int = decimal / 10;
|
||||
if(tmp_int > 0) {
|
||||
name_to_speech(sys_tone_number[tmp_int], format, list);
|
||||
name_to_speech(sys_tone_measure[1], format, list);
|
||||
} else if(integer > 0) {
|
||||
name_to_speech(sys_tone_number[0], format, list);
|
||||
}
|
||||
//分
|
||||
tmp_int = decimal % 10;
|
||||
if(tmp_int > 0) {
|
||||
name_to_speech(sys_tone_number[tmp_int], format, list);
|
||||
name_to_speech(sys_tone_measure[0], format, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
17
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/speech_trans.h
vendored
Normal file
17
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/speech_trans.h
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef __SPEECH_TRANS_H__
|
||||
#define __SPEECH_TRANS_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include "core_list.h"
|
||||
|
||||
typedef struct {
|
||||
char *filename;
|
||||
struct core_list_head linked_node;
|
||||
} play_node_t;
|
||||
|
||||
/* 语料名字转换成文件添加进链表 */
|
||||
void name_to_speech(const char *value, char *format, struct core_list_head *list);
|
||||
/* 将金钱转换成语料文件添加进链表 */
|
||||
void money_to_speech(const char *value, char *format, struct core_list_head *list);
|
||||
|
||||
#endif
|
||||
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/logpost/README.md
vendored
Normal file
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/logpost/README.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Name: 设备日志模块
|
||||
LOGPOST Component for Link SDK V4.0.0
|
||||
|
||||
458
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/logpost/aiot_logpost_api.c
vendored
Normal file
458
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/logpost/aiot_logpost_api.c
vendored
Normal file
@@ -0,0 +1,458 @@
|
||||
/**
|
||||
* @file aiot_logpost_api.c
|
||||
* @brief logpost模块的API接口实现, 提供设备端日志上云的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
#include "logpost_private.h"
|
||||
|
||||
#include "core_string.h"
|
||||
#include "core_log.h"
|
||||
#include "core_mqtt.h"
|
||||
#include "core_global.h"
|
||||
#include "aiot_mqtt_api.h"
|
||||
|
||||
|
||||
#define LOGPOST_JSON_KEY_MODE "mode"
|
||||
|
||||
const char *logpost_loglevel[] = {
|
||||
"FATAL",
|
||||
"ERROR",
|
||||
"WARN",
|
||||
"INFO",
|
||||
"DEBUG",
|
||||
};
|
||||
|
||||
static void _logpost_config_data_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
logpost_handle_t *logpost_handle = (logpost_handle_t *)userdata;
|
||||
aiot_logpost_event_t event;
|
||||
char *value = NULL;
|
||||
uint32_t value_len = 0;
|
||||
uint32_t log_switch = 0;
|
||||
|
||||
/* construct event message */
|
||||
memset(&event, 0, sizeof(aiot_logpost_event_t));
|
||||
event.type = AIOT_LOGPOSTEVT_CONFIG_DATA;
|
||||
|
||||
core_log(logpost_handle->sysdep, STATE_LOGPOST_LOG_RECV, "LOGPOST user log config arrived\r\n");
|
||||
|
||||
if ((core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
LOGPOST_JSON_KEY_MODE, strlen(LOGPOST_JSON_KEY_MODE), &value, &value_len)) < 0 ||
|
||||
(core_str2uint(value, value_len, &log_switch)) < 0) {
|
||||
|
||||
core_log(logpost_handle->sysdep, SATAE_LOGPOST_LOG_PARSE_MSG_FAILED, "LOGPOST parse log config failed\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* update log config */
|
||||
logpost_handle->user_log_switch = log_switch;
|
||||
|
||||
/* invoke user callback */
|
||||
if (logpost_handle->event_handler != NULL) {
|
||||
event.data.config_data.on_off = log_switch;
|
||||
logpost_handle->event_handler(logpost_handle, &event, logpost_handle->userdata);
|
||||
}
|
||||
}
|
||||
|
||||
static void _logpost_get_config(logpost_handle_t *logpost_handle)
|
||||
{
|
||||
char *topic = NULL;
|
||||
char *payload = NULL;
|
||||
char *fmt = "{\"id\":\"%s\",\"version\":\"1.0\",\"params\":{\"getType\":\"content\",\"configScope\":\"device\"}}";
|
||||
int32_t res = STATE_SUCCESS;
|
||||
int32_t id = 0;
|
||||
char *pk = NULL, *dn = NULL;
|
||||
char id_string[11] = { 0 };
|
||||
|
||||
if (NULL == logpost_handle || NULL == logpost_handle->mqtt_handle) {
|
||||
return;
|
||||
}
|
||||
if (NULL == (pk = core_mqtt_get_product_key(logpost_handle->mqtt_handle))) {
|
||||
return;
|
||||
}
|
||||
if (NULL == (dn = core_mqtt_get_device_name(logpost_handle->mqtt_handle))) {
|
||||
return;
|
||||
}
|
||||
|
||||
core_global_alink_id_next(logpost_handle->sysdep, &id);
|
||||
core_int2str(id, id_string, NULL);
|
||||
|
||||
/* construct topic */
|
||||
{
|
||||
char *src[2] = { pk, dn };
|
||||
res = core_sprintf(logpost_handle->sysdep, &topic, LOGPOST_CONFIG_GET_TOPIC_FMT, src, sizeof(src) / sizeof(char *),
|
||||
LOGPOST_MODULE_NAME);
|
||||
if (NULL == topic) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* construct payload */
|
||||
{
|
||||
char *src[1] = { id_string };
|
||||
res = core_sprintf(logpost_handle->sysdep, &payload, fmt,
|
||||
src, sizeof(src) / sizeof(char *), LOGPOST_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
logpost_handle->sysdep->core_sysdep_free(topic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(logpost_handle->mqtt_handle, topic, (uint8_t *)payload, (uint32_t)strlen(payload), 0);
|
||||
logpost_handle->sysdep->core_sysdep_free(topic);
|
||||
logpost_handle->sysdep->core_sysdep_free(payload);
|
||||
}
|
||||
|
||||
int32_t _logpost_send_nwkstats_rtt(logpost_handle_t *handle)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
aiot_logpost_msg_t msg;
|
||||
core_mqtt_nwkstats_info_t nwkstats_info;
|
||||
char *content_fmt = NWKSTAT_RTT_INFO_FMT;
|
||||
char timestamp_str[22] = {0};
|
||||
char rtt_str[22] = {0};
|
||||
char *content = NULL;
|
||||
char *content_src[] = {timestamp_str, rtt_str};
|
||||
|
||||
core_mqtt_get_nwkstats(handle->mqtt_handle, &nwkstats_info);
|
||||
core_uint642str(nwkstats_info.rtt, rtt_str, NULL);
|
||||
core_uint642str(handle->sysdep->core_sysdep_time(), timestamp_str, NULL);
|
||||
res = core_sprintf(handle->sysdep, &content, content_fmt, content_src, 2, LOGPOST_MODULE_NAME);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(aiot_logpost_msg_t));
|
||||
msg.timestamp = 0; /* 单位为ms的时间戳, 填写0则SDK将使用当前的时间戳 */
|
||||
msg.loglevel = AIOT_LOGPOST_LEVEL_INFO; /* 日志级别 */
|
||||
msg.module_name = NWKSTAT_NET_RT; /* 日志对应的模块 */
|
||||
msg.code = 200; /* 状态码 */
|
||||
msg.msg_id = 0;
|
||||
msg.content = content; /* 日志内容 */
|
||||
|
||||
res = aiot_logpost_send(handle, &msg);
|
||||
handle->sysdep->core_sysdep_free(content);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t _logpost_send_nwkstats_conn(logpost_handle_t *handle)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
aiot_logpost_msg_t msg;
|
||||
core_mqtt_nwkstats_info_t nwkstats_info;
|
||||
char *content_fmt = NULL;
|
||||
char success_time[22] = {0};
|
||||
char conn_time_str[22] = {0};
|
||||
char failed_time[22] = {0};
|
||||
char conn_code[12] = {0};
|
||||
char *content = NULL;
|
||||
char *content_src[] = {success_time, NULL, conn_time_str, failed_time, NULL, conn_code};
|
||||
uint8_t content_src_cnt = 0;
|
||||
|
||||
core_mqtt_get_nwkstats(handle->mqtt_handle, &nwkstats_info);
|
||||
if (nwkstats_info.connect_time_used == 0) {
|
||||
return res;
|
||||
}
|
||||
core_uint642str(nwkstats_info.connect_timestamp, success_time, NULL);
|
||||
content_src[1] = (nwkstats_info.network_type == 0) ? "TCP" : "TLS";
|
||||
content_src[4] = (nwkstats_info.network_type == 0) ? "TCP" : "TLS";
|
||||
core_uint642str(nwkstats_info.connect_time_used, conn_time_str, NULL);
|
||||
core_uint642str(nwkstats_info.failed_timestamp, failed_time, NULL);
|
||||
core_int2str(nwkstats_info.failed_error_code, conn_code, NULL);
|
||||
|
||||
/* check if connect failure happened */
|
||||
if (nwkstats_info.failed_error_code != 0) {
|
||||
content_fmt = NWKSTAT_CONN_INFO_FMT2;
|
||||
content_src_cnt = sizeof(content_src) / sizeof(content_src[0]);
|
||||
} else {
|
||||
content_fmt = NWKSTAT_CONN_INFO_FMT;
|
||||
content_src_cnt = 3;
|
||||
}
|
||||
|
||||
res = core_sprintf(handle->sysdep, &content, content_fmt, content_src, content_src_cnt, LOGPOST_MODULE_NAME);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(aiot_logpost_msg_t));
|
||||
msg.timestamp = 0; /* 单位为ms的时间戳, 填写0则SDK将使用当前的时间戳 */
|
||||
msg.loglevel = AIOT_LOGPOST_LEVEL_INFO; /* 日志级别 */
|
||||
msg.module_name = NWKSTAT_NET_CONN; /* 日志对应的模块 */
|
||||
msg.code = 200; /* 状态码 */
|
||||
msg.msg_id = 0;
|
||||
msg.content = content; /* 日志内容 */
|
||||
|
||||
res = aiot_logpost_send(handle, &msg);
|
||||
handle->sysdep->core_sysdep_free(content);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t _should_report_sys_log(logpost_handle_t *logpost_handle, char *module_name)
|
||||
{
|
||||
int result = 0;
|
||||
if (0 == logpost_handle->sys_log_switch) {
|
||||
return result;
|
||||
}
|
||||
if (0 == memcmp(NWKSTAT_NET_CONN, module_name, strlen(NWKSTAT_NET_CONN)) ||
|
||||
0 == memcmp(NWKSTAT_NET_RT, module_name, strlen(NWKSTAT_NET_RT))) {
|
||||
result = 1;
|
||||
core_log(logpost_handle->sysdep, STATE_LOGPOST_LOG_RECV,
|
||||
"sys log config is on, toggle it using AIOT_LOGPOSTOPT_SYS_LOG.\r\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void _logpost_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
|
||||
{
|
||||
logpost_handle_t *logpost_handle = (logpost_handle_t *)context;
|
||||
|
||||
if (core_event != NULL) {
|
||||
switch (core_event->type) {
|
||||
case CORE_MQTTEVT_DEINIT: {
|
||||
logpost_handle->mqtt_handle = NULL;
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == context || NULL == event) {
|
||||
if (logpost_handle->sys_log_switch == 0) {
|
||||
return;
|
||||
}
|
||||
_logpost_send_nwkstats_conn(logpost_handle);
|
||||
|
||||
if ((logpost_handle->sysdep->core_sysdep_time() - logpost_handle->last_post_time) \
|
||||
> LOGPOST_NWKSTATS_POST_INTERVAL) {
|
||||
logpost_handle->last_post_time = logpost_handle->sysdep->core_sysdep_time();
|
||||
|
||||
_logpost_send_nwkstats_rtt(logpost_handle);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->type == AIOT_MQTTEVT_CONNECT) {
|
||||
_logpost_get_config(logpost_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void *aiot_logpost_init(void)
|
||||
{
|
||||
aiot_sysdep_portfile_t *sysdep = aiot_sysdep_get_portfile();
|
||||
logpost_handle_t *logpost_handle = NULL;
|
||||
|
||||
if (NULL == sysdep) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
logpost_handle = sysdep->core_sysdep_malloc(sizeof(logpost_handle_t), LOGPOST_MODULE_NAME);
|
||||
if (NULL == logpost_handle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(logpost_handle, 0, sizeof(logpost_handle_t));
|
||||
logpost_handle->sysdep = sysdep;
|
||||
logpost_handle->user_log_switch = LOGPOST_DEFAULT_LOG_ONOFF;
|
||||
logpost_handle->sys_log_switch = LOGPOST_DEFAULT_LOG_ONOFF;
|
||||
|
||||
core_global_init(sysdep);
|
||||
return logpost_handle;
|
||||
}
|
||||
|
||||
int32_t aiot_logpost_setopt(void *handle, aiot_logpost_option_t option, void *data)
|
||||
{
|
||||
logpost_handle_t *logpost_handle;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == handle || NULL == data) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
if (option >= AIOT_LOGPOSTOPT_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
logpost_handle = (logpost_handle_t *)handle;
|
||||
|
||||
switch (option) {
|
||||
case AIOT_LOGPOSTOPT_MQTT_HANDLE: {
|
||||
aiot_mqtt_topic_map_t topic_mapping;
|
||||
logpost_handle->mqtt_handle = data;
|
||||
core_mqtt_process_data_t process_data;
|
||||
|
||||
/* setup mqtt topic mapping */
|
||||
memset(&topic_mapping, 0, sizeof(aiot_mqtt_topic_map_t));
|
||||
topic_mapping.topic = LOGPOST_CONFIG_PUSH_TOPIC;
|
||||
topic_mapping.handler = _logpost_config_data_handler;
|
||||
topic_mapping.userdata = handle;
|
||||
res = aiot_mqtt_setopt(data, AIOT_MQTTOPT_APPEND_TOPIC_MAP, &topic_mapping);
|
||||
if (res < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
topic_mapping.topic = LOGPOST_CONFIG_GET_REPLY_TOPIC;
|
||||
res = aiot_mqtt_setopt(data, AIOT_MQTTOPT_APPEND_TOPIC_MAP, &topic_mapping);
|
||||
if (res < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup mqtt process handler */
|
||||
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
|
||||
process_data.handler = _logpost_process_handler;
|
||||
process_data.context = logpost_handle;
|
||||
res = core_mqtt_setopt(data, CORE_MQTTOPT_APPEND_PROCESS_HANDLER, &process_data);
|
||||
}
|
||||
break;
|
||||
case AIOT_LOGPOSTOPT_EVENT_HANDLER: {
|
||||
logpost_handle->event_handler = (aiot_logpost_event_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_LOGPOSTOPT_USERDATA: {
|
||||
logpost_handle->userdata = data;
|
||||
}
|
||||
break;
|
||||
case AIOT_LOGPOSTOPT_SYS_LOG: {
|
||||
logpost_handle->sys_log_switch = *(uint8_t *)data;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_logpost_send(void *handle, aiot_logpost_msg_t *msg)
|
||||
{
|
||||
logpost_handle_t *logpost_handle = NULL;
|
||||
char *topic = NULL;
|
||||
char *payload = NULL;
|
||||
char *fmt = "{\"id\":\"%s\",\"version\":\"1.0\",\"params\":" \
|
||||
"[{\"utcTime\":\"%s\",\"logLevel\":\"%s\",\"module\":\"%s\",\"code\":\"%s\",\"traceContext\":\"%s\",\"logContent\":\"%s\"}]}";
|
||||
char *pk = NULL, *dn = NULL;
|
||||
int32_t id = 0;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == handle || NULL == msg) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
if (msg->loglevel > AIOT_LOGPOST_LEVEL_DEBUG) {
|
||||
return STATE_LOGPOST_LOGLEVEL_ERROR;
|
||||
}
|
||||
if (NULL == msg->module_name) {
|
||||
return STATE_LOGPOST_LOG_MODULE_NAME_IS_NULL;
|
||||
}
|
||||
if (NULL == msg->content) {
|
||||
return STATE_LOGPOST_LOG_CONTENT_IS_NULL;
|
||||
}
|
||||
if (strlen(msg->content) > LOGPOST_CONTENT_MAXIMUM_LEN) {
|
||||
return STATE_LOGPOST_LOG_CONTENT_TOO_LONG;
|
||||
}
|
||||
if (msg->timestamp > 100000000000000) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
logpost_handle = (logpost_handle_t *)handle;
|
||||
if (NULL == logpost_handle->mqtt_handle) {
|
||||
return STATE_LOGPOST_MQTT_HANDLE_IS_NULL;
|
||||
}
|
||||
if (NULL == (pk = core_mqtt_get_product_key(logpost_handle->mqtt_handle))) {
|
||||
return STATE_USER_INPUT_MISSING_PRODUCT_KEY;
|
||||
}
|
||||
if (NULL == (dn = core_mqtt_get_device_name(logpost_handle->mqtt_handle))) {
|
||||
return STATE_USER_INPUT_MISSING_DEVICE_NAME;
|
||||
}
|
||||
if (1 != _should_report_sys_log(logpost_handle, msg->module_name) && logpost_handle->user_log_switch == 0) {
|
||||
return STATE_LOGPOST_POST_TURN_OFF;
|
||||
}
|
||||
|
||||
/* construct topic */
|
||||
{
|
||||
char *src[2] = {pk, dn};
|
||||
res = core_sprintf(logpost_handle->sysdep, &topic, LOGPOST_POST_TOPIC_FMT, src, sizeof(src) / sizeof(char *),
|
||||
LOGPOST_MODULE_NAME);
|
||||
if (NULL == topic) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/* construct payload */
|
||||
{
|
||||
char id_string[11] = { 0 };
|
||||
char utc[32] = { 0 };
|
||||
char code[11] = { 0 };
|
||||
char msg_id[22] = { 0 };
|
||||
const char *src[] = { id_string, utc, logpost_loglevel[msg->loglevel], msg->module_name, code, msg_id, msg->content };
|
||||
|
||||
core_global_alink_id_next(logpost_handle->sysdep, &id);
|
||||
core_int2str(id, id_string, NULL);
|
||||
|
||||
if (msg->timestamp == 0) {
|
||||
_core_log_append_date(logpost_handle->sysdep, core_log_get_timestamp(logpost_handle->sysdep), utc);
|
||||
} else {
|
||||
_core_log_append_date(logpost_handle->sysdep, msg->timestamp, utc);
|
||||
}
|
||||
core_int2str(msg->code, code, NULL);
|
||||
core_uint642str(msg->msg_id, msg_id, NULL);
|
||||
|
||||
res = core_sprintf(logpost_handle->sysdep, &payload, fmt,
|
||||
(char **)src, sizeof(src) / sizeof(char *), LOGPOST_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
logpost_handle->sysdep->core_sysdep_free(topic);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(logpost_handle->mqtt_handle, topic, (uint8_t *)payload, (uint32_t)strlen(payload), 0);
|
||||
logpost_handle->sysdep->core_sysdep_free(topic);
|
||||
logpost_handle->sysdep->core_sysdep_free(payload);
|
||||
|
||||
if (res >= STATE_SUCCESS) {
|
||||
res = id;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_logpost_deinit(void **p_handle)
|
||||
{
|
||||
logpost_handle_t *logpost_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
aiot_mqtt_topic_map_t topic_mapping;
|
||||
core_mqtt_process_data_t process_data;
|
||||
|
||||
if (NULL == p_handle || NULL == *p_handle) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
logpost_handle = *p_handle;
|
||||
sysdep = logpost_handle->sysdep;
|
||||
*p_handle = NULL;
|
||||
|
||||
/* remove mqtt precess handler */
|
||||
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
|
||||
process_data.handler = _logpost_process_handler;
|
||||
core_mqtt_setopt(logpost_handle->mqtt_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER, &process_data);
|
||||
|
||||
/* remove mqtt topic mapping */
|
||||
memset(&topic_mapping, 0, sizeof(aiot_mqtt_topic_map_t));
|
||||
topic_mapping.topic = LOGPOST_CONFIG_PUSH_TOPIC;
|
||||
topic_mapping.handler = _logpost_config_data_handler;
|
||||
aiot_mqtt_setopt(logpost_handle->mqtt_handle, AIOT_MQTTOPT_REMOVE_TOPIC_MAP, &topic_mapping);
|
||||
topic_mapping.topic = LOGPOST_CONFIG_GET_REPLY_TOPIC;
|
||||
aiot_mqtt_setopt(logpost_handle->mqtt_handle, AIOT_MQTTOPT_REMOVE_TOPIC_MAP, &topic_mapping);
|
||||
|
||||
sysdep->core_sysdep_free(logpost_handle);
|
||||
|
||||
core_global_deinit(sysdep);
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
268
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/logpost/aiot_logpost_api.h
vendored
Normal file
268
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/logpost/aiot_logpost_api.h
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
/**
|
||||
* @file aiot_logpost_api.h
|
||||
* @brief logpost模块头文件, 提供设备端日志上云的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 1. 在使用日志上云模块前, 用户应首先创建好一个MQTT实例
|
||||
*
|
||||
* 2. 调用`aiot_logpost_init`创建一个日志上云实例, 保存实例句柄
|
||||
*
|
||||
* 3. 调用`aiot_logpost_setopt`配置`AIOT_LOGPOSTOPT_MQTT_HANDLE`选项以设置MQTT句柄, 此选项为强制配置选项
|
||||
*
|
||||
* 4. 调用`aiot_logpost_setopt`配置`AIOT_LOGPOSTOPT_EVENT_HANDLER`和`AIOT_LOGPOSTOPT_USER_DATA`选项以注册事件接收回调函数和用户上下文数据指针
|
||||
*
|
||||
* 5. 在使用`aiot_logpost_send`发送日志消息前, 应先完成MQTT实例的建连
|
||||
*
|
||||
*/
|
||||
#ifndef __AIOT_LOGPOST_API_H__
|
||||
#define __AIOT_LOGPOST_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief -0x1500~-0x15FF表达SDK在logpost模块内的状态码
|
||||
*/
|
||||
#define STATE_LOGPOST_BASE (-0x1500)
|
||||
|
||||
/**
|
||||
* @brief 用户未调用@ref aiot_logpost_setopt 配置MQTT句柄
|
||||
*/
|
||||
#define STATE_LOGPOST_MQTT_HANDLE_IS_NULL (-0x1501)
|
||||
|
||||
/**
|
||||
* @brief 日志上报被云端配置为关闭状态
|
||||
*/
|
||||
#define STATE_LOGPOST_POST_TURN_OFF (-0x1502)
|
||||
|
||||
/**
|
||||
* @brief 日志消息的日志级别有误
|
||||
*/
|
||||
#define STATE_LOGPOST_LOGLEVEL_ERROR (-0x1503)
|
||||
|
||||
/**
|
||||
* @brief 日志消息的模块名称字段为NULL
|
||||
*/
|
||||
#define STATE_LOGPOST_LOG_MODULE_NAME_IS_NULL (-0x1504)
|
||||
|
||||
/**
|
||||
* @brief 日志消息的日志内容字段为NULL
|
||||
*/
|
||||
#define STATE_LOGPOST_LOG_CONTENT_IS_NULL (-0x1505)
|
||||
|
||||
/**
|
||||
* @brief 日志消息的日志内容字段字符串长度大于4096个字节
|
||||
*/
|
||||
#define STATE_LOGPOST_LOG_CONTENT_TOO_LONG (-0x1506)
|
||||
|
||||
/**
|
||||
* @brief 接收到服务器下行消息时的内部日志状态码
|
||||
*/
|
||||
#define STATE_LOGPOST_LOG_RECV (-0x1507)
|
||||
|
||||
/**
|
||||
* @brief 解析服务器下行消息失败时的内部日志状态码
|
||||
*/
|
||||
#define SATAE_LOGPOST_LOG_PARSE_MSG_FAILED (-0x1508)
|
||||
|
||||
|
||||
/**
|
||||
* @brief @ref aiot_logpost_setopt 接口的option参数可选值.
|
||||
*
|
||||
* @details 下文每个选项中的数据类型, 指的是@ref aiot_logpost_setopt 中, data参数的数据类型
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 模块依赖的MQTT句柄
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* LOGPOST模块依赖底层的MQTT模块, 用户必需配置正确的MQTT句柄, 否则无法正常工作, 数据类型为(void *)
|
||||
*/
|
||||
AIOT_LOGPOSTOPT_MQTT_HANDLE,
|
||||
|
||||
/**
|
||||
* @brief 设置回调, 它在SDK收到网络报文的时候被调用, 告知用户, 数据类型为(aiot_logpost_recv_handler_t)
|
||||
*/
|
||||
AIOT_LOGPOSTOPT_EVENT_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief 用户需要SDK暂存的上下文, 数据类型为(void *)
|
||||
*
|
||||
* @details 这个上下文指针会在 AIOT_LOGPOSTOPT_RECV_HANDLER 设置的回调被调用时, 由SDK传给用户
|
||||
*/
|
||||
AIOT_LOGPOSTOPT_USERDATA,
|
||||
|
||||
/**
|
||||
* @brief 系统日志的开关.
|
||||
*
|
||||
* @detail 设置为1表示要上报系统日志, 设置为0表示不上报系统日志. 这里的系统日志是指建连耗时和网络延时
|
||||
*/
|
||||
AIOT_LOGPOSTOPT_SYS_LOG,
|
||||
|
||||
/**
|
||||
* @brief 配置选项数量最大值, 不可用作配置参数
|
||||
*/
|
||||
AIOT_LOGPOSTOPT_MAX,
|
||||
|
||||
} aiot_logpost_option_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 日志级别枚举类型定义
|
||||
*/
|
||||
typedef enum {
|
||||
AIOT_LOGPOST_LEVEL_FATAL,
|
||||
AIOT_LOGPOST_LEVEL_ERR,
|
||||
AIOT_LOGPOST_LEVEL_WARN,
|
||||
AIOT_LOGPOST_LEVEL_INFO,
|
||||
AIOT_LOGPOST_LEVEL_DEBUG,
|
||||
} aiot_logpost_level_t;
|
||||
|
||||
/**
|
||||
* @brief 日志数据结构体定义
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief utc时间戳, 单位为ms, 此数值会直接展示在云端控制台设备日志页面
|
||||
*/
|
||||
uint64_t timestamp;
|
||||
|
||||
/**
|
||||
* @brief 日志级别, 请查看@ref aiot_logpost_level_t 定义
|
||||
*/
|
||||
aiot_logpost_level_t loglevel;
|
||||
|
||||
/**
|
||||
* @brief 模块名称, <b>必须为以结束符'\0'结尾的字符串</b>
|
||||
*/
|
||||
char *module_name;
|
||||
|
||||
/**
|
||||
* @brief 状态码, 可用于标识日志对应的状态
|
||||
*/
|
||||
int32_t code;
|
||||
|
||||
/**
|
||||
* @brief 消息标示符, 用于标识云端下行消息, 可从data-module模块的消息接收回调函数中获得对应的标识符, 如果用户设置为0, 此字段将不上传。
|
||||
*/
|
||||
uint64_t msg_id;
|
||||
|
||||
/**
|
||||
* @brief 日志内容, <b>必须为以结束符'\0'结尾的字符串</b>
|
||||
*/
|
||||
char *content;
|
||||
} aiot_logpost_msg_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief logpost模块内部发生值得用户关注的状态变化时, 通知用户的事件类型
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 接受到云端下发的日志配置数据
|
||||
*/
|
||||
AIOT_LOGPOSTEVT_CONFIG_DATA,
|
||||
} aiot_logpost_event_type_t;
|
||||
|
||||
/**
|
||||
* @brief logpost模块内部发生值得用户关注的状态变化时, 通知用户的事件内容
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 事件内容所对应的事件类型, 更多信息请参考@ref aiot_logpost_event_type_t
|
||||
*/
|
||||
aiot_logpost_event_type_t type;
|
||||
|
||||
union {
|
||||
/**
|
||||
* @brief 日志配置数据结构体
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* @brief 日志开关状态, 0: 关闭日志上传; 1: 打开日志上传
|
||||
*/
|
||||
uint8_t on_off;
|
||||
} config_data;
|
||||
} data;
|
||||
} aiot_logpost_event_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief logpost模块内部发生值得用户关注的状态变化时, 通知用户所调用的事件回调函数
|
||||
*
|
||||
* @param[in] handle logpost会话句柄
|
||||
* @param[in] event logpost模块中发生的事件的内容
|
||||
* @param[in] userdata 指向用户上下文数据的指针, 这个指针由用户通过调用@ref aiot_logpost_setopt 配置@ref AIOT_LOGPOSTOPT_USERDATA 选项设置
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (*aiot_logpost_event_handler_t)(void *handle,
|
||||
const aiot_logpost_event_t *event, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief 创建logpost会话实例, 并以默认值配置会话参数
|
||||
*
|
||||
* @return void *
|
||||
* @retval 非NULL logpost实例的句柄
|
||||
* @retval NULL 初始化失败, 一般是内存分配失败导致
|
||||
*/
|
||||
void *aiot_logpost_init(void);
|
||||
|
||||
/**
|
||||
* @brief 配置logpost会话
|
||||
*
|
||||
* @param[in] handle logpost会话句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_logpost_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_logpost_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 参数配置失败
|
||||
* @retval STATE_SUCCESS 参数配置成功
|
||||
* @retval STATE_USER_INPUT_NULL_POINTER 入参handle或data为NULL
|
||||
* @retval STATE_USER_INPUT_OUT_RANGE 入参optioin的枚举值>=AIOT_LOGPOSTOPT_MAX
|
||||
* @retval others 参考@ref aiot_state_api.h
|
||||
*/
|
||||
int32_t aiot_logpost_setopt(void *handle, aiot_logpost_option_t option, void *data);
|
||||
|
||||
/**
|
||||
* @brief 向服务器发送日志消息
|
||||
*
|
||||
* @param[in] handle logpost会话句柄
|
||||
* @param[in] msg 消息结构体, 可指定日志对应模块, 日志级别等, 更多信息请参考@ref aiot_logpost_msg_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 请求发送成功
|
||||
* @retval STATE_USER_INPUT_NULL_POINTER 入参<i>handle</i>或<i>msg</i>为NULL
|
||||
* @retval STATE_SYS_DEPEND_MALLOC_FAILED 内存分配失败
|
||||
* @retval STATE_LOGPOST_MQTT_HANDLE_IS_NULL 用户未调用@ref aiot_logpost_setopt 配置MQTT句柄
|
||||
* @retval others 参考@ref aiot_state_api.h 或@ref STATE_SHADOW_BASE 中对应的错误码说明
|
||||
*
|
||||
*/
|
||||
int32_t aiot_logpost_send(void *handle, aiot_logpost_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief 结束logpost会话, 销毁实例并回收资源
|
||||
*
|
||||
* @param[in] handle 指向logpost会话句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 执行失败
|
||||
* @retval >=STATE_SUCCESS 执行成功
|
||||
*/
|
||||
int32_t aiot_logpost_deinit(void **handle);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AIOT_LOGPOST_API_H__ */
|
||||
|
||||
64
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/logpost/logpost_private.h
vendored
Normal file
64
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/logpost/logpost_private.h
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @file logpost_private.h
|
||||
* @brief logpost模块内部的宏定义和数据结构声明, 不面向其它模块, 更不面向用户
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __LOGPOST_PRIVATE_H__
|
||||
#define __LOGPOST_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_stdinc.h"
|
||||
|
||||
#include "aiot_state_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_mqtt_api.h"
|
||||
#include "aiot_logpost_api.h"
|
||||
|
||||
|
||||
/* logpost模块内部的会话句柄结构体, SDK用户不可见, 只能得到void *handle类型的指针 */
|
||||
typedef struct {
|
||||
aiot_sysdep_portfile_t *sysdep;
|
||||
void *mqtt_handle;
|
||||
uint8_t user_log_switch;
|
||||
uint8_t sys_log_switch;
|
||||
|
||||
aiot_logpost_event_handler_t event_handler;
|
||||
void *userdata;
|
||||
|
||||
/* network info stats */
|
||||
uint64_t last_post_time;
|
||||
|
||||
} logpost_handle_t;
|
||||
|
||||
#define LOGPOST_MODULE_NAME "logpost" /* 用于内存统计的模块名字符串 */
|
||||
|
||||
#define LOGPOST_DEFAULT_LOG_ONOFF (0)
|
||||
|
||||
#define LOGPOST_CONTENT_MAXIMUM_LEN (4096)
|
||||
|
||||
#define LOGPOST_NWKSTATS_POST_INTERVAL (1800000)
|
||||
|
||||
|
||||
/* 上下行topic定义 */
|
||||
#define LOGPOST_POST_TOPIC_FMT "/sys/%s/%s/thing/log/post"
|
||||
#define LOGPOST_CONFIG_GET_TOPIC_FMT "/sys/%s/%s/thing/config/log/get"
|
||||
#define LOGPOST_CONFIG_PUSH_TOPIC "/sys/+/+/thing/config/log/push"
|
||||
#define LOGPOST_CONFIG_GET_REPLY_TOPIC "/sys/+/+/thing/config/log/get_reply"
|
||||
|
||||
#define NWKSTAT_RTT_INFO_FMT "time=%s^rtt=%s"
|
||||
#define NWKSTAT_CONN_INFO_FMT "time=%s^conn_type=%s^conn_cost=%s^conn_ret=0"
|
||||
#define NWKSTAT_CONN_INFO_FMT2 "time=%s^conn_type=%s^conn_cost=%s^conn_ret=0,time=%s^conn_type=%s^conn_cost=0^conn_ret=%s"
|
||||
|
||||
#define NWKSTAT_NET_RT "net_rt"
|
||||
#define NWKSTAT_NET_CONN "net_conn"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* __LOGPOST_PRIVATE_H__ */
|
||||
|
||||
2
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ntp/README.md
vendored
Normal file
2
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ntp/README.md
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Name: 时间同步模块
|
||||
NTP Component for Link SDK V4.0.0
|
||||
342
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ntp/aiot_ntp_api.c
vendored
Normal file
342
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ntp/aiot_ntp_api.c
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* @file aiot_ntp_api.c
|
||||
* @brief ntp模块的API接口实现, 提供获取utc时间的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
/* TODO: 对本模块的头文件, 仅需包含ntp_private.h, 不需包含aiot_ntp_api.h */
|
||||
#include "ntp_private.h"
|
||||
|
||||
/* TODO: 列出对core模块需要包含的头文件 */
|
||||
#include "core_string.h"
|
||||
#include "core_log.h"
|
||||
#include "core_global.h"
|
||||
#include "core_mqtt.h"
|
||||
|
||||
static void _core_ntp_exec_inc(ntp_handle_t *ntp_handle)
|
||||
{
|
||||
ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
|
||||
ntp_handle->exec_count++;
|
||||
ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
|
||||
}
|
||||
|
||||
static void _core_ntp_exec_dec(ntp_handle_t *ntp_handle)
|
||||
{
|
||||
ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
|
||||
ntp_handle->exec_count--;
|
||||
ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
|
||||
}
|
||||
|
||||
static void _ntp_recv_handler(void *handle, const aiot_mqtt_recv_t *packet, void *userdata)
|
||||
{
|
||||
ntp_handle_t *ntp_handle = (ntp_handle_t *)userdata;
|
||||
|
||||
switch (packet->type) {
|
||||
case AIOT_MQTTRECV_PUB: {
|
||||
char *dst_key = "deviceSendTime", *srt_key = "serverRecvTime", *sst_key = "serverSendTime";
|
||||
char *dst_value = NULL, *srt_value = NULL, *sst_value = NULL;
|
||||
uint32_t dst_value_len = 0, srt_value_len = 0, sst_value_len = 0;
|
||||
uint64_t dst = 0, srt = 0, sst = 0, utc = 0;
|
||||
|
||||
if (core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len, dst_key, (uint32_t)strlen(dst_key),
|
||||
&dst_value, &dst_value_len) == STATE_SUCCESS &&
|
||||
core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len, srt_key, (uint32_t)strlen(srt_key),
|
||||
&srt_value, &srt_value_len) == STATE_SUCCESS &&
|
||||
core_json_value((char *)packet->data.pub.payload, packet->data.pub.payload_len, sst_key, (uint32_t)strlen(sst_key),
|
||||
&sst_value, &sst_value_len) == STATE_SUCCESS) {
|
||||
if (core_str2uint64(dst_value, (uint8_t)dst_value_len, &dst) == STATE_SUCCESS &&
|
||||
core_str2uint64(srt_value, (uint8_t)srt_value_len, &srt) == STATE_SUCCESS &&
|
||||
core_str2uint64(sst_value, (uint8_t)sst_value_len, &sst) == STATE_SUCCESS) {
|
||||
core_date_t date;
|
||||
utc = (srt + sst + ntp_handle->sysdep->core_sysdep_time() - dst) / 2;
|
||||
|
||||
core_log_set_timestamp(ntp_handle->sysdep, utc);
|
||||
|
||||
memset(&date, 0, sizeof(core_date_t));
|
||||
core_utc2date(utc, ntp_handle->time_zone, &date);
|
||||
if (ntp_handle->recv_handler != NULL) {
|
||||
aiot_ntp_recv_t recv;
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_ntp_recv_t));
|
||||
recv.type = AIOT_NTPRECV_LOCAL_TIME;
|
||||
recv.data.local_time.timestamp = utc;
|
||||
recv.data.local_time.year = date.year;
|
||||
recv.data.local_time.mon = date.mon;
|
||||
recv.data.local_time.day = date.day;
|
||||
recv.data.local_time.hour = date.hour;
|
||||
recv.data.local_time.min = date.min;
|
||||
recv.data.local_time.sec = date.sec;
|
||||
recv.data.local_time.msec = date.msec;
|
||||
|
||||
ntp_handle->recv_handler(ntp_handle, &recv, ntp_handle->userdata);
|
||||
}
|
||||
} else {
|
||||
if (ntp_handle->event_handler != NULL) {
|
||||
aiot_ntp_event_t event;
|
||||
|
||||
memset(&event, 0, sizeof(aiot_ntp_event_t));
|
||||
event.type = AIOT_NTPEVT_INVALID_TIME_FORMAT;
|
||||
ntp_handle->event_handler(ntp_handle, &event, ntp_handle->userdata);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ntp_handle->event_handler != NULL) {
|
||||
aiot_ntp_event_t event;
|
||||
|
||||
memset(&event, 0, sizeof(aiot_ntp_event_t));
|
||||
event.type = AIOT_NTPEVT_INVALID_RESPONSE;
|
||||
ntp_handle->event_handler(ntp_handle, &event, ntp_handle->userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _ntp_operate_topic_map(ntp_handle_t *ntp_handle, aiot_mqtt_option_t option)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
aiot_mqtt_topic_map_t map;
|
||||
char *topic = NULL;
|
||||
char *topic_src[] = { core_mqtt_get_product_key(ntp_handle->mqtt_handle), core_mqtt_get_device_name(ntp_handle->mqtt_handle) };
|
||||
char *topic_fmt = NTP_RESPONSE_TOPIC_FMT;
|
||||
|
||||
memset(&map, 0, sizeof(aiot_mqtt_topic_map_t));
|
||||
|
||||
res = core_sprintf(ntp_handle->sysdep, &topic, topic_fmt, topic_src, sizeof(topic_src) / sizeof(char *),
|
||||
NTP_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
map.topic = topic;
|
||||
map.handler = _ntp_recv_handler;
|
||||
map.userdata = (void *)ntp_handle;
|
||||
|
||||
res = aiot_mqtt_setopt(ntp_handle->mqtt_handle, option, &map);
|
||||
ntp_handle->sysdep->core_sysdep_free(topic);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _ntp_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
|
||||
{
|
||||
ntp_handle_t *ntp_handle = (ntp_handle_t *)context;
|
||||
|
||||
if (core_event != NULL) {
|
||||
switch (core_event->type) {
|
||||
case CORE_MQTTEVT_DEINIT: {
|
||||
ntp_handle->mqtt_handle = NULL;
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _ntp_core_mqtt_operate_process_handler(ntp_handle_t *ntp_handle, core_mqtt_option_t option)
|
||||
{
|
||||
core_mqtt_process_data_t process_data;
|
||||
|
||||
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
|
||||
process_data.handler = _ntp_core_mqtt_process_handler;
|
||||
process_data.context = ntp_handle;
|
||||
|
||||
return core_mqtt_setopt(ntp_handle->mqtt_handle, option, &process_data);
|
||||
}
|
||||
|
||||
void *aiot_ntp_init(void)
|
||||
{
|
||||
ntp_handle_t *ntp_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if (sysdep == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ntp_handle = sysdep->core_sysdep_malloc(sizeof(ntp_handle_t), NTP_MODULE_NAME);
|
||||
if (ntp_handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(ntp_handle, 0, sizeof(ntp_handle_t));
|
||||
|
||||
ntp_handle->sysdep = sysdep;
|
||||
ntp_handle->deinit_timeout_ms = NTP_DEFAULT_DEINIT_TIMEOUT_MS;
|
||||
|
||||
ntp_handle->data_mutex = sysdep->core_sysdep_mutex_init();
|
||||
|
||||
ntp_handle->exec_enabled = 1;
|
||||
|
||||
return ntp_handle;
|
||||
}
|
||||
|
||||
int32_t aiot_ntp_setopt(void *handle, aiot_ntp_option_t option, void *data)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
ntp_handle_t *ntp_handle = (ntp_handle_t *)handle;
|
||||
|
||||
if (handle == NULL || data == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (option >= AIOT_NTPOPT_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
if (ntp_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
_core_ntp_exec_inc(ntp_handle);
|
||||
|
||||
ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
|
||||
switch (option) {
|
||||
case AIOT_NTPOPT_MQTT_HANDLE: {
|
||||
ntp_handle->mqtt_handle = data;
|
||||
ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
|
||||
res = _ntp_operate_topic_map(ntp_handle, AIOT_MQTTOPT_APPEND_TOPIC_MAP);
|
||||
if (res >= STATE_SUCCESS) {
|
||||
res = _ntp_core_mqtt_operate_process_handler(ntp_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER);
|
||||
}
|
||||
ntp_handle->sysdep->core_sysdep_mutex_lock(ntp_handle->data_mutex);
|
||||
}
|
||||
break;
|
||||
case AIOT_NTPOPT_TIME_ZONE: {
|
||||
ntp_handle->time_zone = *(int8_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_NTPOPT_RECV_HANDLER: {
|
||||
ntp_handle->recv_handler = (aiot_ntp_recv_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_NTPOPT_EVENT_HANDLER: {
|
||||
ntp_handle->event_handler = (aiot_ntp_event_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_NTPOPT_USERDATA: {
|
||||
ntp_handle->userdata = data;
|
||||
}
|
||||
break;
|
||||
case AIOT_NTPOPT_DEINIT_TIMEOUT_MS: {
|
||||
ntp_handle->deinit_timeout_ms = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
res = STATE_USER_INPUT_UNKNOWN_OPTION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ntp_handle->sysdep->core_sysdep_mutex_unlock(ntp_handle->data_mutex);
|
||||
|
||||
_core_ntp_exec_dec(ntp_handle);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_ntp_deinit(void **handle)
|
||||
{
|
||||
uint64_t deinit_timestart = 0;
|
||||
ntp_handle_t *ntp_handle = NULL;
|
||||
|
||||
if (handle == NULL || *handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
ntp_handle = *(ntp_handle_t **)handle;
|
||||
|
||||
if (ntp_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
ntp_handle->exec_enabled = 0;
|
||||
|
||||
_ntp_core_mqtt_operate_process_handler(ntp_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER);
|
||||
_ntp_operate_topic_map(ntp_handle, AIOT_MQTTOPT_REMOVE_TOPIC_MAP);
|
||||
|
||||
deinit_timestart = ntp_handle->sysdep->core_sysdep_time();
|
||||
do {
|
||||
if (ntp_handle->exec_count == 0) {
|
||||
break;
|
||||
}
|
||||
ntp_handle->sysdep->core_sysdep_sleep(NTP_DEINIT_INTERVAL_MS);
|
||||
} while ((ntp_handle->sysdep->core_sysdep_time() - deinit_timestart) < ntp_handle->deinit_timeout_ms);
|
||||
|
||||
if (ntp_handle->exec_count != 0) {
|
||||
return STATE_MQTT_DEINIT_TIMEOUT;
|
||||
}
|
||||
|
||||
*handle = NULL;
|
||||
|
||||
ntp_handle->sysdep->core_sysdep_mutex_deinit(&ntp_handle->data_mutex);
|
||||
|
||||
ntp_handle->sysdep->core_sysdep_free(ntp_handle);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t aiot_ntp_send_request(void *handle)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *topic = NULL, *payload = NULL;
|
||||
ntp_handle_t *ntp_handle = (ntp_handle_t *)handle;
|
||||
|
||||
if (handle == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (ntp_handle->mqtt_handle == NULL) {
|
||||
return STATE_NTP_MISSING_MQTT_HANDLE;
|
||||
}
|
||||
|
||||
if (ntp_handle->exec_enabled == 0) {
|
||||
return STATE_USER_INPUT_EXEC_DISABLED;
|
||||
}
|
||||
|
||||
_core_ntp_exec_inc(ntp_handle);
|
||||
|
||||
{
|
||||
char *topic_src[] = { core_mqtt_get_product_key(ntp_handle->mqtt_handle), core_mqtt_get_device_name(ntp_handle->mqtt_handle) };
|
||||
char *topic_fmt = NTP_REQUEST_TOPIC_FMT;
|
||||
char time_str[21] = {0};
|
||||
char *payload_src[] = { time_str };
|
||||
char *payload_fmt = NTP_REQUEST_PAYLOAD_FMT;
|
||||
|
||||
res = core_sprintf(ntp_handle->sysdep, &topic, topic_fmt, topic_src, sizeof(topic_src) / sizeof(char *),
|
||||
NTP_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
_core_ntp_exec_dec(ntp_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
core_uint642str(ntp_handle->sysdep->core_sysdep_time(), time_str, NULL);
|
||||
res = core_sprintf(ntp_handle->sysdep, &payload, payload_fmt, payload_src, sizeof(payload_src) / sizeof(char *),
|
||||
NTP_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
ntp_handle->sysdep->core_sysdep_free(topic);
|
||||
_core_ntp_exec_dec(ntp_handle);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(ntp_handle->mqtt_handle, topic, (uint8_t *)payload, (uint32_t)strlen(payload), 0);
|
||||
ntp_handle->sysdep->core_sysdep_free(topic);
|
||||
ntp_handle->sysdep->core_sysdep_free(payload);
|
||||
if (res < STATE_SUCCESS) {
|
||||
_core_ntp_exec_dec(ntp_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
_core_ntp_exec_dec(ntp_handle);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
264
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ntp/aiot_ntp_api.h
vendored
Normal file
264
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ntp/aiot_ntp_api.h
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* @file aiot_ntp_api.h
|
||||
* @brief ntp模块头文件, 提供获取utc时间的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* NTP模块用于从阿里云物联网平台上获取UTC时间, API的使用流程如下:
|
||||
*
|
||||
* 1. 首先参考 @ref aiot_mqtt_api.h 的说明, 保证成功建立与物联网平台的`MQTT`连接
|
||||
*
|
||||
* 2. 调用 @ref aiot_ntp_init 初始化ntp会话, 获取会话句柄
|
||||
*
|
||||
* 3. 调用 @ref aiot_ntp_setopt 配置NTP会话的参数, 常用配置项见 @ref aiot_ntp_setopt 的说明
|
||||
*
|
||||
* 4. 调用 @ref aiot_ntp_send_request 发送NTP请求
|
||||
*
|
||||
* 5. 收到的UTC时间经SDK处理后会调用由 @ref aiot_ntp_setopt 配置的 @ref AIOT_NTPOPT_RECV_HANDLER 回调函数, 通知用户当前的时间
|
||||
*
|
||||
*/
|
||||
#ifndef __AIOT_NTP_API_H__
|
||||
#define __AIOT_NTP_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief -0x1100~-0x11FF表达SDK在ntp模块内的状态码
|
||||
*/
|
||||
#define STATE_NTP_BASE (-0x1100)
|
||||
|
||||
/**
|
||||
* @brief MQTT会话句柄未设置, 请通过 @ref aiot_ntp_setopt 设置MQTT会话句柄
|
||||
*/
|
||||
#define STATE_NTP_MISSING_MQTT_HANDLE (-0x1101)
|
||||
|
||||
/**
|
||||
* @brief ntp模块收到从网络上来的报文时, 通知用户的报文类型
|
||||
*/
|
||||
typedef enum {
|
||||
AIOT_NTPRECV_LOCAL_TIME
|
||||
} aiot_ntp_recv_type_t;
|
||||
|
||||
/**
|
||||
* @brief ntp模块收到从网络上来的报文时, 通知用户的报文内容
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 报文内容所对应的报文类型, 更多信息请参考@ref aiot_ntp_recv_type_t
|
||||
*/
|
||||
aiot_ntp_recv_type_t type;
|
||||
union {
|
||||
/**
|
||||
* @brief utc事件戳以及时区换算后的日期, 以 @ref AIOT_NTPOPT_TIME_ZONE 设置的时区为准
|
||||
*/
|
||||
struct {
|
||||
uint64_t timestamp;
|
||||
uint32_t year;
|
||||
uint32_t mon;
|
||||
uint32_t day;
|
||||
uint32_t hour;
|
||||
uint32_t min;
|
||||
uint32_t sec;
|
||||
uint32_t msec;
|
||||
} local_time;
|
||||
} data;
|
||||
} aiot_ntp_recv_t;
|
||||
|
||||
/**
|
||||
* @brief ntp模块收到从网络上来的报文时, 通知用户所调用的数据回调函数
|
||||
*
|
||||
* @param[in] handle ntp会话句柄
|
||||
* @param[in] packet ntp消息结构体, 存放收到的ntp报文内容
|
||||
* @param[in] userdata 用户上下文
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (* aiot_ntp_recv_handler_t)(void *handle,
|
||||
const aiot_ntp_recv_t *packet, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief ntp内部事件类型
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 收到的ntp应答中字段不合法
|
||||
*/
|
||||
AIOT_NTPEVT_INVALID_RESPONSE,
|
||||
/**
|
||||
* @brief 收到的ntp应答中时间字段格式错误
|
||||
*/
|
||||
AIOT_NTPEVT_INVALID_TIME_FORMAT,
|
||||
} aiot_ntp_event_type_t;
|
||||
|
||||
/**
|
||||
* @brief NTP内部事件
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief NTP内部事件类型. 更多信息请参考@ref aiot_ntp_event_type_t
|
||||
*
|
||||
*/
|
||||
aiot_ntp_event_type_t type;
|
||||
} aiot_ntp_event_t;
|
||||
|
||||
/**
|
||||
* @brief ntp事件回调函数
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 当NTP内部事件被触发时, 调用此函数
|
||||
*
|
||||
*/
|
||||
typedef void (*aiot_ntp_event_handler_t)(void *handle, const aiot_ntp_event_t *event, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief @ref aiot_ntp_setopt 接口的option参数可选值.
|
||||
*
|
||||
* @details 下文每个选项中的数据类型, 指的是@ref aiot_ntp_setopt 中, data参数的数据类型
|
||||
*
|
||||
* 1. data的数据类型是char *时, 以配置@ref AIOT_NTPOPT_MQTT_HANDLE 为例:
|
||||
*
|
||||
* void *mqtt_handle = aiot_mqtt_init();
|
||||
* aiot_ntp_setopt(ntp_handle, AIOT_NTPOPT_MQTT_HANDLE, mqtt_handle);
|
||||
*
|
||||
* 2. data的数据类型是其他数据类型时, 以配置@ref AIOT_NTPOPT_TIME_ZONE 为例:
|
||||
*
|
||||
* int8_t time_zone = 8;
|
||||
* aiot_mqtt_setopt(ntp_handle, AIOT_NTPOPT_TIME_ZONE, (void *)&time_zone);
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief ntp会话 需要的MQTT句柄, 需要先建立MQTT连接, 再设置MQTT句柄
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_NTPOPT_MQTT_HANDLE,
|
||||
|
||||
/**
|
||||
* @brief ntp会话 获取到utc时间后会根据此时区值转换成本地时间, 再通过 @ref aiot_ntp_recv_handler_t 通知
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 取值示例: 东8区, 取值为8; 西3区, 取值为-3
|
||||
*
|
||||
* 数据类型: (int8_t *)
|
||||
*/
|
||||
AIOT_NTPOPT_TIME_ZONE,
|
||||
|
||||
/**
|
||||
* @brief 设置回调, 它在SDK收到网络报文的时候被调用, 告知用户
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: ( @ref aiot_ntp_recv_handler_t )
|
||||
*/
|
||||
AIOT_NTPOPT_RECV_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief ntp内部发生的事件会从此回调函数进行通知
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: ( @ref aiot_ntp_event_handler_t )
|
||||
*/
|
||||
AIOT_NTPOPT_EVENT_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief 用户需要SDK暂存的上下文
|
||||
*
|
||||
* @details 这个上下文指针会在 AIOT_NTPOPT_RECV_HANDLER 和 AIOT_NTPOPT_EVENT_HANDLER 设置的回调被调用时, 由SDK传给用户
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_NTPOPT_USERDATA,
|
||||
|
||||
/**
|
||||
* @brief 销毁ntp实例时, 等待其他api执行完毕的时间
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 当调用@ref aiot_ntp_deinit 销毁NTP实例时, 若继续调用其他aiot_ntp_xxx API, API会返回@ref STATE_USER_INPUT_EXEC_DISABLED 错误
|
||||
*
|
||||
* 此时, 用户应该停止调用其他aiot_ntp_xxx API
|
||||
*
|
||||
* 数据类型: (uint32_t *) 默认值: (2 * 1000) ms
|
||||
*/
|
||||
AIOT_NTPOPT_DEINIT_TIMEOUT_MS,
|
||||
AIOT_NTPOPT_MAX
|
||||
} aiot_ntp_option_t;
|
||||
|
||||
/**
|
||||
* @brief 创建ntp会话实例, 并以默认值配置会话参数
|
||||
*
|
||||
* @return void *
|
||||
* @retval 非NULL ntp实例的句柄
|
||||
* @retval NULL 初始化失败, 一般是内存分配失败导致
|
||||
*
|
||||
*/
|
||||
void *aiot_ntp_init(void);
|
||||
|
||||
/**
|
||||
* @brief 配置ntp会话
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 常见的配置项如下
|
||||
*
|
||||
* + `AIOT_NTPOPT_MQTT_HANDLE`: 已建立连接的MQTT会话句柄
|
||||
*
|
||||
* + `AIOT_NTPOPT_TIME_ZONE`: 时区设置, SDK会将收到的UTC时间按配置的时区进行转换
|
||||
*
|
||||
* + `AIOT_NTPOPT_RECV_HANDLER`: 时间数据接收回调函数, SDK将UTC时间转换完成后, 通过此回调函数输出
|
||||
*
|
||||
* @param[in] handle ntp会话句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_ntp_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_ntp_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 参数配置失败
|
||||
* @retval >=STATE_SUCCESS 参数配置成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_ntp_setopt(void *handle, aiot_ntp_option_t option, void *data);
|
||||
|
||||
/**
|
||||
* @brief 结束ntp会话, 销毁实例并回收资源
|
||||
*
|
||||
* @param[in] handle 指向ntp会话句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 执行失败
|
||||
* @retval >=STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_ntp_deinit(void **handle);
|
||||
|
||||
/**
|
||||
* @brief 向ntp服务器发送ntp消息请求
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 发送NTP请求, 然后SDK会调用通过 @ref aiot_ntp_setopt 配置的 @ref AIOT_NTPOPT_RECV_HANDLER 回调函数, 通知用户当前的时间
|
||||
*
|
||||
* @param handle ntp会话句柄
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 请求发送失败
|
||||
* @retval >=STATE_SUCCESS 请求发送成功
|
||||
*/
|
||||
int32_t aiot_ntp_send_request(void *handle);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AIOT_NTP_API_H__ */
|
||||
|
||||
58
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ntp/ntp_private.h
vendored
Normal file
58
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ntp/ntp_private.h
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file ntp_private.h
|
||||
* @brief ntp模块内部的宏定义和数据结构声明, 不面向其它模块, 更不面向用户
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __NTP_PRIVATE_H__
|
||||
#define __NTP_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 用这种方式包含标准C库的头文件 */
|
||||
#include "core_stdinc.h"
|
||||
|
||||
/* TODO: 这一段列出需要包含SDK其它模块头文件, 与上一段落以1个空行隔开 */
|
||||
#include "aiot_state_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_ntp_api.h" /* 内部头文件是用户可见头文件的超集 */
|
||||
|
||||
/* TODO: 定义ntp模块内部的会话句柄结构体, SDK用户不可见, 只能得到void *handle类型的指针 */
|
||||
typedef struct {
|
||||
aiot_sysdep_portfile_t *sysdep; /* 底层依赖回调合集的引用指针 */
|
||||
void *mqtt_handle;
|
||||
|
||||
int8_t time_zone;
|
||||
uint32_t deinit_timeout_ms;
|
||||
|
||||
aiot_ntp_recv_handler_t recv_handler; /* 组件从协议栈读到内容时, 通知用户的回调 */
|
||||
aiot_ntp_event_handler_t event_handler;
|
||||
void *userdata; /* 组件调用以上2个 ntp_handler 时的入参之一 */
|
||||
|
||||
/*---- 以上都是用户在API可配 ----*/
|
||||
void *data_mutex;
|
||||
|
||||
uint8_t exec_enabled;
|
||||
uint32_t exec_count;
|
||||
|
||||
} ntp_handle_t;
|
||||
|
||||
#define NTP_MODULE_NAME "ntp" /* 用于内存统计的模块名字符串 */
|
||||
|
||||
#define NTP_DEFAULT_DEINIT_TIMEOUT_MS (2 * 1000)
|
||||
#define NTP_DEFAULT_TIME_ZONE (0)
|
||||
|
||||
#define NTP_REQUEST_TOPIC_FMT "/ext/ntp/%s/%s/request"
|
||||
#define NTP_REQUEST_PAYLOAD_FMT "{\"deviceSendTime\":\"%s\"}"
|
||||
#define NTP_RESPONSE_TOPIC_FMT "/ext/ntp/%s/%s/response"
|
||||
|
||||
#define NTP_DEINIT_INTERVAL_MS (100)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* __NTP_PRIVATE_H__ */
|
||||
|
||||
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/README.md
vendored
Normal file
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/README.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Name: 固件升级模块
|
||||
OTA Component for Link SDK V4.0.0
|
||||
|
||||
650
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/aiot_mqtt_download_api.c
vendored
Normal file
650
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/aiot_mqtt_download_api.c
vendored
Normal file
@@ -0,0 +1,650 @@
|
||||
/**
|
||||
* @file aiot_mqtt_download_api.c
|
||||
* @brief mqtt文件下载的实现文件
|
||||
* @date 2019-12-27
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
#include "aiot_ota_api.h"
|
||||
#include "core_mqtt.h"
|
||||
#include "core_string.h"
|
||||
#include "core_sha256.h"
|
||||
#include "ota_md5.h"
|
||||
#include "core_log.h"
|
||||
#include "core_global.h"
|
||||
#include "mqtt_download_private.h"
|
||||
#include "aiot_mqtt_download_api.h"
|
||||
#include "ota_private.h"
|
||||
#include "core_string.h"
|
||||
|
||||
static int32_t _md_send_request(void *handle);
|
||||
static void _md_recv_data_reply_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
|
||||
/*
|
||||
* CRC lookup table for bytes, generating polynomial is 0x8005
|
||||
* input: reflexed (LSB first)
|
||||
* output: reflexed also...
|
||||
*/
|
||||
|
||||
const uint16_t crc_ibm_table[256] = {
|
||||
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
|
||||
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
|
||||
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
|
||||
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
|
||||
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
|
||||
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
|
||||
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
|
||||
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
|
||||
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
|
||||
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
|
||||
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
|
||||
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
|
||||
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
|
||||
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
|
||||
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
|
||||
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
|
||||
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
|
||||
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
|
||||
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
|
||||
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
|
||||
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
|
||||
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
|
||||
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
|
||||
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
|
||||
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
|
||||
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
|
||||
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
|
||||
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
|
||||
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
|
||||
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
|
||||
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
|
||||
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
|
||||
};
|
||||
|
||||
uint16_t crc_ibm(uint8_t const *buffer, size_t len)
|
||||
{
|
||||
uint16_t crc = 0x0000;
|
||||
uint8_t lut;
|
||||
|
||||
while (len--) {
|
||||
lut = (crc ^ (*buffer++)) & 0xFF;
|
||||
crc = (crc >> 8) ^ crc_ibm_table[lut];
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int32_t _md_sub_response_topic(void *handle)
|
||||
{
|
||||
char topic[128];
|
||||
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
|
||||
if(handle == NULL) {
|
||||
return STATE_DOWNLOAD_DEINIT_HANDLE_IS_NULL;
|
||||
}
|
||||
memset(topic, 0, sizeof(topic));
|
||||
snprintf(topic, sizeof(topic) - 1, MQTT_DOWNLOAD_RESPONSE_TOPIC,
|
||||
core_mqtt_get_product_key(md_handle->task_desc->mqtt_handle), core_mqtt_get_device_name(md_handle->task_desc->mqtt_handle));
|
||||
|
||||
return aiot_mqtt_sub(md_handle->task_desc->mqtt_handle, topic, _md_recv_data_reply_handler, 0, handle);
|
||||
}
|
||||
|
||||
int32_t _md_unsub_response_topic(void *handle)
|
||||
{
|
||||
char topic[128];
|
||||
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
|
||||
if(handle == NULL) {
|
||||
return STATE_DOWNLOAD_DEINIT_HANDLE_IS_NULL;
|
||||
}
|
||||
memset(topic, 0, sizeof(topic));
|
||||
snprintf(topic, sizeof(topic) - 1, MQTT_DOWNLOAD_RESPONSE_TOPIC,
|
||||
core_mqtt_get_product_key(md_handle->task_desc->mqtt_handle), core_mqtt_get_device_name(md_handle->task_desc->mqtt_handle));
|
||||
|
||||
return aiot_mqtt_unsub(md_handle->task_desc->mqtt_handle, topic);
|
||||
}
|
||||
|
||||
void *aiot_mqtt_download_init(void)
|
||||
{
|
||||
mqtt_download_handle_t *md_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if (sysdep == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
md_handle = sysdep->core_sysdep_malloc(sizeof(mqtt_download_handle_t), MQTT_DOWNLOAD_MODULE_NAME);
|
||||
if (md_handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(md_handle, 0, sizeof(mqtt_download_handle_t));
|
||||
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_INIT;
|
||||
md_handle->sysdep = sysdep;
|
||||
md_handle->request_size = MQTT_DOWNLOAD_DEFAULT_REQUEST_SIZE;
|
||||
md_handle->last_request_time = 0;
|
||||
md_handle->data_mutex = sysdep->core_sysdep_mutex_init();
|
||||
md_handle->recv_mutex = sysdep->core_sysdep_mutex_init();
|
||||
|
||||
return md_handle;
|
||||
}
|
||||
|
||||
static void _md_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
|
||||
{
|
||||
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)context;
|
||||
|
||||
if (core_event != NULL) {
|
||||
switch (core_event->type) {
|
||||
case CORE_MQTTEVT_DEINIT: {
|
||||
md_handle->task_desc->mqtt_handle = NULL;
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t aiot_mqtt_download_deinit(void **handle)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
if (NULL == handle || NULL == *handle) {
|
||||
return STATE_DOWNLOAD_DEINIT_HANDLE_IS_NULL;
|
||||
}
|
||||
mqtt_download_handle_t *md_handle = *(mqtt_download_handle_t **)handle;
|
||||
|
||||
if (NULL != md_handle->task_desc) {
|
||||
if (AIOT_OTA_DIGEST_MD5 == md_handle->task_desc->digest_method) {
|
||||
if (NULL != md_handle->digest_ctx) {
|
||||
utils_md5_free(md_handle->digest_ctx);
|
||||
md_handle->sysdep->core_sysdep_free(md_handle->digest_ctx);
|
||||
md_handle->digest_ctx = NULL;
|
||||
}
|
||||
}
|
||||
if(md_handle->task_desc->mqtt_handle != NULL) {
|
||||
core_mqtt_process_data_t process_data;
|
||||
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
|
||||
process_data.handler = _md_core_mqtt_process_handler;
|
||||
process_data.context = handle;
|
||||
core_mqtt_setopt(md_handle->task_desc->mqtt_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER, &process_data);
|
||||
_md_unsub_response_topic(md_handle);
|
||||
}
|
||||
_download_deep_free_task_desc(md_handle->sysdep, md_handle->task_desc);
|
||||
md_handle->sysdep->core_sysdep_free(md_handle->task_desc);
|
||||
md_handle->task_desc = NULL;
|
||||
}
|
||||
|
||||
md_handle->sysdep->core_sysdep_mutex_deinit(&md_handle->data_mutex);
|
||||
md_handle->sysdep->core_sysdep_mutex_deinit(&md_handle->recv_mutex);
|
||||
|
||||
md_handle->sysdep->core_sysdep_free(md_handle);
|
||||
*handle = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* 根据下载到的固件的内容, 计算其digest值 */
|
||||
static int32_t _download_digest_update(mqtt_download_handle_t *download_handle, uint8_t *buffer, uint32_t buffer_len)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
if (AIOT_OTA_DIGEST_SHA256 == download_handle->task_desc->digest_method) {
|
||||
core_sha256_update(download_handle->digest_ctx, buffer, buffer_len);
|
||||
} else if (AIOT_OTA_DIGEST_MD5 == download_handle->task_desc->digest_method) {
|
||||
res = utils_md5_update(download_handle->digest_ctx, buffer, buffer_len);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* 对计算出来的digest值, 与云端下发的digest值进行比较 */
|
||||
static int32_t _download_digest_verify(mqtt_download_handle_t *download_handle)
|
||||
{
|
||||
uint8_t output[32] = {0};
|
||||
uint8_t expected_digest[32] = {0};
|
||||
|
||||
if (AIOT_OTA_DIGEST_SHA256 == download_handle->task_desc->digest_method) {
|
||||
core_str2hex(download_handle->task_desc->expect_digest, OTA_SHA256_LEN, expected_digest);
|
||||
core_sha256_finish(download_handle->digest_ctx, output);
|
||||
if (memcmp(output, expected_digest, 32) == 0) {
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
} else if (AIOT_OTA_DIGEST_MD5 == download_handle->task_desc->digest_method) {
|
||||
core_str2hex(download_handle->task_desc->expect_digest, OTA_MD5_LEN, expected_digest);
|
||||
utils_md5_finish(download_handle->digest_ctx, output);
|
||||
if (memcmp(output, expected_digest, 16) == 0) {
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
}
|
||||
return STATE_OTA_DIGEST_MISMATCH;
|
||||
}
|
||||
|
||||
static int32_t _download_report_progress(void *handle, int32_t percent)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
mqtt_download_handle_t *md_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
char out_buffer[4] = {0};
|
||||
uint8_t out_len;
|
||||
char *payload_string;
|
||||
|
||||
if (NULL == handle) {
|
||||
return STATE_MQTT_DOWNLOAD_MQTT_HANDLE_NULL;
|
||||
}
|
||||
|
||||
md_handle = (mqtt_download_handle_t *)handle;
|
||||
sysdep = md_handle->sysdep;
|
||||
|
||||
if (NULL == md_handle->task_desc) {
|
||||
return STATE_MQTT_DOWNLOAD_TASK_DEINIT;
|
||||
}
|
||||
|
||||
core_int2str(percent, out_buffer, &out_len);
|
||||
|
||||
if (md_handle->task_desc->module) {
|
||||
char *src[] = {"{\"step\":\"", out_buffer, "\",\"desc\":\"\",\"module\":\"", md_handle->task_desc->module, "\"}"};
|
||||
uint8_t topic_len = sizeof(src) / sizeof(char *);
|
||||
core_sprintf(sysdep, &payload_string, "%s%s%s%s%s", src, topic_len, OTA_MODULE_NAME);
|
||||
} else {
|
||||
char *src[] = {"{\"step\":\"", out_buffer, "\",\"desc\":\"\"}"};
|
||||
uint8_t topic_len = sizeof(src) / sizeof(char *);
|
||||
core_sprintf(sysdep, &payload_string, "%s%s%s", src, topic_len, OTA_MODULE_NAME);
|
||||
}
|
||||
|
||||
res = _ota_publish_base(md_handle->task_desc->mqtt_handle, OTA_PROGRESS_TOPIC_PREFIX,
|
||||
md_handle->task_desc->product_key,
|
||||
md_handle->task_desc->device_name, NULL, payload_string);
|
||||
sysdep->core_sysdep_free(payload_string);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t _parse_json_header(void *handle, char *data, uint32_t data_len, aiot_mqtt_download_recv_t *pakcet)
|
||||
{
|
||||
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
|
||||
char *header = data, *file_info = NULL, *value = NULL;
|
||||
uint32_t header_len = data_len, file_info_len = 0, value_len = 0;
|
||||
uint32_t code = 0;
|
||||
uint32_t size = 0, offset = 0, fileLenth = 0;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if ((res = core_json_value((char *)header, header_len, "code", strlen("code"),
|
||||
&value, &value_len)) < 0 ||
|
||||
((res = core_str2uint(value, value_len, &code)) < 0) ||
|
||||
code != 200 ) {
|
||||
core_log1(md_handle->sysdep, 0, "recv handle parse err code %d\r\n", &code);
|
||||
return res;
|
||||
}
|
||||
|
||||
if ((res = core_json_value((char *)header, header_len, "data", strlen("data"),
|
||||
&value, &value_len)) < 0 ) {
|
||||
core_log(md_handle->sysdep, 0, "json parse error data\r\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
/* 解析文件的描述信息 */
|
||||
file_info = value;
|
||||
file_info_len = value_len;
|
||||
if ((res = core_json_value((char *)file_info, file_info_len, "bSize", strlen("bSize"),
|
||||
&value, &value_len)) < 0 ||
|
||||
((res = core_str2uint(value, value_len, &size)) < 0)) {
|
||||
core_log(md_handle->sysdep, 0, "json parse error bSize\r\n");
|
||||
return res;
|
||||
}
|
||||
if ((res = core_json_value((char *)file_info, file_info_len, "bOffset", strlen("bOffset"),
|
||||
&value, &value_len)) < 0 ||
|
||||
((res = core_str2uint(value, value_len, &offset)) < 0)) {
|
||||
core_log(md_handle->sysdep, 0, "json parse error bOffset\r\n");
|
||||
return res;
|
||||
}
|
||||
if ((res = core_json_value((char *)file_info, file_info_len, "fileLength", strlen("fileLength"),
|
||||
&value, &value_len)) < 0 ||
|
||||
((res = core_str2uint(value, value_len, &fileLenth)) < 0)) {
|
||||
core_log(md_handle->sysdep, 0, "json parse error bOffset\r\n");
|
||||
return res;
|
||||
}
|
||||
if ((res = core_json_value((char *)file_info, file_info_len, "fileToken", strlen("fileToken"),
|
||||
&value, &value_len)) == 0 ) {
|
||||
memcpy(pakcet->data.data_resp.filename, value, value_len);
|
||||
}
|
||||
|
||||
pakcet->data.data_resp.data_size = size;
|
||||
pakcet->data.data_resp.offset = offset;
|
||||
pakcet->data.data_resp.file_lenth = fileLenth;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _md_resend_request(mqtt_download_handle_t *md_handle)
|
||||
{
|
||||
md_handle->failed_counter++;
|
||||
if(md_handle->failed_counter > 3) {
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_FAILED_TIMEOUT;
|
||||
return;
|
||||
}
|
||||
|
||||
_md_send_request(md_handle);
|
||||
}
|
||||
|
||||
static void _md_recv_data_reply_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)userdata;
|
||||
/*有效文件数据*/
|
||||
uint8_t *data = NULL;
|
||||
uint32_t data_len = 0;
|
||||
/*json头解析变量定义*/
|
||||
char *header = NULL;
|
||||
uint16_t header_len = 0;
|
||||
char file_token[MQTT_DOWNLOAD_TOKEN_MAXLEN];
|
||||
uint16_t crc16 = 0, cal_crc16 = 0;
|
||||
aiot_mqtt_download_recv_t packet;
|
||||
memset(file_token, 0, sizeof(file_token));
|
||||
packet.type = AIOT_MDRECV_DATA_RESP;
|
||||
packet.data.data_resp.filename = file_token;
|
||||
|
||||
if(md_handle == NULL || md_handle->status != STATE_MQTT_DOWNLOAD_ING) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*获取并解析json头*/
|
||||
header = (char *)(msg->data.pub.payload + 2);
|
||||
header_len = *msg->data.pub.payload << 8 | *(msg->data.pub.payload + 1);
|
||||
if(_parse_json_header(md_handle, header, header_len, &packet) < 0) {
|
||||
_md_resend_request(md_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 校验数据长度 */
|
||||
if(msg->data.pub.payload_len != sizeof(header_len) + header_len + packet.data.data_resp.data_size + sizeof(crc16)) {
|
||||
core_log(md_handle->sysdep, 0, "payload lenth dismatch data lenth\r\n");
|
||||
_md_resend_request(md_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 有效的文件数据 */
|
||||
data = msg->data.pub.payload + sizeof(header_len) + header_len;
|
||||
data_len = packet.data.data_resp.data_size;
|
||||
|
||||
/* CRC校验 */
|
||||
crc16 = *(uint16_t *)(msg->data.pub.payload + msg->data.pub.payload_len - sizeof(crc16));
|
||||
cal_crc16 = crc_ibm(data, data_len);
|
||||
if(cal_crc16 != crc16) {
|
||||
_md_resend_request(md_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 判断接收的数据偏移是否为请求的偏移,可能存在重复请求,这里校验失败,不主动重发请求,等超时 */
|
||||
if(packet.data.data_resp.offset != md_handle->size_fetched + md_handle->range_start) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 生成回调packet包回调用户接口 */
|
||||
md_handle->size_fetched += data_len;
|
||||
packet.data.data_resp.data = (char *)data;
|
||||
packet.data.data_resp.percent = md_handle->size_fetched * 100 / md_handle->range_size;
|
||||
|
||||
/* 计算digest, 如果下载完成, 还要看看是否与云端计算出来的一致 */
|
||||
if(md_handle->md5_enabled) {
|
||||
_download_digest_update(md_handle, (uint8_t *)packet.data.data_resp.data, packet.data.data_resp.data_size);
|
||||
}
|
||||
|
||||
/* 数据接收成功,失败统计复位 */
|
||||
md_handle->failed_counter = 0;
|
||||
|
||||
/* 回调用户接口, 通知存储数据 */
|
||||
if(md_handle->recv_handler != NULL) {
|
||||
md_handle->recv_handler(md_handle, &packet, md_handle->userdata);
|
||||
}
|
||||
|
||||
if(md_handle->size_fetched < md_handle->range_size) {
|
||||
/*请求下一包*/
|
||||
_md_send_request(md_handle);
|
||||
} else if(md_handle->size_fetched == md_handle->range_size) {
|
||||
/*下载完成, 如果有md5还需要做整个文件的校验*/
|
||||
md_handle->percent = 100;
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_FINISHED;
|
||||
} else {
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_FAILED_RECVERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t aiot_mqtt_download_setopt(void *handle, aiot_mqtt_download_option_t option, void *data) {
|
||||
int32_t res = STATE_SUCCESS;
|
||||
if (NULL == handle) {
|
||||
return STATE_DOWNLOAD_DEINIT_HANDLE_IS_NULL;
|
||||
}
|
||||
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
|
||||
|
||||
md_handle->sysdep->core_sysdep_mutex_lock(md_handle->data_mutex);
|
||||
switch (option) {
|
||||
case AIOT_MDOPT_USERDATA: {
|
||||
md_handle->userdata = data;
|
||||
}
|
||||
break;
|
||||
case AIOT_MDOPT_TASK_DESC: {
|
||||
void *new_task_desc = _download_deep_copy_task_desc(md_handle->sysdep, data);
|
||||
if (NULL == new_task_desc) {
|
||||
res = STATE_DOWNLOAD_SETOPT_COPIED_DATA_IS_NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
md_handle->task_desc = (aiot_download_task_desc_t *)new_task_desc;
|
||||
core_mqtt_process_data_t process_data;
|
||||
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
|
||||
process_data.handler = _md_core_mqtt_process_handler;
|
||||
process_data.context = handle;
|
||||
|
||||
core_mqtt_setopt(md_handle->task_desc->mqtt_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER, &process_data);
|
||||
}
|
||||
break;
|
||||
case AIOT_MDOPT_RANGE_START: {
|
||||
md_handle->range_start = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_MDOPT_RANGE_END: {
|
||||
md_handle->range_end = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_MDOPT_RECV_HANDLE: {
|
||||
md_handle->recv_handler = (aiot_mqtt_download_recv_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_MDOPT_DATA_REQUEST_SIZE: {
|
||||
md_handle->request_size = *(uint32_t *)data;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
res = STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
md_handle->sysdep->core_sysdep_mutex_unlock(md_handle->data_mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t _md_send_request(void *handle)
|
||||
{
|
||||
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
|
||||
|
||||
char *payload_fmt = "{\"id\":\"%s\",\"version\":\"1.0\",\"params\":%s}";
|
||||
char *params_fmt = "{\"fileToken\":\"%s\",\"fileInfo\":{\"streamId\":%s,\"fileId\":%s,},\"fileBlock\":{\"size\":%s,\"offset\":%s}}";
|
||||
char *params = NULL, *payload = NULL, *topic = NULL;
|
||||
char stream_id_string[21], file_id_string[21], request_size_string[21], offset_string[21];
|
||||
char *params_src[] = {"default", stream_id_string, file_id_string, request_size_string, offset_string };
|
||||
char id_string[21];
|
||||
char *payload_src[2] = { id_string };
|
||||
char *topic_src[2] = { id_string };
|
||||
uint32_t res = STATE_SUCCESS;
|
||||
uint32_t offset = md_handle->size_fetched + md_handle->range_start;
|
||||
/* 生成params */
|
||||
int32_t size = md_handle->request_size;
|
||||
if(md_handle->request_size + md_handle->size_fetched > md_handle->range_size)
|
||||
{
|
||||
size = md_handle->range_size - md_handle->size_fetched;
|
||||
}
|
||||
memset(stream_id_string, 0, sizeof(stream_id_string));
|
||||
core_uint2str(md_handle->task_desc->stream_id, stream_id_string, NULL);
|
||||
|
||||
memset(file_id_string, 0, sizeof(file_id_string));
|
||||
core_uint2str(md_handle->task_desc->stream_file_id, file_id_string, NULL);
|
||||
|
||||
memset(request_size_string, 0, sizeof(request_size_string));
|
||||
core_uint2str(size, request_size_string, NULL);
|
||||
|
||||
memset(offset_string, 0, sizeof(offset_string));
|
||||
core_uint2str(offset, offset_string, NULL);
|
||||
|
||||
core_sprintf(md_handle->sysdep, ¶ms, params_fmt, params_src, sizeof(params_src) / sizeof(char *),
|
||||
MQTT_DOWNLOAD_MODULE_NAME);
|
||||
|
||||
/*生成payload */
|
||||
md_handle->msg_id++;
|
||||
memset(id_string, 0, sizeof(id_string));
|
||||
core_uint2str(md_handle->msg_id, id_string, NULL);
|
||||
payload_src[1] = params;
|
||||
core_sprintf(md_handle->sysdep, &payload, payload_fmt, payload_src, sizeof(payload_src) / sizeof(char *),
|
||||
MQTT_DOWNLOAD_MODULE_NAME);
|
||||
|
||||
topic_src[0] = core_mqtt_get_product_key(md_handle->task_desc->mqtt_handle);
|
||||
topic_src[1] = core_mqtt_get_device_name(md_handle->task_desc->mqtt_handle);
|
||||
core_sprintf(md_handle->sysdep, &topic, MQTT_DOWNLOAD_REQUEST_TOPIC, topic_src, sizeof(topic_src) / sizeof(char *),
|
||||
MQTT_DOWNLOAD_MODULE_NAME);
|
||||
|
||||
if( payload != NULL && topic != NULL) {
|
||||
res = aiot_mqtt_pub(md_handle->task_desc->mqtt_handle, topic, (uint8_t *)payload, strlen(payload), 0);
|
||||
}
|
||||
md_handle->last_request_time = md_handle->sysdep->core_sysdep_time();
|
||||
|
||||
if(topic != NULL) {
|
||||
md_handle->sysdep->core_sysdep_free(topic);
|
||||
}
|
||||
if(payload != NULL) {
|
||||
md_handle->sysdep->core_sysdep_free(payload);
|
||||
}
|
||||
if(params != NULL) {
|
||||
md_handle->sysdep->core_sysdep_free(params);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
static int32_t _md_reset_handle(mqtt_download_handle_t *md_handle)
|
||||
{
|
||||
if(md_handle == NULL) {
|
||||
return STATE_MQTT_DOWNLOAD_MQTT_HANDLE_NULL;
|
||||
}
|
||||
|
||||
md_handle->msg_id = 0;
|
||||
md_handle->size_fetched = 0;
|
||||
md_handle->percent = 0;
|
||||
md_handle->last_request_time = 0;
|
||||
md_handle->failed_counter = 0;
|
||||
md_handle->last_percent = 0;
|
||||
md_handle->range_size = 0;
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
int32_t aiot_mqtt_download_process(void *handle)
|
||||
{
|
||||
uint64_t now;
|
||||
mqtt_download_handle_t *md_handle = (mqtt_download_handle_t *)handle;
|
||||
int32_t percent = 0;
|
||||
int32_t res = 0;
|
||||
if(md_handle == NULL) {
|
||||
return STATE_MQTT_DOWNLOAD_MQTT_HANDLE_NULL;
|
||||
}
|
||||
|
||||
if(md_handle->task_desc == NULL || md_handle->task_desc->mqtt_handle == NULL) {
|
||||
return STATE_MQTT_DOWNLOAD_TASK_DEINIT;
|
||||
}
|
||||
|
||||
res = md_handle->status;
|
||||
switch(md_handle->status) {
|
||||
case STATE_MQTT_DOWNLOAD_INIT: {
|
||||
/* 没有设置片段下载结尾,设置下载至文件结尾 */
|
||||
if(md_handle->range_end == 0) {
|
||||
md_handle->range_end = md_handle->task_desc->size_total;
|
||||
}
|
||||
|
||||
md_handle->range_size = md_handle->range_end - md_handle->range_start;
|
||||
if(md_handle->range_size <= 0) {
|
||||
return STATE_MQTT_DOWNLOAD_FILESIZE_ERROR;
|
||||
}
|
||||
|
||||
/* 订阅数据返回的topic */
|
||||
_md_sub_response_topic(md_handle);
|
||||
/* 完整的文件下载做md5校验 */
|
||||
if(md_handle->range_size == md_handle->task_desc->size_total
|
||||
&& AIOT_OTA_DIGEST_MD5 == md_handle->task_desc->digest_method
|
||||
&& NULL != md_handle->task_desc->expect_digest) {
|
||||
utils_md5_context_t *ctx = md_handle->sysdep->core_sysdep_malloc(sizeof(utils_md5_context_t), MQTT_DOWNLOAD_MODULE_NAME);
|
||||
if (NULL == ctx) {
|
||||
res = STATE_DOWNLOAD_SETOPT_MALLOC_MD5_CTX_FAILED;
|
||||
break;
|
||||
}
|
||||
md_handle->md5_enabled = 1;
|
||||
utils_md5_init(ctx);
|
||||
utils_md5_starts(ctx);
|
||||
md_handle->digest_ctx = (void *) ctx;
|
||||
}
|
||||
|
||||
_md_send_request(handle);
|
||||
md_handle->last_request_time = md_handle->sysdep->core_sysdep_time();
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_ING;
|
||||
res = STATE_MQTT_DOWNLOAD_ING;
|
||||
}
|
||||
break;
|
||||
case STATE_MQTT_DOWNLOAD_ING: {
|
||||
now = md_handle->sysdep->core_sysdep_time();
|
||||
if(now - md_handle->last_request_time > MQTT_DOWNLOAD_DEFAULT_RECV_TIMEOUT) {
|
||||
_md_resend_request(md_handle);
|
||||
}
|
||||
|
||||
percent = md_handle->size_fetched * 100 / md_handle->range_size;
|
||||
if(percent - md_handle->last_percent >= MQTT_DOWNLOAD_REPORT_INTERNEL) {
|
||||
md_handle->last_percent = percent;
|
||||
_download_report_progress(md_handle, percent);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_MQTT_DOWNLOAD_FINISHED: {
|
||||
if(md_handle->md5_enabled) {
|
||||
int32_t ret = _download_digest_verify(md_handle);
|
||||
if (ret != STATE_SUCCESS) {
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_FAILED_MISMATCH;
|
||||
core_log(md_handle->sysdep, ret, "digest mismatch\r\n");
|
||||
} else {
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_SUCCESS;
|
||||
core_log(md_handle->sysdep, STATE_OTA_DIGEST_MATCH, "digest matched\r\n");
|
||||
}
|
||||
if (NULL != md_handle->digest_ctx) {
|
||||
utils_md5_free(md_handle->digest_ctx);
|
||||
md_handle->sysdep->core_sysdep_free(md_handle->digest_ctx);
|
||||
md_handle->digest_ctx = NULL;
|
||||
}
|
||||
} else {
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_SUCCESS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_MQTT_DOWNLOAD_SUCCESS: {
|
||||
_download_report_progress(md_handle, 100);
|
||||
_md_reset_handle(md_handle);
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_INIT;
|
||||
}
|
||||
break;
|
||||
case STATE_MQTT_DOWNLOAD_FAILED_MISMATCH: {
|
||||
_download_report_progress(md_handle, AIOT_OTAERR_CHECKSUM_MISMATCH);
|
||||
_md_reset_handle(md_handle);
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_INIT;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_MQTT_DOWNLOAD_FAILED_RECVERROR:
|
||||
case STATE_MQTT_DOWNLOAD_FAILED_TIMEOUT: {
|
||||
_download_report_progress(md_handle, AIOT_OTAERR_BURN_FAILED);
|
||||
_md_reset_handle(md_handle);
|
||||
md_handle->status = STATE_MQTT_DOWNLOAD_INIT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
289
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/aiot_mqtt_download_api.h
vendored
Normal file
289
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/aiot_mqtt_download_api.h
vendored
Normal file
@@ -0,0 +1,289 @@
|
||||
/**
|
||||
* @file aiot_mqtt_download_api.h
|
||||
* @brief mqtt_download模块头文件, 提供mqtt文件传输的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __AIOT_MQTT_DOWNLOAD_API_H__
|
||||
#define __AIOT_MQTT_DOWNLOAD_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief -0x1D00~-0x1DFF表达SDK在mqtt_download模块内的状态码
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_BASE (-0x1D00)
|
||||
|
||||
/**
|
||||
* @brief mqtt_download_handle为空
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_MQTT_HANDLE_NULL (-0x1D01)
|
||||
|
||||
/**
|
||||
* @brief 任务未初始化
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_TASK_DEINIT (-0x1D02)
|
||||
|
||||
/**
|
||||
* @brief 初始化完,第一次执行请求
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_INIT (-0x1D03)
|
||||
|
||||
/**
|
||||
* @brief 正在下载文件
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_ING (-0x1D04)
|
||||
|
||||
/**
|
||||
* @brief 文件已经下载完,但未校验
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_FINISHED (-0x1D05)
|
||||
|
||||
/**
|
||||
* @brief 文件下载完成,并且校验通过
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_SUCCESS (-0x1D06)
|
||||
|
||||
/**
|
||||
* @brief 文件下载接收失败,重试几个后还是失败,认定为超时
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_FAILED_TIMEOUT (-0x1D07)
|
||||
|
||||
/**
|
||||
* @brief 完整文件下载时,MD5校验失败
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_FAILED_MISMATCH (-0x1D08)
|
||||
|
||||
/**
|
||||
* @brief 接收长度校验错误
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_FAILED_RECVERROR (-0x1D09)
|
||||
|
||||
/**
|
||||
* @brief 用户主动取消下载任务
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_ABORT (-0x1D0A)
|
||||
|
||||
/**
|
||||
* @brief 设置的下载长度为空
|
||||
*/
|
||||
#define STATE_MQTT_DOWNLOAD_FILESIZE_ERROR (-0x1D0B)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief mqtt_download模块收到从网络上来的报文时, 通知用户的报文类型
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 文件分片下载请求的返回报文
|
||||
*/
|
||||
AIOT_MDRECV_DATA_RESP,
|
||||
} aiot_mqtt_download_recv_type_t;
|
||||
|
||||
/**
|
||||
* @brief mqtt_download模块收到从网络上来的报文时, 通知用户的报文内容
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 报文内容所对应的报文类型, 更多信息请参考@ref aiot_mqtt_download_recv_type_t
|
||||
*/
|
||||
aiot_mqtt_download_recv_type_t type;
|
||||
union {
|
||||
/**
|
||||
* @brief data_resp_type的说明
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* @brief 用户标准的文件名称,一般为设置的文件名
|
||||
*/
|
||||
char *filename;
|
||||
/**
|
||||
* @brief 文件的偏移
|
||||
*/
|
||||
uint32_t offset;
|
||||
/**
|
||||
* @brief 接收到的数据长度
|
||||
*/
|
||||
uint32_t data_size;
|
||||
/**
|
||||
* @brief 接收到的数据
|
||||
*/
|
||||
char *data;
|
||||
/**
|
||||
* @brief 接收到的数据
|
||||
*/
|
||||
int32_t percent;
|
||||
/**
|
||||
* @brief 文件的总大小
|
||||
*/
|
||||
int32_t file_lenth;
|
||||
} data_resp;
|
||||
} data;
|
||||
} aiot_mqtt_download_recv_t;
|
||||
|
||||
/**
|
||||
* @brief mqtt_download模块收到从网络上来的报文时, 通知用户所调用的数据回调函数
|
||||
*
|
||||
* @param[in] handle mqtt_download会话句柄
|
||||
* @param[in] packet mqtt_download消息结构体, 存放收到的mqtt_download报文内容
|
||||
* @param[in] userdata 用户上下文
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (* aiot_mqtt_download_recv_handler_t)(void *handle,
|
||||
const aiot_mqtt_download_recv_t *packet, void *userdata);
|
||||
|
||||
|
||||
/**
|
||||
* @brief @ref aiot_mqtt_download_setopt 接口的option参数可选值.
|
||||
*
|
||||
* @details 下文每个选项中的数据类型, 指的是@ref aiot_mqtt_download_setopt 中, data参数的数据类型
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 设置处理OTA消息的用户回调函数
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (aiot_mqtt_download_recv_handler_t)
|
||||
*/
|
||||
AIOT_MDOPT_RECV_HANDLE,
|
||||
|
||||
/**
|
||||
* @brief 设置MQTT的handle
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 文件下载过程中使用MQTT的通道能力, 用以请求数据及接收数据
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_MDOPT_MQTT_HANDLE,
|
||||
|
||||
/**
|
||||
* @brief 用户需要SDK暂存的上下文
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 该上下文会在@ref AIOT_OTAOPT_RECV_HANDLER 中传回给用户
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_MDOPT_USERDATA,
|
||||
/**
|
||||
* @brief 设置download实例句柄所包含下载任务的具体内容
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 用户在收到OTA的mqtt消息后, 如果决定升级, 则需要通过该选项, 在download实例句柄中开辟内存,
|
||||
* 将OTA消息中携带的url, version, digest method, sign等信息复制过来, 有了这些信息后才能开始下载任务
|
||||
*
|
||||
* 数据类型: (aiot_download_task_desc_t *)
|
||||
*
|
||||
**/
|
||||
AIOT_MDOPT_TASK_DESC,
|
||||
|
||||
/**
|
||||
* @brief 设置按照range下载的起始地址
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* MQTT 范围请求(range requests)特性中, 表示从第该byte开始下载
|
||||
* 如果指定从头开始下载, 则start的值为0
|
||||
*
|
||||
* 数据类型: (uint32_t *)
|
||||
*
|
||||
**/
|
||||
AIOT_MDOPT_RANGE_START,
|
||||
/**
|
||||
* @brief 设置按照range下载的结束地址
|
||||
*
|
||||
* @details
|
||||
* MQTT 范围请求(range requests)特性中, 表示下载到该byte后结束.
|
||||
* 如果指定从头开始下载到10个byte后结束,
|
||||
* 则需要指定start = 0, end = 9, 这样总共10个byte
|
||||
*
|
||||
* 数据类型: (uint32_t *)
|
||||
*
|
||||
**/
|
||||
AIOT_MDOPT_RANGE_END,
|
||||
|
||||
/**
|
||||
* @brief 单次请求数据的最大长度
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (uint32_t *) 默认值: (2 *1024) Bytes
|
||||
*/
|
||||
AIOT_MDOPT_DATA_REQUEST_SIZE,
|
||||
|
||||
AIOT_MDOPT_MAX,
|
||||
} aiot_mqtt_download_option_t;
|
||||
|
||||
/**
|
||||
* @brief 创建mqtt_download会话实例, 并以默认值配置会话参数
|
||||
*
|
||||
* @return void *
|
||||
* @retval 非NULL mqtt_download实例的句柄
|
||||
* @retval NULL 初始化失败, 一般是内存分配失败导致
|
||||
*
|
||||
*/
|
||||
void *aiot_mqtt_download_init(void);
|
||||
|
||||
/**
|
||||
* @brief 配置mqtt_download会话
|
||||
*
|
||||
* @param[in] handle mqtt_download会话句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_mqtt_download_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_mqtt_download_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 参数配置失败
|
||||
* @retval >=STATE_SUCCESS 参数配置成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_mqtt_download_setopt(void *handle, aiot_mqtt_download_option_t option, void *data);
|
||||
|
||||
/**
|
||||
* @brief 结束mqtt_download会话, 销毁实例并回收资源
|
||||
*
|
||||
* @param[in] handle 指向mqtt_download会话句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval <STATE_SUCCESS 执行失败
|
||||
* @retval >=STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_mqtt_download_deinit(void **handle);
|
||||
|
||||
/**
|
||||
* @brief 处理下载逻辑
|
||||
*
|
||||
* @param handle mqtt_download会话句柄
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_MQTT_DOWNLOAD_INIT 初始化完成
|
||||
* @retval STATE_MQTT_DOWNLOAD_ING 正在下载
|
||||
* @retval STATE_MQTT_DOWNLOAD_SUCCESS 下载完成
|
||||
* @retval STATE_MQTT_DOWNLOAD_FAILED_RECVERROR 数据接收错误
|
||||
* @retval STATE_MQTT_DOWNLOAD_FAILED_TIMEOUT 接收超时
|
||||
* @retval STATE_MQTT_DOWNLOAD_FAILED_MISMATCH 校验错误
|
||||
* @retval STATE_MQTT_DOWNLOAD_MQTT_HANDLE_NULL handle没有初始化
|
||||
* @retval STATE_MQTT_DOWNLOAD_TASK_DEINIT 没有设置task
|
||||
*/
|
||||
int32_t aiot_mqtt_download_process(void *handle);
|
||||
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AIOT_MQTT_DOWNLOAD_API_H__ */
|
||||
|
||||
1373
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/aiot_ota_api.c
vendored
Normal file
1373
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/aiot_ota_api.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1000
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/aiot_ota_api.h
vendored
Normal file
1000
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/aiot_ota_api.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
68
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/mqtt_download_private.h
vendored
Normal file
68
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/mqtt_download_private.h
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @file mqtt_download_private.h
|
||||
* @brief mqtt_download模块内部的宏定义和数据结构声明, 不面向其它模块, 更不面向用户
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __MQTT_DOWNLOAD_PRIVATE_H__
|
||||
#define __MQTT_DOWNLOAD_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_stdinc.h"
|
||||
#include "aiot_state_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_ota_api.h"
|
||||
#include "aiot_mqtt_download_api.h" /* 内部头文件是用户可见头文件的超集 */
|
||||
|
||||
/* 定义mqtt_download模块内部的会话句柄结构体, SDK用户不可见, 只能得到void *handle类型的指针 */
|
||||
typedef struct {
|
||||
aiot_sysdep_portfile_t *sysdep; /* 底层依赖回调合集的引用指针 */
|
||||
aiot_mqtt_download_recv_handler_t recv_handler; /* 组件从协议栈读到内容时, 通知用户的回调 */
|
||||
void *userdata; /* 组件调用以上2个 mqtt_download_handler 时的入参之一 */
|
||||
aiot_download_task_desc_t *task_desc; /* 某次下载活动的目标描述信息, 如URL等 */
|
||||
uint32_t range_start;
|
||||
uint32_t range_end;
|
||||
uint32_t request_size; /* 每次请求的size */
|
||||
/*---- 以上都是用户在API可配 ----*/
|
||||
uint32_t msg_id;
|
||||
uint32_t size_fetched;
|
||||
int32_t percent;
|
||||
uint64_t last_request_time;
|
||||
uint64_t failed_counter;
|
||||
int32_t status;
|
||||
int32_t last_percent;
|
||||
uint32_t range_size;
|
||||
int8_t md5_enabled;
|
||||
|
||||
void *digest_ctx;
|
||||
void *data_mutex;
|
||||
void *recv_mutex;
|
||||
} mqtt_download_handle_t;
|
||||
|
||||
/* 用于内存统计的模块名字符串 */
|
||||
#define MQTT_DOWNLOAD_MODULE_NAME "mqtt_download"
|
||||
|
||||
/* 发送请求后,等待回复的超时时间设置 */
|
||||
#define MQTT_DOWNLOAD_DEFAULT_RECV_TIMEOUT (10 * 1000)
|
||||
/* 默认的单次请求长度 */
|
||||
#define MQTT_DOWNLOAD_DEFAULT_REQUEST_SIZE (5 * 1024)
|
||||
|
||||
/* 请求及回复的topic定义 */
|
||||
#define MQTT_DOWNLOAD_REQUEST_TOPIC "/sys/%s/%s/thing/file/download"
|
||||
#define MQTT_DOWNLOAD_RESPONSE_TOPIC "/sys/%s/%s/thing/file/download_reply"
|
||||
|
||||
/* TOKEN的最长长度 */
|
||||
#define MQTT_DOWNLOAD_TOKEN_MAXLEN (128)
|
||||
/* 上报进度的间隔,单位:% */
|
||||
#define MQTT_DOWNLOAD_REPORT_INTERNEL (5)
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* __MQTT_DOWNLOAD_PRIVATE_H__ */
|
||||
|
||||
299
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/ota_md5.c
vendored
Normal file
299
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/ota_md5.c
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
|
||||
#include "ota_md5.h"
|
||||
|
||||
/*
|
||||
* 32-bit integer manipulation macros (little endian)
|
||||
*/
|
||||
#ifndef GET_UINT32_LE
|
||||
#define GET_UINT32_LE(n,b,i) \
|
||||
{ \
|
||||
(n) = ( (uint32_t) (b)[(i) ] ) \
|
||||
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
|
||||
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
|
||||
| ( (uint32_t) (b)[(i) + 3] << 24 ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PUT_UINT32_LE
|
||||
#define PUT_UINT32_LE(n,b,i) \
|
||||
{ \
|
||||
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
|
||||
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
|
||||
(b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
|
||||
(b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
static void utils_md5_zeroize(void *v, uint32_t n)
|
||||
{
|
||||
volatile unsigned char *p = v;
|
||||
while (n--) {
|
||||
*p++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void utils_md5_init(utils_md5_context_t *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(utils_md5_context_t));
|
||||
}
|
||||
|
||||
void utils_md5_free(utils_md5_context_t *ctx)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
utils_md5_zeroize(ctx, sizeof(utils_md5_context_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 context setup
|
||||
*/
|
||||
int32_t utils_md5_starts(utils_md5_context_t *ctx)
|
||||
{
|
||||
ctx->total[0] = 0;
|
||||
ctx->total[1] = 0;
|
||||
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32_t utils_internal_md5_process(utils_md5_context_t *ctx,
|
||||
const unsigned char data[64])
|
||||
{
|
||||
uint32_t X[16], A, B, C, D;
|
||||
|
||||
GET_UINT32_LE(X[ 0], data, 0);
|
||||
GET_UINT32_LE(X[ 1], data, 4);
|
||||
GET_UINT32_LE(X[ 2], data, 8);
|
||||
GET_UINT32_LE(X[ 3], data, 12);
|
||||
GET_UINT32_LE(X[ 4], data, 16);
|
||||
GET_UINT32_LE(X[ 5], data, 20);
|
||||
GET_UINT32_LE(X[ 6], data, 24);
|
||||
GET_UINT32_LE(X[ 7], data, 28);
|
||||
GET_UINT32_LE(X[ 8], data, 32);
|
||||
GET_UINT32_LE(X[ 9], data, 36);
|
||||
GET_UINT32_LE(X[10], data, 40);
|
||||
GET_UINT32_LE(X[11], data, 44);
|
||||
GET_UINT32_LE(X[12], data, 48);
|
||||
GET_UINT32_LE(X[13], data, 52);
|
||||
GET_UINT32_LE(X[14], data, 56);
|
||||
GET_UINT32_LE(X[15], data, 60);
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define P(a,b,c,d,k,s,t) \
|
||||
{ \
|
||||
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
|
||||
}
|
||||
|
||||
A = ctx->state[0];
|
||||
B = ctx->state[1];
|
||||
C = ctx->state[2];
|
||||
D = ctx->state[3];
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
|
||||
P(A, B, C, D, 0, 7, 0xD76AA478);
|
||||
P(D, A, B, C, 1, 12, 0xE8C7B756);
|
||||
P(C, D, A, B, 2, 17, 0x242070DB);
|
||||
P(B, C, D, A, 3, 22, 0xC1BDCEEE);
|
||||
P(A, B, C, D, 4, 7, 0xF57C0FAF);
|
||||
P(D, A, B, C, 5, 12, 0x4787C62A);
|
||||
P(C, D, A, B, 6, 17, 0xA8304613);
|
||||
P(B, C, D, A, 7, 22, 0xFD469501);
|
||||
P(A, B, C, D, 8, 7, 0x698098D8);
|
||||
P(D, A, B, C, 9, 12, 0x8B44F7AF);
|
||||
P(C, D, A, B, 10, 17, 0xFFFF5BB1);
|
||||
P(B, C, D, A, 11, 22, 0x895CD7BE);
|
||||
P(A, B, C, D, 12, 7, 0x6B901122);
|
||||
P(D, A, B, C, 13, 12, 0xFD987193);
|
||||
P(C, D, A, B, 14, 17, 0xA679438E);
|
||||
P(B, C, D, A, 15, 22, 0x49B40821);
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (z & (x ^ y)))
|
||||
|
||||
P(A, B, C, D, 1, 5, 0xF61E2562);
|
||||
P(D, A, B, C, 6, 9, 0xC040B340);
|
||||
P(C, D, A, B, 11, 14, 0x265E5A51);
|
||||
P(B, C, D, A, 0, 20, 0xE9B6C7AA);
|
||||
P(A, B, C, D, 5, 5, 0xD62F105D);
|
||||
P(D, A, B, C, 10, 9, 0x02441453);
|
||||
P(C, D, A, B, 15, 14, 0xD8A1E681);
|
||||
P(B, C, D, A, 4, 20, 0xE7D3FBC8);
|
||||
P(A, B, C, D, 9, 5, 0x21E1CDE6);
|
||||
P(D, A, B, C, 14, 9, 0xC33707D6);
|
||||
P(C, D, A, B, 3, 14, 0xF4D50D87);
|
||||
P(B, C, D, A, 8, 20, 0x455A14ED);
|
||||
P(A, B, C, D, 13, 5, 0xA9E3E905);
|
||||
P(D, A, B, C, 2, 9, 0xFCEFA3F8);
|
||||
P(C, D, A, B, 7, 14, 0x676F02D9);
|
||||
P(B, C, D, A, 12, 20, 0x8D2A4C8A);
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
|
||||
P(A, B, C, D, 5, 4, 0xFFFA3942);
|
||||
P(D, A, B, C, 8, 11, 0x8771F681);
|
||||
P(C, D, A, B, 11, 16, 0x6D9D6122);
|
||||
P(B, C, D, A, 14, 23, 0xFDE5380C);
|
||||
P(A, B, C, D, 1, 4, 0xA4BEEA44);
|
||||
P(D, A, B, C, 4, 11, 0x4BDECFA9);
|
||||
P(C, D, A, B, 7, 16, 0xF6BB4B60);
|
||||
P(B, C, D, A, 10, 23, 0xBEBFBC70);
|
||||
P(A, B, C, D, 13, 4, 0x289B7EC6);
|
||||
P(D, A, B, C, 0, 11, 0xEAA127FA);
|
||||
P(C, D, A, B, 3, 16, 0xD4EF3085);
|
||||
P(B, C, D, A, 6, 23, 0x04881D05);
|
||||
P(A, B, C, D, 9, 4, 0xD9D4D039);
|
||||
P(D, A, B, C, 12, 11, 0xE6DB99E5);
|
||||
P(C, D, A, B, 15, 16, 0x1FA27CF8);
|
||||
P(B, C, D, A, 2, 23, 0xC4AC5665);
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (x | ~z))
|
||||
|
||||
P(A, B, C, D, 0, 6, 0xF4292244);
|
||||
P(D, A, B, C, 7, 10, 0x432AFF97);
|
||||
P(C, D, A, B, 14, 15, 0xAB9423A7);
|
||||
P(B, C, D, A, 5, 21, 0xFC93A039);
|
||||
P(A, B, C, D, 12, 6, 0x655B59C3);
|
||||
P(D, A, B, C, 3, 10, 0x8F0CCC92);
|
||||
P(C, D, A, B, 10, 15, 0xFFEFF47D);
|
||||
P(B, C, D, A, 1, 21, 0x85845DD1);
|
||||
P(A, B, C, D, 8, 6, 0x6FA87E4F);
|
||||
P(D, A, B, C, 15, 10, 0xFE2CE6E0);
|
||||
P(C, D, A, B, 6, 15, 0xA3014314);
|
||||
P(B, C, D, A, 13, 21, 0x4E0811A1);
|
||||
P(A, B, C, D, 4, 6, 0xF7537E82);
|
||||
P(D, A, B, C, 11, 10, 0xBD3AF235);
|
||||
P(C, D, A, B, 2, 15, 0x2AD7D2BB);
|
||||
P(B, C, D, A, 9, 21, 0xEB86D391);
|
||||
|
||||
#undef F
|
||||
|
||||
ctx->state[0] += A;
|
||||
ctx->state[1] += B;
|
||||
ctx->state[2] += C;
|
||||
ctx->state[3] += D;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 process buffer
|
||||
*/
|
||||
int32_t utils_md5_update(utils_md5_context_t *ctx,
|
||||
const unsigned char *input,
|
||||
uint32_t ilen)
|
||||
{
|
||||
int32_t ret;
|
||||
uint32_t fill;
|
||||
uint32_t left;
|
||||
|
||||
if (ilen == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
left = ctx->total[0] & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
ctx->total[0] += (uint32_t) ilen;
|
||||
ctx->total[0] &= 0xFFFFFFFF;
|
||||
|
||||
if (ctx->total[0] < (uint32_t) ilen) {
|
||||
ctx->total[1]++;
|
||||
}
|
||||
|
||||
if (left && ilen >= fill) {
|
||||
memcpy((void *)(ctx->buffer + left), input, fill);
|
||||
if ((ret = utils_internal_md5_process(ctx, ctx->buffer)) != 0) {
|
||||
return (ret);
|
||||
}
|
||||
|
||||
input += fill;
|
||||
ilen -= fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while (ilen >= 64) {
|
||||
if ((ret = utils_internal_md5_process(ctx, input)) != 0) {
|
||||
return (ret);
|
||||
}
|
||||
|
||||
input += 64;
|
||||
ilen -= 64;
|
||||
}
|
||||
|
||||
if (ilen > 0) {
|
||||
memcpy((void *)(ctx->buffer + left), input, ilen);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 final digest
|
||||
*/
|
||||
int32_t utils_md5_finish(utils_md5_context_t *ctx,
|
||||
unsigned char output[16])
|
||||
{
|
||||
int32_t ret;
|
||||
uint32_t used;
|
||||
uint32_t high, low;
|
||||
|
||||
/*
|
||||
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
|
||||
*/
|
||||
used = ctx->total[0] & 0x3F;
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
if (used <= 56) {
|
||||
/* Enough room for padding + length in current block */
|
||||
memset(ctx->buffer + used, 0, 56 - used);
|
||||
} else {
|
||||
/* We'll need an extra block */
|
||||
memset(ctx->buffer + used, 0, 64 - used);
|
||||
|
||||
if ((ret = utils_internal_md5_process(ctx, ctx->buffer)) != 0) {
|
||||
return (ret);
|
||||
}
|
||||
|
||||
memset(ctx->buffer, 0, 56);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add message length
|
||||
*/
|
||||
high = (ctx->total[0] >> 29)
|
||||
| (ctx->total[1] << 3);
|
||||
low = (ctx->total[0] << 3);
|
||||
|
||||
PUT_UINT32_LE(low, ctx->buffer, 56);
|
||||
PUT_UINT32_LE(high, ctx->buffer, 60);
|
||||
|
||||
if ((ret = utils_internal_md5_process(ctx, ctx->buffer)) != 0) {
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output final state
|
||||
*/
|
||||
PUT_UINT32_LE(ctx->state[0], output, 0);
|
||||
PUT_UINT32_LE(ctx->state[1], output, 4);
|
||||
PUT_UINT32_LE(ctx->state[2], output, 8);
|
||||
PUT_UINT32_LE(ctx->state[3], output, 12);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
136
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/ota_md5.h
vendored
Normal file
136
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/ota_md5.h
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef __OTA_MD5_H__
|
||||
#define __OTA_MD5_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* \brief MD5 context structure
|
||||
*
|
||||
* \warning MD5 is considered a weak message digest and its use
|
||||
* constitutes a security risk. We recommend considering
|
||||
* stronger message digests instead.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t total[2]; /*!< number of bytes processed */
|
||||
uint32_t state[4]; /*!< intermediate digest state */
|
||||
unsigned char buffer[64]; /*!< data block being processed */
|
||||
} utils_md5_context_t;
|
||||
|
||||
/**
|
||||
* \brief Initialize MD5 context
|
||||
*
|
||||
* \param ctx MD5 context to be initialized
|
||||
*
|
||||
* \warning MD5 is considered a weak message digest and its use
|
||||
* constitutes a security risk. We recommend considering
|
||||
* stronger message digests instead.
|
||||
*
|
||||
*/
|
||||
void utils_md5_init(utils_md5_context_t *ctx);
|
||||
|
||||
/**
|
||||
* \brief Clear MD5 context
|
||||
*
|
||||
* \param ctx MD5 context to be cleared
|
||||
*
|
||||
* \warning MD5 is considered a weak message digest and its use
|
||||
* constitutes a security risk. We recommend considering
|
||||
* stronger message digests instead.
|
||||
*
|
||||
*/
|
||||
void utils_md5_free(utils_md5_context_t *ctx);
|
||||
|
||||
/**
|
||||
* \brief MD5 context setup
|
||||
*
|
||||
* \param ctx context to be initialized
|
||||
*
|
||||
* \return 0 if successful
|
||||
*
|
||||
* \warning MD5 is considered a weak message digest and its use
|
||||
* constitutes a security risk. We recommend considering
|
||||
* stronger message digests instead.
|
||||
*
|
||||
*/
|
||||
int32_t utils_md5_starts(utils_md5_context_t *ctx);
|
||||
|
||||
/**
|
||||
* \brief MD5 process buffer
|
||||
*
|
||||
* \param ctx MD5 context
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
*
|
||||
* \return 0 if successful
|
||||
*
|
||||
* \warning MD5 is considered a weak message digest and its use
|
||||
* constitutes a security risk. We recommend considering
|
||||
* stronger message digests instead.
|
||||
*
|
||||
*/
|
||||
int32_t utils_md5_update(utils_md5_context_t *ctx,
|
||||
const unsigned char *input,
|
||||
uint32_t ilen);
|
||||
|
||||
/**
|
||||
* \brief MD5 final digest
|
||||
*
|
||||
* \param ctx MD5 context
|
||||
* \param output MD5 checksum result
|
||||
*
|
||||
* \return 0 if successful
|
||||
*
|
||||
* \warning MD5 is considered a weak message digest and its use
|
||||
* constitutes a security risk. We recommend considering
|
||||
* stronger message digests instead.
|
||||
*
|
||||
*/
|
||||
int32_t utils_md5_finish(utils_md5_context_t *ctx,
|
||||
unsigned char output[16]);
|
||||
|
||||
/**
|
||||
* \brief MD5 process data block (internal use only)
|
||||
*
|
||||
* \param ctx MD5 context
|
||||
* \param data buffer holding one block of data
|
||||
*
|
||||
* \return 0 if successful
|
||||
*
|
||||
* \warning MD5 is considered a weak message digest and its use
|
||||
* constitutes a security risk. We recommend considering
|
||||
* stronger message digests instead.
|
||||
*
|
||||
*/
|
||||
int32_t utils_internal_md5_process(utils_md5_context_t *ctx,
|
||||
const unsigned char data[64]);
|
||||
|
||||
/**
|
||||
* \brief Output = MD5( input buffer )
|
||||
*
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
* \param output MD5 checksum result
|
||||
*
|
||||
* \return 0 if successful
|
||||
*
|
||||
* \warning MD5 is considered a weak message digest and its use
|
||||
* constitutes a security risk. We recommend considering
|
||||
* stronger message digests instead.
|
||||
*
|
||||
*/
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OTA_MD5_H__ */
|
||||
|
||||
116
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/ota_private.h
vendored
Normal file
116
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/ota/ota_private.h
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
#ifndef __OTA_PRIVATE_H__
|
||||
#define __OTA_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "core_stdinc.h"
|
||||
|
||||
#include "core_http.h"
|
||||
#include "aiot_ota_api.h"
|
||||
|
||||
#define OTA_VERSION_TOPIC_PREFIX "/ota/device/inform"
|
||||
#define OTA_PROGRESS_TOPIC_PREFIX "/ota/device/progress"
|
||||
|
||||
#define OTA_MODULE_NAME "OTA"
|
||||
#define DOWNLOAD_MODULE_NAME "DOWNLOAD"
|
||||
|
||||
#define OTA_DEFAULT_DOWNLOAD_BUFLEN (2 * 1024)
|
||||
#define OTA_DEFAULT_DOWNLOAD_TIMEOUT_MS (5 * 1000)
|
||||
|
||||
#define OTA_FOTA_TOPIC "/ota/device/upgrade/+/+"
|
||||
#define OTA_FOTA_TOPIC_PREFIX "/ota/device/upgrade"
|
||||
#define OTA_COTA_PUSH_TOPIC "/sys/+/+/thing/config/push"
|
||||
#define OTA_COTA_PUSH_TOPIC_POSTFIX "/thing/config/push"
|
||||
#define OTA_COTA_GET_REPLY_TOPIC "/sys/+/+/thing/config/get_reply"
|
||||
#define OTA_COTA_GET_REPLY_TOPIC_POSTFIX "/thing/config/get_reply"
|
||||
#define OTA_COTA_TOPIC_PREFIX "/sys/"
|
||||
#define OTA_GET_TOPIC_PREFIX "/sys"
|
||||
#define OTA_GET_TOPIC_SUFFIX "thing/ota/firmware/get"
|
||||
#define OTA_GET_REPLY_TOPIC_SUFFIX "thing/ota/firmware/get_reply"
|
||||
#define OTA_OTA_GET_REPLY_TOPIC "/sys/+/+/thing/ota/firmware/get_reply"
|
||||
|
||||
#define OTA_HTTPCLIENT_MAX_URL_LEN (256)
|
||||
#define OTA_MAX_DIGIT_NUM_OF_UINT32 (20)
|
||||
#define OTA_RESPONSE_PARTIAL (206)
|
||||
#define OTA_RESPONSE_OK (200)
|
||||
#define OTA_TOPIC_NUM (4)
|
||||
#define OTA_MD5_LEN (32)
|
||||
#define OTA_SHA256_LEN (64)
|
||||
|
||||
typedef enum {
|
||||
DOWNLOAD_STATUS_START,
|
||||
DOWNLOAD_STATUS_FETCH,
|
||||
DOWNLOAD_STATUS_RENEWAL,
|
||||
} download_status_t;
|
||||
|
||||
typedef enum {
|
||||
OTA_TYPE_FOTA,
|
||||
OTA_TYPE_CONFIG_PUSH,
|
||||
OTA_TYPE_CONFIG_GET,
|
||||
} ota_type_t;
|
||||
|
||||
/**
|
||||
* @brief OTA过程中处理mqtt消息的句柄, 该句柄主要用于通过mqtt协议从云端收取固件升级消息, 包括固件的url等
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
void *userdata; /* 组件调用recv_handler的入参之一, 传入用户数据 */
|
||||
aiot_ota_recv_handler_t recv_handler; /* OTA的mqtt消息到达设备端时, 通知用户的回调 */
|
||||
aiot_sysdep_portfile_t *sysdep;
|
||||
|
||||
/*---- 以上都是用户在API可配 ----*/
|
||||
/*---- 以下都是OTA内部使用, 用户无感知 ----*/
|
||||
|
||||
void *mqtt_handle;
|
||||
void *module;
|
||||
void *data_mutex;
|
||||
} ota_handle_t;
|
||||
|
||||
/**
|
||||
* @brief 处理下载任务的句柄, 该句柄主要用于通过http协议从指定的url下载固件
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
void
|
||||
*userdata; /* 组件调用recv_handler 时的入参之一, 传入用户数据 */
|
||||
aiot_download_recv_handler_t recv_handler; /* 设备收到分段的固件报文时的回调函数 */
|
||||
aiot_download_task_desc_t *task_desc; /* 某次下载活动的目标描述信息, 如URL等 */
|
||||
aiot_sysdep_portfile_t *sysdep;
|
||||
uint32_t range_start;
|
||||
uint32_t range_end;
|
||||
|
||||
/*---- 以上都是用户在API可配 ----*/
|
||||
/*---- 以下都是downloader内部使用, 用户无感知 ----*/
|
||||
|
||||
uint8_t download_status;
|
||||
void *http_handle;
|
||||
uint32_t size_fetched;
|
||||
uint32_t range_size_fetched;
|
||||
uint32_t content_len;
|
||||
int32_t percent;
|
||||
int32_t http_rsp_status_code;
|
||||
void *digest_ctx;
|
||||
void *data_mutex;
|
||||
void *recv_mutex;
|
||||
} download_handle_t;
|
||||
|
||||
typedef struct {
|
||||
char *pos;
|
||||
int len;
|
||||
} ota_list_json;
|
||||
|
||||
#define OTA_ARRAY_MAX (20)
|
||||
|
||||
void *_download_deep_copy_task_desc(aiot_sysdep_portfile_t *sysdep, void *data);
|
||||
int32_t _download_deep_free_task_desc(aiot_sysdep_portfile_t *sysdep, void *data);
|
||||
int32_t _ota_publish_base(void *handle, char *topic_prefix, char *product_key, char *device_name, char *suffix,
|
||||
char *params);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OTA_PRIVATE_H__ */
|
||||
|
||||
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/shadow/README.md
vendored
Normal file
3
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/shadow/README.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Name: 设备影子模块
|
||||
SHADOW Component for Link SDK V4.0.0
|
||||
|
||||
438
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/shadow/aiot_shadow_api.c
vendored
Normal file
438
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/shadow/aiot_shadow_api.c
vendored
Normal file
@@ -0,0 +1,438 @@
|
||||
/**
|
||||
* @file aiot_shadow_api.c
|
||||
* @brief shadow模块的API接口实现, 提供更新, 删除, 获取设备影子的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shadow_private.h"
|
||||
|
||||
#include "core_string.h"
|
||||
#include "core_log.h"
|
||||
#include "core_global.h"
|
||||
#include "core_mqtt.h"
|
||||
|
||||
|
||||
static int32_t _shadow_get_pk_dn(aiot_sysdep_portfile_t *sysdep, char *topic, uint16_t topic_len,
|
||||
char **product_key, char **device_name)
|
||||
{
|
||||
uint16_t pk_offset = 12; /* length of "/shadow/get/" */
|
||||
uint16_t idx = 0;
|
||||
uint16_t pk_len = 0, dn_len = 0;
|
||||
char *pk_pos = topic + pk_offset;
|
||||
char *dn_pos = NULL;
|
||||
char *tmp_pk = NULL, *tmp_dn = NULL;
|
||||
|
||||
for (idx = pk_offset; idx < topic_len - 1; idx++) {
|
||||
if (topic[idx] == '/') {
|
||||
dn_pos = topic + idx + 1;
|
||||
pk_len = dn_pos - pk_pos - 1;
|
||||
dn_len = topic_len - idx - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (pk_len == 0 || dn_len == 0) {
|
||||
return STATE_SHADOW_INTERNAL_TOPIC_ERROR;
|
||||
}
|
||||
|
||||
tmp_pk = sysdep->core_sysdep_malloc(pk_len + 1, SHADOW_MODULE_NAME);
|
||||
if (tmp_pk == NULL) {
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
memset(tmp_pk, 0, pk_len + 1);
|
||||
memcpy(tmp_pk, pk_pos, pk_len);
|
||||
|
||||
tmp_dn = sysdep->core_sysdep_malloc(dn_len + 1, SHADOW_MODULE_NAME);
|
||||
if (tmp_dn == NULL) {
|
||||
sysdep->core_sysdep_free(tmp_pk);
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
memset(tmp_dn, 0, dn_len + 1);
|
||||
memcpy(tmp_dn, dn_pos, dn_len);
|
||||
|
||||
*product_key = tmp_pk;
|
||||
*device_name = tmp_dn;
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t _shadow_int642str(int64_t input, char *output, uint8_t *output_len)
|
||||
{
|
||||
uint64_t temp = 0;
|
||||
uint8_t len = 0;
|
||||
|
||||
if (input < 0) {
|
||||
*output = '-';
|
||||
temp = -input;
|
||||
core_uint642str(temp, output + 1, &len);
|
||||
if (output_len != NULL) {
|
||||
*output_len = len + 1;
|
||||
}
|
||||
} else {
|
||||
temp = input;
|
||||
core_uint642str(temp, output, output_len);
|
||||
}
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static void _shadow_recv_message_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
shadow_handle_t *shadow_handle = (shadow_handle_t *)userdata;
|
||||
aiot_shadow_recv_t recv;
|
||||
char *value = NULL;
|
||||
uint32_t value_len = 0;
|
||||
char *pk = NULL;
|
||||
char *dn = NULL;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
char *method = NULL;
|
||||
uint32_t method_len = 0;
|
||||
char *payload = NULL;
|
||||
uint32_t payload_len = 0;
|
||||
uint64_t timestamp = 0;
|
||||
uint64_t version = 0;
|
||||
char status[10] = { 0 };
|
||||
char *version_str = NULL;
|
||||
uint32_t version_strlen = 0;
|
||||
|
||||
if (NULL == shadow_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_shadow_recv_t));
|
||||
|
||||
do {
|
||||
/* get pk & dn */
|
||||
if ((res = _shadow_get_pk_dn(shadow_handle->sysdep, msg->data.pub.topic, msg->data.pub.topic_len, &pk, &dn)) < 0) {
|
||||
break;
|
||||
}
|
||||
recv.product_key = pk;
|
||||
recv.device_name = dn;
|
||||
|
||||
/* parse the message */
|
||||
if ((res = core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
SHADOW_JSON_KEY_METHOD, strlen(SHADOW_JSON_KEY_METHOD), &method, &method_len) < 0) ||
|
||||
(res = core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
SHADOW_JSON_KEY_TIMESTAMP, strlen(SHADOW_JSON_KEY_TIMESTAMP), &value, &value_len) < 0) ||
|
||||
(res = core_str2uint64(value, value_len, ×tamp) < 0) ||
|
||||
(res = core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
SHADOW_JSON_KEY_PAYLOAD, strlen(SHADOW_JSON_KEY_PAYLOAD), &payload, &payload_len) < 0)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
SHADOW_JSON_KEY_VERSION, strlen(SHADOW_JSON_KEY_VERSION), &version_str, &version_strlen) == STATE_SUCCESS) {
|
||||
core_str2uint64(version_str, version_strlen, &version);
|
||||
}
|
||||
|
||||
/* control message */
|
||||
if (method_len == strlen("control") && !memcmp(method, "control", method_len)) {
|
||||
/* get version */
|
||||
if (version_str == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
core_log(shadow_handle->sysdep, STATE_SHADOW_LOG_RECV, "SHADOW recv control message\r\n");
|
||||
recv.type = AIOT_SHADOWRECV_CONTROL;
|
||||
recv.data.control.payload = payload;
|
||||
recv.data.control.payload_len = payload_len;
|
||||
recv.data.control.version = version;
|
||||
} /* reply message */
|
||||
else if (method_len == strlen("reply") && !memcmp(method, "reply", method_len)) {
|
||||
/* get_reply */
|
||||
if (core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
SHADOW_JSON_KEY_STATE, strlen(SHADOW_JSON_KEY_STATE), &value, &value_len) < 0) {
|
||||
|
||||
if ((res = core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
SHADOW_JSON_KEY_STATUS, strlen(SHADOW_JSON_KEY_STATUS), &value, &value_len) < 0) ||
|
||||
(value_len >= sizeof(status))) {
|
||||
break;
|
||||
}
|
||||
|
||||
core_log(shadow_handle->sysdep, STATE_SHADOW_LOG_RECV, "SHADOW recv get_reply message\r\n");
|
||||
memcpy(status, value, value_len);
|
||||
recv.type = AIOT_SHADOWRECV_GENERIC_REPLY;
|
||||
recv.data.generic_reply.payload = payload;
|
||||
recv.data.generic_reply.payload_len = payload_len;
|
||||
recv.data.generic_reply.status = status;
|
||||
recv.data.generic_reply.timestamp = timestamp;
|
||||
} /* get_reply */
|
||||
else {
|
||||
if (version_str == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
core_log(shadow_handle->sysdep, STATE_SHADOW_LOG_RECV, "SHADOW recv generic_reply message\r\n");
|
||||
recv.type = AIOT_SHADOWRECV_GET_REPLY;
|
||||
recv.data.get_reply.payload = payload;
|
||||
recv.data.get_reply.payload_len = payload_len;
|
||||
recv.data.get_reply.version = version;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
shadow_handle->recv_handler(shadow_handle, &recv, shadow_handle->userdata);
|
||||
shadow_handle->sysdep->core_sysdep_free(pk);
|
||||
shadow_handle->sysdep->core_sysdep_free(dn);
|
||||
return;
|
||||
} while (0);
|
||||
|
||||
/* invalid message log */
|
||||
core_log(shadow_handle->sysdep, SATAE_SHADOW_LOG_PARSE_RECV_MSG_FAILED, "SHADOW parse recv message failed\r\n");
|
||||
|
||||
if (pk != NULL) {
|
||||
shadow_handle->sysdep->core_sysdep_free(pk);
|
||||
}
|
||||
if (dn != NULL) {
|
||||
shadow_handle->sysdep->core_sysdep_free(dn);
|
||||
}
|
||||
}
|
||||
|
||||
static void _shadow_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
|
||||
{
|
||||
shadow_handle_t *shadow_handle = (shadow_handle_t *)context;
|
||||
|
||||
if (core_event != NULL) {
|
||||
switch (core_event->type) {
|
||||
case CORE_MQTTEVT_DEINIT: {
|
||||
shadow_handle->mqtt_handle = NULL;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _shadow_core_mqtt_operate_process_handler(shadow_handle_t *shadow_handle, core_mqtt_option_t option)
|
||||
{
|
||||
core_mqtt_process_data_t process_data;
|
||||
|
||||
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
|
||||
process_data.handler = _shadow_core_mqtt_process_handler;
|
||||
process_data.context = shadow_handle;
|
||||
|
||||
return core_mqtt_setopt(shadow_handle->mqtt_handle, option, &process_data);
|
||||
}
|
||||
|
||||
void *aiot_shadow_init(void)
|
||||
{
|
||||
aiot_sysdep_portfile_t *sysdep = aiot_sysdep_get_portfile();
|
||||
shadow_handle_t *shadow_handle = NULL;
|
||||
|
||||
if (NULL == sysdep) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shadow_handle = sysdep->core_sysdep_malloc(sizeof(shadow_handle_t), SHADOW_MODULE_NAME);
|
||||
if (NULL == shadow_handle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(shadow_handle, 0, sizeof(shadow_handle_t));
|
||||
shadow_handle->sysdep = sysdep;
|
||||
|
||||
return shadow_handle;
|
||||
}
|
||||
|
||||
int32_t aiot_shadow_setopt(void *handle, aiot_shadow_option_t option, void *data)
|
||||
{
|
||||
shadow_handle_t *shadow_handle;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == handle || NULL == data) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
if (option >= AIOT_SHADOWOPT_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
shadow_handle = (shadow_handle_t *)handle;
|
||||
|
||||
switch (option) {
|
||||
case AIOT_SHADOWOPT_MQTT_HANDLE: {
|
||||
aiot_mqtt_topic_map_t topic_mapping;
|
||||
shadow_handle->mqtt_handle = data;
|
||||
|
||||
/* setup mqtt topic mapping */
|
||||
topic_mapping.topic = SHADOW_GET_TOPIC;
|
||||
topic_mapping.handler = _shadow_recv_message_handler;
|
||||
topic_mapping.userdata = handle;
|
||||
|
||||
res = aiot_mqtt_setopt(data, AIOT_MQTTOPT_APPEND_TOPIC_MAP, &topic_mapping);
|
||||
if (res >= STATE_SUCCESS) {
|
||||
res = _shadow_core_mqtt_operate_process_handler(shadow_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AIOT_SHADOWOPT_RECV_HANDLER: {
|
||||
shadow_handle->recv_handler = (aiot_shadow_recv_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_SHADOWOPT_USERDATA: {
|
||||
shadow_handle->userdata = data;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_shadow_send(void *handle, aiot_shadow_msg_t *msg)
|
||||
{
|
||||
shadow_handle_t *shadow_handle = NULL;
|
||||
char *topic = NULL;
|
||||
char *payload = NULL;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == handle || NULL == msg) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
if (msg->type >= AIOT_SHADOWMSG_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
shadow_handle = (shadow_handle_t *)handle;
|
||||
if (NULL == shadow_handle->mqtt_handle) {
|
||||
return STATE_SHADOW_MQTT_HANDLE_IS_NULL;
|
||||
}
|
||||
|
||||
/* construct mqtt topic */
|
||||
{
|
||||
char *src[2];
|
||||
char *pk = NULL, *dn = NULL;
|
||||
|
||||
pk = core_mqtt_get_product_key(shadow_handle->mqtt_handle);
|
||||
dn = core_mqtt_get_device_name(shadow_handle->mqtt_handle);
|
||||
|
||||
if (NULL == msg->product_key && NULL == pk) {
|
||||
return STATE_USER_INPUT_MISSING_PRODUCT_KEY;
|
||||
}
|
||||
if (NULL == msg->device_name && NULL == dn) {
|
||||
return STATE_USER_INPUT_MISSING_DEVICE_NAME;
|
||||
}
|
||||
|
||||
src[0] = (msg->product_key != NULL) ? msg->product_key : pk;
|
||||
src[1] = (msg->device_name != NULL) ? msg->device_name : dn;
|
||||
res = core_sprintf(shadow_handle->sysdep, &topic, SHADOW_UPDATE_TOPIC_FMT, src, sizeof(src) / sizeof(char *),
|
||||
SHADOW_MODULE_NAME);
|
||||
if (NULL == topic) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/* construct payload */
|
||||
switch (msg->type) {
|
||||
case AIOT_SHADOWMSG_UPDATE: {
|
||||
char version_string[21] = { 0 };
|
||||
char *src[3] = { NULL };
|
||||
|
||||
if (NULL == msg->data.update.reported) {
|
||||
res = STATE_SHADOW_REPORTED_DATA_IS_NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
_shadow_int642str(msg->data.update.version, version_string, NULL);
|
||||
src[0] = "update";
|
||||
src[1] = msg->data.update.reported;
|
||||
src[2] = version_string;
|
||||
|
||||
res = core_sprintf(shadow_handle->sysdep, &payload, SHADOW_PAYLOAD_REQ_FMT,
|
||||
src, sizeof(src) / sizeof(char *), SHADOW_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AIOT_SHADOWMSG_CLEAN_DESIRED: {
|
||||
char version_string[21] = { 0 };
|
||||
char *src[1] = { NULL };
|
||||
|
||||
_shadow_int642str(msg->data.clean_desired.version, version_string, NULL);
|
||||
src[0] = version_string;
|
||||
|
||||
res = core_sprintf(shadow_handle->sysdep, &payload, SHADOW_PAYLOAD_CLEAN_FMT,
|
||||
src, sizeof(src) / sizeof(char *), SHADOW_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AIOT_SHADOWMSG_GET: {
|
||||
payload = SHADOW_PAYLOAD_GET;
|
||||
}
|
||||
break;
|
||||
case AIOT_SHADOWMSG_DELETE_REPORTED: {
|
||||
char version_string[21] = { 0 };
|
||||
char *src[3] = { NULL };
|
||||
|
||||
if (NULL == msg->data.delete_reporte.reported) {
|
||||
res = STATE_SHADOW_REPORTED_DATA_IS_NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
_shadow_int642str(msg->data.delete_reporte.version, version_string, NULL);
|
||||
src[0] = "delete";
|
||||
src[1] = msg->data.update.reported;
|
||||
src[2] = version_string;
|
||||
|
||||
res = core_sprintf(shadow_handle->sysdep, &payload, SHADOW_PAYLOAD_REQ_FMT,
|
||||
src, sizeof(src) / sizeof(char *), SHADOW_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
res = STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (NULL == payload) {
|
||||
shadow_handle->sysdep->core_sysdep_free(topic);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(shadow_handle->mqtt_handle, topic, (uint8_t *)payload, strlen(payload), 0);
|
||||
|
||||
shadow_handle->sysdep->core_sysdep_free(topic);
|
||||
if (msg->type != AIOT_SHADOWMSG_GET) {
|
||||
shadow_handle->sysdep->core_sysdep_free(payload);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_shadow_deinit(void **p_handle)
|
||||
{
|
||||
shadow_handle_t *shadow_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
aiot_mqtt_topic_map_t topic_mapping;
|
||||
|
||||
if (NULL == p_handle || NULL == *p_handle) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
shadow_handle = *p_handle;
|
||||
sysdep = shadow_handle->sysdep;
|
||||
*p_handle = NULL;
|
||||
|
||||
_shadow_core_mqtt_operate_process_handler(shadow_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER);
|
||||
|
||||
/* remove mqtt topic mapping */
|
||||
memset(&topic_mapping, 0, sizeof(aiot_mqtt_topic_map_t));
|
||||
topic_mapping.topic = SHADOW_GET_TOPIC;
|
||||
topic_mapping.handler = _shadow_recv_message_handler;
|
||||
aiot_mqtt_setopt(shadow_handle->mqtt_handle, AIOT_MQTTOPT_REMOVE_TOPIC_MAP, &topic_mapping);
|
||||
|
||||
sysdep->core_sysdep_free(shadow_handle);
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
411
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/shadow/aiot_shadow_api.h
vendored
Normal file
411
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/shadow/aiot_shadow_api.h
vendored
Normal file
@@ -0,0 +1,411 @@
|
||||
/**
|
||||
* @file aiot_shadow_api.h
|
||||
* @brief shadow模块头文件, 提供更新, 删除, 获取设备影子的能力
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 请按照以下流程使用API
|
||||
*
|
||||
* 1. 在使用设备影子模块前, 用户应首先创建好一个MQTT实例
|
||||
*
|
||||
* 2. 调用`aiot_shadow_init`创建一个设备影子实例, 保存实例句柄
|
||||
*
|
||||
* 3. 调用`aiot_shadow_setopt`配置`AIOT_SHADOWOPT_MQTT_HANDLE`选项以设置MQTT句柄, 此选项为强制配置选项
|
||||
*
|
||||
* 4. 调用`aiot_shadow_setopt`配置`AIOT_SHADOWOPT_RECV_HANDLER`和`AIOT_SHADOWOPT_USERDATA`选项以注册数据接受回调函数和用户上下文数据指针
|
||||
*
|
||||
* 5. 在使用`aiot_shadow_send`发送消息前, 应先完成MQTT实例的建连
|
||||
*
|
||||
* 6. 调动`aiot_shadow_send`发送更新设备影子, 获取设备影子或删除设备等消息到云平台, 在注册的回调函数中处理各种类型的云端应答消息或主动下推消息
|
||||
*
|
||||
*/
|
||||
#ifndef __AIOT_SHADOW_API_H__
|
||||
#define __AIOT_SHADOW_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief -0x1300~-0x13FF表达SDK在data-model模块内的状态码
|
||||
*/
|
||||
#define STATE_SHADOW_BASE (-0x1300)
|
||||
|
||||
/**
|
||||
* @brief 用户未调用@ref aiot_shadow_setopt 配置MQTT句柄
|
||||
*/
|
||||
#define STATE_SHADOW_MQTT_HANDLE_IS_NULL (-0x1301)
|
||||
|
||||
/**
|
||||
* @brief 用户上报@ref AIOT_SHADOWMSG_UPDATE 或 @ref AIOT_SHADOWMSG_DELETE_REPORTED 消息时, 消息结构体中的reported为NULL
|
||||
*
|
||||
*/
|
||||
#define STATE_SHADOW_REPORTED_DATA_IS_NULL (-0x1302)
|
||||
|
||||
/**
|
||||
* @brief 解析下行数据对应的topic时发生错误
|
||||
*/
|
||||
#define STATE_SHADOW_INTERNAL_TOPIC_ERROR (-0x1303)
|
||||
|
||||
/**
|
||||
* @brief 接收到服务器下行消息时的日志状态码
|
||||
*/
|
||||
#define STATE_SHADOW_LOG_RECV (-0x1304)
|
||||
|
||||
/**
|
||||
* @brief 解析服务器下行消息失败时的日志状态码
|
||||
*/
|
||||
#define SATAE_SHADOW_LOG_PARSE_RECV_MSG_FAILED (-0x1305)
|
||||
|
||||
|
||||
/**
|
||||
* @brief @ref aiot_shadow_setopt 接口的option参数可选值.
|
||||
*
|
||||
* @details 下文每个选项中的数据类型, 指的是@ref aiot_shadow_setopt 中, data参数的数据类型
|
||||
*
|
||||
* 当data的数据类型是char *时, 以配置@ref AIOT_SHADOWOPT_PRODUCT_KEY 为例:
|
||||
*
|
||||
* char *product_key = "xxx";
|
||||
* aiot_shadow_setopt(shadow_handle, AIOT_SHADOWOPT_PRODUCT_KEY, product_key);
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 模块依赖的MQTT句柄
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* shadow模块依赖底层的MQTT模块, 用户必需配置正确的MQTT句柄, 否则无法正常工作, 数据类型为(void *)
|
||||
*/
|
||||
AIOT_SHADOWOPT_MQTT_HANDLE,
|
||||
|
||||
/**
|
||||
* @brief 设置回调, 它在SDK收到网络报文的时候被调用, 告知用户, 数据类型为(aiot_shadow_recv_handler_t)
|
||||
*/
|
||||
AIOT_SHADOWOPT_RECV_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief 用户需要SDK暂存的上下文, 数据类型为(void *)
|
||||
*
|
||||
* @details 这个上下文指针会在 AIOT_SHADOWOPT_RECV_HANDLER 设置的回调被调用时, 由SDK传给用户
|
||||
*/
|
||||
AIOT_SHADOWOPT_USERDATA,
|
||||
|
||||
/**
|
||||
* @brief 配置选项数量最大值, 不可用作配置参数
|
||||
*/
|
||||
AIOT_SHADOWOPT_MAX,
|
||||
} aiot_shadow_option_t;
|
||||
|
||||
/**
|
||||
* @brief shadow模块发送消息类型
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 这个枚举类型包括了shadow模块支持发送的所有数据类型, 不同的消息类型将对于不同的消息结构体
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 更新设备影子中的reported值, 消息结构体参考@ref aiot_shadow_msg_update_t
|
||||
*
|
||||
*/
|
||||
AIOT_SHADOWMSG_UPDATE,
|
||||
|
||||
/**
|
||||
* @brief 清空设备影子的desired值, 消息结构体参考@ref aiot_shadow_msg_clean_desired_t
|
||||
*
|
||||
*/
|
||||
AIOT_SHADOWMSG_CLEAN_DESIRED,
|
||||
|
||||
/**
|
||||
* @brief 获取设备影子, 消息结构体参考@ref aiot_shadow_msg_get_t
|
||||
*
|
||||
*/
|
||||
AIOT_SHADOWMSG_GET,
|
||||
|
||||
/**
|
||||
* @brief 删除设备影子的部分或全部reported值, 消息结构体参考@ref aiot_shadow_msg_delete_reported_t
|
||||
*
|
||||
*/
|
||||
AIOT_SHADOWMSG_DELETE_REPORTED,
|
||||
|
||||
/**
|
||||
* @brief 消息数量最大值, 不可用作消息类型
|
||||
*/
|
||||
AIOT_SHADOWMSG_MAX,
|
||||
} aiot_shadow_msg_type_t;
|
||||
|
||||
/**
|
||||
* @brief 用于<b>更新设备影子中的reported数据</b>的消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 设备影子reported object字符串, <b>必须为以结束符'\0'结尾的字符串</b>, 如"{\"LightSwitch\": 1}"
|
||||
*/
|
||||
char *reported;
|
||||
|
||||
/**
|
||||
* @brief 设备影子的目标版本, <b>必须大于设备影子的当前版本</b>, 若设置为-1将清空设备影子数据, 并将设备影子版本更新为0
|
||||
*/
|
||||
int64_t version;
|
||||
} aiot_shadow_msg_update_t;
|
||||
|
||||
/**
|
||||
* @brief 用于<b>清除设备影子中的desired数据</b>的消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 设备影子的目标版本, <b>必须大于设备影子的当前版本</b>
|
||||
*/
|
||||
int64_t version;
|
||||
} aiot_shadow_msg_clean_desired_t;
|
||||
|
||||
/**
|
||||
* @brief 用于<b>获取设备影子</b>的消息结构体,
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 保留字段
|
||||
*/
|
||||
uint32_t resevered;
|
||||
} aiot_shadow_msg_get_t;
|
||||
|
||||
/**
|
||||
* @brief 用于<b>删除设备影子中的reported数据</b>的消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 用户将要删除的reported数据, <b>必须为以结束符'\0'结尾的字符串</b>. \n
|
||||
* 若要删除全部reported数据, 则应填写"\"null\""字符串 \n
|
||||
* 若要删除部分reported数据, 则将对应的值定义为null, 如只清除LightSwitch的值应填写"{\"LightSwitch\":\"null\"}"
|
||||
*/
|
||||
char *reported;
|
||||
|
||||
/**
|
||||
* @brief 设备影子的目标版本, <b>必须大于设备影子的当前版本</b>
|
||||
*/
|
||||
int64_t version;
|
||||
} aiot_shadow_msg_delete_reported_t;
|
||||
|
||||
/**
|
||||
* @brief data-model模块发送消息的消息结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息所属设备的product_key, 若为NULL则使用通过aiot_shadow_setopt配置的product_key \n
|
||||
* 在网关子设备场景下, 可通过指定为子设备的product_key来发送子设备的消息到云端
|
||||
*/
|
||||
char *product_key;
|
||||
/**
|
||||
* @brief 消息所属设备的device_name, 若为NULL则使用通过aiot_shadow_setopt配置的device_name \n
|
||||
* 在网关子设备场景下, 可通过指定为子设备的product_key来发送子设备的消息到云端
|
||||
*/
|
||||
char *device_name;
|
||||
/**
|
||||
* @brief 消息类型, 可参考@ref aiot_shadow_msg_type_t
|
||||
*/
|
||||
aiot_shadow_msg_type_t type;
|
||||
/**
|
||||
* @brief 消息数据联合体, 不同的消息类型将使用不同的消息结构体
|
||||
*/
|
||||
union {
|
||||
aiot_shadow_msg_update_t update;
|
||||
aiot_shadow_msg_clean_desired_t clean_desired;
|
||||
aiot_shadow_msg_get_t get;
|
||||
aiot_shadow_msg_delete_reported_t delete_reporte;
|
||||
} data;
|
||||
} aiot_shadow_msg_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief shadow模块收到从网络上来的报文时, 通知用户的报文类型
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 设备发送 @ref AIOT_SHADOWMSG_UPDATE, @ref AIOT_SHADOWMSG_CLEAN_DESIRED 或 @ref AIOT_SHADOWMSG_DELETE_REPORTED 这3这类型消息后, 云端返回的应答消息, \n
|
||||
* 消息数据结构体参考 @ref aiot_shadow_recv_generic_reply_t
|
||||
*/
|
||||
AIOT_SHADOWRECV_GENERIC_REPLY,
|
||||
|
||||
/**
|
||||
* @brief 设备在线时, 云端自动下发的影子内容, 消息数据结构体参考 @ref aiot_shadow_recv_control_t
|
||||
*/
|
||||
AIOT_SHADOWRECV_CONTROL,
|
||||
|
||||
/**
|
||||
* @brief 主动获取设备影子内容云端返回的影子内容, 消息数据结构体参考 @ref aiot_shadow_recv_get_reply_t
|
||||
*/
|
||||
AIOT_SHADOWRECV_GET_REPLY,
|
||||
} aiot_shadow_recv_type_t;
|
||||
|
||||
/**
|
||||
* @brief 设备发送 @ref AIOT_SHADOWMSG_UPDATE, @ref AIOT_SHADOWMSG_CLEAN_DESIRED 或 @ref AIOT_SHADOWMSG_DELETE_REPORTED 类型消息后, 云端返回的应答消息
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 指向应答数据的指针
|
||||
*/
|
||||
char *payload;
|
||||
|
||||
/**
|
||||
* @brief 应答数据长度
|
||||
*/
|
||||
uint32_t payload_len;
|
||||
|
||||
/**
|
||||
* @brief 应答状态字符串, 云端处理成功则为<b>success</b>, 发送消息错误则为<b>error</b>, 错误信息和错误码放在在payload中
|
||||
*/
|
||||
char *status;
|
||||
|
||||
/**
|
||||
* @brief 应答报文对应的时间戳
|
||||
*/
|
||||
uint64_t timestamp;
|
||||
} aiot_shadow_recv_generic_reply_t;
|
||||
|
||||
/**
|
||||
* @brief 如果设备在线, 用户应用调用云端API<a href="https://help.aliyun.com/document_detail/69954.html#doc-api-Iot-UpdateDeviceShadow">UpdateDeviceShadow</a>后云端下推的消息
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 指向设备影子数据的指针
|
||||
*/
|
||||
char *payload;
|
||||
|
||||
/**
|
||||
* @brief 设备影子数据长度
|
||||
*/
|
||||
uint32_t payload_len;
|
||||
|
||||
/**
|
||||
* @brief 设备影子版本
|
||||
*/
|
||||
uint64_t version;
|
||||
} aiot_shadow_recv_control_t;
|
||||
|
||||
/**
|
||||
* @brief 设备发送 @ref AIOT_SHADOWMSG_GET 类型消息后, 云端返回的设备影子数据
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 指向设备影子数据的指针
|
||||
*/
|
||||
char *payload;
|
||||
|
||||
/**
|
||||
* @brief 设备影子数据长度
|
||||
*/
|
||||
uint32_t payload_len;
|
||||
|
||||
/**
|
||||
* @brief 设备影子版本号
|
||||
*/
|
||||
uint64_t version;
|
||||
} aiot_shadow_recv_get_reply_t;
|
||||
|
||||
/**
|
||||
* @brief shadow模块收到从网络上来的报文时, 通知用户的报文内容
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 消息所属设备的product_key
|
||||
*/
|
||||
char *product_key;
|
||||
/**
|
||||
* @brief 消息所属设备的device_name
|
||||
*/
|
||||
char *device_name;
|
||||
/**
|
||||
* @brief 报文内容所对应的报文类型, 更多信息请参考@ref aiot_shadow_recv_type_t
|
||||
*/
|
||||
aiot_shadow_recv_type_t type;
|
||||
/**
|
||||
* @brief 消息数据联合体, 不同的消息类型将使用不同的消息结构体
|
||||
*/
|
||||
union {
|
||||
aiot_shadow_recv_generic_reply_t generic_reply;
|
||||
aiot_shadow_recv_control_t control;
|
||||
aiot_shadow_recv_get_reply_t get_reply;
|
||||
} data;
|
||||
} aiot_shadow_recv_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief shadow模块收到从网络上来的报文时, 通知用户所调用的数据回调函数
|
||||
*
|
||||
* @param[in] handle shadow会话句柄
|
||||
* @param[in] recv shadow接受消息结构体, 存放收到的shadow报文内容
|
||||
* @param[in] userdata 指向用户上下文数据的指针, 这个指针由用户通过调用@ref aiot_shadow_setopt 配置@ref AIOT_SHADOWOPT_USERDATA 选项设置
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (* aiot_shadow_recv_handler_t)(void *handle,
|
||||
const aiot_shadow_recv_t *recv, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief 创建shadow会话实例, 并以默认值配置会话参数
|
||||
*
|
||||
* @return void *
|
||||
* @retval 非NULL shadow实例的句柄
|
||||
* @retval NULL 初始化失败, 一般是内存分配失败导致
|
||||
*
|
||||
*/
|
||||
void *aiot_shadow_init(void);
|
||||
|
||||
/**
|
||||
* @brief 配置shadow会话
|
||||
*
|
||||
* @param[in] handle shadow会话句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_shadow_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_shadow_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 参数配置成功
|
||||
* @retval STATE_USER_INPUT_NULL_POINTER 入参handle或data为NULL
|
||||
* @retval STATE_USER_INPUT_OUT_RANGE 入参optioin的枚举值>=AIOT_SHADOWOPT_MAX
|
||||
* @retval others 参考@ref aiot_state_api.h
|
||||
*
|
||||
*/
|
||||
int32_t aiot_shadow_setopt(void *handle, aiot_shadow_option_t option, void *data);
|
||||
|
||||
/**
|
||||
* @brief 向服务器发送shadow消息请求
|
||||
*
|
||||
* @param[in] handle shadow会话句柄
|
||||
* @param[in] msg 消息结构体, 可指定发送消息的设备<i>productKey</i>, <i>deviceName</i>; 消息类型, 消息数据等, 更多信息请参考@ref aiot_shadow_msg_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 请求发送成功
|
||||
* @retval STATE_USER_INPUT_NULL_POINTER 入参<i>handle</i>或<i>msg</i>为NULL
|
||||
* @retval STATE_USER_INPUT_OUT_RANGE 入参<i>msg</i>的结构体成员<i>type</i> >= AIOT_SHADOWMSG_MAX
|
||||
* @retval STATE_SYS_DEPEND_MALLOC_FAILED 内存分配失败
|
||||
* @retval STATE_SHADOW_MQTT_HANDLE_IS_NULL 用户未调用@ref aiot_shadow_setopt 配置MQTT句柄
|
||||
* @retval others 参考@ref aiot_state_api.h 或@ref STATE_SHADOW_BASE 中对应的错误码说明
|
||||
*
|
||||
*/
|
||||
int32_t aiot_shadow_send(void *handle, aiot_shadow_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief 结束shadow会话, 销毁实例并回收资源
|
||||
*
|
||||
* @param[in] handle 指向shadow会话句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 执行成功
|
||||
* @retval <STATE_SUCCESS 执行失败
|
||||
*
|
||||
*/
|
||||
int32_t aiot_shadow_deinit(void **handle);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AIOT_SHADOW_API_H__ */
|
||||
|
||||
53
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/shadow/shadow_private.h
vendored
Normal file
53
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/shadow/shadow_private.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @file shadow_private.h
|
||||
* @brief shadow模块内部的宏定义和数据结构声明, 不面向其它模块, 更不面向用户
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __SHADOW_PRIVATE_H__
|
||||
#define __SHADOW_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 用这种方式包含标准C库的头文件 */
|
||||
#include "core_stdinc.h"
|
||||
|
||||
#include "aiot_state_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_mqtt_api.h"
|
||||
#include "aiot_shadow_api.h"
|
||||
|
||||
/* shadow模块内部的会话句柄结构体, SDK用户不可见, 只能得到void *handle类型的指针 */
|
||||
typedef struct {
|
||||
aiot_sysdep_portfile_t *sysdep;
|
||||
void *mqtt_handle;
|
||||
|
||||
aiot_shadow_recv_handler_t recv_handler;
|
||||
void *userdata;
|
||||
} shadow_handle_t;
|
||||
|
||||
#define SHADOW_MODULE_NAME "shadow"
|
||||
|
||||
#define SHADOW_UPDATE_TOPIC_FMT "/shadow/update/%s/%s"
|
||||
#define SHADOW_GET_TOPIC "/shadow/get/+/+"
|
||||
|
||||
#define SHADOW_PAYLOAD_REQ_FMT "{\"method\":\"%s\",\"state\":{\"reported\":%s},\"version\":%s}"
|
||||
#define SHADOW_PAYLOAD_CLEAN_FMT "{\"method\":\"update\",\"state\":{\"desired\":\"null\"},\"version\":%s}"
|
||||
#define SHADOW_PAYLOAD_GET "{\"method\":\"get\"}"
|
||||
|
||||
#define SHADOW_JSON_KEY_METHOD "method"
|
||||
#define SHADOW_JSON_KEY_PAYLOAD "payload"
|
||||
#define SHADOW_JSON_KEY_STATUS "status"
|
||||
#define SHADOW_JSON_KEY_TIMESTAMP "timestamp"
|
||||
#define SHADOW_JSON_KEY_STATE "state"
|
||||
#define SHADOW_JSON_KEY_VERSION "version"
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* __SHADOW_PRIVATE_H__ */
|
||||
|
||||
2
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/task/README.md
vendored
Normal file
2
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/task/README.md
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Name: 任务管理模块
|
||||
Task Component for Link SDK V4.0.0
|
||||
777
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/task/aiot_task_api.c
vendored
Normal file
777
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/task/aiot_task_api.c
vendored
Normal file
@@ -0,0 +1,777 @@
|
||||
/**
|
||||
* @file aiot_task_api.c
|
||||
* @brief TASK模块接口实现文件, 其中包含了TASK的所有用户API
|
||||
* @date 2019-12-27
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
#include "core_mqtt.h"
|
||||
#include "core_string.h"
|
||||
#include "core_log.h"
|
||||
#include "core_global.h"
|
||||
#include "task_private.h"
|
||||
#include "aiot_task_api.h"
|
||||
|
||||
static void _task_recv_notify_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
static void _task_recv_get_reply_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
static void _task_recv_update_reply_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata);
|
||||
|
||||
static const task_status_map_t g_task_stauts_mapping[] = {
|
||||
{"QUEUED", AIOT_TASK_STATUS_QUEUED},
|
||||
{"SENT", AIOT_TASK_STATUS_SENT},
|
||||
{"IN_PROGRESS", AIOT_TASK_STATUS_IN_PROGRESS},
|
||||
{"SUCCEEDED", AIOT_TASK_STATUS_SUCCEEDED},
|
||||
{"FAILED", AIOT_TASK_STATUS_FAILED},
|
||||
{"REJECTED", AIOT_TASK_STATUS_REJECTED},
|
||||
{"CANCELLED", AIOT_TASK_STATUS_CANCELLED},
|
||||
{"REMOVED", AIOT_TASK_STATUS_REMOVED},
|
||||
{"TIMED_OUT", AIOT_TASK_STATUS_TIMED_OUT}
|
||||
};
|
||||
|
||||
static const task_recv_topic_map_t g_task_recv_topic_mapping[] = {
|
||||
{
|
||||
"/sys/+/+/thing/job/notify",
|
||||
_task_recv_notify_handler,
|
||||
},
|
||||
{
|
||||
"/sys/+/+/thing/job/get_reply",
|
||||
_task_recv_get_reply_handler,
|
||||
},
|
||||
{
|
||||
"/sys/+/+/thing/job/update_reply",
|
||||
_task_recv_update_reply_handler,
|
||||
}
|
||||
};
|
||||
|
||||
static char *_task_convert_status_to_str(aiot_task_status_t status)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
|
||||
for (i = 0; i < sizeof(g_task_stauts_mapping) / sizeof(task_status_map_t); i++) {
|
||||
if (g_task_stauts_mapping[i].status == status) {
|
||||
return g_task_stauts_mapping[i].str;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static aiot_task_status_t _task_cover_status_to_enum(char *str)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
|
||||
if (NULL == str) {
|
||||
return AIOT_TASK_STATUS_FAILED;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(g_task_stauts_mapping) / sizeof(task_status_map_t); i++) {
|
||||
if (strcmp(g_task_stauts_mapping[i].str, str) == 0) {
|
||||
return g_task_stauts_mapping[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
return AIOT_TASK_STATUS_FAILED;
|
||||
}
|
||||
|
||||
static int32_t _task_parse_json(aiot_sysdep_portfile_t *sysdep, const void *input, uint32_t input_len, char *key_word,
|
||||
char **out)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *value = NULL, *buffer = NULL;
|
||||
uint32_t value_len = 0, buffer_len = 0;
|
||||
|
||||
res = core_json_value((const char *)input, input_len, key_word, strlen(key_word), &value, &value_len);
|
||||
if (res != STATE_SUCCESS) {
|
||||
return STATE_TASK_PARSE_JSON_ERROR;
|
||||
}
|
||||
buffer_len = value_len + 1;
|
||||
buffer = sysdep->core_sysdep_malloc(buffer_len, TASK_MODULE_NAME);
|
||||
if (NULL == buffer) {
|
||||
return STATE_TASK_PARSE_JSON_MALLOC_FAILED;
|
||||
}
|
||||
memset(buffer, 0, buffer_len);
|
||||
memcpy(buffer, value, value_len);
|
||||
*out = buffer;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t _task_parse_task_detail(task_handle_t *task_handle, const char *payload, uint32_t payload_len,
|
||||
task_desc_t *task)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *status = NULL;
|
||||
char *job_file_key = "jobFile";
|
||||
char *job_file_value = NULL;
|
||||
uint32_t job_file_len = 0;
|
||||
|
||||
if (STATE_SUCCESS != _task_parse_json(task_handle->sysdep, payload, payload_len, "taskId", &(task->task_id))) {
|
||||
return STATE_TASK_PARSE_JSON_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
if (STATE_SUCCESS != _task_parse_json(task_handle->sysdep, payload, payload_len, "status", &status)) {
|
||||
return STATE_TASK_PARSE_JSON_MALLOC_FAILED;
|
||||
}
|
||||
task->status = _task_cover_status_to_enum(status);
|
||||
task_handle->sysdep->core_sysdep_free(status);
|
||||
|
||||
if (STATE_SUCCESS != _task_parse_json(task_handle->sysdep, payload, payload_len, "jobDocument",
|
||||
&(task->job_document))) {
|
||||
core_log(task_handle->sysdep, STATE_TASK_RECV_NOTIFY, "parse jobDocument failed\r\n");
|
||||
};
|
||||
|
||||
if ((res = core_json_value(payload, payload_len, job_file_key, (uint32_t)strlen(job_file_key),
|
||||
&job_file_value, &job_file_len)) != STATE_SUCCESS) {
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
if (STATE_SUCCESS != _task_parse_json(task_handle->sysdep, job_file_value, job_file_len, "signMethod",
|
||||
&(task->sign_method))) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (STATE_SUCCESS != _task_parse_json(task_handle->sysdep, job_file_value, job_file_len, "sign", &(task->sign))) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (STATE_SUCCESS != _task_parse_json(task_handle->sysdep, job_file_value, job_file_len, "fileUrl",
|
||||
&(task->document_file_url))) {
|
||||
return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _task_free_task_list(task_handle_t *task_handle, task_get_list_reply_t *list)
|
||||
{
|
||||
int32_t i = 0;
|
||||
if (NULL == list->tasks) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < list->number; i++) {
|
||||
if (list->tasks[i].task_id) {
|
||||
task_handle->sysdep->core_sysdep_free(list->tasks[i].task_id);
|
||||
}
|
||||
}
|
||||
task_handle->sysdep->core_sysdep_free(list->tasks);
|
||||
}
|
||||
|
||||
static void _task_free_task_detail(task_handle_t *task_handle, task_desc_t *task)
|
||||
{
|
||||
aiot_sysdep_portfile_t *sysdep = aiot_sysdep_get_portfile();
|
||||
if (NULL == task) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (task->task_id) {
|
||||
sysdep->core_sysdep_free(task->task_id);
|
||||
}
|
||||
|
||||
if (task->job_document) {
|
||||
sysdep->core_sysdep_free(task->job_document);
|
||||
}
|
||||
|
||||
if (task->sign_method) {
|
||||
sysdep->core_sysdep_free(task->sign_method);
|
||||
}
|
||||
|
||||
if (task->sign) {
|
||||
sysdep->core_sysdep_free(task->sign);
|
||||
}
|
||||
|
||||
if (task->document_file_url) {
|
||||
sysdep->core_sysdep_free(task->document_file_url);
|
||||
}
|
||||
}
|
||||
|
||||
static void _task_free_update_reply(task_update_reply_t *reply)
|
||||
{
|
||||
aiot_sysdep_portfile_t *sysdep = aiot_sysdep_get_portfile();
|
||||
if (NULL == reply) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply->task_id) {
|
||||
sysdep->core_sysdep_free(reply->task_id);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _task_send_notify_reply(task_handle_t *task_handle, char *msg_id, uint32_t code)
|
||||
{
|
||||
char *topic = NULL, *payload = NULL;
|
||||
char code_string[11] = { 0 };
|
||||
char *src[2] = { NULL };
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
core_uint2str(code, code_string, NULL);
|
||||
|
||||
src[0] = msg_id;
|
||||
src[1] = code_string;
|
||||
|
||||
res = core_sprintf(task_handle->sysdep, &payload, TASK_NOTIFY_REPLY_FMT, src, sizeof(src) / sizeof(char *),
|
||||
TASK_MODULE_NAME);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
char *topic_src[] = { core_mqtt_get_product_key(task_handle->mqtt_handle), core_mqtt_get_device_name(task_handle->mqtt_handle) };
|
||||
res = core_sprintf(task_handle->sysdep, &topic, TASK_NOTIFY_REPLY_TOPIC_FMT, topic_src,
|
||||
sizeof(topic_src) / sizeof(char *),
|
||||
TASK_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
task_handle->sysdep->core_sysdep_free(payload);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(task_handle->mqtt_handle, (char *)topic, (uint8_t *)payload, strlen(payload), 0);
|
||||
task_handle->sysdep->core_sysdep_free(topic);
|
||||
task_handle->sysdep->core_sysdep_free(payload);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t _task_parse_notify(task_handle_t *task_handle, const char *payload, uint32_t payload_len,
|
||||
task_desc_t *task)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
char *params_key = "params";
|
||||
char *params_value = NULL;
|
||||
uint32_t params_len = 0;
|
||||
char *task_key = "task";
|
||||
char *task_value = NULL;
|
||||
uint32_t task_len = 0;
|
||||
if ((res = core_json_value(payload, payload_len, params_key, (uint32_t)strlen(params_key),
|
||||
¶ms_value, ¶ms_len)) != STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if ((res = core_json_value(params_value, params_len, task_key, (uint32_t)strlen(task_key),
|
||||
&task_value, &task_len)) != STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = _task_parse_task_detail(task_handle, task_value, task_len, task);
|
||||
if (STATE_SUCCESS != res) {
|
||||
core_log(task_handle->sysdep, STATE_TASK_RECV_NOTIFY, "parse detail failed\r\n");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _task_recv_notify_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
task_handle_t *task_handle = (task_handle_t *)userdata;
|
||||
aiot_task_recv_t recv;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *id = NULL;
|
||||
|
||||
if (NULL == task_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_task_recv_t));
|
||||
recv.type = AIOT_TASKRECV_NOTIFY;
|
||||
|
||||
core_log(task_handle->sysdep, STATE_TASK_RECV_NOTIFY, "task recv notify\r\n");
|
||||
|
||||
if (STATE_SUCCESS != _task_parse_json(task_handle->sysdep, (char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
"id", &id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_task_send_notify_reply(task_handle, id, 200);
|
||||
if (NULL != id) {
|
||||
task_handle->sysdep->core_sysdep_free(id);
|
||||
}
|
||||
|
||||
if ((res = _task_parse_notify(task_handle, (char *)msg->data.pub.payload, msg->data.pub.payload_len,
|
||||
&(recv.data.notify))) == STATE_SUCCESS) {
|
||||
task_handle->recv_handler(task_handle, &recv, task_handle->userdata);
|
||||
} else {
|
||||
core_log(task_handle->sysdep, STATE_TASK_PARSE_NOTIFY_FAILED, "task parse notify failed\r\n");
|
||||
}
|
||||
_task_free_task_detail(task_handle, &(recv.data.notify));
|
||||
}
|
||||
|
||||
static int32_t _task_parse_get_list_reply_array(char *str, int32_t str_len, task_list_json *array)
|
||||
{
|
||||
int32_t num = 0, len = 0;
|
||||
int32_t i = 0, new = 0;
|
||||
|
||||
if ((NULL == str) || (str_len <= 2)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
str++;
|
||||
if (*str == ']') { /* empty array */
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((i < str_len) && (num < TASK_GET_LIST_REPLY_ARRAY_MAX)) {
|
||||
if (*str == '{') {
|
||||
len = 1;
|
||||
new = 1;
|
||||
array[num].pos = str;
|
||||
} else if (*str == '}') {
|
||||
len++;
|
||||
if (new == 1) {
|
||||
array[num].len = len;
|
||||
num++;
|
||||
new = 0;
|
||||
}
|
||||
} else {
|
||||
len++;
|
||||
}
|
||||
str++;
|
||||
i++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static uint32_t _task_parse_get_list_reply(task_handle_t *task_handle, void *input, uint32_t input_len,
|
||||
task_get_list_reply_t *reply)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
task_list_json json_array[TASK_GET_LIST_REPLY_ARRAY_MAX];
|
||||
int32_t num = _task_parse_get_list_reply_array(input, input_len, json_array);
|
||||
reply->number = num;
|
||||
if (0 == num) {
|
||||
return res;
|
||||
}
|
||||
|
||||
task_summary_t *array = task_handle->sysdep->core_sysdep_malloc(sizeof(task_summary_t) * num, TASK_MODULE_NAME);
|
||||
|
||||
if (NULL == array) {
|
||||
return STATE_TASK_PARSE_JSON_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
memset(array, 0, sizeof(task_summary_t)*num);
|
||||
|
||||
reply->tasks = array;
|
||||
|
||||
for (int32_t i = 0; i < num; i++) {
|
||||
if (STATE_SUCCESS != _task_parse_json(task_handle->sysdep, json_array[i].pos, json_array[i].len, "taskId",
|
||||
&(array[i].task_id))) {
|
||||
return res;
|
||||
}
|
||||
|
||||
char *status = NULL;
|
||||
if (STATE_SUCCESS != _task_parse_json(task_handle->sysdep, json_array[i].pos, json_array[i].len, "status", &status)) {
|
||||
return res;
|
||||
}
|
||||
|
||||
array[i].status = _task_cover_status_to_enum(status);
|
||||
task_handle->sysdep->core_sysdep_free(status);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _task_recv_get_reply_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
task_handle_t *task_handle = (task_handle_t *)userdata;
|
||||
aiot_task_recv_t recv;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == task_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_task_recv_t));
|
||||
|
||||
char *code_key = "code";
|
||||
char *code_value = NULL;
|
||||
uint32_t code_len = 0;
|
||||
if (core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len, code_key, (uint32_t)strlen(code_key),
|
||||
&code_value, &code_len) != STATE_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (core_str2uint(code_value, (uint8_t)code_len, &(recv.data.get_detail_reply.code)) != STATE_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *data_key = "data";
|
||||
char *data_value = NULL;
|
||||
uint32_t data_len = 0;
|
||||
if (core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len, data_key, (uint32_t)strlen(data_key),
|
||||
&data_value, &data_len) != STATE_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *tasks_key = "tasks";
|
||||
char *tasks_value = NULL;
|
||||
uint32_t tasks_len = 0;
|
||||
if (core_json_value(data_value, data_len, tasks_key, (uint32_t)strlen(tasks_key),
|
||||
&tasks_value, &tasks_len) == STATE_SUCCESS) {
|
||||
recv.type = AIOT_TASKRECV_GET_LIST_REPLY;
|
||||
task_get_list_reply_t *reply = &(recv.data.get_list_reply);
|
||||
if ((res = _task_parse_get_list_reply(task_handle, tasks_value, tasks_len, reply)) == STATE_SUCCESS) {
|
||||
task_handle->recv_handler(task_handle, &recv, task_handle->userdata);
|
||||
}
|
||||
_task_free_task_list(task_handle, &(recv.data.get_list_reply));
|
||||
return;
|
||||
}
|
||||
|
||||
char *task_key = "task";
|
||||
char *task_value = NULL;
|
||||
uint32_t task_len = 0;
|
||||
if (core_json_value(data_value, data_len, task_key, (uint32_t)strlen(task_key),
|
||||
&task_value, &task_len) == STATE_SUCCESS) {
|
||||
recv.type = AIOT_TASKRECV_GET_DETAIL_REPLY;
|
||||
task_desc_t *task = &(recv.data.get_detail_reply.task);
|
||||
if ((res = _task_parse_task_detail(task_handle, task_value, task_len, task)) == STATE_SUCCESS) {
|
||||
task_handle->recv_handler(task_handle, &recv, task_handle->userdata);
|
||||
}
|
||||
_task_free_task_detail(task_handle, task);
|
||||
return;
|
||||
}
|
||||
|
||||
char *task_id_key = "taskId";
|
||||
char *task_id_value = NULL;
|
||||
uint32_t task_id_len = 0;
|
||||
if (core_json_value(data_value, data_len, task_id_key, (uint32_t)strlen(task_id_key),
|
||||
&task_id_value, &task_id_len) == STATE_SUCCESS) {
|
||||
if (memcmp(task_id_value, TASK_GET_LIST_REPLY_TASK_ID, strlen(TASK_GET_LIST_REPLY_TASK_ID)) == 0) {
|
||||
recv.type = AIOT_TASKRECV_GET_LIST_REPLY;
|
||||
task_get_list_reply_t *reply = &(recv.data.get_list_reply);
|
||||
reply->number = 0;
|
||||
task_handle->recv_handler(task_handle, &recv, task_handle->userdata);
|
||||
} else {
|
||||
recv.type = AIOT_TASKRECV_GET_DETAIL_REPLY;
|
||||
task_desc_t *task = &(recv.data.get_detail_reply.task);
|
||||
|
||||
char *id = task_handle->sysdep->core_sysdep_malloc(task_id_len + 1, TASK_MODULE_NAME);
|
||||
memset(id, 0, task_id_len + 1);
|
||||
memcpy(id, task_id_value, task_id_len);
|
||||
task->task_id = id;
|
||||
task->status = AIOT_TASK_STATUS_NOT_FOUND;
|
||||
task_handle->recv_handler(task_handle, &recv, task_handle->userdata);
|
||||
_task_free_task_detail(task_handle, task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _task_recv_update_reply_handler(void *handle, const aiot_mqtt_recv_t *msg, void *userdata)
|
||||
{
|
||||
task_handle_t *task_handle = (task_handle_t *)userdata;
|
||||
aiot_task_recv_t recv;
|
||||
|
||||
if (NULL == task_handle->recv_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&recv, 0, sizeof(aiot_task_recv_t));
|
||||
recv.type = AIOT_TASKRECV_UPDATE_REPLY;
|
||||
|
||||
char *code_key = "code";
|
||||
char *code_value = NULL;
|
||||
uint32_t code_len = 0;
|
||||
if (core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len, code_key, (uint32_t)strlen(code_key),
|
||||
&code_value, &code_len) != STATE_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (core_str2uint(code_value, (uint8_t)code_len, &(recv.data.get_detail_reply.code)) != STATE_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *data_key = "data";
|
||||
char *data_value = NULL;
|
||||
uint32_t data_len = 0;
|
||||
if (core_json_value((char *)msg->data.pub.payload, msg->data.pub.payload_len, data_key, (uint32_t)strlen(data_key),
|
||||
&data_value, &data_len) != STATE_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (STATE_SUCCESS != _task_parse_json(task_handle->sysdep, data_value, data_len, "taskId",
|
||||
&(recv.data.update_reply.task_id))) {
|
||||
return;
|
||||
}
|
||||
|
||||
task_handle->recv_handler(task_handle, &recv, task_handle->userdata);
|
||||
|
||||
_task_free_update_reply(&(recv.data.update_reply));
|
||||
}
|
||||
|
||||
static int32_t _task_setup_topic_mapping(void *mqtt_handle, void *task_handle)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
aiot_mqtt_topic_map_t topic_mapping;
|
||||
|
||||
for (i = 0; i < sizeof(g_task_recv_topic_mapping) / sizeof(task_recv_topic_map_t); i++) {
|
||||
topic_mapping.topic = g_task_recv_topic_mapping[i].topic;
|
||||
topic_mapping.handler = g_task_recv_topic_mapping[i].func;
|
||||
topic_mapping.userdata = task_handle;
|
||||
|
||||
res = aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_APPEND_TOPIC_MAP, &topic_mapping);
|
||||
if (STATE_SUCCESS != res) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _task_core_mqtt_process_handler(void *context, aiot_mqtt_event_t *event, core_mqtt_event_t *core_event)
|
||||
{
|
||||
task_handle_t *task_handle = (task_handle_t *)context;
|
||||
|
||||
if (core_event != NULL) {
|
||||
switch (core_event->type) {
|
||||
case CORE_MQTTEVT_DEINIT: {
|
||||
task_handle->mqtt_handle = NULL;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _task_core_mqtt_operate_process_handler(task_handle_t *task_handle, core_mqtt_option_t option)
|
||||
{
|
||||
core_mqtt_process_data_t process_data;
|
||||
|
||||
memset(&process_data, 0, sizeof(core_mqtt_process_data_t));
|
||||
process_data.handler = _task_core_mqtt_process_handler;
|
||||
process_data.context = task_handle;
|
||||
|
||||
return core_mqtt_setopt(task_handle->mqtt_handle, option, &process_data);
|
||||
}
|
||||
|
||||
static int32_t _task_send_query_task(task_handle_t *task_handle, char *task_id)
|
||||
{
|
||||
char *topic = NULL, *payload = NULL;
|
||||
int32_t id = 0;
|
||||
char id_string[11] = { 0 };
|
||||
char *src[2] = { NULL };
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == task_id) {
|
||||
return STATE_TASK_QUERY_TASK_ID_IS_NULL;
|
||||
}
|
||||
|
||||
core_global_alink_id_next(task_handle->sysdep, &id);
|
||||
core_int2str(id, id_string, NULL);
|
||||
|
||||
src[0] = id_string;
|
||||
src[1] = task_id;
|
||||
|
||||
res = core_sprintf(task_handle->sysdep, &payload, TASK_REQUEST_QUERY_TASK_FMT, src, sizeof(src) / sizeof(char *),
|
||||
TASK_MODULE_NAME);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
char *topic_src[] = { core_mqtt_get_product_key(task_handle->mqtt_handle), core_mqtt_get_device_name(task_handle->mqtt_handle) };
|
||||
res = core_sprintf(task_handle->sysdep, &topic, TASK_QUERY_TASK_TOPIC_FMT, topic_src,
|
||||
sizeof(topic_src) / sizeof(char *),
|
||||
TASK_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
task_handle->sysdep->core_sysdep_free(payload);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(task_handle->mqtt_handle, (char *)topic, (uint8_t *)payload, strlen(payload), 0);
|
||||
task_handle->sysdep->core_sysdep_free(payload);
|
||||
task_handle->sysdep->core_sysdep_free(topic);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_task_get_task_list(void *handle)
|
||||
{
|
||||
task_handle_t *task_handle = (task_handle_t *)handle;
|
||||
|
||||
if (NULL == handle) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
return _task_send_query_task(task_handle, "$list");
|
||||
}
|
||||
|
||||
int32_t aiot_task_get_task_detail(void *handle, char *task_id)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
task_handle_t *task_handle = (task_handle_t *)handle;
|
||||
|
||||
if (NULL == handle) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (NULL == task_id) {
|
||||
res = _task_send_query_task(task_handle, "$next");
|
||||
} else {
|
||||
res = _task_send_query_task(task_handle, task_id);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_task_update(void *handle, task_desc_t *task)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *topic = NULL, *payload = NULL, *status = NULL;
|
||||
int32_t id = 0;
|
||||
char id_string[11] = { 0 };
|
||||
char progress_string[11] = { 0 };
|
||||
char *src[5] = { NULL };
|
||||
task_handle_t *task_handle = (task_handle_t *)handle;
|
||||
|
||||
if ((NULL == handle) || (NULL == task)) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if ((NULL != task->status_details) && (strcmp(task->status_details, "") == 0)) {
|
||||
return STATE_TASK_UPDATE_STATUS_DETAILS_INVALID;
|
||||
}
|
||||
|
||||
status = _task_convert_status_to_str(task->status);
|
||||
|
||||
if (NULL == status) {
|
||||
return STATE_TASK_UPDATE_STATUS_INVALID;
|
||||
}
|
||||
|
||||
core_global_alink_id_next(task_handle->sysdep, &id);
|
||||
core_int2str(id, id_string, NULL);
|
||||
|
||||
char *topic_src[] = { core_mqtt_get_product_key(task_handle->mqtt_handle), core_mqtt_get_device_name(task_handle->mqtt_handle) };
|
||||
res = core_sprintf(task_handle->sysdep, &topic, TASK_UPDATE_TASK_TOPIC_FMT, topic_src,
|
||||
sizeof(topic_src) / sizeof(char *),
|
||||
TASK_MODULE_NAME);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
core_uint2str(task->progress, progress_string, NULL);
|
||||
src[0] = id_string;
|
||||
src[1] = task->task_id;
|
||||
src[2] = _task_convert_status_to_str(task->status);
|
||||
src[3] = progress_string;
|
||||
|
||||
if (NULL == task->status_details) {
|
||||
res = core_sprintf(task_handle->sysdep, &payload, TASK_REQUEST_UPDATE_TASK_NO_DETAIL_FMT, src, 4,
|
||||
TASK_MODULE_NAME);
|
||||
} else {
|
||||
src[4] = task->status_details;
|
||||
res = core_sprintf(task_handle->sysdep, &payload, TASK_REQUEST_UPDATE_TASK_FMT, src, sizeof(src) / sizeof(char *),
|
||||
TASK_MODULE_NAME);
|
||||
}
|
||||
|
||||
if (res < STATE_SUCCESS) {
|
||||
task_handle->sysdep->core_sysdep_free(topic);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = aiot_mqtt_pub(task_handle->mqtt_handle, (char *)topic, (uint8_t *)payload, strlen(payload), 0);
|
||||
task_handle->sysdep->core_sysdep_free(topic);
|
||||
task_handle->sysdep->core_sysdep_free(payload);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_task_setopt(void *handle, aiot_task_option_t option, void *data)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
task_handle_t *task_handle = (task_handle_t *)handle;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
|
||||
if (NULL == task_handle) {
|
||||
return STATE_TASK_SETOPT_HANDLE_IS_NULL;
|
||||
}
|
||||
if (NULL == data) {
|
||||
return STATE_TASK_SETOPT_DATA_IS_NULL;
|
||||
}
|
||||
|
||||
sysdep = task_handle->sysdep;
|
||||
sysdep->core_sysdep_mutex_lock(task_handle->data_mutex);
|
||||
switch (option) {
|
||||
case AIOT_TASKOPT_RECV_HANDLER: {
|
||||
task_handle->recv_handler = (aiot_task_recv_handler_t)data;
|
||||
}
|
||||
break;
|
||||
case AIOT_TASKOPT_USERDATA: {
|
||||
task_handle->userdata = data;
|
||||
}
|
||||
break;
|
||||
case AIOT_TASKOPT_MQTT_HANDLE: {
|
||||
task_handle->mqtt_handle = data;
|
||||
res = _task_setup_topic_mapping(data, task_handle);
|
||||
if (res >= STATE_SUCCESS) {
|
||||
res = _task_core_mqtt_operate_process_handler(task_handle, CORE_MQTTOPT_APPEND_PROCESS_HANDLER);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
res = STATE_USER_INPUT_UNKNOWN_OPTION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
sysdep->core_sysdep_mutex_unlock(task_handle->data_mutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void *aiot_task_init(void)
|
||||
{
|
||||
task_handle_t *task_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if (sysdep == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
task_handle = sysdep->core_sysdep_malloc(sizeof(task_handle_t), TASK_MODULE_NAME);
|
||||
if (task_handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(task_handle, 0, sizeof(task_handle_t));
|
||||
task_handle->sysdep = sysdep;
|
||||
task_handle->data_mutex = sysdep->core_sysdep_mutex_init();
|
||||
core_global_init(sysdep);
|
||||
return task_handle;
|
||||
}
|
||||
|
||||
int32_t aiot_task_deinit(void **p_handle)
|
||||
{
|
||||
task_handle_t *task_handle = NULL;
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
uint8_t i = 0;
|
||||
|
||||
if (NULL == p_handle || NULL == *p_handle) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
task_handle = *p_handle;
|
||||
sysdep = task_handle->sysdep;
|
||||
*p_handle = NULL;
|
||||
|
||||
_task_core_mqtt_operate_process_handler(task_handle, CORE_MQTTOPT_REMOVE_PROCESS_HANDLER);
|
||||
|
||||
/* remove mqtt topic mapping */
|
||||
for (i = 0; i < sizeof(g_task_recv_topic_mapping) / sizeof(task_recv_topic_map_t); i++) {
|
||||
aiot_mqtt_topic_map_t topic_mapping;
|
||||
memset(&topic_mapping, 0, sizeof(aiot_mqtt_topic_map_t));
|
||||
topic_mapping.topic = g_task_recv_topic_mapping[i].topic;
|
||||
topic_mapping.handler = g_task_recv_topic_mapping[i].func;
|
||||
|
||||
aiot_mqtt_setopt(task_handle->mqtt_handle, AIOT_MQTTOPT_REMOVE_TOPIC_MAP, &topic_mapping);
|
||||
}
|
||||
|
||||
if (task_handle->data_mutex != NULL) {
|
||||
sysdep->core_sysdep_mutex_deinit(&task_handle->data_mutex);
|
||||
}
|
||||
|
||||
sysdep->core_sysdep_free(task_handle);
|
||||
|
||||
core_global_deinit(sysdep);
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
325
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/task/aiot_task_api.h
vendored
Normal file
325
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/task/aiot_task_api.h
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* @file aiot_task_api.h
|
||||
* @brief task模块头文件, 提供任务管理的能力
|
||||
* @date 2020-11-25
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
* @details
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AIOT_TASK_API_H__
|
||||
#define __AIOT_TASK_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief -0x0B00~-0x0BFF表达SDK在task模块内的状态码
|
||||
*
|
||||
*/
|
||||
#define STATE_TASK_BASE (-0x0B00)
|
||||
|
||||
/**
|
||||
* @brief 销毁task会话实例时, 发现会话句柄为空, 中止销毁动作
|
||||
*
|
||||
*/
|
||||
#define STATE_TASK_DEINIT_HANDLE_IS_NULL (-0x0B01)
|
||||
|
||||
/**
|
||||
* @brief 配置task会话实例时, 发现会话句柄为空, 中止配置动作
|
||||
*
|
||||
*/
|
||||
#define STATE_TASK_SETOPT_HANDLE_IS_NULL (-0x0B02)
|
||||
|
||||
/**
|
||||
* @brief 接收到服务器notify下行消息时的日志状态码
|
||||
*/
|
||||
#define STATE_TASK_RECV_NOTIFY (-0x0B03)
|
||||
|
||||
/**
|
||||
* @brief 解析服务器下推的MQTT下行JSON报文时出错
|
||||
*/
|
||||
#define STATE_TASK_PARSE_NOTIFY_FAILED (-0x0B04)
|
||||
|
||||
/**
|
||||
* @brief 为解析JSON报文而申请内存时, 未获取到所需内存而解析失败
|
||||
*/
|
||||
#define STATE_TASK_PARSE_JSON_MALLOC_FAILED (-0x0B05)
|
||||
|
||||
/**
|
||||
* @brief 接收到服务器notify下行消息时的日志状态码
|
||||
*/
|
||||
#define STATE_TASK_PARSE_JSON_ERROR (-0x0B06)
|
||||
|
||||
/**
|
||||
* @brief 接收到查询task id是空
|
||||
*/
|
||||
#define STATE_TASK_QUERY_TASK_ID_IS_NULL (-0x0B07)
|
||||
|
||||
/**
|
||||
* @brief 接收到服务器get list reply下行消息时的日志状态码
|
||||
*/
|
||||
#define STATE_TASK_RECV_GET_LIST_REPLY (-0x0B08)
|
||||
|
||||
/**
|
||||
* @brief 配置task会话实例时, 发现会话句柄为空, 中止配置动作
|
||||
*
|
||||
*/
|
||||
#define STATE_TASK_SETOPT_DATA_IS_NULL (-0x0B09)
|
||||
|
||||
/**
|
||||
* @brief 配置task 描述时状态设置不对
|
||||
*
|
||||
*/
|
||||
#define STATE_TASK_UPDATE_STATUS_INVALID (-0x0B0A)
|
||||
|
||||
/**
|
||||
* @brief aiot_task_setopt 接口的option参数可选值.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief update task的时候task status_details只能为NULL或者json字符串对象
|
||||
*
|
||||
*/
|
||||
#define STATE_TASK_UPDATE_STATUS_DETAILS_INVALID (-0x0B0B)
|
||||
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 设置MQTT的handle
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* OTA过程中使用MQTT的通道能力, 用以向云端上报版本号, 进度, 以及错误码
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_TASKOPT_MQTT_HANDLE,
|
||||
|
||||
/**
|
||||
* @brief 设置处理task消息的用户回调函数
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 从云端下发或者返回的数据的处理函数
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_TASKOPT_RECV_HANDLER,
|
||||
|
||||
/**
|
||||
* @brief 用户需要SDK暂存的上下文
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 这个上下文指针会在 AIOT_TASKOPT_RECV_HANDLER设置的回调被调用时, 由SDK传给用户
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_TASKOPT_USERDATA,
|
||||
AIOT_TASKOPT_MAX
|
||||
} aiot_task_option_t;
|
||||
|
||||
/**
|
||||
* @brief 任务的状态.
|
||||
*/
|
||||
typedef enum {
|
||||
AIOT_TASK_STATUS_QUEUED, /* 服务端设置的状态: 任务处于队列中, 还没有推送 */
|
||||
AIOT_TASK_STATUS_SENT, /* 服务端设置的状态: 任务已推送 */
|
||||
AIOT_TASK_STATUS_IN_PROGRESS, /* 设备端设置的状态: 任务进行中. 设备端开始执行一个任务后, 将 */
|
||||
AIOT_TASK_STATUS_SUCCEEDED, /* 设备端设置的状态: 任务完成 */
|
||||
AIOT_TASK_STATUS_FAILED, /* 设备端设置的状态: 任务执行失败 */
|
||||
AIOT_TASK_STATUS_REJECTED, /* 设备端设置的状态: 设备端拒绝执行任务 */
|
||||
AIOT_TASK_STATUS_CANCELLED, /* 服务端设置的状态: 任务被服务端取消 */
|
||||
AIOT_TASK_STATUS_REMOVED, /* 服务端设置的状态: 任务从服务端删除 */
|
||||
AIOT_TASK_STATUS_TIMED_OUT, /* 服务端设置的状态: 任务执行超时 */
|
||||
AIOT_TASK_STATUS_NOT_FOUND /* 服务端设置的状态: 没有找到此任务相关信息 */
|
||||
} aiot_task_status_t;
|
||||
|
||||
/**
|
||||
* @brief 下行有关的数据结构
|
||||
*/
|
||||
typedef enum {
|
||||
AIOT_TASKRECV_NOTIFY, /* 对应/sys/{productKey}/{deviceName}/thing/job/notify 这个下行topic, 云端主动下推, 带任务详情 */
|
||||
AIOT_TASKRECV_GET_DETAIL_REPLY, /* 对应/sys/{productKey}/{deviceName}/thing/job/get_reply 这个下行topic, 可以是单个任务的详情, 也可以是任务列表的简单描述 */
|
||||
AIOT_TASKRECV_GET_LIST_REPLY, /* 对应/sys/{productKey}/{deviceName}/thing/job/get_reply 这个下行topic, 可以是单个任务的详情, 也可以是任务列表的简单描述 */
|
||||
AIOT_TASKRECV_UPDATE_REPLY /* 对应/sys/{productKey}/{deviceName}/thing/job/update_reply 这个下行topic, 里面包含某个任务的update的结果, 即是否成功 */
|
||||
} aiot_task_recv_type_t;
|
||||
|
||||
/**
|
||||
* @brief 任务描述的数据结构
|
||||
*/
|
||||
typedef struct {
|
||||
char *task_id; /* 任务ID */
|
||||
aiot_task_status_t status; /* 任务的状态 */
|
||||
char *job_document; /* 任务执行规则 */
|
||||
char *sign_method; /* 文件签名的方法 */
|
||||
char *sign; /* 文件的签名 */
|
||||
char *document_file_url; /* 任务文件下载的url */
|
||||
char *status_details; /* 客户自定义状态,透传到云端, 注意格式为json对象,例如 "{\"key\": \"value\"", strlen("\"key\": \"value\"}"*/
|
||||
uint8_t progress; /* 任务处理的进度,数字从0-100 */
|
||||
void *handle; /* 任务处理的句柄 */
|
||||
} task_desc_t;
|
||||
|
||||
/**
|
||||
* @brief 从云端拉取list时每个任务的简要描述
|
||||
*/
|
||||
typedef struct {
|
||||
char *task_id; /* 任务ID */
|
||||
aiot_task_status_t status; /* 任务的状态 */
|
||||
} task_summary_t;
|
||||
|
||||
/**
|
||||
* @brief 从云端拉取list返回的数据
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t number; /* 从云端拉取的任务list的大小 */
|
||||
task_summary_t *tasks; /* 拉取的任务数组指针 */
|
||||
} task_get_list_reply_t;
|
||||
|
||||
/**
|
||||
* @brief 从云端拉取任务详细信息时返回的数据
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t code; /* 云端返回的code */
|
||||
task_desc_t task; /* 任务描述的详细信息 */
|
||||
} task_get_detail_reply_t;
|
||||
|
||||
/**
|
||||
* @brief 更新任务状态到云端后,云端返回的数据
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t code; /* 云端返回的code */
|
||||
char *task_id; /* 更新任务后返回的任务id */
|
||||
aiot_task_status_t status; /* 更新任务后返回的状态 */
|
||||
} task_update_reply_t;
|
||||
|
||||
/**
|
||||
* @brief 云端主动下发或更新任务云端返回的数据
|
||||
*/
|
||||
typedef struct {
|
||||
aiot_task_recv_type_t type; /* 返回的数据类型 */
|
||||
union {
|
||||
task_desc_t notify; /* 云端主动推送任务的数据 */
|
||||
task_get_list_reply_t get_list_reply; /* 请求任务list返回的数据 */
|
||||
task_get_detail_reply_t get_detail_reply; /* 请求任务详细状态返回的数据 */
|
||||
task_update_reply_t update_reply; /* 更新任务状态返回的数据 */
|
||||
} data;
|
||||
} aiot_task_recv_t;
|
||||
|
||||
/**
|
||||
* @brief 设备收到task的mqtt下行报文时的接收回调函数
|
||||
*
|
||||
* @param[in] handle task实例句柄
|
||||
* @param[in] recv 云端下行的消息
|
||||
* @param[in] userdata 用户上下文
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
typedef void (* aiot_task_recv_handler_t)(void *handle, const aiot_task_recv_t *recv, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief 创建一个task实例
|
||||
*
|
||||
* @return void*
|
||||
* @retval 非NULL task实例句柄
|
||||
* @retval NULL 初始化失败, 或者是因为没有设置portfile, 或者是内存分配失败导致
|
||||
*
|
||||
*/
|
||||
void *aiot_task_init(void);
|
||||
|
||||
/**
|
||||
* @brief 销毁task实例句柄
|
||||
*
|
||||
* @param[in] handle 指向task实例句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_USER_INPUT_NULL_POINTER handle或者handle所指向的地址为空
|
||||
* @retval STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_task_deinit(void **handle);
|
||||
|
||||
/**
|
||||
* @brief 设置task句柄的参数
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 对task会话进行配置, 常见的配置选项包括
|
||||
*
|
||||
* @param[in] handle task句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_task_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_task_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_TASK_SETOPT_HANDLE_IS_NULL task句柄为空
|
||||
* @retval STATE_TASK_SETOPT_DATA_IS_NULL 参数data字段为空
|
||||
* @retval STATE_USER_INPUT_UNKNOWN_OPTION option不支持
|
||||
* @retval STATE_SUCCESS 参数设置成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_task_setopt(void *handle, aiot_task_option_t option, void *data);
|
||||
|
||||
/**
|
||||
* @brief 从云端获取task列表
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 从云端获取task列表
|
||||
*
|
||||
* @param[in] handle task句柄
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_TASK_SETOPT_DATA_IS_NULL 参数的handle字段为空
|
||||
* @retval STATE_SUCCESS 发送成功
|
||||
*/
|
||||
int32_t aiot_task_get_task_list(void *handle);
|
||||
|
||||
/* 发送报文到/sys/{productKey}/{deviceName}/thing/job/get. 若函数入参user_task_id不为空, 则上行报文的payload为 "taskId": user_task_id, 返回该任务的详情; */
|
||||
/* 若user_task_id为空, 则上行报文的payload为 "taskId": "$next", 云端返回未处于终态的任务队列中时间排在最前面一个任务, 该任务状态为QUEUED、SENT、IN_PROGRESS三者之一 */
|
||||
|
||||
/**
|
||||
* @brief 从云端获取task详细内容
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 从云端获取task详细内容
|
||||
*
|
||||
* @param[in] handle task句柄
|
||||
* @param[in] user_task_id task的id或者$next
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_TASK_SETOPT_DATA_IS_NULL或user_task_id 参数的handle字段为空
|
||||
* @retval STATE_SUCCESS 发送成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_task_get_task_detail(void *handle, char *user_task_id);
|
||||
|
||||
/**
|
||||
* @brief 更新任务状态到云端
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 更新任务状态到云端
|
||||
*
|
||||
* @param[in] handle task句柄
|
||||
* @param[in] task task信息
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_TASK_SETOPT_DATA_IS_NULL或task 参数的handle字段为空
|
||||
* @retval STATE_SUCCESS 更新成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_task_update(void *handle, task_desc_t *task);
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef __AIOT_TASK_API_H__ */
|
||||
|
||||
|
||||
74
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/task/task_private.h
vendored
Normal file
74
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/task/task_private.h
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
/**
|
||||
* @file task_private.h
|
||||
* @brief task模块内部的宏定义和数据结构声明, 不面向其它模块, 更不面向用户
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
#ifndef __TASK_PRIVATE_H__
|
||||
#define __TASK_PRIVATE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 用这种方式包含标准C库的头文件 */
|
||||
#include "core_stdinc.h"
|
||||
|
||||
/* TODO: 这一段列出需要包含SDK其它模块头文件, 与上一段落以1个空行隔开 */
|
||||
#include "aiot_state_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_mqtt_api.h"
|
||||
#include "aiot_task_api.h"
|
||||
|
||||
#define TASK_MODULE_NAME "TASK"
|
||||
|
||||
#define TASK_NOTIFY_TOPIC "/sys/+/+/thing/job/notify_reply"
|
||||
#define TASK_QUERY_RESPONSE_TOPIC "/sys/+/+/thing/job/get_reply"
|
||||
|
||||
#define TASK_QUERY_TASK_TOPIC_FMT "/sys/%s/%s/thing/job/get"
|
||||
#define TASK_UPDATE_TASK_TOPIC_FMT "/sys/%s/%s/thing/job/update"
|
||||
#define TASK_NOTIFY_REPLY_TOPIC_FMT "/sys/%s/%s/thing/job/notify_reply"
|
||||
|
||||
/* ALINK请求的JSON格式 */
|
||||
#define TASK_REQUEST_QUERY_TASK_FMT "{\"id\":\"%s\",\"version\":\"1.0.0\",\"params\":{\"taskId\":\"%s\"}}"
|
||||
#define TASK_REQUEST_UPDATE_TASK_FMT "{\"id\":\"%s\",\"version\":\"1.0.0\",\"params\":{\"taskId\":\"%s\",\"status\":\"%s\",\"progress\":%s,\"statusDetails\":%s}}"
|
||||
#define TASK_REQUEST_UPDATE_TASK_NO_DETAIL_FMT "{\"id\":\"%s\",\"version\":\"1.0.0\",\"params\":{\"taskId\":\"%s\",\"status\":\"%s\",\"progress\":%s}}"
|
||||
|
||||
#define TASK_NOTIFY_REPLY_FMT "{\"id\":\"%s\",\"code\":%s,\"data\":{}}"
|
||||
|
||||
#define TASK_GET_LIST_REPLY_ARRAY_MAX 10
|
||||
|
||||
#define TASK_GET_LIST_REPLY_TASK_ID "$list"
|
||||
|
||||
typedef struct {
|
||||
aiot_sysdep_portfile_t *sysdep;
|
||||
aiot_task_recv_handler_t recv_handler;
|
||||
void *mqtt_handle;
|
||||
void *userdata;
|
||||
task_desc_t
|
||||
*default_task_desc; /* handle中用于存储任务描述的数据结构. handle里面只存放一个任务. 如果用户要存放多个,可以自己在外部定义一个列表 */
|
||||
void *data_mutex;
|
||||
} task_handle_t;
|
||||
|
||||
/* 包含下行topic和对应处理函数的结构体定义 */
|
||||
typedef struct {
|
||||
char *topic;
|
||||
aiot_mqtt_recv_handler_t func;
|
||||
} task_recv_topic_map_t;
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
aiot_task_status_t status;
|
||||
} task_status_map_t;
|
||||
|
||||
typedef struct {
|
||||
char *pos;
|
||||
int len;
|
||||
} task_list_json;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* __TASK_PRIVATE_H__ */
|
||||
Reference in New Issue
Block a user