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 * @brief Describes cell search arguments
*/ */
struct cell_search_args_t { 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; srslog::basic_logger& logger;
stack_interface_phy_sa_nr& stack; stack_interface_phy_sa_nr& stack;
srsran::radio_interface_phy& radio; srsran::radio_interface_phy& radio;
srsran_ue_sync_nr_t ue_sync_nr = {};
srsran::rf_timestamp_t last_rx_time; 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_new = {};
srsran_timestamp_t stack_tti_ts = {}; srsran_timestamp_t stack_tti_ts = {};
bool forced_rx_time_init = true; // Rx time sync after first receive from radio bool forced_rx_time_init = true; // Rx time sync after first receive from radio

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

@ -27,17 +27,11 @@ public:
struct args_t { struct args_t {
std::string log_level = "info"; ///< General PHY logging level std::string log_level = "info"; ///< General PHY logging level
double srate_hz = 61.44e6; ///< Sampling rate in Hz 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_); 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, int set_ul_grant(uint32_t rar_slot_idx,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant, std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
@ -56,15 +50,18 @@ public:
void clear_pending_grants() override {} void clear_pending_grants() override {}
bool set_config(const srsran::phy_cfg_nr_t& cfg) override { return false; } 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; } phy_nr_sa_state_t get_state() const override;
void reset() override {} void reset() override;
bool start_cell_search(const cell_search_args_t& req) override { return false; } bool start_cell_search(const cell_search_args_t& req) override;
bool start_cell_select(const cell_search_args_t& req) override { return false; } bool start_cell_select(const cell_search_args_t& req) override { return false; }
void stop() { sync.stop(); }
private: private:
nr::worker_pool workers; nr::worker_pool workers;
nr::sync_sa sync; nr::sync_sa sync;
srslog::basic_logger& logger; srslog::basic_logger& logger;
args_t args;
}; };
} // namespace srsue } // namespace srsue

