9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
622 lines
14 KiB
C
622 lines
14 KiB
C
/**
|
||
* @file debug_link.c
|
||
* @brief 调试链路层实现(comm_link_ctx + TCP Socket + comm_link 分发)
|
||
*/
|
||
|
||
#include "debug_link.h"
|
||
#include "tcp_protocol.h"
|
||
#include "publicdata/public_define.h"
|
||
#include "lwip/sockets.h"
|
||
#include "lwip/netdb.h"
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include "FreeRTOS.h"
|
||
#include "task.h"
|
||
#include "semphr.h"
|
||
#include "app_fatfs/fatfs_init.h"
|
||
|
||
#if BLE_DEBUG_EN
|
||
#include "ble_link/fc41d_ble.h"
|
||
#endif
|
||
|
||
#if TCP_DEBUG_EN
|
||
|
||
/* =============================================================================
|
||
* 会话上下文(原 comm_link_ctx.c)
|
||
* ============================================================================= */
|
||
|
||
static comm_link_ctx_t s_comm_link_ctx;
|
||
|
||
comm_link_ctx_t *comm_link_ctx_get(void)
|
||
{
|
||
return &s_comm_link_ctx;
|
||
}
|
||
|
||
comm_link_session_t *comm_link_session(void)
|
||
{
|
||
return &s_comm_link_ctx.session;
|
||
}
|
||
|
||
void comm_link_ctx_reset_session(void)
|
||
{
|
||
comm_link_type_t saved_type = s_comm_link_ctx.session.type;
|
||
|
||
memset(&s_comm_link_ctx.session, 0, sizeof(s_comm_link_ctx.session));
|
||
s_comm_link_ctx.session.type = saved_type;
|
||
}
|
||
|
||
void comm_link_ctx_reset_all(void)
|
||
{
|
||
memset(&s_comm_link_ctx, 0, sizeof(s_comm_link_ctx));
|
||
}
|
||
|
||
/* =============================================================================
|
||
* TCP Socket 后端(原 tcp_server_socket.c,本文件内 static)
|
||
* ============================================================================= */
|
||
|
||
#ifndef AF_INET
|
||
#define AF_INET 2
|
||
#endif
|
||
#ifndef SOCK_STREAM
|
||
#define SOCK_STREAM 1
|
||
#endif
|
||
#ifndef SOL_SOCKET
|
||
#define SOL_SOCKET 0xFFF
|
||
#endif
|
||
#ifndef SO_REUSEADDR
|
||
#define SO_REUSEADDR 0x0004
|
||
#endif
|
||
#ifndef INADDR_ANY
|
||
#define INADDR_ANY 0x00000000
|
||
#endif
|
||
#ifndef F_GETFL
|
||
#define F_GETFL 3
|
||
#endif
|
||
#ifndef F_SETFL
|
||
#define F_SETFL 4
|
||
#endif
|
||
#ifndef O_NONBLOCK
|
||
#define O_NONBLOCK 0x0004
|
||
#endif
|
||
#ifndef EWOULDBLOCK
|
||
#define EWOULDBLOCK 11
|
||
#endif
|
||
#ifndef EAGAIN
|
||
#define EAGAIN 11
|
||
#endif
|
||
#ifndef ECONNRESET
|
||
#define ECONNRESET 104
|
||
#endif
|
||
#ifndef EPIPE
|
||
#define EPIPE 32
|
||
#endif
|
||
#ifndef ECONNABORTED
|
||
#define ECONNABORTED 103
|
||
#endif
|
||
#ifndef ETIMEDOUT
|
||
#define ETIMEDOUT 110
|
||
#endif
|
||
#ifndef ENETDOWN
|
||
#define ENETDOWN 100
|
||
#endif
|
||
#ifndef ENETUNREACH
|
||
#define ENETUNREACH 101
|
||
#endif
|
||
#ifndef EHOSTUNREACH
|
||
#define EHOSTUNREACH 113
|
||
#endif
|
||
#ifndef errno
|
||
extern int errno;
|
||
#endif
|
||
|
||
#define TCP_LOCAL_PORT TCP_DEBUG_PORT
|
||
#define MAX_CLIENTS TCP_DEBUG_MAX_CLIENTS
|
||
|
||
typedef struct {
|
||
int server_socket;
|
||
int client_socket;
|
||
uint8_t is_client_connected;
|
||
struct sockaddr_in client_addr;
|
||
} tcp_socket_server_t;
|
||
|
||
static tcp_socket_server_t socket_server = {
|
||
.server_socket = -1,
|
||
.client_socket = -1,
|
||
.is_client_connected = 0,
|
||
};
|
||
|
||
static SemaphoreHandle_t socket_mutex = NULL;
|
||
|
||
static int tcp_socket_create_server(void)
|
||
{
|
||
int sock;
|
||
struct sockaddr_in server_addr;
|
||
int opt = 1;
|
||
|
||
sock = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
||
if (sock < 0) {
|
||
TCP_PRINT("Failed to create socket: %d\r\n", sock);
|
||
return -1;
|
||
}
|
||
|
||
lwip_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||
|
||
memset(&server_addr, 0, sizeof(server_addr));
|
||
server_addr.sin_family = AF_INET;
|
||
server_addr.sin_addr.s_addr = INADDR_ANY;
|
||
server_addr.sin_port = htons(TCP_LOCAL_PORT);
|
||
|
||
if (lwip_bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
||
TCP_PRINT("Failed to bind socket to port %d\r\n", TCP_LOCAL_PORT);
|
||
lwip_close(sock);
|
||
return -1;
|
||
}
|
||
|
||
if (lwip_listen(sock, MAX_CLIENTS) < 0) {
|
||
TCP_PRINT("Failed to listen on socket\r\n");
|
||
lwip_close(sock);
|
||
return -1;
|
||
}
|
||
|
||
{
|
||
int flags = lwip_fcntl(sock, F_GETFL, 0);
|
||
lwip_fcntl(sock, F_SETFL, flags | O_NONBLOCK);
|
||
}
|
||
|
||
TCP_PRINT("TCP server socket created on port %d\r\n", TCP_LOCAL_PORT);
|
||
return sock;
|
||
}
|
||
|
||
static int tcp_socket_init(void)
|
||
{
|
||
socket_mutex = xSemaphoreCreateMutex();
|
||
if (socket_mutex == NULL) {
|
||
TCP_PRINT("Failed to create socket mutex\r\n");
|
||
return -1;
|
||
}
|
||
|
||
socket_server.server_socket = tcp_socket_create_server();
|
||
if (socket_server.server_socket < 0) {
|
||
vSemaphoreDelete(socket_mutex);
|
||
socket_mutex = NULL;
|
||
return -1;
|
||
}
|
||
|
||
socket_server.client_socket = -1;
|
||
socket_server.is_client_connected = 0;
|
||
|
||
TCP_PRINT("Socket server initialized successfully\r\n");
|
||
return 0;
|
||
}
|
||
|
||
static int tcp_socket_accept_client(void)
|
||
{
|
||
struct sockaddr_in client_addr;
|
||
socklen_t addr_len = sizeof(client_addr);
|
||
int new_sock;
|
||
|
||
if (socket_server.server_socket < 0) {
|
||
return -1;
|
||
}
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreTake(socket_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
new_sock = lwip_accept(socket_server.server_socket,
|
||
(struct sockaddr *)&client_addr, &addr_len);
|
||
|
||
if (new_sock >= 0) {
|
||
if (socket_server.is_client_connected) {
|
||
TCP_PRINT("Rejecting new connection - already have a client\r\n");
|
||
lwip_close(new_sock);
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
{
|
||
int flags = lwip_fcntl(new_sock, F_GETFL, 0);
|
||
lwip_fcntl(new_sock, F_SETFL, flags | O_NONBLOCK);
|
||
}
|
||
|
||
socket_server.client_socket = new_sock;
|
||
socket_server.is_client_connected = 1;
|
||
memcpy(&socket_server.client_addr, &client_addr, sizeof(client_addr));
|
||
|
||
TCP_PRINT("Client connected from %s:%d\r\n",
|
||
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
|
||
}
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
|
||
return (new_sock >= 0) ? 1 : 0;
|
||
}
|
||
|
||
static int tcp_socket_receive_data(uint8_t *buffer, uint32_t buffer_size)
|
||
{
|
||
int received;
|
||
|
||
if (buffer == NULL || buffer_size == 0U) {
|
||
return -1;
|
||
}
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreTake(socket_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
if (!socket_server.is_client_connected || socket_server.client_socket < 0) {
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
received = lwip_recv(socket_server.client_socket, buffer, buffer_size, 0);
|
||
|
||
if (received > 0) {
|
||
TCP_PRINT("Received %d bytes from client\r\n", received);
|
||
} else if (received == 0) {
|
||
TCP_PRINT("Client disconnected\r\n");
|
||
lwip_close(socket_server.client_socket);
|
||
socket_server.client_socket = -1;
|
||
socket_server.is_client_connected = 0;
|
||
received = -1;
|
||
#if FATFS_EN
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
#endif
|
||
} else {
|
||
int err = errno;
|
||
if (err != EWOULDBLOCK && err != EAGAIN) {
|
||
TCP_PRINT("Socket receive error: %d\r\n", err);
|
||
if (err == ECONNRESET || err == EPIPE || err == ECONNABORTED ||
|
||
err == ETIMEDOUT || err == ENETDOWN || err == ENETUNREACH ||
|
||
err == EHOSTUNREACH) {
|
||
TCP_PRINT("Connection error detected, closing socket\r\n");
|
||
lwip_close(socket_server.client_socket);
|
||
socket_server.client_socket = -1;
|
||
socket_server.is_client_connected = 0;
|
||
#if FATFS_EN
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
#endif
|
||
}
|
||
received = -1;
|
||
} else {
|
||
received = 0;
|
||
}
|
||
}
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
|
||
return received;
|
||
}
|
||
|
||
static int tcp_socket_send_data(const uint8_t *data, uint32_t len)
|
||
{
|
||
int sent;
|
||
|
||
if (data == NULL || len == 0U) {
|
||
return -1;
|
||
}
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreTake(socket_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
if (!socket_server.is_client_connected || socket_server.client_socket < 0) {
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
sent = lwip_send(socket_server.client_socket, data, len, 0);
|
||
|
||
if (sent > 0) {
|
||
TCP_PRINT("Sent %d bytes to client\r\n", sent);
|
||
} else {
|
||
TCP_PRINT("Failed to send data: %d\r\n", sent);
|
||
if (sent < 0) {
|
||
int err = errno;
|
||
if (err == ECONNRESET || err == EPIPE) {
|
||
TCP_PRINT("Connection broken, closing socket\r\n");
|
||
lwip_close(socket_server.client_socket);
|
||
socket_server.client_socket = -1;
|
||
socket_server.is_client_connected = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
|
||
return sent;
|
||
}
|
||
|
||
static int tcp_socket_is_client_connected(void)
|
||
{
|
||
int connected;
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreTake(socket_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
connected = socket_server.is_client_connected;
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
|
||
return connected;
|
||
}
|
||
|
||
static void tcp_socket_close_client(void)
|
||
{
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreTake(socket_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
if (socket_server.client_socket >= 0) {
|
||
lwip_close(socket_server.client_socket);
|
||
socket_server.client_socket = -1;
|
||
}
|
||
|
||
socket_server.is_client_connected = 0;
|
||
|
||
#if FATFS_EN
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
#endif
|
||
|
||
TCP_PRINT("Client connection closed\r\n");
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
}
|
||
|
||
static void tcp_socket_close_server(void)
|
||
{
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreTake(socket_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
if (socket_server.client_socket >= 0) {
|
||
lwip_close(socket_server.client_socket);
|
||
socket_server.client_socket = -1;
|
||
}
|
||
|
||
if (socket_server.server_socket >= 0) {
|
||
lwip_close(socket_server.server_socket);
|
||
socket_server.server_socket = -1;
|
||
}
|
||
|
||
socket_server.is_client_connected = 0;
|
||
|
||
#if FATFS_EN
|
||
fatfs_set_write_disable_flag(FATFS_WRITE_DISABLE_TCP_DEBUG, 0);
|
||
#endif
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
vSemaphoreDelete(socket_mutex);
|
||
socket_mutex = NULL;
|
||
}
|
||
|
||
TCP_PRINT("Socket server closed\r\n");
|
||
}
|
||
|
||
static int tcp_socket_get_client_ip(char *ip_buffer, uint32_t buffer_size)
|
||
{
|
||
const char *ip_str;
|
||
|
||
if (ip_buffer == NULL || buffer_size == 0U) {
|
||
return -1;
|
||
}
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreTake(socket_mutex, portMAX_DELAY);
|
||
}
|
||
|
||
if (!socket_server.is_client_connected) {
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
ip_str = inet_ntoa(socket_server.client_addr.sin_addr);
|
||
if (ip_str != NULL) {
|
||
strncpy(ip_buffer, ip_str, buffer_size - 1U);
|
||
ip_buffer[buffer_size - 1U] = '\0';
|
||
} else {
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
if (socket_mutex != NULL) {
|
||
xSemaphoreGive(socket_mutex);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* =============================================================================
|
||
* comm_link 分发(原 comm_link.c)
|
||
* ============================================================================= */
|
||
|
||
#define SESS (comm_link_session())
|
||
|
||
static uint8_t comm_link_using_ble(void)
|
||
{
|
||
#if BLE_DEBUG_EN
|
||
return (SESS->type == COMM_LINK_BLE) ? 1U : 0U;
|
||
#else
|
||
return 0U;
|
||
#endif
|
||
}
|
||
|
||
void comm_link_set_type(comm_link_type_t type)
|
||
{
|
||
SESS->type = type;
|
||
}
|
||
|
||
comm_link_type_t comm_link_get_type(void)
|
||
{
|
||
return SESS->type;
|
||
}
|
||
|
||
comm_link_type_t comm_link_type_from_dip(void)
|
||
{
|
||
#if BLE_DEBUG_EN
|
||
return ble_link_is_bt_mode() ? COMM_LINK_BLE : COMM_LINK_TCP;
|
||
#else
|
||
return COMM_LINK_TCP;
|
||
#endif
|
||
}
|
||
|
||
int comm_link_start(void)
|
||
{
|
||
if (comm_link_using_ble() != 0U) {
|
||
#if BLE_DEBUG_EN
|
||
return comm_link_ble_start();
|
||
#endif
|
||
}
|
||
return tcp_socket_init();
|
||
}
|
||
|
||
void comm_link_stop(void)
|
||
{
|
||
if (comm_link_using_ble() != 0U) {
|
||
#if BLE_DEBUG_EN
|
||
comm_link_ble_stop();
|
||
#endif
|
||
return;
|
||
}
|
||
tcp_socket_close_server();
|
||
}
|
||
|
||
void comm_link_process(void)
|
||
{
|
||
#if BLE_DEBUG_EN
|
||
if (comm_link_using_ble() != 0U) {
|
||
comm_link_ble_process();
|
||
}
|
||
#endif
|
||
}
|
||
|
||
int comm_link_accept_client(void)
|
||
{
|
||
if (comm_link_using_ble() != 0U) {
|
||
return 0;
|
||
}
|
||
return tcp_socket_accept_client();
|
||
}
|
||
|
||
int comm_link_is_client_connected(void)
|
||
{
|
||
if (comm_link_using_ble() != 0U) {
|
||
#if BLE_DEBUG_EN
|
||
return comm_link_ble_is_client_connected();
|
||
#endif
|
||
return 0;
|
||
}
|
||
return tcp_socket_is_client_connected();
|
||
}
|
||
|
||
void comm_link_close_client(void)
|
||
{
|
||
if (comm_link_using_ble() != 0U) {
|
||
#if BLE_DEBUG_EN
|
||
comm_link_ble_close_client();
|
||
#endif
|
||
return;
|
||
}
|
||
tcp_socket_close_client();
|
||
}
|
||
|
||
int comm_link_receive_data(uint8_t *buffer, uint32_t buffer_size)
|
||
{
|
||
if (comm_link_using_ble() != 0U) {
|
||
#if BLE_DEBUG_EN
|
||
return comm_link_ble_receive_data(buffer, buffer_size);
|
||
#endif
|
||
return 0;
|
||
}
|
||
return tcp_socket_receive_data(buffer, buffer_size);
|
||
}
|
||
|
||
int comm_link_send_data(const uint8_t *data, uint32_t len)
|
||
{
|
||
if (comm_link_using_ble() != 0U) {
|
||
#if BLE_DEBUG_EN
|
||
return comm_link_ble_send_data(data, len);
|
||
#endif
|
||
return -1;
|
||
}
|
||
return tcp_socket_send_data(data, len);
|
||
}
|
||
|
||
int comm_link_get_peer_info(char *buf, uint32_t buf_size)
|
||
{
|
||
if ((buf == NULL) || (buf_size == 0U)) {
|
||
return -1;
|
||
}
|
||
|
||
if (SESS->peer_info[0] != '\0') {
|
||
(void)snprintf(buf, buf_size, "%s", SESS->peer_info);
|
||
return 0;
|
||
}
|
||
|
||
if (comm_link_using_ble() != 0U) {
|
||
#if BLE_DEBUG_EN
|
||
return comm_link_ble_get_peer_info(buf, buf_size);
|
||
#endif
|
||
}
|
||
return tcp_socket_get_client_ip(buf, buf_size);
|
||
}
|
||
|
||
#else /* TCP_DEBUG_EN */
|
||
|
||
comm_link_ctx_t *comm_link_ctx_get(void) { return NULL; }
|
||
comm_link_session_t *comm_link_session(void) { return NULL; }
|
||
void comm_link_ctx_reset_session(void) { }
|
||
void comm_link_ctx_reset_all(void) { }
|
||
|
||
void comm_link_set_type(comm_link_type_t type) { (void)type; }
|
||
comm_link_type_t comm_link_get_type(void) { return COMM_LINK_TCP; }
|
||
comm_link_type_t comm_link_type_from_dip(void) { return COMM_LINK_TCP; }
|
||
int comm_link_start(void) { return -1; }
|
||
void comm_link_stop(void) { }
|
||
void comm_link_process(void) { }
|
||
int comm_link_accept_client(void) { return -1; }
|
||
int comm_link_is_client_connected(void) { return 0; }
|
||
void comm_link_close_client(void) { }
|
||
int comm_link_receive_data(uint8_t *buffer, uint32_t buffer_size)
|
||
{
|
||
(void)buffer;
|
||
(void)buffer_size;
|
||
return -1;
|
||
}
|
||
int comm_link_send_data(const uint8_t *data, uint32_t len)
|
||
{
|
||
(void)data;
|
||
(void)len;
|
||
return -1;
|
||
}
|
||
int comm_link_get_peer_info(char *buf, uint32_t buf_size)
|
||
{
|
||
(void)buf;
|
||
(void)buf_size;
|
||
return -1;
|
||
}
|
||
|
||
#endif /* TCP_DEBUG_EN */
|