ESP32 应用实践:ethernet 转 WiFi 实现_esp32以太网转wifi-程序员宅基地

技术标签: 应用实践 (Applications)  ESP32  无线网卡  以太网转WiFi  WiFi  以太网  

一:简介

Ethernet 转 WiFi 用于实现以太网口的设备通过 WiFi 进行无线互联。将从设备 发出的 802.3 帧数据转化为 802.11 帧数据发送出去,接收到的 802.11 帧数据转换为 802.3 帧数据发送给设备,其跳过了 ESP32 的 lwip,直接在物理层进行了数据的转发,提高了数据转发的效率。

在本 Demo 中,Ethernet 转 WiFi 主要有两种使用方式:STATION 模式和 SOFTAP 模式,

二:硬件准备

实现 Ethernet 转 WiFi 需使用带有 phy 功能的 ESP32 开发板,本 Demo 使用的是 ESP32_Ethernet_v3。对于普通的 ESP32 开发板,想要实现本 Demo 需外接 PHY,目前 ESP32 Ethernt driver 支持的 phy 有 TLK110 和 LAN8720,而在 ESP32_Ethernet_v3 中集成的是 TLK110 。

image

image

三:配置说明

3.1 PHY 配置

用户可以在 make menuconfig 中对 PHY 进行配置。如果使用 ESP32_Ethernet_v3 开发板,只需要使用默认配置即可;对于外接 phy 的用户,可以参照 Ethernet Demo 中的要求对 phy 进行修改。

3.2 WiFi 配置

WiFi 的配置主要是为了提高数据的吞吐率,在本 Demo 中,增加了 WiFi RX 和 TX 的 buffer 数量,并调整了 ESP32 的 CPU 时钟,具体优化信息请参照默认配置项 sdkconfig.defaults。

Note: 用户可以根据自己需要通过make menuconfig调整相关参数,但是 STATIC_RX_BUFFER_NUM和 TX/RX BA Window(the size of WiFi Block Ack TX window) 均不要超过 16 ,否则可能会因为内存问题引起 crash,其中这些参数位于 Component config -> Wi-Fi 下。

四:Demo 使用步骤

通过如下方式获取此 Demo

$ git clone  https://github.com/espressif/esp-iot-solution
$ cd esp-iot-solution
$ git submodule update --init --recursive

本 Demo 位于 esp-iot-solution/examples/eth2wifi 下,Demo 提供了 ethernet 转 WiFi 的两种模式:ESP32 作为 STATION 模式和 ESP32 作为 SOFTAP 模式。

4.1 STATION 模式

STATION 模式是设备将 Ethernet 帧数据转化为 WiFi station 帧数据,然后将 WiFi station 数据无线发送给 AP ,从而实现类似于无线网卡的功能。

a) 使用 USB 转串口线将开发板连接到 PC 上

b) 进入 esp-iot-solution/examples/eth2wifi 所在目录

c) 选择配置

$ make menuconfig
  • 在 Serial flasher config - Default serial port 中,配置需要下载的串口
  • 在 Component config - IoT Example - Ethernet to WiFi Demo Configuration - The SSID for demo 中设置 SSID
  • 在 Component config - IoT Example - Ethernet to WiFi Demo Configuration - The PASSWORD for demo 中设置 WiFi 密码
  • 在 Component config - IoT Example - Ethernet to WiFi Demo Configuration - WiFi station mode 中,输入 y,选择 STA 模式(默认即为 Y )

esp

d) 编译并烧录程序

$ make flash

e) 运行

  1. 烧录成功后,打开串口工具,此时会打印 log,根据 SSID 连接 AP,然后 PC 会发起 DHCP 请求

  2. 查看是否拿到 IP,并尝试 ping 网关来测试是否正常

4.2 SOFTAP 模式

SOFTAP 模式是利用 ESP32 所属的设备作为一个 AP,从而可以组建一个小型的局域网,因为交互需要 IP 信息,所以需要设备具备 DHCP Server 的能力,在本 Demo 中,使用 PC 来作为 DHCP Server。

4.2.1 Ubuntu DHCP server 配置

Ubuntu 配置 dhcp 服务器需要:计算机设置静态 ip ,(充当 dhcp 服务器的计算机的 ip 需要是静态 ip,不可以是通过动态获得,设置静态 ip 需要设置在对应的网卡:如 eth0 )设置子网掩码,默认网关,以及配置 dhcp。

a) PC 设置静态 ip/子网掩码/网关

静态 ip 的配置:
设置–>系统设置–>网络–>选项–> ipv4 –>方法:手动;添加–> address, subnet, netmask.

