Refactored radio class for acommodating multiple RF devices

This commit is contained in:
Xavier Arteaga 2020-05-07 15:37:24 +02:00 committed by Xavier Arteaga
parent e2146e90ad
commit 89b24b54e5
24 changed files with 951 additions and 543 deletions

View File

@ -58,6 +58,35 @@ public:
virtual uint32_t size() = 0;
};
/**
* Class used to pass RF devices timestamps to the radio instance
*
* The class provides an abstraction to store a number of timestamps underlying RF devices.
*/
class rf_timestamp_interface
{
public:
virtual const srslte_timestamp_t& get(uint32_t idx) const = 0;
virtual srslte_timestamp_t* get_ptr(uint32_t idx) = 0;
virtual void add(double secs) = 0;
virtual void sub(double secs) = 0;
void copy(const rf_timestamp_interface& other)
{
// Nothing to copy
if (this == &other) {
return;
}
// Copy timestamps
for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) {
*this->get_ptr(i) = other.get(i);
}
}
srslte_timestamp_t& operator[](uint32_t idx) { return *this->get_ptr(idx); }
};
/**
* Radio interface for the PHY.
*
@ -94,7 +123,7 @@ public:
* @param tx_time Time to transmit all signals
* @return it returns true if the transmission was successful, otherwise it returns false
*/
virtual bool tx(rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time) = 0;
virtual bool tx(rf_buffer_interface& buffer, const uint32_t& nof_samples, const rf_timestamp_interface& tx_time) = 0;
/**
* Indicates the radio to receive from all antennas and carriers synchronously and store the samples
@ -105,7 +134,7 @@ public:
* @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;
virtual bool rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, rf_timestamp_interface& rxd_time) = 0;
/**
* Sets the TX frequency for all antennas in the provided carrier index

View File

@ -29,6 +29,10 @@
#include "srslte/config.h"
#ifdef __cplusplus
extern "C" {
#endif
#define RF_PARAM_LEN (256)
typedef struct {
@ -164,4 +168,8 @@ SRSLTE_API int srslte_rf_send_multi(srslte_rf_t* rf,
bool is_start_of_burst,
bool is_end_of_burst);
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_RF_H

View File

@ -0,0 +1,133 @@
/*
* Copyright 2013-2020 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/.
*
*/
#ifndef SRSLTE_CHANNEL_MAPPING_H
#define SRSLTE_CHANNEL_MAPPING_H
#include <cinttypes>
#include <list>
#include <map>
#include <mutex>
namespace srslte {
/**
* This class manages the mapping between logical and physical channels.
* A physical channel in this class is a carrier index in the radio class, which
* has multiple antenna ports all tuned to the same frequency.
*
* Every group of channels tuned associated with a carrier go through the same band-pass filter. This
* class then manages the allocation of frequencies to these group of channels.
*
* The same object is reused for the reception and transmission.
*
* When the UE wants to tune a logical channel to a new frequency it requests this class
* to provide an available channel that supports this frequency. At that point,
* that channel can not be used anymore until a call to release().
*
*/
class channel_mapping
{
public:
/** Configures a band. A band is defined by an upper and lower frequency boundaries.
* If the upper and lower frequencies are not configured (default is zero), it means
* that they support any frequency
*/
class band_cfg
{
public:
void set(float low_freq_, float high_freq_)
{
low_freq = low_freq_;
high_freq = high_freq_;
}
bool contains(float freq)
{
if (low_freq == 0 && high_freq == 0) {
return true;
} else {
return freq >= low_freq && freq <= high_freq;
}
}
float get_low() { return low_freq; }
float get_high() { return high_freq; }
private:
float low_freq = 0;
float high_freq = 0;
};
/** Each channel is defined by the band it supports and the physical carrier index in the radio
*/
typedef struct {
band_cfg band;
uint32_t carrier_idx;
} channel_cfg_t;
/**
* Sets the channel configuration. If no channels are configured no physical channels can be allocated
* @param channels_
*/
void set_channels(const std::list<channel_cfg_t>& channels_) { available_channels = channels_; }
/**
* Finds an unused physical channel that supports the provided frequency and assigns it to logical channel
* logical_ch
* @param logical_ch logical channel index
* @param freq Frequency (in Hz) that we want to receive/transmitt
* @return true if a physical channel supporting this frequency was found or false otherwise
*/
bool allocate_freq(const uint32_t& logical_ch, const float& freq);
/**
* Releases the allocation of a logical channel allowing to be used in the next call to allocate_freq
* @param logical_ch logical channel index
* @return false if logical_ch is not allocated, true otherwise
*/
bool release_freq(const uint32_t& logical_ch);
/**
* Obtains the carrier index configured in set_channels() in the radio to which the logical channel logical_ch has
* been mapped to
* @param logical_ch logical channel index
* @return <0 if logical_ch is not allocated, true otherwise
*
* @see channel_cfg_t
*/
int get_carrier_idx(const uint32_t& logical_ch);
/**
* Checks if the channel has been allocated using allocate_freq()
*
* @param logical_ch logical channel index
* @return true if the channel is allocated, false otherwise
*/
bool is_allocated(const uint32_t& logical_ch);
private:
std::list<channel_cfg_t> available_channels = {};
std::map<uint32_t, channel_cfg_t> allocated_channels = {};
std::mutex mutex = {};
};
} // namespace srslte
#endif // SRSLTE_CHANNEL_MAPPING_H

View File

