From d6f39fb385e696800373c0a43bdfc03f8ade8353 Mon Sep 17 00:00:00 2001 From: Manish Garg Date: Mon, 16 Sep 2024 14:58:44 +0530 Subject: [PATCH] UDP server support to send CSI data to UDP client ADD sample client file for datadump over UDP --- .../rtl8730e/loadable_ext_psram/defconfig | 1 + framework/src/csifw/CSILogsDumper.c | 209 ++++++++++++++++++ framework/src/csifw/CSIService.c | 92 ++++++++ framework/src/csifw/Make.defs | 3 + framework/src/csifw/include/CSILogsDumper.h | 21 ++ .../README_csi_datadump_udp_client.md | 16 ++ tools/csi_datadump/csi_datadump_udp_client.c | 106 +++++++++ 7 files changed, 448 insertions(+) create mode 100644 framework/src/csifw/CSILogsDumper.c create mode 100644 framework/src/csifw/include/CSILogsDumper.h create mode 100644 tools/csi_datadump/README_csi_datadump_udp_client.md create mode 100644 tools/csi_datadump/csi_datadump_udp_client.c diff --git a/build/configs/rtl8730e/loadable_ext_psram/defconfig b/build/configs/rtl8730e/loadable_ext_psram/defconfig index aedf44ab07..1bf7e52a41 100644 --- a/build/configs/rtl8730e/loadable_ext_psram/defconfig +++ b/build/configs/rtl8730e/loadable_ext_psram/defconfig @@ -1671,6 +1671,7 @@ CONFIG_EXAMPLE_LCD_FPS_TEST=5000 # CONFIG_EXAMPLES_WIFIMANAGER_TEST is not set # CONFIG_WIFIMANAGER_TEST_TRIAL=5 # CONFIG_EXAMPLES_WIFIMANAGER_AP_LIST_ITEMS_COUNT=10 +# CONFIG_CSI_DATA_DUMP_OVER_NETWORK is not set # # Platform-specific Support diff --git a/framework/src/csifw/CSILogsDumper.c b/framework/src/csifw/CSILogsDumper.c new file mode 100644 index 0000000000..30adb89001 --- /dev/null +++ b/framework/src/csifw/CSILogsDumper.c @@ -0,0 +1,209 @@ +#include "include/CSILogsDumper.h" +#include +#include +#include +#include + +#define PORT 5000 +#define CONTROL_COMMAND_BUFFER_SIZE 128 +#define CSI_DATA_DUMP_BUFFER_SIZE 1024 + +unsigned char gCSIDataDumpBuffer[CSI_DATA_DUMP_BUFFER_SIZE]; +char gControlCommandBuffer[CONTROL_COMMAND_BUFFER_SIZE]; + +csiDataDumpListener gListener = NULL; +static pthread_t gThreadId = -1; +static int gSockFd = -1, gFifoFd = -1; +struct sockaddr_in gServerAddr, gClientAddr; +socklen_t gClientLen = sizeof(gClientAddr); +fd_set readfds; +int maxfd; + +static int gWaitingForData = 0; +static int gRemainingBytes = 0; +static int gBytesReadSofar = 0; + +static int recv_message(int fd, void *buf, int buflen) +{ + int received = 0; + while (1) { + int res = read(fd, buf + received, buflen - received); + if (res < 0) { + int err_no = errno; + if (err_no == EAGAIN || err_no == EINTR) { + continue; + } + CSIFW_LOGE("read error %d\n", err_no); + return -1; + } + received += res; + if (received == buflen) { + break; + } + } + return received; +} + +static int print_log(const char *format, ...) +{ + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + return 1; +} + +static void print_buf(const unsigned char* buf, int len) +{ + print_log("\n RAW DATA %d\n\n", len); + unsigned long long *buff_tmp = (u64 *)buf; + int buff_len = (len/8) + 1; + for (int i = 0; i < buff_len; i++) + print_log("[%02d]0x%016llx\n", i, buff_tmp[i]); +} + +void set_event_listener(csiDataDumpListener listener) +{ + gListener = listener; +} + +void *dataTransmitter(void *arg) +{ + int len; + while (1) { + FD_ZERO(&readfds); + FD_SET(gSockFd, &readfds); + FD_SET(gFifoFd, &readfds); + maxfd = (gSockFd > gFifoFd) ? gSockFd : gFifoFd; + + CSIFW_LOGI("Wait for an activity on one of the file descriptors"); + int ret = select(maxfd + 1, &readfds, NULL, NULL, NULL); + if (ret < 0) { + if (errno == EBADF){ + CSIFW_LOGE("select operation failed due to file descripter close: %d", errno); + return; + } + else if(errno == EINTR){ + CSIFW_LOGE("select operation failed due to Temporary Interrupt: %d", errno); + continue;; + } + CSIFW_LOGE("select operation failed over file descripters: %d", errno); + return; + } + + // Check if there's data on the UDP socket + if (FD_ISSET(gSockFd, &readfds)) { + CSIFW_LOGI("Received an activity on sockfd descriptors"); + len = recvfrom(gSockFd, gControlCommandBuffer, CONTROL_COMMAND_BUFFER_SIZE-1, 0, (struct sockaddr *)&gClientAddr, &gClientLen); + if (len < 0) { + continue; + } + gControlCommandBuffer[len] = '\0'; + if (strncmp(gControlCommandBuffer, "START", 6) == 0) { + gListener(START_DUMP); + CSIFW_LOGI("Received START command. Starting to send data to client from FIFO"); + } else if (strncmp(gControlCommandBuffer, "STOP", 5) == 0) { + gListener(STOP_DUMP); + CSIFW_LOGI("Received STOP command. Stopping data transfer to client from FIFO"); + } else { + CSIFW_LOGI("Received unknown command: %s", gControlCommandBuffer); + continue; + } + } + + // Check if there's data on the FIFO + if (FD_ISSET(gFifoFd, &readfds)) { + CSIFW_LOGI("Received an activity on Fifo descriptors"); + + if (!gWaitingForData) { + // Get the length from the first 2 bytes + len = recv_message(gFifoFd, (void *)gCSIDataDumpBuffer, 2); + if (len <= 0) { + CSIFW_LOGE("operation to read length of data from FIFO Failed"); + continue; + } + uint16_t length; + memcpy(&length , gCSIDataDumpBuffer, sizeof(length)); + CSIFW_LOGI("Read %d length to client:", length); + gRemainingBytes = length; + gWaitingForData = 1; + gBytesReadSofar = 0; + } + if (gWaitingForData) { + // We are expecting to read the actual data + ssize_t bytes_read = read(gFifoFd, gCSIDataDumpBuffer + gBytesReadSofar, gRemainingBytes); + if (bytes_read < 0) { + int err_no = errno; + if (err_no == EAGAIN || err_no == EINTR) { + continue; + } + CSIFW_LOGE("read error %d\n", err_no); + continue; // or return + } + + gBytesReadSofar += bytes_read; + gRemainingBytes -= bytes_read; + + if (gRemainingBytes == 0) { + // Complete data received + gWaitingForData = 0; + // Send the data to the client + len = sendto(gSockFd, gCSIDataDumpBuffer, gBytesReadSofar, 0, (struct sockaddr *)&gClientAddr, sizeof(gClientAddr)); + if (len == -1) { + CSIFW_LOGE("sendto error:%d", errno); + continue; + } + CSIFW_LOGI("Sent %d bytes to client", len); + print_buf(gCSIDataDumpBuffer,len); + } + } + } + } +} + +CSIFW_RES csi_logs_dumper_init() +{ + if ((gSockFd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + CSIFW_LOGE("failed to create a socket fd"); + return CSIFW_ERROR; + } + + memset(&gServerAddr, 0, sizeof(gServerAddr)); + gServerAddr.sin_family = AF_INET; + gServerAddr.sin_addr.s_addr = INADDR_ANY; + gServerAddr.sin_port = htons(PORT); + + if (bind(gSockFd, (struct sockaddr*)&gServerAddr, sizeof(gServerAddr)) < 0) { + CSIFW_LOGE("binding socket failed"); + close(gSockFd); + return CSIFW_ERROR; + } + printf("server Socket Created\n"); + gFifoFd = open(CSI_DUMP_DATA_QUEUE_NAME, O_RDONLY | O_NONBLOCK); + if (gFifoFd < 0) { + CSIFW_LOGE("open CSI_DUMP_DATA_QUEUE fail %d", errno); + close(gSockFd); + return CSIFW_ERROR; + } + + if (pthread_create(&gThreadId, NULL, dataTransmitter, NULL) != 0) { + CSIFW_LOGE("Failed to create dataTransmitter thread %d", errno); + close(gSockFd); + close(gFifoFd); + return CSIFW_ERROR; + } + + if (pthread_setname_np(gThreadId, "CSI_DataDumpOverNetwork") != 0) { + CSIFW_LOGE("Error in setting dataTransmitter thread name, error_no: %d", errno); + } + CSIFW_LOGI("CSI_DataDumpOverNetwork created"); + return CSIFW_OK; +} + +CSIFW_RES csi_logs_dumper_deinit() +{ + gListener = NULL; + close(gSockFd); + close(gFifoFd); + return CSIFW_OK; +} diff --git a/framework/src/csifw/CSIService.c b/framework/src/csifw/CSIService.c index da9f6ed676..eb82c8f446 100644 --- a/framework/src/csifw/CSIService.c +++ b/framework/src/csifw/CSIService.c @@ -4,6 +4,11 @@ #include "include/CSIParser.h" #include "include/CSIPacketReceiver.h" #include "include/CSINetworkMonitor.h" +#ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK +#include "include/CSILogsDumper.h" +#endif +#include +#include COLLECT_STATE g_service_state = CSI_STATE_UNITIALIZED; CONNECTION_STATE g_nw_state; @@ -15,6 +20,57 @@ upd_parsed_data_listener g_parsed_callback; static void* g_ptr; static csi_action_param_t g_csifw_config __attribute__((aligned(64))) = {0,}; +#ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK +#define CSI_DATA_BUFFER_SIZE 1024 + +unsigned char gCSIDataBuffer[CSI_DATA_BUFFER_SIZE]; +int gDataDumpDescriptor; +bool gCSIDataDumpEvent = STOP_DUMP; + +static void csi_data_dump_listener(EVENT event) { + CSIFW_LOGD("csi_data_dump_listener called\n"); + gCSIDataDumpEvent = event; + return; +} + +static int send_message(int fd, void *buf, int buflen) +{ + int sent = 0; + while (1) { + int res = write(fd, (void *)buf + sent, buflen - sent); + if (res < 0) { + int err_no = errno; + if (err_no == EAGAIN || err_no == EINTR) { + continue; + } + CSIFW_LOGE("write error %d", err_no); + return -1; + } + sent += res; + if (sent == buflen) { + break; + } + } + return 0; +} + +CSIFW_RES csi_logs_dumper_send_to_queue(unsigned char *csi_buf, int len) +{ + // Copy the length to the first two bytes and the data to the rest of the output buffer + uint16_t dest_len = (uint16_t)len; + memcpy(gCSIDataBuffer, &dest_len, 2); + memcpy(gCSIDataBuffer + 2, csi_buf, len); + + int res = send_message(gDataDumpDescriptor, (void *)gCSIDataBuffer, len + 2); + + if (res < 0) { + CSIFW_LOGE("Failed to send message to CSI_DUMP_DATA_QUEUE"); + return CSIFW_ERROR; + } + return CSIFW_OK; +} +#endif + static void CSIRawDataListener(CSIFW_RES res, int raw_csi_buff_len, unsigned char *raw_csi_buff, int raw_csi_data_len) { //Send raw data to UPD @@ -24,6 +80,15 @@ static void CSIRawDataListener(CSIFW_RES res, int raw_csi_buff_len, unsigned cha } if (g_raw_callback) { g_raw_callback(res, raw_csi_buff_len, raw_csi_buff, g_ptr); + #ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK + if (gCSIDataDumpEvent) { + CSIFW_RES ret = csi_logs_dumper_send_to_queue(raw_csi_buff, raw_csi_buff_len); + if (ret != CSIFW_OK) { + CSIFW_LOGE("Failed to send CSI data to CSI_DUMP_DATA_QUEUE"); + } + CSIFW_LOGD("CSI data sent to CSI_DUMP_DATA_QUEUE"); + } + #endif } } @@ -44,6 +109,28 @@ CSIFW_RES csi_manager_init(void) CSIFW_RES csi_service_init(upd_raw_data_listener raw_callback, upd_parsed_data_listener parsed_callback, unsigned int interval, void* ptr) { + #ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK + int result = mkfifo(CSI_DUMP_DATA_QUEUE_NAME, 0666); + if (result < 0 && result != -EEXIST) { + CSIFW_LOGE("create CSI_DUMP_DATA_QUEUE fail %d", errno); + return CSIFW_ERROR; + } + gDataDumpDescriptor = open(CSI_DUMP_DATA_QUEUE_NAME, O_WRONLY | O_NONBLOCK); + if (gDataDumpDescriptor < 0) { + CSIFW_LOGE("open CSI_DUMP_DATA_QUEUE fail %d", errno); + unlink(CSI_DUMP_DATA_QUEUE_NAME); + return CSIFW_ERROR; + } + result = csi_logs_dumper_init(); + if (result != CSIFW_OK) { + CSIFW_LOGE("open csi_logs_dumper_init fail"); + close(gDataDumpDescriptor); + unlink(CSI_DUMP_DATA_QUEUE_NAME); + return CSIFW_ERROR; + } + set_event_listener(csi_data_dump_listener); + #endif + g_ptr = ptr; if (g_service_state != CSI_STATE_UNITIALIZED) { CSIFW_LOGE("Already Initialized"); @@ -128,6 +215,11 @@ CSIFW_RES csi_service_deinit() } g_service_state = CSI_STATE_UNITIALIZED; csi_packet_receiver_deinit(); + #ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK + csi_logs_dumper_deinit(); + close(gDataDumpDescriptor); + unlink(CSI_DUMP_DATA_QUEUE_NAME); + #endif if (g_parsed_buffptr) { free(g_parsed_buffptr); g_parsed_buffptr = NULL; diff --git a/framework/src/csifw/Make.defs b/framework/src/csifw/Make.defs index a97c34cfe4..bf928e54d2 100644 --- a/framework/src/csifw/Make.defs +++ b/framework/src/csifw/Make.defs @@ -21,6 +21,9 @@ ifeq ($(CONFIG_CSIFW), y) CFLAGS += -I${TOPDIR}/os/include CSRCS += CSIPacketReceiver.c CSIParser.c CSIService.c PingGenerator.c CSINetworkMonitor.c rb.c +ifeq ($(CONFIG_CSI_DATA_DUMP_OVER_NETWORK), y) + CSRCS += CSILogsDumper.c +endif DEPPATH += --dep-path src/csifw VPATH += :src/csifw diff --git a/framework/src/csifw/include/CSILogsDumper.h b/framework/src/csifw/include/CSILogsDumper.h new file mode 100644 index 0000000000..89c6933fc4 --- /dev/null +++ b/framework/src/csifw/include/CSILogsDumper.h @@ -0,0 +1,21 @@ +#ifndef __CSI_LOGS_DUMPER__ +#define __CSI_LOGS_DUMPER__ + +#include "csifw.h" + +#ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK +#define CSI_DUMP_DATA_QUEUE_NAME "/dev/csidump_data" + +typedef enum EVENT { + STOP_DUMP, + START_DUMP +} EVENT; + +CSIFW_RES csi_logs_dumper_init(); +CSIFW_RES csi_logs_dumper_deinit(); + +typedef void (*csiDataDumpListener)(EVENT event); +void set_event_listener(csiDataDumpListener listener); +#endif + +#endif /* __CSI_LOGS_DUMPER__ */ diff --git a/tools/csi_datadump/README_csi_datadump_udp_client.md b/tools/csi_datadump/README_csi_datadump_udp_client.md new file mode 100644 index 0000000000..99e6ba208e --- /dev/null +++ b/tools/csi_datadump/README_csi_datadump_udp_client.md @@ -0,0 +1,16 @@ +# How To Run csi_datadump_udp_client.c File + +## Steps: +### 1. First compile the file: +```bash +gcc -o program csi_datadump_udp_client.c -lpthread +``` + +### 2. Run the program + Command Format: ./program +```bash +./program 192.168.1.120 5000 +``` + +## How to STOP the datadump +#### Type *STOP* in terminal and press enter. \ No newline at end of file diff --git a/tools/csi_datadump/csi_datadump_udp_client.c b/tools/csi_datadump/csi_datadump_udp_client.c new file mode 100644 index 0000000000..8f49d45a21 --- /dev/null +++ b/tools/csi_datadump/csi_datadump_udp_client.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 +#define FILENAME "received_data.txt" +FILE* file; +typedef unsigned long long u64; +int stop = 0; + +static void print_buf(const unsigned char* buf, int len) +{ + printf("\nRAW DATA: %d\n", len); + fprintf(file,"\nRAW DATA: %d\n", len); + unsigned long long *buff_tmp = (u64 *)buf; + int buff_len = (len/8) + 1; + for (int i = 0; i < buff_len; i++) { + printf("[%02d]0x%016llx\n", i, buff_tmp[i]); + fprintf(file, "[%02d]0x%016llx\n", i, buff_tmp[i]); + } +} + +void* receive_data(void* sockfd_ptr) { + int sockfd = *(int*)sockfd_ptr; + struct sockaddr_in servaddr; + char buffer[BUFFER_SIZE]; + int n; + socklen_t addr_len = sizeof(servaddr); + + while (!stop) { + n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, 0, (struct sockaddr *) &servaddr, &addr_len); + if (n < 0) { + printf("Receive failed\n"); + } else { + buffer[n] = '\0'; + printf("Received CSI DATA Success\n"); + print_buf(buffer,n); + } + } + sleep(1); + pthread_exit(NULL); +} + +int main(int argc, char *argv[]) { + int sockfd; + struct sockaddr_in server_addr; + socklen_t addr_len; + pthread_t recv_thread; + char message[20]; + + if(argc != 3){ + printf("Input Error\n"); + return -1; + } + + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("Socket creation failed\n"); + return -1; + } + struct timeval timeout; + timeout.tv_sec = 5; + timeout.tv_usec = 0; + setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + + // Server address setup + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(atoi(argv[2])); + if (inet_pton(AF_INET, argv[1], &server_addr.sin_addr) <= 0) { + printf("Invalid IP address\n"); + close(sockfd); + return -1; + } + addr_len = sizeof(server_addr); + + // Send START command + strncpy(message, "START", 6); + sendto(sockfd, message, strlen(message), 0, (const struct sockaddr *)&server_addr, addr_len); + + file = fopen(FILENAME, "w"); + if (file == NULL) { + printf("Error opening file\n"); + return -1; + } + pthread_create(&recv_thread, NULL, receive_data, (void*)&sockfd); + + // Wait for the user to type "stop" + while (1) { + fgets(message, sizeof(message), stdin); + message[strcspn(message, "\n")] = '\0'; // Remove newline character + + if (strncmp(message, "STOP", 5) == 0) { + stop = 1; + sendto(sockfd, (const char *)message, strlen(message), 0, (const struct sockaddr *) &server_addr, addr_len); + printf("Stop command sent to server\n"); + break; + } + } + pthread_join(recv_thread, NULL); + fclose(file); + close(sockfd); + return 0; +} \ No newline at end of file