More development in UE NR SA cell search

master
Xavier Arteaga 3 years ago committed by Ismael Gomez
parent 47b857db25
commit fb17e3326f

@ -296,7 +296,11 @@ public:
* @brief Describes cell search arguments
*/
struct cell_search_args_t {
// TBD
double center_freq_hz;
double ssb_freq_hz;
srsran_subcarrier_spacing_t ssb_scs;
srsran_ssb_patern_t ssb_pattern;
srsran_duplex_mode_t duplex_mode;
};
/**

@ -49,8 +49,8 @@ private:
srslog::basic_logger& logger;
stack_interface_phy_sa_nr& stack;
srsran::radio_interface_phy& radio;
srsran_ue_sync_nr_t ue_sync_nr = {};
srsran::rf_timestamp_t last_rx_time;
srsran_ue_sync_nr_t ue_sync_nr = {};
srsran_timestamp_t stack_tti_ts_new = {};
srsran_timestamp_t stack_tti_ts = {};
bool forced_rx_time_init = true; // Rx time sync after first receive from radio

@ -81,6 +81,8 @@ public:
void stop();
state_t get_state() const;
void worker_end(const worker_context_t& w_ctx, const bool& tx_enable, srsran::rf_buffer_t& buffer) override;
private:
@ -91,11 +93,12 @@ private:
state_t state = STATE_IDLE;
state_t next_state = STATE_IDLE;
std::mutex state_mutex;
mutable std::mutex state_mutex;
std::condition_variable state_cvar;
std::atomic<bool> running = {false};
uint32_t sf_sz = 0; ///< Subframe size (1-ms)
srsran::tti_semaphore<void*> tti_semaphore;
srsran_slot_cfg_t slot_cfg = {};
cell_search searcher;
slot_sync slot_synchronizer;

@ -27,17 +27,11 @@ public:
struct args_t {
std::string log_level = "info"; ///< General PHY logging level
double srate_hz = 61.44e6; ///< Sampling rate in Hz
// Frequency allocation parameters
uint32_t pointA_arfcn = 0; ///< Resource grid PointA ARFCN
float pointA_Hz = 0; ///< Resource grid PointA frequency in Hz. Overrides pointA_arfcn if valid
uint32_t ssb_arfcn = 0; ///< SS/PBCH block center point ARFCN
float ssb_Hz = 0; ///< SS/PBCH block center point ARFCN. Overrides ssb_arfcn if valid
};
phy_nr_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_);
bool init(const args_t& args);
bool init(const args_t& args_);
int set_ul_grant(uint32_t rar_slot_idx,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
@ -56,15 +50,18 @@ public:
void clear_pending_grants() override {}
bool set_config(const srsran::phy_cfg_nr_t& cfg) override { return false; }
phy_nr_sa_state_t get_state() const override { return PHY_NR_SA_STATE_CELL_SELECT; }
void reset() override {}
bool start_cell_search(const cell_search_args_t& req) override { return false; }
phy_nr_sa_state_t get_state() const override;
void reset() override;
bool start_cell_search(const cell_search_args_t& req) override;
bool start_cell_select(const cell_search_args_t& req) override { return false; }
void stop() { sync.stop(); }
private:
nr::worker_pool workers;
nr::sync_sa sync;
srslog::basic_logger& logger;
args_t args;
};
} // namespace srsue

@ -14,13 +14,13 @@
namespace srsue {
phy_nr_sa::phy_nr_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_) :
logger(srslog::fetch_basic_logger("PHY-NR")),
sync(stack_, radio_, workers),
workers(4)
logger(srslog::fetch_basic_logger("PHY-NR")), sync(stack_, radio_, workers), workers(4)
{}
bool phy_nr_sa::init(const args_t& args)
bool phy_nr_sa::init(const args_t& args_)
{
args = args_;
nr::sync_sa::args_t sync_args = {};
sync_args.srate_hz = args.srate_hz;
if (not sync.init(sync_args)) {
@ -31,4 +31,39 @@ bool phy_nr_sa::init(const args_t& args)
return true;
}
phy_interface_rrc_sa_nr::phy_nr_sa_state_t phy_nr_sa::get_state() const
{
{
switch (sync.get_state()) {
case nr::sync_sa::STATE_IDLE:
break;
case nr::sync_sa::STATE_CELL_SEARCH:
return phy_interface_rrc_sa_nr::PHY_NR_SA_STATE_CELL_SEARCH;
case nr::sync_sa::STATE_CELL_SELECT:
return phy_interface_rrc_sa_nr::PHY_NR_SA_STATE_CELL_SELECT;
}
}
return phy_interface_rrc_sa_nr::PHY_NR_SA_STATE_IDLE;
}
void phy_nr_sa::reset()
{
sync.go_idle();
}
bool phy_nr_sa::start_cell_search(const cell_search_args_t& req)
{
// Prepare cell search configuration from the request
nr::cell_search::cfg_t cfg = {};
cfg.srate_hz = args.srate_hz;
cfg.center_freq_hz = req.center_freq_hz;
cfg.ssb_freq_hz = req.ssb_freq_hz;
cfg.ssb_scs = req.ssb_scs;
cfg.ssb_pattern = req.ssb_pattern;
cfg.duplex_mode = req.duplex_mode;
// Request cell search to lower synchronization instance
return sync.start_cell_search(cfg);
}
} // namespace srsue

@ -59,7 +59,7 @@ bool sync_sa::start_cell_search(const cell_search::cfg_t& cfg)
return false;
}
// Configure searcher without locking state
// Configure searcher without locking state for avoiding stalling the Rx stream
lock.unlock();
if (not searcher.start(cfg)) {
logger.error("Sync: failed to start cell search");
@ -70,11 +70,6 @@ bool sync_sa::start_cell_search(const cell_search::cfg_t& cfg)
// Transition to search
next_state = STATE_CELL_SEARCH;
// Wait for state transition
while (state != STATE_CELL_SEARCH) {
state_cvar.wait(lock);
}
return true;
}
@ -102,6 +97,13 @@ bool sync_sa::go_idle()
void sync_sa::stop()
{
running = false;
wait_thread_finish();
}
sync_sa::state_t sync_sa::get_state() const
{
std::unique_lock<std::mutex> lock(state_mutex);
return state;
}
void sync_sa::run_state_idle()
@ -111,7 +113,10 @@ void sync_sa::run_state_idle()
srsran::rf_timestamp_t ts = {};
// Receives from radio 1 slot
radio.rx_now(rf_buffer, ts);
stack.run_tti(slot_cfg.idx);
}
void sync_sa::run_state_cell_search()

@ -10,6 +10,7 @@
*
*/
#include "srsran/common/band_helper.h"
#include "srsue/hdr/phy/phy_nr_sa.h"
struct test_args_t {};
@ -23,20 +24,57 @@ private:
srsran_ssb_t ssb = {};
srsran_ringbuffer_t ringbuffer = {};
cf_t* buffer = nullptr;
uint32_t slot_idx = 0;
srsran_carrier_nr_t carrier = {};
std::atomic<bool> running = {true};
srslog::basic_logger& logger;
void run_async_slot()
{
// Early return if not running
if (not running) {
return;
}
// Zero slot buffer
srsran_vec_cf_zero(buffer, sf_len);
if (srsran_ssb_send(&ssb, slot_idx)) {
// Create MIB for this slot
srsran_mib_nr_t mib = {};
// Create PBCH message from packed MIB
srsran_pbch_msg_nr_t pbch_msg = {};
srsran_assert(srsran_pbch_msg_nr_mib_pack(&mib, &pbch_msg) >= SRSRAN_SUCCESS,
"Error packing MIB into PBCH message");
// Encode SSB signal and add it to the baseband
srsran_assert(srsran_ssb_add(&ssb, carrier.pci, &pbch_msg, buffer, buffer) >= SRSRAN_SUCCESS,
"Error adding SSB signal");
}
slot_idx++;
// Write slot samples in ringbuffer
srsran_assert(srsran_ringbuffer_write(&ringbuffer, buffer, (int)sizeof(cf_t) * sf_len) > SRSRAN_SUCCESS,
"Error writing in ringbuffer");
}
public:
struct args_t {
double srate_hz;
srsran_carrier_nr_t carrier;
srsran_subcarrier_spacing_t ssb_scs;
srsran_ssb_patern_t ssb_pattern;
srsran_ssb_patern_t ssb_periodicity_ms;
srsran_duplex_config_nr_t duplex;
uint32_t ssb_periodicity_ms;
srsran_duplex_mode_t duplex_mode;
};
gnb_emulator(const args_t& args) : logger(srslog::fetch_basic_logger(LOGNAME))
{
srsran_assert(
std::isnormal(args.srate_hz) and args.srate_hz > 0, "Invalid sampling rate (%.2f MHz)", args.srate_hz);
sf_len = args.srate_hz / 1000;
carrier = args.carrier;
srsran_ssb_args_t ssb_args = {};
ssb_args.enable_encode = true;
@ -48,33 +86,50 @@ public:
ssb_cfg.ssb_freq_hz = args.carrier.ssb_center_freq_hz;
ssb_cfg.scs = args.ssb_scs;
ssb_cfg.pattern = args.ssb_pattern;
ssb_cfg.duplex_mode = args.duplex.mode;
ssb_cfg.duplex_mode = args.duplex_mode;
ssb_cfg.periodicity_ms = args.ssb_periodicity_ms;
srsran_assert(srsran_ssb_set_cfg(&ssb, &ssb_cfg) == SRSRAN_SUCCESS, "SSB set config failed");
srsran_assert(srsran_ringbuffer_init(&ringbuffer, sizeof(cf_t) * BUFFER_SIZE_SF * sf_len),
srsran_assert(srsran_ringbuffer_init(&ringbuffer, sizeof(cf_t) * BUFFER_SIZE_SF * sf_len) >= SRSRAN_SUCCESS,
"Ringbuffer initialisation failed");
buffer = srsran_vec_cf_malloc(sf_len);
buffer = srsran_vec_cf_malloc(BUFFER_SIZE_SF * sf_len);
}
~gnb_emulator()
{
srsran_ssb_free(&ssb);
srsran_ringbuffer_free(&ringbuffer);
if (buffer != nullptr) {
free(buffer);
}
}
void tx_end() override {}
bool tx(srsran::rf_buffer_interface& buffer, const srsran::rf_timestamp_interface& tx_time) override { return false; }
bool rx_now(srsran::rf_buffer_interface& buffer, srsran::rf_timestamp_interface& rxd_time) override
bool tx(srsran::rf_buffer_interface& tx_buffer, const srsran::rf_timestamp_interface& tx_time) override
{
return false;
}
bool rx_now(srsran::rf_buffer_interface& rx_buffer, srsran::rf_timestamp_interface& rxd_time) override
{
uint32_t nbytes = sizeof(cf_t) * buffer.get_nof_samples();
int nbytes = (int)(sizeof(cf_t) * rx_buffer.get_nof_samples());
cf_t* temp_buffer = rx_buffer.get(0);
// If the buffer is invalid, use internal temporal buffer
if (temp_buffer == nullptr) {
temp_buffer = buffer;
}
// As long as there are not enough samples
while (srsran_ringbuffer_status(&ringbuffer) < nbytes) {
if (srsran_ringbuffer_write(&ringbuffer, ) < SRSRAN_SUCCESS) {
logger return false;
while (srsran_ringbuffer_status(&ringbuffer) < nbytes and running) {
run_async_slot();
}
if (not running) {
return true;
}
srsran_assert(srsran_ringbuffer_read(&ringbuffer, temp_buffer, nbytes) >= SRSRAN_SUCCESS,
"Error reading from ringbuffer");
return true;
}
void set_tx_freq(const uint32_t& carrier_idx, const double& freq) override {}
@ -91,11 +146,159 @@ public:
bool is_continuous_tx() override { return false; }
bool get_is_start_of_burst() override { return false; }
bool is_init() override { return false; }
void reset() override {}
void reset() override { running = false; }
srsran_rf_info_t* get_info() override { return nullptr; }
};
class dummy_stack : public srsue::stack_interface_phy_sa_nr
{
private:
srslog::basic_logger& logger = srslog::fetch_basic_logger("STACK");
bool pending_tti = false;
std::mutex pending_tti_mutex;
std::condition_variable pending_tti_cvar;
std::atomic<bool> running = {true};
public:
dummy_stack() { logger.set_level(srslog::str_to_basic_level("info")); }
void in_sync() override {}
void out_of_sync() override {}
void run_tti(const uint32_t tti) override
{
logger.debug("Run TTI %d", tti);
// Wait for tick
std::unique_lock<std::mutex> lock(pending_tti_mutex);
while (not pending_tti and running) {
pending_tti_cvar.wait(lock);
}
// Let the tick proceed
pending_tti = false;
pending_tti_cvar.notify_all();
}
void cell_search_found_cell(const cell_search_result_t& result) override
{
std::array<char, 512> csi_info = {};
srsran_csi_meas_info(&result.measurements, csi_info.data(), (uint32_t)csi_info.size());
logger.info("Cell found pci=%d barred=%c intra_freq=%c %s",
result.pci,
result.barred ? 'y' : 'n',
result.intra_freq_meas ? 'y' : 'n',
csi_info.data());
}
int sf_indication(const uint32_t tti) override
{
logger.info("SF %d indication", tti);
return 0;
}
sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); }
sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); }
void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) override {}
void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) override {}
void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) override {}
void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override {}
bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) override { return false; }
void tick()
{
// Wait for TTI to get processed
std::unique_lock<std::mutex> lock(pending_tti_mutex);
while (pending_tti) {
pending_tti_cvar.wait(lock);
}
// Let the TTI proceed
pending_tti = true;
pending_tti_cvar.notify_all();
}
void stop()
{
running = false;
pending_tti_cvar.notify_all();
}
};
struct args_t {
double srate_hz = 11.52e6;
srsran_carrier_nr_t carrier = SRSRAN_DEFAULT_CARRIER_NR;
srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_A;
uint32_t ssb_periodicity_ms = 10;
srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_15kHz;
srsran_duplex_mode_t duplex_mode = SRSRAN_DUPLEX_MODE_FDD;
uint32_t duration_ms = 1000;
void set_ssb_from_band(uint16_t band)
{
srsran::srsran_band_helper bands;
duplex_mode = bands.get_duplex_mode(band);
ssb_scs = bands.get_ssb_scs(band);
ssb_pattern = bands.get_ssb_pattern(band, ssb_scs);
carrier.ssb_center_freq_hz = bands.get_ssb_center_freq(carrier);
}
};
int main(int argc, char** argv)
{
// Parse Test arguments
args_t args;
// Initialise logging infrastructure
srslog::init();
// Radio can be constructed from different options
std::shared_ptr<srsran::radio_interface_phy> radio = nullptr;
// Create Radio as gNb emulator
gnb_emulator::args_t gnb_args = {};
gnb_args.srate_hz = args.srate_hz;
gnb_args.carrier = args.carrier;
gnb_args.ssb_pattern = args.ssb_pattern;
gnb_args.ssb_periodicity_ms = args.ssb_periodicity_ms;
gnb_args.duplex_mode = args.duplex_mode;
radio = std::make_shared<gnb_emulator>(gnb_args);
// Create stack
dummy_stack stack;
// Create UE PHY
srsue::phy_nr_sa phy(stack, *radio);
// Initialise PHY, it will instantly start free running
srsue::phy_nr_sa::args_t phy_args = {};
phy_args.srate_hz = args.srate_hz;
phy.init(phy_args);
// Transition PHY to cell search
srsue::phy_nr_sa::cell_search_args_t cell_search_req = {};
cell_search_req.center_freq_hz = args.carrier.dl_center_frequency_hz;
cell_search_req.ssb_freq_hz = args.carrier.ssb_center_freq_hz;
cell_search_req.ssb_scs = args.ssb_scs;
cell_search_req.ssb_pattern = args.ssb_pattern;
cell_search_req.duplex_mode = args.duplex_mode;
phy.start_cell_search(cell_search_req);
for (uint32_t i = 0; i < args.duration_ms; i++) {
stack.tick();
}
// First transition PHY to IDLE
phy.reset();
// Make sure PHY transitioned to IDLE
// ...
// Stop stack, it will let PHY free run
stack.stop();
// Stop PHY
phy.stop();
// Stop Radio
radio->reset();
return 0;
}
Loading…
Cancel
Save