@ -19,130 +19,22 @@
*
*/
#include <string.h>
#include "channel_mapping.h"
#include "radio_metrics.h"
#include "rf_buffer.h"
#include "rf_timestamp.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/trace.h"
#include "srslte/interfaces/radio_interfaces.h"
#include "srslte/phy/rf/rf.h"
#include "srslte/srslte.h"
#include <list>
#include <string>
#ifndef SRSLTE_RADIO_H
#define SRSLTE_RADIO_H
namespace srslte {
/**
* Implemenation of the rf_buffer_interface for the current radio implementation which uses flat arrays.
* @see rf_buffer_interface
* @see radio
*
*/
class rf_buffer_t : public rf_buffer_interface
{
public:
/**
* Creates an object and allocates memory for nof_subframes_ assuming the
* largest system bandwidth
* @param nof_subframes_ Number of subframes to allocate
*/
explicit rf_buffer_t(uint32_t nof_subframes_)
{
if (nof_subframes_ > 0) {
// Allocate buffers for an integer number of subframes
for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) {
sample_buffer[i] = srslte_vec_cf_malloc(nof_subframes_ * SRSLTE_SF_LEN_MAX);
srslte_vec_cf_zero(sample_buffer[i], SRSLTE_SF_LEN_MAX);
}
allocated = true;
nof_subframes = nof_subframes_;
}
}
/**
* Creates an object and sets the buffers to the flat array pointed by data. Note that data must
* contain up to SRSLTE_MAX_CHANNELS pointers
* @param data Flat array to use as initializer for the internal buffer pointers
*/
explicit rf_buffer_t(cf_t* data[SRSLTE_MAX_CHANNELS])
{
for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) {
sample_buffer[i] = data[i];
}
}
/**
* Creates an object from a single array pointer. The rest of the channel pointers will be left to NULL
* @param data Flat array to use as initializer for the internal buffer pointers
*/
explicit rf_buffer_t(cf_t* data) { sample_buffer[0] = data; }
/**
* Default constructor leaves the internal pointers to NULL
*/
rf_buffer_t() = default;
/**
* The destructor will deallocate memory only if it was allocated passing nof_subframes > 0
*/
~rf_buffer_t()
{
if (allocated) {
free_all();
}
}
/**
* Overrides the = operator such that the lvalue internal buffers point to the pointers inside rvalue.
* If memory has already been allocated in the lvalue object, it will free it before pointing the
* buffers to the lvalue.
* After this operator, when the lvalue is destroyed no memory will be freed.
* @param other rvalue
* @return lvalue
*/
rf_buffer_t& operator=(const rf_buffer_t& other)
{
if (this == &other) {
return *this;
}
if (this->allocated) {
free_all();
this->allocated = false;
}
for (int i = 0; i < SRSLTE_MAX_CHANNELS; i++) {
this->sample_buffer[i] = other.sample_buffer[i];
}
return *this;
}
rf_buffer_t(const rf_buffer_t& other) = delete;
cf_t* get(const uint32_t& channel_idx) const override { return sample_buffer.at(channel_idx); }
void set(const uint32_t& channel_idx, cf_t* ptr) override { sample_buffer.at(channel_idx) = ptr; }
cf_t* get(const uint32_t& logical_ch, const uint32_t& port_idx, const uint32_t& nof_antennas) const override
{
return sample_buffer.at(logical_ch * nof_antennas + port_idx);
}
void set(const uint32_t& logical_ch, const uint32_t& port_idx, const uint32_t& nof_antennas, cf_t* ptr) override
{
sample_buffer.at(logical_ch * nof_antennas + port_idx) = ptr;
}
void** to_void() override { return (void**)sample_buffer.data(); }
cf_t** to_cf_t() override { return sample_buffer.data(); }
uint32_t size() override { return nof_subframes * SRSLTE_SF_LEN_MAX; }
private:
std::array<cf_t*, SRSLTE_MAX_CHANNELS> sample_buffer = {};
bool allocated = false;
uint32_t nof_subframes = 0;
void free_all()
{
for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) {
if (sample_buffer[i]) {
free(sample_buffer[i]);
}
}
}
};
/**
* Implementation of the radio interface for the PHY
*
@ -168,8 +60,8 @@ public:
// trx functions
void tx_end() override;
bool tx(rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time) override;
bool rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time) override;
bool tx(rf_buffer_interface& buffer, const uint32_t& nof_samples, const rf_timestamp_interface& tx_time) override;
bool rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, rf_timestamp_interface& rxd_time) override;
// setter
void set_tx_freq(const uint32_t& carrier_idx, const double& freq) override;
@ -192,38 +84,36 @@ public:
srslte_rf_info_t* get_info() override;
// Other functions
bool get_metrics(rf_metrics_t* metrics);
float get_rssi();
bool has_rssi();
void get_time(srslte_timestamp_t* now);
bool get_metrics(rf_metrics_t* metrics);
void handle_rf_msg(srslte_rf_error_t error);
static void rf_msg_callback(void* arg, srslte_rf_error_t error);
private:
srslte_rf_t rf_device = {};
srslte_rf_info_t rf_info = {};
rf_metrics_t rf_metrics = {};
log_filter log_local = {};
log_filter* log_h = nullptr;
srslte::logger* logger = nullptr;
phy_interface_radio* phy = nullptr;
cf_t* zeros = nullptr;
std::vector<srslte_rf_t> rf_devices = {};
std::vector<srslte_rf_info_t> rf_info = {};
rf_metrics_t rf_metrics = {};
log_filter log_local = {};
log_filter* log_h = nullptr;
srslte::logger* logger = nullptr;
phy_interface_radio* phy = nullptr;
cf_t* zeros = nullptr;
srslte_timestamp_t end_of_burst_time = {};
bool is_start_of_burst = 0;
uint32_t tx_adv_nsamples = 0;
double tx_adv_sec = 0.0f; // Transmission time advance to compensate for antenna->timestamp delay
bool tx_adv_auto = false;
bool tx_adv_negative = false;
bool is_initialized = false;
bool radio_is_streaming = false;
bool continuous_tx = false;
double freq_offset = 0.0f;
double cur_tx_srate = 0.0f;
uint32_t nof_antennas = 0;
uint32_t nof_channels = 0;
uint32_t nof_carriers = 0;
rf_timestamp_t end_of_burst_time = {};
bool is_start_of_burst = false;
uint32_t tx_adv_nsamples = 0;
double tx_adv_sec = 0.0; // Transmission time advance to compensate for antenna->timestamp delay
bool tx_adv_auto = false;
bool tx_adv_negative = false;
bool is_initialized = false;
bool radio_is_streaming = false;
bool continuous_tx = false;
double freq_offset = 0.0;
double cur_tx_srate = 0.0;
uint32_t nof_antennas = 0;
uint32_t nof_channels = 0;
uint32_t nof_channels_x_dev = 0;
uint32_t nof_carriers = 0;
std::vector<double> cur_tx_freqs = {};
std::vector<double> cur_rx_freqs = {};
@ -232,114 +122,79 @@ private:
///< shall be stopped
// Define default values for known radios
constexpr static double uhd_default_tx_adv_samples = 98;
constexpr static int uhd_default_tx_adv_samples = 98;
constexpr static double uhd_default_tx_adv_offset_sec = 4 * 1e-6;
constexpr static int lime_default_tx_adv_samples = 98;
constexpr static double lime_default_tx_adv_offset_sec = 4 * 1e-6;
constexpr static int blade_default_tx_adv_samples = 27;
constexpr static double blade_default_tx_adv_offset_sec = 1e-6;
/**
* This class manages the mapping between logical and physical channels.
* A physical channel in this class is a carrier index in the radio class, which
* has multiple antenna ports all tuned to the same frequency.
*
* Every group of channels tuned associated with a carrier go through the same band-pass filter. This
* class then manages the allocation of frequencies to these group of channels.
*
* The same object is reused for the reception and transmission.
*
* When the UE wants to tune a logical channel to a new frequency it requests this class
* to provide an available channel that supports this frequency. At that point,
* that channel can not be used anymore until a call to release().
*
* Get device calibrated transmit time in advanced seconds
* @param device_name actual device name
* @return transmit time in advanced in seconds
*/
class channel_mapping
{
public:
/** Configures a band. A band is defined by an upper and lower frequency boundaries.
* If the upper and lower frequencies are not configured (default is zero), it means
* that they support any frequency
*/
class band_cfg
{
public:
void set(float low_freq_, float high_freq_)
{
low_freq = low_freq_;
high_freq = high_freq_;
}
bool contains(float freq)
{
if (low_freq == 0 && high_freq == 0) {
return true;
} else {
return freq >= low_freq && freq <= high_freq;
}
}
float get_low() { return low_freq; }
float get_high() { return high_freq; }
private:
float low_freq = 0;
float high_freq = 0;
};
/** Each channel is defined by the band it supports and the physical carrier index in the radio
*/
typedef struct {
band_cfg band;
uint32_t carrier_idx;
} channel_cfg_t;
/**
* Sets the channel configuration. If no channels are configured no physical channels can be allocated
* @param channels_
*/
void set_channels(const std::list<channel_cfg_t>& channels_) { available_channels = channels_; }
/**
* Finds an unused physical channel that supports the provided frequency and assigns it to logical channel
* logical_ch
* @param logical_ch logical channel index
* @param freq Frequency (in Hz) that we want to receive/transmitt
* @return true if a physical channel supporting this frequency was found or false otherwise
*/
bool allocate_freq(const uint32_t& logical_ch, const float& freq);
/**
* Releases the allocation of a logical channel allowing to be used in the next call to allocate_freq
* @param logical_ch logical channel index
* @return false if logical_ch is not allocated, true otherwise
*/
bool release_freq(const uint32_t& logical_ch);
/**
* Obtains the carrier index configured in set_channels() in the radio to which the logical channel logical_ch has
* been mapped to
* @param logical_ch logical channel index
* @return <0 if logical_ch is not allocated, true otherwise
*
* @see channel_cfg_t
*/
int get_carrier_idx(const uint32_t& logical_ch);
/**
* Checks if the channel has been allocated using allocate_freq()
*
* @param logical_ch logical channel index
* @return true if the channel is allocated, false otherwise
*/
bool is_allocated(const uint32_t& logical_ch);
private:
std::list<channel_cfg_t> available_channels = {};
std::map<uint32_t, channel_cfg_t> allocated_channels = {};
std::mutex mutex = {};
};
double get_dev_cal_tx_adv_sec(const std::string& device_name);
channel_mapping rx_channel_mapping = {}, tx_channel_mapping = {};
/**
* Helper method for opening a RF device
*
* @param device_idx Device index
* @param device_name Device name
* @param devive_args Device arguments
* @return it returns true if the device was opened successful, otherwise it returns false
*/
bool open_dev(const uint32_t& device_idx, const std::string& device_name, const std::string& devive_args);
/**
* Helper method for transmitting over a single RF device. This function maps automatically the logical transmit
* buffers to the physical RF buffers for the given device.
*
* Also, it takes care internally of transmission gaps and overlaps. So, it applies time compensation per channel
* basis.
*
* @param device_idx Device index
* @param buffer Common transmit buffer
* @param nof_samples_ number of samples to transmit
* @param tx_time_ Timestamp to transmit (read only)
* @return it returns true if the transmission was successful, otherwise it returns false
*/
bool tx_dev(const uint32_t& device_idx,
rf_buffer_interface& buffer,
const uint32_t& nof_samples_,
const srslte_timestamp_t& tx_time_);
/**
* Helper method for receiving over a single RF device. This function maps automatically the logical receive buffers
* to the physical RF buffers for the given device.
*
* @param device_idx Device index
* @param buffer Common receive buffers
* @param nof_samples Number of samples to receive
* @param rxd_time Points at the receive time (write only)
* @return it returns true if the reception was successful, otherwise it returns false
*/
bool rx_dev(const uint32_t& device_idx,
const rf_buffer_interface& buffer,
const uint32_t& nof_samples,
srslte_timestamp_t* rxd_time);
/**
* Helper method for mapping logical channels into physical radio buffers.
*
* @param map Channel mapping, it can be either Tx or Rx mapping
* @param device_idx RF Device index for the buffer mapping
* @param sample_offset The physical radio buffer pointer offset
* @param buffer Logical channels buffer
* @param radio_buffers Actual physical radio buffer
* @return It returns true if the mapping was successful, otherwise it returns false.
*/
bool map_channels(channel_mapping& map,
uint32_t device_idx,
uint32_t sample_offset,
const rf_buffer_interface& buffer,
void* radio_buffers[SRSLTE_MAX_CHANNELS]);

View File

