AP模式/ESP32作为TCP服务端,转发串口接收的数据给网络调试助手

此代码为接收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);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/95418.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/95418.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kafka 中的Broker 是什么?它在集群中起什么作用?

Kafka中的Broker&#xff1a;集群的核心支柱 在分布式消息系统Apache Kafka中&#xff0c;Broker是构成Kafka集群的核心节点或服务器。 简单来说&#xff0c;每一个Broker就是运行着Kafka服务的一个实例&#xff0c;多台Broker共同协作&#xff0c;形成了强大的、可扩展的消息处…

【SOA用于噪声抑制】光纤DFB激光器中弛豫振荡噪声抑制

概述&#xff1a;本章记录了我们在光纤分布式反馈DFB激光器中使用饱和SOA来降低RIN的工作&#xff0c;以用于低频传感器应用。结果表明&#xff0c;放大器的增益动力学允许光纤激光器的弛豫振荡RO噪声分量减少30dB。 1 背景到目前为止&#xff0c;我研究了将饱和半导体光放大器…

神经网络的核心组件解析:从理论到实践

神经网络作为深度学习的核心技术&#xff0c;其复杂性常常令人望而却步。然而&#xff0c;尽管神经网络的结构、参数和计算过程看似繁琐&#xff0c;但其核心组件却是相对简洁且易于理解的。本文将深入探讨神经网络的四大核心组件——层、模型、损失函数与优化器&#xff0c;并…

Spring Boot项目通过Feign调用三方接口的详细教程

目录 一、环境准备 二、启用Feign客户端 三、定义Feign客户端接口 四、定义请求/响应DTO 五、调用Feign客户端 六、高级配置 1. 添加请求头&#xff08;如认证&#xff09; 2. 超时配置&#xff08;application.yml&#xff09; 3. 日志配置 七、错误处理 自定义错误…

ubuntu24.04安装 bpftool 以及生成 vmlinux.h 文件

文章目录前言一、apt安装二、源码安装三、生成vmlinux.h参考资料前言 $ cat /etc/os-release PRETTY_NAME"Ubuntu 24.04.2 LTS"$ uname -r 6.14.0-27-generic一、apt安装 安装bpftool&#xff1a; $ sudo apt install linux-tools-commonThe following NEW packa…

Pytorch FSDP权重分片保存与合并

注&#xff1a;本文章方法只适用Pytorch FSDP1的模型&#xff0c;且切分策略为SHARDED_STATE_DICT场景。 在使用FSDP训练模型时&#xff0c;为了节省显存通常会把模型权重也进行切分&#xff0c;在保存权重时为了加速保存通常每个进程各自保存自己持有的部分权重&#xff0c;避…

IDEA自动生成Mapper、XML和实体文件

1. 引入插件 <build><finalName>demo</finalName><plugins><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.5</version><depe…

单例模式的理解

目录单例模式1.饿汉式(线程安全)2.懒汉式(通过synchronized修饰获取实例的方法保证线程安全)3.双重校验锁的方式实现单例模式4.静态内部类方式实现单例模式【推荐】单例模式 1.饿汉式(线程安全) package 并发的例子.单例模式; // 饿汉式单例模式&#xff08;天然线程安全&…

NLP---IF-IDF案例分析

一案例 - 红楼梦1首先准备语料库http://www.dxsxs.com这个网址去下载2 任务一&#xff1a;拆分提取import os import redef split_hongloumeng():# 1. 配置路径&#xff08;关键&#xff1a;根据实际文件位置修改&#xff09; # 脚本所在文件夹&#xff08;自动获取&#xff0…

LaTeX(排版系统)Texlive(环境)Vscode(编辑器)环境配置与安装

LaTeX、Texlive 和 Vscode 三者之间的关系&#xff0c;可以把它们理解成语言、工具链和编辑器的配合关系。 1.下载Texlive 华为镜像网站下载 小编这边下载的是texlive2025.iso最新版的&#xff0c;下载什么版本看自己需求&#xff0c;只要下载后缀未.iso的即可。为避免错误&am…

