feat: 移植腾讯云物联网开发平台 C SDK
This commit is contained in:
@@ -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)
|
@@ -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_
|
@@ -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;
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user