我设置的静态ip地址:192.168.5.0,子网掩码:255.255.255.0,网关:192.168.5.1。

$ sudo vim /etc/network/interfaces

设置成如下内容:

 auto lo
 iface lo inet loopback
 auto eth0
 iface eth0 inet static
 address 192.168.5.0
 gateway 192.168.5.1
 netmask 255.255.255.0

Note: eth0 是测试 PC 上的网卡名称,不同的电脑网卡名称不同,可通过 ipconfig 查看,替换成自己的网卡名称即可
配置完成后重启网络服务:

sudo /etc/init.d/networking restart

b) 配置 DHCP 服务器

  • 首先安装 DHCP 服务器
$ sudo apt-get install isc-dhcpd-server
  • 配置 DHCP 的网卡
$ sudo vim /etc/default/isc-dhcp-server

设置使用网卡(我的是 eth0 )作为 DHCP Server

$ INTERFACES = "eth0"
  • 编辑当前配置
$ sudo vim /etc/dhcp/dhcpd.conf

在文件末尾添加如下几项

subnet 192.168.5.0  netmask 255.255.255.0 {
  range 192.168.5.0 192.168.5.100;
#  option domain-name-servers 210.30.100.2;
#  option domain-name "internal.example.org";
#  option routers 172.6.1.1;
  option broadcast-address 192.168.5.255;
  default-lease-time 600;
  max-lease-time 7200;  
}
  • 配置完成后,重启 dhcp 服务:
$ sudo /etc/init.d/isc-dhcpd-server restart

Note: /etc/dhcp/dhcpd.conf中的 subnet 一定要包含 server 本机的 ip 在内,否则启动不了

最后可以通过 ifconfig eth0 查看是否静态 IP 设置成功

c) 烧写步骤

烧写 softap 的步骤与 STA 基本相同,只需要在第 4 步时将 Ethernet to wifi station forwarding data 设置为 n 即为 softap 模式。

d) 运行

  1. 将 ESP32 连接到 PC 设备上,确保 PC 设备已经开启了 DHCP Server,配置方法请参照前文 Ubuntu 配置 DHCP server
  2. 给 ESP32 上电,并打开 PC 上的串口工具,此时串口会打印 log
  3. 用手机连接 ESP32 的 SSID(默认为 DEMO_TEST),成功后会在步骤 2 中打印 STA 连接成功的 Log
  4. 尝试 ping 手机拿到的 IP 地址测试是否正常

五:核心代码分析

5.1 事件处理

ESP32 代码中将网络中的各种状态全部封装成了事件,所以 Ethernet 转 WiFi 的核心是网络事件( Event )的处理;在本次 Demo 中,主要做了如下事件的处理:

static esp_err_t event_handler(void* ctx, system_event_t* event)
{
    switch (event->event_id) {
        case SYSTEM_EVENT_STA_START:
            printf("SYSTEM_EVENT_STA_START\r\n");
            break;

        case SYSTEM_EVENT_STA_CONNECTED:
            printf("SYSTEM_EVENT_STA_CONNECTED\r\n");
            wifi_is_connected = true;

            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, (wifi_rxcb_t)tcpip_adapter_sta_input_eth_output);

对于 SYSTEM_EVENT_STA_START 事件,我们并没有进行常见的 esp_wifi_connect() 操作,而是放在 Ethernet task 中进行,这么做主要是为了获取 PC 的 MAC 地址,然后将 sta 的 MAC 替换为 PC 的 MAC。
对于 SYSTEM_EVENT_STA_CONNECTED 事件,ESP32 连接上 AP 后,会进入此事件,在一般的网络交互中,此时开始进行 DHCP 请求操作,但因为此时 ESP32 只是作为一个管道,所以在这里我们并不是将数据抛给 lwip 而是将数据“窃取”并转发 给 Ethernet。

       case SYSTEM_EVENT_STA_GOT_IP:
            printf("SYSTEM_EVENT_STA_GOT_IP\r\n");
            break;

        case SYSTEM_EVENT_STA_DISCONNECTED:
            printf("SlYSTEM_EVENT_STA_DISCONNECTED\r\n");
            wifi_is_connected = false;
            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, NULL);
            esp_wifi_connect();
            break;

