此代码为接收STM32的数据然后直接转发到网络调试助手,当有设备连接到esp32软件热点时会通过串口发送字符’a’给STM32,当有设备断开连接时会通过串口发送字符’b’,
ESP32的TX:GPIO4, RX:GPIO5
ESP32作为TCP服务器地址为192.168.4.1 监听端口为3333
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/err.h" //lwip错误代码
#include "lwip/sys.h"
#include "sdkconfig.h"
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include "esp_netif.h"
#include <sys/param.h>
#include "esp_system.h"
#include "lwip/sockets.h"
#include <lwip/netdb.h>
#include "driver/uart.h"
#include "driver/gpio.h"#define EXAMPLE_ESP_WIFI_SSID "laotie666" // 热点名
#define EXAMPLE_ESP_WIFI_PASS "12345678" // 热点密码
#define EXAMPLE_ESP_WIFI_CHANNEL CONFIG_ESP_WIFI_CHANNEL // 信道(来自menuconfig)
#define EXAMPLE_MAX_STA_CONN CONFIG_ESP_MAX_STA_CONN // 最大连接数(来自menuconfig)
#define CONFIG_EXAMPLE_IPV4 1 // 启用IPv4
#define PORT 3333 // 服务器监听的端口号
#define KEEPALIVE_IDLE 5 // TCP Keepalive空闲时间(秒)
#define KEEPALIVE_INTERVAL 5 // Keepalive探测间隔(秒)
#define KEEPALIVE_COUNT 3 // 超时前的探测次数
#define EX_UART_NUM UART_NUM_1 // 使用UART1端口
#define BUF_SIZE (1024) // UART缓冲区大小
#define RD_BUF_SIZE (BUF_SIZE) // 读取缓冲区大小/*函数声明*/uint8_t mac[6];
// 日志标签
static const char *TAG = "wifi softAP";
static const char *TAG_ZH = "Zhanghui:";static uint8_t uart_buffer1[1024];
uint8_t uart_data;static QueueHandle_t uart0_queue;// 当建立tcp连接之后才会进行串口接收震动数据
uint8_t uart_re_en_flag = 0;
// TCP发送错误标志
int tcp_send_error_flag;// WiFi事件处理函数
static void wifi_event_handler(void *arg, esp_event_base_t event_base,int32_t event_id, void *event_data)
{if (event_id == WIFI_EVENT_AP_STACONNECTED){// 有设备连接到我们的软件热点时会触发这个事件wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;ESP_LOGI(TAG, "station " MACSTR " join, AID=%d",MAC2STR(event->mac), event->aid);// 当有设备连接到esp32软件热点时会通过串口发送字符’a’uart_data = 'a';uart_write_bytes(EX_UART_NUM, &uart_data, 1);}else if (event_id == WIFI_EVENT_AP_STADISCONNECTED){// 断开连接时wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;// 打印断开设备的信息,如ipESP_LOGI(TAG, "station " MACSTR " leave, AID=%d, reason=%d",MAC2STR(event->mac), event->aid, event->reason);// 当有设备断开连接时会通过串口发送字符’b’uart_data = 'b';uart_write_bytes(EX_UART_NUM, &uart_data, 1);}
}// 初始化SoftAP模式
void wifi_init_softap(void)
{// 通过调用esp_netif_init()来启动LWIPtaskESP_ERROR_CHECK(esp_netif_init()); // 初始化底层TCP/IP栈// 通过esp_event_loop_create_default()来创建启动事件task--eventtaskESP_ERROR_CHECK(esp_event_loop_create_default()); // 创建默认事件循环esp_netif_create_default_wifi_ap(); // 创建默认WIFI AP网络接口// 初始化WIFI驱动配置为默认值wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();// esp_wifi_init() 初始化WIFI driverESP_ERROR_CHECK(esp_wifi_init(&cfg));// 4.对我们所需处理的一些事件注册了一个回调函数wifi_event_handlerESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&wifi_event_handler,NULL,NULL));// 配置driverwifi_config_t wifi_config = {.ap = {.ssid = EXAMPLE_ESP_WIFI_SSID, // 热点的名字.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID), // SSID长度.channel = EXAMPLE_ESP_WIFI_CHANNEL, // 无线信道 WiFi信号工作在2.4GHz或5GHz频段(取决于设备支持),这些频段被划分为多个子频段,每个子频段称为一个信道。.password = EXAMPLE_ESP_WIFI_PASS, // 热点的密码.max_connection = EXAMPLE_MAX_STA_CONN, // 热点的最大连接数目
#ifdef CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT // 用于根据系统配置决定使用哪种 Wi-Fi 安全协议.authmode = WIFI_AUTH_WPA3_PSK, // 授权的模式,登录的加密模式 // WPA3加密模式.sae_pwe_h2e = WPA3_SAE_PWE_BOTH, // SAE密码交换方法
#else /* CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT */.authmode = WIFI_AUTH_WPA2_PSK, // 默认WPA2加密
#endif.pmf_cfg = {// 受保护的管理帧配置.required = true, // 要求PMF},},};// 如果密码为空则使用开放模式if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0){wifi_config.ap.authmode = WIFI_AUTH_OPEN;}// 使用esp_wifi_set_mode()对driver进行配置ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); // 设置WIFI为AP模式// 应用AP配置ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));// 启动driverESP_ERROR_CHECK(esp_wifi_start()); // 启动WIFI// 打印热点配置信息ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}
/*wifi driver被启动之后, 会发送WIFI_EVENT_AP_START这个事件到event Task中,如果有处理这个事件的回调函数,就会再这个回调函数中进行处理;如果有设备进行连接,就会发送WIFI_EVENT_AP_STACONNECTED这个事件到event Task,之后再wifi_event_handler中进行处理(实例代码中只是打印了相应的信息)如果有断开连接的事件WIFI_EVENT_AP_STADISCONNECTED,也会发送到event Task,event Task调用wifi_event_handler进行处理
*/// 数据转发函数
static void do_retransmit(const int sock)
{int len;uart_event_t event; // UART事件结构体uint8_t *dtmp = (uint8_t *)malloc(RD_BUF_SIZE);while (1){//从名为`uart0_queue`的队列中接收数据,并将接收到的数据存储到`event`变量中,如果没有数据可接收,则无限期等待(阻塞)直到有数据到来。if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY)){//清零内存区域,即将这段内存区域中的所有字节都设置为0,与memset()函数类似但功能受限。由于bzero()已被废弃,推荐使用memset()进行内存设置。bzero(dtmp, RD_BUF_SIZE);ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);switch (event.type){// 接收到的数据通常会在这里被处理 dtmp指向接收到的数据 event.size为接收到数据的大小case UART_DATA: {ESP_LOGI(TAG, "[UART DATA]: %d", event.size);uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);int written = send(sock, dtmp, event.size, 0);if (written < 0){ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);// Failed to retransmit, giving upreturn;}}break;// 硬件FIFO溢出事件case UART_FIFO_OVF:ESP_LOGI(TAG, "hw fifo overflow");// If fifo overflow happened, you should consider adding flow control for your application.// The ISR has already reset the rx FIFO,// As an example, we directly flush the rx buffer here in order to read more data.uart_flush_input(EX_UART_NUM);xQueueReset(uart0_queue);break;// 环形缓冲区满事件case UART_BUFFER_FULL:ESP_LOGI(TAG, "ring buffer full");// If buffer full happened, you should consider increasing your buffer size// As an example, we directly flush the rx buffer here in order to read more data.uart_flush_input(EX_UART_NUM);xQueueReset(uart0_queue);break;// 检测到UART线路断开case UART_BREAK:ESP_LOGI(TAG, "uart rx break");break;// 帧错误case UART_FRAME_ERR:ESP_LOGI(TAG, "uart frame error");break;default:ESP_LOGI(TAG, "uart event type: %d", event.type);break;}}}// do {// len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);// if (len < 0) {// ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);// } else if (len == 0) {// ESP_LOGW(TAG, "Connection closed");// } else {// rx_buffer[len] = 0; // Null-terminate whatever is received and treat it like a string// ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer);// // send() can return less bytes than supplied length.// // Walk-around for robust implementation.// int to_write = len;// while (to_write > 0) {// int written = send(sock, rx_buffer + (len - to_write), to_write, 0);// if (written < 0) {// ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);// // Failed to retransmit, giving up// return;// }// to_write -= written;// }// }// } while (len > 0);
}
/* UART事件处理任务 */// TCP服务器任务
static void tcp_server_task(void *pvParameters)
{char addr_str[128]; // 存储客户端IP字符串int addr_family = (int)pvParameters; // 获取地址族参数int ip_protocol = 0; // IP协议类型int keepAlive = 1; // 启用Keepaliveint keepIdle = 5; // Keepalive空闲时间int keepInterval = 5; // 探测间隔int keepCount = 3; // 探测次数struct sockaddr_storage dest_addr; // 服务器地址存储结构// 配置服务器地址if (addr_family == AF_INET){struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有接口dest_addr_ip4->sin_family = AF_INET; // IPv4地址族dest_addr_ip4->sin_port = htons(PORT); // 设置端口ip_protocol = IPPROTO_IP; // IP协议}// 创建监听套接字ESP_LOGE(TAG_ZH, "create socket");int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);if (listen_sock < 0){ESP_LOGE(TAG_ZH, "Unable to create socket: errno %d", errno);vTaskDelete(NULL);return;}// 设置套接字选项(地址重用)int opt = 1;setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
#if defined(CONFIG_EXAMPLE_IPV4) && defined(CONFIG_EXAMPLE_IPV6)// Note that by default IPV6 binds to both protocols, it is must be disabled// if both protocols used at the same time (used in CI)setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
#endifESP_LOGI(TAG, "套接字已创建");int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));if (err != 0){ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); // 套接字绑定失败ESP_LOGE(TAG, "IPPROTO: %d", addr_family);goto CLEAN_UP;}ESP_LOGI(TAG, "Socket bound, port %d", PORT);err = listen(listen_sock, 1); // 最大挂起连接数为1if (err != 0){ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);goto CLEAN_UP;}while (1){struct sockaddr_storage source_addr; // 客户端地址存储socklen_t addr_len = sizeof(source_addr);// 接受客户端连接int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);if (sock < 0){ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);break;}// 设置TCP Keepalive选项setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int));setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int));setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int));setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int));// 将客户端IP地址转换为字符串
#ifdef CONFIG_EXAMPLE_IPV4if (source_addr.ss_family == PF_INET){inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1);}
#endif
#ifdef CONFIG_EXAMPLE_IPV6if (source_addr.ss_family == PF_INET6){inet6_ntoa_r(((struct sockaddr_in6 *)&source_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1);}
#endifESP_LOGI(TAG_ZH, "Socket accepted ip address: %s", addr_str); // 接受的客户端IP:uart_re_en_flag = 1; // 设置标志位,表示可以接收串口数据// do_retransmit(sock);do_retransmit(sock);shutdown(sock, 0);close(sock);}CLEAN_UP:close(listen_sock);vTaskDelete(NULL);
}void app_main(void)
{// 初始化存储空间esp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND){ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}ESP_ERROR_CHECK(ret);uart_config_t uart_config = {.baud_rate = 115200,.data_bits = UART_DATA_8_BITS,.parity = UART_PARITY_DISABLE,.stop_bits = UART_STOP_BITS_1,.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,.source_clk = UART_SCLK_DEFAULT,};// 安装UART驱动程序(创建事件队列)uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);// 应用参数配置uart_param_config(EX_UART_NUM, &uart_config);// 设置UART引脚(TX:GPIO4, RX:GPIO5)uart_set_pin(EX_UART_NUM, GPIO_NUM_4, GPIO_NUM_5, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");ESP_ERROR_CHECK(esp_efuse_mac_get_default(mac));wifi_init_softap();xTaskCreate(tcp_server_task, "tcp_server", 4096, (void *)AF_INET, 5, NULL);
}