|
|
|
@ -17,18 +17,22 @@
|
|
|
|
|
#include <complex.h>
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
#include <srsran/phy/common/phy_common.h>
|
|
|
|
|
#include <srsran/phy/utils/vector.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <zmq.h>
|
|
|
|
|
|
|
|
|
|
#define NOF_RX_ANT 1
|
|
|
|
|
#define PRINT_SAMPLES 1
|
|
|
|
|
#define COMPARE_BITS 0
|
|
|
|
|
#define COMPARE_EPSILON (1e-6f)
|
|
|
|
|
#define NOF_RX_ANT 4
|
|
|
|
|
#define NUM_SF (500)
|
|
|
|
|
#define SF_LEN (1920)
|
|
|
|
|
#define RF_BUFFER_SIZE (SF_LEN * NUM_SF)
|
|
|
|
|
#define TX_OFFSET_MS (4)
|
|
|
|
|
|
|
|
|
|
static cf_t ue_rx_buffer[RF_BUFFER_SIZE];
|
|
|
|
|
static cf_t enb_tx_buffer[RF_BUFFER_SIZE];
|
|
|
|
|
static cf_t enb_rx_buffer[RF_BUFFER_SIZE];
|
|
|
|
|
static cf_t ue_rx_buffer[NOF_RX_ANT][RF_BUFFER_SIZE];
|
|
|
|
|
static cf_t enb_tx_buffer[NOF_RX_ANT][RF_BUFFER_SIZE];
|
|
|
|
|
static cf_t enb_rx_buffer[NOF_RX_ANT][RF_BUFFER_SIZE];
|
|
|
|
|
|
|
|
|
|
static srsran_rf_t ue_radio, enb_radio;
|
|
|
|
|
pthread_t rx_thread;
|
|
|
|
@ -53,13 +57,15 @@ void* ue_rx_thread_function(void* args)
|
|
|
|
|
uint32_t num_rxed_samps = 0;
|
|
|
|
|
for (uint32_t i = 0; i < num_slots; ++i) {
|
|
|
|
|
void* data_ptr[SRSRAN_MAX_PORTS] = {NULL};
|
|
|
|
|
data_ptr[0] = &ue_rx_buffer[i * num_samps_per_slot];
|
|
|
|
|
for (uint32_t c = 0; c < NOF_RX_ANT; c++) {
|
|
|
|
|
data_ptr[c] = &ue_rx_buffer[c][i * num_samps_per_slot];
|
|
|
|
|
}
|
|
|
|
|
num_rxed_samps += srsran_rf_recv_with_time_multi(&ue_radio, data_ptr, num_samps_per_slot, true, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("received %d samples.\n", num_rxed_samps);
|
|
|
|
|
|
|
|
|
|
printf("closing ue norf device\n");
|
|
|
|
|
printf("closing ue zmq device\n");
|
|
|
|
|
srsran_rf_close(&ue_radio);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
@ -78,16 +84,23 @@ void enb_tx_function(const char* tx_args, bool timed_tx)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// generate random tx data
|
|
|
|
|
for (int c = 0; c < NOF_RX_ANT; c++) {
|
|
|
|
|
for (int i = 0; i < RF_BUFFER_SIZE; i++) {
|
|
|
|
|
enb_tx_buffer[i] = ((float)rand() / (float)RAND_MAX) + _Complex_I * ((float)rand() / (float)RAND_MAX);
|
|
|
|
|
enb_tx_buffer[c][i] = ((float)rand() / (float)RAND_MAX) + _Complex_I * ((float)rand() / (float)RAND_MAX);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// send data subframe per subframe
|
|
|
|
|
uint32_t num_txed_samples = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// initial transmission without ts
|
|
|
|
|
void* data_ptr[SRSRAN_MAX_PORTS] = {NULL};
|
|
|
|
|
data_ptr[0] = &enb_tx_buffer[num_txed_samples];
|
|
|
|
|
cf_t tx_buffer[NOF_RX_ANT][SF_LEN];
|
|
|
|
|
for (int c = 0; c < NOF_RX_ANT; c++) {
|
|
|
|
|
memcpy(&tx_buffer[c], &enb_tx_buffer[c][num_txed_samples], SF_LEN * sizeof (cf_t));
|
|
|
|
|
data_ptr[c] = &tx_buffer[c][0];
|
|
|
|
|
}
|
|
|
|
|
int ret = srsran_rf_send_multi(&enb_radio, (void**)data_ptr, SF_LEN, true, true, false);
|
|
|
|
|
num_txed_samples += SF_LEN;
|
|
|
|
|
|
|
|
|
@ -96,11 +109,16 @@ void enb_tx_function(const char* tx_args, bool timed_tx)
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < NUM_SF - ((timed_tx) ? TX_OFFSET_MS : 1); ++i) {
|
|
|
|
|
// first recv samples
|
|
|
|
|
data_ptr[0] = enb_rx_buffer;
|
|
|
|
|
for (int c = 0; c < NOF_RX_ANT; c++) {
|
|
|
|
|
data_ptr[c] = enb_rx_buffer[c];
|
|
|
|
|
}
|
|
|
|
|
srsran_rf_recv_with_time_multi(&enb_radio, data_ptr, SF_LEN, true, &rx_time.full_secs, &rx_time.frac_secs);
|
|
|
|
|
|
|
|
|
|
// prepare data buffer
|
|
|
|
|
data_ptr[0] = &enb_tx_buffer[num_txed_samples];
|
|
|
|
|
for (int c = 0; c < NOF_RX_ANT; c++) {
|
|
|
|
|
memcpy(&tx_buffer[c], &enb_tx_buffer[c][num_txed_samples], SF_LEN * sizeof (cf_t));
|
|
|
|
|
data_ptr[c] = &tx_buffer[c][0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (timed_tx) {
|
|
|
|
|
// timed tx relative to receive time (this will cause a cap in the rx'ed samples at the UE resulting in 3 zero
|
|
|
|
@ -148,6 +166,8 @@ int run_test(const char* rx_args, const char* tx_args, bool timed_tx)
|
|
|
|
|
// wait for rx thread
|
|
|
|
|
pthread_join(rx_thread, NULL);
|
|
|
|
|
|
|
|
|
|
// channel-wise comparison
|
|
|
|
|
for (int c = 0; c < NOF_RX_ANT; c++) {
|
|
|
|
|
// subframe-wise compare tx'ed and rx'ed data (stop 3 subframes earlier for timed tx)
|
|
|
|
|
for (uint32_t i = 0; i < NUM_SF - (timed_tx ? 3 : 0); ++i) {
|
|
|
|
|
uint32_t sf_offet = 0;
|
|
|
|
@ -156,18 +176,37 @@ int run_test(const char* rx_args, const char* tx_args, bool timed_tx)
|
|
|
|
|
sf_offet = (TX_OFFSET_MS - 1) * SF_LEN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
// print first 3 samples for each SF
|
|
|
|
|
#if PRINT_SAMPLES
|
|
|
|
|
// print first 10 samples for each SF
|
|
|
|
|
printf("enb_tx_buffer sf%d:\n", i);
|
|
|
|
|
srsran_vec_fprint_c(stdout, &enb_tx_buffer[i * SF_LEN], 3);
|
|
|
|
|
srsran_vec_fprint_c(stdout, &enb_tx_buffer[c][i * SF_LEN], 10);
|
|
|
|
|
printf("ue_rx_buffer sf%d:\n", i);
|
|
|
|
|
srsran_vec_fprint_c(stdout, &ue_rx_buffer[sf_offet + i * SF_LEN], 3);
|
|
|
|
|
srsran_vec_fprint_c(stdout, &ue_rx_buffer[c][sf_offet + i * SF_LEN], 10);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (memcmp(&ue_rx_buffer[sf_offet + i * SF_LEN], &enb_tx_buffer[i * SF_LEN], SF_LEN) != 0) {
|
|
|
|
|
#if COMPARE_BITS
|
|
|
|
|
int d = memcmp(&ue_rx_buffer[sf_offet + i * SF_LEN], &enb_tx_buffer[i * SF_LEN], SF_LEN);
|
|
|
|
|
if (d) {
|
|
|
|
|
d = d > 0 ? d : -d;
|
|
|
|
|
fprintf(stderr, "data mismatch in subframe %d, sample %d\n", i, d);
|
|
|
|
|
printf("enb_tx_buffer sf%d:\n", i);
|
|
|
|
|
srsran_vec_fprint_c(stdout, &enb_tx_buffer[i * SF_LEN + d], 10);
|
|
|
|
|
printf("ue_rx_buffer sf%d:\n", i);
|
|
|
|
|
srsran_vec_fprint_c(stdout, &ue_rx_buffer[sf_offet + i * SF_LEN + d], 10);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
srsran_vec_sub_ccc(&ue_rx_buffer[c][sf_offet + i * SF_LEN],
|
|
|
|
|
&enb_tx_buffer[c][i * SF_LEN],
|
|
|
|
|
&ue_rx_buffer[c][sf_offet + i * SF_LEN],
|
|
|
|
|
SF_LEN);
|
|
|
|
|
uint32_t max_ix = srsran_vec_max_abs_ci(&ue_rx_buffer[c][sf_offet + i * SF_LEN], SF_LEN);
|
|
|
|
|
if (cabsf(ue_rx_buffer[c][sf_offet + i * SF_LEN + max_ix]) > COMPARE_EPSILON) {
|
|
|
|
|
fprintf(stderr, "data mismatch in subframe %d\n", i);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = SRSRAN_SUCCESS;
|
|
|
|
@ -195,56 +234,76 @@ int param_test(const char* args_param, const int num_channels)
|
|
|
|
|
|
|
|
|
|
int main()
|
|
|
|
|
{
|
|
|
|
|
// two Rx ports
|
|
|
|
|
if (param_test("rx_port=ipc://dl0,rx_port1=ipc://dl1", 2)) {
|
|
|
|
|
fprintf(stderr, "Param test failed!\n");
|
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// multiple rx ports, no channel index provided
|
|
|
|
|
if (param_test("rx_port=ipc://dl0,rx_port=ipc://dl1,rx_port=ipc://dl2,rx_port=ipc://dl3,base_srate=1.92e6", 4)) {
|
|
|
|
|
fprintf(stderr, "Param test failed!\n");
|
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// One Rx, one Tx and all generic options
|
|
|
|
|
if (param_test("rx_port0=tcp://"
|
|
|
|
|
"localhost:2000,rx_format=sc16,tx_format=sc16,tx_type=pub,rx_type=sub,base_srate=1.92e6,id=test",
|
|
|
|
|
1)) {
|
|
|
|
|
fprintf(stderr, "Param test failed!\n");
|
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 1 port, 2 antennas, MIMO freq config
|
|
|
|
|
if (param_test(
|
|
|
|
|
"tx_port0=tcp://*:2001,tx_port1=tcp://*:2003,rx_port0=tcp://localhost:2000,rx_port1=tcp://"
|
|
|
|
|
"localhost:2002,id=ue,base_srate=23.04e6,tx_freq0=2510e6,tx_freq1=2510e6,rx_freq0=2630e6,,rx_freq1=2630e6",
|
|
|
|
|
2)) {
|
|
|
|
|
fprintf(stderr, "Param test failed!\n");
|
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// // two Rx ports
|
|
|
|
|
// if (param_test("rx_port=ipc://dl0,rx_port1=ipc://dl1", 2)) {
|
|
|
|
|
// fprintf(stderr, "Param test failed!\n");
|
|
|
|
|
// return SRSRAN_ERROR;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // multiple rx ports, no channel index provided
|
|
|
|
|
// if (param_test("rx_port=ipc://dl0,rx_port=ipc://dl1,rx_port=ipc://dl2,rx_port=ipc://dl3,base_srate=1.92e6", 4)) {
|
|
|
|
|
// fprintf(stderr, "Param test failed!\n");
|
|
|
|
|
// return SRSRAN_ERROR;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // One Rx, one Tx and all generic options
|
|
|
|
|
// if (param_test("rx_port0=tcp://"
|
|
|
|
|
// "localhost:2000,rx_format=sc16,tx_format=sc16,tx_type=pub,rx_type=sub,base_srate=1.92e6,id=test",
|
|
|
|
|
// 1)) {
|
|
|
|
|
// fprintf(stderr, "Param test failed!\n");
|
|
|
|
|
// return SRSRAN_ERROR;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // 1 port, 2 antennas, MIMO freq config
|
|
|
|
|
// if (param_test(
|
|
|
|
|
// "tx_port0=tcp://*:2001,tx_port1=tcp://*:2003,rx_port0=tcp://localhost:2000,rx_port1=tcp://"
|
|
|
|
|
// "localhost:2002,id=ue,base_srate=23.04e6,tx_freq0=2510e6,tx_freq1=2510e6,rx_freq0=2630e6,,rx_freq1=2630e6",
|
|
|
|
|
// 2)) {
|
|
|
|
|
// fprintf(stderr, "Param test failed!\n");
|
|
|
|
|
// return SRSRAN_ERROR;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
#if NOF_RX_ANT == 1
|
|
|
|
|
// single tx, single rx with continuous transmissions (no timed tx) using IPC transport
|
|
|
|
|
if (run_test("rx_port=ipc://link1,id=ue,base_srate=1.92e6", "tx_port=ipc://link1,id=enb,base_srate=1.92e6", false) !=
|
|
|
|
|
SRSRAN_SUCCESS) {
|
|
|
|
|
fprintf(stderr, "Single tx, single rx test failed!\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// two trx radios with continous tx (no timed tx) using TCP transport for both directions
|
|
|
|
|
if (run_test("tx_port=tcp://*:5554,rx_port=tcp://"
|
|
|
|
|
"localhost:5555,id=ue,base_srate=1.92e6,log_trx_timeout=true,trx_timeout_ms=1000",
|
|
|
|
|
"rx_port=tcp://localhost:5554,tx_port=tcp://*:5555,id=enb,base_srate=1.92e6",
|
|
|
|
|
// up to 4 trx radios with continous tx (no decimation, no timed tx)
|
|
|
|
|
if (run_test("tx_port=tcp://*:5554,tx_port=tcp://*:5556,tx_port=tcp://*:5558,tx_port=tcp://*:5560,rx_port=tcp://"
|
|
|
|
|
"localhost:5555,rx_port=tcp://localhost:5557,rx_port=tcp://localhost:5559,rx_port=tcp://"
|
|
|
|
|
"localhost:5561,id=ue,base_srate=1.92e6,log_trx_timeout=true,trx_timeout_ms=1000",
|
|
|
|
|
"rx_port=tcp://localhost:5554,rx_port=tcp://localhost:5556,rx_port=tcp://localhost:5558,rx_port=tcp://"
|
|
|
|
|
"localhost:5560,tx_port=tcp://*:5555,tx_port=tcp://*:5557,tx_port=tcp://*:5559,tx_port=tcp://"
|
|
|
|
|
"*:5561,id=enb,base_srate=1.92e6",
|
|
|
|
|
false) != SRSRAN_SUCCESS) {
|
|
|
|
|
fprintf(stderr, "Two TRx radio test failed!\n");
|
|
|
|
|
fprintf(stderr, "Multi TRx radio test failed!\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// up to 4 trx radios with continous tx (timed tx) using TCP for UL (UE tx) and IPC for eNB DL (eNB tx)
|
|
|
|
|
if (run_test("tx_port=tcp://*:5554,tx_port=tcp://*:5556,tx_port=tcp://*:5558,tx_port=tcp://*:5560,rx_port=ipc://"
|
|
|
|
|
"dl0,rx_port=ipc://dl1,rx_port=ipc://dl2,rx_port=ipc://dl3,id=ue,base_srate=1.92e6",
|
|
|
|
|
"rx_port=tcp://localhost:5554,rx_port=tcp://localhost:5556,rx_port=tcp://localhost:5558,rx_port=tcp://"
|
|
|
|
|
"localhost:5560,tx_port=ipc://dl0,tx_port=ipc://dl1,tx_port=ipc://dl2,tx_port=ipc://"
|
|
|
|
|
"dl3,id=enb,base_srate=1.92e6",
|
|
|
|
|
true) != SRSRAN_SUCCESS) {
|
|
|
|
|
fprintf(stderr, "Multi TRx radio test with timed tx failed!\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// two trx radios with continous tx (no timed tx) using TCP for UL (UE tx) and IPC for eNB DL (eNB tx)
|
|
|
|
|
if (run_test("tx_port=tcp://*:5554,rx_port=ipc://dl,id=ue,base_srate=1.92e6",
|
|
|
|
|
"rx_port=tcp://localhost:5554,tx_port=ipc://dl,id=enb,base_srate=1.92e6",
|
|
|
|
|
// up to 4 trx radios with continous tx (timed tx) using TCP for UL (UE tx) and IPC for eNB DL (eNB tx)
|
|
|
|
|
// with decimation 23.04e6 <-> 1.92e6
|
|
|
|
|
if (run_test("tx_port=tcp://*:5554,tx_port=tcp://*:5556,tx_port=tcp://*:5558,tx_port=tcp://*:5560,rx_port=ipc://"
|
|
|
|
|
"dl0,rx_port=ipc://dl1,rx_port=ipc://dl2,rx_port=ipc://dl3,id=ue,base_srate=23.04e6",
|
|
|
|
|
"rx_port=tcp://localhost:5554,rx_port=tcp://localhost:5556,rx_port=tcp://localhost:5558,rx_port=tcp://"
|
|
|
|
|
"localhost:5560,tx_port=ipc://dl0,tx_port=ipc://dl1,tx_port=ipc://dl2,tx_port=ipc://"
|
|
|
|
|
"dl3,id=enb,base_srate=23.04e6",
|
|
|
|
|
true) != SRSRAN_SUCCESS) {
|
|
|
|
|
fprintf(stderr, "Two TRx radio test with timed tx failed!\n");
|
|
|
|
|
fprintf(stderr, "Multi TRx radio test with timed tx and decimation failed!\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|