Commit b2326516 authored by Cedric Roux's avatar Cedric Roux

channel_simulator: initial commit

parent 4f55943b
CC=gcc
CFLAGS=-Wall -g -pthread
CFLAGS += -O3 -ffast-math -march=native
PROG=channel_simulator
OBJS=main.o channel_simulator.o connection_manager.o utils.o
$(PROG): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f $(PROG) *.o core
#include "channel_simulator.h"
#include "utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <sys/socket.h>
void init_channel_simulator(channel_simulator *c,
uint32_t samplerate, int n_samples)
{
c->timestamp = 1024; /* timestamps [0..1023] used as commands */
c->samplerate = samplerate;
c->n_samples = n_samples;
c->channels = NULL;
c->channels_count = 0;
c->connections = NULL;
c->connections_count = 0;
}
void cleanup_connections(channel_simulator *c)
{
connection *con;
int i;
/* remove dead connections */
i = 0;
while (i < c->connections_count) {
if (c->connections[i].socket != -1) { i++; continue; }
con = &c->connections[i];
c->channels[con->rx_channel_index].connection_count--;
c->channels[con->tx_channel_index].connection_count--;
free(con->tx_buffer);
if (c->connections_count == 1) {
free(c->connections);
c->connections = NULL;
c->connections_count = 0;
break;
}
c->connections_count--;
memmove(&c->connections[i], &c->connections[i+1],
(c->connections_count-i) * sizeof(connection));
c->connections = realloc(c->connections,
c->connections_count * sizeof(connection));
if (c->connections == NULL) goto oom;
}
/* remove channels with no more connections */
i = 0;
while (i < c->channels_count) {
if (c->channels[i].connection_count) { i++; continue; }
free(c->channels[i].data);
if (c->channels_count == 1) {
free(c->channels);
c->channels = NULL;
c->channels_count = 0;
break;
}
c->channels_count--;
memmove(&c->channels[i], &c->channels[i+1],
(c->channels_count-i) * sizeof(channel));
c->channels = realloc(c->channels, c->channels_count * sizeof(channel));
if (c->channels == NULL) goto oom;
}
return;
oom:
printf("ERROR: cleanup_connections: out of memory\n");
exit(1);
}
static int find_or_create_channel(channel_simulator *c, uint64_t freq)
{
channel *chan;
int i;
for (i = 0; i < c->channels_count; i++)
if ( c->channels[i].frequency == freq) return i;
c->channels_count++;
c->channels = realloc(c->channels, c->channels_count * sizeof(channel));
if (c->channels == NULL) goto oom;
chan = &c->channels[i];
chan->frequency = freq;
chan->data = calloc(1, c->n_samples * 4);
if (chan->data == NULL) goto oom;
chan->connection_count = 0;
return i;
oom:
printf("ERROR: find_or_create_channel: out of memory\n");
exit(1);
}
void channel_simulator_add_connection(channel_simulator *c,
int socket, uint64_t rx_frequency, uint64_t tx_frequency)
{
connection *con;
printf("INFO: new connection RX %"PRIu64" TX %"PRIu64"\n",
rx_frequency, tx_frequency);
c->connections_count++;
c->connections = realloc(c->connections,
c->connections_count * sizeof(connection));
if (c->connections == NULL) goto oom;
con = &c->connections[c->connections_count-1];
con->socket = socket;
con->tx_buffer = calloc(1, c->n_samples * 4);
if (con->tx_buffer == NULL) goto oom;
con->rx_frequency = rx_frequency;
con->tx_frequency = tx_frequency;
con->rx_channel_index = find_or_create_channel(c, rx_frequency);
con->tx_channel_index = find_or_create_channel(c, tx_frequency);
c->channels[con->rx_channel_index].connection_count++;
c->channels[con->tx_channel_index].connection_count++;
return;
oom:
printf("ERROR: channel_simulator_add_connection: out of memory\n");
exit(1);
}
void connection_send_rx(connection *c, uint64_t timestamp,
uint32_t *data, int n_samples)
{
unsigned char b[8+4];
if (c->socket == -1) return;
pu64(b, timestamp);
pu32(b+8, n_samples);
if (fullwrite(c->socket, b, 8+4) != 8+4 ||
fullwrite(c->socket, data, n_samples * 4) != n_samples * 4) {
printf("ERROR: connection_send_rx failed, dropping\n");
shutdown(c->socket, SHUT_RDWR);
close(c->socket);
c->socket = -1;
}
}
void command_set_frequency(channel_simulator *cs, connection *con, int n)
{
unsigned char b[8*2];
uint64_t rx_frequency;
uint64_t tx_frequency;
if (n != 8*2) goto err;
if (fullread(con->socket, b, 8*2) != 8*2) goto err;
rx_frequency = gu64(b);
tx_frequency = gu64(b+8);
printf("INFO: setting new frequencies RX %"PRIu64" and TX %"PRIu64"\n",
rx_frequency, tx_frequency);
cs->channels[con->rx_channel_index].connection_count--;
cs->channels[con->tx_channel_index].connection_count--;
con->rx_frequency = rx_frequency;
con->tx_frequency = tx_frequency;
con->rx_channel_index = find_or_create_channel(cs, rx_frequency);
con->tx_channel_index = find_or_create_channel(cs, tx_frequency);
cs->channels[con->rx_channel_index].connection_count++;
cs->channels[con->tx_channel_index].connection_count++;
return;
err:
printf("ERROR: command_set_frequency failed, dropping\n");
shutdown(con->socket, SHUT_RDWR);
close(con->socket);
con->socket = -1;
}
void do_command(channel_simulator *cs, connection *c, uint64_t command, int n)
{
switch (command) {
case 0: return command_set_frequency(cs, c, n);
default:
printf("ERROR: bad command %"PRIu64", dropping\n", command);
shutdown(c->socket, SHUT_RDWR);
close(c->socket);
c->socket = -1;
}
}
void connection_receive_tx(channel_simulator *cs,
connection *c, uint64_t timestamp, int n_samples)
{
unsigned char b[8+4];
uint64_t recv_timestamp;
uint32_t recv_n_samples;
again:
if (c->socket == -1) return;
if (fullread(c->socket, b, 8+4) != 8+4) goto err;
recv_timestamp = gu64(b);
recv_n_samples = gu32(b+8);
if (recv_timestamp < 1024) {
do_command(cs, c, recv_timestamp, recv_n_samples);
goto again;
}
if (timestamp != recv_timestamp) {
printf("ERROR: bad timestamp, got %"PRIu64" expected %"PRIu64"\n",
recv_timestamp, timestamp);
goto err;
}
if (n_samples != recv_n_samples) {
printf("ERROR, bad n_samples, got %d expected %d\n",
recv_n_samples, n_samples);
goto err;
}
if (fullread(c->socket, c->tx_buffer, n_samples * 4) != n_samples * 4)
goto err;
return;
err:
printf("ERROR: connection_receive_tx failed, dropping\n");
shutdown(c->socket, SHUT_RDWR);
close(c->socket);
c->socket = -1;
}
void channel_simulate(channel_simulator *c)
{
int i;
int k;
connection *con;
channel *chan;
int16_t *to;
int16_t *from;
int32_t mix[c->channels_count][c->n_samples*2];
memset(mix, 0, c->channels_count * c->n_samples*2 * 4);
/* clear channels */
for (i = 0; i < c->channels_count; i++)
memset(c->channels[i].data, 0, c->n_samples * 4);
/* basic mixing */
for (i = 0; i < c->connections_count; i++) {
con = &c->connections[i];
from = (int16_t *)con->tx_buffer;
for (k = 0; k < c->n_samples * 2; k++)
mix[con->tx_channel_index][k] += from[k];
}
for (i = 0; i < c->channels_count; i++) {
chan = &c->channels[i];
to = (int16_t *)chan->data;
for (k = 0; k < c->n_samples * 2; k++) {
int v = mix[i][k];
if (v > 32767) v = 32767;
if (v < -32768) v = -32768;
to[k] = v;
}
}
}
#ifndef _CHANNEL_SIMULATOR_H_
#define _CHANNEL_SIMULATOR_H_
#include <stdint.h>
typedef struct {
uint64_t frequency; /* unit: Hz */
uint32_t *data;
int connection_count;
} channel;
typedef struct {
int socket;
uint32_t *tx_buffer;
uint64_t rx_frequency;
uint64_t tx_frequency;
int rx_channel_index;
int tx_channel_index;
} connection;
typedef struct {
uint64_t timestamp;
uint32_t samplerate;
int n_samples; /* handle n_samples at a time */
channel *channels;
int channels_count;
connection *connections;
int connections_count;
} channel_simulator;
void init_channel_simulator(channel_simulator *c,
uint32_t samplerate, int n_samples);
void cleanup_connections(channel_simulator *c);
void channel_simulator_add_connection(channel_simulator *c,
int socket, uint64_t rx_frequency, uint64_t tx_frequency);
void connection_send_rx(connection *c, uint64_t timestamp,
uint32_t *data, int n_samples);
void connection_receive_tx(channel_simulator *cs,
connection *c, uint64_t timestamp, int n_samples);
void channel_simulate(channel_simulator *c);
#endif /* _CHANNEL_SIMULATOR_H_ */
#include "connection_manager.h"
#include "utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <unistd.h>
typedef struct {
uint64_t rx_frequency;
uint64_t tx_frequency;
uint32_t samplerate;
} init_message;
static int get_init_message(init_message *m, int s)
{
unsigned char b[8*2+4];
if (fullread(s, b, 8*2+4) != 8*2+4) return -1;
m->rx_frequency = gu64(b);
m->tx_frequency = gu64(b+8);
m->samplerate = gu32(b+8*2);
return 0;
}
static void *connection_manager_thread(void *_cm)
{
connection_manager *cm = _cm;
init_message m;
int s;
int t;
s = create_listen_socket(cm->ip, cm->port);
while (1) {
t = socket_accept(s);
if (t == -1) {
printf("ERROR: socket_accept failed (%s)\n", strerror(errno));
continue;
}
if (get_init_message(&m, t) == -1) {
printf("ERROR: get_init_message failed\n");
close(t);
continue;
}
connection_manager_lock(cm);
cm->new_connections++;
cm->c = realloc(cm->c, cm->new_connections * sizeof(new_connection));
if (cm->c == NULL) {
printf("ERROR: get_init_message: out of memory\n");
exit(1);
}
cm->c[cm->new_connections-1].socket = t;
cm->c[cm->new_connections-1].rx_frequency = m.rx_frequency;
cm->c[cm->new_connections-1].tx_frequency = m.tx_frequency;
cm->c[cm->new_connections-1].samplerate = m.samplerate;
lock_signal(&cm->l);
connection_manager_unlock(cm);
}
return NULL;
}
void init_connection_manager(connection_manager *cm, char *listen_ip, int port)
{
cm->ip = strdup(listen_ip);
if (cm->ip == NULL) {
printf("ERROR: init_connection_manager: out of memory\n");
exit(1);
}
cm->port = port;
cm->new_connections = 0;
cm->c = NULL;
init_lock(&cm->l);
new_thread(connection_manager_thread, cm);
}
void connection_manager_lock(connection_manager *cm)
{
lock(&cm->l);
}
void connection_manager_unlock(connection_manager *cm)
{
unlock(&cm->l);
}
/* this function must be called with lock acquired */
void connection_manager_wait_connection(connection_manager *cm)
{
while (cm->new_connections == 0) lock_wait(&cm->l);
}
/* this function must be called with lock acquired */
void connection_manager_clear(connection_manager *cm)
{
free(cm->c);
cm->c = NULL;
cm->new_connections = 0;
}
#ifndef _CONNECTION_MANAGER_H_
#define _CONNECTION_MANAGER_H_
#include <stdint.h>
#include "utils.h"
typedef struct {
int socket;
uint64_t rx_frequency;
uint64_t tx_frequency;
uint32_t samplerate;
} new_connection;
typedef struct {
char *ip;
int port;
volatile int new_connections;
new_connection *c;
lock_t l;
} connection_manager;
void init_connection_manager(connection_manager *cm, char *listen_ip, int port);
void connection_manager_lock(connection_manager *cm);
void connection_manager_unlock(connection_manager *cm);
void connection_manager_wait_connection(connection_manager *cm);
void connection_manager_clear(connection_manager *cm);
#endif /* _CONNECTION_MANAGER_H_ */
#include "channel_simulator.h"
#include "connection_manager.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
int main(void)
{
channel_simulator c;
connection_manager cm;
int i;
int samplerate = 7680000;
init_connection_manager(&cm, "0.0.0.0", 4024);
init_channel_simulator(&c, samplerate, 512);
while (1) {
connection_manager_lock(&cm);
if (c.connections_count == 0) connection_manager_wait_connection(&cm);
if (cm.new_connections) {
for (i = 0; i < cm.new_connections; i++) {
if (cm.c[i].samplerate != samplerate) {
printf("ERROR: new connection has bad samplerate %d, dropping\n",
cm.c[i].samplerate);
shutdown(cm.c[i].socket, SHUT_RDWR);
close(cm.c[i].socket);
continue;
}
channel_simulator_add_connection(&c,
cm.c[i].socket, cm.c[i].rx_frequency, cm.c[i].tx_frequency);
}
connection_manager_clear(&cm);
}
connection_manager_unlock(&cm);
for (i = 0 ; i < c.connections_count; i++) {
connection *con = &c.connections[i];
channel *ch = &c.channels[con->rx_channel_index];
connection_send_rx(con, c.timestamp, ch->data, c.n_samples);
connection_receive_tx(&c, con, c.timestamp + c.n_samples, c.n_samples);
}
cleanup_connections(&c);
c.timestamp += c.n_samples;
channel_simulate(&c);
static int processed = 0;
processed += c.n_samples;
if (processed >= samplerate/1000) {
processed -= samplerate/1000;
usleep(2000);
}
}
return 0;
}
#include "utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
/************************************************************************/
/* lock */
/************************************************************************/
void init_lock(lock_t *l)
{
if (pthread_mutex_init(&l->m, NULL) ||
pthread_cond_init(&l->c, NULL)) {
printf("ERROR: init_lock failed\n");
exit(1);
}
}
void lock(lock_t *l)
{
if (pthread_mutex_lock(&l->m)) {
printf("ERROR: lock failed\n");
exit(1);
}
}
void unlock(lock_t *l)
{
if (pthread_mutex_unlock(&l->m)) {
printf("ERROR: unlock failed\n");
exit(1);
}
}
void lock_wait(lock_t *l)
{
if (pthread_cond_wait(&l->c, &l->m)) {
printf("ERROR: lock_wait failed\n");
exit(1);
}
}
void lock_signal(lock_t *l)
{
if (pthread_cond_broadcast(&l->c)) {
printf("ERROR: lock_signal failed\n");
exit(1);
}
}
/************************************************************************/
/* thread */
/************************************************************************/
void new_thread(void *(*f)(void *), void *data)
{
pthread_t t;
pthread_attr_t att;
if (pthread_attr_init(&att)) goto error;
if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) goto error;
if (pthread_attr_setstacksize(&att, 10000000)) goto error;
if (pthread_create(&t, &att, f, data)) goto error;
if (pthread_attr_destroy(&att)) goto error;
return;
error:
printf("ERROR: new_thread failed\n");
exit(1);
}
/************************************************************************/
/* socket */
/************************************************************************/
#include <netinet/tcp.h>
int create_listen_socket(char *addr, int port)
{
struct sockaddr_in a;
int s;
int v;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) { perror("socket"); exit(1); }
v = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(int)))
{ perror("setsockopt"); exit(1); }
v = 1;
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)) == -1)
{ perror("setsockopt(NODELAY)"); exit(1); }
a.sin_family = AF_INET;
a.sin_port = htons(port);
a.sin_addr.s_addr = inet_addr(addr);
if (bind(s, (struct sockaddr *)&a, sizeof(a))) { perror("bind"); exit(1); }
if (listen(s, 5)) { perror("listen"); exit(1); }
return s;
}
int socket_accept(int s)
{
struct sockaddr_in a;
socklen_t alen;
alen = sizeof(a);
return accept(s, (struct sockaddr *)&a, &alen);
}
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;
}
uint32_t gu32(unsigned char *x)
{
return (uint32_t)x[0] |
(((uint32_t)x[1]) << 8) |
(((uint32_t)x[2]) << 16) |
(((uint32_t)x[3]) << 24);
}
uint64_t gu64(unsigned char *x)
{
return (uint64_t)x[0] |
(((uint64_t)x[1]) << 8) |
(((uint64_t)x[2]) << 16) |
(((uint64_t)x[3]) << 24) |
(((uint64_t)x[4]) << 32) |
(((uint64_t)x[5]) << 40) |
(((uint64_t)x[6]) << 48) |
(((uint64_t)x[7]) << 56);
}
void pu32(unsigned char *x, uint32_t v)
{
x[0] = v & 255;
x[1] = (v >> 8) & 255;
x[2] = (v >> 16) & 255;
x[3] = (v >> 24) & 255;
}
void pu64(unsigned char *x, uint64_t v)
{
x[0] = v & 255;
x[1] = (v >> 8) & 255;
x[2] = (v >> 16) & 255;
x[3] = (v >> 24) & 255;
x[4] = (v >> 32) & 255;
x[5] = (v >> 40) & 255;
x[6] = (v >> 48) & 255;
x[7] = (v >> 56) & 255;
}
#ifndef _UTILS_H_
#define _UTILS_H_
#include <stdint.h>
#include <pthread.h>
typedef struct {
pthread_mutex_t m;
pthread_cond_t c;
} lock_t;
void init_lock(lock_t *l);
void lock(lock_t *l);
void unlock(lock_t *l);
void lock_wait(lock_t *l);
void lock_signal(lock_t *l);
void new_thread(void *(*f)(void *), void *data);
int create_listen_socket(char *addr, int port);
int socket_accept(int s);
int fullread(int fd, void *buf, int count);
int fullwrite(int fd, void *buf, int count);
uint32_t gu32(unsigned char *x);
uint64_t gu64(unsigned char *x);
void pu32(unsigned char *x, uint32_t v);
void pu64(unsigned char *x, uint64_t v);
#endif /* _UTILS_H_ */
......@@ -604,6 +604,16 @@ set(HWLIB_TCP_BRIDGE_OAI_SOURCE
add_library(tcp_bridge_oai MODULE ${HWLIB_TCP_BRIDGE_OAI_SOURCE} )
set_target_properties(tcp_bridge_oai PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
# channel simulator bridge library
######################################################################
set(HWLIB_CHANNEL_SIMULATOR_SOURCE
${OPENAIR_TARGETS}/ARCH/tcp_bridge/channel_simulator.c
${OPENAIR_DIR}/channel_simulator/utils.c
)
add_library(channel_simulator MODULE ${HWLIB_CHANNEL_SIMULATOR_SOURCE} )
set_target_properties(channel_simulator PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
##########################################################
include_directories ("${OPENAIR_TARGETS}/ARCH/COMMON")
......
#include "common_lib.h"
#include "channel_simulator/utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <inttypes.h>
typedef struct buffer_s {
uint64_t timestamp;
int n_samples;
int used_samples; /* for TX to check correct use of buffer */
void *b;
struct buffer_s *next;
} buffer_t;
typedef struct {
int sock;
int samples_per_subframe;
uint64_t rx_frequency;
uint64_t tx_frequency;
lock_t lock;
buffer_t * volatile rx_head;
buffer_t *rx_last;
buffer_t *tx_head;
buffer_t *tx_last;
volatile int first_rx_ok;
uint64_t rx_next_timestamp;
lock_t tx_lock;
} channel_simulator_state_t;
void add_rx_buffer(channel_simulator_state_t *c, buffer_t *b)
{
lock(&c->lock);
if (c->rx_head == NULL) {
c->rx_head = b;
} else {
c->rx_last->next = b;
}
c->rx_last = b;
lock_signal(&c->lock);
unlock(&c->lock);
}
void add_tx_buffer(channel_simulator_state_t *c, buffer_t *b)
{
lock(&c->lock);
if (c->tx_head == NULL) {
c->tx_head = b;
} else {
c->tx_last->next = b;
}
c->tx_last = b;
lock_signal(&c->lock);
unlock(&c->lock);
}
uint32_t get_rx_sample(channel_simulator_state_t *c, uint64_t timestamp)
{
uint32_t *b;
uint32_t ret;
lock(&c->lock);
again:
while (c->rx_head == NULL) lock_wait(&c->lock);
if (c->rx_head->timestamp + c->rx_head->n_samples <= timestamp) {
buffer_t *cur = c->rx_head;
c->rx_head = cur->next;
if (c->rx_head == NULL) {
c->rx_last = NULL;
}
free(cur->b);
free(cur);
goto again;
}
if (timestamp < c->rx_head->timestamp) {
printf("ERROR: channel_simulator: get_rx_sample failure\n");
exit(1);
}
b = c->rx_head->b;
ret = b[timestamp - c->rx_head->timestamp];
unlock(&c->lock);
return ret;
}
uint32_t get_tx_sample(channel_simulator_state_t *c, uint64_t timestamp)
{
buffer_t *cur;
uint32_t ret;
lock(&c->lock);
again:
if (c->tx_head == NULL) { ret = 0; goto done; }
if (c->tx_head->timestamp + c->tx_head->n_samples <= timestamp) {
cur = c->tx_head;
c->tx_head = cur->next;
if (c->tx_head == NULL) c->tx_last = NULL;
if (cur->used_samples != cur->n_samples) {
printf("ERROR: channel_simulator: get_tx_sample: late packet "
"timestamp %"PRIu64" n_samples %d used_samples %d\n",
cur->timestamp, cur->n_samples, cur->used_samples);
}
free(cur->b);
free(cur);
goto again;
}
cur = c->tx_head;
ret = 0;
while (cur) {
if (timestamp >= cur->timestamp &&
timestamp < cur->timestamp + cur->n_samples) {
uint32_t *b = cur->b;
ret = b[timestamp - cur->timestamp];
cur->used_samples++;
break;
}
cur = cur->next;
}
done:
unlock(&c->lock);
return ret;
}
void *rx_thread(void *_c)
{
channel_simulator_state_t *c = _c;
unsigned char b[8+4];
buffer_t *rx;
uint32_t *out = NULL;
int out_size = 0;
uint64_t timestamp;
int n_samples;
int i;
while (1) {
if (fullread(c->sock, b, 8+4) != 8+4) goto err;
rx = calloc(1, sizeof(buffer_t)); if (rx == NULL) goto err;
timestamp = rx->timestamp = gu64(b);
n_samples = rx->n_samples = gu32(b+8);
rx->b = malloc(rx->n_samples * 4); if (rx->b == NULL) goto err;
rx->next = NULL;
if (fullread(c->sock, rx->b, rx->n_samples * 4) != rx->n_samples * 4)
goto err;
add_rx_buffer(c, rx);
lock(&c->lock);
if (c->first_rx_ok == 0) {
c->rx_next_timestamp = timestamp;
c->first_rx_ok = 1;
lock_signal(&c->lock);
}
unlock(&c->lock);
if (out_size < n_samples) {
free(out);
out = malloc(n_samples * 4);
if (out == NULL) goto err;
out_size = n_samples;
}
for (i = 0; i < n_samples; i++)
out[i] = get_tx_sample(c, timestamp + n_samples + i);
pu64(b, timestamp + n_samples);
pu32(b+8, n_samples);
lock(&c->tx_lock);
if (fullwrite(c->sock, b, 8+4) != 8+4 ||
fullwrite(c->sock, out, n_samples * 4) != n_samples * 4) {
unlock(&c->tx_lock);
goto err;
}
unlock(&c->tx_lock);
}
return NULL;
err:
printf("ERROR: channel_simulator: rx_thread failed\n");
exit(1);
}
void init_connection(channel_simulator_state_t *c)
{
unsigned char b[8*2+4];
pu64(b, c->rx_frequency);
pu64(b+8, c->tx_frequency);
pu32(b+8*2, c->samples_per_subframe * 1000);
lock(&c->tx_lock);
if (fullwrite(c->sock, b, 8*2+4) != 8*2+4) {
printf("ERROR: channel_simulator: init_connection failed\n");
exit(1);
}
unlock(&c->tx_lock);
}
int channel_simulator_start(openair0_device *device)
{
int port = 4024;
char *ip = "127.0.0.1";
char *env;
channel_simulator_state_t *channel_simulator = device->priv;
struct sockaddr_in addr;
int v;
int sock;
env = getenv("CHANNEL_SIMULATOR_IP");
if (env != NULL)
ip = env;
else
printf("channel_simulator: environment variable CHANNEL_SIMULATOR_IP"
" not found, using default IP %s\n", ip);
env = getenv("CHANNEL_SIMULATOR_PORT");
if (env != NULL)
port = atoi(env);
else
printf("channel_simulator: environment variable CHANNEL_SIMULATOR_PORT"
" not found, using default port %d\n", port);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) { perror("channel_simulator: socket"); exit(1); }
v = 1;
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)) == -1)
{ perror("channel_simulator: setsockopt(NODELAY)"); exit(1); }
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip);
while (1) {
printf("channel_simulator: trying to connect to %s:%d\n", ip, port);
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
printf("channel_simulator: connection established\n");
channel_simulator->sock = sock;
init_connection(channel_simulator);
new_thread(rx_thread, channel_simulator);
return 0;
}
perror("channel_simulator");
sleep(1);
}
}
int channel_simulator_request(openair0_device *device, void *msg, ssize_t msg_len) { abort(); return 0; }
int channel_simulator_reply(openair0_device *device, void *msg, ssize_t msg_len) { abort(); return 0; }
int channel_simulator_get_stats(openair0_device* device) { return 0; }
int channel_simulator_reset_stats(openair0_device* device) { return 0; }
void channel_simulator_end(openair0_device *device) {}
int channel_simulator_stop(openair0_device *device) { return 0; }
int channel_simulator_set_gains(openair0_device* device, openair0_config_t *openair0_cfg) { return 0; }
int channel_simulator_set_freq(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config)
{
channel_simulator_state_t *c = device->priv;
unsigned char b[8+4+8*2];
pu64(b, 0);
pu32(b+8, 8*2);
pu64(b+8+4, openair0_cfg[0].rx_freq[0]);
pu64(b+8+4+8, openair0_cfg[0].tx_freq[0]);
lock(&c->tx_lock);
if (fullwrite(c->sock, b, 8+4+8*2) != 8+4+8*2) {
printf("ERROR: channel_simulator: channel_simulator_set_freq failed\n");
exit(1);
}
unlock(&c->tx_lock);
return 0;
}
int channel_simulator_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags)
{
channel_simulator_state_t *c = device->priv;
buffer_t *tx;
//printf("channel_simulator_write start ts %"PRIu64" nsamps %d\n", (uint64_t)timestamp, nsamps);
if (cc != 1)
{ printf("ERROR: channel_simulator: only works with 1 CC\n"); exit(1); }
tx = calloc(1, sizeof(buffer_t)); if (tx == NULL) goto err;
tx->timestamp = timestamp;
tx->n_samples = nsamps;
tx->used_samples = 0;
tx->b = malloc(nsamps * 4); if (tx->b == NULL) goto err;
memcpy(tx->b, buff[0], nsamps * 4);
tx->next = NULL;
add_tx_buffer(c, tx);
//printf("channel_simulator_write done\n");
return nsamps;
err:
printf("ERROR: channel_simulator: channel_simulator_write failed\n");
exit(1);
}
uint64_t get_rx_timestamp(channel_simulator_state_t *c)
{
uint64_t ret;
lock(&c->lock);
while (!c->first_rx_ok) lock_wait(&c->lock);
ret = c->rx_next_timestamp;
unlock(&c->lock);
return ret;
}
int channel_simulator_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc)
{
//printf("channel_simulator_read start nsamps %d\n", nsamps);
channel_simulator_state_t *c = device->priv;
uint32_t *r = (uint32_t *)(buff[0]);
uint64_t ts = get_rx_timestamp(c);
int i;
for (i = 0; i < nsamps; i++) r[i] = get_rx_sample(c, ts + i);
lock(&c->lock);
c->rx_next_timestamp += nsamps;
unlock(&c->lock);
*timestamp = ts;
//printf("channel_simulator_read done ts %"PRIu64"\n", ts);
return nsamps;
}
__attribute__((__visibility__("default")))
int device_init(openair0_device* device, openair0_config_t *openair0_cfg)
{
channel_simulator_state_t *channel_simulator = (channel_simulator_state_t*)malloc(sizeof(channel_simulator_state_t));
memset(channel_simulator, 0, sizeof(channel_simulator_state_t));
/* only 25, 50 or 100 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("channel_simulator: ERROR: only 25, 50 or 100 PRBs supported\n");
exit(1);
}
device->trx_start_func = channel_simulator_start;
device->trx_get_stats_func = channel_simulator_get_stats;
device->trx_reset_stats_func = channel_simulator_reset_stats;
device->trx_end_func = channel_simulator_end;
device->trx_stop_func = channel_simulator_stop;
device->trx_set_freq_func = channel_simulator_set_freq;
device->trx_set_gains_func = channel_simulator_set_gains;
device->trx_write_func = channel_simulator_write;
device->trx_read_func = channel_simulator_read;
device->priv = channel_simulator;
switch ((int)openair0_cfg[0].sample_rate) {
case 30720000: channel_simulator->samples_per_subframe = 30720; break;
case 15360000: channel_simulator->samples_per_subframe = 15360; break;
case 7680000: channel_simulator->samples_per_subframe = 7680; break;
}
init_lock(&channel_simulator->lock);
init_lock(&channel_simulator->tx_lock);
channel_simulator->rx_frequency = openair0_cfg[0].rx_freq[0];
channel_simulator->tx_frequency = openair0_cfg[0].tx_freq[0];
/* let's pretend to be a b2x0 */
device->type = USRP_B200_DEV;
device->openair0_cfg=&openair0_cfg[0];
return 0;
}
......@@ -495,7 +495,7 @@ static void *UE_thread_synch(void *arg) {
for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) {
openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = UE->frame_parms.dl_CarrierFreq;
openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = UE->frame_parms.ul_CarrierFreq;
openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = UE->frame_parms.dl_CarrierFreq + uplink_frequency_offset[CC_id][0];
openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1;
if (uplink_frequency_offset[CC_id][i] != 0) //
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment