/* * networkInterface.c * * Created on: 06.06.2019 * Author: m.bauregger */ #include "networkInterfacep.h" #include "hItfIoDigitalOut.h" #include "oSTaskScheduler.h" #include "tcp.h" #include "timeouts.h" #include "oCfg.h" #include "hItfIhandler.h" static err_t HALNetworkInterface_Accept (void *arg, struct tcp_pcb *pcb, err_t err); static err_t HALNetworkInterface_Recv (void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); static void HALNetworkInterface_Err (void *arg, err_t err); static err_t HALNetworkInterface_Sent (void *arg, struct tcp_pcb *pcb, u16_t len); static bool_t connected = 0; class NetworkInterface : public OSTask { public: NetworkInterface() : OSTask(Uids::eHCtrlX4NetworkInterface){}; protected: virtual void exec(); }; NetworkInterface bgt; bool_t Initialized = false; OUtlTimer Timer_NetworkInterface(TIMEOUT_TIME); void HalNetworkInterface_Init() { if(Initialized == false) { (void)HItfIoDigitalOut::Get()->SetDirect(HItfIoDigitalOut::eDOut_EthOn, true); // switch on supply of phy (void)HItfIoDigitalOut::Get()->SetDirect(HItfIoDigitalOut::eDOut_EthReset, true); // reset is low active -> deassert reset if(ETH_LWIP_Init(Ð_LWIP_0) == ETH_LWIP_STATUS_SUCCESS) { for(int16_t i = 0; i < NI_MAX_HANDLES; i++) { cleanHandle(i); pcbs[i].sentDataAll = 0; pcbs[i].receivedDataAll = 0; } // background task OCfg::GetBackgroundCycle()->RegisterTask(&bgt); Timer_NetworkInterface.Start(); Initialized = true; } else { // TODO m.mayr 28.04.22 emit event in case init failed } } } void NetworkInterface::exec() { uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); sys_check_timeouts(); HItfIhandler::Get()->EndCriticalSection(tmp_Context); } HalNetworkInterface_Handle_t HalNetworkInterface_CreateClient(uint32_t localIp_arg, uint16_t localPort_arg, HalNetworkInterface_eError_t *err_arg) { HalNetworkInterface_Handle_t returnVal = -1; *err_arg = NIER_MEM; uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); int16_t index = getFirstFreePcbHandleId(); if(index != -1) { pcbs[index].pcb = tcp_new(); if(pcbs[index].pcb != NULL) { returnVal = index; pcbs[index].state = NISTATE_CLOSED; pcbs[index].pcb->so_options = SOF_REUSEADDR; // needed if ip is needed twice very fast tcp_arg(pcbs[index].pcb, (void*) &pcbs[index]); // set handle data as argument err_t err = tcp_bind(pcbs[index].pcb, (ip_addr_t*) &localIp_arg, localPort_arg); *err_arg = translateError(err); } } HItfIhandler::Get()->EndCriticalSection(tmp_Context); return returnVal; } HalNetworkInterface_Handle_t HalNetworkInterface_CreateServer(uint32_t localIp_arg, uint16_t localPort_arg, HalNetworkInterface_eError_t *err_arg) { return HalNetworkInterface_CreateClient(localIp_arg, localPort_arg, err_arg); } HalNetworkInterface_eError_t HalNetworkInterface_ConnectClient(HalNetworkInterface_Handle_t handle_arg, uint32_t remoteIp_arg, uint16_t remotePort_arg, HALNetworkInterface_Connected con_arg, HALNetworkInterface_Error err_arg) { if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) return NIER_VAL; pcbs[handle_arg].connectedFunction= con_arg; pcbs[handle_arg].errorFunction = err_arg; uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); tcp_err(pcbs[handle_arg].pcb, HALNetworkInterface_Err); // if an error during the connection occures err_t err = tcp_connect(pcbs[handle_arg].pcb, (ip_addr_t *)&remoteIp_arg, remotePort_arg, HALNetworkInterface_Accept); HItfIhandler::Get()->EndCriticalSection(tmp_Context); if(err == ERR_OK) pcbs[handle_arg].state = NISTATE_CONNECTING; else pcbs[handle_arg].state = NISTATE_CLOSED; return translateError(err); } HalNetworkInterface_eError_t HalNetworkInterface_StartServer(HalNetworkInterface_Handle_t handle_arg, HALNetworkInterface_Error err_arg, HALNetworkInterface_NewClient new_arg) { if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) return NIER_VAL; pcbs[handle_arg].errorFunction = err_arg; pcbs[handle_arg].newClientFunction = new_arg; err_t err; uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); pcbs[handle_arg].pcb = tcp_listen_with_backlog_and_err(pcbs[handle_arg].pcb, 0xff, &err); tcp_err(pcbs[handle_arg].pcb, HALNetworkInterface_Err); // if an error during the connection occures tcp_accept(pcbs[handle_arg].pcb, HALNetworkInterface_Accept); // if an client connects HItfIhandler::Get()->EndCriticalSection(tmp_Context); //TODO FOR ERROR SEARCH if(pcbs[handle_arg].pcb->callback_arg != (void*) &pcbs[handle_arg]) tcp_arg(pcbs[handle_arg].pcb, (void*) &pcbs[handle_arg]); //END pcbs[handle_arg].state = NISTATE_LISTEN; return translateError(err); } void HalNetworkInterface_SetClientCallbacks(HalNetworkInterface_Handle_t handle_arg, HALNetworkInterface_Closed closed_arg, HALNetworkInterface_MessageReceived rec_arg, HALNetworkInterface_MessageSent sent_arg, HALNetworkInterface_Error err_arg) { if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) return; pcbs[handle_arg].closedFunction = closed_arg; pcbs[handle_arg].messageReceivedFunction = rec_arg; pcbs[handle_arg].messageSentFunction = sent_arg; pcbs[handle_arg].errorFunction = err_arg; } HalNetworkInterface_eState_t HalNetworkInterface_GetState(HalNetworkInterface_Handle_t handle_arg, HalNetworkInterface_eError_t *err_arg) { HalNetworkInterface_eState_t returnVal = NISTATE_CLOSED; if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) { if(err_arg != NULL) *err_arg = NIER_VAL; } else { returnVal = pcbs[handle_arg].state; if(pcbs[handle_arg].pcb->unsent != NULL) returnVal = NISTATE_SENDING; else if(err_arg != NULL) *err_arg = NIER_VAL; } return returnVal; } HalNetworkInterface_eError_t HalNetworkInterface_GetPortAndIp(HalNetworkInterface_Handle_t handle_arg, uint32_t *ip_arg, uint16_t *port_arg) { if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) return NIER_VAL; *ip_arg = pcbs[handle_arg].pcb->local_ip.addr; *port_arg = pcbs[handle_arg].pcb->local_port; return NIER_OK; } HalNetworkInterface_eError_t HalNetworkInterface_GetLocalIp(uint32_t *ip_arg) { *ip_arg = (IP_ADDR3<<24)+(IP_ADDR2<<16)+(IP_ADDR1<<8)+IP_ADDR0; return NIER_OK; } HalNetworkInterface_eError_t HalNetworkInterface_GetFreeSendBuffer(HalNetworkInterface_Handle_t handle_arg, uint16_t *pbufferLength_arg) { if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) return NIER_VAL; *pbufferLength_arg = tcp_sndbuf(pcbs[handle_arg].pcb); return NIER_OK; } HalNetworkInterface_eError_t HalNetworkInterface_GetBufferQueueLength(HalNetworkInterface_Handle_t handle_arg, uint16_t *pbufferLength_arg) { if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) return NIER_VAL; *pbufferLength_arg = tcp_sndqueuelen(pcbs[handle_arg].pcb); return NIER_OK; } HalNetworkInterface_eError_t HalNetworkInterface_Write(HalNetworkInterface_Handle_t handle_arg, const void *data_arg, uint16_t len_arg, bool_t copy, bool_t direct_write) { if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) return NIER_VAL; err_t err1; uint16_t freeBufferSapce = tcp_sndbuf(pcbs[handle_arg].pcb); uint16_t currentSendQueueLen = tcp_sndqueuelen(pcbs[handle_arg].pcb); if(freeBufferSapce >= 0 && currentSendQueueLen < TCP_SND_QUEUELEN ) { uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); if(copy != false) { err1 = tcp_write(pcbs[handle_arg].pcb, data_arg, len_arg, TCP_WRITE_FLAG_COPY); } else { err1 = tcp_write(pcbs[handle_arg].pcb, data_arg, len_arg, 0 ); } if(err1 == ERR_OK) { pcbs[handle_arg].sentData += len_arg; pcbs[handle_arg].sentDataAll += len_arg; if(direct_write) { err_t err2 = tcp_output(pcbs[handle_arg].pcb); // write directly (void) err2; if(err2 != ERR_OK) { err1 = err2; } } } HItfIhandler::Get()->EndCriticalSection(tmp_Context); } else { err1 = NIER_NO_BUFFER_SPACE; } return translateError(err1); } uint8_t* HalNetworkInterface_GetDebugInformation(sint32_t *len) { static uint8_t debug_data[264]; uint16_t i = 0; memset(debug_data, 0, 264); #if LWIP_STATS static uint16_t proto_size = sizeof(struct stats_proto); // 24 memcpy(&debug_data[i], &lwip_stats.link, proto_size); i += proto_size; memcpy(&debug_data[i], &lwip_stats.etharp, proto_size); i += proto_size; memcpy(&debug_data[i], &lwip_stats.ip, proto_size); i += proto_size; memcpy(&debug_data[i], &lwip_stats.tcp, proto_size); i += proto_size; #endif #if MEM_STATS static uint16_t mem_size = sizeof(struct stats_mem); memcpy(&debug_data[i], &lwip_stats.mem, mem_size); i += mem_size; for(uint8_t j = 0; j < 7; j++) { memcpy(&debug_data[i], lwip_stats.memp[j], mem_size); i += mem_size; } #endif *len = i; return debug_data; } HalNetworkInterface_eError_t HalNetworkInterface_CloseHandle(HalNetworkInterface_Handle_t handle_arg) { if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) return NIER_VAL; pcbs[handle_arg].state = NISTATE_CLOSED; uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); err_t err = tcp_close(pcbs[handle_arg].pcb); HItfIhandler::Get()->EndCriticalSection(tmp_Context); return translateError(err); } HalNetworkInterface_eError_t HalNetworkInterface_DeleteHandle(HalNetworkInterface_Handle_t handle_arg) { if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) return NIER_VAL; HalNetworkInterface_eError_t returnVal = NIER_OK; if(pcbs[handle_arg].state != NISTATE_CLOSED) { uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); returnVal = HalNetworkInterface_AbortHandle(handle_arg); HItfIhandler::Get()->EndCriticalSection(tmp_Context); } cleanHandle(handle_arg); return returnVal; } HalNetworkInterface_eError_t HalNetworkInterface_AbortHandle(HalNetworkInterface_Handle_t handle_arg) { if(handle_arg < 0 || handle_arg >= NI_MAX_HANDLES || pcbs[handle_arg].pcb == NULL) return NIER_VAL; pcbs[handle_arg].state = NISTATE_CLOSED; uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); tcp_abort(pcbs[handle_arg].pcb); HItfIhandler::Get()->EndCriticalSection(tmp_Context); return NIER_OK; } struct pbuf* handleReceiveMessage(struct pbuf* buffer_arg, PcbData_t *pcbd_arg) { if(buffer_arg == NULL) { pcbd_arg->state = NISTATE_CLOSED; if(pcbd_arg->closedFunction != NULL) pcbd_arg->closedFunction(pcbd_arg->index); } else { struct pbuf *q; struct pbuf *old; for (q = buffer_arg; q != NULL;) // split pbuf into char arrays // take first item { //pbuf to string uint8_t tmp[q->len+1]; for(uint32_t i = 0; i < q->len; i++) tmp[i] = ((uint8_t*)q->payload)[i]; tmp[q->len] = 0; //call function if(pcbd_arg->messageReceivedFunction != NULL) if(pcbd_arg->messageReceivedFunction(pcbd_arg->index, tmp, q->len) != NIER_OK) break; //prepare next run old = q; q = q->next; } if(q != buffer_arg) // only if start and end are different delete the buffer { old->next = NULL; uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); pbuf_free(buffer_arg); HItfIhandler::Get()->EndCriticalSection(tmp_Context); } buffer_arg = q; } return buffer_arg; } err_t HALNetworkInterface_Accept (void *arg, struct tcp_pcb *pcb, err_t err) { if(err != ERR_OK) { HALNetworkInterface_Err(arg, err); return err; } connected = 1; // Special things have happened invalid pointer was sent. if(arg == HALNetworkInterface_Err) { HalNetworkInterface_Init(); // TODO return err; } PcbData_t *d = (PcbData_t*) arg; if(d->newClientFunction == NULL) // is client { uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); tcp_recv(d->pcb, HALNetworkInterface_Recv); tcp_err(d->pcb, HALNetworkInterface_Err); tcp_sent(d->pcb, HALNetworkInterface_Sent); HItfIhandler::Get()->EndCriticalSection(tmp_Context); d->state = NISTATE_CONNECTED; if(d->connectedFunction != NULL) d->connectedFunction(d->index); } else // is server { int16_t index = getFirstFreePcbHandleId(); if(index != -1) // enough place in array { pcbs[index].pcb = pcb; pcbs[index].state = NISTATE_CONNECTED; uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); tcp_arg(pcbs[index].pcb, (void*) &pcbs[index]); tcp_recv(pcb, HALNetworkInterface_Recv); tcp_err(pcb, HALNetworkInterface_Err); tcp_sent(pcb, HALNetworkInterface_Sent); HItfIhandler::Get()->EndCriticalSection(tmp_Context); if(d->newClientFunction != NULL) d->newClientFunction(d->index, index); } else { uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); tcp_abort(pcb); HItfIhandler::Get()->EndCriticalSection(tmp_Context); d->errorFunction(index, NIER_MEM); // no more space for client } } return ERR_OK; } err_t HALNetworkInterface_Recv (void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { (void) pcb; err_t returnVal = ERR_ARG; if(err != ERR_OK) { HALNetworkInterface_Err(arg, err); return err; } PcbData_t *d = (PcbData_t*) arg; if(p == NULL) { d->state = NISTATE_CLOSED; if(d->closedFunction != NULL) d->closedFunction(d->index); returnVal = ERR_OK; } else { struct pbuf* res = handleReceiveMessage(p, d); if(res == NULL) returnVal = ERR_OK; uint32_t tmp_Context = HItfIhandler::Get()->StartCriticalSection(); tcp_recved(d->pcb, p->tot_len); HItfIhandler::Get()->EndCriticalSection(tmp_Context); } return returnVal; } void HALNetworkInterface_Err (void *arg, err_t err) { PcbData_t *d = (PcbData_t*) arg; if(d->errorFunction != NULL) d->errorFunction(d->index, translateError(err)); d->state = NISTATE_ERR; } err_t HALNetworkInterface_Sent (void *arg, struct tcp_pcb *pcb, u16_t len) { (void) pcb; PcbData_t *d = (PcbData_t*) arg; d->receivedData += len; d->receivedDataAll += len; if(d->messageSentFunction != NULL && d->sentData == d->receivedData) { d->messageSentFunction(d->index, d->sentData); d->receivedData = 0; // Could be called by event and then skipped a received len d->sentData = 0; } return ERR_OK; } HalNetworkInterface_eError_t translateError(err_t err_arg) { HalNetworkInterface_eError_t returnVal; switch(err_arg) { case ERR_UNKNOWN: case ERR_ALREADY_SENT: returnVal = NIER_UNKNOWN; break; case ERR_OK: returnVal = NIER_OK; break; case ERR_MEM: returnVal = NIER_MEM; break; case ERR_BUF: returnVal = NIER_BUF; break; case ERR_TIMEOUT: returnVal = NIER_TIMEOUT; break; case ERR_RTE: returnVal = NIER_RTE; break; case ERR_INPROGRESS: returnVal = NIER_INPROGRESS; break; case ERR_VAL: returnVal = NIER_VAL; break; case ERR_WOULDBLOCK: returnVal = NIER_WOULDBLOCK; break; case ERR_USE: returnVal = NIER_USE; break; case ERR_ALREADY: returnVal = NIER_ALREADY; break; case ERR_ISCONN: returnVal = NIER_ISCONN; break; case ERR_CONN: returnVal = NIER_CONN; break; case ERR_IF: returnVal = NIER_IF; break; case ERR_ABRT: returnVal = NIER_ABRT; break; case ERR_RST: returnVal = NIER_RST; break; case ERR_CLSD: returnVal = NIER_CLSD; break; case ERR_ARG: returnVal = NIER_ARG; break; default: returnVal = NIER_UNKNOWN; break; } return returnVal; } void cleanHandle(int16_t i) { pcbs[i].pcb = NULL; pcbs[i].connectedFunction = NULL; pcbs[i].closedFunction = NULL; pcbs[i].newClientFunction = NULL; pcbs[i].messageReceivedFunction = NULL; pcbs[i].messageSentFunction = NULL; pcbs[i].errorFunction = NULL; pcbs[i].state = NISTATE_CLOSED; pcbs[i].index = i; pcbs[i].notYetDeleted = 0; pcbs[i].sentData = 0; pcbs[i].receivedData = 0; } int16_t getFirstFreePcbHandleId() { int16_t i = -1; while(++i < NI_MAX_HANDLES && pcbs[i].pcb != NULL){} if(i >= NI_MAX_HANDLES) return -1; return i; }