From 5d778a5cecd450212f55ef5bb9695fbe7298e845 Mon Sep 17 00:00:00 2001
From: Cedric Roux <cedric.roux@eurecom.fr>
Date: Fri, 6 Oct 2017 16:53:18 +0200
Subject: [PATCH] add debugging tool tcp_bridge

internal use, no documentation, no support.
---
 cmake_targets/CMakeLists.txt         |   9 +
 targets/ARCH/tcp_bridge/README       |   4 +
 targets/ARCH/tcp_bridge/tcp_bridge.c | 292 +++++++++++++++++++++++++++
 3 files changed, 305 insertions(+)
 create mode 100644 targets/ARCH/tcp_bridge/README
 create mode 100644 targets/ARCH/tcp_bridge/tcp_bridge.c

diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 3cdd2b9ccda..f15f0a8d46a 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -563,6 +563,15 @@ add_library(oai_mobipass MODULE ${TPLIB_MOBIPASS_SOURCE} )
 get_target_property(mobipas_cflags oai_mobipass COMPILE_FLAGS)
 set_target_properties(oai_mobipass PROPERTIES COMPILE_FLAGS "${mobipass_cflags} -fvisibility=hidden")
 
+set(HWLIB_TCP_BRIDGE_SOURCE
+  ${OPENAIR_TARGETS}/ARCH/tcp_bridge/tcp_bridge.c
+  )
+add_library(oai_tcp_bridge MODULE ${HWLIB_TCP_BRIDGE_SOURCE} )
+
+#get_target_property(tcp_bridge_cflags oai_tcp_bridge COMPILE_FLAGS)
+#set_target_properties(oai_tcp_bridge PROPERTIES COMPILE_FLAGS "${tcp_bridge_cflags} -fvisibility=hidden")
+set_target_properties(oai_tcp_bridge PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
+
 ##########################################################
 
 include_directories ("${OPENAIR_TARGETS}/ARCH/COMMON")
diff --git a/targets/ARCH/tcp_bridge/README b/targets/ARCH/tcp_bridge/README
new file mode 100644
index 00000000000..9bd1a16e592
--- /dev/null
+++ b/targets/ARCH/tcp_bridge/README
@@ -0,0 +1,4 @@
+This is sort of a "TCP driver" to ease debugging. This is mostly internal
+to EURECOM. You probably don't want to use it.
+
+Same license as the rest.
diff --git a/targets/ARCH/tcp_bridge/tcp_bridge.c b/targets/ARCH/tcp_bridge/tcp_bridge.c
new file mode 100644
index 00000000000..127ba39bbcf
--- /dev/null
+++ b/targets/ARCH/tcp_bridge/tcp_bridge.c
@@ -0,0 +1,292 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int fullread(int fd, void *_buf, int count)
+{
+  char *buf = _buf;
+  int ret = 0;
+  int l;
+  while (count) {
+    l = read(fd, buf, count);
+    if (l <= 0) return -1;
+    count -= l;
+    buf += l;
+    ret += l;
+  }
+  return ret;
+}
+
+int fullwrite(int fd, void *_buf, int count)
+{
+  char *buf = _buf;
+  int ret = 0;
+  int l;
+  while (count) {
+    l = write(fd, buf, count);
+    if (l <= 0) return -1;
+    count -= l;
+    buf += l;
+    ret += l;
+  }
+  return ret;
+}
+
+#include "common_lib.h"
+
+typedef struct {
+  int32_t data[30720]; /* max 20MHz */
+  unsigned long timestamp;
+  int size;
+} input_buffer;
+
+#define BSIZE 16
+
+typedef struct {
+  int sock;
+  int samples_per_subframe;
+  input_buffer b[BSIZE];
+  int bstart;
+  int blen;
+  unsigned long read_timestamp;
+} tcp_bridge_state_t;
+
+
+/****************************************************************************/
+/* buffer management                                                        */
+/* (could be simpler, we are synchronous)                                   */
+/* maybe we should lock                                                     */
+/****************************************************************************/
+
+void put_buffer(tcp_bridge_state_t *t, void *data, int size, unsigned long timestamp)
+{
+  int nextpos;
+  if (t->blen == BSIZE) { printf("tcp_bridge: buffer full\n"); exit(1); }
+  if (size > 30720*4) abort();
+  if (t->blen) {
+    int lastpos = (t->bstart+t->blen-1) % BSIZE;
+    if (timestamp != t->b[lastpos].timestamp + t->samples_per_subframe)
+      { printf("tcp_bridge: discontinuity\n"); exit(1); }
+  }
+  nextpos = (t->bstart+t->blen) % BSIZE;
+  t->b[nextpos].timestamp = timestamp;
+  t->b[nextpos].size      = size;
+  memcpy(t->b[nextpos].data, data, size);
+  t->blen++;
+}
+
+void get_buffer(tcp_bridge_state_t *t, void *data, int size, unsigned long timestamp)
+{
+  int pos;
+  if (t->blen == 0) { printf("tcp_bridge: buffer empty\n"); exit(1); }
+  if (size >30720*4) abort();
+  pos = t->bstart;
+  if (size != t->b[pos].size) { printf("tcp_bridge: bad size\n"); exit(1); }
+  memcpy(data, t->b[pos].data, size);
+  t->bstart = (t->bstart + 1) % BSIZE;
+  t->blen--;
+}
+
+/****************************************************************************/
+/* end of buffer management                                                 */
+/****************************************************************************/
+
+
+/****************************************************************************/
+/* network management (read/write)                                          */
+/****************************************************************************/
+
+void read_data_from_network(int sock, input_buffer *b)
+{
+  if (fullread(sock, &b->timestamp, sizeof(b->timestamp)) != sizeof(b->timestamp)) goto err;
+  if (fullread(sock, &b->size, sizeof(b->size)) != sizeof(b->size)) goto err;
+  if (fullread(sock, b->data, b->size) != b->size) goto err;
+  return;
+
+err:
+  printf("tcp_bridge: read_data_from_network fails\n");
+  exit(1);
+}
+
+void write_data_to_network(int sock, input_buffer *b)
+{
+  if (fullwrite(sock, &b->timestamp, sizeof(b->timestamp)) != sizeof(b->timestamp)) goto err;
+  if (fullwrite(sock, &b->size, sizeof(b->size)) != sizeof(b->size)) goto err;
+  if (fullwrite(sock, b->data, b->size) != b->size) goto err;
+  return;
+
+err:
+  printf("tcp_bridge: write_data_to_network fails\n");
+  exit(1);
+}
+
+/****************************************************************************/
+/* end of network management                                                */
+/****************************************************************************/
+
+
+int tcp_bridge_start(openair0_device *device)
+{
+  int i;
+  int port = 4042;
+  tcp_bridge_state_t *tcp_bridge = device->priv;
+
+  int sock = socket(AF_INET, SOCK_STREAM, 0);
+  if (sock == -1) { perror("tcp_bridge: socket"); exit(1); }
+
+  int enable = 1;
+  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)))
+    { perror("tcp_bridge: SO_REUSEADDR"); exit(1); }
+
+  struct sockaddr_in addr = {
+    sin_family: AF_INET,
+    sin_port: htons(port),
+    sin_addr: { s_addr: INADDR_ANY }
+  };
+
+  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
+    { perror("tcp_bridge: bind"); exit(1); }
+
+  if (listen(sock, 5))
+    { perror("tcp_bridge: listen"); exit(1); }
+
+  printf("tcp_bridge: wait for connection on port %d\n", port);
+
+  socklen_t len = sizeof(addr);
+  int sock2 = accept(sock, (struct sockaddr *)&addr, &len);
+  if (sock2 == -1)
+    { perror("tcp_bridge: accept"); exit(1); }
+
+  close(sock);
+
+  tcp_bridge->sock = sock2;
+
+  /* the other end has to send 10 subframes at startup */
+  for (i = 0; i < 10; i++)
+    read_data_from_network(sock2, &tcp_bridge->b[i]);
+  tcp_bridge->bstart = 0;
+  tcp_bridge->blen = 10;
+
+  printf("tcp_bridge: connection established\n");
+
+  return 0;
+}
+
+int tcp_bridge_request(openair0_device *device, void *msg, ssize_t msg_len) { abort(); return 0; }
+int tcp_bridge_reply(openair0_device *device, void *msg, ssize_t msg_len) { abort(); return 0; }
+int tcp_bridge_get_stats(openair0_device* device) { return 0; }
+int tcp_bridge_reset_stats(openair0_device* device) { return 0; }
+void tcp_bridge_end(openair0_device *device) {}
+int tcp_bridge_stop(openair0_device *device) { return 0; }
+int tcp_bridge_set_freq(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config) { return 0; }
+int tcp_bridge_set_gains(openair0_device* device, openair0_config_t *openair0_cfg) { return 0; }
+
+int tcp_bridge_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags)
+{
+  tcp_bridge_state_t *t = device->priv;
+  input_buffer out;
+  int i;
+//printf("write ts %ld nsamps %d\n", timestamp, nsamps);
+
+  if (nsamps > 30720) abort();
+
+  /* read buffer timestamped with 'timestamp' if not already here */
+  for (i = 0; i < t->blen; i++) {
+    input_buffer *b = &t->b[(t->bstart + i) % BSIZE];
+    if (b->timestamp == timestamp) break;
+  }
+  if (i == t->blen) {
+    int nextpos = (t->bstart + t->blen) % BSIZE;
+    if (t->blen == BSIZE) abort();
+    read_data_from_network(t->sock, &t->b[nextpos]);
+    t->blen++;
+    if (t->b[nextpos].timestamp != timestamp) abort();
+  }
+
+  memcpy(out.data, buff[0], nsamps * 4);
+  out.timestamp = timestamp;
+  out.size = nsamps * 4;
+  write_data_to_network(t->sock, &out);
+
+  return nsamps;
+}
+
+int tcp_bridge_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc)
+{
+  tcp_bridge_state_t *t = device->priv;
+  input_buffer *b;
+
+  if (cc != 1) abort();
+  if (t->blen == 0) abort();
+
+  b = &t->b[t->bstart];
+
+#if 0
+typedef struct {
+  int32_t data[30720]; /* max 20MHz */
+  unsigned long timestamp;
+  int size;
+} input_buffer;
+#endif
+
+  if (b->timestamp != t->read_timestamp) abort();
+  if (b->size != nsamps * 4) abort();
+
+  *timestamp = b->timestamp;
+  memcpy(buff[0], b->data, b->size);
+
+  t->read_timestamp += nsamps;
+  t->bstart = (t->bstart + 1) % BSIZE;
+  t->blen--;
+
+static unsigned long ts = 0;
+//printf("read ts %ld nsamps %d\n", ts, nsamps);
+*timestamp = ts;
+ts += nsamps;
+
+  return nsamps;
+}
+
+__attribute__((__visibility__("default")))
+int device_init(openair0_device* device, openair0_config_t *openair0_cfg)
+{
+  tcp_bridge_state_t *tcp_bridge = (tcp_bridge_state_t*)malloc(sizeof(tcp_bridge_state_t));
+  memset(tcp_bridge, 0, sizeof(tcp_bridge_state_t));
+
+  /* only 25 or 50 PRBs handled for the moment */
+  if (openair0_cfg[0].sample_rate != 30720000 &&
+      openair0_cfg[0].sample_rate != 15360000 &&
+      openair0_cfg[0].sample_rate !=  7680000) {
+    printf("tcp_bridge: ERROR: only 25, 50 or 100 PRBs supported\n");
+    exit(1);
+  }
+
+  device->trx_start_func   = tcp_bridge_start;
+  device->trx_get_stats_func   = tcp_bridge_get_stats;
+  device->trx_reset_stats_func = tcp_bridge_reset_stats;
+  device->trx_end_func         = tcp_bridge_end;
+  device->trx_stop_func        = tcp_bridge_stop;
+  device->trx_set_freq_func = tcp_bridge_set_freq;
+  device->trx_set_gains_func = tcp_bridge_set_gains;
+  device->trx_write_func   = tcp_bridge_write;
+  device->trx_read_func    = tcp_bridge_read;
+
+  device->priv = tcp_bridge;
+
+  switch ((int)openair0_cfg[0].sample_rate) {
+  case 30720000: tcp_bridge->samples_per_subframe = 30720; break;
+  case 15360000: tcp_bridge->samples_per_subframe = 15360; break;
+  case 7680000:  tcp_bridge->samples_per_subframe = 7680; break;
+  }
+
+  /* let's pretend to be a b2x0 */
+  device->type = USRP_B200_DEV;
+
+  device->openair0_cfg=&openair0_cfg[0];
+
+  return 0;
+}
-- 
GitLab