[REBASE] Make PHY non-blocking and fefactor HO procedure (#1753)

* Make PHY non-blocking and fefactor HO procedure

* makes entire PHY non-blocking through command interface
* adds dedicated queue for cell_search/cell_select commands
* refactor HO procedure to run faster, in one stack cycle. Looks closer to the specs
* force ue to always apply SIB2 configuration during reestablishment
* Run update_measurements in all workers

Co-authored-by: Ismael Gomez <ismagom@gmail.com>
master
Andre Puschmann 4 years ago committed by GitHub
parent 399b986d0b
commit 1afc137032
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,52 @@
/*
* 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_PHY_INTERFACE_TYPES_H
#define SRSLTE_PHY_INTERFACE_TYPES_H
#include "srslte/phy/phch/prach.h"
/// Common types defined by the PHY layer.
inline bool operator==(const srslte_tdd_config_t& a, const srslte_tdd_config_t& b)
{
return (a.sf_config == b.sf_config && a.ss_config == b.ss_config && a.configured == b.configured);
}
inline bool operator!=(const srslte_tdd_config_t& a, const srslte_tdd_config_t& b)
{
return !(a == b);
}
inline bool operator==(const srslte_prach_cfg_t& a, const srslte_prach_cfg_t& b)
{
return (a.config_idx == b.config_idx && a.root_seq_idx == b.root_seq_idx && a.zero_corr_zone == b.zero_corr_zone &&
a.freq_offset == b.freq_offset && a.num_ra_preambles == b.num_ra_preambles && a.hs_flag == b.hs_flag &&
a.tdd_config == b.tdd_config && a.enable_successive_cancellation == b.enable_successive_cancellation &&
a.enable_freq_domain_offset_calc == b.enable_freq_domain_offset_calc);
}
inline bool operator!=(const srslte_prach_cfg_t& a, const srslte_prach_cfg_t& b)
{
return !(a == b);
}
#endif // SRSLTE_PHY_INTERFACE_TYPES_H

@ -129,10 +129,16 @@ public:
class rrc_interface_mac : public rrc_interface_mac_common
{
public:
virtual void ho_ra_completed() = 0;
virtual void ra_completed() = 0;
virtual void release_pucch_srs() = 0;
};
struct phy_cell_t {
uint32_t pci;
uint32_t earfcn;
float cfo_hz;
};
// RRC interface for PHY
class rrc_interface_phy_lte
{
@ -149,6 +155,16 @@ public:
virtual void in_sync() = 0;
virtual void out_of_sync() = 0;
virtual void new_cell_meas(const std::vector<phy_meas_t>& meas) = 0;
typedef struct {
enum { CELL_FOUND = 0, CELL_NOT_FOUND, ERROR } found;
enum { MORE_FREQS = 0, NO_MORE_FREQS } last_freq;
} cell_search_ret_t;
virtual void cell_search_complete(cell_search_ret_t ret, phy_cell_t found_cell) = 0;
virtual void cell_select_complete(bool status) = 0;
virtual void set_config_complete(bool status) = 0;
virtual void set_scell_complete(bool status) = 0;
};
// RRC interface for NAS
@ -430,8 +446,6 @@ public:
class mac_interface_rrc : public mac_interface_rrc_common
{
public:
virtual void clear_rntis() = 0;
/* Instructs the MAC to start receiving BCCH */
virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0;
virtual void bcch_stop_rx() = 0;
@ -445,18 +459,15 @@ public:
/* Instructs the MAC to start receiving an MCH */
virtual void mch_start_rx(uint32_t lcid) = 0;
virtual void set_config(srslte::mac_cfg_t& mac_cfg) = 0;
virtual void set_config(srslte::mac_cfg_t& mac_cfg) = 0;
virtual void set_rach_ded_cfg(uint32_t preamble_index, uint32_t prach_mask) = 0;
virtual void get_rntis(ue_rnti_t* rntis) = 0;
virtual void set_contention_id(uint64_t uecri) = 0;
virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0;
virtual void start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask) = 0;
virtual void start_cont_ho() = 0;
virtual void reconfiguration(const uint32_t& cc_idx, const bool& enable) = 0;
virtual void reset() = 0;
virtual void wait_uplink() = 0;
};
/** PHY interface
@ -563,9 +574,6 @@ public:
uint32_t preamble_format;
} prach_info_t;
/* Configure PRACH using parameters written by RRC */
virtual void configure_prach_params() = 0;
virtual void
prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec = 0.0f) = 0;
virtual prach_info_t prach_get_info() = 0;
@ -580,10 +588,8 @@ public:
class phy_interface_rrc_lte
{
public:
virtual void set_config(srslte::phy_cfg_t& config,
uint32_t cc_idx = 0,
uint32_t earfcn = 0,
srslte_cell_t* cell_info = nullptr) = 0;
virtual bool set_config(srslte::phy_cfg_t config, uint32_t cc_idx = 0) = 0;
virtual bool set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) = 0;
virtual void set_config_tdd(srslte_tdd_config_t& tdd_config) = 0;
virtual void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) = 0;
virtual void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) = 0;
@ -595,23 +601,10 @@ public:
virtual void set_cells_to_meas(uint32_t earfcn, const std::set<uint32_t>& pci) = 0;
virtual void meas_stop() = 0;
typedef struct {
enum { CELL_FOUND = 0, CELL_NOT_FOUND, ERROR } found;
enum { MORE_FREQS = 0, NO_MORE_FREQS } last_freq;
} cell_search_ret_t;
typedef struct {
uint32_t pci;
uint32_t earfcn;
float cfo_hz;
} phy_cell_t;
/* Cell search and selection procedures */
virtual cell_search_ret_t cell_search(phy_cell_t* cell) = 0;
virtual bool cell_select(const phy_cell_t* cell = nullptr) = 0;
virtual bool cell_is_camping() = 0;
virtual void reset() = 0;
virtual bool cell_search() = 0;
virtual bool cell_select(phy_cell_t cell) = 0;
virtual bool cell_is_camping() = 0;
virtual void enable_pregen_signals(bool enable) = 0;
};

@ -67,27 +67,24 @@ public:
class phy_dummy_interface : public phy_interface_rrc_lte
{
void
set_config(srslte::phy_cfg_t& config, uint32_t cc_idx = 0, uint32_t earfcn = 0, srslte_cell_t* cell_info = nullptr)
{}
void set_config_tdd(srslte_tdd_config_t& tdd_config) {}
void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) {}
void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) {}
void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) {}
void set_activation_deactivation_scell(uint32_t cmd) {}
bool set_config(srslte::phy_cfg_t config, uint32_t cc_idx = 0) override { return true; }
bool set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) override { return true; }
void set_config_tdd(srslte_tdd_config_t& tdd_config) override {}
void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) override {}
void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) override {}
void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) override {}
void set_activation_deactivation_scell(uint32_t cmd) override {}
/* Measurements interface */
void set_cells_to_meas(uint32_t earfcn, const std::set<uint32_t>& pci) {}
void meas_stop() {}
void set_cells_to_meas(uint32_t earfcn, const std::set<uint32_t>& pci) override {}
void meas_stop() override {}
/* Cell search and selection procedures */
cell_search_ret_t cell_search(phy_cell_t* cell) { return {}; }
bool cell_select(const phy_cell_t* cell = nullptr) { return true; }
bool cell_is_camping() { return false; }
bool cell_search() override { return true; }
bool cell_select(phy_cell_t cell) override { return true; }
bool cell_is_camping() override { return false; }
void reset() {}
void enable_pregen_signals(bool enable) {}
void enable_pregen_signals(bool enable) override {}
};
} // namespace srsue

@ -33,9 +33,6 @@ class cc_worker
public:
cc_worker(uint32_t cc_idx, uint32_t max_prb, phy_common* phy, srslte::log* log);
~cc_worker();
void reset();
bool set_cell(srslte_cell_t cell);
/* Functions used by main PHY thread */
cf_t* get_rx_buffer(uint32_t antenna_idx);
@ -43,13 +40,18 @@ public:
uint32_t get_buffer_len();
void set_tti(uint32_t tti);
void set_cfo(float cfo);
void set_tdd_config(srslte_tdd_config_t config);
void set_config(srslte::phy_cfg_t& phy_cfg);
void upd_config_dci(srslte_dci_cfg_t& dci_cfg);
void set_crnti(uint16_t rnti);
void enable_pregen_signals(bool enabled);
void set_cfo_unlocked(float cfo);
float get_ref_cfo() const;
// Functions to set configuration.
// Warning: all these functions are unlocked and must be called while the worker is not processing data
void reset_cell_unlocked();
bool set_cell_unlocked(srslte_cell_t cell_);
void set_tdd_config_unlocked(srslte_tdd_config_t config);
void set_config_unlocked(srslte::phy_cfg_t& phy_cfg);
void upd_config_dci_unlocked(srslte_dci_cfg_t& dci_cfg);
void set_crnti_unlocked(uint16_t rnti);
void enable_pregen_signals_unlocked(bool enabled);
void set_uci_periodic_cqi(srslte_uci_data_t* uci_data);
@ -64,6 +66,8 @@ public:
cf_t* rssi_power_buffer = nullptr);
private:
void reset();
void dl_phy_to_mac_grant(srslte_pdsch_grant_t* phy_grant,
srslte_dci_dl_t* dl_dci,
mac_interface_phy_lte::mac_grant_dl_t* mac_grant);
@ -116,9 +120,6 @@ private:
/* Objects for UL */
srslte_ue_ul_t ue_ul = {};
srslte_ue_ul_cfg_t ue_ul_cfg = {};
// Mutex, for protecting what matters most: ue_ul, ue_ul_cfg, ue_dl, ue_dl_cfg, cell, pmch_cfg
std::mutex mutex;
};
} // namespace srsue

@ -27,7 +27,9 @@
#include "prach.h"
#include "sf_worker.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/threads.h"
#include "srslte/common/trace.h"
#include "srslte/interfaces/phy_interface_types.h"
#include "srslte/interfaces/radio_interfaces.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio.h"
@ -39,6 +41,37 @@ namespace srsue {
typedef _Complex float cf_t;
class phy_cmd_proc : public srslte::thread
{
public:
phy_cmd_proc() : thread("PHY_CMD") { start(); }
~phy_cmd_proc() { stop(); }
void add_cmd(std::function<void(void)> cmd) { cmd_queue.push(cmd); }
void stop()
{
if (running) {
add_cmd([this]() { running = false; });
wait_thread_finish();
}
}
private:
void run_thread()
{
std::function<void(void)> cmd;
while (running) {
cmd = cmd_queue.wait_pop();
cmd();
}
}
bool running = true;
// Queue for commands
srslte::block_queue<std::function<void(void)> > cmd_queue;
};
class phy final : public ue_lte_phy_base, public srslte::thread
{
public:
@ -65,23 +98,40 @@ public:
void radio_failure() final;
/********** RRC INTERFACE ********************/
void reset() final;
cell_search_ret_t cell_search(phy_cell_t* cell) final;
bool cell_select(const phy_cell_t* cell) final;
bool cell_search() final;
bool cell_select(phy_cell_t cell) final;
// Sets the new PHY configuration for the given CC. The configuration is applied in the background. The notify()
// function will be called when the reconfiguration is completed. Unless the PRACH configuration has changed, the
// reconfiguration will not take more than 3 ms
bool set_config(srslte::phy_cfg_t config, uint32_t cc_idx) final;
// Adds or modifies the cell configuration for a given CC. If the EARFCN has changed w.r.t. the previous value, or if
// the cell is new, this function might take a few hundred ms to complete, depending on the radio
bool set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) final;
// Applies a TDD configuration in the background. This function will take less than 3 ms to execute.
void set_config_tdd(srslte_tdd_config_t& tdd_config) final;
// Todo
void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) final;
void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) final;
void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) final;
// This function applies the new configuration immediately
void set_cells_to_meas(uint32_t earfcn, const std::set<uint32_t>& pci) final;
// This function applies the new configuration immediately
void meas_stop() final;
// also MAC interface
bool cell_is_camping() final;
/********** MAC INTERFACE ********************/
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
// Precomputes sequences for the given RNTI. The computation is done in the background.
void set_crnti(uint16_t rnti) final;
/* Instructs the PHY to configure using the parameters written by set_param() */
void configure_prach_params() final;
/* Transmits PRACH in the next opportunity */
void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec) final;
prach_info_t prach_get_info() final;
@ -100,14 +150,6 @@ public:
/* Sets RAR dci payload */
void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti) final;
/* Get/Set PHY parameters interface from RRC */
void set_config(srslte::phy_cfg_t& config, uint32_t cc_idx, uint32_t earfcn, srslte_cell_t* cell_info) final;
void set_config_tdd(srslte_tdd_config_t& tdd_config) final;
void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) final;
void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) final;
void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) final;
/*Set MAC->PHY MCH period stopping point*/
void set_mch_period_stop(uint32_t stop) final;
@ -125,6 +167,8 @@ public:
private:
void run_thread() final;
void configure_prach_params();
void reset();
std::mutex config_mutex;
std::condition_variable config_cond;
@ -154,8 +198,15 @@ private:
srslte::phy_cfg_t config = {};
phy_args_t args = {};
// Since cell_search/cell_select operations take a lot of time, we use another queue to process the other commands
// in parallel and avoid accumulating in the queue
phy_cmd_proc cmd_worker_cell, cmd_worker;
// Tracks the current selected cell (last call to cell_select)
srslte_cell_t selected_cell = {};
static void set_default_args(phy_args_t& args);
bool check_args(const phy_args_t& args);
bool check_args(const phy_args_t& args);
};
} // namespace srsue

@ -39,8 +39,9 @@ public:
void init(uint32_t max_prb, srslte::log* log_h);
void stop();
bool set_cell(srslte_cell_t cell, srslte_prach_cfg_t prach_cfg);
void reset_cfg();
bool prepare_to_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = -1);
bool is_ready_to_send(uint32_t current_tti);
bool is_ready_to_send(uint32_t current_tti, uint32_t current_pci);
bool is_pending() const;
cf_t* generate(float cfo, uint32_t* nof_sf, float* target_power = NULL);
@ -71,7 +72,7 @@ private:
srslte_prach_cfg_t cfg = {};
std::array<std::array<cf_t*, max_preambles>, max_fs> buffer = {};
cf_t* signal_buffer = nullptr;
int preamble_idx = 0;
int preamble_idx = -1;
uint32_t len = 0;
int allowed_subframe = 0;
int transmitted_tti = 0;

@ -43,9 +43,9 @@ class sf_worker : public srslte::thread_pool::worker
public:
sf_worker(uint32_t max_prb, phy_common* phy, srslte::log* log, srslte::log* log_phy_lib_h);
virtual ~sf_worker();
void reset();
bool set_cell(uint32_t cc_idx, srslte_cell_t cell);
void reset_cell_unlocked(uint32_t cc_idx);
bool set_cell_unlocked(uint32_t cc_idx, srslte_cell_t cell_);
/* Functions used by main PHY thread */
cf_t* get_buffer(uint32_t cc_idx, uint32_t antenna_idx);
@ -53,12 +53,12 @@ public:
void set_tti(uint32_t tti);
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);
void set_cfo_unlocked(const uint32_t& cc_idx, float cfo);
void set_tdd_config(srslte_tdd_config_t config);
void set_config(uint32_t cc_idx, srslte::phy_cfg_t& phy_cfg);
void set_crnti(uint16_t rnti);
void enable_pregen_signals(bool enabled);
void set_tdd_config_unlocked(srslte_tdd_config_t config);
void set_config_unlocked(uint32_t cc_idx, srslte::phy_cfg_t phy_cfg);
void set_crnti_unlocked(uint16_t rnti);
void enable_pregen_signals_unlocked(bool enabled);
///< Methods for plotting called from GUI thread
int read_ce_abs(float* ce_abs, uint32_t tx_antenna, uint32_t rx_antenna);

