From e35672e2348ceba892f4d83709fd1fb6ac059cf3 Mon Sep 17 00:00:00 2001 From: yagoda Date: Tue, 15 May 2018 17:16:28 +0200 Subject: [PATCH] adding PHY embms support to the UE --- srsue/hdr/phy/phch_common.h | 319 ++++++++++++++++++++--------------- srsue/hdr/phy/phch_worker.h | 10 +- srsue/hdr/phy/phy.h | 8 +- srsue/src/phy/phch_common.cc | 171 +++++++++++++++++++ srsue/src/phy/phch_worker.cc | 241 ++++++++++++++++++++------ srsue/src/phy/phy.cc | 36 ++++ 6 files changed, 600 insertions(+), 185 deletions(-) diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index b036f3869..82da05e7d 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -27,6 +27,9 @@ #ifndef SRSUE_PHCH_COMMON_H #define SRSUE_PHCH_COMMON_H +#define TX_MODE_CONTINUOUS 1 + + #include #include #include @@ -34,12 +37,12 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/common/log.h" +#include "srslte/common/gen_mch_tables.h" #include "phy_metrics.h" namespace srsue { - class chest_feedback_itf { public: @@ -48,141 +51,191 @@ public: virtual void set_cfo(float cfo) = 0; }; + +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_decode; + bool is_mcch; +} subframe_cfg_t; + + /* Subclass that manages variables common to all workers */ -class phch_common { -public: + class phch_common { + public: + + /* Common variables used by all phy workers */ + phy_interface_rrc::phy_cfg_t *config; + phy_args_t *args; + rrc_interface_phy *rrc; + mac_interface_phy *mac; + srslte_ue_ul_t ue_ul; + + /* Power control variables */ + float pathloss; + float cur_pathloss; + float p0_preamble; + float cur_radio_power; + float cur_pusch_power; + float avg_rsrp; + float avg_rsrp_cqi; + float avg_rsrp_dbm; + float avg_rsrp_sync_dbm; + float avg_rsrq_db; + float avg_rssi_dbm; + float last_radio_rssi; + float rx_gain_offset; + float avg_snr_db_cqi; + float avg_snr_db_sync; + + float avg_noise; + bool pcell_meas_enabled; + + uint32_t pcell_report_period; + bool pcell_first_measurement; + + // Save last TBS for mcs>28 cases + int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS]; + uint32_t last_dl_tti[2*HARQ_DELAY_MS]; + + int last_ul_tbs[2*HARQ_DELAY_MS]; + uint32_t last_ul_tti[2*HARQ_DELAY_MS]; + srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS]; + uint8_t last_ri; + uint8_t last_pmi; + + phch_common(uint32_t max_mutex = 3); + void init(phy_interface_rrc::phy_cfg_t *config, + phy_args_t *args, + srslte::log *_log, + srslte::radio *_radio, + rrc_interface_phy *rrc, + mac_interface_phy *_mac); + + /* For RNTI searches, -1 means now or forever */ + void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); + uint16_t get_ul_rnti(uint32_t tti); + srslte_rnti_type_t get_ul_rnti_type(); + + void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); + uint16_t get_dl_rnti(uint32_t tti); + srslte_rnti_type_t get_dl_rnti_type(); + + void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]); + bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL); + + void reset_pending_ack(uint32_t tti); + void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs); + bool get_pending_ack(uint32_t tti); + bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs); + bool is_any_pending_ack(); + + void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); + + void set_nof_mutex(uint32_t nof_mutex); + + bool sr_enabled; + int sr_last_tx_tti; + + + srslte::radio* get_radio(); + + void set_cell(const srslte_cell_t &c); + uint32_t get_nof_prb(); + void set_dl_metrics(const dl_metrics_t &m); + void get_dl_metrics(dl_metrics_t &m); + void set_ul_metrics(const ul_metrics_t &m); + void get_ul_metrics(ul_metrics_t &m); + void set_sync_metrics(const sync_metrics_t &m); + void get_sync_metrics(sync_metrics_t &m); + + void reset_ul(); + void reset(); + + // MBSFN helpers + void build_mch_table(); + void build_mcch_table(); + void set_mcch(); + void get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti); + void set_mch_period_stop(uint32_t stop); + + private: + + bool have_mtch_stop; + pthread_mutex_t mtch_mutex; + pthread_cond_t mtch_cvar; + + + + std::vector tx_mutex; + + bool is_first_of_burst; + srslte::radio *radio_h; + float cfo; + srslte::log *log_h; + + + bool ul_rnti_active(uint32_t tti); + bool dl_rnti_active(uint32_t tti); + uint16_t ul_rnti, dl_rnti; + srslte_rnti_type_t ul_rnti_type, dl_rnti_type; + int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end; + + float time_adv_sec; + + srslte_dci_rar_grant_t rar_grant; + bool rar_grant_pending; + uint32_t rar_grant_tti; + + typedef struct { + bool enabled; + uint32_t I_lowest; + uint32_t n_dmrs; + } pending_ack_t; + pending_ack_t pending_ack[TTIMOD_SZ]; + + bool is_first_tx; + + uint32_t nof_workers; + uint32_t nof_mutex; + uint32_t max_mutex; + + srslte_cell_t cell; + + dl_metrics_t dl_metrics; + uint32_t dl_metrics_count; + bool dl_metrics_read; + ul_metrics_t ul_metrics; + uint32_t ul_metrics_count; + bool ul_metrics_read; + sync_metrics_t sync_metrics; + uint32_t sync_metrics_count; + bool sync_metrics_read; + + // MBSFN + bool sib13_configured; + bool mcch_configured; + uint32_t mch_period_stop; + uint8_t mch_table[40]; + uint8_t mcch_table[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); + + }; - /* Common variables used by all phy workers */ - phy_interface_rrc::phy_cfg_t *config; - phy_args_t *args; - rrc_interface_phy *rrc; - mac_interface_phy *mac; - - /* Power control variables */ - float pathloss; - float cur_pathloss; - float p0_preamble; - float cur_radio_power; - float cur_pusch_power; - float avg_rsrp; - float avg_rsrp_cqi; - float avg_rsrp_dbm; - float avg_rsrp_sync_dbm; - float avg_rsrq_db; - float avg_rssi_dbm; - float last_radio_rssi; - float rx_gain_offset; - float avg_snr_db_cqi; - float avg_snr_db_sync; - float avg_noise; - - uint32_t pcell_report_period; - - // Save last TBS for mcs>28 cases - int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS]; - uint32_t last_dl_tti[2*HARQ_DELAY_MS]; - - int last_ul_tbs[2*HARQ_DELAY_MS]; - uint32_t last_ul_tti[2*HARQ_DELAY_MS]; - srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS]; - - uint8_t last_ri; - uint8_t last_pmi; - - phch_common(uint32_t max_mutex = 3); - void init(phy_interface_rrc::phy_cfg_t *config, - phy_args_t *args, - srslte::log *_log, - srslte::radio *_radio, - rrc_interface_phy *rrc, - mac_interface_phy *_mac); - - /* For RNTI searches, -1 means now or forever */ - void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); - uint16_t get_ul_rnti(uint32_t tti); - srslte_rnti_type_t get_ul_rnti_type(); - - void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); - uint16_t get_dl_rnti(uint32_t tti); - srslte_rnti_type_t get_dl_rnti_type(); - - void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]); - bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL); - - void reset_pending_ack(uint32_t tti); - void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs); - bool get_pending_ack(uint32_t tti); - bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs); - bool is_any_pending_ack(); - - void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); - - void set_nof_mutex(uint32_t nof_mutex); - - bool sr_enabled; - int sr_last_tx_tti; - - srslte::radio* get_radio(); - - void set_cell(const srslte_cell_t &c); - uint32_t get_nof_prb(); - void set_dl_metrics(const dl_metrics_t &m); - void get_dl_metrics(dl_metrics_t &m); - void set_ul_metrics(const ul_metrics_t &m); - void get_ul_metrics(ul_metrics_t &m); - void set_sync_metrics(const sync_metrics_t &m); - void get_sync_metrics(sync_metrics_t &m); - - void reset_ul(); - void reset(); - -private: - - std::vector tx_mutex; - - bool is_first_of_burst; - srslte::radio *radio_h; - float cfo; - srslte::log *log_h; - - - bool ul_rnti_active(uint32_t tti); - bool dl_rnti_active(uint32_t tti); - uint16_t ul_rnti, dl_rnti; - srslte_rnti_type_t ul_rnti_type, dl_rnti_type; - int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end; - - float time_adv_sec; - - srslte_dci_rar_grant_t rar_grant; - bool rar_grant_pending; - uint32_t rar_grant_tti; - - typedef struct { - bool enabled; - uint32_t I_lowest; - uint32_t n_dmrs; - } pending_ack_t; - pending_ack_t pending_ack[TTIMOD_SZ]; - - bool is_first_tx; - - uint32_t nof_workers; - uint32_t nof_mutex; - uint32_t max_mutex; - - srslte_cell_t cell; - dl_metrics_t dl_metrics; - uint32_t dl_metrics_count; - bool dl_metrics_read; - ul_metrics_t ul_metrics; - uint32_t ul_metrics_count; - bool ul_metrics_read; - sync_metrics_t sync_metrics; - uint32_t sync_metrics_count; - bool sync_metrics_read; -}; } // namespace srsue diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 14687da73..ff167d20e 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -89,9 +89,10 @@ private: /* Internal methods */ - bool extract_fft_and_pdcch_llr(); - void compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr); + void compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr); + bool extract_fft_and_pdcch_llr(subframe_cfg_t sf_cfg); + /* ... for DL */ bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant); bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant); @@ -105,6 +106,11 @@ private: uint32_t pid, bool acks[SRSLTE_MAX_CODEWORDS]); + bool decode_pmch(srslte_ra_dl_grant_t *grant, + uint8_t *payload, + srslte_softbuffer_rx_t* softbuffer, + uint16_t mbsfn_area_id); + /* ... for UL */ void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer, uint32_t rv, uint16_t rnti, bool is_from_rar); diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index a1a7c2a66..e7661908b 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -128,7 +128,13 @@ public: void set_config_common(phy_cfg_common_t *common); void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd); void set_config_64qam_en(bool enable); - + void set_config_mbsfn_sib2(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); + void set_config_mbsfn_sib13(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13); + void set_config_mbsfn_mcch(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch); + + /*Set MAC->PHY MCH period stopping point*/ + void set_mch_period_stop(uint32_t stop); + float get_phr(); float get_pathloss_db(); diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index 120f2ee51..161d93244 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -26,6 +26,7 @@ #include #include +#include #include "srslte/srslte.h" #include "srsue/hdr/phy/phch_common.h" @@ -71,6 +72,8 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) reset(); + sib13_configured = false; + mcch_configured = false; } void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac) @@ -369,4 +372,172 @@ void phch_common::reset_ul() */ } +/* Convert 6-bit maps to 10-element subframe tables + bitmap = |0|0|0|0|0|0| + subframe index = |1|2|3|6|7|8| +*/ +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], config->mbsfn.mbsfn_subfr_cnfg.subfr_alloc,(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE == config->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] << "|"; + } + Info("MCH table: %s\n", ss.str().c_str()); +} + +void phch_common::build_mcch_table() +{ + // First reset tables + bzero(&mcch_table[0], sizeof(uint8_t)*10); + srslte::generate_mcch_table(&mcch_table[0], config->mbsfn.mbsfn_area_info.sf_alloc_info_r9); + // Debug + std::stringstream ss; + ss << "|"; + for(uint32_t j=0; j<10; j++) { + ss << (int) mcch_table[j] << "|"; + } + Info("MCCH table: %s\n", ss.str().c_str()); + sib13_configured = true; +} + +void phch_common::set_mcch() +{ + mcch_configured = true; +} + +void phch_common::set_mch_period_stop(uint32_t stop) +{ + pthread_mutex_lock(&mtch_mutex); + have_mtch_stop = true; + mch_period_stop = stop; + pthread_cond_signal(&mtch_cvar); + pthread_mutex_unlock(&mtch_mutex); + +} + +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_decode = false; + cfg->is_mcch = false; + // Check for MCCH + if(is_mcch_subframe(cfg, phy_tti)) { + cfg->is_mcch = true; + return true; + } + + // Not MCCH, check for MCH + LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *subfr_cnfg = &config->mbsfn.mbsfn_subfr_cnfg; + LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *area_info = &config->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 = &config->mbsfn.mcch; + uint32_t mbsfn_per_frame = mcch->pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9/mcch->pmch_infolist_r9[0].pmch_config_r9.mch_schedulingperiod_r9; + uint32_t frame_alloc_idx = sfn%liblte_rrc_mbsfn_common_sf_alloc_period_r9_num[mcch->commonsf_allocperiod_r9]; + uint32_t sf_alloc_idx = frame_alloc_idx*mbsfn_per_frame + ((sf<4)?sf-1:sf-3); + pthread_mutex_lock(&mtch_mutex); + while(!have_mtch_stop) { + pthread_cond_wait(&mtch_cvar, &mtch_mutex); + } + pthread_mutex_unlock(&mtch_mutex); + + for(uint32_t i=0; ipmch_infolist_r9_size; i++) { + if(sf_alloc_idx <= mch_period_stop) { + //trigger conditional variable, has ot be untriggered by mtch stop location + cfg->mbsfn_mcs = mcch->pmch_infolist_r9[i].pmch_config_r9.datamcs_r9; + cfg->mbsfn_decode = true; + } else { + //have_mtch_stop = false; + } + } + Debug("MCH subframe TTI:%d\n", phy_tti); + } + } + 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; +} + +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 = &config->mbsfn.mbsfn_subfr_cnfg; + LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *area_info = &config->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_decode = true; + have_mtch_stop = false; + Debug("MCCH subframe TTI:%d\n", phy_tti); + 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; + } +} + } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index d5c586fd7..94f8b7158 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -157,7 +157,11 @@ bool phch_worker::set_cell(srslte_cell_t cell_) Error("Initiating UE DL\n"); goto unlock; } - + + if(srslte_ue_dl_set_mbsfn_area_id(&ue_dl, 1)){ + Error("Setting mbsfn id\n"); + } + if (srslte_ue_ul_set_cell(&ue_ul, cell)) { Error("Initiating UE UL\n"); goto unlock; @@ -247,6 +251,10 @@ void phch_worker::work_imp() reset_uci(); + subframe_cfg_t sf_cfg; + phy->get_sf_config(&sf_cfg, tti); + Debug("TTI: %d, Subframe type: %s\n", tti, subframe_type_text[sf_cfg.sf_type]); + bool dl_grant_available = false; bool ul_grant_available = false; bool dl_ack[SRSLTE_MAX_CODEWORDS] = {false}; @@ -266,47 +274,100 @@ void phch_worker::work_imp() phy->avg_rssi_dbm = SRSLTE_VEC_EMA(rssi_dbm, phy->avg_rssi_dbm, phy->args->snr_ema_coeff); } - /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ - bool chest_ok = extract_fft_and_pdcch_llr(); + bool mch_decoded = false; + srslte_ra_dl_grant_t mch_grant; + // Call feedback loop for chest if (chest_loop && ((1<<(tti%10)) & phy->args->cfo_ref_mask)) { chest_loop->set_cfo(srslte_chest_dl_get_cfo(&ue_dl.chest)); } + bool chest_ok = false; + bool snr_th_ok = false; - if (chest_ok) { + /***** Downlink Processing *******/ + + + if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type) { + /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ + chest_ok = extract_fft_and_pdcch_llr(sf_cfg); + + snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0; - /***** Downlink Processing *******/ + if (chest_ok && snr_th_ok) { + + /***** Downlink Processing *******/ + + /* PDCCH DL + PDSCH */ + dl_grant_available = decode_pdcch_dl(&dl_mac_grant); + if(dl_grant_available) { + /* Send grant to MAC and get action for this TB */ + phy->mac->new_grant_dl(dl_mac_grant, &dl_action); + + /* Set DL ACKs to default */ + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + dl_ack[tb] = dl_action.default_ack[tb]; + } + + /* Decode PDSCH if instructed to do so */ + if (dl_action.decode_enabled[0] || dl_action.decode_enabled[1]) { + decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr, + dl_action.softbuffers, dl_action.rv, dl_action.rnti, + dl_mac_grant.pid, dl_ack); + } + if (dl_action.generate_ack_callback) { + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + if (dl_action.decode_enabled[tb]) { + phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); + dl_ack[tb] = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg); + Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack[tb]); + } + } + } + Debug("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack); + if (dl_action.generate_ack) { + set_uci_ack(dl_ack, dl_mac_grant.tb_en); + } + } + } + + } else if(SUBFRAME_TYPE_MBSFN == sf_cfg.sf_type) { + srslte_ue_dl_set_non_mbsfn_region(&ue_dl, sf_cfg.non_mbsfn_region_length); - /* PDCCH DL + PDSCH */ - dl_grant_available = decode_pdcch_dl(&dl_mac_grant); - if(dl_grant_available) { - /* Send grant to MAC and get action for this TB */ + /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ + if (extract_fft_and_pdcch_llr(sf_cfg)) { + + dl_grant_available = decode_pdcch_dl(&dl_mac_grant); phy->mac->new_grant_dl(dl_mac_grant, &dl_action); /* Set DL ACKs to default */ for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { dl_ack[tb] = dl_action.default_ack[tb]; - } - - /* Decode PDSCH if instructed to do so */ - if (dl_action.decode_enabled[0] || dl_action.decode_enabled[1]) { - decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr, - dl_action.softbuffers, dl_action.rv, dl_action.rnti, - dl_mac_grant.pid, dl_ack); - } - if (dl_action.generate_ack_callback) { - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (dl_action.decode_enabled[tb]) { - phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); - dl_ack[tb] = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg); - Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack[tb]); + } + if(sf_cfg.mbsfn_decode) { + + mch_grant.sf_type = SRSLTE_SF_MBSFN; + mch_grant.mcs[0].idx = sf_cfg.mbsfn_mcs; + mch_grant.tb_en[0] = true; + for(uint32_t i=1;imac->new_mch_dl(mch_grant, &dl_action); + srslte_softbuffer_rx_reset_tbs(dl_action.softbuffers[0], mch_grant.mcs[0].tbs); + Debug("TBS=%d, Softbuffer max_cb=%d\n", mch_grant.mcs[0].tbs, dl_action.softbuffers[0]->max_cb); + if(dl_action.decode_enabled[0]) { + mch_decoded = decode_pmch(&mch_grant, dl_action.payload_ptr[0], dl_action.softbuffers[0], sf_cfg.mbsfn_area_id); + } } } } @@ -390,21 +451,31 @@ void phch_worker::work_imp() phy->worker_end(tx_tti, signal_ready, &signal_ptr[-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time); } - if (!dl_action.generate_ack_callback) { - if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) { - if (dl_ack[0]) { - phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]); - } - } else if (!rar_delivered) { - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (dl_action.decode_enabled[tb]) { - phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); + if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type) { + if (!dl_action.generate_ack_callback) { + if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) { + if (dl_ack[0]) { + phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]); + } + } else if (!rar_delivered) { + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + if (dl_action.decode_enabled[tb]) { + phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); + } } } } + } else if (SUBFRAME_TYPE_MBSFN == sf_cfg.sf_type && sf_cfg.mbsfn_decode) { + if(mch_decoded) { + phy->mac->mch_decoded_ok(mch_grant.mcs[0].tbs/8); + } else if(sf_cfg.is_mcch) { + //release lock in phch_common + phy->set_mch_period_stop(0); + } + } + if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type){ + update_measurements(); } - - update_measurements(); if (chest_ok) { if (phy->avg_rsrp_sync_dbm > -130.0 && phy->avg_snr_db_sync > -10.0) { @@ -452,7 +523,9 @@ void phch_worker::compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr) { } } -bool phch_worker::extract_fft_and_pdcch_llr() { + + +bool phch_worker::extract_fft_and_pdcch_llr(subframe_cfg_t sf_cfg) { bool decode_pdcch = true; // Do always channel estimation to keep track of out-of-sync and send measurements to RRC @@ -471,18 +544,21 @@ bool phch_worker::extract_fft_and_pdcch_llr() { srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS); } - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) { - Error("Getting PDCCH FFT estimate\n"); - return false; - } - chest_done = true; - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) { - Error("Getting PDCCH FFT estimate\n"); - return false; - } + int decode_fft = 0; + if(SUBFRAME_TYPE_MBSFN == sf_cfg.sf_type) { + srslte_ue_dl_set_non_mbsfn_region(&ue_dl, sf_cfg.non_mbsfn_region_length); + decode_fft = srslte_ue_dl_decode_fft_estimate_mbsfn(&ue_dl, tti%10, &cfi, SRSLTE_SF_MBSFN); + }else{ + decode_fft = srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi); + } + if (decode_fft < 0) { + Error("Getting PDCCH FFT estimate\n"); + return false; + } + + chest_done = true; - chest_done = true; if (chest_done && decode_pdcch) { /* and not in DRX mode */ @@ -748,6 +824,73 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL return ret; } +bool phch_worker::decode_pmch(srslte_ra_dl_grant_t *grant, uint8_t *payload, + srslte_softbuffer_rx_t* softbuffer, uint16_t mbsfn_area_id) +{ + char timestr[64]; + timestr[0]='\0'; + + Debug("DL Buffer TTI %d: Decoding PMCH\n", tti); + /* Setup PMCH configuration */ + srslte_ue_dl_set_mbsfn_area_id(&ue_dl, mbsfn_area_id); + + if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, SRSLTE_PMCH_RV, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA)) { + if (ue_dl.pmch_cfg.grant.mcs[0].mod > 0 && ue_dl.pmch_cfg.grant.mcs[0].tbs >= 0) { + + Debug("Decoding PMCH SF: %d, MBSFN area ID: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d, cfi=%d\n", + ue_dl.pmch_cfg.sf_idx, mbsfn_area_id, srslte_mod_string(ue_dl.pmch_cfg.grant.mcs[0].mod), ue_dl.pmch_cfg.grant.mcs[0].tbs, ue_dl.pmch_cfg.nbits[0].nof_re, + ue_dl.pmch_cfg.nbits[0].nof_bits, 0, ue_dl.pmch_cfg.grant.nof_prb, ue_dl.pmch_cfg.nbits[0].lstart-1); + + float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); + + if (!phy->args->equalizer_mode.compare("zf")) { + noise_estimate = 0; + } + + /* Set decoder iterations */ + // TODO: Add separate arg for pmch_max_its + if (phy->args->pdsch_max_its > 0) { + srslte_sch_set_max_noi(&ue_dl.pmch.dl_sch, phy->args->pdsch_max_its); + } + +#ifdef LOG_EXECTIME + struct timeval t[3]; + gettimeofday(&t[1], NULL); +#endif + + bool ack = srslte_pmch_decode_multi(&ue_dl.pmch, &ue_dl.pmch_cfg, softbuffer, ue_dl.sf_symbols_m, + ue_dl.ce_m, noise_estimate, mbsfn_area_id, payload) == 0; + +#ifdef LOG_EXECTIME + gettimeofday(&t[2], NULL); + get_time_interval(t); + snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); +#endif + + Info("PMCH: l_crb=%2d, tbs=%d, mcs=%d, crc=%s, snr=%.1f dB, n_iter=%d%s\n", + grant->nof_prb, + grant->mcs[0].tbs/8, grant->mcs[0].idx, + ack?"OK":"KO", + 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), + srslte_pmch_last_noi(&ue_dl.pmch), + timestr); + + //printf("tti=%d, cfo=%f\n", tti, cfo*15000); + //srslte_vec_save_file("pdsch", signal_buffer, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); + + // Store metrics + //dl_metrics.mcs = grant->mcs.idx; + + return ack; + } else { + Warning("Received grant for TBS=0\n"); + } + } else { + Error("Error configuring DL grant\n"); + } + return true; +} + bool phch_worker::decode_phich(bool *ack) { uint32_t I_lowest, n_dmrs; diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index bf8ccffaa..3cdfcd8da 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -437,4 +437,40 @@ void phy::set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT* tdd) memcpy(&config.common.tdd_cnfg, tdd, sizeof(LIBLTE_RRC_TDD_CONFIG_STRUCT)); } +void phy::set_config_mbsfn_sib2(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) +{ + 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(&config.mbsfn.mbsfn_subfr_cnfg, &sib2->mbsfn_subfr_cnfg_list[0], sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT)); + workers_common.build_mch_table(); + } +} + +void phy::set_config_mbsfn_sib13(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13) +{ + memcpy(&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(&config.mbsfn.mbsfn_area_info, &sib13->mbsfn_area_info_list_r9[0], sizeof(LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT)); + workers_common.build_mcch_table(); + } +} + +void phy::set_config_mbsfn_mcch(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch) +{ + memcpy(&config.mbsfn.mcch, mcch, sizeof(LIBLTE_RRC_MCCH_MSG_STRUCT)); + mac->set_mbsfn_config(config.mbsfn.mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size); + workers_common.set_mch_period_stop(config.mbsfn.mcch.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9); + workers_common.set_mcch(); +} + +void phy::set_mch_period_stop(uint32_t stop) +{ + workers_common.set_mch_period_stop(stop); +} + }