对于事件 SYSTEM_EVENT_STA_GOT_IP ,好吧,这个事件在这个 Demo 是不会被触发了,因为我们没使用 lwip 中的 DHCP client 功能。
当事件 SYSTEM_EVENT_STA_DISCONNECTED 被触发,我们要做的是让 Ethernet 收到的数据将不会通过 WiFi 进行转发,同时重连网络。


        case SYSTEM_EVENT_AP_STACONNECTED:
            printf("SYSTEM_EVENT_AP_STACONNECTED\r\n");
            wifi_is_connected = true;

            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_AP, (wifi_rxcb_t)tcpip_adapter_ap_input_eth_output);
            break;

        case SYSTEM_EVENT_AP_STADISCONNECTED:
            printf("SYSTEM_EVENT_AP_STADISCONNECTED\r\n");
            wifi_is_connected = false;
            esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_AP, NULL);
            break;

作为 AP 时事件处理和 STA 相同,区别是这里设置为 AP 模式,而不是 STA 模式。

        case SYSTEM_EVENT_ETH_CONNECTED:
            printf("SYSTEM_EVENT_ETH_CONNECTED\r\n");
            ethernet_is_connected = true;
            break;

        case SYSTEM_EVENT_ETH_DISCONNECTED:
            printf("SYSTEM_EVENT_ETH_DISCONNECTED\r\n");
            ethernet2wifi_mac_status_set(false);
            ethernet_is_connected = false;
            break;

Ethernet 事件的处理主要是探测以太网是否连接或者断开,同时在断开时,ethernet2wifi_mac_status_set 还要置为 false,以保证下次重新连接时重新替换 sta 的 mac 地址。

5.2 MAC地址设置

因为 Ethernet 转 WiFi 牵涉到 3 个 MAC(PC、Etherner 和 STA/AP ),而网络很多操作需要校验 MAC,为了确保在网络交互时 MAC 还能保持 PC 的 MAC,在本 Demo 中将 STA 的 MAC 设置为 PC 的 MAC。

if (!ethernet2wifi_mac_status_get()) {
   memcpy(eth_mac, (uint8_t*)msg.buffer + 6, sizeof(eth_mac));
   ESP_ERROR_CHECK(esp_wifi_start());
#ifdef CONFIG_ETH_TO_STATION_MODE
   esp_wifi_set_mac(WIFI_IF_STA, eth_mac);
   esp_wifi_connect();
#else
   esp_wifi_set_mac(WIFI_IF_AP, eth_mac);
#endif
   ethernet2wifi_mac_status_set(true);
 }

在 SYSTEM_EVENT_ETH_CONNECTED 事件被触发之后,PC 开始发送包含 MAC 地址的网络数据,如下图所示:

image

我们截取之后将 STA 的 MAC 地址设置为 PC 的 MAC 地址,此时再连接 AP,并将状态置为 true,以避免下次 PC 发送数据时重复设置 MAC。
在连接到 AP 之后,PC 再进行 DHCP 请求时,sta 就会使用 PC的 MAC 地址和 AP 进行交互,以此保证正常通讯。

六:性能指标分析

我们使用了 iperf 对吞吐率进行了简单的测试,在开放工作环境下,其 TCP 吞吐量稳定在 45Mbps 左右。但周围环境会对 WiFi 吞吐量造成较大影响,在环境较差时,WiFi 吞吐量可能会下降。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/espressif/article/details/78608462

智能推荐

双系统linux分多少内存,win+linux双系统的用户,你们的linux分了多少分区?-程序员宅基地

文章浏览阅读943次。hgywww 于 2010-02-03 22:19:15发表:挺好的调查kantiede 于 2010-01-31 14:39:50发表:学习爱唯一 于 2010-01-31 12:13:32发表:分给linux十个G,然后给他分了四个区sagawf 于 2009-11-17 21:03:54发表:win10Gfedora11 15Gyanchao1988 于 2009-11-17 11..._win+lin双系统lin配置多少储存

神经网络硕士就业前景,计算神经科学就业前景_神经网络就业-程序员宅基地

文章浏览阅读7.8k次。一、算法工程师简介(通常是月薪15k以上,年薪18万以上,只是一个概数,具体薪资可以到招聘网站如拉钩,猎聘网上看看)算法工程师目前是一个高端也是相对紧缺的职位;算法工程师包括音/视频算法工程师(通常统称为语音/视频/图形开发工程师)、图像处理算法工程师、计算机视觉算法工程师、通信基带算法工程师、信号算法工程师、射频/通信算法工程师、自然语言算法工程师、数据挖掘算法工程师、搜索算法工程师、控制算法工程师(云台算法工程师,飞控算法工程师,机器人控制算法)、导航算法工程师(@之介感谢补充)、其他【其他一切需要复杂_神经网络就业

Cocos Creator中使用对象池(官方文档摘录)_cocos creator网络请求时如何获取当前的对象-程序员宅基地

