147 lines
3.5 KiB
C
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(ð_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);
|
|
}
|
|
}
|
|
}
|