@ -14,13 +14,13 @@
namespace srsue { namespace srsue {
phy_nr_sa::phy_nr_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_) : phy_nr_sa::phy_nr_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_) :
logger(srslog::fetch_basic_logger("PHY-NR")), logger(srslog::fetch_basic_logger("PHY-NR")), sync(stack_, radio_, workers), workers(4)
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 = {}; nr::sync_sa::args_t sync_args = {};
sync_args.srate_hz = args.srate_hz; sync_args.srate_hz = args.srate_hz;
if (not sync.init(sync_args)) { if (not sync.init(sync_args)) {
@ -31,4 +31,39 @@ bool phy_nr_sa::init(const args_t& args)
return true; 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 } // namespace srsue

@ -59,7 +59,7 @@ bool sync_sa::start_cell_search(const cell_search::cfg_t& cfg)
return false; return false;
} }
// Configure searcher without locking state // Configure searcher without locking state for avoiding stalling the Rx stream
lock.unlock(); lock.unlock();
if (not searcher.start(cfg)) { if (not searcher.start(cfg)) {
logger.error("Sync: failed to start cell search"); 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 // Transition to search
next_state = STATE_CELL_SEARCH; next_state = STATE_CELL_SEARCH;
// Wait for state transition
while (state != STATE_CELL_SEARCH) {
state_cvar.wait(lock);
}
return true; return true;
} }
@ -102,6 +97,13 @@ bool sync_sa::go_idle()
void sync_sa::stop() void sync_sa::stop()
{ {
running = false; 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() void sync_sa::run_state_idle()
@ -111,7 +113,10 @@ void sync_sa::run_state_idle()
srsran::rf_timestamp_t ts = {}; srsran::rf_timestamp_t ts = {};
// Receives from radio 1 slot
radio.rx_now(rf_buffer, ts); radio.rx_now(rf_buffer, ts);
stack.run_tti(slot_cfg.idx);
} }
void sync_sa::run_state_cell_search() 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" #include "srsue/hdr/phy/phy_nr_sa.h"
struct test_args_t {}; struct test_args_t {};
@ -23,20 +24,57 @@ private:
srsran_ssb_t ssb = {}; srsran_ssb_t ssb = {};
srsran_ringbuffer_t ringbuffer = {}; srsran_ringbuffer_t ringbuffer = {};
cf_t* buffer = nullptr; cf_t* buffer = nullptr;
uint32_t slot_idx = 0;
srsran_carrier_nr_t carrier = {};
std::atomic<bool> running = {true};
srslog::basic_logger& logger; 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: public:
struct args_t { struct args_t {
double srate_hz; double srate_hz;
srsran_carrier_nr_t carrier; srsran_carrier_nr_t carrier;
srsran_subcarrier_spacing_t ssb_scs; srsran_subcarrier_spacing_t ssb_scs;
srsran_ssb_patern_t ssb_pattern; srsran_ssb_patern_t ssb_pattern;
srsran_ssb_patern_t ssb_periodicity_ms; uint32_t ssb_periodicity_ms;
srsran_duplex_config_nr_t duplex; srsran_duplex_mode_t duplex_mode;
}; };
gnb_emulator(const args_t& args) : logger(srslog::fetch_basic_logger(LOGNAME)) gnb_emulator(const args_t& args) : logger(srslog::fetch_basic_logger(LOGNAME))
{ {
sf_len = args.srate_hz / 1000; 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 = {}; srsran_ssb_args_t ssb_args = {};
ssb_args.enable_encode = true; ssb_args.enable_encode = true;
@ -48,33 +86,50 @@ public:
ssb_cfg.ssb_freq_hz = args.carrier.ssb_center_freq_hz; ssb_cfg.ssb_freq_hz = args.carrier.ssb_center_freq_hz;
ssb_cfg.scs = args.ssb_scs; ssb_cfg.scs = args.ssb_scs;
ssb_cfg.pattern = args.ssb_pattern; 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; 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_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"); "Ringbuffer initialisation failed");
buffer = srsran_vec_cf_malloc(sf_len); buffer = srsran_vec_cf_malloc(BUFFER_SIZE_SF * sf_len);
} }
~gnb_emulator() ~gnb_emulator()
{ {
srsran_ssb_free(&ssb); srsran_ssb_free(&ssb);
srsran_ringbuffer_free(&ringbuffer); srsran_ringbuffer_free(&ringbuffer);
if (buffer != nullptr) {
free(buffer);
}
} }
void tx_end() override {} void tx_end() override {}
bool tx(srsran::rf_buffer_interface& buffer, const srsran::rf_timestamp_interface& tx_time) override { return false; } bool tx(srsran::rf_buffer_interface& tx_buffer, const srsran::rf_timestamp_interface& tx_time) override
bool rx_now(srsran::rf_buffer_interface& buffer, srsran::rf_timestamp_interface& rxd_time) override
{ {
uint32_t nbytes = sizeof(cf_t) * buffer.get_nof_samples(); return false;
}
bool rx_now(srsran::rf_buffer_interface& rx_buffer, srsran::rf_timestamp_interface& rxd_time) override
{
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 // As long as there are not enough samples
while (srsran_ringbuffer_status(&ringbuffer) < nbytes) { while (srsran_ringbuffer_status(&ringbuffer) < nbytes and running) {
if (srsran_ringbuffer_write(&ringbuffer, ) < SRSRAN_SUCCESS) { run_async_slot();
logger return false;
}
} }
if (not running) {
return true;
}
srsran_assert(srsran_ringbuffer_read(&ringbuffer, temp_buffer, nbytes) >= SRSRAN_SUCCESS,
"Error reading from ringbuffer");
return true; return true;
} }
void set_tx_freq(const uint32_t& carrier_idx, const double& freq) override {} 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 is_continuous_tx() override { return false; }
bool get_is_start_of_burst() override { return false; } bool get_is_start_of_burst() override { return false; }
bool is_init() 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; } 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) 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; return 0;
} }
Loading…
Cancel
Save