【深入浅出STM32(1)】 GPIO 深度解析:引脚特性、工作模式、速度选型及上下拉电阻详解

GPIO 深度解析&#xff1a;引脚特性、工作模式、速度选型及上下拉电阻详解一、GPIO概述二、GPIO的工作模式1、简述&#xff08;1&#xff09;4种输入模式&#xff08;2&#xff09;4种输出模式&#xff08;3&#xff09;4种最大输出速度2、引脚速度&#xff08;1&#xff09;输…

第1节 大模型分布式推理基础与技术体系

前言:为什么分布式推理是大模型时代的核心能力? 当我们谈论大模型时,往往首先想到的是训练阶段的千亿参数、千卡集群和数月的训练周期。但对于商业落地而言,推理阶段的技术挑战可能比训练更复杂。 2025年,某头部AI公司推出的130B参数模型在单机推理时面临两个选择:要么…

《软件工程导论》实验报告一 软件工程文档

目 录 一、实验目的 二、实验环境 三、实验内容与步骤 四、实验心得 一、实验目的 1. 理解软件工程的基本概念&#xff0c;熟悉软件&#xff0c;软件生命周期&#xff0c;软件生存周期过程和软件生命周期各阶段的定义和内容。 2. 了解软件工程文档的类别、内容及撰写软件工…

基于elk实现分布式日志

1.基本介绍 1.1 什么是分布式日志 在分布式应用中&#xff0c;日志被分散在储存不同的设备上。如果你管理数十上百台服务器&#xff0c;你还在使用依次登录每台机器的传统方法查阅日志。这样是不是感觉很繁琐和效率低下。所以我们使用集中化的日志管理&#xff0c;分布式日志…

多模态RAG赛题实战之策略优化--Datawhale AI夏令营

科大讯飞AI大赛&#xff08;多模态RAG方向&#xff09; - Datawhale 项目流程图 1、升级数据解析方案&#xff1a;从 fitz 到 MinerU PyMuPDF&#xff08;fitz&#xff09;是基于规则的方式提取pdf里面的数据&#xff1b;MinerU是基于深度学习模型通过把PDF内的页面看成是图片…

09--解密栈与队列:数据结构核心原理

1. 栈 1.1. 栈的简介 栈 是一种 特殊的线性表&#xff0c;具有数据 先进后出 特点。 注意&#xff1a; stack本身 不支持迭代器操作 主要原因是因为stack不支持数据的随机访问&#xff0c;必须保证数据先进后出的特点。stack在CPP库中实现为一种 容器适配器 所谓容器适配器&a…

打造专属 React 脚手架:从 0 到 1 开发 CLI 工具

前言: 在前端开发中&#xff0c;重复搭建项目环境是个低效的事儿。要是团队技术栈固定&#xff08;比如 React AntD Zustand TS &#xff09;&#xff0c;每次从零开始配路由、状态管理、UI 组件&#xff0c;既耗时又容易出错。这时候&#xff0c;自定义 CLI 脚手架 就派上…

Python day43

浙大疏锦行 Python day43 import torch import numpy as np import pandas as pd import torchvision import torchvision.transforms as transforms import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torch.utils.data import Da…

python基于Hadoop的超市数据分析系统

前端开发框架:vue.js 数据库 mysql 版本不限 后端语言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 数据库工具&#xff1a;Navicat/SQLyog等都可以 摘要&…

如何用 COLMAP 制作 Blender 格式的数据集

如何用 COLMAP 制作 Blender 格式的数据集并划分出 transforms_train.json、transforms_val.json 和 transforms_test.json。 一、什么是 Blender 格式数据集? Blender 格式数据集是 Nerf 和 Nerfstudio 常用的输入格式,其核心是包含了相机内外参的 JSON 文件,一般命名为:…