Merge remote-tracking branch 'origin/issue386_tcpbrige_remoteconnection' into develop_integration_2019_w03
This commit is contained in:
@@ -8,33 +8,47 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
int fullread(int fd, void *_buf, int count)
|
const int port = 4043;
|
||||||
{
|
#define helpTxt "\
|
||||||
|
\x1b[31m\
|
||||||
|
tcp_bridge: error: you have to run one UE and one eNB\n\
|
||||||
|
For this, export TCPBRIDGE=enb (eNB case) or \n\
|
||||||
|
TCPBRIDGE=<an ip address> (UE case)\n\
|
||||||
|
\x1b[m"
|
||||||
|
|
||||||
|
int fullread(int fd, void *_buf, int count) {
|
||||||
char *buf = _buf;
|
char *buf = _buf;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
while (count) {
|
while (count) {
|
||||||
l = read(fd, buf, count);
|
l = read(fd, buf, count);
|
||||||
|
|
||||||
if (l <= 0) return -1;
|
if (l <= 0) return -1;
|
||||||
|
|
||||||
count -= l;
|
count -= l;
|
||||||
buf += l;
|
buf += l;
|
||||||
ret += l;
|
ret += l;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fullwrite(int fd, void *_buf, int count)
|
int fullwrite(int fd, void *_buf, int count) {
|
||||||
{
|
|
||||||
char *buf = _buf;
|
char *buf = _buf;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
while (count) {
|
while (count) {
|
||||||
l = write(fd, buf, count);
|
l = write(fd, buf, count);
|
||||||
|
|
||||||
if (l <= 0) return -1;
|
if (l <= 0) return -1;
|
||||||
|
|
||||||
count -= l;
|
count -= l;
|
||||||
buf += l;
|
buf += l;
|
||||||
ret += l;
|
ret += l;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,157 +58,188 @@ typedef struct {
|
|||||||
int sock;
|
int sock;
|
||||||
int samples_per_subframe;
|
int samples_per_subframe;
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
uint64_t next_tx_timestamp;
|
|
||||||
int is_enb;
|
int is_enb;
|
||||||
|
char *ip;
|
||||||
} tcp_bridge_state_t;
|
} tcp_bridge_state_t;
|
||||||
|
|
||||||
void verify_connection(int fd, int is_enb)
|
void verify_connection(int fd, int is_enb) {
|
||||||
{
|
|
||||||
char c = is_enb;
|
char c = is_enb;
|
||||||
|
|
||||||
if (fullwrite(fd, &c, 1) != 1) exit(1);
|
if (fullwrite(fd, &c, 1) != 1) exit(1);
|
||||||
|
|
||||||
if (fullread(fd, &c, 1) != 1) exit(1);
|
if (fullread(fd, &c, 1) != 1) exit(1);
|
||||||
|
|
||||||
if (c == is_enb) {
|
if (c == is_enb) {
|
||||||
printf("\x1b[31mtcp_bridge: error: you have to run one UE and one eNB"
|
printf(helpTxt);
|
||||||
" (did you run 'export ENODEB=1' in the eNB terminal?)\x1b[m\n");
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int tcp_bridge_start(openair0_device *device)
|
|
||||||
{
|
|
||||||
int port = 4043;
|
|
||||||
tcp_bridge_state_t *tcp_bridge = device->priv;
|
|
||||||
int try;
|
|
||||||
int max_try = 5;
|
|
||||||
|
|
||||||
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); }
|
|
||||||
|
|
||||||
|
int start_enb(tcp_bridge_state_t *tcp_bridge) {
|
||||||
struct sockaddr_in addr = {
|
struct sockaddr_in addr = {
|
||||||
sin_family: AF_INET,
|
sin_family:
|
||||||
sin_port: htons(port),
|
AF_INET,
|
||||||
sin_addr: { s_addr: INADDR_ANY }
|
sin_port:
|
||||||
|
htons(port),
|
||||||
|
sin_addr:
|
||||||
|
{ s_addr: INADDR_ANY }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
|
if (bind(tcp_bridge->sock, (struct sockaddr *)&addr, sizeof(addr))) {
|
||||||
if (errno == EADDRINUSE) goto client_mode;
|
perror("tcp_bridge: bind");
|
||||||
{ perror("tcp_bridge: bind"); exit(1); }
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(sock, 5))
|
if (listen(tcp_bridge->sock, 5)) {
|
||||||
{ perror("tcp_bridge: listen"); exit(1); }
|
perror("tcp_bridge: listen");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
printf("tcp_bridge: wait for connection on port %d\n", port);
|
printf("tcp_bridge: wait for connection on port %d\n", port);
|
||||||
|
|
||||||
socklen_t len = sizeof(addr);
|
socklen_t len = sizeof(addr);
|
||||||
int sock2 = accept(sock, (struct sockaddr *)&addr, &len);
|
int sockServ = accept(tcp_bridge->sock, (struct sockaddr *)&addr, &len);
|
||||||
if (sock2 == -1)
|
|
||||||
{ perror("tcp_bridge: accept"); exit(1); }
|
|
||||||
|
|
||||||
close(sock);
|
if ( sockServ == -1) {
|
||||||
|
perror("tcp_bridge: accept");
|
||||||
tcp_bridge->sock = sock2;
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_connection(sockServ, tcp_bridge->is_enb);
|
||||||
printf("tcp_bridge: connection established\n");
|
printf("tcp_bridge: connection established\n");
|
||||||
|
close(tcp_bridge->sock);
|
||||||
verify_connection(sock2, tcp_bridge->is_enb);
|
tcp_bridge->sock=sockServ;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
client_mode:
|
int start_ue(tcp_bridge_state_t *tcp_bridge) {
|
||||||
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
struct sockaddr_in addr = {sin_family:
|
||||||
|
AF_INET,
|
||||||
|
sin_port:
|
||||||
|
htons(port),
|
||||||
|
sin_addr:
|
||||||
|
{ s_addr: INADDR_ANY }
|
||||||
|
};
|
||||||
|
addr.sin_addr.s_addr = inet_addr(tcp_bridge->ip);
|
||||||
|
|
||||||
for (try = 0; try < max_try; try++) {
|
while(1) {
|
||||||
if (try != 0) sleep(1);
|
printf("tcp_bridge: trying to connect to %s:%d\n", tcp_bridge->ip, port);
|
||||||
|
|
||||||
printf("tcp_bridge: trying to connect to 127.0.0.1:%d (attempt %d/%d)\n",
|
if (connect(tcp_bridge->sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
|
||||||
port, try+1, max_try);
|
verify_connection(tcp_bridge->sock, tcp_bridge->is_enb);
|
||||||
|
|
||||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
|
|
||||||
printf("tcp_bridge: connection established\n");
|
printf("tcp_bridge: connection established\n");
|
||||||
tcp_bridge->sock = sock;
|
|
||||||
verify_connection(sock, tcp_bridge->is_enb);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
perror("tcp_bridge");
|
perror("tcp_bridge");
|
||||||
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("tcp_bridge: connection failed\n");
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcp_bridge_start(openair0_device *device) {
|
||||||
|
tcp_bridge_state_t *tcp_bridge = device->priv;
|
||||||
|
tcp_bridge->sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
if (tcp_bridge->sock == -1) {
|
||||||
|
perror("tcp_bridge: socket");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int tcp_bridge_request(openair0_device *device, void *msg, ssize_t msg_len) { abort(); return 0; }
|
int enable = 1;
|
||||||
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)
|
if (setsockopt(tcp_bridge->sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))) {
|
||||||
{
|
perror("tcp_bridge: SO_REUSEADDR");
|
||||||
if (cc != 1) { printf("tcp_bridge: only 1 antenna supported\n"); exit(1); }
|
exit(1);
|
||||||
tcp_bridge_state_t *t = device->priv;
|
}
|
||||||
/* deal with discontinuities in output (think: eNB in TDD mode) */
|
|
||||||
if (t->next_tx_timestamp && timestamp != t->next_tx_timestamp) {
|
if ( tcp_bridge->is_enb )
|
||||||
uint32_t b[4096];
|
return start_enb(tcp_bridge);
|
||||||
uint64_t to_send = timestamp - t->next_tx_timestamp;
|
else
|
||||||
memset(b, 0, 4096 * sizeof(uint32_t));
|
return start_ue(tcp_bridge);
|
||||||
while (to_send) {
|
}
|
||||||
int len = to_send > 4096 ? 4096 : to_send;
|
|
||||||
int n = fullwrite(t->sock, b, len * 4);
|
int tcp_bridge_request(openair0_device *device, void *msg, ssize_t msg_len) {
|
||||||
if (n != len * 4) {
|
|
||||||
printf("tcp_bridge: write error ret %d error %s\n", n, strerror(errno));
|
|
||||||
abort();
|
abort();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
to_send -= len;
|
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) {
|
||||||
|
if (cc != 1) {
|
||||||
|
printf("tcp_bridge: only 1 antenna supported\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_bridge_state_t *t = device->priv;
|
||||||
int n = fullwrite(t->sock, buff[0], nsamps * 4);
|
int n = fullwrite(t->sock, buff[0], nsamps * 4);
|
||||||
|
|
||||||
if (n != nsamps * 4) {
|
if (n != nsamps * 4) {
|
||||||
printf("tcp_bridge: write error ret %d (wanted %d) error %s\n", n, nsamps*4, strerror(errno));
|
printf("tcp_bridge: write error ret %d (wanted %d) error %s\n", n, nsamps*4, strerror(errno));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
t->next_tx_timestamp = timestamp + nsamps;
|
|
||||||
return nsamps;
|
return nsamps;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tcp_bridge_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc)
|
int tcp_bridge_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
|
||||||
{
|
if (cc != 1) {
|
||||||
if (cc != 1) { printf("tcp_bridge: only 1 antenna supported\n"); exit(1); }
|
printf("tcp_bridge: only 1 antenna supported\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
tcp_bridge_state_t *t = device->priv;
|
tcp_bridge_state_t *t = device->priv;
|
||||||
int n = fullread(t->sock, buff[0], nsamps * 4);
|
int n = fullread(t->sock, buff[0], nsamps * 4);
|
||||||
|
|
||||||
if (n != nsamps * 4) {
|
if (n != nsamps * 4) {
|
||||||
printf("tcp_bridge: read error ret %d nsamps*4 %d error %s\n", n, nsamps * 4, strerror(errno));
|
printf("tcp_bridge: read error ret %d nsamps*4 %d error %s\n", n, nsamps * 4, strerror(errno));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
*timestamp = t->timestamp;
|
*timestamp = t->timestamp;
|
||||||
t->timestamp += nsamps;
|
t->timestamp += nsamps;
|
||||||
return nsamps;
|
return nsamps;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tcp_bridge_read_ue(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc)
|
int tcp_bridge_read_ue(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
|
||||||
{
|
if (cc != 1) {
|
||||||
if (cc != 1) { printf("tcp_bridge: only 1 antenna supported\n"); exit(1); }
|
printf("tcp_bridge: only 1 antenna supported\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
tcp_bridge_state_t *t = device->priv;
|
tcp_bridge_state_t *t = device->priv;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
/* In synch mode, UE does not write, but we need to
|
/* In synch mode, UE does not write, but we need to
|
||||||
* send something to the eNodeB.
|
send something to the eNodeB.
|
||||||
* We know that UE is in synch mode when it reads
|
We know that UE is in synch mode when it reads
|
||||||
* 10 subframes at a time.
|
10 subframes at a time.
|
||||||
*/
|
*/
|
||||||
if (nsamps == t->samples_per_subframe * 10) {
|
if (nsamps == t->samples_per_subframe * 10) {
|
||||||
uint32_t b[nsamps];
|
uint32_t b[nsamps];
|
||||||
memset(b, 0, nsamps * 4);
|
memset(b, 0, nsamps * 4);
|
||||||
n = fullwrite(t->sock, b, nsamps * 4);
|
n = fullwrite(t->sock, b, nsamps * 4);
|
||||||
|
|
||||||
if (n != nsamps * 4) {
|
if (n != nsamps * 4) {
|
||||||
printf("tcp_bridge: write error ret %d error %s\n", n, strerror(errno));
|
printf("tcp_bridge: write error ret %d error %s\n", n, strerror(errno));
|
||||||
abort();
|
abort();
|
||||||
@@ -205,96 +250,106 @@ int tcp_bridge_read_ue(openair0_device *device, openair0_timestamp *timestamp, v
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* To startup proper communcation between eNB and UE,
|
/* To startup proper communcation between eNB and UE,
|
||||||
* we need to understand that:
|
we need to understand that:
|
||||||
* - eNodeB starts reading subframe 0
|
- eNodeB starts reading subframe 0
|
||||||
* - then eNodeB starts sending subframe 4
|
- then eNodeB starts sending subframe 4
|
||||||
* and then repeats read/write for each subframe.
|
and then repeats read/write for each subframe.
|
||||||
* The UE:
|
The UE:
|
||||||
* - reads 10 subframes at a time until it is synchronized
|
- reads 10 subframes at a time until it is synchronized
|
||||||
* - then reads subframe n and writes subframe n+2
|
- then reads subframe n and writes subframe n+2
|
||||||
* We also want to enforce that the subframe 0 is read
|
We also want to enforce that the subframe 0 is read
|
||||||
* at the beginning of the UE RX buffer, not in the middle
|
at the beginning of the UE RX buffer, not in the middle
|
||||||
* of it.
|
of it.
|
||||||
* So it means:
|
So it means:
|
||||||
* - for the eNodeB: let it run as in normal mode (as with a B210)
|
- for the eNodeB: let it run as in normal mode (as with a B210)
|
||||||
* - for the UE, on its very first read:
|
- for the UE, on its very first read:
|
||||||
* - we want this read to get data from subframe 0
|
- we want this read to get data from subframe 0
|
||||||
* but the first write of eNodeB is subframe 4
|
but the first write of eNodeB is subframe 4
|
||||||
* so we first need to read and ignore 6 subframes
|
so we first need to read and ignore 6 subframes
|
||||||
* - the UE will start its TX only at the subframe 2
|
- the UE will start its TX only at the subframe 2
|
||||||
* corresponding to the subframe 0 it just read,
|
corresponding to the subframe 0 it just read,
|
||||||
* so we need to write 12 subframes before anything
|
so we need to write 12 subframes before anything
|
||||||
* (the function tcp_bridge_read_ue takes care to
|
(the function tcp_bridge_read_ue takes care to
|
||||||
* insert dummy TX data during the synch phase)
|
insert dummy TX data during the synch phase)
|
||||||
*
|
|
||||||
* Here is a drawing of the beginning of things to make
|
|
||||||
* this logic clearer.
|
|
||||||
*
|
|
||||||
* We see that eNB starts RX at subframe 0, starts TX at subfram 4,
|
|
||||||
* and that UE starts RX at subframe 10 and TX at subframe 12.
|
|
||||||
*
|
|
||||||
* We understand that the UE has to transmit 12 empty
|
|
||||||
* subframes for the eNodeB to start its processing.
|
|
||||||
*
|
|
||||||
* And because the eNodeB starts its TX at subframe 4 and we
|
|
||||||
* want the UE to start its RX at subframe 10, we need to
|
|
||||||
* read and ignore 6 subframes in the UE.
|
|
||||||
*
|
|
||||||
* -------------------------------------------------------------------------
|
|
||||||
* eNB RX: | *0* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 ...
|
|
||||||
* -------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* -------------------------------------------------------------------------
|
|
||||||
* eNB TX: | 0 | 1 | 2 | 3 | *4* | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 ...
|
|
||||||
* -------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* -------------------------------------------------------------------------
|
|
||||||
* UE RX: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | *10* | 11 | 12 | 13 | 14 ...
|
|
||||||
* -------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* -------------------------------------------------------------------------
|
|
||||||
* UE TX: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | *12* | 13 | 14 ...
|
|
||||||
* -------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* As a final note, we do TX before RX to ensure that the eNB will
|
|
||||||
* get some data and send us something so there is no deadlock
|
|
||||||
* at the beginning of things. Hopefully the kernel buffers for
|
|
||||||
* the sockets are big enough so that the first (big) TX can
|
|
||||||
* return to user mode before the buffers are full. If this
|
|
||||||
* is wrong in some environment, we will need to work by smaller
|
|
||||||
* units of data at a time.
|
|
||||||
*/
|
|
||||||
int tcp_bridge_ue_first_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc)
|
|
||||||
{
|
|
||||||
if (cc != 1) { printf("tcp_bridge: only 1 antenna supported\n"); exit(1); }
|
|
||||||
tcp_bridge_state_t *t = device->priv;
|
|
||||||
|
|
||||||
|
Here is a drawing of the beginning of things to make
|
||||||
|
this logic clearer.
|
||||||
|
|
||||||
|
We see that eNB starts RX at subframe 0, starts TX at subfram 4,
|
||||||
|
and that UE starts RX at subframe 10 and TX at subframe 12.
|
||||||
|
|
||||||
|
We understand that the UE has to transmit 12 empty
|
||||||
|
subframes for the eNodeB to start its processing.
|
||||||
|
|
||||||
|
And because the eNodeB starts its TX at subframe 4 and we
|
||||||
|
want the UE to start its RX at subframe 10, we need to
|
||||||
|
read and ignore 6 subframes in the UE.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
eNB RX: | *0* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 ...
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
eNB TX: | 0 | 1 | 2 | 3 | *4* | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 ...
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
UE RX: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | *10* | 11 | 12 | 13 | 14 ...
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
UE TX: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | *12* | 13 | 14 ...
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
As a final note, we do TX before RX to ensure that the eNB will
|
||||||
|
get some data and send us something so there is no deadlock
|
||||||
|
at the beginning of things. Hopefully the kernel buffers for
|
||||||
|
the sockets are big enough so that the first (big) TX can
|
||||||
|
return to user mode before the buffers are full. If this
|
||||||
|
is wrong in some environment, we will need to work by smaller
|
||||||
|
units of data at a time.
|
||||||
|
*/
|
||||||
|
int tcp_bridge_ue_first_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
|
||||||
|
if (cc != 1) {
|
||||||
|
printf("tcp_bridge: only 1 antenna supported\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_bridge_state_t *t = device->priv;
|
||||||
uint32_t b[t->samples_per_subframe * 12];
|
uint32_t b[t->samples_per_subframe * 12];
|
||||||
memset(b, 0, t->samples_per_subframe * 12 * 4);
|
memset(b, 0, t->samples_per_subframe * 12 * 4);
|
||||||
int n = fullwrite(t->sock, b, t->samples_per_subframe * 12 * 4);
|
int n = fullwrite(t->sock, b, t->samples_per_subframe * 12 * 4);
|
||||||
|
|
||||||
if (n != t->samples_per_subframe * 12 * 4) {
|
if (n != t->samples_per_subframe * 12 * 4) {
|
||||||
printf("tcp_bridge: write error ret %d error %s\n", n, strerror(errno));
|
printf("tcp_bridge: write error ret %d error %s\n", n, strerror(errno));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
n = fullread(t->sock, b, t->samples_per_subframe * 6 * 4);
|
n = fullread(t->sock, b, t->samples_per_subframe * 6 * 4);
|
||||||
|
|
||||||
if (n != t->samples_per_subframe * 6 * 4) {
|
if (n != t->samples_per_subframe * 6 * 4) {
|
||||||
printf("tcp_bridge: read error ret %d error %s\n", n, strerror(errno));
|
printf("tcp_bridge: read error ret %d error %s\n", n, strerror(errno));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
device->trx_read_func = tcp_bridge_read_ue;
|
device->trx_read_func = tcp_bridge_read_ue;
|
||||||
|
|
||||||
return tcp_bridge_read_ue(device, timestamp, buff, nsamps, cc);
|
return tcp_bridge_read_ue(device, timestamp, buff, nsamps, cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((__visibility__("default")))
|
__attribute__((__visibility__("default")))
|
||||||
int device_init(openair0_device* device, openair0_config_t *openair0_cfg)
|
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||||
{
|
tcp_bridge_state_t *tcp_bridge = (tcp_bridge_state_t *)calloc(sizeof(tcp_bridge_state_t),1);
|
||||||
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));
|
|
||||||
|
|
||||||
tcp_bridge->is_enb = getenv("ENODEB") != NULL;
|
if ((tcp_bridge->ip=getenv("TCPBRIDGE")) == NULL ) {
|
||||||
|
/* for compatibility, we test the ENB environment variable */
|
||||||
|
if ((tcp_bridge->ip=getenv("ENODEB")) != NULL ) {
|
||||||
|
tcp_bridge->ip=strdup("enb");
|
||||||
|
} else {
|
||||||
|
tcp_bridge->ip=strdup("127.0.0.1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_bridge->is_enb = strncasecmp(tcp_bridge->ip,"enb",3) == 0;
|
||||||
printf("tcp_bridge: running as %s\n", tcp_bridge->is_enb ? "eNB" : "UE");
|
printf("tcp_bridge: running as %s\n", tcp_bridge->is_enb ? "eNB" : "UE");
|
||||||
|
|
||||||
/* only 25, 50 or 100 PRBs handled for the moment */
|
/* only 25, 50 or 100 PRBs handled for the moment */
|
||||||
@@ -323,15 +378,21 @@ int device_init(openair0_device* device, openair0_config_t *openair0_cfg)
|
|||||||
device->priv = tcp_bridge;
|
device->priv = tcp_bridge;
|
||||||
|
|
||||||
switch ((int)openair0_cfg[0].sample_rate) {
|
switch ((int)openair0_cfg[0].sample_rate) {
|
||||||
case 30720000: tcp_bridge->samples_per_subframe = 30720; break;
|
case 30720000:
|
||||||
case 15360000: tcp_bridge->samples_per_subframe = 15360; break;
|
tcp_bridge->samples_per_subframe = 30720;
|
||||||
case 7680000: tcp_bridge->samples_per_subframe = 7680; break;
|
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 */
|
/* let's pretend to be a b2x0 */
|
||||||
device->type = USRP_B200_DEV;
|
device->type = USRP_B200_DEV;
|
||||||
|
|
||||||
device->openair0_cfg=&openair0_cfg[0];
|
device->openair0_cfg=&openair0_cfg[0];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user