feat: 移植腾讯云物联网开发平台 C SDK

This commit is contained in:
fancyxu
2022-07-01 11:06:09 +08:00
parent 2be1169b0b
commit 0acc079ed6
195 changed files with 36646 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
file(GLOB src ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
set(inc ${CMAKE_CURRENT_SOURCE_DIR}/inc/)
set(src_platform ${src_platform} ${src} PARENT_SCOPE)
set(inc_platform ${inc_platform} ${inc} PARENT_SCOPE)

View File

@@ -0,0 +1,205 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2022 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file qcloud_iot_at_client.h
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2022-05-06
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022-05-06 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#ifndef IOT_HUB_DEVICE_C_SDK_PLATFORM_AT_CLIENT_INC_QCLOUD_IOT_AT_CLIENT_H_
#define IOT_HUB_DEVICE_C_SDK_PLATFORM_AT_CLIENT_INC_QCLOUD_IOT_AT_CLIENT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "qcloud_iot_platform.h"
#define QCLOUD_AT_PARSE_THREAD_NAME "at_parse"
#define QCLOUD_AT_PARSE_THREAD_STACK_SIZE (4096)
#define QCLOUD_AT_PARSE_THREAD_PRIORITY THREAD_PRIORITY_HIGH
#define QCLOUD_AT_URC_THREAD_NAME "at_urc"
#define QCLOUD_AT_URC_THREAD_STACK_SIZE QCLOUD_AT_PARSE_THREAD_STACK_SIZE
#define QCLOUD_AT_URC_THREAD_PRIORITY THREAD_PRIORITY_HIGH
#define QCLOUD_AT_MAX_URC_QUEUE_LEN (16)
typedef enum {
QCLOUD_AT_RET_SUCCESS = 0,
QCLOUD_AT_RET_INITTED = 1,
QCLOUD_AT_ERR_FAILURE = -1,
QCLOUD_AT_ERR_NO_INIT = -2,
QCLOUD_AT_ERR_TIMEOUT = -3,
QCLOUD_AT_ERR_SEND_FAIL = -4,
QCLOUD_AT_ERR_RESP_FAIL = -5,
QCLOUD_AT_ERR_BUFF_SHORT = -5,
} QCloudATErrCode;
/**
* @brief AT urc.
*
*/
typedef struct {
const char *urc_prefix;
OnUrcHandler urc_handle;
} QcloudATUrc;
/**
* @brief Send data to at module.
*
*/
typedef int (*QcloudATSendDataFunc)(const void *data, size_t data_len);
/**
* @brief AT init status.
*
*/
typedef enum {
QCLOUD_AT_STATUS_NO_INIT = 0,
QCLOUD_AT_STATUS_INIT = 1,
} QcloudATStatus;
/**
* @brief AT response status.
*
*/
typedef enum {
QCLOUD_AT_RESP_STATUS_IDLE = 0, /* no change resp status */
QCLOUD_AT_RESP_STATUS_WAIT = 1, /* AT response wait */
QCLOUD_AT_RESP_STATUS_OK = 2, /* AT response OK */
QCLOUD_AT_RESP_STATUS_ERROR = -1, /* AT response ERROR */
} QcloudATRespStatus;
/**
* @brief AT response.
*
*/
typedef struct {
const char *expect;
uint8_t *recv_buf; /* recv data from at buffer */
uint32_t recv_len; /* recv data length */
QcloudATRespStatus status;
} QcloudATResp;
/**
* @brief AT URC Recv handle.
*
*/
typedef struct {
QcloudATUrc *urc;
char *urc_handle_buf;
uint32_t urc_recv_len;
} QcloudATUrcRecv;
/**
* @brief AT client.
*
*/
typedef struct {
QcloudATStatus status;
QcloudATSendDataFunc at_send_func;
// recv data
void *recv_pool;
void *recv_queue;
char *recv_buf;
uint32_t recv_buf_size;
uint32_t recv_len;
// urc
QcloudATUrc *urc_table;
uint32_t urc_table_size;
void *urc_recv_pool;
void *urc_recv_queue;
void *urc_lock;
// resp
QcloudATResp resp;
void *resp_lock;
void *resp_sem;
} QcloudATClient;
/**
* @brief Parse data recv from at module.
*
* @param[in] client pointer to QcloudATClient
*/
void qcloud_iot_at_client_parser(void *client);
/**
* @brief Recv urc and callback.
*
* @param[in] client pointer to QcloudATClient
*/
void qcloud_iot_at_urc_handle(void *client);
/**
* @brief Init at client.
*
* @param[in] max_at_size max at buffer size
* @param[in] at_send_func send at function
* @return @see QCloudATErrCode
*/
int qcloud_iot_at_client_init(int max_at_size, QcloudATSendDataFunc at_send_func);
/**
* @brief Set at urc.
*
* @param[in] urc_table urc table
* @param[in] urc_table_size table size
*/
void qcloud_iot_at_client_set_urc(QcloudATUrc *urc_table, uint32_t urc_table_size);
/**
* @brief Send at command and wait for receiving expect response or data.
*
* @param[in] at_cmd at command
* @param[in] at_expect expect response or data length format
* @param[out] recv_buf recv data buffer
* @param[out] recv_len recv data length
* @param[in] timeout_ms wait timeout
* @return @see QCloudATErrCode
*/
int qcloud_iot_at_client_send_at_util_expect(const char *at_cmd, const char *at_expect, void *recv_buf,
uint32_t *recv_len, uint32_t timeout_ms);
/**
* @brief Send data to at module.
*
* @param[in] data
* @param[in] data_len
* @return 0 for success
*/
int qcloud_iot_at_client_send_data(const void *data, size_t data_len);
/**
* @brief Push data to at client queue.
*
* @param[in] recv_data recv data from uart
* @param[in] data_len recv data length
* @return 0 for success.
*/
int qcloud_iot_at_client_push_data(const void *recv_data, size_t data_len);
#ifdef __cplusplus
}
#endif
#endif // IOT_HUB_DEVICE_C_SDK_PLATFORM_AT_CLIENT_INC_QCLOUD_IOT_AT_CLIENT_H_

