#include "ethernetif.h" #include #include #include #include "ch32fun.h" #include "ch32v20xhw.h" #include "lwip/etharp.h" #include "lwip/snmp.h" #define CH32V208_ETH_IMPLEMENTATION #define ETH_RX_BUF_COUNT 4 #define ETH_TX_BUF_COUNT 2 #include "ch32v208_eth.h" #define IFNAME0 'e' #define IFNAME1 'n' static volatile bool g_link_changed = false; static void eth_link_callback(bool link_up); static err_t low_level_output(struct netif* netif, struct pbuf* p); static void eth_link_callback(bool link_up) { (void)link_up; g_link_changed = true; } err_t ethernetif_init(struct netif* netif) { #if LWIP_NETIF_HOSTNAME netif->hostname = "lwip-ch32"; #endif netif->state = &g_eth_state; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; netif->output = etharp_output; netif->linkoutput = low_level_output; MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 10000000); // 10Mbps netif->mtu = 1500; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; eth_config_t eth_cfg = {.mac_addr = NULL, // we'll use part uuid MAC .rx_callback = NULL, // no cb, polling API .link_callback = eth_link_callback, .promiscuous_mode = false, .broadcast_filter = true, .multicast_filter = true}; if (eth_init(ð_cfg) != 0) { printf("ERROR: Ethernet initialization failed\n"); return ERR_IF; } // get MAC from driver netif->hwaddr_len = ETH_HWADDR_LEN; eth_get_mac_address(netif->hwaddr); printf("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5]); return ERR_OK; } static err_t low_level_output(struct netif* netif, struct pbuf* p) { (void)netif; static uint8_t tx_buffer[ETH_TX_BUF_SIZE]; uint32_t total_len = 0; for (struct pbuf* q = p; q != NULL; q = q->next) { if (total_len + q->len > ETH_TX_BUF_SIZE) { LINK_STATS_INC(link.err); return ERR_BUF; } memcpy(&tx_buffer[total_len], q->payload, q->len); total_len += q->len; } // send packet via driver int result = eth_send_packet(tx_buffer, total_len); if (result == -1) { // tx queue full LINK_STATS_INC(link.drop); return ERR_BUF; } else if (result == -2) { // invalid length LINK_STATS_INC(link.err); return ERR_ARG; } LINK_STATS_INC(link.xmit); return ERR_OK; } void ethernetif_input(struct netif* netif) { uint16_t length; const uint8_t* packet; // process all pending packets using polling API while ((packet = eth_get_rx_packet(&length)) != NULL) { struct pbuf* p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL); if (p != NULL) { // copy packet into pbuf chain uint32_t offset = 0; for (struct pbuf* q = p; q != NULL; q = q->next) { memcpy(q->payload, packet + offset, q->len); offset += q->len; } LINK_STATS_INC(link.recv); // pass to lwIP if (netif->input(p, netif) != ERR_OK) { pbuf_free(p); } } else { // oom LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); } // release packet back to driver eth_release_rx_packet(); } } void ethernetif_link_poll(struct netif* netif) { // driver does PHY polling and autoneg eth_poll_link(); if (g_link_changed) { g_link_changed = false; bool link_up = eth_is_link_up(); if (link_up && !netif_is_link_up(netif)) { netif_set_link_up(netif); } else if (!link_up && netif_is_link_up(netif)) { netif_set_link_down(netif); } } }