From e44d9e8322f6ef9758226f6c78a7dc8ae49006d7 Mon Sep 17 00:00:00 2001 From: caixiang2014 <953748225@qq.com> Date: Mon, 17 Aug 2026 18:17:48 +0800 Subject: [PATCH] feat: add EC800K buffered TCP mode --- applications/VK_Client.c | 168 +++++++++++++++++------ applications/VK_Com.c | 48 ++++++- applications/VK_Com.h | 3 + applications/drv_ec800k.c | 282 ++++++++++++++++++++++++++++++++++++++ applications/drv_ec800k.h | 34 ++++- 5 files changed, 487 insertions(+), 48 deletions(-) diff --git a/applications/VK_Client.c b/applications/VK_Client.c index dea1879..e269d9a 100644 --- a/applications/VK_Client.c +++ b/applications/VK_Client.c @@ -31,6 +31,10 @@ static char cmd_cmd[128] = {0}; +static uint8_t socket_tx_buffer[LTE_SOCKET_TX_CHUNK_SIZE]; +static uint8_t socket_rx_buffer[LTE_SOCKET_RX_CHUNK_SIZE]; +static rt_size_t socket_tx_pending = 0; +static rt_tick_t last_ack_query_tick = 0; no_carrier_match_t _no_carrier_t = {0}; @@ -39,6 +43,10 @@ void client_tcp_close(Cclient_t *client) { char close_cmd[24]; client->connect_sta = false; + BSP_LTE_SetDataTxPaused(true); + BSP_LTE_ClearSocketEvents(); + fmu_net_queue_reset(); + socket_tx_pending = 0; rt_snprintf(close_cmd, sizeof(close_cmd), AT_QICLOSE, client->connect_ID); BSP_LTE_SendCmd(close_cmd, DEFAULT_EXPECT, DEFAULT_ERROR, LTE_CMD_WAIT_QICLOSE); @@ -149,6 +157,8 @@ static const char *disconnect_reason_name(lte_disconnect_reason_t reason) { case LTE_DISC_AT_TIMEOUT: return "AT_TIMEOUT"; case LTE_DISC_QIOPEN_FAILED: return "QIOPEN_FAILED"; case LTE_DISC_MODULE_RESET: return "MODULE_RESET"; + case LTE_DISC_SERVER_SILENCE: return "SERVER_SILENCE"; + case LTE_DISC_SOCKET_SEND: return "SOCKET_SEND"; default: return "UNKNOWN"; } } @@ -180,6 +190,15 @@ void lte_diag_disconnect(lte_disconnect_reason_t reason) { lte_diag.fmu_rx_bytes, lte_diag.fmu_tx_bytes, lte_diag.server_rx_bytes, lte_diag.server_rx_read_events, lte_diag.server_silence_timeout_count); + LOG_I("[DISC] socket_tx=%u send_ok=%u send_fail=%u prompt_timeout=%u read_errors=%u", + lte_diag.socket_tx_bytes, lte_diag.socket_send_ok, + lte_diag.socket_send_fail, lte_diag.socket_prompt_timeouts, + lte_diag.socket_read_errors); + LOG_I("[DISC] acked=%u unacked=%u ack_queries=%u ack_errors=%u", + lte_diag.socket_acked_bytes, lte_diag.socket_unacked_bytes, + lte_diag.socket_ack_queries, lte_diag.socket_ack_errors); + LOG_I("[DISC] tx_queue_high=%u drops=%u", + lte_diag.tx_queue_high_water, lte_diag.tx_queue_drops); LOG_I("[DISC] age_uart2_rx=%u age_uart2_tx=%u age_fmu_rx=%u age_server_rx=%u", diag_age(now, lte_diag.last_uart2_rx_tick), diag_age(now, lte_diag.last_uart2_tx_tick), @@ -211,11 +230,7 @@ int16_t EC800K_Reset(void) { lte_dev.client1->connect_sta = false; //lte_dev.client2->connect_sta = false; - rt_thread_mdelay(3000); - BSP_LTE_SendData((uint8_t *)"+++", 3); - rt_thread_mdelay(2000); - BSP_LTE_SendData((uint8_t *)"+++", 3); - rt_thread_mdelay(2000); + rt_thread_mdelay(1000); uint8_t try_count = 5; @@ -261,9 +276,9 @@ int16_t client_tcp_connect(Cclient_t *client) { BSP_LTE_InitLogClock(); // - BSP_LTE_SendCmd(AT_CFG_TRANS_SIZE, DEFAULT_EXPECT, DEFAULT_ERROR, + BSP_LTE_SendCmd(AT_CFG_RECV_IND, DEFAULT_EXPECT, DEFAULT_ERROR, LTE_CMD_WAIT_NORMAL); - BSP_LTE_SendCmd(AT_CFG_TRANS_WAITTM, DEFAULT_EXPECT, DEFAULT_ERROR, + BSP_LTE_SendCmd(AT_QISDE0, DEFAULT_EXPECT, DEFAULT_ERROR, LTE_CMD_WAIT_NORMAL); BSP_LTE_SendCmd(AT_CFG_PASSIVE_CLOSED, DEFAULT_EXPECT, DEFAULT_ERROR, LTE_CMD_WAIT_NORMAL); @@ -276,7 +291,7 @@ int16_t client_tcp_connect(Cclient_t *client) { // 2, 打开链接 memset(cmd_cmd, 0, sizeof(cmd_cmd)); - cmd_len = rt_snprintf(cmd_cmd, sizeof(cmd_cmd), AT_QIOPEN_TRANS, + cmd_len = rt_snprintf(cmd_cmd, sizeof(cmd_cmd), AT_QIOPEN_BUFFER, client->connect_ID, client->mode, client->ip, client->port); if (cmd_len < 0 || cmd_len >= (int)sizeof(cmd_cmd)) { @@ -285,8 +300,7 @@ int16_t client_tcp_connect(Cclient_t *client) { return -1; } /* 透传模式成功返回 CONNECT;一次尝试只发送一次 QIOPEN。 */ - while (0 != BSP_LTE_SendCmd(cmd_cmd, CONNECTE_OK, DEFAULT_ERROR, - LTE_CMD_WAIT_QIOPEN)) { + while (0 != BSP_LTE_OpenSocket(cmd_cmd, client->connect_ID)) { lte_diag.qioopen_failures++; client_tcp_close(client); #ifdef debug_mode @@ -305,8 +319,12 @@ int16_t client_tcp_connect(Cclient_t *client) { #endif } client->connect_sta = true; + BSP_LTE_ClearSocketEvents(); + fmu_net_queue_reset(); + socket_tx_pending = 0; BSP_LTE_SetDataTxPaused(false); lte_diag_connect_success(); + last_ack_query_tick = lte_diag.connect_tick; client->error_cnt = 0; lte_dev.reset_flag = DTU_CF_NO_NEED_RESET; @@ -323,7 +341,7 @@ int16_t client_tcp_connect(Cclient_t *client) { mav_len = mavlink_msg_to_send_buffer(mav_buf, &msg); for (int i = 0; i < 3; i++) { - BSP_LTE_SendData(mav_buf, mav_len); + BSP_LTE_SendSocketData(client->connect_ID, mav_buf, mav_len); } rt_device_t fmu_com = fmu_com_get(); if (fmu_com != RT_NULL) { @@ -334,11 +352,11 @@ int16_t client_tcp_connect(Cclient_t *client) { rt_sprintf(buf, "{\"sn\":\"%s\",\"client_id\":\"%s\",\"csq\":\"%d\"}\r\n", lte_dev.iccid, lte_dev.imei, lte_dev.csq); - BSP_LTE_SendData((uint8_t *)buf, sizeof(buf)); + BSP_LTE_SendSocketData(client->connect_ID, (uint8_t *)buf, sizeof(buf)); - BSP_LTE_SendData((uint8_t *)buf, sizeof(buf)); + BSP_LTE_SendSocketData(client->connect_ID, (uint8_t *)buf, sizeof(buf)); - BSP_LTE_SendData((uint8_t *)buf, sizeof(buf)); + BSP_LTE_SendSocketData(client->connect_ID, (uint8_t *)buf, sizeof(buf)); //hw_printf(buf); #endif @@ -350,37 +368,7 @@ int16_t client_tcp_connect(Cclient_t *client) { static rt_tick_t last_rx_tick = 0; #endif -/* Leave transparent mode only after the UART has been quiet for the - * required guard time. The caller keeps data_tx_paused asserted until the - * next successful QIOPEN. */ -static bool client_exit_transparent_mode(CLte_dev_t *pLte_dev) { - rt_tick_t deadline; - rt_ssize_t len; - - BSP_LTE_SetDataTxPaused(true); - rt_thread_mdelay(1000); - BSP_LTE_SendData((uint8_t *)"+++", 3); - rt_thread_mdelay(1000); - - deadline = rt_tick_get() + 2000; - while ((rt_int32_t)(rt_tick_get() - deadline) < 0) { - if (pLte_dev->com_dev_rx_sem != RT_NULL) { - rt_sem_take(pLte_dev->com_dev_rx_sem, 100); - } - rt_memset(pLte_dev->at_buf, 0, sizeof(pLte_dev->at_buf)); - len = rt_device_read(pLte_dev->com_dev, 0, pLte_dev->at_buf, - sizeof(pLte_dev->at_buf) - 1); - if (len > 0) { - lte_diag_uart2_rx((rt_size_t)len); - pLte_dev->at_buf[len] = '\0'; - if (rt_strstr((const char *)pLte_dev->at_buf, DEFAULT_EXPECT) != RT_NULL) { - return true; - } - } - } - return false; -} - +#if 0 void client_yield(CLte_dev_t *pLte_dev) { while (1) { if (pLte_dev->client1->connect_sta == true) { @@ -468,6 +456,96 @@ void client_yield(CLte_dev_t *pLte_dev) { } } +#endif + +void client_yield(CLte_dev_t *pLte_dev) { + while (1) { + if (pLte_dev->client1->connect_sta == true) { + int16_t socket_result; + + BSP_LTE_PollSocketUrc(20); + if (pLte_dev->socket_closed_pending) { + LOG_W("[URC] socket closed received"); + lte_diag_disconnect(LTE_DISC_CLOSED); + client_tcp_close(pLte_dev->client1); + continue; + } + + while (pLte_dev->socket_recv_pending && + pLte_dev->client1->connect_sta) { + rt_device_t fmu_com; + int16_t read_length = BSP_LTE_ReadSocketData( + pLte_dev->client1->connect_ID, socket_rx_buffer, + sizeof(socket_rx_buffer)); + if (read_length < 0) { + lte_diag_disconnect(pLte_dev->socket_closed_pending + ? LTE_DISC_CLOSED + : LTE_DISC_AT_TIMEOUT); + client_tcp_close(pLte_dev->client1); + break; + } + if (read_length == 0) break; + + lte_diag.server_rx_bytes += read_length; + lte_diag.server_rx_read_events++; + lte_diag.last_server_rx_tick = rt_tick_get(); +#if LTE_SERVER_SILENCE_TIMEOUT_SEC > 0 + last_rx_tick = lte_diag.last_server_rx_tick; +#endif + fmu_com = fmu_com_get(); + if (fmu_com != RT_NULL) { + rt_ssize_t written = rt_device_write(fmu_com, 0, socket_rx_buffer, + read_length); + if (written > 0) lte_diag_fmu_tx((rt_size_t)written); + } + if (read_length == sizeof(socket_rx_buffer)) + pLte_dev->socket_recv_pending = true; + } + if (!pLte_dev->client1->connect_sta) continue; + + if (socket_tx_pending == 0) { + socket_tx_pending = fmu_net_queue_get(socket_tx_buffer, + sizeof(socket_tx_buffer)); + } + if (socket_tx_pending > 0) { + socket_result = BSP_LTE_SendSocketData( + pLte_dev->client1->connect_ID, socket_tx_buffer, + (uint16_t)socket_tx_pending); + if (socket_result == 0) { + socket_tx_pending = 0; + } else if (socket_result < 0) { + lte_diag_disconnect(LTE_DISC_SOCKET_SEND); + client_tcp_close(pLte_dev->client1); + continue; + } else { + rt_thread_mdelay(50); + } + } + + if (rt_tick_get() - last_ack_query_tick >= RT_TICK_PER_SECOND * 5) { + last_ack_query_tick = rt_tick_get(); + BSP_LTE_QuerySocketSendStatus(pLte_dev->client1->connect_ID); + } + +#if LTE_SERVER_SILENCE_TIMEOUT_SEC > 0 + if (rt_tick_get() - last_rx_tick > + RT_TICK_PER_SECOND * LTE_SERVER_SILENCE_TIMEOUT_SEC) { + lte_diag.server_silence_timeout_count++; + LOG_W("server silence timeout, reconnect\n"); + lte_diag_disconnect(LTE_DISC_SERVER_SILENCE); + client_tcp_close(pLte_dev->client1); + continue; + } +#endif + } else { + if (pLte_dev->reset_flag == DTU_CF_NEED_RESET) BSP_LTE_Config(); + client_tcp_connect(pLte_dev->client1); +#if LTE_SERVER_SILENCE_TIMEOUT_SEC > 0 + last_rx_tick = rt_tick_get(); +#endif + } + } +} void client_task(void) { client_yield(<e_dev); diff --git a/applications/VK_Com.c b/applications/VK_Com.c index 1a68f10..7ade07e 100644 --- a/applications/VK_Com.c +++ b/applications/VK_Com.c @@ -3,6 +3,7 @@ #include "drv_ec800k.h" #include "rtdef.h" #include "rtthread.h" +#include #define ENABLE_MEMORY_USAGE_LOG 0 @@ -15,6 +16,12 @@ rt_device_t fmu_com = RT_NULL; rt_sem_t fmu_com_rx_sem = RT_NULL; +#define FMU_NET_QUEUE_SIZE 512 +static struct rt_ringbuffer fmu_net_queue; +static struct rt_mutex fmu_net_queue_lock; +static uint8_t fmu_net_queue_pool[FMU_NET_QUEUE_SIZE]; +static bool fmu_net_queue_ready = false; + #if ENABLE_MEMORY_USAGE_LOG static rt_size_t thread_stack_used(rt_thread_t thread) { rt_uint8_t *stack; @@ -69,9 +76,48 @@ int fmu_com_register(rt_device_t com_dev) { rt_device_set_rx_indicate(fmu_com, fmu_com_rx_cb); + if (!fmu_net_queue_ready) { + rt_ringbuffer_init(&fmu_net_queue, fmu_net_queue_pool, + sizeof(fmu_net_queue_pool)); + rt_mutex_init(&fmu_net_queue_lock, "fmuNet", RT_IPC_FLAG_PRIO); + fmu_net_queue_ready = true; + } + return 0; } +rt_size_t fmu_net_queue_put(const uint8_t *data, rt_size_t length) { + rt_size_t queued; + rt_size_t used; + + if (!fmu_net_queue_ready || data == RT_NULL || length == 0) return 0; + rt_mutex_take(&fmu_net_queue_lock, RT_WAITING_FOREVER); + queued = rt_ringbuffer_put(&fmu_net_queue, data, length); + used = rt_ringbuffer_data_len(&fmu_net_queue); + rt_mutex_release(&fmu_net_queue_lock); + + if (queued < length) lte_diag.tx_queue_drops += length - queued; + if (used > lte_diag.tx_queue_high_water) lte_diag.tx_queue_high_water = used; + return queued; +} + +rt_size_t fmu_net_queue_get(uint8_t *data, rt_size_t length) { + rt_size_t read; + + if (!fmu_net_queue_ready || data == RT_NULL || length == 0) return 0; + rt_mutex_take(&fmu_net_queue_lock, RT_WAITING_FOREVER); + read = rt_ringbuffer_get(&fmu_net_queue, data, length); + rt_mutex_release(&fmu_net_queue_lock); + return read; +} + +void fmu_net_queue_reset(void) { + if (!fmu_net_queue_ready) return; + rt_mutex_take(&fmu_net_queue_lock, RT_WAITING_FOREVER); + rt_ringbuffer_reset(&fmu_net_queue); + rt_mutex_release(&fmu_net_queue_lock); +} + /*接收到串口的数据,并将数据转发到网络端*/ void com_task(void) { static uint8_t buff[128]; @@ -90,7 +136,7 @@ void com_task(void) { if (lte_dev.client1->connect_sta == true && lte_dev.data_tx_paused == false) { /* 仅在客户端2连接时转发 */ - BSP_LTE_SendData(buff, len); + fmu_net_queue_put(buff, len); } } else { break; diff --git a/applications/VK_Com.h b/applications/VK_Com.h index aa25c7c..edd12eb 100644 --- a/applications/VK_Com.h +++ b/applications/VK_Com.h @@ -15,6 +15,9 @@ void com_task(void); rt_device_t fmu_com_get(void); int fmu_com_register(rt_device_t com_dev); +rt_size_t fmu_net_queue_put(const uint8_t *data, rt_size_t length); +rt_size_t fmu_net_queue_get(uint8_t *data, rt_size_t length); +void fmu_net_queue_reset(void); #ifdef __cplusplus } diff --git a/applications/drv_ec800k.c b/applications/drv_ec800k.c index ef242a4..7d81634 100644 --- a/applications/drv_ec800k.c +++ b/applications/drv_ec800k.c @@ -38,6 +38,116 @@ CLte_dev_t lte_dev = { lte_diag_t lte_diag = {0}; static bool lte_log_clock_query_done = false; +static char socket_urc_line[80]; +static rt_size_t socket_urc_line_len = 0; +static volatile bool socket_open_seen = false; +static volatile int16_t socket_open_result = -1; + +static int parse_decimal(const char **text) { + int value = 0; + bool found = false; + const char *p = *text; + + while (*p == ' ') p++; + while (*p >= '0' && *p <= '9') { + found = true; + value = value * 10 + (*p++ - '0'); + } + *text = p; + return found ? value : -1; +} + +static void lte_process_urc_line(const char *line) { + const char *p; + + if (rt_strstr(line, "+QIURC:") != RT_NULL) { + if (rt_strstr(line, "\"recv\"") != RT_NULL) { + lte_dev.socket_recv_pending = true; + } else if (rt_strstr(line, "\"closed\"") != RT_NULL) { + lte_dev.socket_closed_pending = true; + } + } + + p = rt_strstr(line, "+QIOPEN:"); + if (p != RT_NULL) { + int connect_id; + int error; + p += rt_strlen("+QIOPEN:"); + connect_id = parse_decimal(&p); + if (*p == ',') p++; + error = parse_decimal(&p); + if (connect_id == lte_dev.client1->connect_ID && error >= 0) { + socket_open_result = (int16_t)error; + socket_open_seen = true; + } + } +} + +static void lte_process_text(const uint8_t *data, rt_size_t length) { + rt_size_t i; + + for (i = 0; i < length; i++) { + uint8_t ch = data[i]; + if (ch == '\r') continue; + if (ch == '\n') { + if (socket_urc_line_len > 0) { + socket_urc_line[socket_urc_line_len] = '\0'; + lte_process_urc_line(socket_urc_line); + socket_urc_line_len = 0; + } + } else if (ch >= 0x20 && ch <= 0x7e) { + if (socket_urc_line_len < sizeof(socket_urc_line) - 1) { + socket_urc_line[socket_urc_line_len++] = (char)ch; + } else { + socket_urc_line_len = 0; + } + } + } +} + +static rt_ssize_t lte_read_available(uint8_t *buffer, rt_size_t capacity) { + rt_ssize_t length = rt_device_read(lte_dev.com_dev, 0, buffer, capacity); + if (length > 0) lte_diag_uart2_rx((rt_size_t)length); + return length; +} + +static void lte_drain_socket_input(void) { + rt_ssize_t length; + + do { + length = lte_read_available(lte_dev.at_buf, sizeof(lte_dev.at_buf)); + if (length > 0) lte_process_text(lte_dev.at_buf, (rt_size_t)length); + } while (length > 0); + while (rt_sem_take(lte_dev.com_dev_rx_sem, 0) == RT_EOK) { } +} + +static int lte_wait_text(const char *success, const char *failure, + rt_tick_t timeout) { + rt_tick_t deadline = rt_tick_get() + timeout; + rt_size_t used = 0; + + rt_memset(lte_dev.at_buf, 0, sizeof(lte_dev.at_buf)); + while ((rt_int32_t)(rt_tick_get() - deadline) < 0) { + rt_ssize_t length; + rt_sem_take(lte_dev.com_dev_rx_sem, 50); + length = lte_read_available(lte_dev.at_buf + used, + sizeof(lte_dev.at_buf) - 1 - used); + if (length <= 0) continue; + lte_process_text(lte_dev.at_buf + used, (rt_size_t)length); + used += (rt_size_t)length; + lte_dev.at_buf[used] = '\0'; + if (lte_dev.socket_closed_pending) return 1; + if (success != RT_NULL && rt_strstr((char *)lte_dev.at_buf, success)) return 0; + if ((failure != RT_NULL && rt_strstr((char *)lte_dev.at_buf, failure)) || + rt_strstr((char *)lte_dev.at_buf, DEFAULT_ERROR)) return 1; + if (used >= sizeof(lte_dev.at_buf) - 1) { + rt_memcpy(lte_dev.at_buf, lte_dev.at_buf + used - 32, 32); + used = 32; + lte_dev.at_buf[used] = '\0'; + } + } + return -1; +} void lte_diag_at_begin(const char *cmd) { rt_size_t i; @@ -135,6 +245,178 @@ void BSP_LTE_SetDataTxPaused(bool paused) { } } +void BSP_LTE_ClearSocketEvents(void) { + lte_dev.socket_recv_pending = false; + lte_dev.socket_closed_pending = false; + socket_open_seen = false; + socket_open_result = -1; + socket_urc_line_len = 0; +} + +int16_t BSP_LTE_OpenSocket(const char *cmd, uint8_t connect_id) { + rt_tick_t deadline; + + (void)connect_id; + lte_drain_socket_input(); + socket_open_seen = false; + socket_open_result = -1; + lte_diag_at_begin(cmd); + LOG_I("%s", cmd); + BSP_LTE_SendData((uint8_t *)cmd, rt_strlen(cmd)); + deadline = rt_tick_get() + LTE_CMD_WAIT_QIOPEN; + while ((rt_int32_t)(rt_tick_get() - deadline) < 0) { + rt_ssize_t length; + rt_sem_take(lte_dev.com_dev_rx_sem, 100); + length = lte_read_available(lte_dev.at_buf, sizeof(lte_dev.at_buf) - 1); + if (length > 0) { + lte_dev.at_buf[length] = '\0'; + lte_process_text(lte_dev.at_buf, (rt_size_t)length); + if (rt_strstr((char *)lte_dev.at_buf, DEFAULT_ERROR)) { + lte_diag_at_end(1); + return 1; + } + } + if (socket_open_seen) { + LOG_I("[SOCKET] open result=%d", socket_open_result); + lte_diag_at_end(socket_open_result == 0 ? 0 : 1); + return socket_open_result == 0 ? 0 : 1; + } + } + lte_diag_at_end(-1); + return -1; +} + +int16_t BSP_LTE_SendSocketData(uint8_t connect_id, const uint8_t *data, + uint16_t length) { + char command[32]; + int result; + + if (data == RT_NULL || length == 0 || length > 1460) return -1; + lte_drain_socket_input(); + rt_snprintf(command, sizeof(command), AT_QISEND, connect_id, length); + BSP_LTE_SendData((uint8_t *)command, rt_strlen(command)); + result = lte_wait_text(TPOK, DEFAULT_ERROR, LTE_CMD_WAIT_PROMPT); + if (result != 0) { + if (result < 0) lte_diag.socket_prompt_timeouts++; + lte_diag.socket_send_fail++; + return result < 0 ? -1 : 1; + } + + BSP_LTE_SendData((uint8_t *)data, length); + result = lte_wait_text(QI_SEND_OK, QI_SEND_FAIL, LTE_CMD_WAIT_SEND); + if (result == 0) { + lte_diag.socket_tx_bytes += length; + lte_diag.socket_send_ok++; + return 0; + } + lte_diag.socket_send_fail++; + return result < 0 ? -1 : 1; +} + +int16_t BSP_LTE_QuerySocketSendStatus(uint8_t connect_id) { + char command[24]; + const char *p; + int total; + int acked; + int unacked; + + lte_drain_socket_input(); + rt_snprintf(command, sizeof(command), AT_QISEND, connect_id, 0); + BSP_LTE_SendData((uint8_t *)command, rt_strlen(command)); + if (lte_wait_text("\r\nOK\r\n", DEFAULT_ERROR, LTE_CMD_WAIT_SEND) != 0) { + lte_diag.socket_ack_errors++; + return -1; + } + + p = rt_strstr((char *)lte_dev.at_buf, "+QISEND:"); + if (p == RT_NULL) { + lte_diag.socket_ack_errors++; + return -1; + } + p += rt_strlen("+QISEND:"); + total = parse_decimal(&p); + if (*p == ',') p++; + acked = parse_decimal(&p); + if (*p == ',') p++; + unacked = parse_decimal(&p); + if (total < 0 || acked < 0 || unacked < 0) { + lte_diag.socket_ack_errors++; + return -1; + } + (void)total; + lte_diag.socket_acked_bytes = (rt_uint32_t)acked; + lte_diag.socket_unacked_bytes = (rt_uint32_t)unacked; + lte_diag.socket_ack_queries++; + return 0; +} + +int16_t BSP_LTE_ReadSocketData(uint8_t connect_id, uint8_t *data, + uint16_t capacity) { + char command[32]; + rt_tick_t deadline; + rt_size_t used = 0; + + if (data == RT_NULL || capacity == 0 || capacity > LTE_SOCKET_RX_CHUNK_SIZE) + return -1; + lte_drain_socket_input(); + lte_dev.socket_recv_pending = false; + rt_snprintf(command, sizeof(command), "AT+QIRD=%u,%u\r\n", + connect_id, capacity); + BSP_LTE_SendData((uint8_t *)command, rt_strlen(command)); + rt_memset(lte_dev.at_buf, 0, sizeof(lte_dev.at_buf)); + deadline = rt_tick_get() + LTE_CMD_WAIT_SEND; + while ((rt_int32_t)(rt_tick_get() - deadline) < 0) { + rt_ssize_t length; + char *header; + char *payload; + const char *number; + int payload_length; + + rt_sem_take(lte_dev.com_dev_rx_sem, 50); + length = lte_read_available(lte_dev.at_buf + used, + sizeof(lte_dev.at_buf) - 1 - used); + if (length <= 0) continue; + used += (rt_size_t)length; + lte_dev.at_buf[used] = '\0'; + header = rt_strstr((char *)lte_dev.at_buf, "+QIRD:"); + if (header == RT_NULL) { + if (rt_strstr((char *)lte_dev.at_buf, "\"closed\"") != RT_NULL) { + lte_dev.socket_closed_pending = true; + return -1; + } + continue; + } + number = header + rt_strlen("+QIRD:"); + payload_length = parse_decimal(&number); + payload = rt_strstr((char *)number, "\r\n"); + if (payload_length < 0 || payload == RT_NULL) continue; + payload += 2; + if ((rt_size_t)(payload - (char *)lte_dev.at_buf) + payload_length + 6 > used) + continue; + if (payload_length > capacity) { + lte_diag.socket_read_errors++; + return -1; + } + if (header > (char *)lte_dev.at_buf) + lte_process_text(lte_dev.at_buf, (rt_size_t)(header - (char *)lte_dev.at_buf)); + if (payload_length > 0) rt_memcpy(data, payload, payload_length); + lte_process_text((uint8_t *)payload + payload_length, 6); + return (int16_t)payload_length; + } + lte_diag.socket_read_errors++; + return -1; +} + +void BSP_LTE_PollSocketUrc(uint32_t waittime) { + rt_ssize_t length; + + if (rt_sem_take(lte_dev.com_dev_rx_sem, waittime) != RT_EOK) return; + do { + length = lte_read_available(lte_dev.at_buf, sizeof(lte_dev.at_buf)); + if (length > 0) lte_process_text(lte_dev.at_buf, (rt_size_t)length); + } while (length > 0); +} + void BSP_LTE_InitLogClock(void) { if (lte_log_clock_query_done) { return; diff --git a/applications/drv_ec800k.h b/applications/drv_ec800k.h index 4e20fee..e8d551b 100644 --- a/applications/drv_ec800k.h +++ b/applications/drv_ec800k.h @@ -88,6 +88,7 @@ extern "C" { #define AT_TPCLOSE "+++\r\n" #define AT_CIPSEND "AT+CIPSEND=%d,%d\r\n" #define AT_QISEND "AT+QISEND=%d,%d\r\n" +#define AT_QISDE0 "AT+QISDE=0\r\n" #define QI_SEND_OK "\r\nSEND OK\r\n" #define QI_SEND_FAIL "\r\nSEND FAIL\r\n" #define AT_CGMR "AT+CGMR\r\n" @@ -98,6 +99,8 @@ extern "C" { #define AT_QIOPEN_TRANS \ "AT+QIOPEN=1,%d,\"%s\",\"%s\",%s,0,2\r\n" // transparent Mode +#define AT_QIOPEN_BUFFER \ + "AT+QIOPEN=1,%d,\"%s\",\"%s\",%s,0,0\r\n" // buffer Mode #define AT_QIOPEN_FORW \ "AT+QIOPEN=1,%d,\"%s\",\"%s\",%s,0,1\r\n" // Immediate Forwarding Mode @@ -199,6 +202,7 @@ extern "C" { //AT CFG #define AT_CFG_TRANS_SIZE "AT+QICFG=\"transpktsize\",512\r\n" #define AT_CFG_TRANS_WAITTM "AT+QICFG=\"transwaittm\",0\r\n" +#define AT_CFG_RECV_IND "AT+QICFG=\"recvind\",1\r\n" #define AT_CFG_PASSIVE_CLOSED "AT+QICFG=\"passiveclosed\",1\r\n" #define AT_CFG_TCP_KEEPALIVE "AT+QICFG=\"tcp/keepalive\",1,30,25,3\r\n" @@ -206,9 +210,12 @@ extern "C" { #define LTE_CMD_WAIT_QICLOSE (10000) #define LTE_CMD_WAIT_QIACT (150000) #define LTE_CMD_WAIT_QIDEACT (40000) +#define LTE_CMD_WAIT_PROMPT (3000) +#define LTE_CMD_WAIT_SEND (10000) +#define LTE_SOCKET_RX_CHUNK_SIZE (128) +#define LTE_SOCKET_TX_CHUNK_SIZE (256) -/* Set after confirming the server MAVLink heartbeat period. 0 disables the - * application-level silence recovery and leaves NO CARRIER/keepalive active. */ +/* Set after confirming the server MAVLink heartbeat period. */ #define LTE_SERVER_SILENCE_TIMEOUT_SEC (15) typedef struct { @@ -227,6 +234,8 @@ typedef enum { LTE_DISC_AT_TIMEOUT, LTE_DISC_QIOPEN_FAILED, LTE_DISC_MODULE_RESET, + LTE_DISC_SERVER_SILENCE, + LTE_DISC_SOCKET_SEND, } lte_disconnect_reason_t; typedef struct { @@ -250,6 +259,17 @@ typedef struct { rt_uint32_t server_rx_bytes; rt_uint32_t server_rx_read_events; rt_uint32_t server_silence_timeout_count; + rt_uint32_t socket_tx_bytes; + rt_uint32_t socket_send_ok; + rt_uint32_t socket_send_fail; + rt_uint32_t socket_prompt_timeouts; + rt_uint32_t socket_read_errors; + rt_uint32_t socket_acked_bytes; + rt_uint32_t socket_unacked_bytes; + rt_uint32_t socket_ack_queries; + rt_uint32_t socket_ack_errors; + rt_uint32_t tx_queue_drops; + rt_uint32_t tx_queue_high_water; rt_tick_t last_uart2_rx_tick; rt_tick_t last_uart2_tx_tick; rt_tick_t last_fmu_rx_tick; @@ -299,6 +319,8 @@ typedef struct { bool reset_flag; bool dev_init_flag; volatile bool data_tx_paused; + volatile bool socket_recv_pending; + volatile bool socket_closed_pending; } CLte_dev_t; extern CLte_dev_t lte_dev; @@ -320,6 +342,14 @@ void BSP_LTE_SetDataTxPaused(bool paused); void BSP_LTE_Config(void); void BSP_LTE_InitLogClock(void); +int16_t BSP_LTE_OpenSocket(const char *cmd, uint8_t connect_id); +int16_t BSP_LTE_SendSocketData(uint8_t connect_id, const uint8_t *data, + uint16_t length); +int16_t BSP_LTE_ReadSocketData(uint8_t connect_id, uint8_t *data, + uint16_t capacity); +int16_t BSP_LTE_QuerySocketSendStatus(uint8_t connect_id); +void BSP_LTE_PollSocketUrc(uint32_t waittime); +void BSP_LTE_ClearSocketEvents(void); int BSP_LTE_GetICCID(char *pICCID);