#include "FreeRTOS.h" #include "lwip/init.h" #include "lwip/sio.h" #include "lwip/timeouts.h" #include "lwip/udp.h" #include "queue.h" #include "task.h" #include #include #include #include #include #undef XUARTPS_IXR_RXOVR #define XUARTPS_IXR_RXOVR 0x00000020U /**< Rx Overrun error interrupt */ #define XUARTPS_IXR_RTRIG 0x00000001U /**< RX FIFO trigger interrupt. */ // #include // void slipif_rxbyte_input(struct netif *netif, u8_t c); // uint8_t packets = 0; // static void *tftp_open(const char *fname, const char *mode, u8_t is_write) { // LWIP_UNUSED_ARG(mode); // packets = 100; // return (void *)13; // } // static void tftp_close(void *handle) {} // static int tftp_read(void *handle, void *buf, int bytes) { // memset(buf, 'x', bytes); // if (packets == 0) { // return 0; // } else { // packets--; // return bytes; // } // } // static int tftp_write(void *handle, struct pbuf *p) { return 0; } // /* For TFTP client only */ // static void tftp_error(void *handle, int err, const char *msg, int size) {} // static const struct tftp_context tftp = {tftp_open, tftp_close, tftp_read, // tftp_write, tftp_error}; struct netif netif; QueueHandle_t uartIsrQueue; extern XScuGic xInterruptController; /* Interrupt controller instance */ /** this is based on XUartPs_InterruptHandler() in xuartps_intr.c*/ void handleUARTInt(void *) { u32 IsrStatus; /* * Read the interrupt ID register to determine which * interrupt is active */ IsrStatus = XUartPs_ReadReg(STDIN_BASEADDRESS, XUARTPS_IMR_OFFSET); IsrStatus &= XUartPs_ReadReg(STDIN_BASEADDRESS, XUARTPS_ISR_OFFSET); // Onlx RX intterupts are enabled // We do not care which interrupt actually triggered, just get all bytes // available into the stack uint8_t RecievedByte; BaseType_t xHigherPriorityTaskWoken; while (XUartPs_IsReceiveData(STDIN_BASEADDRESS)) { RecievedByte = XUartPs_ReadReg(STDIN_BASEADDRESS, XUARTPS_FIFO_OFFSET); xQueueSendToBackFromISR(uartIsrQueue, &RecievedByte, &xHigherPriorityTaskWoken); } /* Clear the interrupt status. */ XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_ISR_OFFSET, IsrStatus); /* directly yield if sending to the queue woke something in ourselves */ portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } static struct udp_pcb *udpecho_raw_pcb; static void udpecho_raw_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { LWIP_UNUSED_ARG(arg); if (p != NULL) { /* send received packet back to sender */ udp_sendto(upcb, p, addr, port); /* free the pbuf */ pbuf_free(p); } } uint8_t data[] = {'1','2','3','4','5'}; void lwip_main(void *) { struct pbuf* tx = pbuf_alloc_reference(data, sizeof(data), PBUF_REF); ip_addr_t addr = IPADDR4_INIT_BYTES(10,0,0,13); udp_sendto(udpecho_raw_pcb, tx, &addr, 1177); pbuf_free(tx); while (1) { // slipif_rxbyte_input() is private, so we use slipif_poll and implement // sio_tryread() // sio_tryread() will do a blocking read with a timeout, so we get to check // the timeouts even if no data is incoming slipif_poll(&netif); sys_check_timeouts(); } } // TODO define sio_fd_t to an int uint32_t sio_data; sio_fd_t sio_open(u8_t devnum) { return &sio_data; } void sio_send(u8_t c, sio_fd_t fd) { XUartPs_SendByte(STDOUT_BASEADDRESS, c); } u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len) { if (len < 1) { return 0; } BaseType_t result; //need a timeout because lwip task needs to do background work result = xQueueReceive(uartIsrQueue, data, pdMS_TO_TICKS(250)); if (result == pdTRUE) { return 1; } else { return 0; } } #ifdef LWIP_DEBUG const char *lwip_strerr(err_t err) { return "Dafuq i know? I am a NOSYS"; } #endif u32_t sys_now(void) { return xTaskGetTickCount() * portTICK_PERIOD_MS; } static StaticQueue_t xStaticQueue; static const uint16_t QUEUE_LENGTH = 512; uint8_t ucQueueStorageArea[512 * 1]; static const uint16_t stackSizeWords = 512; StaticTask_t xTaskBuffer; StackType_t xStack[512]; void testIp() { uartIsrQueue = xQueueCreateStatic(QUEUE_LENGTH, 1, ucQueueStorageArea, &xStaticQueue); lwip_init(); ip4_addr_t slip_addr = {PP_HTONL(LWIP_MAKEU32(10, 0, 0, 32))}, slip_mask = {PP_HTONL(LWIP_MAKEU32(255, 255, 255, 0))}, slip_gw = {PP_HTONL(LWIP_MAKEU32(10, 0, 0, 1))}; netif_add(&netif, &slip_addr, &slip_mask, &slip_gw, NULL, slipif_init, netif_input); netif_set_default(&netif); // should be done by driver, which does not do it, so we do it here netif_set_link_up(&netif); netif_set_up(&netif); udpecho_raw_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); if (udpecho_raw_pcb != NULL) { err_t err; err = udp_bind(udpecho_raw_pcb, IP_ANY_TYPE, 7); if (err == ERR_OK) { udp_recv(udpecho_raw_pcb, udpecho_raw_recv, NULL); } else { /* TODO */ } } else { /* TODO */ } /* Install the UART Interrupt handler. */ BaseType_t xStatus = XScuGic_Connect(&xInterruptController, STDIN_INT_NR, (Xil_ExceptionHandler)handleUARTInt, NULL); configASSERT(xStatus == XST_SUCCESS); (void)xStatus; /* Remove compiler warning if configASSERT() is not defined. */ // Set trigger level to 62 of 64 bytes, giving interrupt some time to react XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_RXWM_OFFSET, 62); // Setting the rx timeout to n*4 -1 bits XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_RXTOUT_OFFSET, 50); // enable UART Interrupts u32 mask = XUARTPS_IXR_RTRIG | XUARTPS_IXR_RXOVR | XUARTPS_IXR_RXFULL | XUARTPS_IXR_TOUT; /* Write the mask to the IER Register */ XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_IER_OFFSET, mask); /* Write the inverse of the Mask to the IDR register */ XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_IDR_OFFSET, (~mask)); /* Enable the interrupt for the UART1 in the interrupt controller. */ XScuGic_Enable(&xInterruptController, STDIN_INT_NR); // Start lwip task xTaskCreateStatic( lwip_main, /* The function that implements the task. */ "lwip", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ stackSizeWords, /* The size of the stack to allocate to the task. */ NULL, /* The parameter passed to the task - not used in this simple case. */ 4, /* The priority assigned to the task. */ xStack, &xTaskBuffer); }