@ -0,0 +1,139 @@
/*
* Copyright 2013-2020 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/.
*
*/
#ifndef SRSLTE_RF_BUFFER_H
#define SRSLTE_RF_BUFFER_H
#include "srslte/interfaces/radio_interfaces.h"
namespace srslte {
/**
* Implemenation of the rf_buffer_interface for the current radio implementation which uses flat arrays.
* @see rf_buffer_interface
* @see radio
*
*/
class rf_buffer_t : public rf_buffer_interface
{
public:
/**
* Creates an object and allocates memory for nof_subframes_ assuming the
* largest system bandwidth
* @param nof_subframes_ Number of subframes to allocate
*/
explicit rf_buffer_t(uint32_t nof_subframes_)
{
if (nof_subframes_ > 0) {
// Allocate buffers for an integer number of subframes
for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) {
sample_buffer[i] = srslte_vec_cf_malloc(nof_subframes_ * SRSLTE_SF_LEN_MAX);
srslte_vec_cf_zero(sample_buffer[i], SRSLTE_SF_LEN_MAX);
}
allocated = true;
nof_subframes = nof_subframes_;
}
}
/**
* Creates an object and sets the buffers to the flat array pointed by data. Note that data must
* contain up to SRSLTE_MAX_CHANNELS pointers
* @param data Flat array to use as initializer for the internal buffer pointers
*/
explicit rf_buffer_t(cf_t* data[SRSLTE_MAX_CHANNELS])
{
for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) {
sample_buffer[i] = data[i];
}
}
/**
* Creates an object from a single array pointer. The rest of the channel pointers will be left to NULL
* @param data Flat array to use as initializer for the internal buffer pointers
*/
explicit rf_buffer_t(cf_t* data) { sample_buffer[0] = data; }
/**
* Default constructor leaves the internal pointers to NULL
*/
rf_buffer_t() = default;
/**
* The destructor will deallocate memory only if it was allocated passing nof_subframes > 0
*/
~rf_buffer_t()
{
if (allocated) {
free_all();
}
}
/**
* Overrides the = operator such that the lvalue internal buffers point to the pointers inside rvalue.
* If memory has already been allocated in the lvalue object, it will free it before pointing the
* buffers to the lvalue.
* After this operator, when the lvalue is destroyed no memory will be freed.
* @param other rvalue
* @return lvalue
*/
rf_buffer_t& operator=(const rf_buffer_t& other)
{
if (this == &other) {
return *this;
}
if (this->allocated) {
free_all();
this->allocated = false;
}
for (int i = 0; i < SRSLTE_MAX_CHANNELS; i++) {
this->sample_buffer[i] = other.sample_buffer[i];
}
return *this;
}
rf_buffer_t(const rf_buffer_t& other) = delete;
cf_t* get(const uint32_t& channel_idx) const override { return sample_buffer.at(channel_idx); }
void set(const uint32_t& channel_idx, cf_t* ptr) override { sample_buffer.at(channel_idx) = ptr; }
cf_t* get(const uint32_t& logical_ch, const uint32_t& port_idx, const uint32_t& nof_antennas) const override
{
return sample_buffer.at(logical_ch * nof_antennas + port_idx);
}
void set(const uint32_t& logical_ch, const uint32_t& port_idx, const uint32_t& nof_antennas, cf_t* ptr) override
{
sample_buffer.at(logical_ch * nof_antennas + port_idx) = ptr;
}
void** to_void() override { return (void**)sample_buffer.data(); }
cf_t** to_cf_t() override { return sample_buffer.data(); }
uint32_t size() override { return nof_subframes * SRSLTE_SF_LEN_MAX; }
private:
std::array<cf_t*, SRSLTE_MAX_CHANNELS> sample_buffer = {};
bool allocated = false;
uint32_t nof_subframes = 0;
void free_all()
{
for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) {
if (sample_buffer[i]) {
free(sample_buffer[i]);
}
}
}
};
} // namespace srslte
#endif // SRSLTE_RF_BUFFER_H

View File

@ -0,0 +1,107 @@
/*
* Copyright 2013-2020 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/.
*
*/
#ifndef SRSLTE_RF_TIMESTAMP_H
#define SRSLTE_RF_TIMESTAMP_H
#include "srslte/interfaces/radio_interfaces.h"
namespace srslte {
/**
* Implemenation of the rf_buffer_interface for the current radio implementation which uses flat arrays.
* @see rf_buffer_interface
* @see radio
*
*/
class rf_timestamp_t : public rf_timestamp_interface
{
public:
/**
* Default constructor, all timestamps are zero by default
*/
rf_timestamp_t() = default;
/**
* Copy constructor
* @param other the other object to copy
*/
rf_timestamp_t(const rf_timestamp_t& other) { copy(other); }
/**
* Default destructor
*/
~rf_timestamp_t() = default;
/**
* Gets a timestamp by reference
* @return Given timestamp of the indicated device if the index is bounded, otherwise it returns the default timestamp
*/
const srslte_timestamp_t& get(uint32_t idx) const override
{
if (idx >= SRSLTE_MAX_CHANNELS) {
return default_ts;
}
return timestamps[idx];
}
/**
* Get the timestamp array pointer
* @return timestamp pointer with the value if the channel index is bounded. Otherwise, returns nullptr
*/
srslte_timestamp_t* get_ptr(uint32_t idx) override
{
if (idx >= SRSLTE_MAX_CHANNELS) {
return nullptr;
}
return &timestamps[idx];
}
/**
* Add a given amount of seconds to all the timestamps
* @param secs number of seconds
*/
void add(double secs) override
{
for (srslte_timestamp_t& ts : timestamps) {
srslte_timestamp_add(&ts, 0, secs);
}
}
/**
* Subtract a given amount of seconds to all the timestamps
* @param secs number of seconds
*/
void sub(double secs) override
{
for (srslte_timestamp_t& ts : timestamps) {
srslte_timestamp_sub(&ts, 0, secs);
}
}
private:
const srslte_timestamp_t default_ts = {};
std::array<srslte_timestamp_t, SRSLTE_MAX_CHANNELS> timestamps = {};
};
} // namespace srslte
#endif // SRSLTE_RF_TIMESTAMP_H

View File

@ -19,7 +19,7 @@
#
if(RF_FOUND)
add_library(srslte_radio STATIC radio.cc)
add_library(srslte_radio STATIC radio.cc channel_mapping.cc)
target_link_libraries(srslte_radio srslte_rf)
endif(RF_FOUND)

View File