文章浏览阅读3k次。在运行时进行节点的创建(cc.instantiate)和销毁(node.destroy)操作是非常耗费性能的,因此我们在比较复杂的场景中,通常只有在场景初始化逻辑(onLoad)中才会进行节点的创建,在切换场景时才会进行节点的销毁。如果制作有大量敌人或子弹需要反复生成和被消灭的动作类游戏,我们要如何在游戏进行过程中随时创建和销毁节点呢?这里就需要对象池的帮助了。对象池的概念对象池就是一组可回收的节_cocos creator网络请求时如何获取当前的对象

网管软件——Acronis True Image Enterprise Server 9-程序员宅基地

文章浏览阅读206次。服务器的系统备份一直困饶着企业网管,ghost也是从版本8系列开始支持ntfs格式,虽说也可以达到了备份服务器系统的要求,但效果无法满足实时备份(系统运行过程中实行备份),现在介绍的是由acronis出品的Acronis True Image Enterprise Server可以实现一健(F11)进行备份及恢复,而且可以在增量备份,不影响系统正常运行的情况下。这是安装好后..._acronis true image 9

JDOM-程序员宅基地

文章浏览阅读57次。JDOM是一种使用 XML(标准通用标记语言下的一个子集) 的独特 Java 工具包,。它的设计包含 Java 语言的语法乃至语义。概述编辑JDOM是两位著名的 Java 开发人员兼作者,Brett Mclaughlin 和 Jason Hunter 的创作成果, 2000 年初在类似于Apache协议的许可下,JDOM作为一个开放源代码项目正式开始研发了。它已成长为包含来自...

LangChain-Chatchat学习资料-Windows开发部署(踩坑篇)_int4weightextractionhalf-程序员宅基地

文章浏览阅读832次。1.[LangChain-Chatchat学习资料-简介]2.[LangChain-Chatchat学习资料-Windows开发部署]3.[LangChain-Chatchat学习资料-Windows开发部署(踩坑篇)]4.LangChain-Chatchat学习资料-Ubuntu安装Nvidia驱动和CUDA5.LangChain-Chatchat学习资料-Ubuntu开发部署6.LangChain-Chatchat学习资料-Ubuntu开发部署(踩坑篇)_int4weightextractionhalf

随便推点

Java多线程知识点总结(思维导图+源码笔记,Java架构师成长路线-程序员宅基地

文章浏览阅读713次,点赞5次,收藏10次。又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考以下是部分内容截图最后又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考以下是部分内容截图。

Sci-Hub的URL使用_scihub url-程序员宅基地

文章浏览阅读2.7k次。目录标题@[TOC](目录标题)借鉴文章出处URL就是出版商的文章页面路径,要把文章的全部网址复制到Sci-Hub主页的搜索框进行搜索。_scihub url

如何从零将vue+springboot项目打包部署到云服务器(亲测,图文教程超详细!!)_spring boot vue 部署 图解-程序员宅基地

文章浏览阅读5.2k次,点赞30次,收藏115次。手把手教如何将个人项目部署到云服务器(超详细!!)步骤目录手把手教如何将个人项目部署到云服务器(超详细!!)前言一、云服务器设置1.1 首先去购买一个云服务器,阿里或腾讯,具体步骤就不讲了1.2 拿到服务器后先修改密码1.3 修改服务器安全组策略1.4 远程连接云服务器二、远程服务器环境配置2.1 安装jdk(1) 将Linux系统下自带JDK(如果原先安装过,无则忽略)的删除(2) JDK11的安装(3) 设置JAVA_HOME2.2 安装配置MySQL(1)下载mysql(2)卸载Maria DB_spring boot vue 部署 图解

Docker容器—Windows下的安装与使用_docker windows容器-程序员宅基地

文章浏览阅读5.8k次,点赞3次,收藏12次。Docker容器—Windows下的安装与使用_docker windows容器

云原生数据库性能对比(阿里云、百度智能云、腾讯云)-程序员宅基地

文章浏览阅读1.7k次,点赞27次,收藏27次。SysBench 是一个跨平台且支持多线程的模块化基准测试工具,用于评估系统在运行高负载的数据库时相关核心参数的性能表现。可绕过复杂的数据库基准设置,甚至在没有安装数据库的前提下,快速了解数据库系统的性能。

CAS单点登录6 - 服务端自定义返回的用户信息_如何获取单点登录自定义得值-程序员宅基地

文章浏览阅读3.9k次。原理返回的用户信息是在deployerConfigContext.xml中的配置的既然想自定义返回的用户信息,那么继承org.jasig.services.persondir.support.StubPersonAttributeDao就好了1、创建com.jadyer.sso.authentication extends StubPersonAttributeDao并复写getPer..._如何获取单点登录自定义得值