使用 ESP-IDF 通过以太网接收 UDP 数据包

问题描述 投票:0回答:2

我想使用 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);
udp esp32 ethernet esp-idf
2个回答
0
投票

我在 espressif ESP-IDF 论坛上发布了几乎相同的问题,然后在此发布此问题,并得到了用户 ESP_ondrej 的以下回答。 我将其发布在这里,以防这可以帮助某人。

ESP-IDF 中的所有协议示例都支持 Wifi 和 以太网。您只需通过

idf.py menuconfig
进行配置即可。 请查看 README https://github.com/espressif/esp-idf/bl ... /自述文件.md

如果您想从头开始使用以太网 UDP 应用程序, 你可以这样做。您无需致电

esp_eth_update_input_path
。 该功能用于将 L2 以太网帧定向到特定的 因为你想要通信所以你不想要回调函数 通过IP协议。因此保持原样,即以太网帧 由 lwIP 堆栈处理,并像您可能的那样使用套接字 API 习惯了其他平台。


0
投票

我有一个ESP32-Ethernet-KitV1.2板。

对于以太网,安装了IP101GRI芯片。我使用 ESP-IDF eth_basic example 作为配置以太网的基础,并删除了其他芯片的代码。该板还具有 WiFi。

据我了解,使用 UDP 与以太网或 WiFi 没有直接关系。当数据包到达时,无论它是通过电缆还是无线方式到达,都会由套接字进行处理。我已经证实了这一点。您将收到发件人的地址并可以回复。如果稍后需要发送响应,只需将地址保存在另一个变量中,并在准备发送数据时使用它。

以太网设置:

  • IP=192.168.4.1
  • 掩码=255.255.255.0
  • 网关=192.168.4.1

我还将 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, &eth_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, &eth_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);
}
© www.soinside.com 2019 - 2024. All rights reserved.