Commit e793a677 authored by Cedric Roux's avatar Cedric Roux

channel_simulator: ability to connect a real USRP device to the simulator

This commit introduces the ability to connect a real hardware device to
the channel simulator.

It is possible to run an eNB with the libchannel_simulator.so as
liboai_device.so and the "usrp" program and have both connected
as if the eNB was directly talking to the USRP device.

For that, a channel can now have a "sample_advance". (The USRP receives
data from the air for subframe N and sends data for subframe N+x in the
future. In this commit x = 2 subframes.)

The following commands can be run to connect an eNB and the "usrp"
program in FDD mode with 25 RBs.

First, run the the channel simulator. In the directory channel_simulator:

    ./channel_simulator

To run usrp, as root, in the directory channel_simulator/usrp:

    ./usrp

To run the eNB, as root:

    CHANNEL_SIMULATOR_RX_FREQUENCY=2 CHANNEL_SIMULATOR_TX_FREQUENCY=1 CHANNEL_SIMULATOR_TX_SAMPLE_ADVANCE=15360 ./lte-softmodem -O [config file]

Then it is possible to connect a COTS UE.

It is also possible to connect openair UE which uses libchannel_simulator.so
as liboai_device.so. For that, run, as root:

    CHANNEL_SIMULATOR_RX_FREQUENCY=1 CHANNEL_SIMULATOR_TX_FREQUENCY=2 CHANNEL_SIMULATOR_RX_SAMPLE_ADVANCE=15360 ./lte-uesoftmodem -C 2680000000 -r 25 --ue-rxgain 140 --nokrnmod

Connecting both the openair UE and a COTS UE, it is possible to send traffic
between the two.

Note: performances need to be improved.