@ -0,0 +1,76 @@
/*
* Copyright 2013-2020 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/channel_mapping.h"
#include "srslte/phy/utils/debug.h"
namespace srslte {
bool channel_mapping::allocate_freq(const uint32_t& logical_ch, const float& freq)
{
std::lock_guard<std::mutex> lock(mutex);
if (allocated_channels.count(logical_ch)) {
ERROR("allocate_freq: Carrier logical_ch=%d already allocated to channel=%d\n",
logical_ch,
allocated_channels[logical_ch].carrier_idx);
return false;
}
// Find first available channel that supports this frequency and allocated it
for (auto c = available_channels.begin(); c != available_channels.end(); ++c) {
if (c->band.contains(freq)) {
allocated_channels[logical_ch] = *c;
available_channels.erase(c);
return true;
}
}
ERROR("allocate_freq: No channels available for frequency=%.1f\n", freq);
return false;
}
bool channel_mapping::release_freq(const uint32_t& logical_ch)
{
std::lock_guard<std::mutex> lock(mutex);
if (allocated_channels.count(logical_ch)) {
available_channels.push_back(allocated_channels[logical_ch]);
allocated_channels.erase(logical_ch);
return true;
}
return false;
}
int channel_mapping::get_carrier_idx(const uint32_t& logical_ch)
{
std::lock_guard<std::mutex> lock(mutex);
if (allocated_channels.count(logical_ch)) {
return allocated_channels[logical_ch].carrier_idx;
}
return -1;
}
bool channel_mapping::is_allocated(const uint32_t& logical_ch)
{
std::lock_guard<std::mutex> lock(mutex);
return allocated_channels.count(logical_ch) > 0;
}
} // namespace srslte

View File

@ -19,25 +19,21 @@
*
*/
#include "srslte/srslte.h"
extern "C" {
#include "srslte/phy/rf/rf.h"
}
#include "srslte/common/log_filter.h"
#include "srslte/radio/radio.h"
#include "srslte/config.h"
#include <list>
#include <string.h>
#include <string>
#include <unistd.h>
namespace srslte {
radio::radio(srslte::log_filter* log_h_) : logger(nullptr), log_h(log_h_), zeros(NULL)
radio::radio(srslte::log_filter* log_h_) : logger(nullptr), log_h(log_h_), zeros(nullptr)
{
zeros = srslte_vec_cf_malloc(SRSLTE_SF_LEN_MAX);
srslte_vec_cf_zero(zeros, SRSLTE_SF_LEN_MAX);
}
radio::radio(srslte::logger* logger_) : logger(logger_), log_h(nullptr), zeros(NULL)
radio::radio(srslte::logger* logger_) : logger(logger_), log_h(nullptr), zeros(nullptr)
{
zeros = srslte_vec_cf_malloc(SRSLTE_SF_LEN_MAX);
srslte_vec_cf_zero(zeros, SRSLTE_SF_LEN_MAX);
@ -51,6 +47,18 @@ radio::~radio()
}
}
static inline void split_string(const std::string& input, char delimiter, std::vector<std::string>& list)
{
std::stringstream ss(input);
while (ss.good()) {
std::string substr;
getline(ss, substr, delimiter);
if (not substr.empty()) {
list.push_back(substr);
}
}
}
int radio::init(const rf_args_t& args, phy_interface_radio* phy_)
{
phy = phy_;
@ -89,23 +97,35 @@ int radio::init(const rf_args_t& args, phy_interface_radio* phy_)
cur_tx_freqs.resize(nof_carriers);
cur_rx_freqs.resize(nof_carriers);
// Init and start Radio
char* device_args = nullptr;
if (args.device_args != "auto") {
device_args = (char*)args.device_args.c_str();
// Split multiple RF channels using `;` delimiter
std::vector<std::string> device_args_list;
split_string(args.device_args, ';', device_args_list);
// Add auto if list is empty
if (device_args_list.empty()) {
device_args_list.emplace_back("auto");
}
char* dev_name = nullptr;
if (args.device_name != "auto") {
dev_name = (char*)args.device_name.c_str();
}
log_h->console("Opening %d channels in RF device=%s with args=%s\n",
nof_channels,
dev_name ? dev_name : "default",
device_args ? device_args : "default");
if (srslte_rf_open_devname(&rf_device, dev_name, device_args, nof_channels)) {
log_h->error("Error opening RF device\n");
// Makes sure it is possible to have the same number of RF channels in each RF device
if (nof_channels % device_args_list.size() != 0) {
log_h->console(
"Error: The number of required RF channels (%d) is not divisible between the number of RF devices (%ld).\n",
nof_channels,
device_args_list.size());
return SRSLTE_ERROR;
}
nof_channels_x_dev = nof_channels / device_args_list.size();
// Allocate RF devices
rf_devices.resize(device_args_list.size());
rf_info.resize(device_args_list.size());
// Init and start Radios
for (uint32_t device_idx = 0; device_idx < (uint32_t)device_args_list.size(); device_idx++) {
if (not open_dev(device_idx, args.device_name, device_args_list[device_idx])) {
log_h->error("Error opening RF device %d\n", device_idx);
}
}
is_start_of_burst = true;
is_initialized = true;
@ -139,15 +159,6 @@ int radio::init(const rf_args_t& args, phy_interface_radio* phy_)
// Frequency offset
freq_offset = args.freq_offset;
// Get device info
rf_info = *get_info();
// Suppress radio stdout
srslte_rf_suppress_stdout(&rf_device);
// Register handler for processing O/U/L
srslte_rf_register_error_handler(&rf_device, rf_msg_callback, this);
return SRSLTE_SUCCESS;
}
@ -163,13 +174,17 @@ void radio::stop()
zeros = NULL;
}
if (is_initialized) {
srslte_rf_close(&rf_device);
for (srslte_rf_t& rf_device : rf_devices) {
srslte_rf_close(&rf_device);
}
}
}
void radio::reset()
{
srslte_rf_stop_rx_stream(&rf_device);
for (srslte_rf_t& rf_device : rf_devices) {
srslte_rf_stop_rx_stream(&rf_device);
}
radio_is_streaming = false;
usleep(100000);
}
@ -198,72 +213,113 @@ bool radio::start_agc(bool tx_gain_same_rx)
if (!is_initialized) {
return false;
}
if (srslte_rf_start_gain_thread(&rf_device, tx_gain_same_rx)) {
ERROR("Error starting AGC Thread RF device\n");
return false;
for (srslte_rf_t& rf_device : rf_devices) {
if (srslte_rf_start_gain_thread(&rf_device, tx_gain_same_rx)) {
ERROR("Error starting AGC Thread RF device\n");
return false;
}
}
return true;
}
bool radio::rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time)
bool radio::rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, rf_timestamp_interface& rxd_time)
{
if (!is_initialized) {
return false;
}
bool ret = true;
if (!radio_is_streaming) {
srslte_rf_start_rx_stream(&rf_device, false);
if (not radio_is_streaming) {
for (srslte_rf_t& rf_device : rf_devices) {
srslte_rf_start_rx_stream(&rf_device, false);
}
radio_is_streaming = true;
}
time_t* full_secs = rxd_time ? &rxd_time->full_secs : NULL;
double* frac_secs = rxd_time ? &rxd_time->frac_secs : NULL;
void* radio_buffers[SRSLTE_MAX_CHANNELS] = {};
if (!map_channels(rx_channel_mapping, 0, buffer, radio_buffers)) {
log_h->error("Mapping logical channels to physical channels for transmission\n");
return false;
}
if (srslte_rf_recv_with_time_multi(&rf_device, radio_buffers, nof_samples, true, full_secs, frac_secs) > 0) {
ret = true;
} else {
ret = false;
for (uint32_t device_idx = 0; device_idx < (uint32_t)rf_devices.size(); device_idx++) {
ret &= rx_dev(device_idx, buffer, nof_samples, rxd_time.get_ptr(device_idx));
}
return ret;
}
void radio::get_time(srslte_timestamp_t* now)
{
if (!is_initialized) {
return;
}
srslte_rf_get_time(&rf_device, &now->full_secs, &now->frac_secs);
}
float radio::get_rssi()
{
if (!is_initialized) {
return 0.0f;
}
return srslte_rf_get_rssi(&rf_device);
}
bool radio::has_rssi()
bool radio::rx_dev(const uint32_t& device_idx,
const rf_buffer_interface& buffer,
const uint32_t& nof_samples,
srslte_timestamp_t* rxd_time)
{
if (!is_initialized) {
return false;
}
return srslte_rf_has_rssi(&rf_device);
time_t* full_secs = rxd_time ? &rxd_time->full_secs : nullptr;
double* frac_secs = rxd_time ? &rxd_time->frac_secs : nullptr;
void* radio_buffers[SRSLTE_MAX_CHANNELS] = {};
if (not map_channels(rx_channel_mapping, device_idx, 0, buffer, radio_buffers)) {
log_h->error("Mapping logical channels to physical channels for transmission\n");
return false;
}
int ret =
srslte_rf_recv_with_time_multi(&rf_devices[device_idx], radio_buffers, nof_samples, true, full_secs, frac_secs);
return ret > 0;
}
bool radio::tx(rf_buffer_interface& buffer, const uint32_t& nof_samples_, const srslte_timestamp_t& tx_time_)
bool radio::tx(rf_buffer_interface& buffer, const uint32_t& nof_samples, const rf_timestamp_interface& tx_time)
{
uint32_t nof_samples = nof_samples_;
uint32_t sample_offset = 0;
bool ret = true;
for (uint32_t device_idx = 0; device_idx < (uint32_t)rf_devices.size(); device_idx++) {
ret &= tx_dev(device_idx, buffer, nof_samples, tx_time.get(device_idx));
}
is_start_of_burst = false;
return ret;
}
bool radio::open_dev(const uint32_t& device_idx, const std::string& device_name, const std::string& devive_args)
{
srslte_rf_t* rf_device = &rf_devices[device_idx];
char* dev_args = nullptr;
if (devive_args != "auto") {
dev_args = (char*)devive_args.c_str();
}
char* dev_name = nullptr;
if (device_name != "auto") {
dev_name = (char*)device_name.c_str();
}
log_h->console("Opening %d channels in RF device=%s with args=%s\n",
nof_channels_x_dev,
dev_name ? dev_name : "default",
dev_args ? dev_args : "default");
if (srslte_rf_open_devname(rf_device, dev_name, dev_args, nof_channels_x_dev)) {
log_h->error("Error opening RF device\n");
return false;
}
// Suppress radio stdout
srslte_rf_suppress_stdout(rf_device);
// Register handler for processing O/U/L
srslte_rf_register_error_handler(rf_device, rf_msg_callback, this);
// Get device info
rf_info[device_idx] = *srslte_rf_get_info(rf_device);
return true;
}
bool radio::tx_dev(const uint32_t& device_idx,
rf_buffer_interface& buffer,
const uint32_t& nof_samples_,
const srslte_timestamp_t& tx_time_)
{
uint32_t nof_samples = nof_samples_;
uint32_t sample_offset = 0;
srslte_rf_t* rf_device = &rf_devices[device_idx];
// Return instantly if the radio module is not initialised
if (!is_initialized) {
@ -281,7 +337,7 @@ bool radio::tx(rf_buffer_interface& buffer, const uint32_t& nof_samples_, const
// Calculate transmission overlap/gap if it is not start of the burst
if (not is_start_of_burst) {
// Calculates transmission time overlap with previous transmission
srslte_timestamp_t ts_overlap = end_of_burst_time;
srslte_timestamp_t ts_overlap = end_of_burst_time[device_idx];
srslte_timestamp_sub(&ts_overlap, tx_time.full_secs, tx_time.frac_secs);
// Calculates number of overlap samples with previous transmission
@ -297,9 +353,9 @@ bool radio::tx(rf_buffer_interface& buffer, const uint32_t& nof_samples_, const
}
// Trim the first past_nsamples
sample_offset = (uint32_t)past_nsamples; // Sets an offset for moving first samples offset
tx_time = end_of_burst_time; // Keeps same transmission time
nof_samples = nof_samples - past_nsamples; // Subtracts the number of trimmed samples
sample_offset = (uint32_t)past_nsamples; // Sets an offset for moving first samples offset
tx_time = end_of_burst_time[device_idx]; // Keeps same transmission time
nof_samples = nof_samples - past_nsamples; // Subtracts the number of trimmed samples
} else if (past_nsamples < 0) {
// if the gap is bigger than TX_MAX_GAP_ZEROS, stop burst
@ -313,8 +369,13 @@ bool radio::tx(rf_buffer_interface& buffer, const uint32_t& nof_samples_, const
uint32_t nzeros = SRSLTE_MIN(gap_nsamples, SRSLTE_SF_LEN_MAX);
// Zeros transmission
int ret = srslte_rf_send_timed2(
&rf_device, zeros, nzeros, end_of_burst_time.full_secs, end_of_burst_time.frac_secs, false, false);
int ret = srslte_rf_send_timed2(rf_device,
zeros,
nzeros,
end_of_burst_time[device_idx].full_secs,
end_of_burst_time[device_idx].frac_secs,
false,
false);
if (ret < SRSLTE_SUCCESS) {
return false;
}
@ -323,25 +384,25 @@ bool radio::tx(rf_buffer_interface& buffer, const uint32_t& nof_samples_, const
gap_nsamples -= nzeros;
// Increase timestamp
srslte_timestamp_add(&end_of_burst_time, 0, (double)nzeros / cur_tx_srate);
srslte_timestamp_add(&end_of_burst_time[device_idx], 0, (double)nzeros / cur_tx_srate);
}
}
}
}
// Save possible end of burst time
srslte_timestamp_copy(&end_of_burst_time, &tx_time);
srslte_timestamp_add(&end_of_burst_time, 0, (double)nof_samples / cur_tx_srate);
srslte_timestamp_copy(&end_of_burst_time[device_idx], &tx_time);
srslte_timestamp_add(&end_of_burst_time[device_idx], 0, (double)nof_samples / cur_tx_srate);
void* radio_buffers[SRSLTE_MAX_CHANNELS] = {};
if (!map_channels(rx_channel_mapping, sample_offset, buffer, radio_buffers)) {
if (not map_channels(rx_channel_mapping, device_idx, sample_offset, buffer, radio_buffers)) {
log_h->error("Mapping logical channels to physical channels for transmission\n");
return false;
}
int ret = srslte_rf_send_timed_multi(
&rf_device, radio_buffers, nof_samples, tx_time.full_secs, tx_time.frac_secs, true, is_start_of_burst, false);
is_start_of_burst = false;
rf_device, radio_buffers, nof_samples, tx_time.full_secs, tx_time.frac_secs, true, is_start_of_burst, false);
return ret > SRSLTE_SUCCESS;
}
@ -351,7 +412,10 @@ void radio::tx_end()
return;
}
if (!is_start_of_burst) {
srslte_rf_send_timed2(&rf_device, zeros, 0, end_of_burst_time.full_secs, end_of_burst_time.frac_secs, false, true);
for (uint32_t i = 0; i < (uint32_t)rf_devices.size(); i++) {
srslte_rf_send_timed2(
&rf_devices[i], zeros, 0, end_of_burst_time[i].full_secs, end_of_burst_time[i].frac_secs, false, true);
}
is_start_of_burst = true;
}
}
@ -387,7 +451,13 @@ void radio::set_rx_freq(const uint32_t& carrier_idx, const double& freq)
if ((physical_channel_idx + 1) * nof_antennas <= nof_channels) {
cur_rx_freqs[physical_channel_idx] = freq;
for (uint32_t i = 0; i < nof_antennas; i++) {
srslte_rf_set_rx_freq(&rf_device, physical_channel_idx * nof_antennas + i, freq + freq_offset);
uint32_t phys_antenna_idx = physical_channel_idx * nof_antennas + i;
// From channel number deduce RF device index and channel
uint32_t rf_device_idx = phys_antenna_idx / nof_channels_x_dev;
uint32_t rf_channel_idx = phys_antenna_idx % nof_channels_x_dev;
srslte_rf_set_rx_freq(&rf_devices[rf_device_idx], rf_channel_idx, freq + freq_offset);
}
} else {
log_h->error("set_rx_freq: physical_channel_idx=%d for %d antennas exceeds maximum channels (%d)\n",
@ -408,7 +478,9 @@ void radio::set_rx_gain(const float& gain)
if (!is_initialized) {
return;
}
srslte_rf_set_rx_gain(&rf_device, gain);
for (srslte_rf_t& rf_device : rf_devices) {
srslte_rf_set_rx_gain(&rf_device, gain);
}
}
void radio::set_rx_gain_th(const float& gain)
@ -416,7 +488,9 @@ void radio::set_rx_gain_th(const float& gain)
if (!is_initialized) {
return;
}
srslte_rf_set_rx_gain_th(&rf_device, gain);
for (srslte_rf_t& rf_device : rf_devices) {
srslte_rf_set_rx_gain_th(&rf_device, gain);
}
}
void radio::set_rx_srate(const double& srate)
@ -424,7 +498,9 @@ void radio::set_rx_srate(const double& srate)
if (!is_initialized) {
return;
}
srslte_rf_set_rx_srate(&rf_device, srate);
for (srslte_rf_t& rf_device : rf_devices) {
srslte_rf_set_rx_srate(&rf_device, srate);
}
}
void radio::set_tx_freq(const uint32_t& carrier_idx, const double& freq)
@ -447,7 +523,13 @@ void radio::set_tx_freq(const uint32_t& carrier_idx, const double& freq)
if ((physical_channel_idx + 1) * nof_antennas <= nof_channels) {
cur_tx_freqs[physical_channel_idx] = freq;
for (uint32_t i = 0; i < nof_antennas; i++) {
srslte_rf_set_tx_freq(&rf_device, physical_channel_idx * nof_antennas + i, freq + freq_offset);
uint32_t phys_antenna_idx = physical_channel_idx * nof_antennas + i;
// From channel number deduce RF device index and channel
uint32_t rf_device_idx = phys_antenna_idx / nof_channels_x_dev;
uint32_t rf_channel_idx = phys_antenna_idx % nof_channels_x_dev;
srslte_rf_set_tx_freq(&rf_devices[rf_device_idx], rf_channel_idx, freq + freq_offset);
}
} else {
log_h->error("set_tx_freq: physical_channel_idx=%d for %d antennas exceeds maximum channels (%d)\n",
@ -468,7 +550,9 @@ void radio::set_tx_gain(const float& gain)
if (!is_initialized) {
return;
}
srslte_rf_set_tx_gain(&rf_device, gain);
for (srslte_rf_t& rf_device : rf_devices) {
srslte_rf_set_tx_gain(&rf_device, gain);
}
}
double radio::get_freq_offset()
@ -481,23 +565,18 @@ float radio::get_rx_gain()
if (!is_initialized) {
return 0.0f;
}
return srslte_rf_get_rx_gain(&rf_device);
return (float)srslte_rf_get_rx_gain(&rf_devices[0]);
}
void radio::set_tx_srate(const double& srate)
double radio::get_dev_cal_tx_adv_sec(const std::string& device_name)
{
if (!is_initialized) {
return;
}
cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, srate);
int nsamples = 0;
/* Set time advance for each known device if in auto mode */
if (tx_adv_auto) {
/* This values have been calibrated using the prach_test_usrp tool in srsLTE */
if (!strcmp(srslte_rf_name(&rf_device), "uhd_b200")) {
if (device_name == "uhd_b200") {
double srate_khz = round(cur_tx_srate / 1e3);
if (srate_khz == 1.92e3) {
@ -523,10 +602,10 @@ void radio::set_tx_srate(const double& srate)
log_h->console(
"\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n",
cur_tx_srate);
nsamples = cur_tx_srate * (uhd_default_tx_adv_samples * (1 / cur_tx_srate) + uhd_default_tx_adv_offset_sec);
nsamples = uhd_default_tx_adv_samples + (int)(cur_tx_srate * uhd_default_tx_adv_offset_sec);
}
} else if (!strcmp(srslte_rf_name(&rf_device), "uhd_usrp2")) {
} else if (device_name == "uhd_usrp2") {
double srate_khz = round(cur_tx_srate / 1e3);
if (srate_khz == 1.92e3) {
nsamples = 14; // estimated
@ -545,10 +624,10 @@ void radio::set_tx_srate(const double& srate)
log_h->console(
"\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n",
cur_tx_srate);
nsamples = cur_tx_srate * (uhd_default_tx_adv_samples * (1 / cur_tx_srate) + uhd_default_tx_adv_offset_sec);
nsamples = uhd_default_tx_adv_samples + (int)(cur_tx_srate * uhd_default_tx_adv_offset_sec);
}
} else if (!strcmp(srslte_rf_name(&rf_device), "lime")) {
} else if (device_name == "lime") {
double srate_khz = round(cur_tx_srate / 1e3);
if (srate_khz == 1.92e3) {
nsamples = 28;
@ -567,14 +646,14 @@ void radio::set_tx_srate(const double& srate)
log_h->console(
"\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n",
cur_tx_srate);
nsamples = cur_tx_srate * (uhd_default_tx_adv_samples * (1 / cur_tx_srate) + uhd_default_tx_adv_offset_sec);
nsamples = lime_default_tx_adv_samples + (int)(cur_tx_srate * lime_default_tx_adv_offset_sec);
}
} else if (!strcmp(srslte_rf_name(&rf_device), "uhd_x300")) {
} else if (device_name == "uhd_x300") {
// In X300 TX/RX offset is independent of sampling rate
nsamples = 45;
} else if (!strcmp(srslte_rf_name(&rf_device), "bladerf")) {
} else if (device_name == "bladerf") {
double srate_khz = round(cur_tx_srate / 1e3);
if (srate_khz == 1.92e3) {
@ -594,9 +673,9 @@ void radio::set_tx_srate(const double& srate)
log_h->console(
"\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n",
cur_tx_srate);
nsamples = blade_default_tx_adv_samples + blade_default_tx_adv_offset_sec * cur_tx_srate;
nsamples = blade_default_tx_adv_samples + (int)(blade_default_tx_adv_offset_sec * cur_tx_srate);
}
} else if (!strcmp(srslte_rf_name(&rf_device), "zmq")) {
} else if (device_name == "zmq") {
nsamples = 0;
}
} else {
@ -605,7 +684,22 @@ void radio::set_tx_srate(const double& srate)
}
// Calculate TX advance in seconds from samples and sampling rate
tx_adv_sec = nsamples / cur_tx_srate;
return (double)nsamples / cur_tx_srate;
}
void radio::set_tx_srate(const double& srate)
{
if (!is_initialized) {
return;
}
for (srslte_rf_t& rf_device : rf_devices) {
cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, srate);
}
// Get calibrated advanced
tx_adv_sec = get_dev_cal_tx_adv_sec(std::string(srslte_rf_name(&rf_devices[0])));
if (tx_adv_sec < 0) {
tx_adv_sec *= -1;
tx_adv_negative = true;
@ -615,9 +709,9 @@ void radio::set_tx_srate(const double& srate)
srslte_rf_info_t* radio::get_info()
{
if (!is_initialized) {
return NULL;
return nullptr;
}
return srslte_rf_get_info(&rf_device);
return srslte_rf_get_info(&rf_devices[0]);
}
bool radio::get_metrics(rf_metrics_t* metrics)
@ -668,6 +762,7 @@ void radio::rf_msg_callback(void* arg, srslte_rf_error_t error)
}
bool radio::map_channels(channel_mapping& map,
uint32_t device_idx,
uint32_t sample_offset,
const rf_buffer_interface& buffer,
void* radio_buffers[SRSLTE_MAX_CHANNELS])
@ -679,21 +774,38 @@ bool radio::map_channels(channel_mapping& map,
// Conversion from safe C++ std::array to the unsafe C interface. We must ensure that the RF driver implementation
// accepts up to SRSLTE_MAX_CHANNELS buffers
for (uint32_t i = 0; i < nof_carriers; i++) {
if (map.is_allocated(i)) {
uint32_t physical_idx = map.get_carrier_idx(i);
for (uint32_t j = 0; j < nof_antennas; j++) {
if (physical_idx * nof_antennas + j < SRSLTE_MAX_CHANNELS) {
cf_t* ptr = buffer.get(i, j, nof_antennas);
// Skip if not allocated
if (not map.is_allocated(i)) {
continue;
}
// Add sample offset only if it is a valid pointer
if (ptr != nullptr) {
ptr += sample_offset;
}
// Get physical channel
uint32_t physical_idx = map.get_carrier_idx(i);
radio_buffers[physical_idx * nof_antennas + j] = ptr;
} else {
return false;
// Map each antenna
for (uint32_t j = 0; j < nof_antennas; j++) {
// Detect mapping out-of-bounds
if (physical_idx * nof_antennas + j >= SRSLTE_MAX_CHANNELS) {
return false;
}
// Calculate actual physical port index
uint32_t phys_chan_idx = physical_idx * nof_antennas + j;
// Deduce physical device and port
uint32_t rf_device_idx = phys_chan_idx / nof_channels_x_dev;
uint32_t rf_channel_idx = phys_chan_idx % nof_channels_x_dev;
// Set pointer if device index matches
if (rf_device_idx == device_idx) {
cf_t* ptr = buffer.get(i, j, nof_antennas);
// Add sample offset only if it is a valid pointer
if (ptr != nullptr) {
ptr += sample_offset;
}
radio_buffers[rf_channel_idx] = ptr;
}
}
}
@ -733,56 +845,4 @@ bool radio::config_rf_channels(const rf_args_t& args)
return true;
}
/***
* Carrier mapping class
*/
bool radio::channel_mapping::allocate_freq(const uint32_t& logical_ch, const float& freq)
{
std::lock_guard<std::mutex> lock(mutex);
if (allocated_channels.count(logical_ch)) {
ERROR("allocate_freq: Carrier logical_ch=%d already allocated to channel=%d\n",
logical_ch,
allocated_channels[logical_ch].carrier_idx);
return false;
}
// Find first available channel that supports this frequency and allocated it
for (auto c = available_channels.begin(); c != available_channels.end(); ++c) {
if (c->band.contains(freq)) {
allocated_channels[logical_ch] = *c;
available_channels.erase(c);
return true;
}
}
ERROR("allocate_freq: No channels available for frequency=%.1f\n", freq);
return false;
}
bool radio::channel_mapping::release_freq(const uint32_t& logical_ch)
{
std::lock_guard<std::mutex> lock(mutex);
if (allocated_channels.count(logical_ch)) {
available_channels.push_back(allocated_channels[logical_ch]);
allocated_channels.erase(logical_ch);
return true;
}
return false;
}
int radio::channel_mapping::get_carrier_idx(const uint32_t& logical_ch)
{
std::lock_guard<std::mutex> lock(mutex);
if (allocated_channels.count(logical_ch)) {
return allocated_channels[logical_ch].carrier_idx;
}
return -1;
}
bool radio::channel_mapping::is_allocated(const uint32_t& logical_ch)
{
std::lock_guard<std::mutex> lock(mutex);
return allocated_channels.count(logical_ch) > 0;
}
} // namespace srslte

View File

@ -265,19 +265,15 @@ private:
int main(int argc, char** argv)
{
int ret = SRSLTE_ERROR;
radio* radio_h[SRSLTE_MAX_RADIOS] = {NULL};
srslte_timestamp_t ts_prev[SRSLTE_MAX_RADIOS], ts_rx[SRSLTE_MAX_RADIOS], ts_tx;
uint32_t nof_gaps = 0;
char filename[256] = {};
srslte_filesink_t filesink[SRSLTE_MAX_RADIOS] = {};
srslte_dft_plan_t dft_plan = {}, idft_plan = {};
srslte_agc_t agc[SRSLTE_MAX_RADIOS] = {};
phy_dummy phy;
bzero(&ts_prev, sizeof(ts_prev));
bzero(&ts_rx, sizeof(ts_rx));
bzero(&ts_tx, sizeof(ts_tx));
int ret = SRSLTE_ERROR;
radio* radio_h[SRSLTE_MAX_RADIOS] = {nullptr};
srslte::rf_timestamp_t ts_prev[SRSLTE_MAX_RADIOS], ts_rx[SRSLTE_MAX_RADIOS], ts_tx;
uint32_t nof_gaps = 0;
char filename[256] = {};
srslte_filesink_t filesink[SRSLTE_MAX_RADIOS] = {};
srslte_dft_plan_t dft_plan = {}, idft_plan = {};
srslte_agc_t agc[SRSLTE_MAX_RADIOS] = {};
phy_dummy phy;
rf_buffer_t rf_buffers[SRSLTE_MAX_RADIOS] = {};
@ -413,7 +409,7 @@ int main(int argc, char** argv)
// receive each radio
for (uint32_t r = 0; r < nof_radios; r++) {
radio_h[r]->rx_now(rf_buffers[r], frame_size, &ts_rx[r]);
radio_h[r]->rx_now(rf_buffers[r], frame_size, ts_rx[r]);
}
// run agc
@ -426,8 +422,8 @@ int main(int argc, char** argv)
// Transmit
if (tx_enable) {
for (uint32_t r = 0; r < nof_radios; r++) {
srslte_timestamp_copy(&ts_tx, &ts_rx[r]);
srslte_timestamp_add(&ts_tx, 0, 0.004);
ts_tx.copy(ts_rx[r]);
ts_tx.add(0.004);
radio_h[r]->tx(rf_buffers[r], frame_size, ts_tx);
}
}
@ -485,20 +481,19 @@ int main(int argc, char** argv)
if (i != 0) {
for (uint32_t r = 0; r < nof_radios; r++) {
srslte_timestamp_t ts_diff;
bzero(&ts_diff, sizeof(ts_diff));
srslte_timestamp_copy(&ts_diff, &ts_rx[r]);
srslte_timestamp_sub(&ts_diff, ts_prev[r].full_secs, ts_prev[r].frac_secs);
gap = (int)round(srslte_timestamp_real(&ts_diff) * srate) - frame_size;
srslte_timestamp_copy(&ts_diff, ts_rx[r].get_ptr(0));
srslte_timestamp_sub(&ts_diff, ts_prev[r].get_ptr(0)->full_secs, ts_prev[r].get_ptr(0)->frac_secs);
gap = (int32_t)round(srslte_timestamp_real(&ts_diff) * srate) - (int32_t)frame_size;
if (gap) {
if (gap != 0) {
INFO("Timestamp gap (%d samples) detected! Frame %d/%d. ts=%.9f+%.9f=%.9f\n",
gap,
i + 1,
nof_frames,
srslte_timestamp_real(&ts_prev[r]),
srslte_timestamp_real(ts_prev[r].get_ptr(0)),
srslte_timestamp_real(&ts_diff),
srslte_timestamp_real(&ts_rx[r]));
srslte_timestamp_real(ts_rx[r].get_ptr(0)));
nof_gaps++;
}
}
@ -506,7 +501,7 @@ int main(int argc, char** argv)
/* Save timestamp */
for (uint32_t r = 0; r < nof_radios; r++) {
srslte_timestamp_copy(&ts_prev[r], &ts_rx[r]);
ts_prev[r].copy(ts_rx[r]);
}
nof_samples -= frame_size;

View File

@ -63,7 +63,7 @@ public:
* @param nof_samples number of samples to transmit
* @param tx_time timestamp to transmit samples
*/
void worker_end(void* tx_sem_id, srslte::rf_buffer_t& buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
void worker_end(void* tx_sem_id, srslte::rf_buffer_t& buffer, uint32_t nof_samples, srslte::rf_timestamp_t& tx_time);
// Common objects
phy_args_t params = {};

View File

@ -39,7 +39,7 @@ public:
void init(phy_common* phy, srslte::log* log_h);
cf_t* get_buffer_rx(uint32_t cc_idx, uint32_t antenna_idx);
void set_time(uint32_t tti, uint32_t tx_worker_cnt, srslte_timestamp_t tx_time);
void set_time(uint32_t tti_, uint32_t tx_worker_cnt_, const srslte::rf_timestamp_t& tx_time_);
int add_rnti(uint16_t rnti, uint32_t cc_idx);
void rem_rnti(uint16_t rnti);
@ -65,10 +65,10 @@ private:
bool running = false;
std::mutex work_mutex;
uint32_t tti_rx = 0, tti_tx_dl = 0, tti_tx_ul = 0;
uint32_t t_rx = 0, t_tx_dl = 0, t_tx_ul = 0;
uint32_t tx_worker_cnt = 0;
srslte_timestamp_t tx_time = {};
uint32_t tti_rx = 0, tti_tx_dl = 0, tti_tx_ul = 0;
uint32_t t_rx = 0, t_tx_dl = 0, t_tx_ul = 0;
uint32_t tx_worker_cnt = 0;
srslte::rf_timestamp_t tx_time = {};
std::vector<std::unique_ptr<cc_worker> > cc_workers;

View File

@ -124,17 +124,17 @@ void phy_common::set_ul_grants(uint32_t tti, const stack_interface_phy_lte::ul_s
* Each worker uses this function to indicate that all processing is done and data is ready for transmission or
* there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio
*/
void phy_common::worker_end(void* tx_sem_id,
srslte::rf_buffer_t& buffer,
uint32_t nof_samples,
srslte_timestamp_t tx_time)
void phy_common::worker_end(void* tx_sem_id,
srslte::rf_buffer_t& buffer,
uint32_t nof_samples,
srslte::rf_timestamp_t& tx_time)
{
// Wait for the green light to transmit in the current TTI
semaphore.wait(tx_sem_id);
// Run DL channel emulator if created
if (dl_channel) {
dl_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), nof_samples, tx_time);
dl_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), nof_samples, tx_time.get(0));
}
// Always transmit on single radio

View File

@ -111,7 +111,7 @@ cf_t* sf_worker::get_buffer_rx(uint32_t cc_idx, uint32_t antenna_idx)
return cc_workers[cc_idx]->get_buffer_rx(antenna_idx);
}
void sf_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, srslte_timestamp_t tx_time_)
void sf_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, const srslte::rf_timestamp_t& tx_time_)
{
tti_rx = tti_;
tti_tx_dl = TTI_ADD(tti_rx, FDD_HARQ_DELAY_UL_MS);
@ -122,7 +122,7 @@ void sf_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, srslte_timestam
t_tx_ul = TTIMOD(tti_tx_ul);
tx_worker_cnt = tx_worker_cnt_;
srslte_timestamp_copy(&tx_time, &tx_time_);
tx_time.copy(tx_time_);
for (auto& w : cc_workers) {
w->set_tti(tti_);

View File

@ -87,11 +87,10 @@ void txrx::stop()
void txrx::run_thread()
{
sf_worker* worker = nullptr;
srslte::rf_buffer_t buffer = {};
srslte_timestamp_t rx_time = {};
srslte_timestamp_t tx_time = {};
uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->get_nof_prb(0));
sf_worker* worker = nullptr;
srslte::rf_buffer_t buffer = {};
srslte::rf_timestamp_t timestamp = {};
uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->get_nof_prb(0));
float samp_rate = srslte_sampling_freq_hz(worker_com->get_nof_prb(0));
@ -134,24 +133,23 @@ void txrx::run_thread()
}
}
radio_h->rx_now(buffer, sf_len, &rx_time);
radio_h->rx_now(buffer, sf_len, timestamp);
if (ul_channel) {
ul_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), sf_len, rx_time);
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 */
srslte_timestamp_copy(&tx_time, &rx_time);
srslte_timestamp_add(&tx_time, 0, FDD_HARQ_DELAY_UL_MS * 1e-3);
// 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\n",
tti,
tx_worker_cnt,
tx_time.full_secs,
tx_time.frac_secs,
timestamp.get(0).full_secs,
timestamp.get(0).frac_secs,
worker->get_id());
worker->set_time(tti, tx_worker_cnt, tx_time);
worker->set_time(tti, tx_worker_cnt, timestamp);
tx_worker_cnt = (tx_worker_cnt + 1) % nof_workers;
// Trigger phy worker execution

