You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
6.7 KiB
C++

/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include <unistd.h>
#include "srsran/common/threads.h"
#include "srsran/srsran.h"
#include "srsenb/hdr/phy/txrx.h"
#define Error(fmt, ...) \
if (SRSRAN_DEBUG_ENABLED) \
logger.error(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) \
if (SRSRAN_DEBUG_ENABLED) \
logger.warning(fmt, ##__VA_ARGS__)
#define Info(fmt, ...) \
if (SRSRAN_DEBUG_ENABLED) \
logger.info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) \
if (SRSRAN_DEBUG_ENABLED) \
logger.debug(fmt, ##__VA_ARGS__)
using namespace std;
namespace srsenb {
txrx::txrx(srslog::basic_logger& logger) : thread("TXRX"), logger(logger), running(false)
{
/* Do nothing */
}
bool txrx::init(stack_interface_phy_lte* stack_,
srsran::radio_interface_phy* radio_h_,
lte::worker_pool* lte_workers_,
nr::worker_pool* nr_workers_,
phy_common* worker_com_,
prach_worker_pool* prach_,
uint32_t prio_)
{
stack = stack_;
radio_h = radio_h_;
lte_workers = lte_workers_;
nr_workers = nr_workers_;
worker_com = worker_com_;
prach = prach_;
tx_worker_cnt = 0;
running = true;
nof_workers = lte_workers->get_nof_workers();
// Instantiate UL channel emulator
if (worker_com->params.ul_channel_args.enable) {
ul_channel = srsran::channel_ptr(
new srsran::channel(worker_com->params.ul_channel_args, worker_com->get_nof_rf_channels(), logger));
}
start(prio_);
return true;
}
void txrx::stop()
{
if (running) {
running = false;
wait_thread_finish();
}
}
void txrx::run_thread()
{
srsran::rf_buffer_t buffer = {};
srsran::rf_timestamp_t timestamp = {};
uint32_t sf_len = SRSRAN_SF_LEN_PRB(worker_com->get_nof_prb(0));
float samp_rate = srsran_sampling_freq_hz(worker_com->get_nof_prb(0));
// Configure radio
radio_h->set_rx_srate(samp_rate);
radio_h->set_tx_srate(samp_rate);
// Set Tx/Rx frequencies
for (uint32_t cc_idx = 0; cc_idx < worker_com->get_nof_carriers(); cc_idx++) {
double tx_freq_hz = worker_com->get_dl_freq_hz(cc_idx);
double rx_freq_hz = worker_com->get_ul_freq_hz(cc_idx);
uint32_t rf_port = worker_com->get_rf_port(cc_idx);
srsran::console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz for cc_idx=%d nof_prb=%d\n",
tx_freq_hz / 1e6f,
rx_freq_hz / 1e6f,
cc_idx,
worker_com->get_nof_prb(cc_idx));
radio_h->set_tx_freq(rf_port, tx_freq_hz);
radio_h->set_rx_freq(rf_port, rx_freq_hz);
}
// Set channel emulator sampling rate
if (ul_channel) {
ul_channel->set_srate(static_cast<uint32_t>(samp_rate));
}
logger.info("Starting RX/TX thread nof_prb=%d, sf_len=%d", worker_com->get_nof_prb(0), sf_len);
// Set TTI so that first TX is at tti=0
tti = TTI_SUB(0, FDD_HARQ_DELAY_UL_MS + 1);
// Main loop
while (running) {
tti = TTI_ADD(tti, 1);
logger.set_context(tti);
lte::sf_worker* lte_worker = nullptr;
if (worker_com->get_nof_carriers_lte() > 0) {
lte_worker = lte_workers->wait_worker(tti);
if (lte_worker == nullptr) {
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here
running = false;
continue;
}
}
nr::sf_worker* nr_worker = nullptr;
if (worker_com->get_nof_carriers_nr() > 0) {
nr_worker = nr_workers->wait_worker(tti);
if (nr_worker == nullptr) {
running = false;
continue;
}
}
// Multiple cell buffer mapping
{
uint32_t cc = 0;
for (uint32_t cc_lte = 0; cc_lte < worker_com->get_nof_carriers_lte(); cc_lte++, cc++) {
uint32_t rf_port = worker_com->get_rf_port(cc);
for (uint32_t p = 0; p < worker_com->get_nof_ports(cc); p++) {
// WARNING: The number of ports for all cells must be the same
buffer.set(rf_port, p, worker_com->get_nof_ports(0), lte_worker->get_buffer_rx(cc_lte, p));
}
}
for (uint32_t cc_nr = 0; cc_nr < worker_com->get_nof_carriers_lte(); cc_nr++, cc++) {
uint32_t rf_port = worker_com->get_rf_port(cc);
for (uint32_t p = 0; p < worker_com->get_nof_ports(cc); p++) {
// WARNING: The number of ports for all cells must be the same
buffer.set(rf_port, p, worker_com->get_nof_ports(0), nr_worker->get_buffer_rx(cc_nr, p));
}
}
}
buffer.set_nof_samples(sf_len);
radio_h->rx_now(buffer, timestamp);
if (ul_channel) {
ul_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), sf_len, timestamp.get(0));
}
// Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time
timestamp.add(FDD_HARQ_DELAY_UL_MS * 1e-3);
Debug("Setting TTI=%d, tx_mutex=%d, tx_time=%ld:%f to worker %d",
tti,
tx_worker_cnt,
timestamp.get(0).full_secs,
timestamp.get(0).frac_secs,
lte_worker->get_id());
lte_worker->set_time(tti, tx_worker_cnt, timestamp);
tx_worker_cnt = (tx_worker_cnt + 1) % nof_workers;
// Trigger prach worker execution
for (uint32_t cc = 0; cc < worker_com->get_nof_carriers_lte(); cc++) {
prach->new_tti(cc, tti, buffer.get(worker_com->get_rf_port(cc), 0, worker_com->get_nof_ports(0)));
}
// Launch NR worker only if available
if (nr_worker != nullptr) {
nr_worker->set_tti(tti);
worker_com->semaphore.push(nr_worker);
nr_workers->start_worker(nr_worker);
}
// Trigger phy worker execution
worker_com->semaphore.push(lte_worker);
lte_workers->start_worker(lte_worker);
// Advance stack in time
stack->tti_clock();
}
}
} // namespace srsenb