refactor cell param handling and fix SIB transmissions

- move cell specific eNB params to cell list in rr.conf
- make sure DL EARFCN and DL freq can be used to manually overwrite a single cell config
- fix SIB packing and transmission for multi cell configs
- introduce cell list to MAC
- adapt default enb.conf.example and rr.conf.example
This commit is contained in:
Andre Puschmann 2020-03-06 10:58:02 +01:00
parent 4e12405fff
commit 120ad76c63
18 changed files with 235 additions and 212 deletions

View File

@ -296,8 +296,8 @@ public:
* Segmentation happens in this function. RLC PDU is stored in payload. */
virtual int read_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0;
virtual void read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t* payload) = 0;
virtual void read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) = 0;
virtual void read_pdu_bcch_dlsch(const uint8_t cc_idx, const uint32_t sib_index, uint8_t* payload) = 0;
virtual void read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) = 0;
/* MAC calls RLC to push an RLC PDU. This function is called from an independent MAC thread.
* PDU gets placed into the buffer and higher layer thread gets notified. */
@ -371,10 +371,10 @@ public:
class rrc_interface_rlc
{
public:
virtual void read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t* payload) = 0;
virtual void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) = 0;
virtual void max_retx_attempted(uint16_t rnti) = 0;
virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void read_pdu_bcch_dlsch(const uint8_t cc_idx, const uint32_t sib_index, uint8_t* payload) = 0;
virtual void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) = 0;
virtual void max_retx_attempted(uint16_t rnti) = 0;
virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
};
// RRC interface for MAC
@ -389,6 +389,29 @@ public:
virtual bool is_paging_opportunity(uint32_t tti, uint32_t* payload_len) = 0;
};
// SCell configuration
struct scell_cfg_t {
uint32_t cell_id;
bool cross_carrier_sched = false;
uint32_t sched_cell_id;
bool ul_allowed;
};
// Cell/Sector configuration
struct cell_cfg_t {
uint32_t rf_port;
uint32_t cell_id;
uint16_t tac;
uint32_t pci;
uint16_t root_seq_idx;
uint32_t dl_earfcn;
float dl_freq_hz;
uint32_t ul_earfcn;
float ul_freq_hz;
std::vector<scell_cfg_t> scell_list;
};
typedef std::vector<cell_cfg_t> cell_list_t;
// RRC interface for PDCP
class rrc_interface_pdcp
{
@ -482,6 +505,7 @@ typedef struct {
} s1ap_args_t;
typedef struct {
uint32_t nof_prb; ///< Needed to dimension MAC softbuffers for all cells
sched_interface::sched_args_t sched;
int link_failure_nof_err;
} mac_args_t;

View File

@ -6,8 +6,6 @@
# eNB configuration
#
# enb_id: 20-bit eNB identifier.
# cell_id: 8-bit cell identifier.
# tac: 16-bit Tracking Area Code.
# mcc: Mobile Country Code
# mnc: Mobile Network Code
# mme_addr: IP address of MME for S1 connnection
@ -20,9 +18,6 @@
#####################################################################
[enb]
enb_id = 0x19B
cell_id = 0x01
phy_cell_id = 1
tac = 0x0007
mcc = 001
mnc = 01
mme_addr = 127.0.1.100
@ -48,7 +43,7 @@ drb_config = drb.conf
#####################################################################
# RF configuration
#
# dl_earfcn: EARFCN code for DL
# dl_earfcn: EARFCN code for DL (only valid if a single cell is configured in rr.conf)
# tx_gain: Transmit gain (dB).
# rx_gain: Optional receive gain (dB). If disabled, AGC if enabled
#
@ -64,7 +59,7 @@ drb_config = drb.conf
# Default "auto". B210 USRP: 100 samples, bladeRF: 27.
#####################################################################
[rf]
dl_earfcn = 3400
#dl_earfcn = 3400
tx_gain = 80
rx_gain = 40

View File

@ -59,10 +59,10 @@ namespace srsenb {
*******************************************************************************/
struct enb_args_t {
uint32_t dl_earfcn;
uint32_t ul_earfcn;
std::string enb_id;
uint32_t dl_earfcn; // By default the EARFCN from rr.conf's cell list are used but this value can be used for single
// cell eNB
uint32_t n_prb;
uint32_t pci;
uint32_t nof_ports;
uint32_t transmission_mode;
float p_a;

View File

@ -370,6 +370,17 @@ int parse_default_field(T& obj,
return ret;
}
//! Parse required field and return error if field isn't specified
template <typename T, typename Parser = DefaultFieldParser<T> >
int parse_required_field(T& obj, Setting& root, const char* field_name, const Parser& field_parser = {})
{
if (not root.exists(field_name)) {
fprintf(stderr, "PARSER ERROR: Field \"%s\" doesn't exist.\n", field_name);
return -1;
}
return field_parser(obj, root[field_name]);
}
template <typename T>
int parse_bounded_number(T& number, Setting& fieldroot, T num_min, T num_max)
{

View File

@ -42,7 +42,7 @@ public:
mac();
~mac();
bool init(const mac_args_t& args_,
srslte_cell_t* cell,
const cell_list_t& cells_,
phy_interface_stack_lte* phy,
rlc_interface_mac* rlc,
rrc_interface_mac* rrc,
@ -114,7 +114,7 @@ private:
stack_interface_mac_lte* stack = nullptr;
srslte::log* log_h = nullptr;
srslte_cell_t cell = {};
cell_list_t cells = {};
mac_args_t args = {};
// derived from args
@ -137,7 +137,7 @@ private:
int rar_idx,
uint32_t pdu_len,
uint32_t tti);
uint8_t* assemble_si(uint32_t index);
uint8_t* assemble_si(const uint8_t cc_idx, const uint32_t index);
const static int rar_payload_len = 128;
std::vector<srslte::rar_pdu> rar_pdu_msg;

View File

@ -74,13 +74,6 @@ struct meas_cell_cfg_t {
float q_offset;
};
struct scell_cfg_t {
uint32_t cell_id;
bool cross_carrier_sched = false;
uint32_t sched_cell_id;
bool ul_allowed;
};
// neigh measurement Cell info
struct rrc_meas_cfg_t {
std::vector<meas_cell_cfg_t> meas_cells;
@ -92,23 +85,10 @@ struct rrc_meas_cfg_t {
// TODO: Add multiple meas configs
};
// Cell/Sector configuration
struct cell_cfg_t {
uint32_t rf_port;
uint32_t cell_id;
uint16_t tac;
uint32_t pci;
uint16_t root_seq_idx;
uint32_t dl_earfcn;
float dl_freq_hz;
uint32_t ul_earfcn;
float ul_freq_hz;
std::vector<scell_cfg_t> scell_list;
};
#define MAX_NOF_QCI 10
struct rrc_cfg_t {
uint32_t enb_id; ///< Required to pack SIB1
asn1::rrc::sib_type1_s sib1;
asn1::rrc::sib_info_item_c sibs[ASN1_RRC_MAX_SIB];
asn1::rrc::mac_main_cfg_s mac_cnfg;
@ -119,16 +99,14 @@ struct rrc_cfg_t {
rrc_cfg_sr_t sr_cfg;
rrc_cfg_cqi_t cqi_cfg;
rrc_cfg_qci_t qci_cfg[MAX_NOF_QCI];
srslte_cell_t cell;
bool enable_mbsfn;
uint32_t inactivity_timeout_ms;
srslte::CIPHERING_ALGORITHM_ID_ENUM eea_preference_list[srslte::CIPHERING_ALGORITHM_ID_N_ITEMS];
srslte::INTEGRITY_ALGORITHM_ID_ENUM eia_preference_list[srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS];
bool meas_cfg_present = false;
rrc_meas_cfg_t meas_cfg;
std::vector<cell_cfg_t> cell_list;
uint32_t pci; // TODO: add this to srslte_cell_t?
uint32_t dl_earfcn; // TODO: add this to srslte_cell_t?
srslte_cell_t cell;
cell_list_t cell_list;
};
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
@ -148,7 +126,7 @@ public:
rrc();
~rrc();
void init(rrc_cfg_t* cfg,
void init(const rrc_cfg_t& cfg_,
phy_interface_rrc_lte* phy,
mac_interface_rrc* mac,
rlc_interface_rrc* rlc,
@ -170,7 +148,7 @@ public:
bool is_paging_opportunity(uint32_t tti, uint32_t* payload_len) override;
// rrc_interface_rlc
void read_pdu_bcch_dlsch(uint32_t sib_idx, uint8_t* payload) override;
void read_pdu_bcch_dlsch(const uint8_t cc_idx, const uint32_t sib_index, uint8_t* payload) override;
void read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) override;
void max_retx_attempted(uint16_t rnti) override;
@ -390,7 +368,7 @@ private:
std::map<uint16_t, std::unique_ptr<ue> > users; // NOTE: has to have fixed addr
std::map<uint32_t, asn1::s1ap::ue_paging_id_c> pending_paging;
std::vector<srslte::unique_byte_buffer_t> sib_buffer;
std::map<uint8_t, std::vector<srslte::unique_byte_buffer_t> > sib_buffer; ///< Packed SIBs for each CC
void process_release_complete(uint16_t rnti);
void process_rl_failure(uint16_t rnti);

View File

@ -64,7 +64,7 @@ public:
// rlc_interface_mac
int read_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes);
void read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t* payload);
void read_pdu_bcch_dlsch(const uint8_t cc_idx, const uint32_t sib_index, uint8_t* payload);
void write_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes);
void read_pdu_pcch(uint8_t* payload, uint32_t buffer_size);

View File

@ -54,12 +54,12 @@ cell_list =
(
{
// rf_port = 0;
// cell_id = 0x01;
// tac = 0x0001;
// pci = 1;
cell_id = 0x01;
tac = 0x0001;
pci = 1;
// root_seq_idx = 204;
// dl_earfcn = 3400;
// ul_earfcn = 21400;
dl_earfcn = 3400;
ul_earfcn = 21400;
ho_active = false;
// CA cells

View File

@ -651,19 +651,6 @@ int parse_rr(all_args_t* args_, rrc_cfg_t* rrc_cfg_)
p.add_section(&phy_cfg_);
p.add_section(&rrc_cnfg);
// If the cell list is empty, use default values from enb.conf to keep backwards compatibility
if (rrc_cfg_->cell_list.empty()) {
rrc_cfg_->cell_list.resize(1);
cell_cfg_t& cell_cfg = rrc_cfg_->cell_list[0];
cell_cfg.rf_port = 0;
cell_cfg.cell_id = 0;
cell_cfg.tac = args_->stack.s1ap.tac;
cell_cfg.pci = args_->enb.pci;
cell_cfg.root_seq_idx = rrc_cfg_->sibs[1].sib2().rr_cfg_common.prach_cfg.root_seq_idx;
cell_cfg.dl_earfcn = args_->enb.dl_earfcn;
cell_cfg.ul_earfcn = args_->enb.ul_earfcn;
}
return p.parse();
}
@ -672,7 +659,7 @@ static int parse_meas_cell_list(rrc_meas_cfg_t* meas_cfg, Setting& root)
meas_cfg->meas_cells.resize(root.getLength());
for (uint32_t i = 0; i < meas_cfg->meas_cells.size(); ++i) {
meas_cfg->meas_cells[i].earfcn = root[i]["dl_earfcn"];
meas_cfg->meas_cells[i].pci = (unsigned int)root[i]["pci"] % 504;
meas_cfg->meas_cells[i].pci = (unsigned int)root[i]["pci"] % SRSLTE_NUM_PCI;
meas_cfg->meas_cells[i].eci = (unsigned int)root[i]["eci"];
meas_cfg->meas_cells[i].q_offset = 0; // LIBLTE_RRC_Q_OFFSET_RANGE_DB_0; // TODO
// // TODO: TEMP
@ -715,7 +702,6 @@ static int parse_meas_report_desc(rrc_meas_cfg_t* meas_cfg, Setting& root)
static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
{
auto cell_id_parser = [](uint32_t& cell_id, Setting& root) { return parse_bounded_number(cell_id, root, 0u, 255u); };
uint32_t self_cellid = args->stack.s1ap.cell_id & 0xFFu;
rrc_cfg->cell_list.resize(root.getLength());
for (uint32_t n = 0; n < rrc_cfg->cell_list.size(); ++n) {
@ -723,13 +709,14 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
auto& cellroot = root[n];
parse_opt_field(cell_cfg.rf_port, cellroot, "rf_port");
parse_default_field(cell_cfg.cell_id, cellroot, "cell_id", self_cellid, cell_id_parser);
parse_default_field(cell_cfg.tac, cellroot, "tac", args->stack.s1ap.tac);
parse_default_field(cell_cfg.pci, cellroot, "pci", args->enb.pci);
HANDLEPARSERCODE(parse_required_field(cell_cfg.cell_id, cellroot, "cell_id"));
HANDLEPARSERCODE(parse_required_field(cell_cfg.tac, cellroot, "tac"));
HANDLEPARSERCODE(parse_required_field(cell_cfg.pci, cellroot, "pci"));
cell_cfg.pci = cell_cfg.pci % SRSLTE_NUM_PCI;
HANDLEPARSERCODE(parse_required_field(cell_cfg.dl_earfcn, cellroot, "dl_earfcn"));
HANDLEPARSERCODE(parse_required_field(cell_cfg.ul_earfcn, cellroot, "ul_earfcn"));
parse_default_field(
cell_cfg.root_seq_idx, cellroot, "root_seq_idx", rrc_cfg->sibs[1].sib2().rr_cfg_common.prach_cfg.root_seq_idx);
cell_cfg.dl_earfcn = cellroot["dl_earfcn"];
cell_cfg.ul_earfcn = cellroot["ul_earfcn"];
if (cellroot["ho_active"]) {
HANDLEPARSERCODE(parse_meas_cell_list(&rrc_cfg->meas_cfg, cellroot["meas_cell_list"]));
@ -778,13 +765,12 @@ namespace enb_conf_sections {
int parse_cell_cfg(all_args_t* args_, srslte_cell_t* cell)
{
cell->frame_type = SRSLTE_FDD;
cell->id = args_->enb.pci;
cell->cp = SRSLTE_CP_NORM;
cell->nof_ports = args_->enb.nof_ports;
cell->nof_prb = args_->enb.n_prb;
// PCI not configured yet
phich_cfg_s phichcfg;
parser::section phy_cnfg("phy_cnfg");
parser::section phich_cnfg("phich_cnfg");
phy_cnfg.add_subsection(&phich_cnfg);
@ -853,7 +839,7 @@ int parse_cfg_files(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_)
return SRSLTE_ERROR;
}
} catch (const SettingTypeException& stex) {
fprintf(stderr, "\"Error parsing DRB configuration: %s\n", stex.getPath());
fprintf(stderr, "Error parsing DRB configuration: %s\n", stex.getPath());
return SRSLTE_ERROR;
} catch (const ConfigException& cex) {
fprintf(stderr, "Error parsing DRB configuration\n");
@ -861,18 +847,61 @@ int parse_cfg_files(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_)
}
// Set fields derived from others, and check for correctness of the parsed configuration
return enb_conf_sections::set_derived_args(args_, rrc_cfg_, phy_cfg_, &cell_common_cfg);
return enb_conf_sections::set_derived_args(args_, rrc_cfg_, phy_cfg_, cell_common_cfg);
}
int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_, srslte_cell_t* cell_cfg_)
int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_, const srslte_cell_t& cell_cfg_)
{
// Copy cell struct to rrc and phy
rrc_cfg_->cell = *cell_cfg_;
// Sanity check
if (rrc_cfg_->cell_list.empty()) {
ERROR("No cell specified in RR config.");
return SRSLTE_ERROR;
}
// Check for a forced DL EARFCN or frequency (only valid for a single cell config (Xico's favorite feature))
if (rrc_cfg_->cell_list.size() == 1) {
auto& cfg = rrc_cfg_->cell_list.at(0);
if (args_->enb.dl_earfcn > 0) {
cfg.dl_earfcn = args_->enb.dl_earfcn;
ERROR("Force DL EARFCN for cell PCI=%d to %d\n", cfg.pci, cfg.dl_earfcn);
}
if (args_->rf.dl_freq > 0) {
cfg.dl_freq_hz = args_->rf.dl_freq;
ERROR("Force DL freq for cell PCI=%d to %f MHz\n", cfg.pci, cfg.dl_freq_hz / 1e6f);
}
} else {
// If more than one cell is defined, single EARFCN or DL freq will be ignored
if (args_->enb.dl_earfcn > 0 || args_->rf.dl_freq > 0) {
INFO("Multiple cells defined in rr.conf. Ignoring single EARFCN and/or frequency config.\n");
}
}
// set config for RRC's base cell
rrc_cfg_->cell = cell_cfg_;
// Set S1AP related params from cell list (Convert hex strings)
{
std::stringstream sstr;
sstr << std::hex << args_->enb.enb_id;
sstr >> args_->stack.s1ap.enb_id;
}
{
std::stringstream sstr;
sstr << std::hex << rrc_cfg_->cell_list.at(0).cell_id;
uint16_t tmp; // Need intermediate uint16_t as uint8_t is treated as char
sstr >> tmp;
args_->stack.s1ap.cell_id = tmp;
}
{
std::stringstream sstr;
sstr << std::hex << rrc_cfg_->cell_list.at(0).tac;
sstr >> args_->stack.s1ap.tac;
}
// Create dedicated cell configuration from RRC configuration
for (auto& cfg : rrc_cfg_->cell_list) {
phy_cell_cfg_t phy_cell_cfg = {};
phy_cell_cfg.cell = *cell_cfg_;
phy_cell_cfg.cell = cell_cfg_;
phy_cell_cfg.cell.id = cfg.pci;
phy_cell_cfg.cell_id = cfg.cell_id;
phy_cell_cfg.root_seq_idx = cfg.root_seq_idx;
@ -906,16 +935,12 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_
rrc_cfg_->inactivity_timeout_ms = args_->general.rrc_inactivity_timer;
rrc_cfg_->enable_mbsfn = args_->stack.embms.enable;
rrc_cfg_->dl_earfcn = args_->enb.dl_earfcn;
rrc_cfg_->pci = args_->enb.pci;
// Check number of control symbols
if (cell_cfg_->nof_prb < 50 && args_->stack.mac.sched.nof_ctrl_symbols != 3) {
if (cell_cfg_.nof_prb < 50 && args_->stack.mac.sched.nof_ctrl_symbols != 3) {
args_->stack.mac.sched.nof_ctrl_symbols = 3;
fprintf(stdout,
"Setting number of control symbols to %d for %d PRB cell.\n",
args_->stack.mac.sched.nof_ctrl_symbols,
cell_cfg_->nof_prb);
INFO("Setting number of control symbols to %d for %d PRB cell.\n",
args_->stack.mac.sched.nof_ctrl_symbols,
cell_cfg_.nof_prb);
}
// Parse EEA preference list
@ -968,9 +993,9 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_
// Check PRACH configuration
uint32_t prach_freq_offset = rrc_cfg_->sibs[1].sib2().rr_cfg_common.prach_cfg.prach_cfg_info.prach_freq_offset;
if (rrc_cfg_->cell.nof_prb > 10) {
if (args_->enb.n_prb > 10) {
uint32_t lower_bound = SRSLTE_MAX(rrc_cfg_->sr_cfg.nof_prb, rrc_cfg_->cqi_cfg.nof_prb);
uint32_t upper_bound = rrc_cfg_->cell.nof_prb - lower_bound;
uint32_t upper_bound = args_->enb.n_prb - lower_bound;
if (prach_freq_offset + 6 > upper_bound or prach_freq_offset < lower_bound) {
fprintf(stderr,
"ERROR: Invalid PRACH configuration - prach_freq_offset=%d collides with PUCCH.\n",
@ -982,12 +1007,12 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_
return SRSLTE_ERROR;
}
} else { // 6 PRB case
if (prach_freq_offset + 6 > rrc_cfg_->cell.nof_prb) {
if (prach_freq_offset + 6 > args_->enb.n_prb) {
fprintf(stderr,
"WARNING: Invalid PRACH configuration - prach=(%d, %d) does not fit into the eNB PRBs=(0, %d).\n",
prach_freq_offset,
prach_freq_offset + 6,
rrc_cfg_->cell.nof_prb);
args_->enb.n_prb);
fprintf(
stderr,
" Consider changing the \"prach_freq_offset\" value to 0 in the sib.conf file when using 6 PRBs.\n");
@ -1001,6 +1026,12 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_
args_->rf.nof_carriers = rrc_cfg_->cell_list.size();
args_->rf.nof_antennas = args_->enb.nof_ports;
// MAC needs to know the cell bandwidth to dimension softbuffers
args_->stack.mac.nof_prb = args_->enb.n_prb;
// RRC needs eNB id for SIB1 packing
rrc_cfg_->enb_id = args_->stack.s1ap.enb_id;
return SRSLTE_SUCCESS;
}
@ -1390,10 +1421,6 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co
}
// Fill rest of data from enb config
sib_type1_s::cell_access_related_info_s_* cell_access = &sib1->cell_access_related_info;
cell_access->cell_id.from_number((args_->stack.s1ap.enb_id << 8u) + args_->stack.s1ap.cell_id);
cell_access->tac.from_number(args_->stack.s1ap.tac);
sib1->freq_band_ind = (uint8_t)srslte_band_get_band(args_->enb.dl_earfcn);
std::string mnc_str;
if (not srslte::mnc_to_string(args_->stack.s1ap.mnc, &mnc_str)) {
ERROR("The provided mnc=%d is not valid", args_->stack.s1ap.mnc);
@ -1404,6 +1431,7 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co
ERROR("The provided mnc=%d is not valid", args_->stack.s1ap.mcc);
return -1;
}
sib_type1_s::cell_access_related_info_s_* cell_access = &sib1->cell_access_related_info;
cell_access->plmn_id_list.resize(1);
srslte::plmn_id_t plmn;
if (plmn.from_string(mcc_str + mnc_str) == SRSLTE_ERROR) {
@ -1424,9 +1452,7 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co
if (sib2->freq_info.ul_bw_present) {
asn1::number_to_enum(sib2->freq_info.ul_bw, args_->enb.n_prb);
}
if (sib2->freq_info.ul_carrier_freq_present) {
sib2->freq_info.ul_carrier_freq = (uint16_t)args_->enb.ul_earfcn;
}
// UL carrier freq is patched before packing the SIB for each CC
// Update MBSFN list counter. Only 1 supported
if (not args_->stack.embms.enable) {

View File

@ -47,7 +47,7 @@ namespace enb_conf_sections {
int parse_cell_cfg(all_args_t* args_, srslte_cell_t* cell);
int parse_cfg_files(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_);
int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_, srslte_cell_t* cell_cfg_);
int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_, const srslte_cell_t& cell_cfg_);
} // namespace enb_conf_sections

View File

@ -49,9 +49,6 @@ string config_file;
void parse_args(all_args_t* args, int argc, char* argv[])
{
string enb_id;
string cell_id;
string tac;
string mcc;
string mnc;
@ -67,16 +64,13 @@ void parse_args(all_args_t* args, int argc, char* argv[])
bpo::options_description common("Configuration options");
common.add_options()
("enb.enb_id", bpo::value<string>(&enb_id)->default_value("0x0"), "eNodeB ID")
("enb.enb_id", bpo::value<string>(&args->enb.enb_id)->default_value("0x0"), "eNodeB ID")
("enb.name", bpo::value<string>(&args->stack.s1ap.enb_name)->default_value("srsenb01"), "eNodeB Name")
("enb.cell_id", bpo::value<string>(&cell_id)->default_value("0x0"), "Cell ID")
("enb.tac", bpo::value<string>(&tac)->default_value("0x0"), "Tracking Area Code")
("enb.mcc", bpo::value<string>(&mcc)->default_value("001"), "Mobile Country Code")
("enb.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code")
("enb.mme_addr", bpo::value<string>(&args->stack.s1ap.mme_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connection")
("enb.gtp_bind_addr", bpo::value<string>(&args->stack.s1ap.gtp_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for GTP connection")
("enb.s1c_bind_addr", bpo::value<string>(&args->stack.s1ap.s1c_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for S1AP connection")
("enb.phy_cell_id", bpo::value<uint32_t>(&args->enb.pci)->default_value(0), "Physical Cell Identity (PCI)")
("enb.n_prb", bpo::value<uint32_t>(&args->enb.n_prb)->default_value(25), "Number of PRB")
("enb.nof_ports", bpo::value<uint32_t>(&args->enb.nof_ports)->default_value(1), "Number of ports")
("enb.tm", bpo::value<uint32_t>(&args->enb.transmission_mode)->default_value(1), "Transmission mode (1-8)")
@ -86,8 +80,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("enb_files.rr_config", bpo::value<string>(&args->enb_files.rr_config)->default_value("rr.conf"), "RR configuration files")
("enb_files.drb_config", bpo::value<string>(&args->enb_files.drb_config)->default_value("drb.conf"), "DRB configuration files")
("rf.dl_earfcn", bpo::value<uint32_t>(&args->enb.dl_earfcn)->default_value(3400), "Downlink EARFCN")
("rf.ul_earfcn", bpo::value<uint32_t>(&args->enb.ul_earfcn)->default_value(0), "Uplink EARFCN (Default based on Downlink EARFCN)")
("rf.dl_earfcn", bpo::value<uint32_t>(&args->enb.dl_earfcn)->default_value(0), "Force Downlink EARFCN for single cell")
("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(50), "Front-end receiver gain")
("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(70), "Front-end transmitter gain")
("rf.dl_freq", bpo::value<float>(&args->rf.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)")
@ -252,25 +245,6 @@ void parse_args(all_args_t* args, int argc, char* argv[])
exit(1);
}
// Convert hex strings
{
std::stringstream sstr;
sstr << std::hex << vm["enb.enb_id"].as<std::string>();
sstr >> args->stack.s1ap.enb_id;
}
{
std::stringstream sstr;
sstr << std::hex << vm["enb.cell_id"].as<std::string>();
uint16_t tmp; // Need intermediate uint16_t as uint8_t is treated as char
sstr >> tmp;
args->stack.s1ap.cell_id = tmp;
}
{
std::stringstream sstr;
sstr << std::hex << vm["enb.tac"].as<std::string>();
sstr >> args->stack.s1ap.tac;
}
// Convert MCC/MNC strings
if (!srslte::string_to_mcc(mcc, &args->stack.s1ap.mcc)) {
cout << "Error parsing enb.mcc:" << mcc << " - must be a 3-digit string." << endl;
@ -279,24 +253,6 @@ void parse_args(all_args_t* args, int argc, char* argv[])
cout << "Error parsing enb.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl;
}
// Convert UL/DL EARFCN to frequency if needed
if (args->rf.dl_freq < 0) {
args->rf.dl_freq = 1e6 * srslte_band_fd(args->enb.dl_earfcn);
if (args->rf.dl_freq < 0) {
fprintf(stderr, "Error getting DL frequency for EARFCN=%d\n", args->enb.dl_earfcn);
exit(1);
}
}
if (args->rf.ul_freq < 0) {
if (args->enb.ul_earfcn == 0) {
args->enb.ul_earfcn = srslte_band_ul_earfcn(args->enb.dl_earfcn);
}
args->rf.ul_freq = 1e6 * srslte_band_fu(args->enb.ul_earfcn);
if (args->rf.ul_freq < 0) {
fprintf(stderr, "Error getting UL frequency for EARFCN=%d\n", args->enb.dl_earfcn);
exit(1);
}
}
if (args->stack.embms.enable) {
if (args->stack.mac.sched.nof_ctrl_symbols == 3) {
fprintf(stderr,

View File

@ -106,10 +106,10 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_)
rx_sockets.reset(new srslte::rx_multisocket_handler("ENBSOCKETS", &stack_log));
// Init all layers
mac.init(args.mac, &rrc_cfg.cell, phy, &rlc, &rrc, this, &mac_log);
mac.init(args.mac, rrc_cfg.cell_list, phy, &rlc, &rrc, this, &mac_log);
rlc.init(&pdcp, &rrc, &mac, &timers, &rlc_log);
pdcp.init(&rlc, &rrc, &gtpu);
rrc.init(&rrc_cfg, phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &timers, &rrc_log);
rrc.init(rrc_cfg, phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &timers, &rrc_log);
s1ap.init(args.s1ap, &rrc, &timers, this);
gtpu.init(args.s1ap.gtp_bind_addr,
args.s1ap.mme_addr,

View File

@ -51,7 +51,7 @@ mac::~mac()
}
bool mac::init(const mac_args_t& args_,
srslte_cell_t* cell_,
const cell_list_t& cells_,
phy_interface_stack_lte* phy,
rlc_interface_mac* rlc,
rrc_interface_mac* rrc,
@ -60,7 +60,7 @@ bool mac::init(const mac_args_t& args_,
{
started = false;
if (cell_ && phy && rlc && log_h_) {
if (phy && rlc && log_h_) {
phy_h = phy;
rlc_h = rlc;
rrc_h = rrc;
@ -68,7 +68,7 @@ bool mac::init(const mac_args_t& args_,
log_h = log_h_;
args = args_;
cell = *cell_;
cells = cells_;
stack_task_queue = stack->get_task_queue();
@ -79,13 +79,13 @@ bool mac::init(const mac_args_t& args_,
// Init softbuffer for SI messages
for (int i = 0; i < NOF_BCCH_DLSCH_MSG; i++) {
srslte_softbuffer_tx_init(&bcch_softbuffer_tx[i], cell.nof_prb);
srslte_softbuffer_tx_init(&bcch_softbuffer_tx[i], args.nof_prb);
}
// Init softbuffer for PCCH
srslte_softbuffer_tx_init(&pcch_softbuffer_tx, cell.nof_prb);
srslte_softbuffer_tx_init(&pcch_softbuffer_tx, args.nof_prb);
// Init softbuffer for RAR
srslte_softbuffer_tx_init(&rar_softbuffer_tx, cell.nof_prb);
srslte_softbuffer_tx_init(&rar_softbuffer_tx, args.nof_prb);
reset();
@ -430,7 +430,7 @@ void mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx
// Create new UE
if (ue_db.count(rnti) == 0) {
ue_db[rnti] = new ue(rnti, cell.nof_prb, &scheduler, rrc_h, rlc_h, log_h, SRSLTE_FDD_NOF_HARQ);
ue_db[rnti] = new ue(rnti, args.nof_prb, &scheduler, rrc_h, rlc_h, log_h, SRSLTE_FDD_NOF_HARQ);
}
// Set PCAP if available
@ -581,7 +581,7 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res_list)
// Set softbuffer
if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) {
dl_sched_res->pdsch[n].softbuffer_tx[0] = &bcch_softbuffer_tx[sched_result.bc[i].index];
dl_sched_res->pdsch[n].data[0] = assemble_si(sched_result.bc[i].index);
dl_sched_res->pdsch[n].data[0] = assemble_si(enb_cc_idx, sched_result.bc[i].index);
#ifdef WRITE_SIB_PCAP
if (pcap) {
pcap->write_dl_sirnti(dl_sched_res->pdsch[n].data[0], sched_result.bc[i].tbs, true, tti, enb_cc_idx);
@ -739,9 +739,9 @@ uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants,
}
}
uint8_t* mac::assemble_si(uint32_t index)
uint8_t* mac::assemble_si(const uint8_t cc_idx, const uint32_t index)
{
rlc_h->read_pdu_bcch_dlsch(index, bcch_dlsch_payload);
rlc_h->read_pdu_bcch_dlsch(cc_idx, index, bcch_dlsch_payload);
return bcch_dlsch_payload;
}
@ -833,7 +833,7 @@ void mac::write_mcch(sib_type2_s* sib2_, sib_type13_r9_s* sib13_, mcch_msg_s* mc
mcch.pack(bref);
current_mcch_length = bref.distance_bytes(&mcch_payload_buffer[1]);
current_mcch_length = current_mcch_length + rlc_header_len;
ue_db[SRSLTE_MRNTI] = new ue(SRSLTE_MRNTI, cell.nof_prb, &scheduler, rrc_h, rlc_h, log_h);
ue_db[SRSLTE_MRNTI] = new ue(SRSLTE_MRNTI, args.nof_prb, &scheduler, rrc_h, rlc_h, log_h);
rrc_h->add_user(SRSLTE_MRNTI, {});
}

View File

@ -43,7 +43,7 @@ rrc::rrc()
rrc::~rrc() {}
void rrc::init(rrc_cfg_t* cfg_,
void rrc::init(const rrc_cfg_t& cfg_,
phy_interface_rrc_lte* phy_,
mac_interface_rrc* mac_,
rlc_interface_rrc* rlc_,
@ -64,10 +64,10 @@ void rrc::init(rrc_cfg_t* cfg_,
pool = srslte::byte_buffer_pool::get_instance();
cfg = *cfg_;
cfg = cfg_;
if (cfg.sibs[12].type() == asn1::rrc::sys_info_r8_ies_s::sib_type_and_info_item_c_::types::sib13_v920 &&
cfg_->enable_mbsfn) {
cfg.enable_mbsfn) {
configure_mbsfn_sibs(&cfg.sibs[1].sib2(), &cfg.sibs[12].sib13_v920());
}
@ -126,10 +126,10 @@ void rrc::get_metrics(rrc_metrics_t& m)
to the queue and process later
*******************************************************************************/
void rrc::read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t* payload)
void rrc::read_pdu_bcch_dlsch(const uint8_t cc_idx, const uint32_t sib_index, uint8_t* payload)
{
if (sib_index < ASN1_RRC_MAX_SIB) {
memcpy(payload, sib_buffer[sib_index]->msg, sib_buffer[sib_index]->N_bytes);
if (sib_index < ASN1_RRC_MAX_SIB && cc_idx < sib_buffer.size()) {
memcpy(payload, sib_buffer.at(cc_idx).at(sib_index)->msg, sib_buffer.at(cc_idx).at(sib_index)->N_bytes);
}
}
@ -776,7 +776,7 @@ void rrc::config_mac()
// set sib/prach cfg
for (uint32_t i = 0; i < nof_si_messages; i++) {
item.sibs[i].len = sib_buffer[i]->N_bytes;
item.sibs[i].len = sib_buffer.at(ccidx).at(i)->N_bytes;
if (i == 0) {
item.sibs[i].period_rf = 8; // SIB1 is always 8 rf
} else {
@ -794,7 +794,7 @@ void rrc::config_mac()
item.nrb_pucch = SRSLTE_MAX(cfg.sr_cfg.nof_prb, cfg.cqi_cfg.nof_prb);
rrc_log->info("Allocating %d PRBs for PUCCH\n", item.nrb_pucch);
// Copy Cell configuration
// Copy base cell configuration
item.cell = cfg.cell;
// copy secondary cell list info
@ -821,58 +821,90 @@ void rrc::config_mac()
mac->cell_cfg(sched_cfg);
}
/* This methods packs the SIBs for each component carrier and stores them
* inside the sib_buffer, a vector of SIBs for each CC.
*
* Before packing the message, it patches the cell specific params of
* the SIB, including the cellId and the PRACH config index.
*
* @return The number of SIBs messages per CC
*/
uint32_t rrc::generate_sibs()
{
// nof_messages includes SIB2 by default, plus all configured SIBs
uint32_t nof_messages = 1 + cfg.sib1.sched_info_list.size();
sched_info_list_l& sched_info = cfg.sib1.sched_info_list;
// msg is array of SI messages, each SI message msg[i] may contain multiple SIBs
// all SIBs in a SI message msg[i] share the same periodicity
asn1::dyn_array<bcch_dl_sch_msg_s> msg(nof_messages + 1);
// generate SIBs for each CC
for (uint8_t cc_idx = 0; cc_idx < cfg.cell_list.size(); cc_idx++) {
// msg is array of SI messages, each SI message msg[i] may contain multiple SIBs
// all SIBs in a SI message msg[i] share the same periodicity
asn1::dyn_array<bcch_dl_sch_msg_s> msg(nof_messages + 1);
// Copy SIB1 to first SI message
msg[0].msg.set_c1().set_sib_type1() = cfg.sib1;
// Copy SIB1 to first SI message
msg[0].msg.set_c1().set_sib_type1() = cfg.sib1;
// Copy rest of SIBs
for (uint32_t sched_info_elem = 0; sched_info_elem < nof_messages - 1; sched_info_elem++) {
uint32_t msg_index = sched_info_elem + 1; // first msg is SIB1, therefore start with second
// Update cellId
sib_type1_s::cell_access_related_info_s_* cell_access = &msg[0].msg.c1().sib_type1().cell_access_related_info;
cell_access->cell_id.from_number((cfg.enb_id << 8u) + cfg.cell_list.at(cc_idx).cell_id);
cell_access->tac.from_number(cfg.cell_list.at(cc_idx).tac);
msg[msg_index].msg.set_c1().set_sys_info().crit_exts.set_sys_info_r8();
sys_info_r8_ies_s::sib_type_and_info_l_& sib_list =
msg[msg_index].msg.c1().sys_info().crit_exts.sys_info_r8().sib_type_and_info;
// Update DL EARFCN
msg[0].msg.c1().sib_type1().freq_band_ind = (uint8_t)srslte_band_get_band(cfg.cell_list.at(cc_idx).dl_earfcn);
// SIB2 always in second SI message
if (msg_index == 1) {
sib_list.push_back(cfg.sibs[1]);
// Save SIB2
sib2 = cfg.sibs[1].sib2();
// Copy rest of SIBs
for (uint32_t sched_info_elem = 0; sched_info_elem < nof_messages - 1; sched_info_elem++) {
uint32_t msg_index = sched_info_elem + 1; // first msg is SIB1, therefore start with second
msg[msg_index].msg.set_c1().set_sys_info().crit_exts.set_sys_info_r8();
sys_info_r8_ies_s::sib_type_and_info_l_& sib_list =
msg[msg_index].msg.c1().sys_info().crit_exts.sys_info_r8().sib_type_and_info;
// SIB2 always in second SI message
if (msg_index == 1) {
// update PRACH root seq index for this cell
cfg.sibs[1].sib2().rr_cfg_common.prach_cfg.root_seq_idx = cfg.cell_list.at(cc_idx).root_seq_idx;
// update carrier freq
if (cfg.sibs[1].sib2().freq_info.ul_carrier_freq_present) {
cfg.sibs[1].sib2().freq_info.ul_carrier_freq = cfg.cell_list.at(cc_idx).ul_earfcn;
}
sib_list.push_back(cfg.sibs[1]);
// Save SIB2
sib2 = cfg.sibs[1].sib2();
}
// Add other SIBs to this message, if any
for (auto& mapping_enum : sched_info[sched_info_elem].sib_map_info) {
sib_list.push_back(cfg.sibs[(int)mapping_enum + 2]);
}
}
// Add other SIBs to this message, if any
for (auto& mapping_enum : sched_info[sched_info_elem].sib_map_info) {
sib_list.push_back(cfg.sibs[(int)mapping_enum + 2]);
// Pack payload for all messages
for (uint32_t msg_index = 0; msg_index < nof_messages; msg_index++) {
srslte::unique_byte_buffer_t sib = srslte::allocate_unique_buffer(*pool);
asn1::bit_ref bref(sib->msg, sib->get_tailroom());
asn1::bit_ref bref0 = bref;
if (msg[msg_index].pack(bref) == asn1::SRSASN_ERROR_ENCODE_FAIL) {
rrc_log->error("Failed to pack SIB message %d\n", msg_index);
}
sib->N_bytes = static_cast<uint32_t>((bref.distance(bref0) - 1) / 8 + 1);
sib_buffer[cc_idx].push_back(std::move(sib));
// Log SIBs in JSON format
std::string log_msg("CC" + std::to_string(cc_idx) + " SIB payload");
log_rrc_message(log_msg,
Tx,
sib_buffer.at(cc_idx).at(msg_index).get(),
msg[msg_index],
msg[msg_index].msg.c1().type().to_string());
}
}
// Pack payload for all messages
for (uint32_t msg_index = 0; msg_index < nof_messages; msg_index++) {
srslte::unique_byte_buffer_t sib = srslte::allocate_unique_buffer(*pool);
asn1::bit_ref bref(sib->msg, sib->get_tailroom());
asn1::bit_ref bref0 = bref;
if (msg[msg_index].pack(bref) == asn1::SRSASN_ERROR_ENCODE_FAIL) {
rrc_log->error("Failed to pack SIB message %d\n", msg_index);
if (cfg.sibs[6].type() == asn1::rrc::sys_info_r8_ies_s::sib_type_and_info_item_c_::types::sib7) {
sib7 = cfg.sibs[6].sib7();
}
sib->N_bytes = static_cast<uint32_t>((bref.distance(bref0) - 1) / 8 + 1);
sib_buffer.push_back(std::move(sib));
// Log SIBs in JSON format
log_rrc_message(
"SIB payload", Tx, sib_buffer[msg_index].get(), msg[msg_index], msg[msg_index].msg.c1().type().to_string());
}
if (cfg.sibs[6].type() == asn1::rrc::sys_info_r8_ies_s::sib_type_and_info_item_c_::types::sib7) {
sib7 = cfg.sibs[6].sib7();
}
return nof_messages;

View File

@ -861,15 +861,16 @@ bool rrc::ue::rrc_mobility::start_ho_preparation(uint32_t target_eci,
hoprep_r8.as_cfg.source_sib_type1 = rrc_enb->cfg.sib1;
hoprep_r8.as_cfg.source_sib_type2 = rrc_enb->sib2;
asn1::number_to_enum(hoprep_r8.as_cfg.ant_info_common.ant_ports_count, rrc_enb->cfg.cell.nof_ports);
hoprep_r8.as_cfg.source_dl_carrier_freq = rrc_enb->cfg.dl_earfcn;
hoprep_r8.as_cfg.source_dl_carrier_freq =
rrc_enb->cfg.cell_list.at(0).dl_earfcn; // TODO: use actual DL EARFCN of source cell
// - fill as_context
hoprep_r8.as_context_present = true;
hoprep_r8.as_context.reest_info_present = true;
hoprep_r8.as_context.reest_info.source_pci = rrc_enb->cfg.pci;
hoprep_r8.as_context.reest_info.source_pci = rrc_enb->cfg.cell_list.at(0).pci; // TODO: use actual PCI of source cell
hoprep_r8.as_context.reest_info.target_cell_short_mac_i.from_number(
rrc_details::compute_mac_i(rrc_ue->rnti,
rrc_enb->cfg.sib1.cell_access_related_info.cell_id.to_number(),
rrc_enb->cfg.pci,
rrc_enb->cfg.cell_list.at(0).pci, // TODO: use actual PCI of source cell
rrc_ue->integ_algo,
rrc_ue->k_rrc_int));

View File

@ -193,10 +193,10 @@ void rlc::write_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof
pthread_rwlock_unlock(&rwlock);
}
void rlc::read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t* payload)
void rlc::read_pdu_bcch_dlsch(const uint8_t cc_idx, const uint32_t sib_index, uint8_t* payload)
{
// RLC is transparent for BCCH
rrc->read_pdu_bcch_dlsch(sib_index, payload);
rrc->read_pdu_bcch_dlsch(cc_idx, sib_index, payload);
}
void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu)

View File

@ -46,7 +46,7 @@ int test_erab_setup(bool qci_exists)
gtpu_dummy gtpu;
rrc_log->set_level(srslte::LOG_LEVEL_INFO);
rrc_log->set_hex_limit(1024);
rrc.init(&cfg, &phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &timers, rrc_log.get());
rrc.init(cfg, &phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &timers, rrc_log.get());
auto tic = [&timers, &rrc] {
timers.step_all();

View File

@ -282,7 +282,7 @@ int test_mobility_class(mobility_test_params test_params)
gtpu_dummy gtpu;
rrc_log->set_level(srslte::LOG_LEVEL_INFO);
rrc_log->set_hex_limit(1024);
rrc.init(&cfg, &phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &timers, rrc_log.get());
rrc.init(cfg, &phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &timers, rrc_log.get());
auto tic = [&timers, &rrc] {
timers.step_all();