mirror of https://github.com/pvnis/srsRAN_4G.git
Remove radio_multi class and organize channels, ports and carrier buffers (#1019)
parent
ecb22600ff
commit
4e12405fff
@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: common_interfaces.h
|
||||
* Description: Common interface for eNB/UE for PHY and radio
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SRSLTE_COMMON_INTERFACES_H
|
||||
#define SRSLTE_COMMON_INTERFACES_H
|
||||
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/common/timestamp.h"
|
||||
#include "srslte/phy/rf/rf.h"
|
||||
|
||||
namespace srslte {
|
||||
|
||||
class radio_interface_phy
|
||||
{
|
||||
public:
|
||||
// trx functions
|
||||
virtual bool tx(const uint32_t& radio_idx,
|
||||
cf_t* buffer[SRSLTE_MAX_PORTS],
|
||||
const uint32_t& nof_samples,
|
||||
const srslte_timestamp_t& tx_time) = 0;
|
||||
virtual void tx_end() = 0;
|
||||
virtual bool rx_now(const uint32_t& radio_idx,
|
||||
cf_t* buffer[SRSLTE_MAX_PORTS],
|
||||
const uint32_t& nof_samples,
|
||||
srslte_timestamp_t* rxd_time) = 0;
|
||||
|
||||
// setter
|
||||
virtual void set_tx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) = 0;
|
||||
virtual void set_rx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) = 0;
|
||||
|
||||
virtual void set_rx_gain_th(const float& gain) = 0;
|
||||
virtual void set_rx_gain(const uint32_t& radio_idx, const float& gain) = 0;
|
||||
virtual void set_tx_srate(const uint32_t& radio_idx, const double& srate) = 0;
|
||||
virtual void set_rx_srate(const uint32_t& radio_idx, const double& srate) = 0;
|
||||
|
||||
// getter
|
||||
virtual float get_rx_gain(const uint32_t& radio_idx) = 0;
|
||||
virtual double get_freq_offset() = 0;
|
||||
virtual double get_tx_freq(const uint32_t& radio_idx) = 0;
|
||||
virtual double get_rx_freq(const uint32_t& radio_idx) = 0;
|
||||
virtual float get_max_tx_power() = 0;
|
||||
virtual float get_tx_gain_offset() = 0;
|
||||
virtual float get_rx_gain_offset() = 0;
|
||||
virtual bool is_continuous_tx() = 0;
|
||||
virtual bool get_is_start_of_burst(const uint32_t& radio_idx) = 0;
|
||||
virtual bool is_init() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual srslte_rf_info_t* get_info(const uint32_t& radio_idx) = 0;
|
||||
};
|
||||
|
||||
class phy_interface_radio
|
||||
{
|
||||
public:
|
||||
virtual void radio_overflow() = 0;
|
||||
virtual void radio_failure() = 0;
|
||||
};
|
||||
|
||||
} // namespace srslte
|
||||
|
||||
#endif // SRSLTE_COMMON_INTERFACES_H
|
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: radio_interfaces.h
|
||||
* Description: Common interface for eNB/UE for PHY and radio
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SRSLTE_RADIO_INTERFACES_H
|
||||
#define SRSLTE_RADIO_INTERFACES_H
|
||||
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/common/timestamp.h"
|
||||
#include "srslte/phy/rf/rf.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
#include <array>
|
||||
|
||||
namespace srslte {
|
||||
|
||||
/**
|
||||
* Class used to pass buffers for all channels and antennas to the radio
|
||||
*
|
||||
* The class provides an abstraction to map carriers and antennas to the underlying
|
||||
* RF channels. It provides getters and setters to access the raw pointers where the signal
|
||||
* is stored.
|
||||
*
|
||||
* It can automatically allocate and deallocate memory for the buffers if
|
||||
* a non-zero number of subframes is passed to the constructor.
|
||||
*
|
||||
*/
|
||||
class rf_buffer_interface
|
||||
{
|
||||
public:
|
||||
virtual cf_t* get(uint32_t channel_idx) const = 0;
|
||||
virtual void set(uint32_t channel_idx, cf_t* ptr) = 0;
|
||||
virtual cf_t* get(uint32_t cc_idx, uint32_t port_idx, uint32_t nof_antennas) const = 0;
|
||||
virtual void set(uint32_t cc_idx, uint32_t port_idx, uint32_t nof_antennas, cf_t* ptr) = 0;
|
||||
virtual void** to_void() = 0;
|
||||
virtual cf_t** to_cf_t() = 0;
|
||||
virtual uint32_t size() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Radio interface for the PHY.
|
||||
*
|
||||
* The main functionality is to allow TX and RX of samples to the radio.
|
||||
* It also provides functions to change the radio settings such as carrier frequency,
|
||||
* sampling rate, gains, etc.
|
||||
*
|
||||
* The radio interface supports multiple carriers and multiple antennas per carrier. This interface presents an
|
||||
* abstract access to carries and ports to the PHY, regardless of the mapping to RF channels in the underlying radio.
|
||||
* number of carriers <= SRSLTE_MAX_CARRIERS
|
||||
* number of ports <= SRSLTE_MAX_PORTS
|
||||
*
|
||||
* Changing the tx/rx frequency is done on a carrier level and the underlying implementation
|
||||
* will set it for all ports when necessary.
|
||||
*
|
||||
* Samples are passed and received to/from the radio using rf_buffer_t object
|
||||
* @see rf_buffer_t
|
||||
* @see radio
|
||||
*/
|
||||
class radio_interface_phy
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Indicates the end of a burst in the current TX stream. Usually called after a call to tx() if
|
||||
* no more samples are needed to be transmitted.
|
||||
*/
|
||||
virtual void tx_end() = 0;
|
||||
/**
|
||||
* Indicates the radio to transmit on all antennas and carriers synchronously the samples contained in
|
||||
* the buffer object.
|
||||
*
|
||||
* @param buffer Is the object that contains the pointers to all RF channels
|
||||
* @param nof_samples Number of samples to transmit on all carriers and antennas
|
||||
* @param tx_time Time to transmit all signals
|
||||
* @return
|
||||
*/
|
||||
virtual bool tx(rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time) = 0;
|
||||
|
||||
/**
|
||||
* Indicates the radio to receive from all antennas and carriers synchronously and store the samples
|
||||
* in the buffer object
|
||||
*
|
||||
* @param buffer Is the object where the samples will be stored
|
||||
* @param nof_samples Number of samples to receive from all carriers and antennas
|
||||
* @param tx_time Time at which the samples were received. Note the time is the same for all carriers
|
||||
* @return
|
||||
*/
|
||||
virtual bool rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time) = 0;
|
||||
|
||||
/**
|
||||
* Sets the TX frequency for all antennas in the provided carrier index
|
||||
* @param carrier_idx Index of the carrier to change the frequency
|
||||
* @param freq Frequency to set to in Hz
|
||||
*/
|
||||
virtual void set_tx_freq(const uint32_t& carrier_idx, const double& freq) = 0;
|
||||
|
||||
/**
|
||||
* Sets the RX frequency for all antennas in the provided carrier index
|
||||
* @param carrier_idx Index of the carrier to change the frequency
|
||||
* @param freq Frequency to set to in Hz
|
||||
*/
|
||||
virtual void set_rx_freq(const uint32_t& carrier_idx, const double& freq) = 0;
|
||||
|
||||
/**
|
||||
* Sets the transmit gain for all carriers and antennas
|
||||
* @param gain Gain in dB
|
||||
*/
|
||||
virtual void set_tx_gain(const float& gain) = 0;
|
||||
|
||||
/**
|
||||
* Sets the receive gain for all carriers and antennas in a background
|
||||
* @param gain Gain in dB
|
||||
*/
|
||||
virtual void set_rx_gain_th(const float& gain) = 0;
|
||||
|
||||
/**
|
||||
* Sets the receive gain for all carriers and antennas
|
||||
* @param gain Gain in dB
|
||||
*/
|
||||
virtual void set_rx_gain(const float& gain) = 0;
|
||||
|
||||
/**
|
||||
* Sets the sampling rate of the D/A converter simultaneously for all carriers and antennas
|
||||
* @param srate Sampling rate in Hz
|
||||
*/
|
||||
virtual void set_tx_srate(const double& srate) = 0;
|
||||
|
||||
/**
|
||||
* Sets the sampling rate of the A/D converter simultaneously for all carriers and antennas
|
||||
* @param srate Sampling rate in Hz
|
||||
*/
|
||||
virtual void set_rx_srate(const double& srate) = 0;
|
||||
|
||||
// getter
|
||||
virtual double get_freq_offset() = 0;
|
||||
virtual float get_rx_gain() = 0;
|
||||
virtual bool is_continuous_tx() = 0;
|
||||
virtual bool get_is_start_of_burst() = 0;
|
||||
virtual bool is_init() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual srslte_rf_info_t* get_info() = 0;
|
||||
};
|
||||
|
||||
class phy_interface_radio
|
||||
{
|
||||
public:
|
||||
virtual void radio_overflow() = 0;
|
||||
virtual void radio_failure() = 0;
|
||||
};
|
||||
|
||||
} // namespace srslte
|
||||
|
||||
#endif // SRSLTE_RADIO_INTERFACES_H
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: radio_base.h
|
||||
* Description: Base class for all eNB/UE radios.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SRSLTE_RADIO_BASE_H
|
||||
#define SRSLTE_RADIO_BASE_H
|
||||
|
||||
#include "srslte/common/interfaces_common.h"
|
||||
#include "srslte/common/logger.h"
|
||||
#include "srslte/interfaces/common_interfaces.h"
|
||||
#include "srslte/radio/radio_metrics.h"
|
||||
|
||||
namespace srslte {
|
||||
|
||||
class radio_base
|
||||
{
|
||||
public:
|
||||
radio_base(srslte::logger* logger_){};
|
||||
virtual ~radio_base(){};
|
||||
|
||||
virtual std::string get_type() = 0;
|
||||
|
||||
virtual int init(const rf_args_t& args_, phy_interface_radio* phy_) = 0;
|
||||
virtual void stop() = 0;
|
||||
|
||||
virtual bool get_metrics(rf_metrics_t* metrics) = 0;
|
||||
};
|
||||
|
||||
} // namespace srslte
|
||||
|
||||
#endif // SRSLTE_RADIO_BASE_H
|
@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: radio_multi.h
|
||||
* Description: Class for using multiple srslte::radio's for both eNB/UE
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SRSLTE_RADIO_MULTI_H
|
||||
#define SRSLTE_RADIO_MULTI_H
|
||||
|
||||
#include "srslte/common/logger.h"
|
||||
#include "srslte/interfaces/common_interfaces.h"
|
||||
#include "srslte/phy/rf/rf.h"
|
||||
#include "srslte/radio/radio.h"
|
||||
#include "srslte/radio/radio_base.h"
|
||||
#include "srslte/radio/radio_metrics.h"
|
||||
|
||||
namespace srslte {
|
||||
|
||||
class radio_multi : public radio_base, public radio_interface_phy
|
||||
{
|
||||
public:
|
||||
radio_multi(srslte::logger* logger_);
|
||||
~radio_multi() override;
|
||||
|
||||
std::string get_type() override;
|
||||
|
||||
int init(const rf_args_t& args_, phy_interface_radio* phy_);
|
||||
|
||||
void stop() override;
|
||||
|
||||
static void rf_msg(srslte_rf_error_t error);
|
||||
void handle_rf_msg(srslte_rf_error_t error);
|
||||
|
||||
bool get_metrics(rf_metrics_t* metrics) override;
|
||||
|
||||
// radio_interface_phy
|
||||
bool is_init() override
|
||||
{
|
||||
if (not radios.empty()) {
|
||||
return radios.at(0)->is_init();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void reset() override
|
||||
{
|
||||
if (not radios.empty()) {
|
||||
radios.at(0)->reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_continuous_tx() override
|
||||
{
|
||||
if (not radios.empty()) {
|
||||
return radios.at(0)->is_continuous_tx();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool get_is_start_of_burst(const uint32_t& radio_idx) override
|
||||
{
|
||||
return radios.at(radio_idx)->get_is_start_of_burst();
|
||||
}
|
||||
bool tx(const uint32_t& radio_idx,
|
||||
cf_t* buffer[SRSLTE_MAX_PORTS],
|
||||
const uint32_t& nof_samples,
|
||||
const srslte_timestamp_t& tx_time) override
|
||||
{
|
||||
return radios.at(radio_idx)->tx(buffer, nof_samples, tx_time);
|
||||
}
|
||||
void tx_end() override
|
||||
{
|
||||
// Send Tx exd to all radios
|
||||
for (auto& r : radios) {
|
||||
r->tx_end();
|
||||
}
|
||||
}
|
||||
|
||||
bool rx_now(const uint32_t& radio_idx,
|
||||
cf_t* buffer[SRSLTE_MAX_PORTS],
|
||||
const uint32_t& nof_samples,
|
||||
srslte_timestamp_t* rxd_time) override
|
||||
{
|
||||
return radios.at(radio_idx)->rx_now(buffer, nof_samples, rxd_time);
|
||||
}
|
||||
void set_rx_gain(const uint32_t& radio_idx, const float& gain) override { radios.at(radio_idx)->set_rx_gain(gain); }
|
||||
void set_rx_gain_th(const float& gain) override { radios.at(0)->set_rx_gain_th(gain); }
|
||||
float get_rx_gain(const uint32_t& radio_idx) override { return radios.at(radio_idx)->get_rx_gain(); }
|
||||
void set_tx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) override
|
||||
{
|
||||
radios.at(radio_idx)->set_tx_freq(channel_idx, freq);
|
||||
}
|
||||
void set_rx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) override
|
||||
{
|
||||
radios.at(radio_idx)->set_rx_freq(channel_idx, freq);
|
||||
}
|
||||
double get_freq_offset() override { return radios.at(0)->get_freq_offset(); }
|
||||
double get_tx_freq(const uint32_t& radio_idx) override { return radios.at(radio_idx)->get_tx_freq(); }
|
||||
double get_rx_freq(const uint32_t& radio_idx) override { return radios.at(radio_idx)->get_rx_freq(); }
|
||||
float get_max_tx_power() override { return args.tx_max_power; }
|
||||
float get_tx_gain_offset() override { return args.tx_gain_offset; }
|
||||
float get_rx_gain_offset() override { return args.rx_gain_offset; }
|
||||
void set_tx_srate(const uint32_t& radio_idx, const double& srate) override
|
||||
{
|
||||
radios.at(radio_idx)->set_tx_srate(srate);
|
||||
}
|
||||
void set_rx_srate(const uint32_t& radio_idx, const double& srate) override
|
||||
{
|
||||
radios.at(radio_idx)->set_rx_srate(srate);
|
||||
}
|
||||
srslte_rf_info_t* get_info(const uint32_t& radio_idx) override
|
||||
{
|
||||
srslte_rf_info_t* ret = nullptr;
|
||||
|
||||
if (radio_idx < radios.size()) {
|
||||
ret = radios.at(radio_idx)->get_info();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected:
|
||||
rf_args_t args = {};
|
||||
|
||||
std::vector<std::unique_ptr<radio> > radios;
|
||||
|
||||
srslte::logger* logger = nullptr;
|
||||
srslte::log_filter log;
|
||||
bool running = false;
|
||||
|
||||
srslte::rf_metrics_t rf_metrics = {};
|
||||
phy_interface_radio* phy = nullptr;
|
||||
};
|
||||
} // namespace srslte
|
||||
|
||||
#endif // SRSLTE_RADIO_MULTI_H
|
@ -1,178 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srslte/radio/radio_multi.h"
|
||||
#include <mutex>
|
||||
|
||||
namespace srslte {
|
||||
|
||||
std::mutex radio_instance_mutex;
|
||||
static radio_multi* instance;
|
||||
|
||||
radio_multi::radio_multi(srslte::logger* logger_) : logger(logger_), radio_base(logger_)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(radio_instance_mutex);
|
||||
instance = this;
|
||||
}
|
||||
|
||||
radio_multi::~radio_multi()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
std::string radio_multi::get_type()
|
||||
{
|
||||
return "radio_multi";
|
||||
}
|
||||
|
||||
int radio_multi::init(const rf_args_t& args_, phy_interface_radio* phy_)
|
||||
{
|
||||
args = args_;
|
||||
phy = phy_;
|
||||
|
||||
// Init log
|
||||
log.init("RF ", logger);
|
||||
log.set_level(args.log_level);
|
||||
|
||||
if (args.nof_radios > SRSLTE_MAX_RADIOS) {
|
||||
log.error("Maximum supported number of radios exceeded (%d > %d)\n", args.nof_radios, SRSLTE_MAX_RADIOS);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Init and start Radio
|
||||
char* dev_name = nullptr;
|
||||
if (args.device_name != "auto") {
|
||||
dev_name = (char*)args.device_name.c_str();
|
||||
}
|
||||
|
||||
const char* dev_args[SRSLTE_MAX_RADIOS] = {nullptr};
|
||||
for (int i = 0; i < SRSLTE_MAX_RADIOS; i++) {
|
||||
if (args.device_args[i] != "auto") {
|
||||
dev_args[i] = args.device_args[i].c_str();
|
||||
}
|
||||
}
|
||||
|
||||
log.console(
|
||||
"Opening %d RF devices with %d RF channels...\n", args.nof_radios, args.nof_rf_channels * args.nof_rx_ant);
|
||||
for (uint32_t r = 0; r < args.nof_radios; r++) {
|
||||
std::unique_ptr<srslte::radio> radio = std::unique_ptr<srslte::radio>(new srslte::radio());
|
||||
if (!radio->init(&log, dev_args[r], dev_name, args.nof_rf_channels * args.nof_rx_ant)) {
|
||||
log.console("Failed to find device %s with args %s\n", args.device_name.c_str(), args.device_args[0].c_str());
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Set RF options
|
||||
if (args.time_adv_nsamples != "auto") {
|
||||
int t = (int)strtol(args.time_adv_nsamples.c_str(), nullptr, 10);
|
||||
radio->set_tx_adv(abs(t));
|
||||
radio->set_tx_adv_neg(t < 0);
|
||||
}
|
||||
if (args.burst_preamble != "auto") {
|
||||
radio->set_burst_preamble(strtof(args.burst_preamble.c_str(), nullptr));
|
||||
}
|
||||
if (args.continuous_tx != "auto") {
|
||||
radio->set_continuous_tx(args.continuous_tx == "yes");
|
||||
}
|
||||
|
||||
// Set PHY options
|
||||
if (args.rx_gain < 0) {
|
||||
radio->start_agc(false);
|
||||
} else {
|
||||
radio->set_rx_gain(args.rx_gain);
|
||||
}
|
||||
if (args.tx_gain > 0) {
|
||||
radio->set_tx_gain(args.tx_gain);
|
||||
} else {
|
||||
radio->set_tx_gain(args.rx_gain);
|
||||
log.console("\nWarning: TX gain was not set. Using open-loop power control (not working properly)\n\n");
|
||||
}
|
||||
|
||||
radio->register_error_handler(rf_msg);
|
||||
radio->set_freq_offset(args.freq_offset);
|
||||
|
||||
// append to radios
|
||||
radios.push_back(std::move(radio));
|
||||
}
|
||||
|
||||
running = true;
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void radio_multi::stop()
|
||||
{
|
||||
if (running) {
|
||||
for (auto& radio : radios) {
|
||||
radio->stop();
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(radio_instance_mutex);
|
||||
instance = nullptr;
|
||||
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool radio_multi::get_metrics(rf_metrics_t* metrics)
|
||||
{
|
||||
*metrics = rf_metrics;
|
||||
rf_metrics = {};
|
||||
return true;
|
||||
}
|
||||
|
||||
void radio_multi::rf_msg(srslte_rf_error_t error)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(radio_instance_mutex);
|
||||
if (instance) {
|
||||
instance->handle_rf_msg(error);
|
||||
}
|
||||
}
|
||||
|
||||
void radio_multi::handle_rf_msg(srslte_rf_error_t error)
|
||||
{
|
||||
if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) {
|
||||
rf_metrics.rf_o++;
|
||||
rf_metrics.rf_error = true;
|
||||
log.info("Overflow\n");
|
||||
|
||||
// inform PHY about overflow
|
||||
phy->radio_overflow();
|
||||
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) {
|
||||
rf_metrics.rf_u++;
|
||||
rf_metrics.rf_error = true;
|
||||
log.info("Underflow\n");
|
||||
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) {
|
||||
rf_metrics.rf_l++;
|
||||
rf_metrics.rf_error = true;
|
||||
log.info("Late (detected in %s)\n", error.opt ? "rx call" : "asynchronous thread");
|
||||
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_RX) {
|
||||
log.error("Fatal radio error occured.\n");
|
||||
phy->radio_failure();
|
||||
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) {
|
||||
std::string str(error.msg);
|
||||
str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
|
||||
str.erase(std::remove(str.begin(), str.end(), '\r'), str.end());
|
||||
str.push_back('\n');
|
||||
log.info("%s\n", str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace srslte
|
@ -1,49 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: enb_radio_multi.h
|
||||
* Description: Header-only class for eNB to set DL/UL freq during init
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SRSENB_RADIO_MULTI_H
|
||||
#define SRSENB_RADIO_MULTI_H
|
||||
|
||||
#include "srslte/common/logger.h"
|
||||
#include "srslte/interfaces/common_interfaces.h"
|
||||
#include "srslte/phy/rf/rf.h"
|
||||
#include "srslte/radio/radio_base.h"
|
||||
#include "srslte/radio/radio_metrics.h"
|
||||
#include "srslte/radio/radio_multi.h"
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
class enb_radio_multi : public srslte::radio_multi
|
||||
{
|
||||
public:
|
||||
enb_radio_multi(srslte::logger* logger_);
|
||||
~enb_radio_multi() override;
|
||||
int init(const srslte::rf_args_t& args_, srslte::phy_interface_radio* phy_);
|
||||
};
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSENB_RADIO_MULTI_H
|
@ -1,22 +0,0 @@
|
||||
#
|
||||
# Copyright 2013-2019 Software Radio Systems Limited
|
||||
#
|
||||
# This file is part of srsLTE
|
||||
#
|
||||
# srsLTE is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# srsLTE is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# A copy of the GNU Affero General Public License can be found in
|
||||
# the LICENSE file in the top-level directory of this distribution
|
||||
# and at http://www.gnu.org/licenses/.
|
||||
#
|
||||
|
||||
file(GLOB SOURCES "*.cc")
|
||||
add_library(srsenb_radio STATIC ${SOURCES})
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsenb/hdr/radio/enb_radio_multi.h"
|
||||
#include <mutex>
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
enb_radio_multi::enb_radio_multi(srslte::logger* logger_) : radio_multi(logger_) {}
|
||||
|
||||
enb_radio_multi::~enb_radio_multi() {}
|
||||
|
||||
int enb_radio_multi::init(const srslte::rf_args_t& args_, srslte::phy_interface_radio* phy_)
|
||||
{
|
||||
return radio_multi::init(args_, phy_);
|
||||
}
|
||||
|
||||
} // namespace srsenb
|
@ -1,621 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsue/hdr/phy/scell/async_scell_recv.h"
|
||||
#include "srsue/hdr/phy/phy_common.h"
|
||||
#include <srslte/interfaces/ue_interfaces.h>
|
||||
#include <srslte/phy/ch_estimation/chest_dl.h>
|
||||
#include <srslte/phy/common/phy_common.h>
|
||||
#include <srslte/phy/ue/ue_sync.h>
|
||||
#include <srslte/srslte.h>
|
||||
|
||||
#define LOG_PREABLE "[scell_recv] "
|
||||
|
||||
#define LOG_ALL_CONSOLE 0
|
||||
|
||||
#if LOG_ALL_CONSOLE
|
||||
#define Error(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__)
|
||||
#define Warning(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__)
|
||||
#define Info(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__)
|
||||
#define Debug(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define Error(fmt, ...) log_h->error(LOG_PREABLE fmt, ##__VA_ARGS__)
|
||||
#define Warning(fmt, ...) log_h->warning(LOG_PREABLE fmt, ##__VA_ARGS__)
|
||||
#define Info(fmt, ...) log_h->info(LOG_PREABLE fmt, ##__VA_ARGS__)
|
||||
#define Debug(fmt, ...) log_h->debug(LOG_PREABLE fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
namespace srsue {
|
||||
namespace scell {
|
||||
|
||||
async_scell_recv::async_scell_recv() : thread("ASYNC_SCELL_RECV")
|
||||
{
|
||||
initiated = false;
|
||||
buffer_write_idx = 0;
|
||||
buffer_read_idx = 0;
|
||||
dl_freq = -1;
|
||||
ul_freq = -1;
|
||||
bzero(&cell, sizeof(srslte_cell_t));
|
||||
bzero(sf_buffer, sizeof(sf_buffer));
|
||||
running = false;
|
||||
radio_idx = 1;
|
||||
current_sflen = 0;
|
||||
next_radio_offset = 0;
|
||||
}
|
||||
|
||||
async_scell_recv::~async_scell_recv()
|
||||
{
|
||||
if (initiated) {
|
||||
srslte_ue_sync_free(&ue_sync);
|
||||
}
|
||||
|
||||
for (auto& b : sf_buffer) {
|
||||
if (b) {
|
||||
free(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int radio_recv_callback(void* obj, cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time)
|
||||
{
|
||||
return ((async_scell_recv*)obj)->radio_recv_fnc(data, nsamples, rx_time);
|
||||
}
|
||||
|
||||
static SRSLTE_AGC_CALLBACK(callback_set_rx_gain)
|
||||
{
|
||||
((async_scell_recv*)h)->set_rx_gain(gain_db);
|
||||
}
|
||||
|
||||
void async_scell_recv::init(srslte::radio_interface_phy* _radio_handler, phy_common* _worker_com, srslte::log* _log_h)
|
||||
{
|
||||
// Get handlers
|
||||
radio_h = _radio_handler;
|
||||
worker_com = _worker_com;
|
||||
log_h = _log_h;
|
||||
|
||||
// Calculate number of RF channels
|
||||
uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant;
|
||||
|
||||
// Initialise buffers
|
||||
for (uint32_t s = 0; s < ASYNC_NOF_BUFFERS; s++) {
|
||||
buffers[s].init(nof_rf_channels);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < nof_rf_channels; i++) {
|
||||
sf_buffer[i] = srslte_vec_cf_malloc(SF_BUFFER_MAX_SAMPLES);
|
||||
if (!sf_buffer[i]) {
|
||||
fprintf(stderr, "Error allocating buffer\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_callback, nof_rf_channels, this)) {
|
||||
fprintf(stderr, "SYNC: Initiating ue_sync\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (srslte_ue_mib_init(&ue_mib, sf_buffer, SRSLTE_MAX_PRB)) {
|
||||
fprintf(stderr, "Error initaiting UE MIB decoder\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pthread_cond_init(&cvar_buffer, nullptr)) {
|
||||
fprintf(stderr, "Initiating condition var\n");
|
||||
return;
|
||||
}
|
||||
|
||||
reset();
|
||||
running = false;
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
void async_scell_recv::stop()
|
||||
{
|
||||
running = false;
|
||||
wait_thread_finish();
|
||||
|
||||
pthread_mutex_destroy(&mutex_buffer);
|
||||
pthread_mutex_destroy(&mutex_uesync);
|
||||
pthread_cond_destroy(&cvar_buffer);
|
||||
}
|
||||
|
||||
void async_scell_recv::in_sync()
|
||||
{
|
||||
in_sync_cnt++;
|
||||
// Send RRC in-sync signal after 100 ms consecutive subframes
|
||||
if (in_sync_cnt == NOF_IN_SYNC_SF) {
|
||||
in_sync_cnt = 0;
|
||||
out_of_sync_cnt = 0;
|
||||
}
|
||||
}
|
||||
void async_scell_recv::out_of_sync()
|
||||
{
|
||||
// Send RRC out-of-sync signal after 200 ms consecutive subframes
|
||||
Info("Out-of-sync %d/%d\n", out_of_sync_cnt, NOF_OUT_OF_SYNC_SF);
|
||||
out_of_sync_cnt++;
|
||||
if (out_of_sync_cnt == NOF_OUT_OF_SYNC_SF) {
|
||||
Info("Sending to RRC\n");
|
||||
out_of_sync_cnt = 0;
|
||||
in_sync_cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void async_scell_recv::set_cfo(float cfo)
|
||||
{
|
||||
srslte_ue_sync_set_cfo_ref(&ue_sync, cfo);
|
||||
}
|
||||
|
||||
float async_scell_recv::get_tx_cfo()
|
||||
{
|
||||
float cfo = srslte_ue_sync_get_cfo(&ue_sync);
|
||||
|
||||
float ret = cfo * ul_dl_factor;
|
||||
|
||||
if (worker_com->args->cfo_is_doppler) {
|
||||
ret *= -1;
|
||||
} else {
|
||||
/* Compensates the radio frequency offset applied equally to DL and UL. Does not work in doppler mode */
|
||||
if (radio_h->get_freq_offset() != 0.0f) {
|
||||
const float offset_hz = (float)radio_h->get_freq_offset() * (1.0f - ul_dl_factor);
|
||||
ret = cfo - offset_hz;
|
||||
}
|
||||
}
|
||||
|
||||
return ret / 15000;
|
||||
}
|
||||
|
||||
void async_scell_recv::set_agc_enable(bool enable)
|
||||
{
|
||||
do_agc = enable;
|
||||
if (do_agc) {
|
||||
if (radio_h) {
|
||||
srslte_rf_info_t* rf_info = radio_h->get_info(radio_idx);
|
||||
srslte_ue_sync_start_agc(
|
||||
&ue_sync, callback_set_rx_gain, rf_info->min_rx_gain, rf_info->max_rx_gain, radio_h->get_rx_gain(radio_idx));
|
||||
} else {
|
||||
fprintf(stderr, "Error setting Secondary cell AGC: PHY not initiated\n");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Error stopping AGC: not implemented\n");
|
||||
}
|
||||
}
|
||||
|
||||
void async_scell_recv::set_rx_gain(float gain)
|
||||
{
|
||||
radio_h->set_rx_gain_th(gain);
|
||||
}
|
||||
|
||||
int async_scell_recv::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (running) {
|
||||
if (radio_h->rx_now(radio_idx, data, nsamples, rx_time)) {
|
||||
int offset = nsamples - current_sflen;
|
||||
if (abs(offset) < 10 && offset != 0) {
|
||||
next_radio_offset += offset;
|
||||
} else if (nsamples < 10) {
|
||||
next_radio_offset += nsamples;
|
||||
}
|
||||
|
||||
log_h->debug("SYNC: received %d samples from radio\n", nsamples);
|
||||
ret = nsamples;
|
||||
} else {
|
||||
ret = SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void async_scell_recv::reset()
|
||||
{
|
||||
in_sync_cnt = 0;
|
||||
out_of_sync_cnt = 0;
|
||||
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
current_earfcn[i] = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void async_scell_recv::radio_error()
|
||||
{
|
||||
log_h->error("SYNC: Receiving from radio.\n");
|
||||
// Need to find a method to effectively reset radio, reloading the driver does not work
|
||||
radio_h->reset();
|
||||
}
|
||||
|
||||
void async_scell_recv::set_ue_sync_opts(srslte_ue_sync_t* q, float cfo)
|
||||
{
|
||||
if (worker_com->args->cfo_integer_enabled) {
|
||||
srslte_ue_sync_set_cfo_i_enable(q, true);
|
||||
}
|
||||
|
||||
srslte_ue_sync_set_cfo_ema(q, worker_com->args->cfo_pss_ema);
|
||||
srslte_ue_sync_set_cfo_tol(q, worker_com->args->cfo_correct_tol_hz);
|
||||
srslte_ue_sync_set_cfo_loop_bw(q,
|
||||
worker_com->args->cfo_loop_bw_pss,
|
||||
worker_com->args->cfo_loop_bw_ref,
|
||||
worker_com->args->cfo_loop_pss_tol,
|
||||
worker_com->args->cfo_loop_ref_min,
|
||||
worker_com->args->cfo_loop_pss_tol,
|
||||
worker_com->args->cfo_loop_pss_conv);
|
||||
|
||||
// Disable CP based CFO estimation during find
|
||||
if (cfo != 0) {
|
||||
q->cfo_current_value = cfo / 15000;
|
||||
q->cfo_is_copied = true;
|
||||
q->cfo_correct_enable_find = true;
|
||||
srslte_sync_set_cfo_cp_enable(&q->sfind, false, 0);
|
||||
}
|
||||
|
||||
// Set SFO ema and correct period
|
||||
srslte_ue_sync_set_sfo_correct_period(q, worker_com->args->sfo_correct_period);
|
||||
srslte_ue_sync_set_sfo_ema(q, worker_com->args->sfo_ema);
|
||||
|
||||
srslte_sync_set_sss_algorithm(&q->strack, SSS_FULL);
|
||||
srslte_sync_set_sss_algorithm(&q->sfind, SSS_FULL);
|
||||
}
|
||||
|
||||
bool async_scell_recv::set_scell_cell(uint32_t carrier_idx, srslte_cell_t* _cell, uint32_t dl_earfcn)
|
||||
{
|
||||
bool ret = true;
|
||||
bool reset_ue_sync = false;
|
||||
|
||||
Info("Set cell:{nof_prb=%d; cp=%s; id=%d} dl_earfcn=%d\n",
|
||||
_cell->nof_prb,
|
||||
srslte_cp_string(_cell->cp),
|
||||
_cell->id,
|
||||
dl_earfcn);
|
||||
|
||||
// Lock mutex
|
||||
pthread_mutex_lock(&mutex_uesync);
|
||||
|
||||
// Get transceiver mapping
|
||||
carrier_map_t* m = &worker_com->args->carrier_map[carrier_idx];
|
||||
uint32_t channel_idx = m->channel_idx;
|
||||
radio_idx = m->radio_idx;
|
||||
|
||||
// Set radio frequency if frequency changed
|
||||
if (current_earfcn[channel_idx] != dl_earfcn) {
|
||||
dl_freq = srslte_band_fd(dl_earfcn) * 1e6f;
|
||||
ul_freq = srslte_band_fu(srslte_band_ul_earfcn(dl_earfcn)) * 1e6f;
|
||||
for (uint32_t p = 0; p < worker_com->args->nof_rx_ant; p++) {
|
||||
radio_h->set_rx_freq(m->radio_idx, m->channel_idx + p, dl_freq);
|
||||
radio_h->set_tx_freq(m->radio_idx, m->channel_idx + p, ul_freq);
|
||||
}
|
||||
Info("Setting DL: %.1f MHz; UL %.1fMHz; Radio/Chan: %d/%d\n", dl_freq / 1e6, ul_freq / 1e6, radio_idx, channel_idx);
|
||||
ul_dl_factor = ul_freq / dl_freq;
|
||||
current_earfcn[channel_idx] = dl_earfcn;
|
||||
reset_ue_sync = true;
|
||||
}
|
||||
|
||||
// Detect change in cell configuration
|
||||
if (memcmp(&cell, _cell, sizeof(srslte_cell_t)) != 0) {
|
||||
// Set sampling rate, if number of PRB changed
|
||||
if (cell.nof_prb != _cell->nof_prb) {
|
||||
double srate = srslte_sampling_freq_hz(_cell->nof_prb);
|
||||
radio_h->set_rx_srate(radio_idx, srate);
|
||||
radio_h->set_tx_srate(radio_idx, srate);
|
||||
current_sflen = (uint32_t)SRSLTE_SF_LEN_PRB(_cell->nof_prb);
|
||||
|
||||
Info("Setting SRate to %.2f MHz\n", srate / 1e6);
|
||||
}
|
||||
|
||||
// Copy cell
|
||||
cell = *_cell;
|
||||
reset_ue_sync = true;
|
||||
|
||||
// Set cell in ue sync
|
||||
if (srslte_ue_sync_set_cell(&ue_sync, cell)) {
|
||||
Error("SYNC: Setting cell: initiating ue_sync\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
// Set cell in MIB decoder
|
||||
if (srslte_ue_mib_set_cell(&ue_mib, cell)) {
|
||||
fprintf(stderr, "Error setting cell in UE MIB decoder\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
srslte_ue_mib_reset(&ue_mib);
|
||||
}
|
||||
|
||||
// Reset ue_sync and set CFO/gain from search procedure
|
||||
if (reset_ue_sync) {
|
||||
srslte_ue_sync_reset(&ue_sync);
|
||||
}
|
||||
|
||||
// Reset thread state
|
||||
state = DECODE_MIB;
|
||||
|
||||
// If not running start!
|
||||
if (!running) {
|
||||
// Start main thread
|
||||
start(1);
|
||||
running = true;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex_uesync);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void async_scell_recv::state_decode_mib()
|
||||
{
|
||||
int sfn_offset = 0;
|
||||
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
|
||||
|
||||
uint32_t sfidx = srslte_ue_sync_get_sfidx(&ue_sync);
|
||||
|
||||
if (sfidx == 0) {
|
||||
// Run only for sub-frame index 0
|
||||
int n = srslte_ue_mib_decode(&ue_mib, bch_payload, nullptr, &sfn_offset);
|
||||
|
||||
if (n < SRSLTE_SUCCESS) {
|
||||
// Error decoding MIB, log error
|
||||
Error("Error decoding UE MIB (%d)\n", n);
|
||||
} else if (n == SRSLTE_UE_MIB_FOUND) {
|
||||
// MIB Found
|
||||
uint32_t sfn = 0;
|
||||
srslte_pbch_mib_unpack(bch_payload, &cell, &sfn);
|
||||
|
||||
Info("SCell MIB synchronised (SNR=%.2fdB)\n", ue_mib.chest_res.snr_db);
|
||||
|
||||
// Set sub-frame index
|
||||
tti = ((sfn + sfn_offset) % 1024) * 10;
|
||||
|
||||
// Change state, reset ring buffer and go to Synchronized but idle
|
||||
buffer_write_idx = 0;
|
||||
buffer_read_idx = 0;
|
||||
state = SYNCH_IDLE;
|
||||
} else {
|
||||
// MIB Not found
|
||||
// Do nothing. Keep going.
|
||||
}
|
||||
} else {
|
||||
// Do nothing. Keep going.
|
||||
}
|
||||
}
|
||||
|
||||
void async_scell_recv::state_write_buffer()
|
||||
{
|
||||
if (tti % SRSLTE_NOF_SF_X_FRAME != srslte_ue_sync_get_sfidx(&ue_sync) || ue_sync.state != SF_TRACK) {
|
||||
// Real-time failure, go to decode MIB
|
||||
Info("Detected Real-Time failure; Going to search MIB (from WRITE)\n");
|
||||
state = DECODE_MIB;
|
||||
} else {
|
||||
// Normal operation, try to write buffer
|
||||
phch_scell_recv_buffer* buffer = &buffers[buffer_write_idx];
|
||||
srslte_timestamp_t rx_time = {};
|
||||
|
||||
// Lock mutex
|
||||
pthread_mutex_lock(&mutex_buffer);
|
||||
|
||||
// Copy last timestamp
|
||||
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
|
||||
|
||||
// Extract essential information
|
||||
buffer->set_sf(tti, &rx_time, next_radio_offset);
|
||||
next_radio_offset = 0;
|
||||
|
||||
// Increment write index
|
||||
buffer_write_idx = (buffer_write_idx + 1) % ASYNC_NOF_BUFFERS;
|
||||
|
||||
// Detect overflow
|
||||
if (buffer_write_idx == buffer_read_idx) {
|
||||
// Reset buffer and goto synchronized IDLE
|
||||
Info("Detected overflow; reseting ring buffer and going to IDLE...\n");
|
||||
buffer_write_idx = 0;
|
||||
buffer_read_idx = 0;
|
||||
state = SYNCH_IDLE;
|
||||
}
|
||||
|
||||
// Unlock mutex and inform that data was received
|
||||
pthread_cond_broadcast(&cvar_buffer);
|
||||
pthread_mutex_unlock(&mutex_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void async_scell_recv::state_synch_idle()
|
||||
{
|
||||
if (tti % SRSLTE_NOF_SF_X_FRAME != srslte_ue_sync_get_sfidx(&ue_sync)) {
|
||||
// Real-time failure, go to decode MIB
|
||||
Debug("Detected Real-Time failure; Going to search MIB (from IDLE)\n");
|
||||
state = DECODE_MIB;
|
||||
} else {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
void async_scell_recv::run_thread()
|
||||
{
|
||||
Info("Starting asynchronous scell reception...\n");
|
||||
while (running) {
|
||||
phch_scell_recv_buffer* buffer = &buffers[buffer_write_idx];
|
||||
|
||||
// Lock ue_sync
|
||||
pthread_mutex_lock(&mutex_uesync);
|
||||
|
||||
// Get RF base-band
|
||||
int ret = srslte_ue_sync_zerocopy(
|
||||
&ue_sync, (state == DECODE_MIB) ? sf_buffer : buffer->get_buffer_ptr(), SF_BUFFER_MAX_SAMPLES);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error calling srslte_ue_sync_work()\n");
|
||||
}
|
||||
|
||||
// Unlock ue_sync
|
||||
pthread_mutex_unlock(&mutex_uesync);
|
||||
|
||||
if (ret == 1) {
|
||||
// Synchronized
|
||||
switch (state) {
|
||||
case DECODE_MIB:
|
||||
state_decode_mib();
|
||||
break;
|
||||
case WRITE_BUFFER:
|
||||
state_write_buffer();
|
||||
break;
|
||||
case SYNCH_IDLE:
|
||||
state_synch_idle();
|
||||
break;
|
||||
}
|
||||
|
||||
// Load metrics
|
||||
sync_metrics_t metrics = {};
|
||||
metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync);
|
||||
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
|
||||
metrics.ta_us = NAN;
|
||||
for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) {
|
||||
if (worker_com->args->carrier_map[i].radio_idx == radio_idx) {
|
||||
worker_com->set_sync_metrics(i, metrics);
|
||||
}
|
||||
}
|
||||
|
||||
// Increment tti
|
||||
tti = (tti + 1) % 10240;
|
||||
} else if (ret == 0) {
|
||||
// Error in synchronization
|
||||
// Warning("SYNC: Out-of-sync detected in PSS/SSS\n");
|
||||
// out_of_sync();
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
// Radio error
|
||||
radio_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool async_scell_recv::tti_align(uint32_t tti)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (state == SYNCH_IDLE) {
|
||||
// Enable Writing in buffer
|
||||
Debug("Start writing in buffer\n");
|
||||
state = WRITE_BUFFER;
|
||||
} else if (state == DECODE_MIB) {
|
||||
// Debug("SCell not ready for reading\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&mutex_buffer);
|
||||
|
||||
// Stage 1: Flush buffers if the tti is not available
|
||||
// While data is available and no tti match, discard
|
||||
while ((buffer_write_idx != buffer_read_idx) && (buffers[buffer_read_idx].get_tti() != tti)) {
|
||||
// Discard buffer
|
||||
Error("Expected TTI %d. Discarding tti %d.\n", tti, buffers[buffer_read_idx].get_tti());
|
||||
buffer_read_idx = (buffer_read_idx + 1) % ASYNC_NOF_BUFFERS;
|
||||
}
|
||||
|
||||
if ((buffers[buffer_read_idx].get_tti() == tti)) {
|
||||
// tti match
|
||||
ret = true;
|
||||
}
|
||||
|
||||
// Stage 2: If the tti is not found and the latest tti was -1; wait
|
||||
// Get time and set timeout time
|
||||
if (!ret) {
|
||||
bool timedout = false;
|
||||
|
||||
while (!ret && !timedout && buffer_write_idx == buffer_read_idx && running) {
|
||||
struct timespec timeToWait = {};
|
||||
struct timeval now = {};
|
||||
|
||||
gettimeofday(&now, nullptr);
|
||||
timeToWait.tv_sec = now.tv_sec;
|
||||
timeToWait.tv_nsec = (now.tv_usec + 1000UL) * 1000UL;
|
||||
|
||||
int rt = pthread_cond_timedwait(&cvar_buffer, &mutex_buffer, &timeToWait);
|
||||
switch (rt) {
|
||||
case ETIMEDOUT:
|
||||
case EPERM:
|
||||
// Consider all errors timed out, exit loop
|
||||
timedout = true;
|
||||
Error("Expected TTI %04d. timeout (%d).\n", tti, rt);
|
||||
tti_align_timeout_counter++;
|
||||
if (tti_align_timeout_counter > max_tti_align_timeout_counter) {
|
||||
Error("Maximum number of timeouts reached (%d). Going back to decode MIB.\n",
|
||||
max_tti_align_timeout_counter);
|
||||
state = DECODE_MIB;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ((buffers[buffer_read_idx].get_tti() == tti)) {
|
||||
// tti match
|
||||
ret = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex_buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void async_scell_recv::read_sf(cf_t** dst, srslte_timestamp_t* timestamp, int* next_offset)
|
||||
{
|
||||
pthread_mutex_lock(&mutex_buffer);
|
||||
|
||||
// Block until data is filled
|
||||
while (buffer_write_idx == buffer_read_idx && running) {
|
||||
pthread_cond_wait(&cvar_buffer, &mutex_buffer);
|
||||
}
|
||||
|
||||
// Exit condition detected
|
||||
if (!running) {
|
||||
pthread_mutex_unlock(&mutex_buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get reading buffer
|
||||
phch_scell_recv_buffer* buffer = &buffers[buffer_read_idx];
|
||||
|
||||
if (dst) {
|
||||
// Get data pointer
|
||||
cf_t** buff = buffer->get_buffer_ptr();
|
||||
|
||||
uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant;
|
||||
|
||||
// Copy data
|
||||
for (uint32_t i = 0; i < nof_rf_channels; i++) {
|
||||
if (dst[i]) {
|
||||
// Check pointer is allocated
|
||||
memcpy(dst[i], buff[i], sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer->get_timestamp(timestamp);
|
||||
buffer->get_next_offset(next_offset);
|
||||
|
||||
// Increment read index
|
||||
buffer_read_idx = (buffer_read_idx + 1) % ASYNC_NOF_BUFFERS;
|
||||
|
||||
pthread_mutex_unlock(&mutex_buffer);
|
||||
}
|
||||
|
||||
} // namespace scell
|
||||
} // namespace srsue
|
Loading…
Reference in New Issue