|
|
|
|
@@ -66,15 +66,12 @@ typedef enum { SIMU_ROLE_SERVER = 1, SIMU_ROLE_CLIENT } simuRole;
|
|
|
|
|
#define RFSIMU_SERVER_PORT "serverport"
|
|
|
|
|
#define RFSIMU_OPTIONS_PARAMNAME "options"
|
|
|
|
|
#define RFSIMU_IQFILE "IQfile"
|
|
|
|
|
#define RFSIMU_MODELNAME "modelname"
|
|
|
|
|
#define RFSIMU_PLOSS "ploss"
|
|
|
|
|
#define RFSIMU_FORGETFACT "forgetfact"
|
|
|
|
|
#define RFSIMU_OFFSET "offset"
|
|
|
|
|
#define RFSIMU_PROP_DELAY "prop_delay"
|
|
|
|
|
#define RFSIMU_WAIT_TIMEOUT "wait_timeout"
|
|
|
|
|
#define RFSIMU_ENABLE_BEAMS "enable_beams"
|
|
|
|
|
#define RFSIMU_NUM_CONCURRENT_BEAMS "num_concurrent_beams"
|
|
|
|
|
#define RFSIMU_BEAM_MAP "beam_map"
|
|
|
|
|
#define RFSIMU_BEAM_GAINS "beam_gains"
|
|
|
|
|
#define RFSIMU_BEAM_IDS "beam_ids"
|
|
|
|
|
|
|
|
|
|
@@ -95,15 +92,12 @@ typedef enum { SIMU_ROLE_SERVER = 1, SIMU_ROLE_CLIENT } simuRole;
|
|
|
|
|
UINT16PARAM(RFSIMU_SERVER_PORT, "<port to connect to>\n", simOpt, NULL, PORT), \
|
|
|
|
|
STRLISTPARAM(RFSIMU_OPTIONS_PARAMNAME, RFSIM_CONFIG_HELP_OPTIONS, simOpt, NULL, NULL), \
|
|
|
|
|
STRINGPARAM(RFSIMU_IQFILE, "<file path to use when saving IQs>\n", simOpt, NULL, "/tmp/rfsimulator.iqs"),\
|
|
|
|
|
STRINGPARAM(RFSIMU_MODELNAME, "<channel model name>\n", simOpt, NULL, "AWGN"), \
|
|
|
|
|
DOUBLEPARAM(RFSIMU_PLOSS, "<channel path loss in dB>\n", simOpt, NULL, 0), \
|
|
|
|
|
DOUBLEPARAM(RFSIMU_FORGETFACT, "<channel forget factor ((0 to 1)>\n", simOpt, NULL, 0), \
|
|
|
|
|
UINT64PARAM(RFSIMU_OFFSET, "<channel offset in samps>\n", simOpt, NULL, 0L), \
|
|
|
|
|
DOUBLEPARAM(RFSIMU_PROP_DELAY, "<propagation delay in ms>\n", simOpt, NULL, 0.0), \
|
|
|
|
|
INTPARAM(RFSIMU_WAIT_TIMEOUT, "<wait timeout if no UE connected>\n", simOpt, NULL, 1), \
|
|
|
|
|
BOOLPARAM(RFSIMU_ENABLE_BEAMS, "<enable simplified beam simulation>\n", simBool,NULL, 0), \
|
|
|
|
|
INTPARAM(RFSIMU_NUM_CONCURRENT_BEAMS, "<number of concurrent beams supported>\n", simOpt, NULL, 1), \
|
|
|
|
|
UINT64PARAM(RFSIMU_BEAM_MAP, "<initial beam map>\n", simOpt, NULL, 1), \
|
|
|
|
|
STRINGPARAM(RFSIMU_BEAM_IDS, "<initial beam ids>\n", simOpt, NULL, NULL), \
|
|
|
|
|
STRINGPARAM(RFSIMU_BEAM_GAINS, "<beam gain matrix in toeplitz form>\n", simOpt, NULL, NULL), \
|
|
|
|
|
};
|
|
|
|
|
@@ -113,7 +107,6 @@ static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt,
|
|
|
|
|
static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
|
|
|
|
|
static int rfsimu_getdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
|
|
|
|
|
static int rfsimu_vtime_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
|
|
|
|
|
static int rfsimu_set_beam(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
|
|
|
|
|
static int rfsimu_set_beamids(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
|
|
|
|
|
// clang-format off
|
|
|
|
|
static telnetshell_cmddef_t rfsimu_cmdarray[] = {
|
|
|
|
|
@@ -122,7 +115,6 @@ static telnetshell_cmddef_t rfsimu_cmdarray[] = {
|
|
|
|
|
{"setdistance", "<model name> <distance>", (cmdfunc_t)rfsimu_setdistance_cmd, {NULL}, TELNETSRV_CMDFLAG_PUSHINTPOOLQ | TELNETSRV_CMDFLAG_NEEDPARAM },
|
|
|
|
|
{"getdistance", "<model name>", (cmdfunc_t)rfsimu_getdistance_cmd, {NULL}, TELNETSRV_CMDFLAG_PUSHINTPOOLQ},
|
|
|
|
|
{"vtime", "", (cmdfunc_t)rfsimu_vtime_cmd, {NULL}, TELNETSRV_CMDFLAG_PUSHINTPOOLQ | TELNETSRV_CMDFLAG_AUTOUPDATE},
|
|
|
|
|
{"setbeam", "beam_map", (cmdfunc_t)rfsimu_set_beam, {NULL}, TELNETSRV_CMDFLAG_PUSHINTPOOLQ},
|
|
|
|
|
{"setbeamids", "beam_id1,beam_id2,...", (cmdfunc_t)rfsimu_set_beamids, {NULL}, TELNETSRV_CMDFLAG_PUSHINTPOOLQ},
|
|
|
|
|
{"", "", NULL},
|
|
|
|
|
};
|
|
|
|
|
@@ -133,12 +125,12 @@ static telnetshell_vardef_t rfsimu_vardef[] = {{"", 0, 0, NULL}};
|
|
|
|
|
typedef c16_t sample_t; // 2*16 bits complex number
|
|
|
|
|
|
|
|
|
|
typedef struct beam_switch_command_t {
|
|
|
|
|
std::vector<int> beams;
|
|
|
|
|
std::vector<uint16_t> beams;
|
|
|
|
|
openair0_timestamp_t timestamp;
|
|
|
|
|
} beam_switch_command_t;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
std::vector<int> beams;
|
|
|
|
|
std::vector<uint16_t> beams;
|
|
|
|
|
std::queue<beam_switch_command_t> cmd_queue;
|
|
|
|
|
std::mutex mutex;
|
|
|
|
|
} beam_state_t;
|
|
|
|
|
@@ -166,7 +158,6 @@ typedef struct buffer_s {
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
int enable_beams;
|
|
|
|
|
int num_concurrent_beams;
|
|
|
|
|
std::vector<std::vector<float>> beam_gains;
|
|
|
|
|
beam_state_t tx;
|
|
|
|
|
beam_state_t rx;
|
|
|
|
|
@@ -212,10 +203,10 @@ typedef struct {
|
|
|
|
|
* @param nsamps_out output pointer to receive the number of samples until the next beam switch.
|
|
|
|
|
* @return The beam map (uint64_t) valid for the given timestamp.
|
|
|
|
|
*/
|
|
|
|
|
static std::vector<int> get_beams(beam_state_t *beam_state, openair0_timestamp_t timestamp, uint32_t nsamps, uint32_t *nsamps_out)
|
|
|
|
|
static std::vector<uint16_t> get_beams(beam_state_t *beam_state, openair0_timestamp_t timestamp, uint32_t nsamps, uint32_t *nsamps_out)
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(beam_state->mutex);
|
|
|
|
|
std::vector<int> current_beams = beam_state->beams;
|
|
|
|
|
std::vector<uint16_t> current_beams = beam_state->beams;
|
|
|
|
|
uint32_t samples_to_next_switch = nsamps;
|
|
|
|
|
|
|
|
|
|
// Find the latest beam_switch_command_t with timestamp <= requested timestamp
|
|
|
|
|
@@ -243,30 +234,6 @@ static std::vector<int> get_beams(beam_state_t *beam_state, openair0_timestamp_t
|
|
|
|
|
return current_beams;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static std::vector<int> beam_map_to_beams(uint64_t beam_map)
|
|
|
|
|
{
|
|
|
|
|
int num_beams = __builtin_popcountll(beam_map);
|
|
|
|
|
AssertFatal(num_beams > 0, "Needs at least one beam\n");
|
|
|
|
|
std::vector<int> beam_ids;
|
|
|
|
|
for (int i = 0; i < MAX_BEAMS; i++) {
|
|
|
|
|
if (beam_map & (1ULL << i)) {
|
|
|
|
|
beam_ids.push_back(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return beam_ids;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint64_t beams_to_beam_map(const std::vector<int> &beam_ids)
|
|
|
|
|
{
|
|
|
|
|
uint64_t beam_map = 0;
|
|
|
|
|
for (size_t i = 0; i < beam_ids.size(); i++) {
|
|
|
|
|
beam_map |= (1ULL << beam_ids[i]);
|
|
|
|
|
}
|
|
|
|
|
return beam_map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Clears outdated beam switch commands from the queue and updates the current beam map.
|
|
|
|
|
*
|
|
|
|
|
@@ -466,25 +433,13 @@ static float get_rx_gain_db(rfsimulator_state_t *rfsimulator, uint rx_beam, uint
|
|
|
|
|
return rfsimulator->beam_ctrl->beam_gains[rx_beam][tx_beam];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rfsimulator_set_beams(openair0_device_t *device, uint64_t beam_map, openair0_timestamp_t timestamp)
|
|
|
|
|
static int rfsimulator_set_beams_vector(openair0_device_t *device, uint16_t *beams, int num_beams, openair0_timestamp_t timestamp)
|
|
|
|
|
{
|
|
|
|
|
rfsimulator_state_t *s = static_cast<rfsimulator_state_t *>(device->priv);
|
|
|
|
|
rfsim_beam_ctrl_t *beam_ctrl = s->beam_ctrl;
|
|
|
|
|
std::lock_guard<std::mutex> lock_tx(beam_ctrl->tx.mutex);
|
|
|
|
|
std::lock_guard<std::mutex> lock_rx(beam_ctrl->rx.mutex);
|
|
|
|
|
beam_switch_command_t command = {.beams = beam_map_to_beams(beam_map), .timestamp = timestamp};
|
|
|
|
|
beam_ctrl->rx.cmd_queue.emplace(command);
|
|
|
|
|
beam_ctrl->tx.cmd_queue.emplace(command);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rfsimulator_set_beams_vector(openair0_device_t *device, int *beams, int num_beams, openair0_timestamp_t timestamp)
|
|
|
|
|
{
|
|
|
|
|
rfsimulator_state_t *s = static_cast<rfsimulator_state_t *>(device->priv);
|
|
|
|
|
rfsim_beam_ctrl_t *beam_ctrl = s->beam_ctrl;
|
|
|
|
|
std::lock_guard<std::mutex> lock_tx(beam_ctrl->tx.mutex);
|
|
|
|
|
std::lock_guard<std::mutex> lock_rx(beam_ctrl->rx.mutex);
|
|
|
|
|
beam_switch_command_t command = {.beams = std::vector<int>(beams, beams + num_beams), .timestamp = timestamp};
|
|
|
|
|
beam_switch_command_t command = {.beams = std::vector<uint16_t>(beams, beams + num_beams), .timestamp = timestamp};
|
|
|
|
|
beam_ctrl->rx.cmd_queue.emplace(command);
|
|
|
|
|
beam_ctrl->tx.cmd_queue.emplace(command);
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -536,7 +491,6 @@ static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator)
|
|
|
|
|
rfsimulator->ip = strdup(*(gpd(rfsimuParam, sizeofArray(rfsimuParams), RFSIMU_SERVER_ADDR)->strptr));
|
|
|
|
|
rfsimulator->port = *(gpd(rfsimuParam, sizeofArray(rfsimuParams), RFSIMU_SERVER_PORT)->u16ptr);
|
|
|
|
|
char *saveF = strdup(*(gpd(rfsimuParam, sizeofArray(rfsimuParams), RFSIMU_IQFILE)->strptr));
|
|
|
|
|
//char *modelname = strdup(*(gpd(rfsimuParam, sizeofArray(rfsimuParams), RFSIMU_MODELNAME)->strptr));
|
|
|
|
|
rfsimulator->chan_pathloss = *(gpd(rfsimuParam, sizeofArray(rfsimuParams), RFSIMU_PLOSS)->dblptr);
|
|
|
|
|
rfsimulator->chan_forgetfact = *(gpd(rfsimuParam, sizeofArray(rfsimuParams), RFSIMU_FORGETFACT)->dblptr);
|
|
|
|
|
rfsimulator->chan_offset = *(gpd(rfsimuParam, sizeofArray(rfsimuParams), RFSIMU_OFFSET)->u64ptr);
|
|
|
|
|
@@ -545,8 +499,6 @@ static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator)
|
|
|
|
|
|
|
|
|
|
rfsim_beam_ctrl_t *beam_ctrl = rfsimulator->beam_ctrl;
|
|
|
|
|
beam_ctrl->enable_beams = *(gpd(rfsimuParam, sizeofArray(rfsimuParams), RFSIMU_ENABLE_BEAMS)->iptr);
|
|
|
|
|
beam_ctrl->num_concurrent_beams = *(gpd(rfsimuParam, sizeofArray(rfsimuParams), RFSIMU_NUM_CONCURRENT_BEAMS)->iptr);
|
|
|
|
|
uint64_t beam_map = *(gpd(rfsimuParam, sizeofArray(rfsimuParams), RFSIMU_BEAM_MAP)->u64ptr);
|
|
|
|
|
|
|
|
|
|
rfsimulator->saveIQfile = -1;
|
|
|
|
|
|
|
|
|
|
@@ -582,13 +534,9 @@ static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator)
|
|
|
|
|
process_gains(*rfsimuParam[beam_gains_param_index].strptr, beam_ctrl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<int> initial_beams = beam_map_to_beams(beam_map);
|
|
|
|
|
beam_ctrl->rx.beams = initial_beams;
|
|
|
|
|
beam_ctrl->tx.beams = initial_beams;
|
|
|
|
|
|
|
|
|
|
int beam_ids_param_index = config_paramidx_fromname(rfsimuParams, sizeofArray(rfsimuParams), RFSIMU_BEAM_IDS);
|
|
|
|
|
if (rfsimuParam[beam_ids_param_index].strptr) {
|
|
|
|
|
std::vector<int> beam_ids;
|
|
|
|
|
std::vector<uint16_t> beam_ids;
|
|
|
|
|
std::stringstream ss(*rfsimuParam[beam_ids_param_index].strptr);
|
|
|
|
|
std::string token;
|
|
|
|
|
while (std::getline(ss, token, ',')) {
|
|
|
|
|
@@ -604,28 +552,13 @@ static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator)
|
|
|
|
|
rfsimulator->role = SIMU_ROLE_CLIENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rfsimu_set_beam(char *buff, int debug, telnet_printfunc_t prnt, void *arg)
|
|
|
|
|
{
|
|
|
|
|
UNUSED(debug);
|
|
|
|
|
rfsimulator_state_t *t = (rfsimulator_state_t *)arg;
|
|
|
|
|
rfsim_beam_ctrl_t *beam_ctrl = t->beam_ctrl;
|
|
|
|
|
AssertFatal(beam_ctrl->enable_beams, "Beam simualtion is disabled, cannot set beams\n");
|
|
|
|
|
uint64_t beam_map = strtoull(buff, NULL, 0);
|
|
|
|
|
std::lock_guard<std::mutex> lock_tx(beam_ctrl->tx.mutex);
|
|
|
|
|
std::lock_guard<std::mutex> lock_rx(beam_ctrl->rx.mutex);
|
|
|
|
|
beam_ctrl->rx.beams = beam_map_to_beams(beam_map);
|
|
|
|
|
beam_ctrl->tx.beams = beam_map_to_beams(beam_map);
|
|
|
|
|
prnt("Beam map set to 0x%lx\n", beam_map);
|
|
|
|
|
return CMDSTATUS_FOUND;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rfsimu_set_beamids(char *buff, int debug, telnet_printfunc_t prnt, void *arg)
|
|
|
|
|
{
|
|
|
|
|
UNUSED(debug);
|
|
|
|
|
rfsimulator_state_t *t = (rfsimulator_state_t *)arg;
|
|
|
|
|
rfsim_beam_ctrl_t *beam_ctrl = t->beam_ctrl;
|
|
|
|
|
AssertFatal(beam_ctrl->enable_beams, "Beam simualtion is disabled, cannot set beams\n");
|
|
|
|
|
std::vector<int> beam_ids;
|
|
|
|
|
std::vector<uint16_t> beam_ids;
|
|
|
|
|
std::stringstream ss(buff);
|
|
|
|
|
std::string token;
|
|
|
|
|
while (std::getline(ss, token, ',')) {
|
|
|
|
|
@@ -735,7 +668,7 @@ static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt
|
|
|
|
|
|
|
|
|
|
rfsimulator_state_t *t = (rfsimulator_state_t *)arg;
|
|
|
|
|
const double sample_rate = t->sample_rate;
|
|
|
|
|
const double c = (double) SPEED_OF_LIGHT;
|
|
|
|
|
const double c = (double)SPEED_OF_LIGHT;
|
|
|
|
|
|
|
|
|
|
const uint64_t new_offset = (double)distance * sample_rate / c;
|
|
|
|
|
const double new_distance = (double)new_offset * c / sample_rate;
|
|
|
|
|
@@ -771,7 +704,7 @@ static int rfsimu_getdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt
|
|
|
|
|
|
|
|
|
|
rfsimulator_state_t *t = (rfsimulator_state_t *)arg;
|
|
|
|
|
const double sample_rate = t->sample_rate;
|
|
|
|
|
const double c = (double) SPEED_OF_LIGHT;
|
|
|
|
|
const double c = (double)SPEED_OF_LIGHT;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_FD_RFSIMU; i++) {
|
|
|
|
|
buffer_t *b = &t->buf[i];
|
|
|
|
|
@@ -953,10 +886,10 @@ static int startClient(openair0_device_t *device)
|
|
|
|
|
|
|
|
|
|
static int rfsimulator_write_internal(rfsimulator_state_t *t,
|
|
|
|
|
openair0_timestamp_t timestamp,
|
|
|
|
|
void ***samplesVoid,
|
|
|
|
|
sample_t **samples,
|
|
|
|
|
int nsamps,
|
|
|
|
|
int nbAnt,
|
|
|
|
|
std::vector<int> tx_beams,
|
|
|
|
|
std::vector<uint16_t> tx_beams,
|
|
|
|
|
int flags)
|
|
|
|
|
{
|
|
|
|
|
mutexlock(t->Sockmutex);
|
|
|
|
|
@@ -966,20 +899,12 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t,
|
|
|
|
|
buffer_t *b = &t->buf[i];
|
|
|
|
|
|
|
|
|
|
if (b->conn_sock >= 0) {
|
|
|
|
|
samplesBlockHeader_t header = {(uint32_t)nsamps, (uint32_t)nbAnt, (uint64_t)timestamp, 0, 0, beams_to_beam_map(tx_beams)};
|
|
|
|
|
samplesBlockHeader_t header = {(uint32_t)nsamps, (uint32_t)nbAnt, (uint64_t)timestamp, 0, 0};
|
|
|
|
|
fullwrite(b->conn_sock, &header, sizeof(header), t);
|
|
|
|
|
int num_beams = tx_beams.size();
|
|
|
|
|
// Send beams in order of beam index. This is required for beam_map to work correctly on the receiver side.
|
|
|
|
|
std::vector<size_t> indices(tx_beams.size());
|
|
|
|
|
std::iota(indices.begin(), indices.end(), 0);
|
|
|
|
|
std::sort(indices.begin(), indices.end(), [&](size_t i, size_t j) { return tx_beams[i] < tx_beams[j]; });
|
|
|
|
|
|
|
|
|
|
AssertFatal(num_beams > 0, "Must set at least one bit in beam_map\n");
|
|
|
|
|
for (int beam = 0; beam < num_beams; beam++) {
|
|
|
|
|
for (int a = 0; a < nbAnt; a++) {
|
|
|
|
|
sample_t *in = (sample_t *)samplesVoid[indices[beam]][a];
|
|
|
|
|
fullwrite(b->conn_sock, (void *)in, sampleToByte(nsamps, 1), t);
|
|
|
|
|
}
|
|
|
|
|
AssertFatal((uint)nbAnt == tx_beams.size(), "rfsim requires one beam per IQ stream\n");
|
|
|
|
|
fullwrite(b->conn_sock, tx_beams.data(), sizeof(uint16_t) * nbAnt, t);
|
|
|
|
|
for (int a = 0; a < nbAnt; a++) {
|
|
|
|
|
fullwrite(b->conn_sock, (void *)samples[a], sampleToByte(nsamps, 1), t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1002,42 +927,40 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t,
|
|
|
|
|
nsamps,
|
|
|
|
|
timestamp,
|
|
|
|
|
timestamp + nsamps,
|
|
|
|
|
signal_energy(static_cast<int32_t *>(samplesVoid[0][0]), nsamps));
|
|
|
|
|
signal_energy_nodc(samples[0], nsamps));
|
|
|
|
|
|
|
|
|
|
/* trace only first antenna */
|
|
|
|
|
T(T_USRP_TX_ANT0, T_INT(timestamp), T_BUFFER(samplesVoid[0][0], (int)sampleToByte(nsamps, 1)));
|
|
|
|
|
T(T_USRP_TX_ANT0, T_INT(timestamp), T_BUFFER(samples[0], (int)sampleToByte(nsamps, 1)));
|
|
|
|
|
|
|
|
|
|
return nsamps;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rfsimulator_write_beams(openair0_device_t *device,
|
|
|
|
|
openair0_timestamp_t timestamp,
|
|
|
|
|
void ***samplesVoid,
|
|
|
|
|
int nsamps,
|
|
|
|
|
int nbAnt,
|
|
|
|
|
int num_beams,
|
|
|
|
|
int flags)
|
|
|
|
|
static int rfsimulator_write(openair0_device_t *device,
|
|
|
|
|
openair0_timestamp_t timestamp,
|
|
|
|
|
void **samplesVoid,
|
|
|
|
|
int nsamps,
|
|
|
|
|
int nbAnt,
|
|
|
|
|
int flags)
|
|
|
|
|
{
|
|
|
|
|
timestamp -= device->openair0_cfg->command_line_sample_advance;
|
|
|
|
|
int nsamps_initial = nsamps;
|
|
|
|
|
rfsimulator_state_t *t = static_cast<rfsimulator_state_t *>(device->priv);
|
|
|
|
|
void *samples[num_beams][nbAnt];
|
|
|
|
|
void **samples_ptr[num_beams];
|
|
|
|
|
for (int beam = 0; beam < num_beams; beam++) {
|
|
|
|
|
samples_ptr[beam] = samples[beam];
|
|
|
|
|
for (int aatx = 0; aatx < nbAnt; aatx++) {
|
|
|
|
|
samples[beam][aatx] = samplesVoid[beam][aatx];
|
|
|
|
|
}
|
|
|
|
|
sample_t *samples[nbAnt];
|
|
|
|
|
for (int aatx = 0; aatx < nbAnt; aatx++) {
|
|
|
|
|
samples[aatx] = (sample_t *)samplesVoid[aatx];
|
|
|
|
|
}
|
|
|
|
|
while (nsamps > 0) {
|
|
|
|
|
uint32_t nsamps_beam_map;
|
|
|
|
|
std::vector<int> beams = get_beams(&t->beam_ctrl->tx, timestamp, nsamps, &nsamps_beam_map);
|
|
|
|
|
rfsimulator_write_internal(t, timestamp, samples_ptr, nsamps_beam_map, nbAnt, beams, flags);
|
|
|
|
|
for (int beam = 0; beam < num_beams; beam++) {
|
|
|
|
|
for (int aatx = 0; aatx < nbAnt; aatx++) {
|
|
|
|
|
char *ptr = (char *)samples_ptr[beam][aatx];
|
|
|
|
|
samples_ptr[beam][aatx] = (void *)(ptr + nsamps_beam_map * sizeof(sample_t));
|
|
|
|
|
}
|
|
|
|
|
std::vector<uint16_t> tx_beams = get_beams(&t->beam_ctrl->tx, timestamp, nsamps, &nsamps_beam_map);
|
|
|
|
|
if (t->beam_ctrl->enable_beams && (int)tx_beams.size() != nbAnt) {
|
|
|
|
|
LOG_W(HW, "Number of beams does not match application request nbAnt %d, beams %lu\n", nbAnt, tx_beams.size());
|
|
|
|
|
}
|
|
|
|
|
while ((int)tx_beams.size() < nbAnt)
|
|
|
|
|
tx_beams.push_back(0);
|
|
|
|
|
|
|
|
|
|
rfsimulator_write_internal(t, timestamp, samples, nsamps_beam_map, nbAnt, tx_beams, flags);
|
|
|
|
|
for (int aatx = 0; aatx < nbAnt; aatx++) {
|
|
|
|
|
samples[aatx] += nsamps_beam_map;
|
|
|
|
|
}
|
|
|
|
|
timestamp += nsamps_beam_map;
|
|
|
|
|
nsamps -= nsamps_beam_map;
|
|
|
|
|
@@ -1046,12 +969,6 @@ static int rfsimulator_write_beams(openair0_device_t *device,
|
|
|
|
|
return nsamps_initial;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rfsimulator_write(openair0_device_t *device, openair0_timestamp_t timestamp, void **buff, int nsamps, int cc, int flags)
|
|
|
|
|
{
|
|
|
|
|
void **tmp = buff;
|
|
|
|
|
return rfsimulator_write_beams(device, timestamp, &tmp, nsamps, cc, 1, flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool add_client(rfsimulator_state_t *t)
|
|
|
|
|
{
|
|
|
|
|
struct sockaddr_storage sa = {0};
|
|
|
|
|
@@ -1075,13 +992,17 @@ static bool add_client(rfsimulator_state_t *t)
|
|
|
|
|
getnameinfo((struct sockaddr *)&sa, socklen, ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
|
|
|
|
|
uint16_t port = ((struct sockaddr_in *)&sa)->sin_port;
|
|
|
|
|
LOG_I(HW, "Client connects from %s:%d\n", ip, port);
|
|
|
|
|
c16_t v = {0};
|
|
|
|
|
void *samplesVoid[t->tx_num_channels];
|
|
|
|
|
for (int i = 0; i < t->tx_num_channels; i++)
|
|
|
|
|
samplesVoid[i] = (void *)&v;
|
|
|
|
|
samplesBlockHeader_t header = {1, (uint32_t)t->tx_num_channels, (uint64_t)t->lastWroteTS, 0, 0, 1};
|
|
|
|
|
samplesBlockHeader_t header = {1, (uint32_t)t->tx_num_channels, (uint64_t)t->lastWroteTS, 0, 0};
|
|
|
|
|
|
|
|
|
|
fullwrite(conn_sock, &header, sizeof(header), t);
|
|
|
|
|
fullwrite(conn_sock, samplesVoid, sampleToByte(1, t->tx_num_channels), t);
|
|
|
|
|
uint16_t beam_ids[t->tx_num_channels];
|
|
|
|
|
for (int i = 0; i < t->tx_num_channels; i++)
|
|
|
|
|
beam_ids[i] = 0;
|
|
|
|
|
fullwrite(conn_sock, beam_ids, sizeof(beam_ids), t);
|
|
|
|
|
|
|
|
|
|
c16_t v[t->rx_num_channels];
|
|
|
|
|
memset(v, 0, sizeof(v));
|
|
|
|
|
fullwrite(conn_sock, v, sizeof(v), t);
|
|
|
|
|
|
|
|
|
|
if (new_buf->channel_model)
|
|
|
|
|
new_buf->channel_model->start_TS = t->lastWroteTS;
|
|
|
|
|
@@ -1089,7 +1010,7 @@ static bool add_client(rfsimulator_state_t *t)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void process_recv_header(rfsimulator_state_t *t, buffer_t *b, bool first_time)
|
|
|
|
|
static void process_recv_header(buffer_t *b, bool first_time)
|
|
|
|
|
{
|
|
|
|
|
b->headerMode = false; // We got the header
|
|
|
|
|
AssertFatal(b->th.nbAnt != 0, "Number of antennas not set\n");
|
|
|
|
|
@@ -1112,14 +1033,12 @@ static void process_recv_header(rfsimulator_state_t *t, buffer_t *b, bool first_
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int num_beams = __builtin_popcountll(b->th.beam_map);
|
|
|
|
|
AssertFatal(b->th.beam_map == 1ULL || t->beam_ctrl->enable_beams == 1,
|
|
|
|
|
"The transmitter has enabled beam simulation while this receiver has not\n");
|
|
|
|
|
size_t payload_sz = sampleToByte(b->th.size, b->th.nbAnt) * num_beams;
|
|
|
|
|
b->packet_ptr = static_cast<rfsim_packet_t *>(calloc_or_fail(1, payload_sz + sizeof(samplesBlockHeader_t)));
|
|
|
|
|
size_t beam_payload_size = b->th.nbAnt * sizeof(uint16_t);
|
|
|
|
|
size_t payload_sz = sampleToByte(b->th.size, b->th.nbAnt);
|
|
|
|
|
b->packet_ptr = static_cast<rfsim_packet_t *>(malloc(beam_payload_size + payload_sz + sizeof(samplesBlockHeader_t)));
|
|
|
|
|
b->packet_ptr->header = b->th;
|
|
|
|
|
b->transferPtr = b->packet_ptr->payload;
|
|
|
|
|
b->remainToTransfer = payload_sz;
|
|
|
|
|
b->remainToTransfer = payload_sz + beam_payload_size;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1163,9 +1082,10 @@ static void combine_received_beams(rfsimulator_state_t *t,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The beams transmitted in are ordered by beam index
|
|
|
|
|
std::vector<int> tx_beams = beam_map_to_beams(pkt->header.beam_map);
|
|
|
|
|
for (uint beam = 0; beam < tx_beams.size(); beam++) {
|
|
|
|
|
float gain_dB = get_rx_gain_db(t, rx_beam_id, tx_beams[beam]);
|
|
|
|
|
uint16_t *beams = (uint16_t *)pkt->payload;
|
|
|
|
|
for (uint aatx = 0; aatx < pkt->header.nbAnt; aatx++) {
|
|
|
|
|
int beam = beams[aatx];
|
|
|
|
|
float gain_dB = get_rx_gain_db(t, rx_beam_id, beam);
|
|
|
|
|
float gain_linear = powf(10, gain_dB / 20.0);
|
|
|
|
|
uint64_t overlap_start = std::max(start_timestamp, pkt->header.timestamp);
|
|
|
|
|
uint64_t overlap_end = std::min(start_timestamp + num_samples, pkt->header.timestamp + pkt->header.size);
|
|
|
|
|
@@ -1173,35 +1093,12 @@ static void combine_received_beams(rfsimulator_state_t *t,
|
|
|
|
|
int write_end_idx = overlap_end - start_timestamp;
|
|
|
|
|
int read_start_idx = overlap_start - pkt->header.timestamp;
|
|
|
|
|
for (int aatx = 0; aatx < num_aatx; aatx++) {
|
|
|
|
|
c16_t *buffer = (c16_t *)pkt->payload;
|
|
|
|
|
c16_t *buffer = (c16_t *)&pkt->payload[sizeof(uint16_t) * pkt->header.nbAnt];
|
|
|
|
|
c16_t *tx_ant_buffer_in = &buffer[(num_aatx * beam + aatx) * pkt->header.size + read_start_idx];
|
|
|
|
|
if (beam == 0) {
|
|
|
|
|
// For the first beam, we can directly copy the samples
|
|
|
|
|
if (gain_dB == 0.0f) {
|
|
|
|
|
// If gain is 0 dB, we can use memcpy for efficiency
|
|
|
|
|
memcpy(&samples[aatx][write_start_idx], tx_ant_buffer_in, (write_end_idx - write_start_idx) * sizeof(c16_t));
|
|
|
|
|
} else {
|
|
|
|
|
for (int s = write_start_idx; s < write_end_idx; s++) {
|
|
|
|
|
samples[aatx][s].r = tx_ant_buffer_in->r * gain_linear;
|
|
|
|
|
samples[aatx][s].i = tx_ant_buffer_in->i * gain_linear;
|
|
|
|
|
tx_ant_buffer_in++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// For subsequent beams, we need to ensure we accumulate the samples
|
|
|
|
|
if (gain_dB == 0.0f) {
|
|
|
|
|
for (int s = write_start_idx; s < write_end_idx; s++) {
|
|
|
|
|
samples[aatx][s].r += tx_ant_buffer_in->r;
|
|
|
|
|
samples[aatx][s].i += tx_ant_buffer_in->i;
|
|
|
|
|
tx_ant_buffer_in++;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (int s = write_start_idx; s < write_end_idx; s++) {
|
|
|
|
|
samples[aatx][s].r += tx_ant_buffer_in->r * gain_linear;
|
|
|
|
|
samples[aatx][s].i += tx_ant_buffer_in->i * gain_linear;
|
|
|
|
|
tx_ant_buffer_in++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int s = write_start_idx; s < write_end_idx; s++) {
|
|
|
|
|
samples[aatx][s].r += tx_ant_buffer_in->r * gain_linear;
|
|
|
|
|
samples[aatx][s].i += tx_ant_buffer_in->i * gain_linear;
|
|
|
|
|
tx_ant_buffer_in++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1253,7 +1150,7 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, bool first_time)
|
|
|
|
|
b->transferPtr += sz;
|
|
|
|
|
if (b->remainToTransfer == 0) {
|
|
|
|
|
if (b->headerMode)
|
|
|
|
|
process_recv_header(t, b, first_time);
|
|
|
|
|
process_recv_header(b, first_time);
|
|
|
|
|
else {
|
|
|
|
|
LOG_D(HW, "UEsock: %d Completed block reception: %ld\n", b->conn_sock, b->lastReceivedTS);
|
|
|
|
|
b->headerMode = true;
|
|
|
|
|
@@ -1276,17 +1173,15 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, bool first_time)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void rfsimulator_read_internal(rfsimulator_state_t *t,
|
|
|
|
|
c16_t **samples,
|
|
|
|
|
sample_t **samples,
|
|
|
|
|
openair0_timestamp_t timestamp,
|
|
|
|
|
int nsamps,
|
|
|
|
|
int nbAnt,
|
|
|
|
|
int rx_beam_id,
|
|
|
|
|
bool is_first_beam)
|
|
|
|
|
std::vector<uint16_t> rx_beams)
|
|
|
|
|
{
|
|
|
|
|
cf_t temp_array[nbAnt][nsamps];
|
|
|
|
|
bool channel_modelling = false;
|
|
|
|
|
// Add all input nodes signal in the output buffer
|
|
|
|
|
bool is_first_peer = true;
|
|
|
|
|
for (int sock = 0; sock < MAX_FD_RFSIMU; sock++) {
|
|
|
|
|
buffer_t *ptr = &t->buf[sock];
|
|
|
|
|
|
|
|
|
|
@@ -1312,46 +1207,64 @@ static void rfsimulator_read_internal(rfsimulator_state_t *t,
|
|
|
|
|
input[aatx] = ant_buffers[aatx].data();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
combine_received_beams(t,
|
|
|
|
|
ptr->received_packets,
|
|
|
|
|
timestamp - channel_offset - (channel_length - 1),
|
|
|
|
|
ptr->nbAnt,
|
|
|
|
|
nsamps + channel_length - 1,
|
|
|
|
|
rx_beam_id,
|
|
|
|
|
input);
|
|
|
|
|
|
|
|
|
|
for (int aarx = 0; aarx < nbAnt; aarx++) {
|
|
|
|
|
combine_received_beams(t,
|
|
|
|
|
ptr->received_packets,
|
|
|
|
|
timestamp - channel_offset - (channel_length - 1),
|
|
|
|
|
ptr->nbAnt,
|
|
|
|
|
nsamps + channel_length - 1,
|
|
|
|
|
rx_beams[aarx],
|
|
|
|
|
input);
|
|
|
|
|
|
|
|
|
|
rxAddInput(input, temp_array[aarx], aarx, ptr->channel_model, nsamps);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (is_first_beam && is_first_peer && (ptr->nbAnt == 1 || nbAnt == 1)) {
|
|
|
|
|
// optimization: The buffer is uninitialized so samples can be written directly in the buffer
|
|
|
|
|
combine_received_beams(t, ptr->received_packets, timestamp - t->chan_offset, 1, nsamps, rx_beam_id, samples);
|
|
|
|
|
} else {
|
|
|
|
|
std::vector<std::vector<c16_t>> ant_buffers(ptr->nbAnt, std::vector<c16_t>(nsamps, {0, 0}));
|
|
|
|
|
c16_t *input[ant_buffers.size()];
|
|
|
|
|
for (uint aatx = 0; aatx < ant_buffers.size(); aatx++) {
|
|
|
|
|
input[aatx] = ant_buffers[aatx].data();
|
|
|
|
|
// Assume received_packets is ordered by timestamp
|
|
|
|
|
std::queue<rfsim_packet_t *> packets_copy = ptr->received_packets;
|
|
|
|
|
while (!packets_copy.empty()) {
|
|
|
|
|
rfsim_packet_t *pkt = packets_copy.front();
|
|
|
|
|
if (static_cast<int64_t>(pkt->header.timestamp + pkt->header.size) <= timestamp) {
|
|
|
|
|
// This packet is before the start timestamp, discard it
|
|
|
|
|
packets_copy.pop();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
combine_received_beams(t, ptr->received_packets, timestamp - t->chan_offset, ptr->nbAnt, nsamps, rx_beam_id, input);
|
|
|
|
|
if (static_cast<int64_t>(pkt->header.timestamp) > timestamp + nsamps) {
|
|
|
|
|
// This packet is after the end of the buffer, stop processing
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The beams transmitted in are ordered by beam index
|
|
|
|
|
uint16_t *tx_beams = (uint16_t *)pkt->payload;
|
|
|
|
|
uint64_t overlap_start = std::max(timestamp, static_cast<int64_t>(pkt->header.timestamp));
|
|
|
|
|
uint64_t overlap_end = std::min(timestamp + nsamps, static_cast<int64_t>(pkt->header.timestamp + pkt->header.size));
|
|
|
|
|
int write_start_idx = overlap_start - timestamp;
|
|
|
|
|
int write_end_idx = overlap_end - timestamp;
|
|
|
|
|
int read_start_idx = overlap_start - pkt->header.timestamp;
|
|
|
|
|
c16_t *buffer = (c16_t *)&pkt->payload[sizeof(uint16_t) * pkt->header.nbAnt];
|
|
|
|
|
|
|
|
|
|
for (int aarx = 0; aarx < nbAnt; aarx++) {
|
|
|
|
|
double H_awgn_mimo_coeff[ant_buffers.size()];
|
|
|
|
|
for (int aatx = 0; aatx < (int)ant_buffers.size(); aatx++) {
|
|
|
|
|
double H_awgn_mimo_coeff[pkt->header.nbAnt];
|
|
|
|
|
for (int aatx = 0; aatx < (int)pkt->header.nbAnt; aatx++) {
|
|
|
|
|
uint32_t ant_diff = std::abs(aatx - aarx);
|
|
|
|
|
H_awgn_mimo_coeff[aatx] = ant_diff ? (0.2 / ant_diff) : 1.0;
|
|
|
|
|
float gain_dB = get_rx_gain_db(t, rx_beams[aarx], tx_beams[aatx]);
|
|
|
|
|
float gain_linear = powf(10, gain_dB / 20.0);
|
|
|
|
|
H_awgn_mimo_coeff[aatx] *= gain_linear;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (uint aatx = 0; aatx < ant_buffers.size(); aatx++) {
|
|
|
|
|
for (int i = 0; i < nsamps; i++) {
|
|
|
|
|
samples[aarx][i].r += ant_buffers[aatx][i].r * H_awgn_mimo_coeff[aatx];
|
|
|
|
|
samples[aarx][i].i += ant_buffers[aatx][i].i * H_awgn_mimo_coeff[aatx];
|
|
|
|
|
for (uint aatx = 0; aatx < pkt->header.nbAnt; aatx++) {
|
|
|
|
|
c16_t *tx_ant_buffer_in = &buffer[aatx * pkt->header.size + read_start_idx];
|
|
|
|
|
for (int i = write_start_idx; i < write_end_idx; i++) {
|
|
|
|
|
samples[aarx][i].r += tx_ant_buffer_in->r * H_awgn_mimo_coeff[aatx];
|
|
|
|
|
samples[aarx][i].i += tx_ant_buffer_in->i * H_awgn_mimo_coeff[aatx];
|
|
|
|
|
tx_ant_buffer_in++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
packets_copy.pop();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
is_first_peer = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool apply_global_noise = get_noise_power_dBFS() != INVALID_DBFS_VALUE;
|
|
|
|
|
@@ -1379,12 +1292,7 @@ static void rfsimulator_read_internal(rfsimulator_state_t *t,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rfsimulator_read_beams(openair0_device_t *device,
|
|
|
|
|
openair0_timestamp_t *ptimestamp,
|
|
|
|
|
void ***samplesVoid,
|
|
|
|
|
int nsamps,
|
|
|
|
|
int nbAnt,
|
|
|
|
|
int num_beams)
|
|
|
|
|
static int rfsimulator_read(openair0_device_t *device, openair0_timestamp_t *ptimestamp, void **samplesVoid, int nsamps, int nbAnt)
|
|
|
|
|
{
|
|
|
|
|
rfsimulator_state_t *t = static_cast<rfsimulator_state_t *>(device->priv);
|
|
|
|
|
LOG_D(HW,
|
|
|
|
|
@@ -1407,9 +1315,8 @@ static int rfsimulator_read_beams(openair0_device_t *device,
|
|
|
|
|
LOG_I(HW, "No connected device, generating void samples...\n");
|
|
|
|
|
|
|
|
|
|
if (!flushInput(t, t->wait_timeout, false)) {
|
|
|
|
|
for (int beam = 0; beam < num_beams; beam++)
|
|
|
|
|
for (int x = 0; x < nbAnt; x++)
|
|
|
|
|
memset(samplesVoid[beam][x], 0, sampleToByte(nsamps, 1));
|
|
|
|
|
for (int x = 0; x < nbAnt; x++)
|
|
|
|
|
memset(samplesVoid[x], 0, sampleToByte(nsamps, 1));
|
|
|
|
|
|
|
|
|
|
t->nextRxTstamp += nsamps;
|
|
|
|
|
|
|
|
|
|
@@ -1458,43 +1365,29 @@ static int rfsimulator_read_beams(openair0_device_t *device,
|
|
|
|
|
t->poll_telnetcmdq(t->telnetcmd_qid, t);
|
|
|
|
|
|
|
|
|
|
// Clear the output buffer
|
|
|
|
|
for (int beam = 0; beam < num_beams; beam++)
|
|
|
|
|
for (int a = 0; a < nbAnt; a++)
|
|
|
|
|
memset(samplesVoid[beam][a], 0, sampleToByte(nsamps, 1));
|
|
|
|
|
for (int a = 0; a < nbAnt; a++)
|
|
|
|
|
memset(samplesVoid[a], 0, sampleToByte(nsamps, 1));
|
|
|
|
|
|
|
|
|
|
openair0_timestamp_t timestamp = t->nextRxTstamp;
|
|
|
|
|
sample_t **samples = (sample_t **)samplesVoid;
|
|
|
|
|
int nsamps_to_process = nsamps;
|
|
|
|
|
while (nsamps_to_process > 0) {
|
|
|
|
|
uint32_t nsamps_beam_map;
|
|
|
|
|
std::vector<int> rx_beams = get_beams(&t->beam_ctrl->tx, timestamp, nsamps_to_process, &nsamps_beam_map);
|
|
|
|
|
if ((int)rx_beams.size() != num_beams) {
|
|
|
|
|
LOG_D(HW,
|
|
|
|
|
"Number of beams does not match application request num_beams %d, beam_map beams %lu\n",
|
|
|
|
|
num_beams,
|
|
|
|
|
rx_beams.size());
|
|
|
|
|
std::vector<uint16_t> rx_beams = get_beams(&t->beam_ctrl->tx, timestamp, nsamps_to_process, &nsamps_beam_map);
|
|
|
|
|
if (t->beam_ctrl->enable_beams && (int)rx_beams.size() != nbAnt) {
|
|
|
|
|
LOG_D(HW, "Number of beams does not match application request nbAnt %d, beams %lu\n", nbAnt, rx_beams.size());
|
|
|
|
|
}
|
|
|
|
|
for (int beam = 0; beam < num_beams && beam < (int)rx_beams.size(); beam++) {
|
|
|
|
|
c16_t *samples_beam[nbAnt];
|
|
|
|
|
for (int i = 0; i < nbAnt; i++) {
|
|
|
|
|
samples_beam[i] = (c16_t *)samplesVoid[beam][i] + timestamp - t->nextRxTstamp;
|
|
|
|
|
}
|
|
|
|
|
rfsimulator_read_internal(t, samples_beam, timestamp, nsamps_beam_map, nbAnt, rx_beams[beam], beam == 0);
|
|
|
|
|
while ((int)rx_beams.size() < nbAnt)
|
|
|
|
|
rx_beams.push_back(0);
|
|
|
|
|
|
|
|
|
|
rfsimulator_read_internal(t, samples, timestamp, nsamps_beam_map, nbAnt, rx_beams);
|
|
|
|
|
for (int a = 0; a < nbAnt; a++) {
|
|
|
|
|
samples[0] += timestamp - t->nextRxTstamp;
|
|
|
|
|
}
|
|
|
|
|
timestamp += nsamps_beam_map;
|
|
|
|
|
nsamps_to_process -= nsamps_beam_map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct timespec end_time;
|
|
|
|
|
ret = clock_gettime(CLOCK_REALTIME, &end_time);
|
|
|
|
|
AssertFatal(ret == 0, "clock_gettime() failed: errno %d, %s\n", errno, strerror(errno));
|
|
|
|
|
double diff_ns = (end_time.tv_sec - start_time.tv_sec) * 1000000000 + (end_time.tv_nsec - start_time.tv_nsec);
|
|
|
|
|
static double average = 0.0;
|
|
|
|
|
average = (average * 0.98) + (nsamps / (diff_ns / 1e9) * 0.02);
|
|
|
|
|
static int calls = 0;
|
|
|
|
|
if (calls++ % 10000 == 0) {
|
|
|
|
|
LOG_D(HW, "Rfsimulator: velocity %.2f Msps, realtime requirements %.2f Msps\n", average / 1e6, t->sample_rate / 1e6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*ptimestamp = t->nextRxTstamp; // return the time of the first sample
|
|
|
|
|
t->nextRxTstamp += nsamps;
|
|
|
|
|
clear_beam_queue(&t->beam_ctrl->rx, t->nextRxTstamp);
|
|
|
|
|
@@ -1503,7 +1396,7 @@ static int rfsimulator_read_beams(openair0_device_t *device,
|
|
|
|
|
nsamps,
|
|
|
|
|
*ptimestamp,
|
|
|
|
|
t->nextRxTstamp,
|
|
|
|
|
signal_energy(static_cast<int32_t *>(samplesVoid[0][0]), nsamps));
|
|
|
|
|
signal_energy_nodc(samples[0], nsamps));
|
|
|
|
|
|
|
|
|
|
/* trace only first antenna */
|
|
|
|
|
T(T_USRP_RX_ANT0, T_INT(t->nextRxTstamp), T_BUFFER(samplesVoid[0], (int)sampleToByte(nsamps, 1)));
|
|
|
|
|
@@ -1526,21 +1419,18 @@ static int rfsimulator_read_beams(openair0_device_t *device,
|
|
|
|
|
return nsamps;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rfsimulator_read(openair0_device_t *device, openair0_timestamp_t *ptimestamp, void **samplesVoid, int nsamps, int nbAnt)
|
|
|
|
|
{
|
|
|
|
|
return rfsimulator_read_beams(device, ptimestamp, &samplesVoid, nsamps, nbAnt, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rfsimulator_get_stats(openair0_device_t *device)
|
|
|
|
|
{
|
|
|
|
|
UNUSED(device);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int rfsimulator_reset_stats(openair0_device_t *device)
|
|
|
|
|
{
|
|
|
|
|
UNUSED(device);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void rfsimulator_end(openair0_device_t *device)
|
|
|
|
|
{
|
|
|
|
|
rfsimulator_state_t *s = static_cast<rfsimulator_state_t *>(device->priv);
|
|
|
|
|
@@ -1621,18 +1511,14 @@ extern "C" __attribute__((__visibility__("default"))) int device_init(openair0_d
|
|
|
|
|
device->trx_set_gains_func = rfsimulator_set_gains;
|
|
|
|
|
device->trx_write_func = rfsimulator_write;
|
|
|
|
|
device->trx_read_func = rfsimulator_read;
|
|
|
|
|
if (rfsimulator->beam_ctrl->enable_beams) {
|
|
|
|
|
device->trx_write_beams_func = rfsimulator_write_beams;
|
|
|
|
|
device->trx_read_beams_func = rfsimulator_read_beams;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* let's pretend to be a b2x0 */
|
|
|
|
|
device->type = RFSIMULATOR;
|
|
|
|
|
openair0_cfg->rx_gain[0] = 0;
|
|
|
|
|
device->openair0_cfg = openair0_cfg;
|
|
|
|
|
device->priv = rfsimulator;
|
|
|
|
|
device->trx_write_init = rfsimulator_write_init;
|
|
|
|
|
device->trx_set_beams = rfsimulator_set_beams;
|
|
|
|
|
device->trx_set_beams2 = rfsimulator_set_beams_vector;
|
|
|
|
|
device->trx_set_beams = rfsimulator_set_beams_vector;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_FD_RFSIMU; i++)
|
|
|
|
|
rfsimulator->buf[i].conn_sock = -1;
|
|
|
|
|
|