View File

@ -80,7 +80,7 @@ private:
srslte::log_filter log_h;
std::vector<srslte_ringbuffer_t*> ringbuffers_tx;
std::vector<srslte_ringbuffer_t*> ringbuffers_rx;
srslte_timestamp_t ts_rx = {};
srslte::rf_timestamp_t ts_rx = {};
double rx_srate = 0.0;
bool running = true;
@ -186,7 +186,9 @@ public:
}
}
bool tx(srslte::rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time) override
bool tx(srslte::rf_buffer_interface& buffer,
const uint32_t& nof_samples,
const srslte::rf_timestamp_interface& tx_time) override
{
int err = SRSLTE_SUCCESS;
@ -207,7 +209,9 @@ public:
return err >= SRSLTE_SUCCESS;
}
void tx_end() override {}
bool rx_now(srslte::rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time) override
bool rx_now(srslte::rf_buffer_interface& buffer,
const uint32_t& nof_samples,
srslte::rf_timestamp_interface& rxd_time) override
{
int err = SRSLTE_SUCCESS;
@ -224,13 +228,11 @@ public:
}
// Copy new timestamp
if (rxd_time) {
*rxd_time = ts_rx;
}
rxd_time = ts_rx;
// Copy new timestamp
if (std::isnormal(rx_srate)) {
srslte_timestamp_add(&ts_rx, 0, static_cast<double>(nof_samples) / rx_srate);
ts_rx.add(static_cast<double>(nof_samples) / rx_srate);
}
// Notify Rx