@ -67,8 +67,10 @@ public:
void radio_overflow();
// RRC interface for controling the SYNC state
phy_interface_rrc_lte::cell_search_ret_t cell_search(phy_interface_rrc_lte::phy_cell_t* cell);
bool cell_select(const phy_interface_rrc_lte::phy_cell_t* cell);
bool cell_search_init();
rrc_interface_phy_lte::cell_search_ret_t cell_search_start(phy_cell_t* cell);
bool cell_select_init(phy_cell_t cell);
bool cell_select_start(phy_cell_t cell);
bool cell_is_camping();
// RRC interface for controlling the neighbour cell measurement
@ -227,6 +229,13 @@ private:
uint32_t in_sync_cnt = 0;
std::mutex rrc_mutex;
enum {
PROC_IDLE = 0,
PROC_SELECT_START,
PROC_SELECT_RUNNING,
PROC_SEARCH_START,
PROC_SEARCH_RUNNING
} rrc_proc_state = PROC_IDLE;
sync_state phy_state;

@ -75,7 +75,8 @@ public:
void go_idle()
{
std::lock_guard<std::mutex> lock(outside);
go_state(IDLE);
// Do not wait when transitioning to IDLE to avoid blocking
go_state_nowait(IDLE);
}
void run_cell_search()
{
@ -125,6 +126,13 @@ private:
}
}
void go_state_nowait(state_t s)
{
std::unique_lock<std::mutex> ul(inside);
next_state = s;
state_setting = true;
}
/* Waits until there is a call to set_state() and then run_state(). Returns when run_state() returns */
void wait_state_run()
{

@ -81,7 +81,6 @@ public:
void mch_start_rx(uint32_t lcid);
void reconfiguration(const uint32_t& cc_idx, const bool& enable);
void reset();
void wait_uplink();
/******** set/get MAC configuration ****************/
void set_config(mac_cfg_t& mac_cfg);
@ -91,8 +90,7 @@ public:
void reset_harq(uint32_t cc_idx);
bool contention_resolution_id_rcv(uint64_t id);
void start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask);
void start_cont_ho();
void set_rach_ded_cfg(uint32_t preamble_index, uint32_t prach_mask);
void get_rntis(ue_rnti_t* rntis);
void set_ho_rnti(uint16_t crnti, uint16_t target_pci);

@ -77,9 +77,10 @@ public:
void reset();
void set_config(srslte::rach_cfg_t& rach_cfg);
void set_config_ded(uint32_t preamble_index, uint32_t prach_mask);
void start_pdcch_order();
void start_mac_order(uint32_t msg_len_bits = 56, bool is_ho = false);
void start_mac_order(uint32_t msg_len_bits = 56);
void step(uint32_t tti);
void update_rar_window(int& rar_window_start, int& rar_window_length);
@ -91,11 +92,9 @@ public:
void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action);
void tb_decoded_ok(const uint8_t cc_idx, const uint32_t tti);
void start_noncont(uint32_t preamble_index, uint32_t prach_mask);
bool contention_resolution_id_received(uint64_t uecri);
void start_pcap(srslte::mac_pcap* pcap);
void notify_phy_config_completed(uint32_t task_id);
void notify_ra_completed(uint32_t task_id);
bool is_idle() const { return state == IDLE; }
@ -149,7 +148,6 @@ private:
enum {
IDLE = 0,
WAITING_PHY_CONFIG,
PDCCH_SETUP,
RESPONSE_RECEPTION,
BACKOFF_WAIT,
@ -183,7 +181,6 @@ private:
std::mutex mutex;
bool ra_is_ho;
bool started_by_pdcch;
uint32_t rar_grant_nbytes;
bool rar_received;

@ -31,8 +31,7 @@ namespace srsue {
class phy_controller : public srslte::fsm_t<phy_controller>
{
using phy_cell_t = phy_interface_rrc_lte::phy_cell_t;
using cell_search_ret_t = phy_interface_rrc_lte::cell_search_ret_t;
using cell_search_ret_t = rrc_interface_phy_lte::cell_search_ret_t;
public:
static const uint32_t wait_sync_timeout_ms = 50;

@ -123,9 +123,13 @@ public:
void in_sync() final;
void out_of_sync() final;
void new_cell_meas(const std::vector<phy_meas_t>& meas);
void cell_search_complete(cell_search_ret_t ret, phy_cell_t found_cell);
void cell_select_complete(bool status);
void set_config_complete(bool status);
void set_scell_complete(bool status);
// MAC interface
void ho_ra_completed() final;
void ra_completed() final;
void release_pucch_srs();
void run_tti();
void ra_problem();
@ -141,22 +145,18 @@ public:
void write_pdu_pcch(srslte::unique_byte_buffer_t pdu);
void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu);
// STACK interface
void cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& cs_ret,
const phy_interface_rrc_lte::phy_cell_t& found_cell);
void cell_select_completed(bool cs_ret);
bool srbs_flushed(); //< Check if data on SRBs still needs to be sent
protected:
// Moved to protected to be accessible by unit tests
void set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving);
void set_serving_cell(phy_cell_t phy_cell, bool discard_serving);
bool has_neighbour_cell(uint32_t earfcn, uint32_t pci) const;
bool is_serving_cell(uint32_t earfcn, uint32_t pci) const;
int start_cell_select();
private:
typedef struct {
enum { PCCH, RLF, HO_COMPLETE, STOP } command;
enum { PCCH, RLF, RA_COMPLETE, STOP } command;
srslte::unique_byte_buffer_t pdu;
uint16_t lcid;
} cmd_msg_t;
@ -301,7 +301,7 @@ private:
class cell_reselection_proc;
class connection_reest_proc;
class ho_proc;
srslte::proc_t<cell_search_proc, phy_interface_rrc_lte::cell_search_ret_t> cell_searcher;
srslte::proc_t<cell_search_proc, rrc_interface_phy_lte::cell_search_ret_t> cell_searcher;
srslte::proc_t<si_acquire_proc> si_acquirer;
srslte::proc_t<serving_cell_config_proc> serv_cell_cfg;
srslte::proc_t<cell_selection_proc, cs_result_t> cell_selector;

@ -32,7 +32,7 @@ class cell_t
{
public:
cell_t() { gettimeofday(&last_update, nullptr); }
explicit cell_t(phy_interface_rrc_lte::phy_cell_t phy_cell_) : cell_t() { phy_cell = phy_cell_; }
explicit cell_t(phy_cell_t phy_cell_) : cell_t() { phy_cell = phy_cell_; }
// comparison based on pci and earfcn
bool is_valid() { return phy_cell.earfcn != 0 && srslte_cellid_isvalid(phy_cell.pci); }
@ -110,7 +110,7 @@ public:
bool is_sib_scheduled(uint32_t sib_index) const;
phy_interface_rrc_lte::phy_cell_t phy_cell = {0, 0, 0};
phy_cell_t phy_cell = {0, 0, 0};
bool has_mcch = false;
asn1::rrc::sib_type1_s sib1 = {};
asn1::rrc::sib_type2_s sib2 = {};
@ -192,7 +192,7 @@ public:
cell_t* find_cell(uint32_t earfcn, uint32_t pci);
// serving cell handling
int set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving);
int set_serving_cell(phy_cell_t phy_cell, bool discard_serving);
cell_t& serving_cell() { return *serv_cell; }
const cell_t& serving_cell() const { return *serv_cell; }

@ -35,7 +35,7 @@ namespace srsue {
using namespace asn1::rrc;
typedef std::vector<phy_interface_rrc_lte::phy_cell_t> cell_triggered_t;
typedef std::vector<phy_cell_t> cell_triggered_t;
// RRC Measurements class
class rrc::rrc_meas

@ -95,8 +95,7 @@ public:
void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) final;
// STACK interface
void cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& cs_ret,
const phy_interface_rrc_lte::phy_cell_t& found_cell);
void cell_search_completed(const rrc_interface_phy_lte::cell_search_ret_t& cs_ret, const phy_cell_t& found_cell);
private:
struct cmd_msg_t {

@ -47,11 +47,11 @@ public:
srslte::proc_outcome_t react(const bool& event);
srslte::proc_outcome_t step_wait_measurement();
phy_interface_rrc_lte::cell_search_ret_t get_result() const { return search_result.cs_ret; }
rrc_interface_phy_lte::cell_search_ret_t get_result() const { return search_result.cs_ret; }
static const char* name() { return "Cell Search"; }
private:
srslte::proc_outcome_t handle_cell_found(const phy_interface_rrc_lte::phy_cell_t& new_cell);
srslte::proc_outcome_t handle_cell_found(const phy_cell_t& new_cell);
// conts
rrc* rrc_ptr;
@ -147,7 +147,7 @@ private:
search_state_t state;
uint32_t neigh_index;
bool serv_cell_select_attempted = false;
srslte::proc_future_t<phy_interface_rrc_lte::cell_search_ret_t> cell_search_fut;
srslte::proc_future_t<rrc_interface_phy_lte::cell_search_ret_t> cell_search_fut;
srslte::proc_future_t<void> serv_cell_cfg_fut;
bool discard_serving = false;
};
@ -169,7 +169,7 @@ private:
// state variables
found_plmn_t found_plmns[MAX_FOUND_PLMNS];
int nof_plmns = 0;
srslte::proc_future_t<phy_interface_rrc_lte::cell_search_ret_t> cell_search_fut;
srslte::proc_future_t<rrc_interface_phy_lte::cell_search_ret_t> cell_search_fut;
};
class rrc::connection_request_proc
@ -306,12 +306,12 @@ private:
asn1::rrc::rrc_conn_recfg_r8_ies_s recfg_r8;
// state
phy_interface_rrc_lte::phy_cell_t target_cell;
phy_cell_t target_cell;
// helper to revert security config of source cell
void reset_security_config();
enum state_t { launch_phy_cell_select, wait_phy_cell_select_complete, wait_ra_completion } state;
enum state_t { wait_phy_cell_select_complete, wait_ra_completion } state;
};
} // namespace srsue

@ -79,6 +79,10 @@ public:
void in_sync() final;
void out_of_sync() final;
void new_cell_meas(const std::vector<phy_meas_t>& meas) override { rrc.new_cell_meas(meas); }
void cell_search_complete(cell_search_ret_t ret, phy_cell_t found_cell) final;
void cell_select_complete(bool status) final;
void set_config_complete(bool status) final;
void set_scell_complete(bool status) final;
// MAC Interface for PHY
uint16_t get_dl_sched_rnti(uint32_t tti) final { return mac.get_dl_sched_rnti(tti); }
@ -158,7 +162,7 @@ private:
static const int STACK_MAIN_THREAD_PRIO = 4; // Next lower priority after PHY workers
srslte::block_queue<stack_metrics_t> pending_stack_metrics;
task_scheduler task_sched;
srslte::task_multiqueue::queue_handle sync_task_queue, ue_task_queue, gw_queue_id;
srslte::task_multiqueue::queue_handle sync_task_queue, ue_task_queue, gw_queue_id, cfg_task_queue;
// TTI stats
srslte::tprof<srslte::sliding_window_stats_ms> tti_tprof;

