我想使用 ESP-IDF 框架制作一个通过以太网接收 UDP 数据包的程序。我没有使用 ESP32-Ethernet-Kit,而是使用 ESP32 和 PHY (DP83848) 来访问以太网。
我能找到的关于 UDP 和 ESP32 的几乎所有示例都使用 Wifi 而不是以太网。
我想要做的是使用 espressif esp-idf git 存储库中提供的基本以太网示例作为起点,然后添加接收数据报的功能。 如果我没记错的话,我应该做的是创建一个新的事件处理程序并使用 esp_eth_driver.h 中存在的 esp_eth_update_input_path API,但我不确定如何使用它。谁能帮我解决这个问题吗?
esp_err_t esp_eth_update_input_path(
esp_eth_handle_t hdl,
esp_err_t (*stack_input)(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv),
void *priv);
我在 espressif ESP-IDF 论坛上发布了几乎相同的问题,然后在此发布此问题,并得到了用户 ESP_ondrej 的以下回答。 我将其发布在这里,以防这可以帮助某人。
ESP-IDF 中的所有协议示例都支持 Wifi 和 以太网。您只需通过
进行配置即可。 请查看 README https://github.com/espressif/esp-idf/bl ... /自述文件.mdidf.py menuconfig
如果您想从头开始使用以太网 UDP 应用程序, 你可以这样做。您无需致电
。 该功能用于将 L2 以太网帧定向到特定的 因为你想要通信所以你不想要回调函数 通过IP协议。因此保持原样,即以太网帧 由 lwIP 堆栈处理,并像您可能的那样使用套接字 API 习惯了其他平台。esp_eth_update_input_path
我有一个ESP32-Ethernet-KitV1.2板。
对于以太网,安装了IP101GRI芯片。我使用 ESP-IDF eth_basic example 作为配置以太网的基础,并删除了其他芯片的代码。该板还具有 WiFi。
据我了解,使用 UDP 与以太网或 WiFi 没有直接关系。当数据包到达时,无论它是通过电缆还是无线方式到达,都会由套接字进行处理。我已经证实了这一点。您将收到发件人的地址并可以回复。如果稍后需要发送响应,只需将地址保存在另一个变量中,并在准备发送数据时使用它。
以太网设置:
我还将 ESP32 配置为 DHCP 服务器。我还没弄清楚如何设置 DHCP 地址池。
在示例中,所有消息都打印到控制台,但如果收到消息“Hi”,则响应将为“Hello”,如果收到字符“2”,则响应将为“5”。使用文本只是为了演示和清晰,您可以发送任何数据。
将 udp.c 和 udp.h 添加到您的项目中,不要忘记 CMakeLists.txt。
我使用 esp-idf-v4.4.2 宽度 VS Code。
如果您配置了 WiFi,则 udp 将与其配合使用,无需在 udp.c 中进行额外更改
文件 udp.h:
#ifndef MAIN_UDP_H_
#define MAIN_UDP_H_
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
void IRAM_ATTR udp_ap_task(void *pvParameters);
void UDPSend(int sockfd, char* buf,int size, struct sockaddr_in* pAddr);
#endif /* MAIN_UDP_H_ */
文件 udp.c:
#include "freertos/FreeRTOS.h"
#include "freertos/FreeRTOSConfig.h"
#include "freertos/task.h"
#include "freertos/portmacro.h"
#include "esp_event.h"
#include "udp.h"
#include "esp_netif.h"
#define SELF_UDP_PORT 33000
static const char *TAG_AP = "udp_ap";
#define SIZE_UDPBUF 1460
char udpBuf[SIZE_UDPBUF]={0,};
char* p_udpBuf=0;
int ap_sockfd=-1;
struct sockaddr_in self_ap_addr;//, gateway, netmask;
int MsgCntr=0;//debug
void IRAM_ATTR udp_ap_task(void *pvParameters) {
struct sockaddr_in source_addr;
socklen_t source_addr_len;
while(1) {
ESP_LOGI(TAG_AP, "Create AP UDP socket...\n");
if ( (ap_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 ) {
ESP_LOGE(TAG_AP, "UDP socket not created\n");
break;
}
ESP_LOGI(TAG_AP, "AP UDP socket created");
self_ap_addr.sin_family = AF_INET; // IPv4
self_ap_addr.sin_port = htons(SELF_UDP_PORT);
if (bind(ap_sockfd, (const struct sockaddr *)&self_ap_addr, sizeof(struct sockaddr_in)) < 0 ) {
ESP_LOGI(TAG_AP,"AP UDP socket not binded");
shutdown(ap_sockfd, 0);
close(ap_sockfd);
break;
}
char addr_str[16]={0,};
ESP_LOGI(TAG_AP,"AP UDP socket binded");
while(1) {
p_udpBuf=udpBuf;
source_addr_len=sizeof(struct sockaddr_in);
ssize_t size=recvfrom(ap_sockfd, udpBuf, sizeof(udpBuf), 0, (struct sockaddr *)&source_addr,&source_addr_len);
if (size<0) break;
if (size==0) continue;
MsgCntr++;//debug
if(size<SIZE_UDPBUF){
udpBuf[size]=0;//NULL terminator if use udpBuf as string for printf
}
printf("Message received: %d, Size=%d, Text:%s\n",MsgCntr, size, udpBuf);
printf("Port: %d Addr: %s\n",htons(source_addr.sin_port),esp_ip4addr_ntoa((esp_ip4_addr_t*)&source_addr.sin_addr.s_addr,addr_str,sizeof(addr_str)-1));
if (strcmp(udpBuf,"Hi") == 0){
sprintf(udpBuf, "%s", "Hello");
UDPSend(ap_sockfd,udpBuf,strlen(udpBuf),&source_addr);
}
if(udpBuf[0]=='2'){
udpBuf[0]='5';
UDPSend(ap_sockfd,udpBuf,strlen(udpBuf),&source_addr);
}
}
if (ap_sockfd != -1) {
ESP_LOGE(TAG_AP, "Shutting down AP socket and restarting...");
shutdown(ap_sockfd, 0);
close(ap_sockfd);
}
}
vTaskDelete(NULL);
}
void UDPSend(int sockfd, char* buf,int size, struct sockaddr_in* pAddr) {
if (sockfd<0) return;
sendto(sockfd, buf, size, 0,(struct sockaddr*)pAddr, sizeof(struct sockaddr));
}
文件main.c
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "./sdkconfig.h"
#if CONFIG_ETH_USE_SPI_ETHERNET
#include "driver/spi_master.h"
#endif // CONFIG_ETH_USE_SPI_ETHERNET
#include "udp.h"
static const char *TAG = "eth_example";
#include <esp_netif.h>
#include <esp_eth.h>
esp_netif_t *eth_netif=0;
esp_eth_handle_t eth_handle = NULL;
//Event handler for Ethernet events
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
uint8_t mac_addr[6] = {0};
//we can get the ethernet driver handle from event data
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
ESP_LOGI(TAG, "Ethernet Link Up");
ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
break;
case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down");
break;
case ETHERNET_EVENT_START:
ESP_LOGI(TAG, "Ethernet Started");
break;
case ETHERNET_EVENT_STOP:
ESP_LOGI(TAG, "Ethernet Stopped");
break;
default:
break;
}
}
//Event handler for IP_EVENT_ETH_GOT_IP
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
const esp_netif_ip_info_t *ip_info = &event->ip_info;
ESP_LOGI(TAG, "Ethernet Got IP Address");
ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
ESP_LOGI(TAG, "~~~~~~~~~~~");
esp_netif_dns_info_t dns_info;
esp_netif_get_dns_info(eth_netif, ESP_NETIF_DNS_MAIN, &dns_info);
char dns_str[16];
sprintf(dns_str, IPSTR, IP2STR(&dns_info.ip.u_addr.ip4));
ESP_LOGI(TAG, "DNS Server: %s", dns_str);
ESP_LOGI(TAG, "~~~~~~~~~~~");
}
void setupEthernet() {
// Create new default instance of esp-netif for Ethernet
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
eth_netif = esp_netif_new(&cfg);
//static IP
esp_netif_dhcpc_stop(eth_netif);
esp_netif_ip_info_t ip_info;
IP4_ADDR(&ip_info.ip, 192, 168, 4, 1);
IP4_ADDR(&ip_info.gw, 192, 168, 4, 1);
IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);
ESP_ERROR_CHECK(esp_netif_set_ip_info(eth_netif, &ip_info));
// Init MAC and PHY configs to default
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR;//1
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO;//5
mac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;//23
mac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;//18
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle));// Init Ethernet
ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)));//attach Ethernet driver to TCP/IP stack
// Register user defined event handers
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
ESP_ERROR_CHECK(esp_eth_start(eth_handle));//start Ethernet driver state machine
//DHCP
esp_netif_dhcp_status_t DHCPStatus;
esp_netif_dhcps_get_status(eth_netif,&DHCPStatus);
//ESP_LOGW(TAG_STA,"DHCP srv status: %d",DHCPStatus);
if (DHCPStatus!=ESP_NETIF_DHCP_STOPPED){// Stop dhcp server
ESP_ERROR_CHECK(esp_netif_dhcps_stop(eth_netif));
}
ESP_ERROR_CHECK(esp_netif_dhcps_start(eth_netif));// Start dhcp server
}
void app_main() {
// Initialize TCP/IP network interface (should be called only once in application)
ESP_ERROR_CHECK(esp_netif_init());
// Create default event loop that running in background
ESP_ERROR_CHECK(esp_event_loop_create_default());
setupEthernet();// setup Ethernet and make netif
xTaskCreatePinnedToCore(udp_ap_task,"udp_ap_task", 4096, NULL, 5, NULL, 1);
}