197 lines
5.0 KiB
C
197 lines
5.0 KiB
C
#include "eth_drv_etherlib.h"
|
|
|
|
#include <memory.h>
|
|
|
|
#include <stm32h7xx_hal.h>
|
|
|
|
#include "cmsis_os2.h"
|
|
#include "mac_drv.h"
|
|
#include "phy_drv/phy_common.h"
|
|
|
|
#include <etherlib/dynmem.h>
|
|
#include <etherlib/eth_interface.h>
|
|
|
|
// -------------------------------------
|
|
// --------- Ethernet buffers ----------
|
|
// -------------------------------------
|
|
|
|
#define ETH_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 osTimerId_t eventTmr;
|
|
|
|
int ethdrv_send(EthIODef *io, MsgQueue *mq);
|
|
|
|
int ethdrv_read();
|
|
|
|
static void process_phy_event();
|
|
|
|
static int ethdrv_trigger_link_change_int(EthIODef * io) {
|
|
process_phy_event();
|
|
return 0;
|
|
}
|
|
|
|
static void process_phy_event() {
|
|
PHY_Event evt = phy_get_event(); // get event
|
|
if (evt != PHYEVENT_NO_EVENT) {
|
|
if (ioDef.llLinkChg != NULL) {
|
|
int up = evt == PHYEVENT_AUTONEGOTIATION_DONE;
|
|
|
|
// link properties
|
|
uint16_t speed = 0;
|
|
bool duplex = false;
|
|
|
|
// if link is up, then set link properties accordingly
|
|
if (up) {
|
|
const PHY_LinkStatus * status = phy_get_link_status();
|
|
bool fe = status->speed == PHY_LS_100Mbps;
|
|
duplex = status->type == PHY_LT_FULL_DUPLEX;
|
|
ETHHW_SetLinkProperties(ETH, fe, duplex);
|
|
|
|
// convert "Fast Ethernet" to numerical speed value
|
|
speed = (status->speed == PHY_LS_100Mbps) ? 100 : 10;
|
|
}
|
|
|
|
// invoke link change notification callback
|
|
ioDef.llLinkChg(&ioDef, up, speed, duplex);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void event_check_tmr_cb(void * arg) {
|
|
process_phy_event();
|
|
}
|
|
|
|
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 = {ETH_MAC_ADDR0, ETH_MAC_ADDR1, ETH_MAC_ADDR2, ETH_MAC_ADDR3, ETH_MAC_ADDR4, ETH_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;
|
|
|
|
// -------- Start loop that periodically pools PHY interrupts
|
|
eventTmr = osTimerNew(event_check_tmr_cb, osTimerPeriodic, NULL, NULL);
|
|
osTimerStart(eventTmr, 1000);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// -------------
|
|
|
|
void ETH_IRQHandler() {
|
|
ETHHW_ISR(ETH);
|
|
} |