Files
ch32v208_sens/port/ethernetif.c
2025-12-12 23:05:27 +06:00

147 lines
3.5 KiB
C

#include "ethernetif.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#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(&eth_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;
// single-segment pbuf
if (p->next == NULL && p->len <= ETH_TX_BUF_SIZE) {
if (eth_send_packet(p->payload, p->len) == 0) {
LINK_STATS_INC(link.xmit);
return ERR_OK;
}
}
// chain of pbufs
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;
}
if (eth_send_packet(tx_buffer, total_len) == 0) {
LINK_STATS_INC(link.xmit);
return ERR_OK;
}
LINK_STATS_INC(link.drop);
return ERR_BUF;
}
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) {
// usually contiguous in PBUF_POOL
pbuf_take(p, packet, length);
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);
}
}
}