View File

@ -138,8 +138,11 @@ public:
srslte_pdsch_ack_resource_t resource);
bool get_dl_pending_ack(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, srslte_pdsch_ack_cc_t* ack);
void
worker_end(void* h, bool tx_enable, srslte::rf_buffer_t& buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
void worker_end(void* h,
bool tx_enable,
srslte::rf_buffer_t& buffer,
uint32_t nof_samples,
srslte::rf_timestamp_t& tx_time);
void set_cell(const srslte_cell_t& c);
void set_nof_workers(uint32_t nof_workers);

View File

@ -55,7 +55,7 @@ public:
cf_t* get_buffer(uint32_t cc_idx, uint32_t antenna_idx);
uint32_t get_buffer_len();
void set_tti(uint32_t tti);
void set_tx_time(srslte_timestamp_t tx_time);
void set_tx_time(const srslte::rf_timestamp_t& tx_time);
void set_prach(cf_t* prach_ptr, float prach_power);
void set_cfo(const uint32_t& cc_idx, float cfo);
@ -104,13 +104,13 @@ private:
srslte_tdd_config_t tdd_config = {};
std::condition_variable cell_init_cond;
bool cell_initiated = false;
bool cell_initiated = false;
cf_t* prach_ptr = nullptr;
float prach_power = 0;
uint32_t tti = 0;
srslte_timestamp_t tx_time = {};
uint32_t tti = 0;
srslte::rf_timestamp_t tx_time = {};
uint32_t rssi_read_cnt = 0;
};

