Improve robustness in RF Overflow (#1124)

* Use task id to track old background tasks in RA procedure

* Improve robustness against RF overflow in PHY

* Increase SNR out-of-sync threshold

* Do not change frequency if it's the same

* Increase sync priority

* Increase time to start receiving to reduce input buffer occupation

* Use scoped lock in sf_worker
This commit is contained in:
Ismael Gomez 2020-03-25 16:56:32 +01:00 committed by GitHub
parent 8aa44928e9
commit 95c6916987
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 136 additions and 125 deletions

View File

@ -223,6 +223,9 @@ private:
uint32_t nof_channels = 0;
uint32_t nof_carriers = 0;
std::vector<double> cur_tx_freqs = {};
std::vector<double> cur_rx_freqs = {};
// Define default values for known radios
constexpr static double uhd_default_tx_adv_samples = 98;
constexpr static double uhd_default_tx_adv_offset_sec = 4 * 1e-6;

View File

@ -403,7 +403,7 @@ int rf_uhd_start_rx_stream(void* h, bool now)
uhd_stream_cmd_t stream_cmd = {.stream_mode = UHD_STREAM_MODE_START_CONTINUOUS, .stream_now = now};
if (!now) {
uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs);
stream_cmd.time_spec_frac_secs += 0.2;
stream_cmd.time_spec_frac_secs += 0.5;
if (stream_cmd.time_spec_frac_secs > 1) {
stream_cmd.time_spec_frac_secs -= 1;
stream_cmd.time_spec_full_secs += 1;

View File

@ -86,6 +86,9 @@ int radio::init(const rf_args_t& args, phy_interface_radio* phy_)
nof_antennas = args.nof_antennas;
nof_carriers = args.nof_carriers;
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") {
@ -323,19 +326,24 @@ void radio::set_rx_freq(const uint32_t& carrier_idx, const double& freq)
// Map carrier index to physical channel
if (rx_channel_mapping.allocate_freq(carrier_idx, freq)) {
uint32_t physical_channel_idx = rx_channel_mapping.get_carrier_idx(carrier_idx);
if ((physical_channel_idx + 1) * nof_antennas <= nof_channels) {
for (uint32_t i = 0; i < nof_antennas; i++) {
log_h->info("Mapping RF channel %d to logical carrier %d on f_rx=%.1f MHz\n",
physical_channel_idx * nof_antennas + i,
carrier_idx,
freq / 1e6);
srslte_rf_set_rx_freq(&rf_device, physical_channel_idx * nof_antennas + i, freq + freq_offset);
log_h->info("Mapping RF channel %d to logical carrier %d on f_rx=%.1f MHz\n",
physical_channel_idx * nof_antennas,
carrier_idx,
freq / 1e6);
if (cur_rx_freqs[physical_channel_idx] != 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);
}
} else {
log_h->error("set_rx_freq: physical_channel_idx=%d for %d antennas exceeds maximum channels (%d)\n",
physical_channel_idx,
nof_antennas,
nof_channels);
}
} else {
log_h->error("set_rx_freq: physical_channel_idx=%d for %d antennas exceeds maximum channels (%d)\n",
physical_channel_idx,
nof_antennas,
nof_channels);
log_h->info("RF channel %d already on freq\n", physical_channel_idx * nof_antennas);
}
} else {
log_h->error("set_rx_freq: Could not allocate frequency %.1f MHz to carrier %d\n", freq / 1e6, carrier_idx);
@ -378,19 +386,24 @@ void radio::set_tx_freq(const uint32_t& carrier_idx, const double& freq)
// Map carrier index to physical channel
if (tx_channel_mapping.allocate_freq(carrier_idx, freq)) {
uint32_t physical_channel_idx = tx_channel_mapping.get_carrier_idx(carrier_idx);
if ((physical_channel_idx + 1) * nof_antennas <= nof_channels) {
for (uint32_t i = 0; i < nof_antennas; i++) {
log_h->info("Mapping RF channel %d to logical carrier %d on f_tx=%.1f MHz\n",
physical_channel_idx * nof_antennas + i,
carrier_idx,
freq / 1e6);
srslte_rf_set_tx_freq(&rf_device, physical_channel_idx * nof_antennas + i, freq + freq_offset);
log_h->info("Mapping RF channel %d to logical carrier %d on f_tx=%.1f MHz\n",
physical_channel_idx * nof_antennas,
carrier_idx,
freq / 1e6);
if (cur_tx_freqs[physical_channel_idx] != 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);
}
} else {
log_h->error("set_tx_freq: physical_channel_idx=%d for %d antennas exceeds maximum channels (%d)\n",
physical_channel_idx,
nof_antennas,
nof_channels);
}
} else {
log_h->error("set_tx_freq: physical_channel_idx=%d for %d antennas exceeds maximum channels (%d)\n",
physical_channel_idx,
nof_antennas,
nof_channels);
log_h->info("RF channel %d already on freq\n", physical_channel_idx * nof_antennas);
}
} else {
log_h->error("set_tx_freq: Could not allocate frequency %.1f MHz to carrier %d\n", freq / 1e6, carrier_idx);

View File

@ -133,7 +133,7 @@ private:
bool is_configured = false;
uint32_t nof_workers = 0;
const static int SF_RECV_THREAD_PRIO = 1;
const static int SF_RECV_THREAD_PRIO = 0;
const static int WORKERS_THREAD_PRIO = 2;
srslte::radio_interface_phy* radio = nullptr;

View File

@ -166,9 +166,8 @@ private:
bool set_frequency();
bool set_cell();
bool radio_is_overflow = false;
bool radio_overflow_return = false;
bool running = false;
bool is_overflow = false;
// Objects for internal use
search search_p;

View File

@ -61,6 +61,7 @@ public:
noncontention_enabled = false;
next_preamble_idx = 0;
next_prach_mask = 0;
current_task_id = 0;
};
~ra_proc();
@ -94,8 +95,8 @@ public:
bool contention_resolution_id_received(uint64_t uecri);
void start_pcap(srslte::mac_pcap* pcap);
void notify_phy_config_completed();
void notify_ra_completed();
void notify_phy_config_completed(uint32_t task_id);
void notify_ra_completed(uint32_t task_id);
private:
void state_pdcch_setup();
@ -139,6 +140,8 @@ private:
uint32_t ra_rnti;
uint32_t ra_tti;
uint32_t current_ta;
// The task_id is a unique number associated with each RA procedure used to track background tasks
uint32_t current_task_id;
srslte_softbuffer_rx_t softbuffer_rar;

View File

@ -361,7 +361,7 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
"RSRP threshold (in dBm) above which the UE considers to be in-sync")
("phy.in_sync_snr_db_th",
bpo::value<float>(&args->phy.in_sync_snr_db_th)->default_value(1.0f),
bpo::value<float>(&args->phy.in_sync_snr_db_th)->default_value(3.0f),
"SNR threshold (in dB) above which the UE considers to be in-sync")
("phy.nof_in_sync_events",

View File

@ -198,58 +198,60 @@ void sf_worker::set_config(uint32_t cc_idx, srslte::phy_cfg_t& phy_cfg)
void sf_worker::work_imp()
{
std::lock_guard<std::mutex> lock(mutex);
srslte::rf_buffer_t tx_signal_ptr = {};
if (!cell_initiated) {
phy->worker_end(this, false, tx_signal_ptr, 0, tx_time);
}
/***** Downlink Processing *******/
bool rx_signal_ok = false;
// Loop through all carriers. carrier_idx=0 is PCell
for (uint32_t carrier_idx = 0; carrier_idx < cc_workers.size(); carrier_idx++) {
// Process all DL and special subframes
if (srslte_sfidx_tdd_type(tdd_config, tti % 10) != SRSLTE_TDD_SF_U || cell.frame_type == SRSLTE_FDD) {
srslte_mbsfn_cfg_t mbsfn_cfg;
ZERO_OBJECT(mbsfn_cfg);
if (carrier_idx == 0 && phy->is_mbsfn_sf(&mbsfn_cfg, tti)) {
cc_workers[0]->work_dl_mbsfn(mbsfn_cfg); // Don't do chest_ok in mbsfn since it trigger measurements
} else {
if ((carrier_idx == 0) || phy->scell_cfg[carrier_idx].enabled) {
rx_signal_ok = cc_workers[carrier_idx]->work_dl_regular();
}
}
}
}
/***** Uplink Generation + Transmission *******/
bool rx_signal_ok = false;
bool tx_signal_ready = false;
uint32_t nof_samples = SRSLTE_SF_LEN_PRB(cell.nof_prb);
/* If TTI+4 is an uplink subframe (TODO: Support short PRACH and SRS in UpPts special subframes) */
if ((srslte_sfidx_tdd_type(tdd_config, TTI_TX(tti) % 10) == SRSLTE_TDD_SF_U) || cell.frame_type == SRSLTE_FDD) {
// Generate Uplink signal if no PRACH pending
if (!prach_ptr) {
/***** Downlink Processing *******/
{
std::lock_guard<std::mutex> lock(mutex);
// Common UCI data object for all carriers
srslte_uci_data_t uci_data;
reset_uci(&uci_data);
// Loop through all carriers. carrier_idx=0 is PCell
for (uint32_t carrier_idx = 0; carrier_idx < cc_workers.size(); carrier_idx++) {
// Loop through all carriers. Do in reverse order since control information from SCells is transmitted in PCell
for (int carrier_idx = phy->args->nof_carriers - 1; carrier_idx >= 0; carrier_idx--) {
tx_signal_ready |= cc_workers[carrier_idx]->work_ul(&uci_data);
// Process all DL and special subframes
if (srslte_sfidx_tdd_type(tdd_config, tti % 10) != SRSLTE_TDD_SF_U || cell.frame_type == SRSLTE_FDD) {
srslte_mbsfn_cfg_t mbsfn_cfg;
ZERO_OBJECT(mbsfn_cfg);
// Set signal pointer based on offset
cf_t* b = cc_workers[carrier_idx]->get_tx_buffer(0);
if (next_offset > 0) {
tx_signal_ptr.set(carrier_idx, 0, phy->args->nof_rx_ant, b);
if (carrier_idx == 0 && phy->is_mbsfn_sf(&mbsfn_cfg, tti)) {
cc_workers[0]->work_dl_mbsfn(mbsfn_cfg); // Don't do chest_ok in mbsfn since it trigger measurements
} else {
tx_signal_ptr.set(carrier_idx, 0, phy->args->nof_rx_ant, &b[-next_offset]);
if ((carrier_idx == 0) || phy->scell_cfg[carrier_idx].enabled) {
rx_signal_ok = cc_workers[carrier_idx]->work_dl_regular();
}
}
}
}
/***** Uplink Generation + Transmission *******/
/* If TTI+4 is an uplink subframe (TODO: Support short PRACH and SRS in UpPts special subframes) */
if ((srslte_sfidx_tdd_type(tdd_config, TTI_TX(tti) % 10) == SRSLTE_TDD_SF_U) || cell.frame_type == SRSLTE_FDD) {
// Generate Uplink signal if no PRACH pending
if (!prach_ptr) {
// Common UCI data object for all carriers
srslte_uci_data_t uci_data;
reset_uci(&uci_data);
// Loop through all carriers. Do in reverse order since control information from SCells is transmitted in PCell
for (int carrier_idx = phy->args->nof_carriers - 1; carrier_idx >= 0; carrier_idx--) {
tx_signal_ready |= cc_workers[carrier_idx]->work_ul(&uci_data);
// Set signal pointer based on offset
cf_t* b = cc_workers[carrier_idx]->get_tx_buffer(0);
if (next_offset > 0) {
tx_signal_ptr.set(carrier_idx, 0, phy->args->nof_rx_ant, b);
} else {
tx_signal_ptr.set(carrier_idx, 0, phy->args->nof_rx_ant, &b[-next_offset]);
}
}
}
}

View File

@ -134,8 +134,6 @@ void sync::stop()
void sync::reset()
{
radio_is_overflow = false;
radio_overflow_return = false;
in_sync_cnt = 0;
out_of_sync_cnt = 0;
time_adv_sec = 0;
@ -442,11 +440,17 @@ void sync::run_thread()
force_camping_sfn_sync = true;
}
if (is_overflow) {
force_camping_sfn_sync = true;
is_overflow = false;
log_h->info("Detected overflow, trying to resync SFN\n");
}
// Force decode MIB if required
if (force_camping_sfn_sync) {
uint32_t _tti = 0;
temp_cell = cell;
sync::sfn_sync::ret_code ret = sfn_p.decode_mib(&temp_cell, &_tti, &sf_buffer, mib);
sync::sfn_sync::ret_code ret = sfn_p.decode_mib(&temp_cell, &_tti, &sync_buffer, mib);
if (ret == sfn_sync::SFN_FOUND) {
// Force tti
tti = _tti;
@ -459,7 +463,11 @@ void sync::run_thread()
"reselection to cells with different MIB is not supported\n");
log_h->console("Detected cell during SFN synchronization differs from configured cell. Cell "
"reselection to cells with different MIB is not supported\n");
} else {
log_h->info("SFN resynchronized successfully\n");
}
} else {
log_h->warning("SFN not yet synchronized, sending out-of-sync\n");
}
}
@ -571,39 +579,6 @@ void sync::run_thread()
break;
}
/* Radio overflow detected. If CAMPING, go through SFN sync again and when
* SFN is found again go back to camping
*/
if (!rrc_mutex.try_lock()) {
if (radio_is_overflow) {
// If we are coming back from an overflow
if (radio_overflow_return) {
if (phy_state.is_camping()) {
log_h->info("Successfully resynchronized after overflow. Returning to CAMPING\n");
radio_overflow_return = false;
radio_is_overflow = false;
} else if (phy_state.is_idle()) {
log_h->warning("Could not synchronize SFN after radio overflow. Trying again\n");
stack->out_of_sync();
phy_state.force_sfn_sync();
}
} else {
// Overflow has occurred now while camping
if (phy_state.is_camping()) {
log_h->warning("Detected radio overflow while camping. Resynchronizing cell\n");
sfn_p.reset();
srslte_ue_sync_reset(&ue_sync);
phy_state.force_sfn_sync();
radio_overflow_return = true;
} else {
radio_is_overflow = false;
}
// If overflow occurs in any other state, it does not harm
}
}
rrc_mutex.unlock();
}
// Increase TTI counter
tti = (tti + 1) % 10240;
}
@ -616,7 +591,7 @@ void sync::run_thread()
*/
void sync::radio_overflow()
{
radio_is_overflow = true;
is_overflow = true;
}
void sync::radio_error()

View File

@ -236,51 +236,66 @@ void ra_proc::state_contention_resolution()
*/
void ra_proc::state_completition()
{
state = WAITING_COMPLETION;
uint16_t rnti = rntis->crnti;
stack->enqueue_background_task([this, rnti](uint32_t worker_id) {
state = WAITING_COMPLETION;
uint16_t rnti = rntis->crnti;
uint32_t task_id = current_task_id;
stack->enqueue_background_task([this, rnti, task_id](uint32_t worker_id) {
phy_h->set_crnti(rnti);
// signal MAC RA proc to go back to idle
notify_ra_completed();
notify_ra_completed(task_id);
});
}
void ra_proc::notify_phy_config_completed()
void ra_proc::notify_phy_config_completed(uint32_t task_id)
{
if (state != WAITING_PHY_CONFIG) {
rError("Received unexpected notification of PHY configuration completed\n");
if (current_task_id == task_id) {
if (state != WAITING_PHY_CONFIG) {
rError("Received unexpected notification of PHY configuration completed\n");
} else {
rDebug("RA waiting PHY configuration completed\n");
}
// Jump directly to Resource selection
resource_selection();
} else {
rDebug("RA waiting PHY configuration completed\n");
rError("Received old notification of PHY configuration (old task_id=%d, current_task_id=%d)\n",
task_id,
current_task_id);
}
// Jump directly to Resource selection
resource_selection();
}
void ra_proc::notify_ra_completed()
void ra_proc::notify_ra_completed(uint32_t task_id)
{
if (state != WAITING_COMPLETION) {
rError("Received unexpected notification of RA completion\n");
if (current_task_id == task_id) {
if (state != WAITING_COMPLETION) {
rError("Received unexpected notification of RA completion\n");
} else {
rInfo("RA waiting procedure completed\n");
}
state = IDLE;
} else {
rInfo("RA waiting procedure completed\n");
rError("Received old notification of RA completition (old task_id=%d, current_task_id=%d)\n",
task_id,
current_task_id);
}
state = IDLE;
}
/* RA procedure initialization as defined in 5.1.1 */
void ra_proc::initialization()
{
read_params();
current_task_id++;
transmitted_contention_id = 0;
preambleTransmissionCounter = 1;
mux_unit->msg3_flush();
backoff_param_ms = 0;
// Instruct phy to configure PRACH
state = WAITING_PHY_CONFIG;
stack->enqueue_background_task([this](uint32_t worker_id) {
state = WAITING_PHY_CONFIG;
uint32_t task_id = current_task_id;
stack->enqueue_background_task([this, task_id](uint32_t worker_id) {
phy_h->configure_prach_params();
// notify back MAC
stack->notify_background_task_result([this]() { notify_phy_config_completed(); });
stack->notify_background_task_result([this, task_id]() { notify_phy_config_completed(task_id); });
});
}

View File

@ -1002,6 +1002,7 @@ rrc::go_idle_proc::go_idle_proc(srsue::rrc* rrc_) : rrc_ptr(rrc_)
proc_outcome_t rrc::go_idle_proc::init()
{
Info("Starting...\n");
rlc_flush_timer.run();
return step();
}

View File

@ -343,7 +343,7 @@ enable = false
#force_ul_amplitude = 0
#in_sync_rsrp_dbm_th = -130.0
#in_sync_snr_db_th = 1.0
#in_sync_snr_db_th = 3.0
#nof_in_sync_events = 10
#nof_out_of_sync_events = 20