2025-06-11 14:32:56 +02:00

203 lines
5.0 KiB
C

#include "eth_drv_etherlib.h"
#include <memory.h>
#include <stm32f4xx_hal.h>
#include "mac_drv.h"
#include "phy_drv/phy_common.h"
#include <etherlib/dynmem.h>
#include <etherlib/eth_interface.h>
// -------------------------------------
// --------- Ethernet buffers ----------
// -------------------------------------
#define ETH_RX_BUFFER_SIZE (1536UL)
uint8_t ETHBuffer[(ETH_RX_DESC_CNT + ETH_TX_DESC_CNT) * ETH_BUFFER_SIZE] __attribute__((section(".ETHBufferSection"))); /* Ethernet Receive Buffers */
struct {
ETHHW_State ETHState;
ETHHW_DescFull DMARxDscrTab[ETH_RX_DESC_CNT];
ETHHW_DescFull DMATxDscrTab[ETH_TX_DESC_CNT];
} ETHStateAndDesc __attribute__((section(".ETHStateAndDecripSection")));
// -------------------------------------
// ---------- Global objects -----------
// -------------------------------------
static EthIODef ioDef;
static LinkState linkState = {false, false, 0, false};
static osThreadId_t th;
int ethdrv_send(EthIODef *io, MsgQueue *mq);
int ethdrv_read();
static void fetch_link_properties();
static int ethdrv_trigger_link_change_int(EthIODef *io) {
fetch_link_properties();
return 0;
}
static void fetch_link_properties() {
const PHY_LinkStatus *status = phy_get_link_status();
// set link up/down state
if ((linkState.up != status->up) || (!linkState.init)) {
linkState.up = status->up;
if (linkState.up) {
bool fe = status->speed == PHY_LS_100Mbps;
bool duplex = status->type == PHY_LT_FULL_DUPLEX;
ETHHW_SetLinkProperties(ETH, fe, duplex);
// convert "Fast Ethernet" to numerical speed value
linkState.speed = (status->speed == PHY_LS_100Mbps) ? 100 : 10;
// save duplex field
linkState.duplex = duplex;
}
// invoke link change notification callback
if (ioDef.llLinkChg != NULL) {
ioDef.llLinkChg(&ioDef, status->up, linkState.speed, linkState.duplex);
}
}
linkState.init = true;
}
static void phy_thread(void *arg) {
while (true) {
fetch_link_properties();
osDelay(500);
}
return;
}
void ethdrv_init() {
// ------- Ethernet MAC initialization -----
ETHHW_InitOpts opts = {
.statePtr = &(ETHStateAndDesc.ETHState),
.rxRingLen = ETH_RX_DESC_CNT,
.bufPtr = ETHBuffer,
.rxRingPtr = (uint8_t *)ETHStateAndDesc.DMARxDscrTab,
.txRingLen = ETH_TX_DESC_CNT,
.txRingPtr = (uint8_t *)ETHStateAndDesc.DMATxDscrTab,
.blockSize = ETH_BUFFER_SIZE,
.mac = {MAC_ADDR0, MAC_ADDR1, MAC_ADDR2, MAC_ADDR3, MAC_ADDR4, MAC_ADDR5}};
ETHHW_Init(ETH, &opts);
ETHHW_Start(ETH);
// -------- IODef initialization -----------
memset(&ioDef, 0, sizeof(EthIODef));
ioDef.llTxTrigger = ethdrv_send;
ioDef.llRxRead = ethdrv_read;
ioDef.llTrigLinkChg = ethdrv_trigger_link_change_int;
// -------- Process PHY events occured during the initialization phase
// start PHY event processing thread
osThreadAttr_t attr;
memset(&attr, 0, sizeof(attr));
attr.stack_size = 2048;
attr.name = "phy";
th = osThreadNew(phy_thread, NULL, &attr);
}
int ethdrv_read() {
ETHHW_ProcessRx(ETH);
return 0;
}
int ETHHW_ReadCallback(ETHHW_EventDesc *evt) {
// packet reception
if (evt->type != ETHHW_EVT_RX_READ) {
return 0;
}
// allocate raw buffer
RawPckt pckt;
uint16_t size = evt->data.rx.size;
uint8_t *plBuf = dynmem_alloc(size);
if (plBuf == NULL) {
MSG("malloc failed in ethdrv_input()!");
return 0; // processing failed
}
// fill-in packet data
pckt.payload = plBuf;
pckt.size = size;
pckt.ext.rx.time_s = evt->data.rx.ts_s;
pckt.ext.rx.time_ns = evt->data.rx.ts_ns;
// copy data
memcpy(pckt.payload, evt->data.rx.payload, size); // copy payload
if (ioDef.llRxStore != NULL) {
ioDef.llRxStore(&ioDef, &pckt);
}
return ETHHW_RET_RX_PROCESSED;
}
int ETHHW_EventCallback(ETHHW_EventDesc *evt) {
if (evt->type == ETHHW_EVT_RX_NOTFY) {
if (ioDef.llRxNotify != NULL) {
ioDef.llRxNotify(&ioDef);
}
}
return 0; // unhandled event
}
int ethdrv_output(const RawPckt *pckt) {
// check if timestamping is demanded
uint8_t opts = ETHHW_TXOPT_NONE;
bool tsEn = (pckt->ext.tx.txTsCb != NULL);
ETHHW_OptArg_TxTsCap optArg;
if (tsEn) {
opts = ETHHW_TXOPT_CAPTURE_TS;
optArg.txTsCbPtr = (uint32_t)pckt->ext.tx.txTsCb;
optArg.tag = pckt->ext.tx.arg;
}
// transmit
ETHHW_Transmit(ETH, pckt->payload, pckt->size, opts, &optArg);
return 0;
}
int ethdrv_send(EthIODef *io, MsgQueue *mq) {
uint32_t bytes_sent = 0;
if (mq_avail(mq) > 0) {
RawPckt pckt = mq_top(mq);
mq_pop(mq);
int ret = ethdrv_output(&pckt);
if (ret != 0) {
MSG("Tx ERROR!\n");
}
bytes_sent += pckt.size;
dynmem_free(pckt.payload);
// MSGraw("TX\r\n");
}
return (int)bytes_sent;
}
EthIODef *ethdrv_get() {
return &ioDef;
}