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 ...@@ -604,6 +604,16 @@ set(HWLIB_TCP_BRIDGE_OAI_SOURCE
add_library(tcp_bridge_oai MODULE ${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") 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_directories ("${OPENAIR_TARGETS}/ARCH/COMMON")
......
This diff is collapsed.
...@@ -495,7 +495,7 @@ static void *UE_thread_synch(void *arg) { ...@@ -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++) { 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].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; openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1;
if (uplink_frequency_offset[CC_id][i] != 0) // 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