@ -119,13 +119,16 @@ void cc_worker::reset()
{
// constructor sets defaults
srslte::phy_cfg_t empty_cfg;
set_config(empty_cfg);
set_config_unlocked(empty_cfg);
}
bool cc_worker::set_cell(srslte_cell_t cell_)
void cc_worker::reset_cell_unlocked()
{
std::unique_lock<std::mutex> lock(mutex);
cell_initiated = false;
}
bool cc_worker::set_cell_unlocked(srslte_cell_t cell_)
{
if (cell.id != cell_.id || !cell_initiated) {
cell = cell_;
@ -175,27 +178,29 @@ void cc_worker::set_tti(uint32_t tti)
sf_cfg_ul.shortened = false;
}
void cc_worker::set_cfo(float cfo)
void cc_worker::set_cfo_unlocked(float cfo)
{
std::unique_lock<std::mutex> lock(mutex);
ue_ul_cfg.cfo_value = cfo;
}
void cc_worker::set_crnti(uint16_t rnti)
float cc_worker::get_ref_cfo() const
{
return ue_dl.chest_res.cfo;
}
void cc_worker::set_crnti_unlocked(uint16_t rnti)
{
std::unique_lock<std::mutex> lock(mutex);
srslte_ue_dl_set_rnti(&ue_dl, rnti);
srslte_ue_ul_set_rnti(&ue_ul, rnti);
}
void cc_worker::set_tdd_config(srslte_tdd_config_t config)
void cc_worker::set_tdd_config_unlocked(srslte_tdd_config_t config)
{
std::unique_lock<std::mutex> lock(mutex);
sf_cfg_dl.tdd_config = config;
sf_cfg_ul.tdd_config = config;
}
void cc_worker::enable_pregen_signals(bool enabled)
void cc_worker::enable_pregen_signals_unlocked(bool enabled)
{
pregen_enabled = enabled;
}
@ -208,13 +213,17 @@ void cc_worker::enable_pregen_signals(bool enabled)
bool cc_worker::work_dl_regular()
{
std::unique_lock<std::mutex> lock(mutex);
bool dl_ack[SRSLTE_MAX_CODEWORDS] = {};
mac_interface_phy_lte::tb_action_dl_t dl_action = {};
bool found_dl_grant = false;
if (!cell_initiated) {
log_h->warning("Trying to access cc_worker=%d while cell not initialized (DL)\n", cc_idx);
return false;
}
sf_cfg_dl.sf_type = SRSLTE_SF_NORM;
// Set default channel estimation
@ -266,7 +275,7 @@ bool cc_worker::work_dl_regular()
// Generate PHY grant
if (srslte_ue_dl_dci_to_pdsch_grant(&ue_dl, &sf_cfg_dl, &ue_dl_cfg, &dci_dl, &ue_dl_cfg.cfg.pdsch.grant)) {
Error("Converting DCI message to DL dci\n");
return -1;
return false;
}
// Save TB for next retx
@ -285,17 +294,13 @@ bool cc_worker::work_dl_regular()
srslte_pdsch_ack_resource_t ack_resource = {dci_dl.dai, dci_dl.location.ncce, grant_cc_idx, dci_dl.tpc_pucch};
// Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC
mutex.unlock();
phy->stack->new_grant_dl(cc_idx, mac_grant, &dl_action);
mutex.lock();
// Decode PDSCH
decode_pdsch(ack_resource, &dl_action, dl_ack);
// Informs Stack about the decoding status
mutex.unlock();
phy->stack->tb_decoded(cc_idx, mac_grant, dl_ack);
mutex.lock();
}
/* Decode PHICH */
@ -306,9 +311,13 @@ bool cc_worker::work_dl_regular()
bool cc_worker::work_dl_mbsfn(srslte_mbsfn_cfg_t mbsfn_cfg)
{
std::unique_lock<std::mutex> lock(mutex);
mac_interface_phy_lte::tb_action_dl_t dl_action = {};
if (!cell_initiated) {
log_h->warning("Trying to access cc_worker=%d while cell not initialized (MBSFN)\n", cc_idx);
return false;
}
// Configure MBSFN settings
srslte_ue_dl_set_mbsfn_area_id(&ue_dl, mbsfn_cfg.mbsfn_area_id);
srslte_ue_dl_set_non_mbsfn_region(&ue_dl, mbsfn_cfg.non_mbsfn_region_length);
@ -569,7 +578,6 @@ void cc_worker::update_measurements(std::vector<rrc_interface_phy_lte::phy_meas_
bool cc_worker::work_ul(srslte_uci_data_t* uci_data)
{
std::unique_lock<std::mutex> lock(mutex);
bool signal_ready;
srslte_dci_ul_t dci_ul = {};
@ -577,6 +585,11 @@ bool cc_worker::work_ul(srslte_uci_data_t* uci_data)
mac_interface_phy_lte::tb_action_ul_t ul_action = {};
uint32_t pid = 0;
if (!cell_initiated) {
log_h->warning("Trying to access cc_worker=%d while cell not initialized (UL)\n", cc_idx);
return false;
}
bool ul_grant_available = phy->get_ul_pending_grant(&sf_cfg_ul, cc_idx, &pid, &dci_ul);
ul_mac_grant.phich_available =
phy->get_ul_received_ack(&sf_cfg_ul, cc_idx, &ul_mac_grant.hi_value, ul_grant_available ? nullptr : &dci_ul);
@ -618,9 +631,7 @@ bool cc_worker::work_ul(srslte_uci_data_t* uci_data)
// Fill MAC dci
ul_phy_to_mac_grant(&ue_ul_cfg.ul_cfg.pusch.grant, &dci_ul, pid, ul_grant_available, &ul_mac_grant);
mutex.unlock();
phy->stack->new_grant_ul(cc_idx, ul_mac_grant, &ul_action);
mutex.lock();
// Calculate PUSCH Hopping procedure
ue_ul_cfg.ul_cfg.hopping.current_tx_nb = ul_action.current_tx_nb;
@ -810,7 +821,6 @@ uint32_t cc_worker::get_wideband_cqi()
void cc_worker::set_uci_periodic_cqi(srslte_uci_data_t* uci_data)
{
std::unique_lock<std::mutex> lock(mutex);
srslte_ue_dl_gen_cqi_periodic(&ue_dl, &ue_dl_cfg, get_wideband_cqi(), CURRENT_TTI_TX, uci_data);
}
@ -862,10 +872,8 @@ void cc_worker::set_uci_ack(srslte_uci_data_t* uci_data,
/* Translates RRC structs into PHY structs
*/
void cc_worker::set_config(srslte::phy_cfg_t& phy_cfg)
void cc_worker::set_config_unlocked(srslte::phy_cfg_t& phy_cfg)
{
std::unique_lock<std::mutex> lock(mutex);
// Save configuration
ue_dl_cfg.cfg = phy_cfg.dl_cfg;
ue_ul_cfg.ul_cfg = phy_cfg.ul_cfg;
@ -880,9 +888,8 @@ void cc_worker::set_config(srslte::phy_cfg_t& phy_cfg)
}
}
void cc_worker::upd_config_dci(srslte_dci_cfg_t& dci_cfg)
void cc_worker::upd_config_dci_unlocked(srslte_dci_cfg_t& dci_cfg)
{
std::unique_lock<std::mutex> lock(mutex);
ue_dl_cfg.cfg.dci = dci_cfg;
}

@ -225,6 +225,8 @@ bool phy::is_initiated()
void phy::stop()
{
std::unique_lock<std::mutex> lock(config_mutex);
cmd_worker.stop();
cmd_worker_cell.stop();
if (is_configured) {
sfsync.stop();
workers_pool.stop();
@ -284,12 +286,10 @@ void phy::set_activation_deactivation_scell(uint32_t cmd)
void phy::configure_prach_params()
{
Debug("Configuring PRACH parameters\n");
srslte_cell_t cell;
sfsync.get_current_cell(&cell);
prach_cfg.tdd_config = tdd_config;
if (!prach_buffer.set_cell(cell, prach_cfg)) {
if (!prach_buffer.set_cell(selected_cell, prach_cfg)) {
Error("Configuring PRACH parameters\n");
}
}
@ -304,16 +304,49 @@ void phy::meas_stop()
sfsync.meas_stop();
}
bool phy::cell_select(const phy_cell_t* cell)
// This function executes one part of the procedure immediatly and returns to continue in the background.
// When it returns, the caller thread can expect the PHY to have switched to IDLE and have stopped all DL/UL/PRACH
// processing.
bool phy::cell_select(phy_cell_t cell)
{
sfsync.scell_sync_stop();
return sfsync.cell_select(cell);
if (sfsync.cell_select_init(cell)) {
reset();
// Update PCI before starting the background command to make sure PRACH gets the updated value
selected_cell.id = cell.pci;
cmd_worker_cell.add_cmd([this, cell]() {
bool ret = sfsync.cell_select_start(cell);
if (ret) {
srslte_cell_t sync_cell;
sfsync.get_current_cell(&sync_cell);
selected_cell = sync_cell;
}
stack->cell_select_complete(ret);
});
return true;
} else {
log_h->warning("Could not start Cell Selection procedure\n");
return false;
}
}
phy_interface_rrc_lte::cell_search_ret_t phy::cell_search(phy_cell_t* cell)
// This function executes one part of the procedure immediatly and returns to continue in the background.
// When it returns, the caller thread can expect the PHY to have switched to IDLE and have stopped all DL/UL/PRACH
// processing.
bool phy::cell_search()
{
sfsync.scell_sync_stop();
return sfsync.cell_search(cell);
if (sfsync.cell_search_init()) {
reset();
cmd_worker_cell.add_cmd([this]() {
phy_cell_t found_cell = {};
rrc_interface_phy_lte::cell_search_ret_t ret = sfsync.cell_search_start(&found_cell);
stack->cell_search_complete(ret, found_cell);
});
} else {
log_h->warning("Could not start Cell Search procedure\n");
}
return true;
}
bool phy::cell_is_camping()
@ -360,11 +393,8 @@ void phy::radio_failure()
void phy::reset()
{
Info("Resetting PHY\n");
Info("Resetting PHY...\n");
common.ta.set_base_sec(0);
for (uint32_t i = 0; i < nof_workers; i++) {
workers[i]->reset();
}
common.reset();
}
@ -392,14 +422,19 @@ void phy::set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rn
void phy::set_crnti(uint16_t rnti)
{
// set_crnti() is an operation that takes time, apply asynrhonously with processing
for (uint32_t i = 0; i < nof_workers; i++) {
sf_worker* w = (sf_worker*)workers_pool.wait_worker_id(i);
if (w) {
w->set_crnti(rnti);
w->release();
// set_crnti() is an operation that takes time, run in background worker
cmd_worker.add_cmd([this, rnti]() {
log_h->info("Configuring sequences for C-RNTI=0x%x...\n", rnti);
for (uint32_t i = 0; i < nof_workers; i++) {
// set_crnti is not protected so run when worker is finished
sf_worker* w = (sf_worker*)workers_pool.wait_worker_id(i);
if (w) {
w->set_crnti_unlocked(rnti);
w->release();
}
}
}
log_h->info("Finished configuring sequences for C-RNTI=0x%x.\n", rnti);
});
}
// Start GUI
@ -411,69 +446,124 @@ void phy::start_plot()
void phy::enable_pregen_signals(bool enable)
{
for (uint32_t i = 0; i < nof_workers; i++) {
workers[i]->enable_pregen_signals(enable);
workers[i]->enable_pregen_signals_unlocked(enable);
}
}
void phy::set_config(srslte::phy_cfg_t& config_, uint32_t cc_idx, uint32_t earfcn, srslte_cell_t* cell_info)
bool phy::set_config(srslte::phy_cfg_t config_, uint32_t cc_idx)
{
if (!is_initiated()) {
fprintf(stderr, "Error calling set_config(): PHY not initialized\n");
return;
return false;
}
// Disable cell_info if configuration has not been set
if (cell_info) {
if (!srslte_cell_isvalid(cell_info)) {
cell_info = nullptr;
}
// Check parameters are valid
if (cc_idx >= args.nof_carriers) {
log_h->console("Received SCell configuration for index %d but there are not enough CC workers available\n", cc_idx);
return false;
}
// Component carrier index zero should be reserved for PCell
if (cc_idx < args.nof_carriers) {
// Send configuration to workers
Info("Setting configuration\n");
bool reconfigure_prach = !cc_idx && (prach_cfg != config_.prach_cfg);
if (reconfigure_prach) {
prach_buffer.reset_cfg();
}
// Apply configuration after the worker is finished to avoid race conditions
cmd_worker.add_cmd([this, config_, cc_idx, reconfigure_prach]() {
log_h->info("Setting new PHY configuration...\n");
for (uint32_t i = 0; i < nof_workers; i++) {
if (cell_info) {
// set_cell() is an operation that takes time, apply asynrhonously with processing
sf_worker* w = (sf_worker*)workers_pool.wait_worker_id(i);
if (w) {
w->set_cell(cc_idx, *cell_info);
w->release();
}
// set_cell is not protected so run when worker is finished
sf_worker* w = (sf_worker*)workers_pool.wait_worker_id(i);
if (w) {
w->set_config_unlocked(cc_idx, config_);
w->release();
}
// set_config() is just a memcpy
workers[i]->set_config(cc_idx, config_);
}
log_h->info("Finished setting new PHY configuration.\n");
if (reconfigure_prach) {
// Reconfigure PRACH parameters only if configuration is different
prach_cfg = config_.prach_cfg;
log_h->info("Setting new PRACH configuration...\n");
configure_prach_params();
log_h->info("Finished setting new PRACH configuration.\n");
}
stack->set_config_complete(true);
});
return true;
}
bool phy::set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn)
{
if (!is_initiated()) {
fprintf(stderr, "Error calling set_config(): PHY not initialized\n");
return false;
}
if (cell_info) {
// Set inter-frequency measurement
sfsync.set_inter_frequency_measurement(cc_idx, earfcn, *cell_info);
if (cc_idx == 0) {
log_h->error("Received SCell configuration for invalid cc_idx=0\n");
return false;
}
// Set secondary serving cell synchronization
sfsync.scell_sync_set(cc_idx, *cell_info);
}
// Check parameters are valid
if (cc_idx >= args.nof_carriers) {
log_h->console("Received SCell configuration for index %d but there are not enough CC workers available\n", cc_idx);
return false;
}
if (cc_idx == 0) {
prach_cfg = config_.prach_cfg;
} else if (cell_info != nullptr) {
// Change frequency only if the earfcn was modified
if (common.scell_cfg[cc_idx].earfcn != earfcn) {
double dl_freq = srslte_band_fd(earfcn) * 1e6;
double ul_freq = srslte_band_fu(common.get_ul_earfcn(earfcn)) * 1e6;
radio->set_rx_freq(cc_idx, dl_freq);
radio->set_tx_freq(cc_idx, ul_freq);
// First of all check validity of parameters
if (!srslte_cell_isvalid(&cell_info)) {
log_h->error("Received SCell configuration for an invalid cell\n");
return false;
}
bool earfcn_is_different = common.scell_cfg[cc_idx].earfcn != earfcn;
// Set inter-frequency measurement
sfsync.set_inter_frequency_measurement(cc_idx, earfcn, cell_info);
// Store SCell earfcn and pci
common.scell_cfg[cc_idx].earfcn = earfcn;
common.scell_cfg[cc_idx].pci = cell_info.id;
common.scell_cfg[cc_idx].configured = true;
common.scell_cfg[cc_idx].enabled = false;
// Reset cell configuration
for (uint32_t i = 0; i < nof_workers; i++) {
workers[i]->reset_cell_unlocked(cc_idx);
}
// Component carrier index zero should be reserved for PCell
// Send configuration to workers
cmd_worker.add_cmd([this, cell_info, cc_idx, earfcn, earfcn_is_different]() {
log_h->info("Setting new SCell configuration cc_idx=%d, earfcn=%d...\n", cc_idx, earfcn);
for (uint32_t i = 0; i < nof_workers; i++) {
// set_cell is not protected so run when worker is finished
sf_worker* w = (sf_worker*)workers_pool.wait_worker_id(i);
if (w) {
w->set_cell_unlocked(cc_idx, cell_info);
w->release();
}
}
// Store SCell earfcn and pci
common.scell_cfg[cc_idx].earfcn = earfcn;
common.scell_cfg[cc_idx].pci = cell_info->id;
common.scell_cfg[cc_idx].configured = true;
common.scell_cfg[cc_idx].enabled = false;
// Change frequency only if the earfcn was modified
if (earfcn_is_different) {
double dl_freq = srslte_band_fd(earfcn) * 1e6;
double ul_freq = srslte_band_fu(common.get_ul_earfcn(earfcn)) * 1e6;
radio->set_rx_freq(cc_idx, dl_freq);
radio->set_tx_freq(cc_idx, ul_freq);
}
} else {
log_h->console("Received SCell configuration for index %d but there are not enough CC workers available\n", cc_idx);
}
// Set secondary serving cell synchronization
sfsync.scell_sync_set(cc_idx, cell_info);
log_h->info("Finished setting new SCell configuration cc_idx=%d, earfcn=%d\n", cc_idx, earfcn);
stack->set_scell_complete(true);
});
return true;
}
void phy::set_config_tdd(srslte_tdd_config_t& tdd_config_)
@ -485,9 +575,17 @@ void phy::set_config_tdd(srslte_tdd_config_t& tdd_config_)
}
tdd_config.configured = true;
for (uint32_t i = 0; i < nof_workers; i++) {
workers[i]->set_tdd_config(tdd_config);
}
// Apply config when worker is finished
cmd_worker.add_cmd([this]() {
for (uint32_t i = 0; i < nof_workers; i++) {
// set_tdd_config is not protected so run when worker is finished
sf_worker* w = (sf_worker*)workers_pool.wait_worker_id(i);
if (w) {
w->set_tdd_config_unlocked(tdd_config);
w->release();
}
}
});
}
void phy::set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs)

@ -878,19 +878,28 @@ void phy_common::reset()
ZERO_OBJECT(scell_cfg);
// Note: Using memset to reset these members is forbidden because they are real objects, not plain arrays.
for (auto& i : pending_dl_ack) {
i = {};
{
std::lock_guard<std::mutex> lock(pending_dl_ack_mutex);
for (auto& i : pending_dl_ack) {
i = {};
}
}
for (auto& i : pending_dl_dai) {
i = {};
}
for (auto& i : pending_ul_ack) {
for (auto& j : i) {
j = {};
{
std::lock_guard<std::mutex> lock(pending_ul_ack_mutex);
for (auto& i : pending_ul_ack) {
for (auto& j : i) {
j = {};
}
}
}
for (auto& i : pending_ul_grant) {
i = {};
{
std::lock_guard<std::mutex> lock(pending_ul_grant_mutex);
for (auto& i : pending_ul_grant) {
i = {};
}
}
// Release mapping of secondary cells

@ -92,6 +92,11 @@ void prach::stop()
mem_initiated = false;
}
void prach::reset_cfg()
{
cell_initiated = false;
}
bool prach::set_cell(srslte_cell_t cell_, srslte_prach_cfg_t prach_cfg)
{
if (!mem_initiated) {
@ -106,7 +111,7 @@ bool prach::set_cell(srslte_cell_t cell_, srslte_prach_cfg_t prach_cfg)
cell = cell_;
cfg = prach_cfg;
preamble_idx = -1;
// We must not reset preamble_idx here, MAC might have already called prepare_to_send()
if (6 + prach_cfg.freq_offset > cell.nof_prb) {
log_h->console("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", prach_cfg.freq_offset, cell.nof_prb);
@ -156,21 +161,17 @@ bool prach::generate_buffer(uint32_t f_idx)
bool prach::prepare_to_send(uint32_t preamble_idx_, int allowed_subframe_, float target_power_dbm_)
{
if (cell_initiated && preamble_idx_ < max_preambles) {
preamble_idx = preamble_idx_;
target_power_dbm = target_power_dbm_;
allowed_subframe = allowed_subframe_;
transmitted_tti = -1;
Debug("PRACH: prepare to send preamble %d\n", preamble_idx);
return true;
}
if (!cell_initiated) {
Error("PRACH: Cell not configured\n");
} else {
if (preamble_idx_ >= max_preambles) {
Error("PRACH: Invalid preamble %d\n", preamble_idx_);
return false;
}
return false;
preamble_idx = preamble_idx_;
target_power_dbm = target_power_dbm_;
allowed_subframe = allowed_subframe_;
transmitted_tti = -1;
Debug("PRACH: prepare to send preamble %d\n", preamble_idx);
return true;
}
bool prach::is_pending() const
@ -178,9 +179,10 @@ bool prach::is_pending() const
return cell_initiated && preamble_idx >= 0 && unsigned(preamble_idx) < max_preambles;
}
bool prach::is_ready_to_send(uint32_t current_tti_)
bool prach::is_ready_to_send(uint32_t current_tti_, uint32_t current_pci)
{
if (is_pending()) {
// Make sure the curernt PCI is the one we configured the PRACH for
if (is_pending() && current_pci == cell.id) {
// consider the number of subframes the transmission must be anticipated
uint32_t tti_tx = TTI_TX(current_tti_);
if (srslte_prach_tti_opportunity(&prach_obj, tti_tx, allowed_subframe)) {

@ -74,19 +74,15 @@ sf_worker::~sf_worker()
}
}
void sf_worker::reset()
void sf_worker::reset_cell_unlocked(uint32_t cc_idx)
{
for (auto& cc_worker : cc_workers) {
cc_worker->reset();
}
cc_workers[cc_idx]->reset_cell_unlocked();
}
bool sf_worker::set_cell(uint32_t cc_idx, srslte_cell_t cell_)
bool sf_worker::set_cell_unlocked(uint32_t cc_idx, srslte_cell_t cell_)
{
std::lock_guard<std::mutex> lock(cell_mutex);
if (cc_idx < cc_workers.size()) {
if (!cc_workers[cc_idx]->set_cell(cell_)) {
if (!cc_workers[cc_idx]->set_cell_unlocked(cell_)) {
Error("Setting cell for cc=%d\n", cc_idx);
return false;
}
@ -95,6 +91,7 @@ bool sf_worker::set_cell(uint32_t cc_idx, srslte_cell_t cell_)
}
if (cc_idx == 0) {
std::lock_guard<std::mutex> lock(cell_mutex);
cell = cell_;
cell_initiated = true;
cell_init_cond.notify_one();
@ -142,41 +139,40 @@ void sf_worker::set_prach(cf_t* prach_ptr_, float prach_power_)
prach_power = prach_power_;
}
void sf_worker::set_cfo(const uint32_t& cc_idx, float cfo)
void sf_worker::set_cfo_unlocked(const uint32_t& cc_idx, float cfo)
{
cc_workers[cc_idx]->set_cfo(cfo);
cc_workers[cc_idx]->set_cfo_unlocked(cfo);
}
void sf_worker::set_crnti(uint16_t rnti)
void sf_worker::set_crnti_unlocked(uint16_t rnti)
{
for (auto& cc_worker : cc_workers) {
cc_worker->set_crnti(rnti);
cc_worker->set_crnti_unlocked(rnti);
}
}
void sf_worker::set_tdd_config(srslte_tdd_config_t config)
void sf_worker::set_tdd_config_unlocked(srslte_tdd_config_t config)
{
for (auto& cc_worker : cc_workers) {
cc_worker->set_tdd_config(config);
cc_worker->set_tdd_config_unlocked(config);
}
tdd_config = config;
}
void sf_worker::enable_pregen_signals(bool enabled)
void sf_worker::enable_pregen_signals_unlocked(bool enabled)
{
for (auto& cc_worker : cc_workers) {
cc_worker->enable_pregen_signals(enabled);
cc_worker->enable_pregen_signals_unlocked(enabled);
}
}
void sf_worker::set_config(uint32_t cc_idx, srslte::phy_cfg_t& phy_cfg)
void sf_worker::set_config_unlocked(uint32_t cc_idx, srslte::phy_cfg_t phy_cfg)
{
if (cc_idx < cc_workers.size()) {
Info("Setting configuration for worker=%d, cc=%d\n", get_id(), cc_idx);
cc_workers[cc_idx]->set_config(phy_cfg);
cc_workers[cc_idx]->set_config_unlocked(phy_cfg);
if (cc_idx > 0) {
// Update DCI config for PCell
cc_workers[0]->upd_config_dci(phy_cfg.dl_cfg.dci);
cc_workers[0]->upd_config_dci_unlocked(phy_cfg.dl_cfg.dci);
}
} else {
Error("Setting config for cc=%d; Invalid cc_idx\n", cc_idx);
@ -209,7 +205,7 @@ void sf_worker::work_imp()
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) {
if ((carrier_idx == 0) || (phy->scell_cfg[carrier_idx].enabled && phy->scell_cfg[carrier_idx].configured)) {
rx_signal_ok = cc_workers[carrier_idx]->work_dl_regular();
}
}
@ -241,10 +237,12 @@ void sf_worker::work_imp()
// Loop through all carriers
for (uint32_t carrier_idx = 0; carrier_idx < phy->args->nof_carriers; carrier_idx++) {
tx_signal_ready |= cc_workers[carrier_idx]->work_ul(uci_cc_idx == carrier_idx ? &uci_data : nullptr);
if ((carrier_idx == 0) || (phy->scell_cfg[carrier_idx].enabled && phy->scell_cfg[carrier_idx].configured)) {
tx_signal_ready |= cc_workers[carrier_idx]->work_ul(uci_cc_idx == carrier_idx ? &uci_data : nullptr);
// Set signal pointer based on offset
tx_signal_ptr.set(carrier_idx, 0, phy->args->nof_rx_ant, cc_workers[carrier_idx]->get_tx_buffer(0));
// Set signal pointer based on offset
tx_signal_ptr.set(carrier_idx, 0, phy->args->nof_rx_ant, cc_workers[carrier_idx]->get_tx_buffer(0));
}
}
}
}
@ -283,20 +281,18 @@ void sf_worker::reset_uci(srslte_uci_data_t* uci_data)
void sf_worker::update_measurements()
{
// Run measurements in all carriers, but only in one worker
if (get_id() == 0) {
std::vector<rrc_interface_phy_lte::phy_meas_t> serving_cells = {};
for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) {
cf_t* rssi_power_buffer = nullptr;
if (cc_idx == 0) {
rssi_power_buffer = cc_workers[0]->get_rx_buffer(0);
}
cc_workers[cc_idx]->update_measurements(serving_cells, rssi_power_buffer);
}
// Send report to stack
if (not serving_cells.empty()) {
phy->stack->new_cell_meas(serving_cells);
std::vector<rrc_interface_phy_lte::phy_meas_t> serving_cells = {};
for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) {
cf_t* rssi_power_buffer = nullptr;
// Setting rssi_power_buffer to nullptr disables RSSI update. Do it only by worker 0
if (cc_idx == 0 && get_id() == 0) {
rssi_power_buffer = cc_workers[0]->get_rx_buffer(0);
}
cc_workers[cc_idx]->update_measurements(serving_cells, rssi_power_buffer);
}
// Send report to stack
if (not serving_cells.empty()) {
phy->stack->new_cell_meas(serving_cells);
}
}

@ -181,15 +181,18 @@ void sync::reset()
* returns 1 and stores cell information and RSRP values in the pointers (if provided). If a cell is not found in the
* current frequency it moves to the next one and the next call to cell_search() will look in the next EARFCN in the
* set. If no cells are found in any frequency it returns 0. If error returns -1.
*
* The first part of the procedure (call to _init()) moves the PHY To IDLE, ensuring that no UL/DL/PRACH will happen
*
*/
phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte::phy_cell_t* found_cell)
bool sync::cell_search_init()
{
std::unique_lock<std::mutex> ul(rrc_mutex);
phy_interface_rrc_lte::cell_search_ret_t ret = {};
ret.found = phy_interface_rrc_lte::cell_search_ret_t::ERROR;
ret.last_freq = phy_interface_rrc_lte::cell_search_ret_t::NO_MORE_FREQS;
if (rrc_proc_state != PROC_IDLE) {
Error("Cell Search: Can't start procedure. SYNC already running a procedure (%d)\n", (uint32_t)rrc_proc_state);
return false;
}
// Move state to IDLE
Info("Cell Search: Start EARFCN index=%u/%zd\n", cellsearch_earfcn_index, worker_com->args->dl_earfcn_list.size());
@ -199,6 +202,26 @@ phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte
// Stop all intra-frequency measurement before changing frequency
meas_stop();
rrc_proc_state = PROC_SEARCH_START;
return true;
}
rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* found_cell)
{
std::unique_lock<std::mutex> ul(rrc_mutex);
rrc_interface_phy_lte::cell_search_ret_t ret = {};
ret.found = rrc_interface_phy_lte::cell_search_ret_t::ERROR;
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS;
if (rrc_proc_state != PROC_SEARCH_START) {
Error("Cell Search: Can't run procedure. Must call cell_search_init() first (%d)\n", (uint32_t)rrc_proc_state);
return ret;
}
rrc_proc_state = PROC_SEARCH_RUNNING;
if (srate_mode != SRATE_FIND) {
srate_mode = SRATE_FIND;
radio_h->set_rx_srate(1.92e6);
@ -230,11 +253,11 @@ phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte
found_cell->pci = cell.id;
found_cell->cfo_hz = search_p.get_last_cfo();
}
ret.found = phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND;
ret.found = rrc_interface_phy_lte::cell_search_ret_t::CELL_FOUND;
break;
case search::CELL_NOT_FOUND:
Info("Cell Search: No cell found in this frequency\n");
ret.found = phy_interface_rrc_lte::cell_search_ret_t::CELL_NOT_FOUND;
ret.found = rrc_interface_phy_lte::cell_search_ret_t::CELL_NOT_FOUND;
break;
default:
Error("Cell Search: while receiving samples\n");
@ -246,76 +269,90 @@ phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte
if (cellsearch_earfcn_index >= worker_com->args->dl_earfcn_list.size()) {
Info("Cell Search: No more frequencies in the current EARFCN set\n");
cellsearch_earfcn_index = 0;
ret.last_freq = phy_interface_rrc_lte::cell_search_ret_t::NO_MORE_FREQS;
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS;
} else {
ret.last_freq = phy_interface_rrc_lte::cell_search_ret_t::MORE_FREQS;
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::MORE_FREQS;
}
rrc_proc_state = PROC_IDLE;
return ret;
}
/* Cell select synchronizes to a new cell (e.g. during HO or during cell reselection on IDLE) or
* re-synchronizes with the current cell if cell argument is NULL
* The first phase of the procedure verifies the validity of the input parameters and switches the
* PHY to IDLE. Once this function returns, the PHY will not process any DL/UL nor will PRACH
*
* See cell_select_start()
*/
bool sync::cell_select(const phy_interface_rrc_lte::phy_cell_t* new_cell)
bool sync::cell_select_init(phy_cell_t new_cell)
{
std::unique_lock<std::mutex> ul(rrc_mutex);
bool ret = false;
int cnt = 0;
// Move state to IDLE
if (new_cell == nullptr) {
Info("Cell Select: Starting cell resynchronization\n");
} else {
if (!srslte_cellid_isvalid(new_cell->pci)) {
log_h->error("Cell Select: Invalid cell_id=%d\n", new_cell->pci);
return ret;
}
Info("Cell Select: Starting cell selection for PCI=%d, EARFCN=%d\n", new_cell->pci, new_cell->earfcn);
if (rrc_proc_state != PROC_IDLE) {
Error("Cell Select: Can't start procedure. SYNC already running a procedure (%d)\n", (uint32_t)rrc_proc_state);
return false;
}
// Wait for any pending PHICH
while (worker_com->is_any_ul_pending_ack() && cnt < 10) {
usleep(1000);
cnt++;
Info("Cell Select: waiting pending PHICH (cnt=%d)\n", cnt);
// Move state to IDLE
if (!srslte_cellid_isvalid(new_cell.pci)) {
Error("Cell Select: Invalid cell_id=%d\n", new_cell.pci);
return false;
}
Info("Cell Select: Going to IDLE\n");
phy_state.go_idle();
worker_com->reset();
// Stop intra-frequency measurements if need to change frequency
if ((int)new_cell.earfcn != current_earfcn) {
meas_stop();
}
rrc_proc_state = PROC_SELECT_START;
return true;
}
bool sync::cell_select_start(phy_cell_t new_cell)
{
std::unique_lock<std::mutex> ul(rrc_mutex);
if (rrc_proc_state != PROC_SELECT_START) {
Error("Cell Select: Can't run procedure. Must call cell_select_init() first (%d)\n", (uint32_t)rrc_proc_state);
return false;
}
rrc_proc_state = PROC_SELECT_RUNNING;
bool ret = false;
sfn_p.reset();
search_p.reset();
srslte_ue_sync_reset(&ue_sync);
/* Reconfigure cell if necessary */
if (new_cell != nullptr) {
cell.id = new_cell->pci;
if (not set_cell(new_cell->cfo_hz)) {
Error("Cell Select: Reconfiguring cell\n");
return ret;
}
/* Select new frequency if necessary */
if ((int)new_cell->earfcn != current_earfcn) {
current_earfcn = new_cell->earfcn;
cell.id = new_cell.pci;
if (not set_cell(new_cell.cfo_hz)) {
Error("Cell Select: Reconfiguring cell\n");
return false;
}
// Stop all intra-frequency measurement before changing frequency
meas_stop();
/* Select new frequency if necessary */
if ((int)new_cell.earfcn != current_earfcn) {
current_earfcn = new_cell.earfcn;
Info("Cell Select: Setting new frequency EARFCN=%d\n", new_cell->earfcn);
if (!set_frequency()) {
Error("Cell Select: Setting new frequency EARFCN=%d\n", new_cell->earfcn);
return ret;
}
Info("Cell Select: Setting new frequency EARFCN=%d\n", new_cell.earfcn);
if (!set_frequency()) {
Error("Cell Select: Setting new frequency EARFCN=%d\n", new_cell.earfcn);
return false;
}
// Reconfigure first intra-frequency measurement
intra_freq_meas[0]->set_primary_cell(current_earfcn, cell);
}
// Reconfigure first intra-frequency measurement
intra_freq_meas[0]->set_primary_cell(current_earfcn, cell);
// Change sampling rate if necessary
if (srate_mode != SRATE_CAMP) {
log_h->info("Cell Select: Setting CAMPING sampling rate\n");
@ -332,6 +369,8 @@ bool sync::cell_select(const phy_interface_rrc_lte::phy_cell_t* new_cell)
Info("Cell Select: Could not synchronize SFN\n");
}
rrc_proc_state = PROC_IDLE;
return ret;
}
@ -433,7 +472,7 @@ void sync::run_camping_in_sync_state(sf_worker* worker, srslte::rf_buffer_t& syn
}
// Check if we need to TX a PRACH
if (prach_buffer->is_ready_to_send(tti)) {
if (prach_buffer->is_ready_to_send(tti, cell.id)) {
prach_ptr = prach_buffer->generate(get_tx_cfo(), &prach_nof_sf, &prach_power);
if (prach_ptr == nullptr) {
Error("Generating PRACH\n");
@ -444,7 +483,7 @@ void sync::run_camping_in_sync_state(sf_worker* worker, srslte::rf_buffer_t& syn
// Set CFO for all Carriers
for (uint32_t cc = 0; cc < worker_com->args->nof_carriers; cc++) {
worker->set_cfo(cc, get_tx_cfo());
worker->set_cfo_unlocked(cc, get_tx_cfo());
worker_com->update_cfo_measurement(cc, srslte_ue_sync_get_cfo(&ue_sync));
}
@ -508,6 +547,7 @@ void sync::run_camping_state()
}
// Run stack
Debug("run_stack_tti: from main\n");
run_stack_tti();
}
@ -712,8 +752,15 @@ void sync::set_ue_sync_opts(srslte_ue_sync_t* q, float cfo)
bool sync::set_cell(float cfo)
{
// Wait the SYNC thread to transition to IDLE
uint32_t cnt = 0;
while (!phy_state.is_idle() && cnt <= 20) {
Info("SYNC: PHY state is_idle=%d, cnt=%d\n", phy_state.is_idle(), cnt);
usleep(500);
cnt++;
}
if (!phy_state.is_idle()) {
Warning("Can not change Cell while not in IDLE\n");
Error("Can not change Cell while not in IDLE\n");
return false;
}
@ -730,11 +777,16 @@ bool sync::set_cell(float cfo)
sfn_p.set_cell(cell);
worker_com->set_cell(cell);
// Reset cell configuration
for (uint32_t i = 0; i < nof_workers; i++) {
((sf_worker*)workers_pool->get_worker(i))->reset_cell_unlocked(0);
}
bool success = true;
for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) {
sf_worker* w = (sf_worker*)workers_pool->wait_worker_id(i);
if (w) {
success &= w->set_cell(0, cell);
success &= w->set_cell_unlocked(0, cell);
w->release();
}
}
@ -855,6 +907,7 @@ int sync::radio_recv_fnc(srslte::rf_buffer_t& data, srslte_timestamp_t* rx_time)
// Run stack if the sync state is not in camping
if (not phy_state.is_camping()) {
Debug("run_stack_tti: from recv\n");
run_stack_tti();
}
@ -910,7 +963,9 @@ void sync::run_stack_tti()
}
// Run stack
Debug("run_stack_tti: calling stack\n");
stack->run_tti(tti, tti_jump);
Debug("run_stack_tti: stack called\n");
}
// update timestamp

@ -225,10 +225,6 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::reset(bool lock)
payload_buffer_ptr = NULL;
}
if (is_initiated && lock) {
srslte_softbuffer_rx_reset(&softbuffer);
}
if (lock) {
mutex.unlock();
}

@ -152,16 +152,6 @@ void mac::reconfiguration(const uint32_t& cc_idx, const bool& enable)
}
}
void mac::wait_uplink()
{
int cnt = 0;
Info("Waiting to uplink...\n");
while (mux_unit.is_pending_any_sdu() && cnt < 20) {
usleep(1000);
cnt++;
}
}
// Implement Section 5.9
void mac::reset()
{
@ -601,14 +591,9 @@ void mac::set_contention_id(uint64_t uecri)
uernti.contention_id = uecri;
}
void mac::start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask)
{
ra_procedure.start_noncont(preamble_index, prach_mask);
}
void mac::start_cont_ho()
void mac::set_rach_ded_cfg(uint32_t preamble_index, uint32_t prach_mask)
{
ra_procedure.start_mac_order(56, true);
ra_procedure.set_config_ded(preamble_index, prach_mask);
}
void mac::set_mbsfn_config(uint32_t nof_mbsfn_services)
@ -619,6 +604,7 @@ void mac::set_mbsfn_config(uint32_t nof_mbsfn_services)
void mac::set_config(mac_cfg_t& mac_cfg)
{
Info("Setting configuration\n");
// Set configuration for each module in MAC
bsr_procedure.set_config(mac_cfg.bsr_cfg);
phr_procedure.set_config(mac_cfg.phr_cfg);

@ -31,7 +31,6 @@
namespace srsue {
const char* state_str[] = {"RA: INIT: ",
"RA: INIT: ",
"RA: PDCCH: ",
"RA: Rx: ",
"RA: Backoff: ",
@ -97,6 +96,14 @@ void ra_proc::set_config(srslte::rach_cfg_t& rach_cfg_)
new_cfg = rach_cfg_;
}
void ra_proc::set_config_ded(uint32_t preamble_index, uint32_t prach_mask)
{
std::unique_lock<std::mutex> ul(mutex);
next_preamble_idx = preamble_index;
next_prach_mask = prach_mask;
noncontention_enabled = true;
}
/* Reads the configuration and configures internal variables */
void ra_proc::read_params()
{
@ -148,7 +155,6 @@ void ra_proc::step(uint32_t tti_)
case START_WAIT_COMPLETION:
state_completition();
break;
case WAITING_PHY_CONFIG:
case WAITING_COMPLETION:
// do nothing, bc we are waiting for the phy to finish
break;
@ -232,28 +238,11 @@ void ra_proc::state_completition()
state = WAITING_COMPLETION;
uint16_t rnti = rntis->crnti;
uint32_t task_id = current_task_id;
task_sched->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(task_id);
});
}
void ra_proc::notify_phy_config_completed(uint32_t task_id)
{
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 {
rError("Received old notification of PHY configuration (old task_id=%d, current_task_id=%d)\n",
task_id,
current_task_id);
}
phy_h->set_crnti(rnti);
// signal MAC RA proc to go back to idle
notify_ra_completed(task_id);
}
void ra_proc::notify_ra_completed(uint32_t task_id)
@ -281,15 +270,7 @@ void ra_proc::initialization()
preambleTransmissionCounter = 1;
mux_unit->msg3_flush();
backoff_param_ms = 0;
// Instruct phy to configure PRACH
state = WAITING_PHY_CONFIG;
uint32_t task_id = current_task_id;
task_sched->enqueue_background_task([this, task_id](uint32_t worker_id) {
phy_h->configure_prach_params();
// notify back MAC
task_sched->notify_background_task_result([this, task_id]() { notify_phy_config_completed(task_id); });
});
resource_selection();
}
/* Resource selection as defined in 5.1.2 */
@ -538,27 +519,17 @@ void ra_proc::complete()
mux_unit->msg3_flush();
if (ra_is_ho) {
rrc->ho_ra_completed();
}
rrc->ra_completed();
log_h->console("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta);
rInfo("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta);
state = START_WAIT_COMPLETION;
}
void ra_proc::start_noncont(uint32_t preamble_index, uint32_t prach_mask)
{
next_preamble_idx = preamble_index;
next_prach_mask = prach_mask;
noncontention_enabled = true;
start_mac_order(56, true);
}
void ra_proc::start_mac_order(uint32_t msg_len_bits, bool is_ho)
void ra_proc::start_mac_order(uint32_t msg_len_bits)
{
if (state == IDLE) {
ra_is_ho = is_ho;
started_by_pdcch = false;
new_ra_msg_len = msg_len_bits;
rInfo("Starting PRACH by MAC order\n");

@ -240,7 +240,7 @@ void ul_harq_entity::ul_harq_process::new_grant_ul(mac_interface_phy_lte::mac_gr
// Uplink dci in a RAR and there is a PDU in the Msg3 buffer
if (grant.is_rar) {
if (harq_entity->mux_unit->msg3_is_pending()) {
Debug("Getting Msg3 buffer payload, dci size=%d bytes\n", grant.tb.tbs);
Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant.tb.tbs);
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer.get(), grant.tb.tbs);
if (pdu_ptr) {
generate_new_tx(grant, action);

@ -23,7 +23,7 @@
namespace srsue {
std::string to_string(const phy_interface_rrc_lte::phy_cell_t& cell)
std::string to_string(const phy_cell_t& cell)
{
char buffer[128];
snprintf(buffer, sizeof(buffer), "{pci=%d, dl_earfcn=%d}", cell.pci, cell.earfcn);
@ -79,12 +79,7 @@ void phy_controller::selecting_cell::enter(phy_controller* f, const cell_sel_cmd
csel_res.result = false;
fsmInfo("Starting for pci=%d, earfcn=%d\n", target_cell.pci, target_cell.earfcn);
phy_interface_rrc_lte::phy_cell_t cell_copy = target_cell;
f->task_sched.enqueue_background_task([f, cell_copy](uint32_t worker_id) {
bool ret = f->phy->cell_select(&cell_copy);
// notify back RRC
f->task_sched.notify_background_task_result([f, ret]() { f->cell_selection_completed(ret); });
});
f->phy->cell_select(target_cell);
}
void phy_controller::selecting_cell::exit(phy_controller* f)
@ -139,12 +134,7 @@ void phy_controller::cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t
void phy_controller::searching_cell::enter(phy_controller* f)
{
otherfsmInfo(f, "Initiating Cell search\n");
f->task_sched.enqueue_background_task([f](uint32_t worker_id) {
phy_interface_rrc_lte::phy_cell_t found_cell;
phy_interface_rrc_lte::cell_search_ret_t ret = f->phy->cell_search(&found_cell);
// notify back RRC
f->task_sched.notify_background_task_result([f, found_cell, ret]() { f->cell_search_completed(ret, found_cell); });
});
f->phy->cell_search();
}
void phy_controller::handle_cell_search_res(searching_cell& s, const cell_srch_res& result)

@ -247,8 +247,10 @@ void rrc::run_tti()
case cmd_msg_t::RLF:
radio_link_failure_process();
break;
case cmd_msg_t::HO_COMPLETE:
ho_handler.trigger(ho_proc::ra_completed_ev{msg.lcid > 0});
case cmd_msg_t::RA_COMPLETE:
if (ho_handler.is_busy()) {
ho_handler.trigger(ho_proc::ra_completed_ev{msg.lcid > 0});
}
break;
case cmd_msg_t::STOP:
return;
@ -348,6 +350,20 @@ void rrc::set_ue_identity(srslte::s_tmsi_t s_tmsi)
*
*******************************************************************************/
void rrc::cell_search_complete(rrc_interface_phy_lte::cell_search_ret_t cs_ret, phy_cell_t found_cell)
{
phy_ctrl->cell_search_completed(cs_ret, found_cell);
}
void rrc::cell_select_complete(bool cs_ret)
{
phy_ctrl->cell_selection_completed(cs_ret);
}
void rrc::set_config_complete(bool status) {}
void rrc::set_scell_complete(bool status) {}
/* This function is called from a PHY worker thus must return very quickly.
* Queue the values of the measurements and process them from the RRC thread
*/
@ -478,8 +494,8 @@ void rrc::cell_reselection(float rsrp, float rsrq)
// TODO: Inter-frequency cell reselection
}
// Set serving cell
void rrc::set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving)
// Set new serving cell
void rrc::set_serving_cell(phy_cell_t phy_cell, bool discard_serving)
{
meas_cells.set_serving_cell(phy_cell, discard_serving);
}
@ -499,6 +515,11 @@ bool rrc::has_neighbour_cell(uint32_t earfcn, uint32_t pci) const
return meas_cells.has_neighbour_cell(earfcn, pci);
}
bool rrc::is_serving_cell(uint32_t earfcn, uint32_t pci) const
{
return meas_cells.serving_cell().phy_cell.earfcn == earfcn and meas_cells.serving_cell().phy_cell.pci == pci;
}
/*******************************************************************************
*
*
@ -854,10 +875,10 @@ void rrc::send_rrc_con_reconfig_complete()
send_ul_dcch_msg(RB_ID_SRB1, ul_dcch_msg);
}
void rrc::ho_ra_completed()
void rrc::ra_completed()
{
cmd_msg_t msg;
msg.command = cmd_msg_t::HO_COMPLETE;
msg.command = cmd_msg_t::RA_COMPLETE;
msg.lcid = 1;
cmd_q.push(std::move(msg));
}
@ -915,36 +936,31 @@ bool rrc::con_reconfig(const rrc_conn_recfg_s& reconfig)
}
}
// Apply Scell RR configurations (call is non-blocking). Make a copy since can be changed inside apply_scell_config()
// Note that apply_scell_config() calls set_scell() and set_config() which run in the background.
rrc_conn_recfg_r8_ies_s reconfig_r8_ = *reconfig_r8;
task_sched.enqueue_background_task([this, reconfig_r8_](uint32_t worker_id) mutable {
// Apply configurations without blocking stack
apply_scell_config(&reconfig_r8_);
// notify back RRC
task_sched.notify_background_task_result([this, reconfig_r8_]() {
const rrc_conn_recfg_r8_ies_s* reconfig_r8 = &reconfig_r8_;
apply_scell_config(&reconfig_r8_);
if (!measurements->parse_meas_config(
reconfig_r8, reestablishment_successful, connection_reest.get()->get_source_earfcn())) {
return;
}
if (!measurements->parse_meas_config(
reconfig_r8, reestablishment_successful, connection_reest.get()->get_source_earfcn())) {
return false;
}
send_rrc_con_reconfig_complete();
// FIXME-@frankist: From here to the end need to be processed when set_config_complete() is called
send_rrc_con_reconfig_complete();
unique_byte_buffer_t nas_sdu;
for (uint32_t i = 0; i < reconfig_r8->ded_info_nas_list.size(); i++) {
nas_sdu = srslte::allocate_unique_buffer(*pool);
if (nas_sdu.get()) {
memcpy(nas_sdu->msg, reconfig_r8->ded_info_nas_list[i].data(), reconfig_r8->ded_info_nas_list[i].size());
nas_sdu->N_bytes = reconfig_r8->ded_info_nas_list[i].size();
nas->write_pdu(RB_ID_SRB1, std::move(nas_sdu));
} else {
rrc_log->error("Fatal Error: Couldn't allocate PDU in %s.\n", __FUNCTION__);
return;
}
}
});
});
unique_byte_buffer_t nas_sdu;
for (uint32_t i = 0; i < reconfig_r8->ded_info_nas_list.size(); i++) {
nas_sdu = srslte::allocate_unique_buffer(*pool);
if (nas_sdu.get()) {
memcpy(nas_sdu->msg, reconfig_r8->ded_info_nas_list[i].data(), reconfig_r8->ded_info_nas_list[i].size());
nas_sdu->N_bytes = reconfig_r8->ded_info_nas_list[i].size();
nas->write_pdu(RB_ID_SRB1, std::move(nas_sdu));
} else {
rrc_log->error("Fatal Error: Couldn't allocate PDU in %s.\n", __FUNCTION__);
return false;
}
}
return true;
}
@ -1011,7 +1027,6 @@ void rrc::leave_connected()
pdcp->reset();
rlc->reset();
mac->reset();
phy->reset();
set_phy_default();
set_mac_default();
stop_timers();
@ -1051,17 +1066,6 @@ void rrc::start_con_restablishment(reest_cause_e cause)
callback_list.add_proc(connection_reest);
}
void rrc::cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& cs_ret,
const phy_interface_rrc_lte::phy_cell_t& found_cell)
{
phy_ctrl->cell_search_completed(cs_ret, found_cell);
}
void rrc::cell_select_completed(bool cs_ret)
{
phy_ctrl->cell_selection_completed(cs_ret);
}
/**
* Check whether data on SRB1 or SRB2 still needs to be sent.
* If the bearer is suspended it will not be considered.
@ -1947,6 +1951,8 @@ void rrc::log_rr_config_common()
void rrc::apply_rr_config_common(rr_cfg_common_s* config, bool send_lower_layers)
{
rrc_log->info("Applying MAC/PHY config common\n");
if (config->rach_cfg_common_present) {
set_mac_cfg_t_rach_cfg_common(&current_mac_cfg, config->rach_cfg_common);
}
@ -2023,6 +2029,8 @@ void rrc::log_phy_config_dedicated()
// Apply default physical common and dedicated configuration
void rrc::set_phy_default()
{
rrc_log->info("Setting default PHY config (common and dedicated)\n");
current_phy_cfg.set_defaults();
if (phy != nullptr) {
@ -2040,6 +2048,8 @@ void rrc::set_phy_default()
// Apply default physical channel configs (9.2.4)
void rrc::set_phy_config_dedicated_default()
{
rrc_log->info("Setting default PHY config dedicated\n");
current_phy_cfg.set_defaults_dedicated();
if (phy != nullptr) {
@ -2057,6 +2067,8 @@ void rrc::set_phy_config_dedicated_default()
// Apply provided PHY config
void rrc::apply_phy_config_dedicated(const phys_cfg_ded_s& phy_cnfg, bool is_handover)
{
rrc_log->info("Applying PHY config dedicated\n");
set_phy_cfg_t_dedicated_cfg(&current_phy_cfg, phy_cnfg);
if (is_handover) {
current_phy_cfg.ul_cfg.pucch.sr_configured = false;
@ -2083,6 +2095,8 @@ void rrc::apply_phy_scell_config(const scell_to_add_mod_r10_s& scell_config)
return;
}
rrc_log->info("Applying PHY config to scell\n");
// Initialise default parameters from primary cell
earfcn = meas_cells.serving_cell().get_earfcn();
@ -2122,10 +2136,14 @@ void rrc::apply_phy_scell_config(const scell_to_add_mod_r10_s& scell_config)
}
// Initialize scell config with pcell cfg
srslte::phy_cfg_t scell_phy_cfg = current_phy_cfg;
set_phy_cfg_t_scell_config(&scell_phy_cfg, scell_config);
set_phy_cfg_t_scell_config(&current_phy_cfg, scell_config);
if (!phy->set_scell(scell, scell_config.scell_idx_r10, earfcn)) {
rrc_log->error("Adding SCell cc_idx=%d\n", scell_config.scell_idx_r10);
} else if (!phy->set_config(current_phy_cfg, scell_config.scell_idx_r10)) {
rrc_log->error("Setting SCell configuration for cc_idx=%d\n", scell_config.scell_idx_r10);
}
phy->set_config(scell_phy_cfg, scell_config.scell_idx_r10, earfcn, &scell);
current_scell_configured[scell_config.scell_idx_r10] = true;
}
@ -2146,7 +2164,7 @@ void rrc::log_mac_config_dedicated()
// 3GPP 36.331 v10 9.2.2 Default MAC main configuration
void rrc::apply_mac_config_dedicated_default()
{
rrc_log->info("Set MAC default configuration\n");
rrc_log->info("Setting MAC default configuration\n");
current_mac_cfg.set_mac_main_cfg_default();
mac->set_config(current_mac_cfg);
log_mac_config_dedicated();
@ -2169,6 +2187,8 @@ bool rrc::apply_rr_config_dedicated(const rr_cfg_ded_s* cnfg, bool is_handover)
}
}
rrc_log->info("Applying MAC config dedicated\n");
if (cnfg->mac_main_cfg_present) {
if (cnfg->mac_main_cfg.type() == rr_cfg_ded_s::mac_main_cfg_c_::types::default_value) {
current_mac_cfg.set_mac_main_cfg_default();
@ -2217,6 +2237,8 @@ bool rrc::apply_rr_config_dedicated(const rr_cfg_ded_s* cnfg, bool is_handover)
bool rrc::apply_rr_config_dedicated_on_ho_complete(const rr_cfg_ded_s& cnfg)
{
rrc_log->info("Applying MAC/PHY config dedicated on HO complete\n");
// Apply SR+CQI configuration to PHY
if (cnfg.phys_cfg_ded_present) {
current_phy_cfg.ul_cfg.pucch.sr_configured = cnfg.phys_cfg_ded.sched_request_cfg_present;
@ -2246,9 +2268,9 @@ void rrc::apply_scell_config(rrc_conn_recfg_r8_ies_s* reconfig_r8)
if (reconfig_r8->non_crit_ext_present) {
auto reconfig_r890 = &reconfig_r8->non_crit_ext;
if (reconfig_r890->non_crit_ext_present) {
rrc_conn_recfg_v920_ies_s* reconfig_r920 = &reconfig_r890->non_crit_ext;
auto* reconfig_r920 = &reconfig_r890->non_crit_ext;
if (reconfig_r920->non_crit_ext_present) {
rrc_conn_recfg_v1020_ies_s* reconfig_r1020 = &reconfig_r920->non_crit_ext;
auto* reconfig_r1020 = &reconfig_r920->non_crit_ext;
// Handle Add/Modify SCell list
if (reconfig_r1020->scell_to_add_mod_list_r10_present) {
@ -2486,7 +2508,6 @@ void rrc::add_mrb(uint32_t lcid, uint32_t port)
// PHY CONFIG DEDICATED Defaults (3GPP 36.331 v10 9.2.4)
void rrc::set_phy_default_pucch_srs()
{
rrc_log->info("Setting default PHY config dedicated\n");
set_phy_config_dedicated_default();
// SR configuration affects to MAC SR too

@ -171,7 +171,7 @@ const cell_t* meas_cell_list::get_neighbour_cell_handle(uint32_t earfcn, uint32_
// If only neighbour PCI is provided, copy full cell from serving cell
bool meas_cell_list::add_meas_cell(const rrc_interface_phy_lte::phy_meas_t& meas)
{
phy_interface_rrc_lte::phy_cell_t phy_cell = {};
phy_cell_t phy_cell = {};
phy_cell.earfcn = meas.earfcn;
phy_cell.pci = meas.pci;
unique_cell_t c = unique_cell_t(new cell_t(phy_cell));
@ -337,7 +337,7 @@ cell_t* meas_cell_list::find_cell(uint32_t earfcn, uint32_t pci)
return get_neighbour_cell_handle(earfcn, pci);
}
int meas_cell_list::set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving)
int meas_cell_list::set_serving_cell(phy_cell_t phy_cell, bool discard_serving)
{
// don't update neighbor cell list unless serving cell changes
if (phy_cell.pci == serving_cell().get_pci() && phy_cell.earfcn == serving_cell().get_earfcn()) {

@ -208,11 +208,10 @@ void rrc::rrc_meas::var_meas_report_list::generate_report(const uint32_t measId)
var_meas_report& var_meas = varMeasReportList.at(measId);
// sort cells by RSRP
std::sort(var_meas.cell_triggered_list.begin(),
var_meas.cell_triggered_list.end(),
[this](phy_interface_rrc_lte::phy_cell_t a, phy_interface_rrc_lte::phy_cell_t b) {
return rrc_ptr->get_cell_rsrp(a.earfcn, a.pci) > rrc_ptr->get_cell_rsrp(b.earfcn, b.pci);
});
std::sort(
var_meas.cell_triggered_list.begin(), var_meas.cell_triggered_list.end(), [this](phy_cell_t a, phy_cell_t b) {
return rrc_ptr->get_cell_rsrp(a.earfcn, a.pci) > rrc_ptr->get_cell_rsrp(b.earfcn, b.pci);
});
// set the measResultNeighCells to include the best neighbouring cells up to maxReportCells in accordance with
// the following
@ -382,10 +381,9 @@ void rrc::rrc_meas::var_meas_cfg::report_triggers()
for (auto& cell : trigger_state[m.first]) {
if (cell.second.is_enter_equal(report_cfg.trigger_type.event().time_to_trigger.to_number())) {
// Do not add if already exists
if (std::find_if(cells_triggered_list.begin(),
cells_triggered_list.end(),
[&cell](const phy_interface_rrc_lte::phy_cell_t& c) { return cell.first == c.pci; }) ==
cells_triggered_list.end()) {
if (std::find_if(cells_triggered_list.begin(), cells_triggered_list.end(), [&cell](const phy_cell_t& c) {
return cell.first == c.pci;
}) == cells_triggered_list.end()) {
cells_triggered_list.push_back({cell.first, meas_obj.carrier_freq});
new_cell_trigger = true;
}

@ -99,8 +99,7 @@ void rrc_nr::write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) {}
void rrc_nr::max_retx_attempted() {}
// STACK interface
void rrc_nr::cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& cs_ret,
const phy_interface_rrc_lte::phy_cell_t& found_cell)
void rrc_nr::cell_search_completed(const rrc_interface_phy_lte::cell_search_ret_t& cs_ret, const phy_cell_t& found_cell)
{}
} // namespace srsue

@ -77,14 +77,14 @@ proc_outcome_t rrc::cell_search_proc::step_si_acquire()
// SI Acquire has completed
if (si_acquire_fut.is_error()) {
Error("Failed SI acquire for SIB0\n");
search_result.cs_ret.found = phy_interface_rrc_lte::cell_search_ret_t::CELL_NOT_FOUND;
search_result.cs_ret.found = cell_search_ret_t::CELL_NOT_FOUND;
return proc_outcome_t::success;
}
Info("Completed successfully\n");
return proc_outcome_t::success;
}
proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_lte::phy_cell_t& new_cell)
proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_cell_t& new_cell)
{
Info("Cell found in this frequency. Setting new serving cell EARFCN=%d PCI=%d ...\n", new_cell.earfcn, new_cell.pci);
@ -135,13 +135,13 @@ proc_outcome_t rrc::cell_search_proc::react(const bool& cs_ret)
if (not cs_ret) {
Error("Couldn't select new serving cell\n");
search_result.cs_ret.found = phy_interface_rrc_lte::cell_search_ret_t::CELL_NOT_FOUND;
search_result.cs_ret.found = cell_search_ret_t::CELL_NOT_FOUND;
return proc_outcome_t::success;
}
if (not rrc_ptr->phy->cell_is_camping()) {
Warning("Could not camp on found cell.\n");
search_result.cs_ret.found = phy_interface_rrc_lte::cell_search_ret_t::CELL_NOT_FOUND;
search_result.cs_ret.found = cell_search_ret_t::CELL_NOT_FOUND;
return proc_outcome_t::success;
}
@ -161,9 +161,9 @@ proc_outcome_t rrc::cell_search_proc::react(const phy_controller::cell_srch_res&
search_result = event;
// Transition to SI Acquire or finish
if (search_result.cs_ret.found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND) {
if (search_result.cs_ret.found == cell_search_ret_t::CELL_FOUND) {
return handle_cell_found(search_result.found_cell);
} else if (search_result.cs_ret.found == phy_interface_rrc_lte::cell_search_ret_t::CELL_NOT_FOUND) {
} else if (search_result.cs_ret.found == cell_search_ret_t::CELL_NOT_FOUND) {
// No cells found. Do nothing
return proc_outcome_t::success;
}
@ -618,9 +618,8 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_search()
cs_result = cs_result_t::no_cell;
return proc_outcome_t::error;
}
cs_result = (cell_search_fut.value()->found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND)
? cs_result_t::changed_cell
: cs_result_t::no_cell;
cs_result = (cell_search_fut.value()->found == cell_search_ret_t::CELL_FOUND) ? cs_result_t::changed_cell
: cs_result_t::no_cell;
Info("Cell Search of cell selection run successfully\n");
return proc_outcome_t::success;
}
@ -697,14 +696,14 @@ proc_outcome_t rrc::plmn_search_proc::step()
// wait for new TTI
return proc_outcome_t::yield;
}
if (cell_search_fut.is_error() or cell_search_fut.value()->found == phy_interface_rrc_lte::cell_search_ret_t::ERROR) {
if (cell_search_fut.is_error() or cell_search_fut.value()->found == cell_search_ret_t::ERROR) {
// stop search
nof_plmns = -1;
Error("Failed due to failed cell search sub-procedure\n");
return proc_outcome_t::error;
}
if (cell_search_fut.value()->found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND) {
if (cell_search_fut.value()->found == cell_search_ret_t::CELL_FOUND) {
if (rrc_ptr->meas_cells.serving_cell().has_sib1()) {
// Save PLMN and TAC to NAS
for (uint32_t i = 0; i < rrc_ptr->meas_cells.serving_cell().nof_plmns(); i++) {
@ -721,7 +720,7 @@ proc_outcome_t rrc::plmn_search_proc::step()
}
}
if (cell_search_fut.value()->last_freq == phy_interface_rrc_lte::cell_search_ret_t::NO_MORE_FREQS) {
if (cell_search_fut.value()->last_freq == cell_search_ret_t::NO_MORE_FREQS) {
Info("completed PLMN search\n");
return proc_outcome_t::success;
}
@ -1175,8 +1174,11 @@ proc_outcome_t rrc::connection_reest_proc::init(asn1::rrc::reest_cause_e cause)
// reset MAC;
rrc_ptr->mac->reset();
// configure lower layers to consider the SCell(s), if configured, to be in deactivated state;
rrc_ptr->phy->set_activation_deactivation_scell(0);
// apply the default physical channel configuration as specified in 9.2.4;
rrc_ptr->set_phy_default_pucch_srs();
// Note: this is done by the MAC Reset procedure
// apply the default semi-persistent scheduling configuration as specified in 9.2.3;
// N.A.
@ -1290,6 +1292,11 @@ srslte::proc_outcome_t rrc::connection_reest_proc::cell_criteria()
Info("Cell Selection criteria passed after %dms. Sending RRC Connection Reestablishment Request\n",
rrc_ptr->t311.time_elapsed());
// Note: Not explicitly defined in the specs, but UE should apply SIB1 and SIB2 configuration in order to attempt
// a PRACH to a different cell
Info("Applying SIB2 configuration\n");
rrc_ptr->handle_sib2();
// stop timer T311;
rrc_ptr->t311.stop();
@ -1343,6 +1350,19 @@ proc_outcome_t rrc::connection_reest_proc::step()
rrc::ho_proc::ho_proc(srsue::rrc* rrc_) : rrc_ptr(rrc_) {}
/**
* This function implements the core of the HO procedure defined in 5.3.5.4
*
* Right after the PHY is instructed to synchronize with the new cell, DL and UL will be suspended by the PHY until in
* sync again with the new cell.
*
* Note that this function is executed by the main stack thread and needs to terminate in less than 1 ms. Any sub-task
* requiring more time shall use background workers.
*
* It is important that the whole 5.3.5.4 section is executed in a single procedure step. This guarantees that the stack
* will not run other functions between the steps, like SR, PRACH, etc.
*
*/
srslte::proc_outcome_t rrc::ho_proc::init(const asn1::rrc::rrc_conn_recfg_s& rrc_reconf)
{
Info("Starting...\n");
@ -1376,12 +1396,103 @@ srslte::proc_outcome_t rrc::ho_proc::init(const asn1::rrc::rrc_conn_recfg_s& rrc
rrc_ptr->mac->get_rntis(&uernti);
ho_src_rnti = uernti.crnti;
// Section 5.3.5.4. The implementation of the procedure follows in function step()
// Section 5.3.5.4
rrc_ptr->t310.stop();
rrc_ptr->t304.set(mob_ctrl_info->t304.to_number(), [this](uint32_t tid) { rrc_ptr->timer_expired(tid); });
rrc_ptr->t304.run();
state = launch_phy_cell_select;
// starting at start synchronising to the DL of the target PCell
Info("Starting cell selection of target cell PCI=%d EARFCN=%d\n", target_cell.pci, target_cell.earfcn);
if (not rrc_ptr->phy_ctrl->start_cell_select(target_cell, rrc_ptr->ho_handler)) {
Error("Failed to launch the selection of target cell PCI=%d EARFCN=%d\n", target_cell.pci, target_cell.earfcn);
return proc_outcome_t::error;
}
// reset MAC
rrc_ptr->mac->reset();
// Reestablish PDCP/RLC
rrc_ptr->pdcp->reestablish();
rrc_ptr->rlc->reestablish();
// configure lower layers to consider the SCell(s), if configured, to be in deactivated state;
rrc_ptr->phy->set_activation_deactivation_scell(0);
// apply the value of the newUE-Identity as the C-RNTI;
rrc_ptr->mac->set_ho_rnti(recfg_r8.mob_ctrl_info.new_ue_id.to_number(), recfg_r8.mob_ctrl_info.target_pci);
// perform radio configuration when fullConfig is enabled
if (recfg_r8.non_crit_ext.non_crit_ext.full_cfg_r9_present) {
Error("fullConfig section was present but is not supported. Ignoring it.\n");
}
// configure lower layers in accordance with the received radioResourceConfigCommon
// Apply common config, but do not send to lower layers if Dedicated is present (to avoid sending twice)
rrc_ptr->apply_rr_config_common(&recfg_r8.mob_ctrl_info.rr_cfg_common, !recfg_r8.rr_cfg_ded_present);
// configure lower layers in accordance with any additional fields, not covered in the previous, if included in the
// received mobilityControlInfo
if (recfg_r8.mob_ctrl_info.rach_cfg_ded_present) {
Info("Configuring RACH dedicated configuration with preamble_idx=%d, mask_idx=%d\n",
recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_preamb_idx,
recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_prach_mask_idx);
rrc_ptr->mac->set_rach_ded_cfg(recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_preamb_idx,
recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_prach_mask_idx);
}
// if the RRCConnectionReconfiguration message includes the radioResourceConfigDedicated
if (recfg_r8.rr_cfg_ded_present) {
// Note: Disable SR config until RA completion
rrc_ptr->apply_rr_config_dedicated(&recfg_r8.rr_cfg_ded, true);
}
// Security procedure
int ncc = -1;
if (recfg_r8.security_cfg_ho_present) {
auto& sec_intralte = recfg_r8.security_cfg_ho.handov_type.intra_lte();
ncc = sec_intralte.next_hop_chaining_count;
if (sec_intralte.key_change_ind) {
// update Kenb based on fresh Kasme taken from previous successful NAS SMC
rrc_ptr->generate_as_keys();
}
if (sec_intralte.security_algorithm_cfg_present) {
rrc_ptr->sec_cfg.cipher_algo =
(srslte::CIPHERING_ALGORITHM_ID_ENUM)sec_intralte.security_algorithm_cfg.ciphering_algorithm.to_number();
rrc_ptr->sec_cfg.integ_algo =
(srslte::INTEGRITY_ALGORITHM_ID_ENUM)sec_intralte.security_algorithm_cfg.integrity_prot_algorithm.to_number();
Info("Changed Ciphering to %s and Integrity to %s\n",
srslte::ciphering_algorithm_id_text[rrc_ptr->sec_cfg.cipher_algo],
srslte::integrity_algorithm_id_text[rrc_ptr->sec_cfg.integ_algo]);
}
}
rrc_ptr->usim->generate_as_keys_ho(recfg_r8.mob_ctrl_info.target_pci, target_earfcn, ncc, &rrc_ptr->sec_cfg);
rrc_ptr->pdcp->config_security_all(rrc_ptr->sec_cfg);
// perform the measurement related actions as specified in 5.5.6.1;
rrc_ptr->measurements->ho_reest_actions(ho_src_cell.get_earfcn(), target_earfcn);
// if the RRCConnectionReconfiguration message includes the measConfig:
if (not rrc_ptr->measurements->parse_meas_config(&recfg_r8, true, ho_src_cell.get_earfcn())) {
Error("Parsing measurementConfig. TODO: Send ReconfigurationReject\n");
return proc_outcome_t::error;
}
// Have RRCReconfComplete message ready when Msg3 is sent
rrc_ptr->send_rrc_con_reconfig_complete();
// SCell addition/removal can take some time to compute. Enqueue in a background task and do it in the end.
rrc_ptr->apply_scell_config(&recfg_r8);
Info("Finished HO configuration. Waiting PHY to synchronize with target cell\n");
state = wait_phy_cell_select_complete;
return proc_outcome_t::yield;
}
srslte::proc_outcome_t rrc::ho_proc::step()
{
return proc_outcome_t::yield;
}
@ -1400,107 +1511,14 @@ srslte::proc_outcome_t rrc::ho_proc::react(const bool& cs_ret)
return proc_outcome_t::error;
}
rrc_ptr->set_serving_cell(target_cell, false);
// Extract and apply scell config if any
rrc_ptr->task_sched.enqueue_background_task([this](uint32_t wid) {
rrc_ptr->apply_scell_config(&recfg_r8);
rrc_ptr->task_sched.notify_background_task_result([this]() {
if (recfg_r8.mob_ctrl_info.rach_cfg_ded_present) {
Info("Starting non-contention based RA with preamble_idx=%d, mask_idx=%d\n",
recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_preamb_idx,
recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_prach_mask_idx);
rrc_ptr->mac->start_noncont_ho(recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_preamb_idx,
recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_prach_mask_idx);
} else {
Info("Starting contention-based RA\n");
rrc_ptr->mac->start_cont_ho();
}
int ncc = -1;
if (recfg_r8.security_cfg_ho_present) {
auto& sec_intralte = recfg_r8.security_cfg_ho.handov_type.intra_lte();
ncc = sec_intralte.next_hop_chaining_count;
if (sec_intralte.key_change_ind) {
// update Kenb based on fresh Kasme taken from previous successful NAS SMC
rrc_ptr->generate_as_keys();
}
if (sec_intralte.security_algorithm_cfg_present) {
rrc_ptr->sec_cfg.cipher_algo =
(srslte::CIPHERING_ALGORITHM_ID_ENUM)sec_intralte.security_algorithm_cfg.ciphering_algorithm.to_number();
rrc_ptr->sec_cfg.integ_algo = (srslte::INTEGRITY_ALGORITHM_ID_ENUM)
sec_intralte.security_algorithm_cfg.integrity_prot_algorithm.to_number();
Info("Changed Ciphering to %s and Integrity to %s\n",
srslte::ciphering_algorithm_id_text[rrc_ptr->sec_cfg.cipher_algo],
srslte::integrity_algorithm_id_text[rrc_ptr->sec_cfg.integ_algo]);
}
}
rrc_ptr->usim->generate_as_keys_ho(
recfg_r8.mob_ctrl_info.target_pci, rrc_ptr->meas_cells.serving_cell().get_earfcn(), ncc, &rrc_ptr->sec_cfg);
Info("PHY has synchronized with target cell. Waiting Random Access to complete\n");
rrc_ptr->pdcp->config_security_all(rrc_ptr->sec_cfg);
rrc_ptr->set_serving_cell(target_cell, false);
// Have RRCReconfComplete message ready when Msg3 is sent
rrc_ptr->send_rrc_con_reconfig_complete();
});
});
state = wait_ra_completion;
return proc_outcome_t::yield;
}
srslte::proc_outcome_t rrc::ho_proc::step()
{
if (rrc_ptr->state != RRC_STATE_CONNECTED) {
Info("HO interrupted, since RRC is no longer in connected state\n");
return srslte::proc_outcome_t::error;
}
if (state == launch_phy_cell_select) {
// Reset/Reestablish stack
rrc_ptr->pdcp->reestablish();
rrc_ptr->rlc->reestablish();
rrc_ptr->mac->wait_uplink();
rrc_ptr->mac->clear_rntis();
rrc_ptr->mac->reset();
rrc_ptr->phy->reset();
// configure lower layers to consider the SCell(s), if configured, to be in deactivated state;
rrc_ptr->phy->set_activation_deactivation_scell(0);
// Todo: perform radio configuration when fullConfig is enabled
// apply the value of the newUE-Identity as the C-RNTI;
rrc_ptr->mac->set_ho_rnti(recfg_r8.mob_ctrl_info.new_ue_id.to_number(), recfg_r8.mob_ctrl_info.target_pci);
// Apply common config, but do not send to lower layers if Dedicated is present (to avoid sending twice)
rrc_ptr->apply_rr_config_common(&recfg_r8.mob_ctrl_info.rr_cfg_common, !recfg_r8.rr_cfg_ded_present);
if (recfg_r8.rr_cfg_ded_present) {
// Note: Disable SR config until RA completion
rrc_ptr->apply_rr_config_dedicated(&recfg_r8.rr_cfg_ded, true);
}
// if the RRCConnectionReconfiguration message includes the measConfig:
if (not rrc_ptr->measurements->parse_meas_config(&recfg_r8, true, ho_src_cell.get_earfcn())) {
Error("Parsing measurementConfig. TODO: Send ReconfigurationReject\n");
return proc_outcome_t::error;
}
// perform the measurement related actions as specified in 5.5.6.1;
rrc_ptr->measurements->ho_reest_actions(ho_src_cell.get_earfcn(), rrc_ptr->get_serving_cell()->get_earfcn());
Info("Starting cell selection of target cell PCI=%d on EARFCN=%d\n", target_cell.pci, target_cell.earfcn);
if (not rrc_ptr->phy_ctrl->start_cell_select(target_cell, rrc_ptr->ho_handler)) {
Error("Failed to launch the selection of target cell PCI=%d on EARFCN=%d\n", target_cell.pci, target_cell.earfcn);
return proc_outcome_t::error;
}
state = wait_phy_cell_select_complete;
}
return proc_outcome_t::yield;
}
srslte::proc_outcome_t rrc::ho_proc::react(t304_expiry ev)
{
Info("HO preparation timed out. Reverting RRC security config from source cell.\n");
@ -1521,6 +1539,8 @@ srslte::proc_outcome_t rrc::ho_proc::react(ra_completed_ev ev)
}
if (ev.success) {
Info("Random Access completed. Applying final configuration and finishing procedure\n");
// TS 36.331, sec. 5.3.5.4, last "1>"
rrc_ptr->t304.stop();
rrc_ptr->apply_rr_config_dedicated_on_ho_complete(recfg_r8.rr_cfg_ded);

@ -46,8 +46,9 @@ ue_stack_lte::ue_stack_lte() :
task_sched(512, 2, 64),
tti_tprof("tti_tprof", "STCK", TTI_STAT_PERIOD)
{
ue_task_queue = task_sched.make_task_queue();
gw_queue_id = task_sched.make_task_queue();
ue_task_queue = task_sched.make_task_queue();
gw_queue_id = task_sched.make_task_queue();
cfg_task_queue = task_sched.make_task_queue();
// sync_queue is added in init()
}
@ -250,6 +251,30 @@ void ue_stack_lte::write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu)
}
}
/********************
* PHY Interface
*******************/
void ue_stack_lte::cell_search_complete(cell_search_ret_t ret, phy_cell_t found_cell)
{
cfg_task_queue.push([this, ret, found_cell]() { rrc.cell_search_complete(ret, found_cell); });
}
void ue_stack_lte::cell_select_complete(bool status)
{
cfg_task_queue.push([this, status]() { rrc.cell_select_complete(status); });
}
void ue_stack_lte::set_config_complete(bool status)
{
cfg_task_queue.push([this, status]() { rrc.set_config_complete(status); });
}
void ue_stack_lte::set_scell_complete(bool status)
{
cfg_task_queue.push([this, status]() { rrc.set_scell_complete(status); });
}
/********************
* SYNC Interface
*******************/

@ -75,6 +75,12 @@ public:
uint32_t get_received_bytes() { return received_bytes; }
void disable_read() { read_enable = false; }
void reset_queues()
{
for (auto& q : ul_queues) {
q.second = 0;
}
}
private:
bool read_enable = true;
@ -321,7 +327,7 @@ private:
class rrc_dummy : public rrc_interface_mac
{
public:
void ho_ra_completed() { ho_finish_successful = true; }
void ra_completed() { ho_finish_successful = true; }
void release_pucch_srs() { printf("%s\n", __FUNCTION__); }
void run_tti(uint32_t tti) { printf("%s\n", __FUNCTION__); }
void ra_problem() { rach_problem++; }
@ -1274,11 +1280,12 @@ int run_mac_ra_test(struct ra_test test, mac* mac, phy_dummy* phy, uint32_t* tti
break;
}
// Request Msg3 (re)-transmission
for (uint32_t i = 0; i < test.nof_msg3_retx + 1; i++) {
// Step to contention resolution. Make sure timer does not start until Msg3 is transmitted
// and restarts on every retx
for (int j = 0; j < test.rach_cfg.ra_supervision_info.mac_contention_resolution_timer.to_number() - 1; j++) {
for (int k = 0; k < test.rach_cfg.ra_supervision_info.mac_contention_resolution_timer.to_number() - 1; k++) {
stack->run_tti(tti);
TESTASSERT(mac->get_dl_sched_rnti(tti) == (test.crnti ? test.crnti : test.temp_rnti));
tti++;
@ -1300,7 +1307,7 @@ int run_mac_ra_test(struct ra_test test, mac* mac, phy_dummy* phy, uint32_t* tti
break;
}
for (int i = 0; i < test.rach_cfg.ra_supervision_info.mac_contention_resolution_timer.to_number() - 1; i++) {
for (int k = 0; k < test.rach_cfg.ra_supervision_info.mac_contention_resolution_timer.to_number() - 1; k++) {
stack->run_tti(tti);
TESTASSERT(mac->get_dl_sched_rnti(tti) == (test.crnti ? test.crnti : test.temp_rnti));
tti++;
@ -1319,7 +1326,7 @@ int run_mac_ra_test(struct ra_test test, mac* mac, phy_dummy* phy, uint32_t* tti
return -1;
}
break;
} else if ((int)i == test.rach_cfg.ra_supervision_info.mac_contention_resolution_timer.to_number() - 2) {
} else if ((int)k == test.rach_cfg.ra_supervision_info.mac_contention_resolution_timer.to_number() - 2) {
new_prach = true;
}
} else {
@ -1507,9 +1514,10 @@ int mac_random_access_test()
// In this case we will let the procedure expire the Contention Resolution window and make sure
// and RRC HO fail signal is sent to RRC.
mac_log->info("\n=========== Test %d =============\n", test_id++);
rrc.ho_finish_successful = false;
phy.set_prach_tti(tti + phy.prach_delay);
phy.set_crnti(0);
mac.start_cont_ho();
rlc.write_sdu(0, 6); // Add new UL-CCCH with Msg3 (DRB SDU still buffered)
stack.run_tti(tti++);
my_test.nof_prachs = rach_cfg.ra_supervision_info.preamb_trans_max.to_number();
my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate
@ -1519,15 +1527,22 @@ int mac_random_access_test()
my_test.send_valid_ul_grant = false;
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti, &stack));
TESTASSERT(!rrc.ho_finish_successful);
TESTASSERT(rrc.rach_problem == 2);
// Test 8: Test Contention based Random Access. Same as above but we let the procedure finish successfully.
mac_log->info("\n=========== Test %d =============\n", test_id++);
rrc.ho_finish_successful = false;
// Reset queue to make sure BSR retriggers a SR
rlc.reset_queues();
stack.run_tti(tti++);
rlc.write_sdu(0, 6); // Add new UL-CCCH with Msg3 (DRB SDU still buffered)
phy.set_prach_tti(tti + phy.prach_delay);
phy.set_crnti(0);
mac.start_cont_ho();
stack.run_tti(tti++);
my_test.nof_prachs = 1;
my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate
my_test.nof_msg3_retx = 0;
my_test.temp_rnti++;
my_test.msg4_valid_conres = true;
my_test.msg4_enable = true;
my_test.send_valid_ul_grant = true;
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti, &stack));
TESTASSERT(rrc.ho_finish_successful);
@ -1537,12 +1552,16 @@ int mac_random_access_test()
// In this first test, no RAR is received and RA procedure fails
mac_log->info("\n=========== Test %d =============\n", test_id++);
rrc.ho_finish_successful = false;
// Reset queue to make sure BSR retriggers a SR
my_test.preamble_idx = 3;
mac.set_rach_ded_cfg(my_test.preamble_idx, 0);
stack.run_pending_tasks();
rlc.reset_queues();
stack.run_tti(tti++);
rlc.write_sdu(0, 6); // Add new UL-CCCH with Msg3 (DRB SDU still buffered)
phy.set_prach_tti(tti + phy.prach_delay);
stack.run_tti(tti++);
phy.set_crnti(0);
my_test.preamble_idx = 3;
mac.start_noncont_ho(my_test.preamble_idx, 0);
stack.run_pending_tasks();
my_test.nof_prachs = rach_cfg.ra_supervision_info.preamb_trans_max.to_number();
my_test.rar_nof_invalid_rapid = rach_cfg.ra_supervision_info.ra_resp_win_size.to_number();
my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate
@ -1553,12 +1572,15 @@ int mac_random_access_test()
// Test 10: Test non-Contention based HO. Used in HO but preamble is given by the network. We check that
// the procedure is considered successful without waiting for contention
mac_log->info("\n=========== Test %d =============\n", test_id++);
my_test.preamble_idx = 3;
mac.set_rach_ded_cfg(my_test.preamble_idx, 0);
stack.run_pending_tasks();
rlc.reset_queues();
stack.run_tti(tti++);
rlc.write_sdu(0, 6); // Add new UL-CCCH with Msg3 (DRB SDU still buffered)
phy.set_prach_tti(tti + phy.prach_delay);
stack.run_tti(tti++);
phy.set_crnti(0);
my_test.preamble_idx = 3;
mac.start_noncont_ho(my_test.preamble_idx, 0);
stack.run_pending_tasks();
my_test.nof_prachs = 1;
my_test.rar_nof_invalid_rapid = 0;
my_test.check_ra_successful = true;

@ -269,6 +269,11 @@ public:
}
}
void cell_search_complete(cell_search_ret_t ret, srsue::phy_cell_t found_cell) override {}
void cell_select_complete(bool status) override {}
void set_config_complete(bool status) override {}
void set_scell_complete(bool status) override {}
bool print_stats()
{
printf("\n-- Statistics:\n");

@ -79,6 +79,10 @@ private:
CALLBACK(new_grant_ul)
CALLBACK(new_grant_dl)
CALLBACK(run_tti)
CALLBACK(cell_search)
CALLBACK(cell_select)
CALLBACK(config)
CALLBACK(scell)
public:
// Local test access methods
@ -116,6 +120,32 @@ private:
notify_run_tti();
log_h.debug("Run TTI %d\n", tti);
}
void cell_search_complete(cell_search_ret_t ret, srsue::phy_cell_t found_cell) override
{
cell_search_ret = ret;
last_found_cell = found_cell;
notify_cell_search();
}
void cell_select_complete(bool status) override
{
notify_cell_select();
last_cell_select = status;
}
void set_config_complete(bool status) override
{
notify_config();
last_config = status;
}
void set_scell_complete(bool status) override
{
notify_scell();
last_scell = status;
}
cell_search_ret_t cell_search_ret = {};
srsue::phy_cell_t last_found_cell = {};
bool last_cell_select = false, last_config = false, last_scell = false;
};
class dummy_radio : public srslte::radio_interface_phy
@ -399,7 +429,7 @@ public:
phy->set_crnti(rnti);
// Set PHY configuration
phy->set_config(phy_cfg, 0, 0, nullptr);
phy->set_config(phy_cfg, 0);
}
void run_thread() override
@ -506,23 +536,30 @@ int main(int argc, char** argv)
phy_test->start();
// 1. Cell search
srsue::phy_interface_rrc_lte::phy_cell_t phy_cell;
auto cell_search_res = phy_test->get_phy_interface_rrc()->cell_search(&phy_cell);
TESTASSERT(cell_search_res.found == srsue::phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND);
TESTASSERT(phy_test->get_phy_interface_rrc()->cell_search());
TESTASSERT(phy_test->get_stack()->wait_cell_search(default_timeout));
TESTASSERT(phy_test->get_stack()->cell_search_ret.found ==
srsue::rrc_interface_phy_lte::cell_search_ret_t::CELL_FOUND);
// 2. Cell select
phy_test->get_phy_interface_rrc()->cell_select(&phy_cell);
srsue::phy_cell_t phy_cell = phy_test->get_stack()->last_found_cell;
TESTASSERT(phy_test->get_phy_interface_rrc()->cell_select(phy_cell));
TESTASSERT(phy_test->get_stack()->wait_cell_select(default_timeout));
TESTASSERT(phy_test->get_stack()->wait_in_sync(default_timeout));
TESTASSERT(phy_test->get_stack()->wait_new_phy_meas(default_timeout));
// 3. Transmit PRACH
phy_test->get_phy_interface_mac()->configure_prach_params();
srslte::phy_cfg_t phy_cfg = {};
phy_cfg.set_defaults();
phy_test->get_phy_interface_rrc()->set_config(phy_cfg, 0);
TESTASSERT(phy_test->get_stack()->wait_config(default_timeout));
// phy_test->get_phy_interface_mac()->configure_prach_params();
phy_test->get_phy_interface_mac()->prach_send(0, -1, 0.0f);
TESTASSERT(phy_test->get_radio()->wait_tx(default_timeout, false));
// 4. Configure RNTI with PUCCH and check transmission
uint16_t rnti = 0x3c;
srslte::phy_cfg_t phy_cfg = {};
uint16_t rnti = 0x3c;
phy_cfg = {};
phy_cfg.set_defaults();
phy_cfg.dl_cfg.cqi_report.periodic_mode = SRSLTE_CQI_MODE_12;
phy_cfg.dl_cfg.cqi_report.periodic_configured = true;

@ -65,10 +65,8 @@ public:
// phy_interface_rrc_lte
void enable_pregen_signals(bool enable) override;
void set_activation_deactivation_scell(uint32_t cmd) override;
void set_config(srslte::phy_cfg_t& config,
uint32_t cc_idx = 0,
uint32_t earfcn = 0,
srslte_cell_t* cell_info = nullptr) override;
bool set_config(srslte::phy_cfg_t config, uint32_t cc_idx = 0) override;
bool set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) override;
void set_config_tdd(srslte_tdd_config_t& tdd_config) override;
void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) override{};
void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) override{};
@ -81,13 +79,11 @@ public:
void set_mch_period_stop(uint32_t stop) override{};
// Cell search and selection procedures
cell_search_ret_t cell_search(phy_cell_t* found_cell) override;
bool cell_select(const phy_cell_t* cell) override;
bool cell_is_camping() override;
void reset() override;
bool cell_search() override;
bool cell_select(phy_cell_t cell) override;
bool cell_is_camping() override;
// phy_interface_mac_lte
void configure_prach_params() override;
void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec) override;
prach_info_t prach_get_info() override;
void sr_send() override;
@ -128,8 +124,8 @@ private:
srslte::phy_cfg_t phy_cfg = {};
uint32_t current_tti = 0;
uint32_t cc_idx = 0;
uint32_t current_tti = 0;
uint32_t cc_idx = 0;
int prach_tti_tx = -1;
@ -146,4 +142,4 @@ private:
} // namespace srsue
#endif
#endif

@ -80,27 +80,35 @@ void lte_ttcn3_phy::set_activation_deactivation_scell(uint32_t cmd)
log.debug("%s not implemented.\n", __FUNCTION__);
}
void lte_ttcn3_phy::set_config(srslte::phy_cfg_t& config, uint32_t cc_idx, uint32_t earfcn, srslte_cell_t* cell_info)
bool lte_ttcn3_phy::set_config(srslte::phy_cfg_t config, uint32_t cc_idx_)
{
log.debug("%s not implemented.\n", __FUNCTION__);
return true;
}
bool lte_ttcn3_phy::set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn)
{
log.debug("%s not implemented.\n", __FUNCTION__);
return true;
}
// Measurements interface
void lte_ttcn3_phy::meas_stop(){};
void lte_ttcn3_phy::meas_stop() {}
// Cell search and selection procedures
// Note that in contrast to a real PHY, we have visibility of all existing cells
// configured by the SS, including the ones that we should not even detect because
// their power is too weak. The cell search should only report the cells that
// are actually visible though.
phy_interface_rrc_lte::cell_search_ret_t lte_ttcn3_phy::cell_search(phy_cell_t* found_cell)
bool lte_ttcn3_phy::cell_search()
{
std::lock_guard<std::mutex> lock(mutex);
log.info("Running cell search in PHY\n");
cell_search_ret_t ret = {};
ret.found = cell_search_ret_t::CELL_NOT_FOUND;
rrc_interface_phy_lte::cell_search_ret_t ret = {};
ret.found = rrc_interface_phy_lte::cell_search_ret_t::CELL_NOT_FOUND;
phy_cell_t found_cell = {};
if (not cells.empty() && cell_idx < cells.size()) {
// only find suitable cells
@ -109,11 +117,9 @@ phy_interface_rrc_lte::cell_search_ret_t lte_ttcn3_phy::cell_search(phy_cell_t*
cells[cell_idx].earfcn,
cells[cell_idx].info.id,
cells[cell_idx].power);
if (found_cell) {
found_cell->earfcn = cells[cell_idx].earfcn;
found_cell->pci = cells[cell_idx].info.id;
}
ret.found = cell_search_ret_t::CELL_FOUND;
found_cell.earfcn = cells[cell_idx].earfcn;
found_cell.pci = cells[cell_idx].info.id;
ret.found = rrc_interface_phy_lte::cell_search_ret_t::CELL_FOUND;
}
// advance index
@ -121,41 +127,44 @@ phy_interface_rrc_lte::cell_search_ret_t lte_ttcn3_phy::cell_search(phy_cell_t*
if (cell_idx < cells.size()) {
// more cells will be reported
ret.last_freq = cell_search_ret_t::MORE_FREQS;
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::MORE_FREQS;
} else {
// all available cells have been reported, reset cell index
ret.last_freq = cell_search_ret_t::NO_MORE_FREQS;
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS;
cell_idx = 0;
}
} else {
log.warning("No cells configured yet.\n");
}
return ret;
};
stack->cell_search_complete(ret, found_cell);
return true;
}
bool lte_ttcn3_phy::cell_select(const phy_cell_t* rrc_cell)
bool lte_ttcn3_phy::cell_select(phy_cell_t rrc_cell)
{
// try to find RRC cell in current cell map
for (auto& cell : cells) {
if (cell.info.id == rrc_cell->pci && cell.earfcn == rrc_cell->earfcn) {
if (cell.info.id == rrc_cell.pci && cell.earfcn == rrc_cell.earfcn) {
if (cell.power >= SUITABLE_CELL_RS_EPRE) {
pcell = cell;
pcell_set = true;
syssim->select_cell(pcell.info);
log.info("Select PCell with %.2f on PCI=%d on EARFCN=%d.\n", cell.power, rrc_cell->pci, rrc_cell->earfcn);
log.info("Select PCell with %.2f on PCI=%d on EARFCN=%d.\n", cell.power, rrc_cell.pci, rrc_cell.earfcn);
} else {
pcell_set = false;
log.error("Power of selected cell too low (%.2f < %.2f)\n", cell.power, SUITABLE_CELL_RS_EPRE);
}
return pcell_set;
stack->cell_select_complete(pcell_set);
return true;
}
}
log.error("Couldn't find RRC cell with PCI=%d on EARFCN=%d in cell map.\n", rrc_cell->pci, rrc_cell->earfcn);
log.error("Couldn't find RRC cell with PCI=%d on EARFCN=%d in cell map.\n", rrc_cell.pci, rrc_cell.earfcn);
return false;
};
}
bool lte_ttcn3_phy::cell_is_camping()
{
@ -164,18 +173,9 @@ bool lte_ttcn3_phy::cell_is_camping()
return (pcell.power >= SUITABLE_CELL_RS_EPRE);
}
return false;
};
void lte_ttcn3_phy::reset()
{
log.debug("%s not implemented.\n", __FUNCTION__);
};
}
// The interface for MAC (called from Stack thread context)
void lte_ttcn3_phy::configure_prach_params()
{
log.debug("%s not implemented.\n", __FUNCTION__);
};
void lte_ttcn3_phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec)
{

@ -605,7 +605,7 @@ void ttcn3_syssim::send_rar(uint32_t preamble_index)
// Internal function called from main thread
void ttcn3_syssim::send_msg3_grant()
{
log->info("Sending Msg3 grant for C-RNTI=%d\n", cells[pcell_idx]->config.crnti);
log->info("Sending Msg3 grant for C-RNTI=0x%x\n", cells[pcell_idx]->config.crnti);
mac_interface_phy_lte::mac_grant_ul_t ul_grant = {};
ul_grant.tti_tx = (tti + 3) % 10240;

@ -43,43 +43,20 @@ public:
}
// Not implemented methods
void set_config(srslte::phy_cfg_t& config,
uint32_t cc_idx = 0,
uint32_t earfcn = 0,
srslte_cell_t* cell_info = nullptr) override
{}
void set_config_tdd(srslte_tdd_config_t& tdd_config) override {}
void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) override {}
void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) override {}
void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) override {}
cell_search_ret_t cell_search(phy_cell_t* cell) override
bool set_config(srslte::phy_cfg_t config, uint32_t cc_idx) override { return true; }
bool set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) override { return true; }
void set_config_tdd(srslte_tdd_config_t& tdd_config) override {}
void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) override {}
void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) override {}
void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) override {}
bool cell_search() override { return true; }
bool cell_is_camping() override { return false; }
void set_activation_deactivation_scell(uint32_t cmd) override {}
bool cell_select(phy_cell_t cell) override
{
*cell = cell_search_res_cell;
cell_select_ret = true;
return cell_search_res_ret;
last_selected_cell = cell;
return true;
}
bool cell_is_camping() override { return false; }
void set_activation_deactivation_scell(uint32_t cmd) override {}
bool cell_select(const phy_cell_t* cell = nullptr) override
{
last_selected_cell = *cell;
bool ret = cell_select_ret;
if (return_to_true) {
cell_select_ret = true;
}
return ret;
}
void set_cell_select_ret(bool cell_select_ret_, bool return_to_true_)
{
cell_select_ret = cell_select_ret_;
return_to_true = return_to_true_;
}
void set_cell_search_result(phy_cell_t cell, cell_search_ret_t ret)
{
cell_search_res_cell = cell;
cell_search_res_ret = ret;
}
void reset() override {}
void enable_pregen_signals(bool enable) override {}
void set_cells_to_meas(uint32_t earfcn, const std::set<uint32_t>& pci) override
@ -120,17 +97,14 @@ public:
}
}
phy_interface_rrc_lte::phy_cell_t last_selected_cell = {};
phy_cell_t last_selected_cell = {};
private:
bool meas_reset_called = false;
std::set<uint32_t> freqs_started;
std::map<uint32_t, std::set<uint32_t> > cells_started;
uint32_t serving_pci = 0;
uint32_t serving_earfcn = 0;
bool cell_select_ret = true;
bool return_to_true = true;
cell_search_ret_t cell_search_res_ret = {};
phy_cell_t cell_search_res_cell = {};
};
class nas_test : public srsue::nas
@ -195,7 +169,7 @@ private:
class rrc_test : public rrc
{
srsue::stack_test_dummy* stack = nullptr;
stack_test_dummy* stack = nullptr;
public:
rrc_test(srslte::log_ref log_, stack_test_dummy* stack_) : rrc(stack_, &stack_->task_sched), stack(stack_)
@ -203,16 +177,8 @@ public:
pool = srslte::byte_buffer_pool::get_instance();
nastest = std::unique_ptr<nas_test>(new nas_test(&stack->task_sched));
pdcptest = std::unique_ptr<pdcp_test>(new pdcp_test(log_->get_service_name().c_str(), &stack->task_sched));
};
void init()
{
rrc::init(&phytest, nullptr, nullptr, pdcptest.get(), nastest.get(), nullptr, nullptr, {});
phy_interface_rrc_lte::phy_cell_t cell_search_cell = {};
phy_interface_rrc_lte::cell_search_ret_t cell_search_ret = {};
cell_search_ret.found = srsue::phy_interface_rrc_lte::cell_search_ret_t::CELL_NOT_FOUND;
cell_search_ret.last_freq = srsue::phy_interface_rrc_lte::cell_search_ret_t::NO_MORE_FREQS;
phytest.set_cell_search_result(cell_search_cell, cell_search_ret);
}
void init() { rrc::init(&phytest, nullptr, nullptr, pdcptest.get(), nastest.get(), nullptr, nullptr, {}); }
void run_tti(uint32_t tti_)
{
@ -296,6 +262,7 @@ public:
}
using rrc::has_neighbour_cell;
using rrc::is_serving_cell;
using rrc::start_cell_select;
bool get_meas_res(meas_results_s& meas_res) { return pdcptest->get_meas_res(meas_res); }
@ -362,7 +329,7 @@ int cell_select_test()
rrctest.connect();
rrctest.add_neighbour_cell(1, 1, 2.0);
rrctest.add_neighbour_cell(2, 2, 1.0);
rrctest.add_neighbour_cell(2, 2, 1.1);
rrctest.add_neighbour_cell(3, 2, 1.0);
rrctest.set_serving_cell(1, 1);
TESTASSERT(not rrctest.has_neighbour_cell(1, 1));
@ -371,29 +338,40 @@ int cell_select_test()
// Start cell selection procedure. The RRC will start with strongest cell
TESTASSERT(rrctest.start_cell_select() == SRSLTE_SUCCESS);
rrctest.phytest.set_cell_select_ret(false, true); // failed to set serving cell
TESTASSERT(rrctest.phytest.last_selected_cell.earfcn == 1);
TESTASSERT(rrctest.phytest.last_selected_cell.pci == 1);
stack.run_pending_tasks();
rrctest.cell_select_complete(false); // it will fail to select pci=1
stack.run_pending_tasks();
rrctest.cell_select_complete(true); // it will select pci=2
rrctest.in_sync();
stack.run_pending_tasks(); // it will select pci=2
TESTASSERT(rrctest.phytest.last_selected_cell.earfcn == 2);
TESTASSERT(rrctest.phytest.last_selected_cell.pci == 2);
TESTASSERT(rrctest.has_neighbour_cell(1, 1));
TESTASSERT(rrctest.has_neighbour_cell(2, 3));
TESTASSERT(!rrctest.has_neighbour_cell(2, 2));
rrctest.in_sync();
stack.run_pending_tasks();
TESTASSERT(not rrctest.has_neighbour_cell(2, 2));
// Cell Selection fails, make sure it goes to Cell Search
TESTASSERT(rrctest.start_cell_select() == SRSLTE_SUCCESS);
phy_interface_rrc_lte::phy_cell_t cell_search_cell = {};
phy_interface_rrc_lte::cell_search_ret_t cell_search_ret = {};
phy_cell_t cell_search_cell = {};
rrc_interface_phy_lte::cell_search_ret_t cell_search_ret = {};
cell_search_cell.pci = 5;
cell_search_cell.earfcn = 5;
cell_search_ret.found = srsue::phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND;
rrctest.phytest.set_cell_search_result(cell_search_cell, cell_search_ret);
rrctest.phytest.set_cell_select_ret(false, false); // failed to set serving cell
cell_search_ret.found = srsue::rrc_interface_phy_lte::cell_search_ret_t::CELL_FOUND;
TESTASSERT(rrctest.start_cell_select() == SRSLTE_SUCCESS);
rrctest.cell_select_complete(false); // it will fail to select pci=2
stack.run_pending_tasks();
rrctest.cell_select_complete(false); // it will fail to select pci=3
stack.run_pending_tasks();
rrctest.cell_search_complete(cell_search_ret, cell_search_cell);
stack.run_pending_tasks();
rrctest.in_sync();
TESTASSERT(rrctest.phytest.last_selected_cell.earfcn == 5);
TESTASSERT(rrctest.phytest.last_selected_cell.pci == 5);
rrctest.cell_select_complete(true);
rrctest.in_sync();
stack.run_pending_tasks();
TESTASSERT(not rrctest.has_neighbour_cell(5, 5));
TESTASSERT(rrctest.is_serving_cell(5, 5));
}
return SRSLTE_SUCCESS;

@ -59,7 +59,7 @@ struct cell_select_result_test {
// start a new cell selection right away
if (counter++ < 1) {
phy_interface_rrc_lte::phy_cell_t new_cell;
phy_cell_t new_cell;
new_cell.pci = 3;
new_cell.earfcn = 3400;
phy_ctrl->start_cell_select(new_cell, *this);
@ -100,9 +100,9 @@ int test_phy_ctrl_fsm()
phy_ctrl.out_sync();
TESTASSERT(not phy_ctrl.is_in_sync());
TESTASSERT(phy_ctrl.current_state_name() == "searching_cell");
phy_interface_rrc_lte::cell_search_ret_t cs_ret;
cs_ret.found = phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND;
phy_interface_rrc_lte::phy_cell_t found_cell;
rrc_interface_phy_lte::cell_search_ret_t cs_ret;
cs_ret.found = rrc_interface_phy_lte::cell_search_ret_t::CELL_FOUND;
phy_cell_t found_cell;
found_cell.pci = 1;
found_cell.earfcn = 2;
phy_ctrl.cell_search_completed(cs_ret, found_cell);

Loading…
Cancel
Save