Note 2: the program "channel_simulator" now requires AVX2 instruction set.
parent b2326516
......@@ -73,12 +73,19 @@ oom:
exit(1);
}
static int find_or_create_channel(channel_simulator *c, uint64_t freq)
static int find_or_create_channel(channel_simulator *c, uint64_t freq,
uint32_t sample_advance)
{
channel *chan;
int i;
for (i = 0; i < c->channels_count; i++)
if ( c->channels[i].frequency == freq) return i;
for (i = 0; i < c->channels_count; i++) {
if (c->channels[i].frequency != freq) continue;
if (c->channels[i].sample_advance != sample_advance) {
printf("ERROR: bad sample_advance\n");
exit(1);
}
return i;
}
c->channels_count++;
c->channels = realloc(c->channels, c->channels_count * sizeof(channel));
......@@ -86,6 +93,7 @@ static int find_or_create_channel(channel_simulator *c, uint64_t freq)
chan = &c->channels[i];
chan->frequency = freq;
chan->sample_advance = sample_advance;
chan->data = calloc(1, c->n_samples * 4);
if (chan->data == NULL) goto oom;
chan->connection_count = 0;
......@@ -98,7 +106,8 @@ oom:
}
void channel_simulator_add_connection(channel_simulator *c,
int socket, uint64_t rx_frequency, uint64_t tx_frequency)
int socket, uint64_t rx_frequency, uint64_t tx_frequency,
uint32_t rx_sample_advance, uint32_t tx_sample_advance)
{
connection *con;
......@@ -116,8 +125,10 @@ void channel_simulator_add_connection(channel_simulator *c,
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);
con->rx_channel_index = find_or_create_channel(c, rx_frequency,
rx_sample_advance);
con->tx_channel_index = find_or_create_channel(c, tx_frequency,
tx_sample_advance);
c->channels[con->rx_channel_index].connection_count++;
c->channels[con->tx_channel_index].connection_count++;
......@@ -152,6 +163,8 @@ void command_set_frequency(channel_simulator *cs, connection *con, int n)
unsigned char b[8*2];
uint64_t rx_frequency;
uint64_t tx_frequency;
uint32_t rx_sample_advance;
uint32_t tx_sample_advance;
if (n != 8*2) goto err;
if (fullread(con->socket, b, 8*2) != 8*2) goto err;
......@@ -164,10 +177,15 @@ void command_set_frequency(channel_simulator *cs, connection *con, int n)
cs->channels[con->rx_channel_index].connection_count--;
cs->channels[con->tx_channel_index].connection_count--;
rx_sample_advance = cs->channels[con->rx_channel_index].sample_advance;
tx_sample_advance = cs->channels[con->tx_channel_index].sample_advance;
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);
con->rx_channel_index = find_or_create_channel(cs, rx_frequency,
rx_sample_advance);
con->tx_channel_index = find_or_create_channel(cs, tx_frequency,
tx_sample_advance);
cs->channels[con->rx_channel_index].connection_count++;
cs->channels[con->tx_channel_index].connection_count++;
......@@ -233,6 +251,8 @@ err:
c->socket = -1;
}
#include <immintrin.h>
void channel_simulate(channel_simulator *c)
{
int i;
......@@ -241,14 +261,15 @@ void channel_simulate(channel_simulator *c)
channel *chan;
int16_t *to;
int16_t *from;
int32_t mix[c->channels_count][c->n_samples*2];
int16_t mix[c->channels_count][c->n_samples*2] __attribute__ ((aligned (32)));
memset(mix, 0, c->channels_count * c->n_samples*2 * 4);
memset(mix, 0, c->channels_count * c->n_samples*2 * 2);
/* clear channels */
for (i = 0; i < c->channels_count; i++)
memset(c->channels[i].data, 0, c->n_samples * 4);
#if 0
/* basic mixing */
for (i = 0; i < c->connections_count; i++) {
con = &c->connections[i];
......@@ -269,4 +290,24 @@ void channel_simulate(channel_simulator *c)
to[k] = v;
}
}
#else
/* 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+=16) {
__m256i *a, *b;
a = (__m256i *)&mix[con->tx_channel_index][k];
b = (__m256i *)&from[k];
*a = _mm256_adds_epi16(*a, *b);
}
}
for (i = 0; i < c->channels_count; i++) {
chan = &c->channels[i];
to = (int16_t *)chan->data;
memcpy(to, mix[i], c->n_samples * 2 * 2);
}
#endif
}
......@@ -5,6 +5,7 @@
typedef struct {
uint64_t frequency; /* unit: Hz */
uint32_t sample_advance;
uint32_t *data;
int connection_count;
} channel;
......@@ -32,7 +33,8 @@ 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);
int socket, uint64_t rx_frequency, uint64_t tx_frequency,
uint32_t rx_sample_advance, uint32_t tx_sample_advance);
void connection_send_rx(connection *c, uint64_t timestamp,
uint32_t *data, int n_samples);
......
......@@ -12,16 +12,20 @@
typedef struct {
uint64_t rx_frequency;
uint64_t tx_frequency;
uint32_t rx_sample_advance;
uint32_t tx_sample_advance;
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;
unsigned char b[8*2+4*3];
if (fullread(s, b, 8*2+4*3) != 8*2+4*3) return -1;
m->rx_frequency = gu64(b);
m->tx_frequency = gu64(b+8);
m->samplerate = gu32(b+8*2);
m->rx_sample_advance = gu32(b+8*2);
m->tx_sample_advance = gu32(b+8*2+4);
m->samplerate = gu32(b+8*2+4*2);
return 0;
}
......@@ -56,6 +60,8 @@ static void *connection_manager_thread(void *_cm)
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].rx_sample_advance = m.rx_sample_advance;
cm->c[cm->new_connections-1].tx_sample_advance = m.tx_sample_advance;
cm->c[cm->new_connections-1].samplerate = m.samplerate;
lock_signal(&cm->l);
connection_manager_unlock(cm);
......
......@@ -8,6 +8,8 @@ typedef struct {
int socket;
uint64_t rx_frequency;
uint64_t tx_frequency;
uint32_t tx_sample_advance;
uint32_t rx_sample_advance;
uint32_t samplerate;
} new_connection;
......
......@@ -28,7 +28,8 @@ int main(void)
continue;
}
channel_simulator_add_connection(&c,
cm.c[i].socket, cm.c[i].rx_frequency, cm.c[i].tx_frequency);
cm.c[i].socket, cm.c[i].rx_frequency, cm.c[i].tx_frequency,
cm.c[i].rx_sample_advance, cm.c[i].tx_sample_advance);
}
connection_manager_clear(&cm);
}
......@@ -36,9 +37,12 @@ int main(void)
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);
channel *ch_rx = &c.channels[con->rx_channel_index];
channel *ch_tx = &c.channels[con->tx_channel_index];
connection_send_rx(con, c.timestamp + ch_rx->sample_advance,
ch_rx->data, c.n_samples);
connection_receive_tx(&c, con, c.timestamp + ch_tx->sample_advance
+ c.n_samples, c.n_samples);
}
cleanup_connections(&c);
......@@ -46,12 +50,14 @@ int main(void)
c.timestamp += c.n_samples;
channel_simulate(&c);
#if 0
static int processed = 0;
processed += c.n_samples;
if (processed >= samplerate/1000) {
processed -= samplerate/1000;
usleep(2000);
}
#endif
}
return 0;
......
CC=gcc
CPP=g++
CFLAGS=-Wall -g -pthread
PROG=usrp
OBJS=main.o usrp.o ../utils.o
$(PROG): $(OBJS)
$(CPP) $(CFLAGS) -o $@ $^ -luhd -lboost_system
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
%.o: %.cc
$(CPP) $(CFLAGS) -c -o $@ $<
clean:
rm -f $(PROG) *.o core
#include "usrp.h"
#include "../utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <pthread.h>
#include <inttypes.h>
typedef struct {
char *data;
uint32_t n_samples;
uint64_t timestamp;
} buffer_t;
void receive_from_channel_simulator(int sock, buffer_t *buf)
{
unsigned char b[8+4];
uint32_t n_samples;
if (fullread(sock, b, 8+4) != 8+4) goto err;
buf->timestamp = gu64(b);
n_samples = gu32(b+8);
if (n_samples != buf->n_samples) {
free(buf->data);
buf->n_samples = n_samples;
buf->data = malloc(buf->n_samples * 4); if (buf->data == NULL) goto err;
}
if (fullread(sock, buf->data, buf->n_samples * 4) != buf->n_samples * 4)
goto err;
return;
err:
printf("ERROR: receive_from_channel_simulator failed\n");
exit(1);
}
void send_to_channel_simulator(int sock, char *usrp_data, int n_samples,
uint64_t timestamp)
{
unsigned char b[8+4];
pu64(b, timestamp);
pu32(b+8, n_samples);
if (fullwrite(sock, b, 8+4) != 8+4 ||
fullwrite(sock, usrp_data, n_samples * 4) != n_samples * 4) {
printf("ERROR: send_to_channel_simulator failed\n");
exit(1);
}
}
int connect_to_channel_simulator(void)
{
int port = 4024;
char *ip = "127.0.0.1";
struct sockaddr_in addr;
int sock;
int v;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) { perror("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("trying to connect to %s:%d\n", ip, port);
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
printf("connection established\n");
return sock;
}
perror("channel_simulator");
sleep(1);
}
}
void init_connection(int sock, uint64_t rx_frequency, uint64_t tx_frequency,
int samples_per_subframe)
{
unsigned char b[8*2+4*3];
pu64(b, rx_frequency);
pu64(b+8, tx_frequency);
pu32(b+8*2, samples_per_subframe * 2); /* RX sample advance */
pu32(b+8*2+4, 0); /* TX sample advance */
pu32(b+8*2+4*2, samples_per_subframe * 1000);
if (fullwrite(sock, b, 8*2+4*3) != 8*2+4*3) {
printf("ERROR: init_connection failed\n");
exit(1);
}
}
void go_realtime(void)
{
struct sched_param sparam;
int policy;
memset(&sparam, 0, sizeof(sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
policy = SCHED_FIFO ;
if (pthread_setschedparam(pthread_self(), policy, &sparam) != 0) {
printf("ERROR: Failed to set pthread priority\n");
exit(1);
}
}
int main(void)
{
int sock;
buffer_t buf = { data:NULL, n_samples:0, timestamp:0 };
uint64_t sim_timestamp;
uint64_t usrp_timestamp;
int samples_per_subframe = 7680;
int tx_sample_advance = 0; //40;
char *usrp_data;
go_realtime();
usrp_init_connection(2560000000, 2680000000);
sock = connect_to_channel_simulator();
init_connection(sock, 1, 2, samples_per_subframe);
receive_from_channel_simulator(sock, &buf);
sim_timestamp = buf.timestamp - 2 * samples_per_subframe + buf.n_samples;
usrp_data = calloc(1, buf.n_samples * 4);
if (usrp_data == NULL) {
printf("ERROR: out of memory\n");
exit(1);
}
send_to_channel_simulator(sock, usrp_data, buf.n_samples, sim_timestamp);
sim_timestamp += buf.n_samples;
usrp_start();
usrp_timestamp = usrp_read(usrp_data, buf.n_samples);
while (1) {
usrp_write(buf.data, buf.n_samples,
usrp_timestamp - buf.n_samples + 2 * samples_per_subframe - tx_sample_advance);
usrp_timestamp = usrp_read(usrp_data, buf.n_samples);
send_to_channel_simulator(sock, usrp_data, buf.n_samples, sim_timestamp);
sim_timestamp += buf.n_samples;
receive_from_channel_simulator(sock, &buf);
}
return 0;
}
/* g++ bug-3.13.1.0.cc -luhd -lboost_system */
#include <uhd/usrp/multi_usrp.hpp>
#include <stdio.h>
#include <stdlib.h>
static uhd::usrp::multi_usrp::sptr usrp;
static uhd::rx_streamer::sptr rx_stream;
static uhd::tx_streamer::sptr tx_stream;
static uhd::rx_metadata_t rx_md;
static uhd::tx_metadata_t tx_md;
extern "C" {
#include "usrp.h"
void usrp_init_connection(uint64_t rx_freq, uint64_t tx_freq)
{
std::string args = "type=b200";
uhd::device_addrs_t device_adds = uhd::device::find(args);
if (device_adds.size() == 0) { printf("no device\n"); exit(1); }
if (device_adds[0].get("type") != "b200") { printf("no b200\n"); exit(1); }
double usrp_master_clock = 30.72e6;
args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock);
//args += ",num_send_frames=256,num_recv_frames=256, send_frame_size=3840, recv_frame_size=3840";
args += ",num_send_frames=256,num_recv_frames=256";
usrp = uhd::usrp::multi_usrp::make(args);
usrp->set_clock_source("internal");
usrp->set_master_clock_rate(30.72e6);
usrp->set_rx_rate(7680000, 0);
usrp->set_rx_freq(rx_freq, 0);
usrp->set_rx_gain(40, 0);
usrp->set_tx_rate(7680000, 0);
usrp->set_tx_freq(tx_freq, 0);
usrp->set_tx_gain(90, 0);
uhd::stream_args_t stream_args_rx("sc16", "sc16");
stream_args_rx.args["spp"] = str(boost::format("%d") % 768 );
stream_args_rx.channels.push_back(0);
rx_stream = usrp->get_rx_stream(stream_args_rx);
uhd::stream_args_t stream_args_tx("sc16", "sc16");
stream_args_tx.channels.push_back(0);
tx_stream = usrp->get_tx_stream(stream_args_tx);
usrp->set_tx_bandwidth(20e6);
usrp->set_rx_bandwidth(20e6);
}
void usrp_start(void)
{
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
cmd.stream_now = false; // start at constant delay
cmd.time_spec = usrp->get_time_now() + uhd::time_spec_t(0.05);
rx_stream->issue_stream_cmd(cmd);
tx_md.start_of_burst = true;
tx_md.end_of_burst = false;
}
uint64_t usrp_read(char *buf, int samples_count)
{
std::vector<void *> buff_ptrs;
buff_ptrs.push_back(buf);
int recv = rx_stream->recv(buff_ptrs, samples_count, rx_md);
return rx_md.time_spec.to_ticks(7680000);
}
void usrp_write(char *buf, int samples_count, uint64_t timestamp)
{
tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, 7680000);
tx_md.has_time_spec = true;
int sendv = tx_stream->send(buf, samples_count, tx_md, 10 /*1e-3*/);
tx_md.start_of_burst = false;
}
#if 0
while (1) {
char buf[7680*2*2];
std::vector<void *> buff_ptrs;
buff_ptrs.push_back(buf);
int recv = rx_stream->recv(buff_ptrs, 7680, rx_md);
//printf("got %d samples ret %d [%lld]\n", recv, rx_md.error_code, rx_md.time_spec.to_ticks(7680000));
unsigned long long ts = rx_md.time_spec.to_ticks(7680000) + 4 * 7680;
tx_md.time_spec = uhd::time_spec_t::from_ticks(ts, 7680000);
tx_md.has_time_spec = true;
int sendv = tx_stream->send(buf, 7680, tx_md, 1e-3);
//printf("send %d samples\n", sendv);
tx_md.start_of_burst = false;
}
return 0;
}
#endif
} /* extern "C" */
#ifndef _USRP_H_openair
#define _USRP_H_openair
#include <stdint.h>
void usrp_init_connection(uint64_t rx_freq, uint64_t tx_freq);
void usrp_start(void);
uint64_t usrp_read(char *buf, int samples_count);
void usrp_write(char *buf, int samples_count, uint64_t timestamp);
#endif /* _USRP_H_openair */
......@@ -23,6 +23,8 @@ typedef struct {
int samples_per_subframe;
uint64_t rx_frequency;
uint64_t tx_frequency;
uint32_t rx_sample_advance;
uint32_t tx_sample_advance;
lock_t lock;
buffer_t * volatile rx_head;
buffer_t *rx_last;
......@@ -31,6 +33,7 @@ typedef struct {
volatile int first_rx_ok;
uint64_t rx_next_timestamp;
lock_t tx_lock;
lock_t tx_buf_lock;
} channel_simulator_state_t;
void add_rx_buffer(channel_simulator_state_t *c, buffer_t *b)
......@@ -48,22 +51,21 @@ void add_rx_buffer(channel_simulator_state_t *c, buffer_t *b)
void add_tx_buffer(channel_simulator_state_t *c, buffer_t *b)
{
lock(&c->lock);
lock(&c->tx_buf_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);
unlock(&c->tx_buf_lock);
}
/* called with c->lock acquired */
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) {
......@@ -82,7 +84,6 @@ again:
}
b = c->rx_head->b;
ret = b[timestamp - c->rx_head->timestamp];
unlock(&c->lock);
return ret;
}
......@@ -90,7 +91,6 @@ 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) {
......@@ -119,7 +119,6 @@ again:
cur = cur->next;
}
done:
unlock(&c->lock);
return ret;
}
......@@ -157,9 +156,14 @@ void *rx_thread(void *_c)
if (out == NULL) goto err;
out_size = n_samples;
}
lock(&c->tx_buf_lock);
for (i = 0; i < n_samples; i++)
out[i] = get_tx_sample(c, timestamp + n_samples + i);
pu64(b, timestamp + n_samples);
out[i] = get_tx_sample(c, timestamp - c->rx_sample_advance
+ c->tx_sample_advance
+ n_samples + i);
unlock(&c->tx_buf_lock);
pu64(b, timestamp - c->rx_sample_advance
+ c->tx_sample_advance + n_samples);
pu32(b+8, n_samples);
lock(&c->tx_lock);
if (fullwrite(c->sock, b, 8+4) != 8+4 ||
......@@ -179,14 +183,41 @@ err:
void init_connection(channel_simulator_state_t *c)
{
unsigned char b[8*2+4];
unsigned char b[8*2+4*3];
char *env;
env = getenv("CHANNEL_SIMULATOR_RX_SAMPLE_ADVANCE");
if (env != NULL) {
c->rx_sample_advance = atoi(env);
printf("channel_simulator: setting rx_sample_advance to %"PRIu32"\n",
c->rx_sample_advance);
} else {
c->rx_sample_advance = 0;
printf("channel_simulator: environment variable"
" CHANNEL_SIMULATOR_RX_SAMPLE_ADVANCE"
" not found, using 0\n");
}
env = getenv("CHANNEL_SIMULATOR_TX_SAMPLE_ADVANCE");
if (env != NULL) {
c->tx_sample_advance = atoi(env);
printf("channel_simulator: setting tx_sample_advance to %"PRIu32"\n",
c->tx_sample_advance);
} else {
c->tx_sample_advance = 0;
printf("channel_simulator: environment variable"
" CHANNEL_SIMULATOR_TX_SAMPLE_ADVANCE"
" not found, using 0\n");
}
pu64(b, c->rx_frequency);
pu64(b+8, c->tx_frequency);
pu32(b+8*2, c->samples_per_subframe * 1000);
pu32(b+8*2, c->rx_sample_advance);
pu32(b+8*2+4, c->tx_sample_advance);
pu32(b+8*2+4*2, c->samples_per_subframe * 1000);
lock(&c->tx_lock);
if (fullwrite(c->sock, b, 8*2+4) != 8*2+4) {
if (fullwrite(c->sock, b, 8*2+4*3) != 8*2+4*3) {
printf("ERROR: channel_simulator: init_connection failed\n");
exit(1);
}
......@@ -257,6 +288,10 @@ int channel_simulator_set_freq(openair0_device* device, openair0_config_t *opena
channel_simulator_state_t *c = device->priv;
unsigned char b[8+4+8*2];
if (getenv("CHANNEL_SIMULATOR_RX_FREQUENCY") != NULL ||
getenv("CHANNEL_SIMULATOR_TX_FREQUENCY") != NULL)
return 0;
pu64(b, 0);
pu32(b+8, 8*2);
pu64(b+8+4, openair0_cfg[0].rx_freq[0]);
......@@ -316,8 +351,8 @@ int channel_simulator_read(openair0_device *device, openair0_timestamp *timestam
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);
for (i = 0; i < nsamps; i++) r[i] = get_rx_sample(c, ts + i);
c->rx_next_timestamp += nsamps;
unlock(&c->lock);
*timestamp = ts;
......@@ -329,6 +364,8 @@ __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));
char *env;
memset(channel_simulator, 0, sizeof(channel_simulator_state_t));
/* only 25, 50 or 100 PRBs handled for the moment */
......@@ -359,9 +396,27 @@ int device_init(openair0_device* device, openair0_config_t *openair0_cfg)
init_lock(&channel_simulator->lock);
init_lock(&channel_simulator->tx_lock);
init_lock(&channel_simulator->tx_buf_lock);
env = getenv("CHANNEL_SIMULATOR_RX_FREQUENCY");
if (env == NULL) {
printf("channel_simulator: CHANNEL_SIMULATOR_RX_FREQUENCY not set, used provided value %g\n",
openair0_cfg[0].rx_freq[0]);
channel_simulator->rx_frequency = openair0_cfg[0].rx_freq[0];
} else {
channel_simulator->rx_frequency = atoll(env);
printf("channel_simulator: set RX frequency to %"PRIu64"\n", channel_simulator->rx_frequency);
}
env = getenv("CHANNEL_SIMULATOR_TX_FREQUENCY");
if (env == NULL) {
printf("channel_simulator: CHANNEL_SIMULATOR_TX_FREQUENCY not set, used provided value %g\n",
openair0_cfg[0].tx_freq[0]);
channel_simulator->tx_frequency = openair0_cfg[0].tx_freq[0];
} else {
channel_simulator->tx_frequency = atoll(env);
printf("channel_simulator: set TX frequency to %"PRIu64"\n", channel_simulator->tx_frequency);
}
/* let's pretend to be a b2x0 */
device->type = USRP_B200_DEV;
......
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