EtherLib/eth_interface.c
Wiesner András 754b43c51a EthInterface: notifications
- queues have been replaced by OS queues
- serving plain interrupts is replaced by queuing events
2023-10-31 12:01:34 +01:00

173 lines
5.3 KiB
C

//
// Created by epagris on 2022.10.20..
//
#include "eth_interface.h"
#include "dynmem.h"
#include "etherlib/prefab/conn_blocks/ethernet_connblock.h"
#include "etherlib_options.h"
#include "utils.h"
typedef enum {
ETH_IIE_RECV_NOTIFY = 0,
ETH_IIE_LINK_CHG_NOTIFY,
ETH_IIE_TRANSMIT_NOTIFY,
ETH_IIE_UNKNOWN = 0xFFFF
} EthIntfInternalEvent;
static int ethintf_llrecv(EthIODef *io, const RawPckt *pckt) {
ethinf_receive((EthInterface *)io->tag, pckt);
return 0;
}
static int ethintf_llrxnotify(EthIODef *io) {
ethinf_push_notification((EthInterface *)io->tag, ETH_IIE_RECV_NOTIFY, 0);
return 0;
}
static int ethinf_lllinkchg(EthIODef *io, int ls) {
ethinf_push_notification((EthInterface *)io->tag, ETH_IIE_LINK_CHG_NOTIFY, (uint16_t)ls);
return 0;
}
static void ethintf_register(EthInterface *intf) {
intf->ioDef->tag = intf;
intf->ioDef->llRxStore = ethintf_llrecv;
intf->ioDef->llRxNotify = ethintf_llrxnotify;
intf->ioDef->llLinkChg = ethinf_lllinkchg;
}
// interface processing thread
static ThreadReturnType task_ethintf(ThreadParamType param);
EthInterface *ethintf_new(EthIODef *io) {
EthInterface *ethIntf = (EthInterface *)dynmem_alloc(sizeof(EthInterface));
ASSERT_NULL(ethIntf);
memset(&ethIntf->sieve.layer0, 0, sizeof(PcktSieveLayer));
ethIntf->sieve.intf = ethIntf;
ethIntf->sieve.layer0.connBReportFn = ethernet_print_report;
ethIntf->ioDef = io;
ethIntf->ip = 0;
ethIntf->arpc = arpc_new(ethIntf, ETHLIB_ARPCACHE_SIZE);
ASSERT_NULL(ethIntf->arpc);
ethintf_register(ethIntf);
ethIntf->txQ = mq_create(ETHLIB_DEF_MQ_SIZE);
ethIntf->rxQ = mq_create(ETHLIB_DEF_MQ_SIZE);
ETHLIB_OS_QUEUE_CREATE(ethIntf->eventQ, ETHLIB_DEF_MQ_SIZE, uint32_t);
// ETHLIB_OS_SEM_CREATE(&ethIntf->eventSem, ETHLIB_DEF_MQ_SIZE);
ETHLIB_OS_THREAD_DEFINE(task_ethintf, osPriorityHigh, 512, ethIntf);
ETHLIB_OS_THREAD_CREATE(task_ethintf, ethIntf);
ethIntf->ipra = ipra_new();
ethIntf->capabilities = 0;
ethIntf->dhcp = NULL;
memset(&ethIntf->evtCbTable, 0, sizeof(EthIntfEventCbTable));
ethIntf->linkState = false;
return ethIntf;
}
static ThreadReturnType task_ethintf(ThreadParamType param) {
EthInterface *intf = (EthInterface *)param;
while (true) {
// fetch notification
uint16_t event_code = ETH_IIE_UNKNOWN;
uint16_t event_data;
ethinf_pull_notification(intf, &event_code, &event_data);
// act accordingly...
switch (event_code) {
case ETH_IIE_RECV_NOTIFY: {
intf->ioDef->llRxRead(intf->ioDef); // read packets, will invoke RxStore
while (mq_avail(intf->rxQ) > 0) {
RawPckt rawPckt = mq_top(intf->rxQ);
mq_pop(intf->rxQ);
packsieve_input(&intf->sieve, &rawPckt);
}
} break;
case ETH_IIE_LINK_CHG_NOTIFY: {
bool ls = event_data;
ethinf_set_link_state(intf, ls);
if (intf->dhcp != NULL) {
if (ls) { // if link is on
dhcp_start(intf->dhcp);
} else { // if link is off
dhcp_stop(intf->dhcp);
}
}
MSG("Link state: %d\n", ls);
} break;
case ETH_IIE_TRANSMIT_NOTIFY: {
intf->ioDef->llTxTrigger(intf->ioDef, intf->txQ);
} break;
default:
MSG("UNKNOWN event!\n");
break;
}
}
}
void ethinf_receive(EthInterface *intf, const RawPckt *rawPckt) {
bool pushOK = mq_push(intf->rxQ, rawPckt);
if (!pushOK) {
dynmem_free(rawPckt->payload);
ERROR("Input queue full, packet dropped!\n");
}
}
void ethinf_transmit(EthInterface *intf, const RawPckt *rawPckt) {
mq_push(intf->txQ, rawPckt); // push packet onto the message queue
ethinf_push_notification(intf, ETH_IIE_TRANSMIT_NOTIFY, 0); // notify processing thread of the peding transmit
}
void ethinf_push_notification(EthInterface *intf, uint16_t event_code, uint16_t event_data) {
uint32_t cpd = (event_data << 16) | event_code; // create event compound
ETHLIB_OS_QUEUE_PUSH(intf->eventQ, cpd);
}
void ethinf_pull_notification(EthInterface *intf, uint16_t *event_code, uint16_t *event_data) {
uint32_t cpd;
cpd = ETHLIB_OS_QUEUE_POP(intf->eventQ); // wait for event semaphore
// retrieve event code and data
*event_code = cpd & 0xFFFF;
*event_data = (cpd >> 16) & 0xFFFF;
//MSG("EC: %d\n", *event_code);
}
void ethinf_set_capabilities(EthInterface *intf, uint32_t cap) {
intf->capabilities = cap;
}
void ethinf_set_event_callback(EthInterface *intf, EthIntfEvIndex idx, EthIntfEvtCb cb) {
((EthIntfEvtCb *)((&(intf->evtCbTable))))[idx] = cb;
}
void ethinf_trigger_event(EthInterface *intf, EthIntfEvIndex idx) {
EthIntfEvtCb cb = ((EthIntfEvtCb *)((&(intf->evtCbTable))))[idx];
if (cb != NULL) {
cb(intf);
}
}
void ethinf_set_link_state(EthInterface *intf, bool ls) {
if (intf->linkState != ls) { // trigger event only if state has actually changed
intf->linkState = ls;
ethinf_trigger_event(intf, ETH_EVT_LINK_CHANGE);
}
}
bool ethinf_get_link_state(EthInterface *intf) {
return intf->linkState;
}