View File

@@ -0,0 +1,256 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2022 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file qcloud_iot_at_client.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2022-05-06
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022-05-06 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "qcloud_iot_at_client.h"
/**
* @brief Only one client is support.
*
*/
static QcloudATClient sg_client;
/**
* @brief Init at client.
*
* @param[in] max_at_size max at buffer size
* @param[in] at_send_func send at function
* @return @see QCloudATErrCode
*/
int qcloud_iot_at_client_init(int max_at_size, QcloudATSendDataFunc at_send_func)
{
if (QCLOUD_AT_STATUS_INIT == sg_client.status) {
return QCLOUD_AT_RET_INITTED;
}
sg_client.status = QCLOUD_AT_STATUS_INIT;
int rc;
QcloudATClient *client = &sg_client;
client->at_send_func = at_send_func;
client->recv_pool = HAL_Malloc(max_at_size);
if (!client->recv_pool) {
goto exit;
}
client->recv_queue = HAL_MailQueueInit(client->recv_pool, 1, max_at_size);
if (!client->recv_queue) {
goto exit;
}
client->recv_buf = HAL_Malloc(max_at_size);
if (!client->recv_buf) {
goto exit;
}
client->recv_buf_size = max_at_size;
client->recv_len = 0;
client->urc_table = NULL;
client->urc_table_size = 0;
client->urc_recv_pool = HAL_Malloc(sizeof(QcloudATUrcRecv) * QCLOUD_AT_MAX_URC_QUEUE_LEN);
if (!client->urc_recv_pool) {
goto exit;
}
client->urc_recv_queue =
HAL_MailQueueInit(client->urc_recv_pool, sizeof(QcloudATUrcRecv), QCLOUD_AT_MAX_URC_QUEUE_LEN);
if (!client->urc_recv_queue) {
goto exit;
}
client->resp.expect = NULL;
client->resp.status = QCLOUD_AT_RESP_STATUS_IDLE;
client->resp_lock = HAL_MutexCreate();
if (!client->resp_lock) {
goto exit;
}
client->resp_sem = HAL_SemaphoreCreate();
if (!client->resp_sem) {
goto exit;
}
static ThreadParams sg_qcloud_at_parse_thread_params = {0};
static void *sg_qcloud_at_parse_thread_stack;
if (!sg_qcloud_at_parse_thread_stack) {
sg_qcloud_at_parse_thread_stack = HAL_Malloc(QCLOUD_AT_PARSE_THREAD_STACK_SIZE);
if (!sg_qcloud_at_parse_thread_stack) {
goto exit;
}
}
sg_qcloud_at_parse_thread_params.user_arg = client;
sg_qcloud_at_parse_thread_params.stack_base = sg_qcloud_at_parse_thread_stack;
sg_qcloud_at_parse_thread_params.stack_size = QCLOUD_AT_PARSE_THREAD_STACK_SIZE;
sg_qcloud_at_parse_thread_params.thread_name = QCLOUD_AT_PARSE_THREAD_NAME;
sg_qcloud_at_parse_thread_params.priority = QCLOUD_AT_PARSE_THREAD_PRIORITY;
sg_qcloud_at_parse_thread_params.thread_func = qcloud_iot_at_client_parser;
rc = HAL_ThreadCreate(&sg_qcloud_at_parse_thread_params);
if (rc) {
goto exit;
}
static ThreadParams sg_qcloud_at_urc_thread_params = {0};
static void *sg_qcloud_at_urc_thread_stack;
if (!sg_qcloud_at_urc_thread_stack) {
sg_qcloud_at_urc_thread_stack = HAL_Malloc(QCLOUD_AT_URC_THREAD_STACK_SIZE);
if (!sg_qcloud_at_urc_thread_stack) {
goto exit;
}
}
sg_qcloud_at_urc_thread_params.user_arg = client;
sg_qcloud_at_urc_thread_params.stack_base = sg_qcloud_at_urc_thread_stack;
sg_qcloud_at_urc_thread_params.stack_size = QCLOUD_AT_URC_THREAD_STACK_SIZE;
sg_qcloud_at_urc_thread_params.thread_name = QCLOUD_AT_URC_THREAD_NAME;
sg_qcloud_at_urc_thread_params.priority = QCLOUD_AT_URC_THREAD_PRIORITY;
sg_qcloud_at_urc_thread_params.thread_func = qcloud_iot_at_urc_handle;
rc = HAL_ThreadCreate(&sg_qcloud_at_urc_thread_params);
if (rc) {
HAL_ThreadDestroy(sg_qcloud_at_parse_thread_params.thread_id);
goto exit;
}
return QCLOUD_AT_RET_SUCCESS;
exit:
HAL_MailQueueDeinit(client->recv_queue);
HAL_Free(client->recv_pool);
HAL_Free(client->recv_buf);
HAL_MutexDestroy(client->resp_lock);
HAL_SemaphoreDestroy(client->resp_sem);
HAL_MailQueueDeinit(client->urc_recv_queue);
HAL_Free(client->urc_recv_pool);
memset(client, 0, sizeof(QcloudATClient));
return QCLOUD_AT_ERR_FAILURE;
}
/**
* @brief Set at urc.
*
* @param[in] urc_table urc table
* @param[in] urc_table_size table size
*/
void qcloud_iot_at_client_set_urc(QcloudATUrc *urc_table, uint32_t urc_table_size)
{
sg_client.urc_table = urc_table;
sg_client.urc_table_size = urc_table_size;
}
/**
* @brief Send at command and wait for receiving expect response.
*
* @param[in] at_cmd at command
* @param[in] at_expect expect response
* @param[in] timeout_ms wait timeout
* @return @see QCloudATErrCode
*/
/**
* @brief Send at command and wait for receiving expect response or data.
*
* @param[in] at_cmd at command
* @param[in] at_expect expect response or data length format
* @param[out] recv_buf recv data buffer
* @param[out] recv_len recv data length
* @param[in] timeout_ms wait timeout
* @return @see QCloudATErrCode
*/
int qcloud_iot_at_client_send_at_util_expect(const char *at_cmd, const char *at_expect, void *recv_buf,
uint32_t *recv_len, uint32_t timeout_ms)
{
QcloudATClient *client = &sg_client;
if (QCLOUD_AT_STATUS_NO_INIT == client->status) {
return QCLOUD_AT_ERR_NO_INIT;
}
int rc;
HAL_MutexLock(client->resp_lock);
client->resp.expect = at_expect;
client->resp.recv_buf = recv_buf;
client->resp.recv_len = 0;
client->resp.status = QCLOUD_AT_RESP_STATUS_WAIT;
rc = client->at_send_func(at_cmd, strlen(at_cmd));
if (rc) {
rc = QCLOUD_AT_ERR_SEND_FAIL;
goto exit;
}
rc = HAL_SemaphoreWait(client->resp_sem, timeout_ms);
if (rc) {
rc = QCLOUD_AT_ERR_TIMEOUT;
goto exit;
}
if (client->resp.status != QCLOUD_AT_RESP_STATUS_OK) {
rc = QCLOUD_AT_ERR_RESP_FAIL;
}
*recv_len = client->resp.recv_len;
exit:
client->resp.expect = NULL;
client->resp.status = QCLOUD_AT_RESP_STATUS_IDLE;
HAL_MutexUnlock(client->resp_lock);
return rc;
}
/**
* @brief Send data to at module.
*
* @param[in] data
* @param[in] data_len
* @return 0 for success
*/
int qcloud_iot_at_client_send_data(const void *data, size_t data_len)
{
QcloudATClient *client = &sg_client;
if (QCLOUD_AT_STATUS_NO_INIT == client->status) {
return QCLOUD_AT_ERR_NO_INIT;
}
return client->at_send_func(data, data_len);
}
/**
* @brief Push data to at client queue.
*
* @param[in] recv_data recv data from uart
* @param[in] data_len recv data length
* @return 0 for success.
*/
int qcloud_iot_at_client_push_data(const void *recv_data, size_t data_len)
{
int rc = 0;
QcloudATClient *client = &sg_client;
if (QCLOUD_AT_STATUS_NO_INIT == client->status) {
return QCLOUD_AT_ERR_NO_INIT;
}
for (size_t i = 0; i < data_len; i++) {
rc = HAL_MailQueueSend(client->recv_queue, (uint8_t *)recv_data + i, 1);
if (rc) {
return QCLOUD_AT_ERR_FAILURE;
}
}
return QCLOUD_AT_RET_SUCCESS;
}

