From 08976bb9480cfc7818f10f69ac40dd53739914f5 Mon Sep 17 00:00:00 2001 From: yagoda Date: Tue, 15 May 2018 17:01:51 +0200 Subject: [PATCH] introducing support for embms in the enodeb PHY --- srsenb/hdr/phy/phch_common.h | 41 +++++++++- srsenb/hdr/phy/phch_worker.h | 3 +- srsenb/hdr/phy/phy.h | 7 +- srsenb/src/phy/phch_common.cc | 141 +++++++++++++++++++++++++++++++++- srsenb/src/phy/phch_worker.cc | 84 ++++++++++++++++---- srsenb/src/phy/phy.cc | 26 ++++++- 6 files changed, 280 insertions(+), 22 deletions(-) diff --git a/srsenb/hdr/phy/phch_common.h b/srsenb/hdr/phy/phch_common.h index 6adc926f3..8cebcb042 100644 --- a/srsenb/hdr/phy/phch_common.h +++ b/srsenb/hdr/phy/phch_common.h @@ -30,12 +30,12 @@ #include #include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_metrics_interface.h" - +#include "srslte/common/gen_mch_tables.h" #include "srslte/common/log.h" #include "srslte/common/threads.h" #include "srslte/common/thread_pool.h" #include "srslte/radio/radio.h" - +#include namespace srsenb { typedef struct { @@ -48,6 +48,26 @@ typedef struct { bool pregenerate_signals; } phy_args_t; +typedef enum{ + SUBFRAME_TYPE_REGULAR = 0, + SUBFRAME_TYPE_MBSFN, + SUBFRAME_TYPE_N_ITEMS, +} subframe_type_t; +static const char subframe_type_text[SUBFRAME_TYPE_N_ITEMS][20] = {"Regular", "MBSFN"}; + +/* Subframe config */ + +typedef struct { + subframe_type_t sf_type; + uint8_t mbsfn_area_id; + uint8_t non_mbsfn_region_length; + uint8_t mbsfn_mcs; + bool mbsfn_encode; + bool is_mcch; +} subframe_cfg_t; + + + class phch_common { public: @@ -119,6 +139,12 @@ public: srslte_mod_t ue_db_get_last_ul_mod(uint16_t rnti, uint32_t tti); void ue_db_set_last_ul_tbs(uint16_t rnti, uint32_t tti, int tbs); int ue_db_get_last_ul_tbs(uint16_t rnti, uint32_t tti); + + void configure_mbsfn(phy_interface_rrc::phy_cfg_mbsfn_t *cfg); + void build_mch_table(); + void build_mcch_table(); + void get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti); + private: std::vector tx_mutex; @@ -129,6 +155,17 @@ private: uint32_t nof_mutex; uint32_t max_mutex; + phy_interface_rrc::phy_cfg_mbsfn_t mbsfn; + bool sib13_configured; + bool mcch_configured; + uint8_t mch_table[40]; + uint8_t mcch_table[10]; + + uint8_t mch_sf_idx_lut[10]; + bool is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti); + bool is_mcch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti); + + }; } // namespace srsenb diff --git a/srsenb/hdr/phy/phch_worker.h b/srsenb/hdr/phy/phch_worker.h index 9821a2d1e..a04c9232e 100644 --- a/srsenb/hdr/phy/phch_worker.h +++ b/srsenb/hdr/phy/phch_worker.h @@ -76,6 +76,7 @@ private: void work_imp(); int encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants); + int encode_pmch(srslte_enb_dl_pdsch_t *grant, srslte_ra_dl_grant_t *phy_grant); int decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch); int encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks); int encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants); @@ -96,7 +97,7 @@ private: uint32_t t_rx, t_tx_dl, t_tx_ul; srslte_enb_dl_t enb_dl; srslte_enb_ul_t enb_ul; - + srslte_softbuffer_tx_t temp_mbsfn_softbuffer; srslte_timestamp_t tx_time; // Class to store user information diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h index 74b28be11..a6240b8b3 100644 --- a/srsenb/hdr/phy/phy.h +++ b/srsenb/hdr/phy/phy.h @@ -62,6 +62,9 @@ public: /* MAC->PHY interface */ int add_rnti(uint16_t rnti); void rem_rnti(uint16_t rnti); + + /*RRC-PHY interface*/ + void configure_mbsfn(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT mcch); static uint32_t tti_to_SFN(uint32_t tti); static uint32_t tti_to_subf(uint32_t tti); @@ -73,7 +76,7 @@ public: void get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]); private: - + phy_rrc_cfg_t phy_rrc_config; uint32_t nof_workers; const static int MAX_WORKERS = 4; @@ -84,7 +87,7 @@ private: const static int WORKERS_THREAD_PRIO = 0; srslte::radio *radio_handler; - + srslte::log *log_h; srslte::thread_pool workers_pool; std::vector workers; phch_common workers_common; diff --git a/srsenb/src/phy/phch_common.cc b/srsenb/src/phy/phch_common.cc index ce8026ca5..b284c1036 100644 --- a/srsenb/src/phy/phch_common.cc +++ b/srsenb/src/phy/phch_common.cc @@ -26,7 +26,7 @@ #include "srslte/common/threads.h" #include "srslte/common/log.h" - +#include #include "srsenb/hdr/phy/txrx.h" #include @@ -177,5 +177,144 @@ int phch_common::ue_db_get_last_ul_tbs(uint16_t rnti, uint32_t tti) { } return ret; } +void phch_common::configure_mbsfn(phy_interface_rrc::phy_cfg_mbsfn_t *cfg) { + memcpy(&mbsfn, cfg, sizeof(phy_interface_rrc::phy_cfg_mbsfn_t)); + + build_mch_table(); + build_mcch_table(); + sib13_configured = true; + mcch_configured = true; } + + +void phch_common::build_mch_table() { + // First reset tables + bzero(&mch_table[0], sizeof(uint8_t)*40); + // 40 element table represents 4 frames (40 subframes) + srslte::generate_mch_table(&mch_table[0], mbsfn.mbsfn_subfr_cnfg.subfr_alloc,(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE == mbsfn.mbsfn_subfr_cnfg.subfr_alloc_num_frames)?1:4); + // Debug + std::stringstream ss; + ss << "|"; + for(uint32_t j=0; j<40; j++) { + ss << (int) mch_table[j] << "|"; + } +} + +void phch_common::build_mcch_table() { + bzero(&mcch_table[0], sizeof(uint8_t)*10); + + srslte::generate_mcch_table(&mcch_table[0], mbsfn.mbsfn_area_info.sf_alloc_info_r9); + + std::stringstream ss; + ss << "|"; + for(uint32_t j=0; j<10; j++) { + ss << (int) mcch_table[j] << "|"; + } +} + + + +bool phch_common::is_mcch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti) +{ + uint32_t sfn; // System Frame Number + uint8_t sf; // Subframe + uint8_t offset; + uint8_t period; + + sfn = phy_tti/10; + sf = phy_tti%10; + + if(sib13_configured) { + LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *subfr_cnfg = &mbsfn.mbsfn_subfr_cnfg; + LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *area_info = &mbsfn.mbsfn_area_info; + + offset = area_info->mcch_offset_r9; + period = liblte_rrc_mcch_repetition_period_r9_num[area_info->mcch_repetition_period_r9]; + + if((sfn%period == offset) && mcch_table[sf] > 0) { + cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9; + cfg->non_mbsfn_region_length = liblte_rrc_non_mbsfn_region_length_num[area_info->non_mbsfn_region_length]; + cfg->mbsfn_mcs = liblte_rrc_mcch_signalling_mcs_r9_num[area_info->signalling_mcs_r9]; + cfg->mbsfn_encode = true; + cfg->is_mcch = true; + return true; + } + } + return false; +} +bool phch_common::is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti) +{ + uint32_t sfn; // System Frame Number + uint8_t sf; // Subframe + uint8_t offset; + uint8_t period; + + sfn = phy_tti/10; + sf = phy_tti%10; + + // Set some defaults + cfg->mbsfn_area_id = 0; + cfg->non_mbsfn_region_length = 1; + cfg->mbsfn_mcs = 2; + cfg->mbsfn_encode = false; + cfg->is_mcch = false; + // Check for MCCH + if(is_mcch_subframe(cfg, phy_tti)) { + return true; + } + + // Not MCCH, check for MCH + LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *subfr_cnfg = &mbsfn.mbsfn_subfr_cnfg; + LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *area_info = &mbsfn.mbsfn_area_info; + + offset = subfr_cnfg->radio_fr_alloc_offset; + period = liblte_rrc_radio_frame_allocation_period_num[subfr_cnfg->radio_fr_alloc_period]; + + if(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE == subfr_cnfg->subfr_alloc_num_frames) { + if((sfn%period == offset) && (mch_table[sf] > 0)) { + if(sib13_configured) { + cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9; + cfg->non_mbsfn_region_length = liblte_rrc_non_mbsfn_region_length_num[area_info->non_mbsfn_region_length]; + if(mcch_configured) { + // Iterate through PMCH configs to see which one applies in the current frame + LIBLTE_RRC_MCCH_MSG_STRUCT *mcch = &mbsfn.mcch; + uint32_t sf_alloc_idx = sfn%liblte_rrc_mbsfn_common_sf_alloc_period_r9_num[mcch->commonsf_allocperiod_r9]; + for(uint32_t i=0; ipmch_infolist_r9_size; i++) { + //if(sf_alloc_idx < mch_period_stop) { + cfg->mbsfn_mcs = mcch->pmch_infolist_r9[i].pmch_config_r9.datamcs_r9; + cfg->mbsfn_encode = true; + //} + } + + } + } + return true; + } + }else if(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_FOUR == subfr_cnfg->subfr_alloc_num_frames) { + uint8_t idx = sfn%period; + if((idx >= offset) && (idx < offset+4)) { + if(mch_table[(idx*10)+sf] > 0){ + if(sib13_configured) { + cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9; + cfg->non_mbsfn_region_length = liblte_rrc_non_mbsfn_region_length_num[area_info->non_mbsfn_region_length]; + // TODO: check for MCCH configuration, set MCS and decode + + } + return true; + } + } + } + + return false; +} + +void phch_common::get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti) +{ + if(is_mch_subframe(cfg, phy_tti)) { + cfg->sf_type = SUBFRAME_TYPE_MBSFN; + }else{ + cfg->sf_type = SUBFRAME_TYPE_REGULAR; + } +} +} \ No newline at end of file diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 9982841f0..dc7dc1b42 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -140,7 +140,14 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_) for (int i=0;i<10;i++) { add_rnti(1+i); } - + + + if (srslte_softbuffer_tx_init(&temp_mbsfn_softbuffer, phy->cell.nof_prb)) { + fprintf(stderr, "Error initiating soft buffer\n"); + exit(-1); + } + + srslte_softbuffer_tx_reset(&temp_mbsfn_softbuffer); srslte_pucch_set_threshold(&enb_ul.pucch, 0.8); srslte_sch_set_max_noi(&enb_ul.pusch.ul_sch, phy->params.pusch_max_its); srslte_enb_dl_set_amp(&enb_dl, phy->params.tx_amplitude); @@ -159,7 +166,7 @@ void phch_worker::stop() { running = false; pthread_mutex_lock(&mutex); - + srslte_softbuffer_tx_free(&temp_mbsfn_softbuffer); srslte_enb_dl_free(&enb_dl); srslte_enb_ul_free(&enb_ul); for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { @@ -351,9 +358,11 @@ void phch_worker::work_imp() if (!running) { return; } - + subframe_cfg_t sf_cfg; + phy->get_sf_config(&sf_cfg, tti_tx_dl);// TODO difference between tti_tx_dl and t_tx_dl pthread_mutex_lock(&mutex); + mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants; mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants; mac_interface_phy *mac = phy->mac; @@ -377,9 +386,19 @@ void phch_worker::work_imp() decode_pucch(); // Get DL scheduling for the TX TTI from MAC - if (mac->get_dl_sched(tti_tx_dl, &dl_grants[t_tx_dl]) < 0) { - Error("Getting DL scheduling from MAC\n"); - goto unlock; + + if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) { + if (mac->get_dl_sched(tti_tx_dl, &dl_grants[t_tx_dl]) < 0) { + Error("Getting DL scheduling from MAC\n"); + goto unlock; + } + } else { + dl_grants[t_tx_dl].cfi = sf_cfg.non_mbsfn_region_length; + srslte_enb_dl_set_non_mbsfn_region(&enb_dl, sf_cfg.non_mbsfn_region_length); + if(mac->get_mch_sched(sf_cfg.is_mcch, &dl_grants[t_tx_dl])){ + Error("Getting MCH packets from MAC\n"); + goto unlock; + } } if (dl_grants[t_tx_dl].cfi < 1 || dl_grants[t_tx_dl].cfi > 3) { @@ -396,18 +415,30 @@ void phch_worker::work_imp() // Put base signals (references, PBCH, PCFICH and PSS/SSS) into the resource grid srslte_enb_dl_clear_sf(&enb_dl); srslte_enb_dl_set_cfi(&enb_dl, dl_grants[t_tx_dl].cfi); - srslte_enb_dl_put_base(&enb_dl, tti_tx_dl); - - // Put UL/DL grants to resource grid. PDSCH data will be encoded as well. - encode_pdcch_dl(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants); + + if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) { + srslte_enb_dl_put_base(&enb_dl, tti_tx_dl); + } else if (sf_cfg.mbsfn_encode){ + srslte_enb_dl_put_mbsfn_base(&enb_dl, tti_tx_dl); + } + + if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) { + // Put UL/DL grants to resource grid. PDSCH data will be encoded as well. + encode_pdcch_dl(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants); + encode_pdsch(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants); + }else { + srslte_ra_dl_grant_t phy_grant; + phy_grant.mcs[0].idx = sf_cfg.mbsfn_mcs; + encode_pmch(&dl_grants[t_tx_dl].sched_grants[0], &phy_grant); + } + encode_pdcch_ul(ul_grants[t_tx_ul].sched_grants, ul_grants[t_tx_ul].nof_grants); - encode_pdsch(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants); - // Put pending PHICH HARQ ACK/NACK indications into subframe encode_phich(ul_grants[t_tx_ul].phich, ul_grants[t_tx_ul].nof_phich); // Prepare for receive ACK for DL grants in t_tx_dl+4 phy->ue_db_clear(TTIMOD(TTI_TX(t_tx_dl))); + for (uint32_t i=0;iworker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); #ifdef DEBUG_WRITE_FILE @@ -837,6 +872,25 @@ int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_gra return 0; } + +int phch_worker::encode_pmch(srslte_enb_dl_pdsch_t *grant, srslte_ra_dl_grant_t *phy_grant) +{ + + phy_grant->tb_en[0] = true; + phy_grant->tb_en[1] = false; + phy_grant->nof_prb = enb_dl.cell.nof_prb; + phy_grant->sf_type = SRSLTE_SF_MBSFN; + srslte_dl_fill_ra_mcs(&phy_grant->mcs[0], enb_dl.cell.nof_prb); + phy_grant->Qm[0] = srslte_mod_bits_x_symbol(phy_grant->mcs[0].mod); + for(int i = 0; i < 2; i++){ + for(uint32_t j = 0; j < phy_grant->nof_prb; j++){ + phy_grant->prb_idx[i][j] = true; + } + } + srslte_enb_dl_put_pmch(&enb_dl, phy_grant, &temp_mbsfn_softbuffer, sf_tx, &grant->data[0][0]); + return SRSLTE_SUCCESS; +} + int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants) { /* Scales the Resources Elements affected by the power allocation (p_b) */ diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index 120a3c7b5..ee7c1e890 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -95,7 +95,9 @@ bool phy::init(phy_args_t *args, mac_interface_phy *mac, srslte::log_filter* log_h) { + std::vector log_vec; + this->log_h = log_h; for (int i=0;inof_phy_threads;i++) { log_vec.push_back(log_h); } @@ -114,7 +116,7 @@ bool phy::init(phy_args_t *args, radio_handler = radio_handler_; nof_workers = args->nof_phy_threads; - + this->log_h = (srslte::log*)log_vec[0]; workers_common.params = *args; workers_common.init(&cfg->cell, radio_handler, mac); @@ -227,6 +229,28 @@ void phy::set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICAT } } +void phy::configure_mbsfn(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT mcch) +{ + if(sib2->mbsfn_subfr_cnfg_list_size > 1) { + Warning("SIB2 has %d MBSFN subframe configs - only 1 supported\n", sib2->mbsfn_subfr_cnfg_list_size); + } + if(sib2->mbsfn_subfr_cnfg_list_size > 0) { + memcpy(&phy_rrc_config.mbsfn.mbsfn_subfr_cnfg, &sib2->mbsfn_subfr_cnfg_list[0], sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT)); + } + + memcpy(&phy_rrc_config.mbsfn.mbsfn_notification_cnfg, &sib13->mbsfn_notification_config, sizeof(LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT)); + if(sib13->mbsfn_area_info_list_r9_size > 1) { + Warning("SIB13 has %d MBSFN area info elements - only 1 supported\n", sib13->mbsfn_area_info_list_r9_size); + } + if(sib13->mbsfn_area_info_list_r9_size > 0) { + memcpy(&phy_rrc_config.mbsfn.mbsfn_area_info, &sib13->mbsfn_area_info_list_r9[0], sizeof(LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT)); + } + + memcpy(&phy_rrc_config.mbsfn.mcch, &mcch, sizeof(LIBLTE_RRC_MCCH_MSG_STRUCT)); + + workers_common.configure_mbsfn(&phy_rrc_config.mbsfn); +} + // Start GUI void phy::start_plot() { ((phch_worker) workers[0]).start_plot();