View File

@ -153,6 +153,7 @@ private:
bool running = false;
bool is_overflow = false;
srslte::rf_timestamp_t last_rx_time;
bool forced_rx_time_init = true; // Rx time sync after first receive from radio
// Objects for internal use

View File

@ -47,10 +47,7 @@ phy_common::phy_common()
reset();
}
phy_common::~phy_common()
{
}
phy_common::~phy_common() = default;
void phy_common::set_nof_workers(uint32_t nof_workers_)
{
@ -101,8 +98,8 @@ void phy_common::set_ue_dl_cfg(srslte_ue_dl_cfg_t* ue_dl_cfg)
chest_cfg->noise_alg = SRSLTE_NOISE_ALG_PSS;
}
chest_cfg->rsrp_neighbour = false;
chest_cfg->sync_error_enable = args->correct_sync_error;
chest_cfg->rsrp_neighbour = false;
chest_cfg->sync_error_enable = args->correct_sync_error;
chest_cfg->estimator_alg =
args->interpolate_subframe_enabled ? SRSLTE_ESTIMATOR_ALG_INTERPOLATE : SRSLTE_ESTIMATOR_ALG_AVERAGE;
chest_cfg->cfo_estimate_enable = args->cfo_ref_mask != 0;
@ -524,23 +521,23 @@ bool phy_common::get_dl_pending_ack(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, srs
* Each worker uses this function to indicate that all processing is done and data is ready for transmission or
* there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio
*/
void phy_common::worker_end(void* tx_sem_id,
bool tx_enable,
srslte::rf_buffer_t& buffer,
uint32_t nof_samples,
srslte_timestamp_t tx_time)
void phy_common::worker_end(void* tx_sem_id,
bool tx_enable,
srslte::rf_buffer_t& buffer,
uint32_t nof_samples,
srslte::rf_timestamp_t& tx_time)
{
// Wait for the green light to transmit in the current TTI
semaphore.wait(tx_sem_id);
// Add Time Alignment
srslte_timestamp_sub(&tx_time, 0, ta.get_sec());
tx_time.sub((double)ta.get_sec());
// For each radio, transmit
if (tx_enable && !srslte_timestamp_iszero(&tx_time)) {
if (tx_enable) {
if (ul_channel) {
ul_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), nof_samples, tx_time);
ul_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), nof_samples, tx_time.get(0));
}
radio_h->tx(buffer, nof_samples, tx_time);
@ -552,9 +549,9 @@ void phy_common::worker_end(void* tx_sem_id,
} else {
if (!radio_h->get_is_start_of_burst()) {
if (ul_channel && !srslte_timestamp_iszero(&tx_time)) {
if (ul_channel) {
srslte_vec_cf_zero(zeros_multi.get(0), nof_samples);
ul_channel->run(zeros_multi.to_cf_t(), zeros_multi.to_cf_t(), nof_samples, tx_time);
ul_channel->run(zeros_multi.to_cf_t(), zeros_multi.to_cf_t(), nof_samples, tx_time.get(0));
}
radio_h->tx(zeros_multi, nof_samples, tx_time);
@ -662,11 +659,11 @@ void phy_common::reset()
{
reset_radio();
sr_enabled = false;
cur_pathloss = 0;
cur_pusch_power = 0;
sr_last_tx_tti = -1;
cur_pusch_power = 0;
sr_enabled = false;
cur_pathloss = 0;
cur_pusch_power = 0;
sr_last_tx_tti = -1;
cur_pusch_power = 0;
pcell_report_period = 20;
ZERO_OBJECT(pathloss);

View File

@ -138,9 +138,9 @@ void sf_worker::set_tti(uint32_t tti_)
}
}
void sf_worker::set_tx_time(srslte_timestamp_t tx_time_)
void sf_worker::set_tx_time(const srslte::rf_timestamp_t& tx_time_)
{
tx_time = tx_time_;
tx_time.copy(tx_time_);
}
void sf_worker::set_prach(cf_t* prach_ptr_, float prach_power_)

View File

@ -429,11 +429,6 @@ void sync::run_camping_in_sync_state(sf_worker* worker, srslte::rf_buffer_t& syn
}
}
// Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time
srslte_timestamp_t tx_time;
srslte_ue_sync_get_last_timestamp(&ue_sync, &tx_time); // Get Rx Timestamp
srslte_timestamp_add(&tx_time, 0, FDD_HARQ_DELAY_DL_MS * 1e-3); // Add Tx delay
worker->set_prach(prach_ptr ? &prach_ptr[prach_sf_cnt * SRSLTE_SF_LEN_PRB(cell.nof_prb)] : nullptr, prach_power);
// Set CFO for all Carriers
@ -443,7 +438,10 @@ void sync::run_camping_in_sync_state(sf_worker* worker, srslte::rf_buffer_t& syn
}
worker->set_tti(tti);
worker->set_tx_time(tx_time);
// Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time
last_rx_time.add(FDD_HARQ_DELAY_DL_MS * 1e-3);
worker->set_tx_time(last_rx_time);
// Advance/reset prach subframe pointer
if (prach_ptr) {
@ -807,15 +805,21 @@ void sync::get_current_cell(srslte_cell_t* cell_, uint32_t* earfcn_)
int sync::radio_recv_fnc(srslte::rf_buffer_t& data, uint32_t nsamples, srslte_timestamp_t* rx_time)
{
srslte_timestamp_t ts = {};
// Use local timestamp if timestamp is not provided
if (!rx_time) {
rx_time = &ts;
}
// This function is designed for being called from the UE sync object which will pass a null rx_time in case
// receive dummy samples. So, rf_timestamp points at dummy timestamp in case rx_time is not provided
srslte::rf_timestamp_t dummy_ts = {};
srslte::rf_timestamp_t& rf_timestamp = (rx_time == nullptr) ? dummy_ts : last_rx_time;
// Receive
if (radio_h->rx_now(data, nsamples, rx_time)) {
if (radio_h->rx_now(data, nsamples, rf_timestamp)) {
srslte_timestamp_t dummy_flat_ts = {};
// Load flat timestamp
if (rx_time == nullptr) {
rx_time = &dummy_flat_ts;
}
*rx_time = rf_timestamp.get(0);
// check timestamp reset
if (forced_rx_time_init || srslte_timestamp_iszero(&tti_ts) || srslte_timestamp_compare(rx_time, &tti_ts) < 0) {
if (srslte_timestamp_compare(rx_time, &tti_ts) < 0) {

View File

@ -136,13 +136,13 @@ public:
}
}
int work(srslte_dl_sf_cfg_t* dl_sf,
srslte_dci_cfg_t* dci_cfg,
srslte_dci_dl_t* dci,
srslte_softbuffer_tx_t** softbuffer_tx,
uint8_t** data_tx,
cf_t* baseband_buffer,
const srslte_timestamp_t& ts)
int work(srslte_dl_sf_cfg_t* dl_sf,
srslte_dci_cfg_t* dci_cfg,
srslte_dci_dl_t* dci,
srslte_softbuffer_tx_t** softbuffer_tx,
uint8_t** data_tx,
cf_t* baseband_buffer,
const srslte::rf_timestamp_t& ts)
{
int ret = SRSLTE_SUCCESS;
@ -189,7 +189,7 @@ public:
srslte_enb_dl_gen_signal(&enb_dl);
// Apply channel
channel->run(signal_buffer, signal_buffer, sf_len, ts);
channel->run(signal_buffer, signal_buffer, sf_len, ts.get(0));
// Combine Tx ports
for (uint32_t i = 1; i < enb_dl.cell.nof_ports; i++) {
@ -417,7 +417,7 @@ int main(int argc, char** argv)
// Common for simulation and over-the-air
cf_t* baseband_buffer = srslte_vec_cf_malloc(SRSLTE_SF_LEN_MAX);
srslte_timestamp_t ts = {};
srslte::rf_timestamp_t ts = {};
srsue::scell::intra_measure intra_measure;
srslte::log_filter logger("intra_measure");
dummy_rrc rrc;
@ -567,7 +567,7 @@ int main(int argc, char** argv)
if (radio) {
// Receive radio
srslte::rf_buffer_t radio_buffer(baseband_buffer);
radio->rx_now(radio_buffer, SRSLTE_SF_LEN_PRB(cell_base.nof_prb), &ts);
radio->rx_now(radio_buffer, SRSLTE_SF_LEN_PRB(cell_base.nof_prb), ts);
} else {
// Run eNb simulator
bool put_pdsch = serving_cell_pdsch_enable;
@ -594,9 +594,9 @@ int main(int argc, char** argv)
dci.tb_cw_swap = false;
dci.pconf = false;
dci.power_offset = false;
dci.tpc_pucch = false;
dci.ra_preamble = false;
dci.ra_mask_idx = false;
dci.tpc_pucch = 0;
dci.ra_preamble = 0;
dci.ra_mask_idx = 0;
dci.srs_request = false;
dci.srs_request_present = false;
dci.cif_present = false;
@ -653,7 +653,7 @@ int main(int argc, char** argv)
}
// Increase Time counter
srslte_timestamp_add(&ts, 0, 0.001f);
ts.add(0.001);
// Give data to intra measure component
intra_measure.write(sf_idx % 10240, baseband_buffer, SRSLTE_SF_LEN_PRB(cell_base.nof_prb));

View File

@ -131,7 +131,7 @@ private:
std::mutex mutex;
std::condition_variable cvar;
srslte_rf_info_t rf_info = {};
srslte_timestamp_t tx_last_tx = {};
srslte::rf_timestamp_t tx_last_tx = {};
uint32_t count_late = 0;
CALLBACK(rx_now)
@ -191,8 +191,9 @@ private:
uint32_t get_count_late() { return count_late; }
bool
tx(srslte::rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time) override
bool tx(srslte::rf_buffer_interface& buffer,
const uint32_t& nof_samples,
const srslte::rf_timestamp_interface& tx_time) override
{
bool ret = true;
notify_tx();
@ -201,18 +202,20 @@ private:
if (!std::isnormal(tx_srate)) {
count_late++;
}
if (srslte_timestamp_compare(&tx_time, &tx_last_tx) < 0) {
if (srslte_timestamp_compare(&tx_time.get(0), tx_last_tx.get_ptr(0)) < 0) {
ret = false;
}
tx_last_tx = tx_time;
srslte_timestamp_add(&tx_last_tx, 0, (double)nof_samples / (double)tx_srate);
tx_last_tx.copy(tx_time);
tx_last_tx.add((double)nof_samples / (double)tx_srate);
return ret;
}
void release_freq(const uint32_t& carrier_idx) override{};
void tx_end() override {}
bool rx_now(srslte::rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time) override
bool rx_now(srslte::rf_buffer_interface& buffer,
const uint32_t& nof_samples,
srslte::rf_timestamp_interface& rxd_time) override
{
notify_rx_now();
@ -255,9 +258,7 @@ private:
}
// Set Rx timestamp
if (rxd_time) {
srslte_timestamp_init_uint64(rxd_time, rx_timestamp, (double)base_srate);
}
srslte_timestamp_init_uint64(rxd_time.get_ptr(0), rx_timestamp, (double)base_srate);
// Update timestamp
rx_timestamp += base_nsamples;