View File

@@ -0,0 +1,259 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2022 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file qcloud_iot_at_client_parse.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2022-04-27
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022-04-27 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "qcloud_iot_at_client.h"
#include <string.h>
/**
* @brief Max recv timeout.
*
*/
#define MAX_RECV_TIMEOUT 0xffffffffUL
/**
* @brief Get expect len from expect.
*
* @param[in] client pointer to QcloudATClient
*/
static void _at_client_get_expect_len(QcloudATClient *client, uint32_t *expect_len)
{
int len = 0;
if (sscanf(client->recv_buf, client->resp.expect, &len) == 1 &&
client->recv_buf[client->recv_len - 1] == client->resp.expect[strlen(client->resp.expect) - 1]) {
*expect_len = len + client->recv_len;
client->resp.recv_len = len;
}
}
/**
* @brief Read one line for at recv queue.
*
* @param[in] client pointer to QcloudATClient
* @return @see QCloudATErrCode
*/
static int _at_client_readline(QcloudATClient *client)
{
int rc, read_len = 0;
char ch = 0, last_ch = 0;
size_t read_size = 1;
uint32_t expect_len = 0;
memset(client->recv_buf, 0, client->recv_buf_size);
client->recv_len = 0;
while (1) {
rc = HAL_MailQueueRecv(client->recv_queue, &ch, &read_size, MAX_RECV_TIMEOUT);
if (rc) {
Log_e("recv from queue fail, %d", rc);
return QCLOUD_AT_ERR_BUFF_SHORT;
}
if (read_len >= client->recv_buf_size) {
Log_e("read line failed. The line data length is out of buffer size(%d)!", client->recv_buf_size);
client->recv_len = 0;
return QCLOUD_AT_ERR_BUFF_SHORT;
}
client->recv_buf[read_len++] = ch;
client->recv_len = read_len;
// check if using expect string to get length
if (client->resp.recv_buf) {
if (!client->resp.recv_len) {
_at_client_get_expect_len(client, &expect_len);
}
if (expect_len) {
if (expect_len == client->recv_len) {
break;
}
continue;
}
}
if ((ch == '\n' && last_ch == '\r')) {
break;
}
last_ch = ch;
}
client->recv_buf[read_len] = '\0';
return QCLOUD_AT_RET_SUCCESS;
}
/**
* @brief Check urc table.
*
* @param[in] client pointer to QcloudATClient
* @return @see QCloudATErrCode
*/
static int _at_client_check_urc(QcloudATClient *client)
{
int i;
size_t urc_len;
QcloudATUrc *urc;
for (i = 0; i < client->urc_table_size; i++) {
urc = &client->urc_table[i];
urc_len = strlen(urc->urc_prefix);
if (client->recv_len < urc_len) {
continue;
}
if (!strncmp(urc->urc_prefix, client->recv_buf, urc_len)) {
QcloudATUrcRecv urc_recv;
urc_recv.urc = urc;
urc_recv.urc_recv_len = client->recv_len;
urc_recv.urc_handle_buf = HAL_Malloc(client->recv_len + 1);
if (!urc_recv.urc_handle_buf) {
Log_e("malloc urc_handle_buf error.");
return QCLOUD_AT_ERR_FAILURE;
}
memcpy(urc_recv.urc_handle_buf, client->recv_buf, client->recv_len);
urc_recv.urc_handle_buf[client->recv_len] = '\0';
return HAL_MailQueueSend(client->urc_recv_queue, &urc_recv, sizeof(QcloudATUrcRecv));
}
}
return QCLOUD_AT_ERR_FAILURE;
}
/**
* @brief Check at response.
*
* @param[in] client pointer to QcloudATClient
*/
static int _at_client_check_common_resp(QcloudATClient *client)
{
if (!strncmp(client->recv_buf, "OK", 2) && !client->resp.expect) {
client->resp.status = QCLOUD_AT_RESP_STATUS_OK;
return QCLOUD_AT_RET_SUCCESS;
}
if (strstr(client->recv_buf, "ERROR") || !strncmp(client->recv_buf, "FAIL", 4)) {
client->resp.status = QCLOUD_AT_RESP_STATUS_ERROR;
return QCLOUD_AT_ERR_RESP_FAIL;
}
return QCLOUD_AT_ERR_FAILURE;
}
/**
* @brief Check expect response.
*
* @param[in] client pointer to QcloudATClient
* @return @see QCloudATErrCode
*/
static int _at_client_check_expect(QcloudATClient *client)
{
if (!client->resp.expect) {
return QCLOUD_AT_ERR_FAILURE;
}
if (client->resp.recv_buf && client->resp.recv_len) {
memcpy(client->resp.recv_buf, client->recv_buf + client->recv_len - client->resp.recv_len,
client->resp.recv_len);
client->resp.status = QCLOUD_AT_RESP_STATUS_OK;
return QCLOUD_AT_RET_SUCCESS;
}
if (strncmp(client->resp.expect, client->recv_buf, strlen(client->resp.expect))) {
return QCLOUD_AT_ERR_FAILURE;
}
client->resp.status = QCLOUD_AT_RESP_STATUS_OK;
return QCLOUD_AT_RET_SUCCESS;
}
/**
* @brief Parse data recv from at module.
*
* @param[in] client pointer to QcloudATClient
*/
void qcloud_iot_at_client_parser(void *client)
{
int rc;
QcloudATClient *at_client = (QcloudATClient *)client;
while (1) {
rc = _at_client_readline(at_client);
if (rc) {
continue;
}
printf("AT recv <--:%.*s\r\n", at_client->recv_len, at_client->recv_buf);
rc = _at_client_check_urc(at_client);
if (!rc) {
continue;
}
if (QCLOUD_AT_RESP_STATUS_WAIT != at_client->resp.status) {
continue;
}
rc = _at_client_check_expect(at_client);
if (!rc) {
HAL_SemaphorePost(at_client->resp_sem);
continue;
}
rc = _at_client_check_common_resp(at_client);
switch (rc) {
case QCLOUD_AT_RET_SUCCESS:
// if expect, ignore "OK"
if (at_client->resp.expect) {
break;
}
case QCLOUD_AT_ERR_RESP_FAIL:
HAL_SemaphorePost(at_client->resp_sem);
break;
default:
// Log_w("ignore %.*s", at_client->recv_len, at_client->recv_buf);
break;
}
}
}
/**
* @brief Recv urc and callback.
*
* @param[in] client pointer to QcloudATClient
*/
void qcloud_iot_at_urc_handle(void *client)
{
QcloudATClient *at_client = (QcloudATClient *)client;
QcloudATUrcRecv urc_recv;
size_t recv_size = sizeof(QcloudATUrcRecv);
while (1) {
int rc = HAL_MailQueueRecv(at_client->urc_recv_queue, &urc_recv, &recv_size, MAX_RECV_TIMEOUT);
if (rc) {
continue;
}
urc_recv.urc->urc_handle(urc_recv.urc_handle_buf, urc_recv.urc_recv_len);
HAL_Free(urc_recv.urc_handle_buf);
}
}