// // Created by epagris on 2022.10.20.. // #include "eth_interface.h" #include "dynmem.h" #include "utils.h" #include "etherlib_options.h" #include "etherlib/prefab/conn_blocks/ethernet_connblock.h" static int ethintf_llrecv(EthIODef * io, const RawPckt * pckt) { ethinf_receive((EthInterface *) io->tag, pckt); return 0; } static int ethintf_llrxnotify(EthIODef * io) { ethinf_notify((EthInterface *) io->tag); return 0; } static int ethinf_lllinkchg(EthIODef * io, int ls) { EthInterface * intf = (EthInterface *) io->tag; 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); 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 void task_ethinf(const void * param); EthInterface *ethintf_new(EthIODef * io) { EthInterface * ethIntf = (EthInterface *)dynmem_alloc(sizeof(EthInterface)); ASSERT_NULL(ethIntf); memset(ðIntf->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_SEM_CREATE(ðIntf->rxSem, ETHLIB_DEF_MQ_SIZE); ETHLIB_OS_THREAD_DEFINE(task_ethinf, osPriorityHigh, 512, ethIntf); ETHLIB_OS_THREAD_CREATE(task_ethinf, ethIntf); ethIntf->ipra = ipra_new(); ethIntf->capabilities = 0; ethIntf->dhcp = NULL; memset(ðIntf->evtCbTable, 0, sizeof(EthIntfEventCbTable)); ethIntf->linkState = false; return ethIntf; } static void task_ethinf(const void * param) { EthInterface * intf = (EthInterface *) param; while (true) { ETHLIB_OS_SEM_WAIT(&intf->rxSem); intf->ioDef->llRxRead(intf->ioDef, intf->rxQ); // read packets while (mq_avail(intf->rxQ) > 0) { RawPckt rawPckt = mq_top(intf->rxQ); mq_pop(intf->rxQ); packsieve_input(&intf->sieve, &rawPckt); } } } 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 intf->ioDef->llTxTrigger(intf->ioDef, intf->txQ); } void ethinf_notify(EthInterface *intf) { ETHLIB_OS_SEM_POST(&intf->rxSem); } 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; }