#include //printf #include //open #include //open #include //open #include //close, getopt #include //perror #include //exit #include //mmap #include //signal #include //assert #include //socket, inet_aton #include //socket, inet_aton #include //socket #include //htons, ntohs, htonl, ntohl, inet_aton #include // nanosleep #include // bool #include "hps_0.h" /*PROTOTYPES*/ void usage(char* name); void bail(int code); void sig_handler(int signum); /*DEFINES*/ #define LW_FPGA_SLAVES_BASE 0xFF200000 #define LW_FPGA_SLAVES_END 0xFF3FFFFF #define LW_FPGA_SLAVES_SPAN 0x00200000 #define BUF_LENGTH 65536 #define NUM_SOCKETS 5 #define PORT_CONFIG_PB 7400 #define PORT_CONFIG_DG 250 #define PORT_CONFIG_PG 2 #define PORT_CONFIG_D0 0 #define PORT_CONFIG_D1 10 #define PORT_CONFIG_D2 1 #define PORT_CONFIG_D3 11 /*GLOBAL VARIABLES*/ //NOTE: use void* Pointer to avoid pointer arithmetic during offset addition void* lw_bridge = NULL; int mem_fd = -1; int sock_fd[NUM_SOCKETS]; uint8_t endian = -1; //0 Big Endian, 1 Little Endian in_addr_t src_addr; long src_did; bool quiet = false; /*CONSTANTS*/ const struct timespec ms = {0, 10^6}; // 1ms const struct timespec us = {0, 10^3}; // 1us const struct timespec sec = {1, 0}; // 1sec int main(int argc, char** argv) { int opt; while ((opt = getopt(argc, argv, "q")) != -1) { switch (opt) { case 'q': quiet = true; break; default: /* invalid option */ fprintf(stderr, "Invalid Option\n"); usage(argv[0]); break; } } if (argc-optind < 2) { fprintf(stderr, "Insufficient arguments\n"); usage(argv[0]); } src_addr = inet_addr(argv[optind]); if (src_addr == INADDR_NONE) { fprintf(stderr, "Invalid IP Address\n"); usage(argv[0]); } errno = 0; src_did = strtol(argv[optind+1], NULL, 10); if (errno != 0) { fprintf(stderr, "Invalid Domain ID\n"); usage(argv[0]); } // Initialize Sockets to aid bail function for (int i = 0; i < NUM_SOCKETS; i++) { sock_fd[i] = -1; } //Register Signal Handling signal(SIGHUP, sig_handler); signal(SIGINT, sig_handler); signal(SIGQUIT, sig_handler); signal(SIGABRT, sig_handler); // Check Endianness { int i = 1; endian = (* (char*) &i == 1) ? 1 : 0; printf("ENDIANNESS: %d\n", endian); } if (endian != 1) { fprintf(stderr, "Program is tested on Little Endian Systems\n"); bail(EXIT_FAILURE); } mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (mem_fd < 0) { perror("Could not open /dev/mem"); bail(EXIT_FAILURE); } lw_bridge = (uint32_t*)mmap(NULL, LW_FPGA_SLAVES_SPAN, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, LW_FPGA_SLAVES_BASE); if (lw_bridge == MAP_FAILED) { perror("Could not mmap /dev/mem"); bail(EXIT_FAILURE); } // Polling Address uint32_t* ADDR_0 = (uint32_t*)(lw_bridge + TEST_FPGA_0_BASE); // Read Address uint32_t* ADDR_1 = ADDR_0 + 1; //Pointer Arithmetic // Write Address uint32_t* ADDR_2 = ADDR_0 + 2; //Pointer Arithmetic for (int i = 0; i < NUM_SOCKETS; i++) { sock_fd[i] = socket(AF_INET, SOCK_DGRAM, 0); if (sock_fd[i] < 0) { fprintf(stderr, "Socket %d", i); perror("Could not open socket"); bail(EXIT_FAILURE); } } const struct sockaddr_in bind_addr[NUM_SOCKETS] = { {AF_INET, htons(PORT_CONFIG_PB + PORT_CONFIG_D0 + PORT_CONFIG_DG * src_did), {inet_addr("239.255.0.1")}}, {AF_INET, htons(PORT_CONFIG_PB + PORT_CONFIG_D0 + PORT_CONFIG_DG * src_did), {src_addr}}, {AF_INET, htons(PORT_CONFIG_PB + PORT_CONFIG_D1 + PORT_CONFIG_DG * src_did), {src_addr}}, {AF_INET, htons(PORT_CONFIG_PB + PORT_CONFIG_D2 + PORT_CONFIG_DG * src_did), {src_addr}}, {AF_INET, htons(PORT_CONFIG_PB + PORT_CONFIG_D3 + PORT_CONFIG_DG * src_did), {src_addr}} }; printf("bind_addr[0]: %s:%d\n",inet_ntoa(bind_addr[0].sin_addr),ntohs(bind_addr[0].sin_port)); printf("bind_addr[1]: %s:%d\n",inet_ntoa(bind_addr[1].sin_addr),ntohs(bind_addr[1].sin_port)); printf("bind_addr[2]: %s:%d\n",inet_ntoa(bind_addr[2].sin_addr),ntohs(bind_addr[2].sin_port)); printf("bind_addr[3]: %s:%d\n",inet_ntoa(bind_addr[3].sin_addr),ntohs(bind_addr[3].sin_port)); printf("bind_addr[4]: %s:%d\n",inet_ntoa(bind_addr[4].sin_addr),ntohs(bind_addr[4].sin_port)); for (int i = 0; i < NUM_SOCKETS; i++) { if (bind(sock_fd[i], (const struct sockaddr*) &bind_addr[i], sizeof(bind_addr[i])) < 0) { fprintf(stderr, "bind_addr[%d]", i); perror("Bind failed"); bail(EXIT_FAILURE); } } struct sockaddr_in src, dest; char buffer[BUF_LENGTH]; int n, addrlen, j; uint32_t* p; uint32_t tmp; printf("Entering Loop\n"); while (1) { /*UDP OUTPUT*/ // FPGA has output if (*ADDR_0 != 0) { src.sin_family = AF_INET; dest.sin_family = AF_INET; // Read SRC Address src.sin_addr.s_addr = *ADDR_1; // Read DEST Address dest.sin_addr.s_addr = *ADDR_1; // Read UDP Ports tmp = *ADDR_1; dest.sin_port = ((tmp >> 16) & 0xFFFF); src.sin_port = (tmp & 0xFFFF); // Read Packet Length n = ntohl(*ADDR_1); // Read Packet p = (uint32_t*) buffer; for(int i = 0; i < n; i++) { p[i] = *ADDR_1; } // Convert n to Byte Count n = n * 4; // Select correct socket j = NUM_SOCKETS; for (int i = 0; i < NUM_SOCKETS; i++) { if (bind_addr[i].sin_addr.s_addr == src.sin_addr.s_addr && bind_addr[i].sin_port == src.sin_port) { j = i; break; } } // No bind_addr Match if (j == NUM_SOCKETS) { fprintf(stderr, "Provided SRC does not have respective bind_addr\n"); fprintf(stderr, "SRC: %s %d\n", inet_ntoa(src.sin_addr), ntohs(src.sin_port)); bail(EXIT_FAILURE); } n = sendto(sock_fd[j], buffer, n, 0, (const struct sockaddr*) &dest, sizeof(dest)); if (n < 0) { perror("sendto failed"); bail(EXIT_FAILURE); } if (!quiet) { printf("Packet sent (%d Words)\n", n/4); printf(" Src: %s:%d\n",inet_ntoa(bind_addr[j].sin_addr),ntohs(bind_addr[j].sin_port)); printf(" Dest: %s:%d\n",inet_ntoa(dest.sin_addr),ntohs(dest.sin_port)); } } /*UDP INPUT*/ for (j = 0; j < NUM_SOCKETS; j++) { addrlen = sizeof(src); n = recvfrom(sock_fd[j], buffer, BUF_LENGTH, MSG_DONTWAIT | MSG_TRUNC, (struct sockaddr*) &src, &addrlen); if (n < 0) { // Error if (errno != EAGAIN && errno != EWOULDBLOCK) { perror("rcvfrom() error"); bail(EXIT_FAILURE); } } // Exit Condition else if (n > 0) { break; } } if (n > 0) { //Buffer not 4-Byte aligned if ((n % 4) != 0) { // Add zero byte padding for(int offset = 4 - (n % 4); offset > 0; offset--){ buffer[n+offset-1] = 0; } // Convert n to Word Count n = (n / 4) + 1; } else { // Convert n to Word Count n = n / 4; } //SANITY CHECK if (addrlen != sizeof(src)){ fprintf(stderr, "rcvfrom() returned unexpected addrlen.\n"); bail(EXIT_FAILURE); } // Write SRC Address *ADDR_2 = src.sin_addr.s_addr; // Write DEST Address *ADDR_2 = bind_addr[j].sin_addr.s_addr; // Write UDP Ports *ADDR_2 = ((bind_addr[j].sin_port << 16) & 0xFFFF0000) | (src.sin_port & 0xFFFF); // Write Packet Length *ADDR_2 = htonl(n); // Write Packet p = (uint32_t*) buffer; for (int i = 0; i < n; i++) { *ADDR_2 = p[i]; } if (!quiet){ printf("Packet received (%d Words)\n", n); printf(" Src: %s:%d\n",inet_ntoa(bind_addr[j].sin_addr),ntohs(bind_addr[j].sin_port)); } } /* else { nanosleep(&ms, NULL); //Wait 1 ms } */ } } void bail(int code){ // Close File Descriptors if (mem_fd != -1){ close(mem_fd); } for (int i = 0; i < NUM_SOCKETS; i++) { if (sock_fd[i] != -1) { close(sock_fd[i]); } } // Unmap /dev/mem if (lw_bridge != NULL){ munmap(lw_bridge, LW_FPGA_SLAVES_SPAN); } exit(code); } void sig_handler(int signum){ fprintf(stderr, "Received Signal %d.\n Exiting...\n", signum); bail(EXIT_SUCCESS); } void usage(char* name){ printf("USAGE: %s [-q] ADDRESS DOMAIN_ID\n", name); printf("-q Quiet Flag. When specified, no information is printed during the main loops\n"); printf("ADDRESS The SRC IPv4 Address of the FPGA implementation (In x.x.x.x format)\n"); printf(" NOTE: The system has to have a interface with the same address\n"); printf("DOMAIN_ID The Domain ID of the FPGA implementation\n"); bail(EXIT_SUCCESS); }