add debugging tool tcp_bridge
internal use, no documentation, no support.
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user