adding PHY embms support to the UE

This commit is contained in:
yagoda 2018-05-15 17:16:28 +02:00
parent 84f4996584
commit e35672e234
6 changed files with 581 additions and 166 deletions

View File

@ -27,6 +27,9 @@
#ifndef SRSUE_PHCH_COMMON_H
#define SRSUE_PHCH_COMMON_H
#define TX_MODE_CONTINUOUS 1
#include <pthread.h>
#include <string.h>
#include <vector>
@ -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;
/* 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;
float avg_noise;
bool pcell_meas_enabled;
/* 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;
bool pcell_first_measurement;
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];
// 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;
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];
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);
uint8_t last_ri;
uint8_t last_pmi;
/* 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();
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);
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();
/* 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_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 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 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 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 worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
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 set_nof_mutex(uint32_t nof_mutex);
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<pthread_mutex_t> tx_mutex;
bool is_first_of_burst;
srslte::radio *radio_h;
float cfo;
srslte::log *log_h;
bool sr_enabled;
int sr_last_tx_tti;
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;
srslte::radio* get_radio();
float time_adv_sec;
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);
srslte_dci_rar_grant_t rar_grant;
bool rar_grant_pending;
uint32_t rar_grant_tti;
void reset_ul();
void reset();
typedef struct {
bool enabled;
uint32_t I_lowest;
uint32_t n_dmrs;
} pending_ack_t;
pending_ack_t pending_ack[TTIMOD_SZ];
// 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;
bool is_first_tx;
std::vector<pthread_mutex_t> tx_mutex;
uint32_t nof_workers;
uint32_t nof_mutex;
uint32_t max_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);
};
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

View File

@ -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);

View File

@ -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();

View File

@ -26,6 +26,7 @@
#include <assert.h>
#include <string.h>
#include <sstream>
#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; i<mcch->pmch_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;
}
}
}

View File

@ -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);
/***** Downlink Processing *******/
snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0;
/* 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 */
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);
/* 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;i<SRSLTE_MAX_CODEWORDS;i++) {
mch_grant.tb_en[i] = false;
}
mch_grant.nof_prb = ue_dl.pmch.cell.nof_prb;
srslte_dl_fill_ra_mcs(&mch_grant.mcs[0], mch_grant.nof_prb);
for(int j = 0; j < 2; j++){
for(uint32_t f = 0; f < mch_grant.nof_prb; f++){
mch_grant.prb_idx[j][f] = true;
}
}
}
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);
mch_grant.Qm[0] = srslte_mod_bits_x_symbol(mch_grant.mcs[0].mod);
/* Get MCH action for this TB */
phy->mac->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;

View File

@ -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);
}
}