introducing support for embms in the enodeb PHY

master
yagoda 7 years ago
parent d80d49a9da
commit 08976bb948

@ -30,12 +30,12 @@
#include <map>
#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 <string.h>
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:
@ -120,6 +140,12 @@ public:
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<pthread_mutex_t> tx_mutex;
bool is_first_tx;
@ -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

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

@ -63,6 +63,9 @@ public:
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<phch_worker> workers;
phch_common workers_common;

@ -26,7 +26,7 @@
#include "srslte/common/threads.h"
#include "srslte/common/log.h"
#include <sstream>
#include "srsenb/hdr/phy/txrx.h"
#include <assert.h>
@ -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; i<mcch->pmch_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;
}
}
}

@ -141,6 +141,13 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_)
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);
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);
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);
// 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;i<dl_grants[t_tx_dl].nof_grants;i++) {
// SI-RNTI and RAR-RNTI do not have ACK
uint16_t rnti = dl_grants[t_tx_dl].sched_grants[i].rnti;
@ -426,7 +457,11 @@ void phch_worker::work_imp()
}
// Generate signal and transmit
srslte_enb_dl_gen_signal(&enb_dl);
if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) {
srslte_enb_dl_gen_signal(&enb_dl);
} else {
srslte_enb_dl_gen_signal_mbsfn(&enb_dl);
}
Debug("Sending to radio\n");
phy->worker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time);
@ -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) */

@ -95,7 +95,9 @@ bool phy::init(phy_args_t *args,
mac_interface_phy *mac,
srslte::log_filter* log_h)
{
std::vector<srslte::log_filter*> log_vec;
this->log_h = log_h;
for (int i=0;i<args->nof_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();

Loading…
Cancel
Save