Mbms fixes (#225)

* fixing the threading structure for mbms in the gtpu

fixing some leaks in pmch tests

fixing stack overflow caused by radio objext

* adding sib.conf.mbsfn.example

* creating a different thread_mch object for the gtpu

* Make mch_thread an isolated class

* excluding mbsfn subframes from noise estimation and cfo estimation

* fixing pdsch ue plotting to only show pmch constellation when mbsfn is activated.
This commit is contained in:
jctallon 2018-07-02 17:51:09 +02:00 committed by Ismael Gomez
parent 0321a967f2
commit 50589108c6
9 changed files with 347 additions and 152 deletions

View File

@ -67,6 +67,7 @@ pthread_t plot_thread;
sem_t plot_sem;
uint32_t plot_sf_idx=0;
bool plot_track = true;
bool enable_mbsfn_plot = false;
#endif
char *output_file_name;
#define PRINT_CHANGE_SCHEDULIGN
@ -363,6 +364,12 @@ int main(int argc, char **argv) {
parse_args(&prog_args, argc, argv);
#ifndef DISABLE_GRAPHICS
if(prog_args.mbsfn_area_id > -1) {
enable_mbsfn_plot = true;
}
#endif
for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) {
data[i] = srslte_vec_malloc(sizeof(uint8_t)*1500*8);
if (!data[i]) {
@ -981,14 +988,14 @@ void *plot_thread_run(void *arg) {
plot_scatter_addToWindowGrid(&pscatequal, (char*)"pdsch_ue", 0, 0);
if(enable_mbsfn_plot) {
plot_scatter_init(&pscatequal_pmch);
plot_scatter_setTitle(&pscatequal_pmch, "PMCH - Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal_pmch, -4, 4);
plot_scatter_setYAxisScale(&pscatequal_pmch, -4, 4);
plot_scatter_addToWindowGrid(&pscatequal_pmch, (char*)"pdsch_ue", 0, 1);
}
plot_scatter_init(&pscatequal_pmch);
plot_scatter_setTitle(&pscatequal_pmch, "PMCH - Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal_pmch, -4, 4);
plot_scatter_setYAxisScale(&pscatequal_pmch, -4, 4);
plot_scatter_addToWindowGrid(&pscatequal_pmch, (char*)"pdsch_ue", 0, 1);
if (!prog_args.disable_plots_except_constellation) {
plot_real_init(&pce);
plot_real_setTitle(&pce, "Channel Response - Magnitude");
@ -1004,7 +1011,7 @@ void *plot_thread_run(void *arg) {
plot_scatter_setXAxisScale(&pscatequal_pdcch, -4, 4);
plot_scatter_setYAxisScale(&pscatequal_pdcch, -4, 4);
plot_real_addToWindowGrid(&pce, (char*)"pdsch_ue", 0, 2);
plot_real_addToWindowGrid(&pce, (char*)"pdsch_ue", 0, (enable_mbsfn_plot)?2:1);
plot_real_addToWindowGrid(&pscatequal_pdcch, (char*)"pdsch_ue", 1, 0);
plot_real_addToWindowGrid(&p_sync, (char*)"pdsch_ue", 1, 1);
}
@ -1057,7 +1064,10 @@ void *plot_thread_run(void *arg) {
plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d[0], nof_symbols);
plot_scatter_setNewData(&pscatequal_pmch, ue_dl.pmch.d, nof_symbols_pmch);
if(enable_mbsfn_plot) {
plot_scatter_setNewData(&pscatequal_pmch, ue_dl.pmch.d, nof_symbols_pmch);
}
if (plot_sf_idx == 1) {
if (prog_args.net_port_signal > 0) {
srslte_netsink_write(&net_sink_signal, &sf_buffer[srslte_ue_sync_sf_len(&ue_sync)/7],

View File

@ -53,6 +53,7 @@ class radio {
radio() : tr_local_time(1024 * 10), tr_usrp_time(1024 * 10), tr_tx_time(1024 * 10), tr_is_eob(1024 * 10) {
bzero(&rf_device, sizeof(srslte_rf_t));
bzero(&end_of_burst_time, sizeof(srslte_timestamp_t));
zeros = (cf_t *) srslte_vec_malloc(burst_preamble_max_samples * sizeof (cf_t));
bzero(zeros, burst_preamble_max_samples * sizeof(cf_t));
burst_preamble_sec = 0;
@ -145,7 +146,7 @@ class radio {
bool is_start_of_burst;
uint32_t burst_preamble_samples;
double burst_preamble_time_rounded; // preamble time rounded to sample time
cf_t zeros[burst_preamble_max_samples];
cf_t *zeros;
double cur_tx_srate;
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay

View File

@ -603,12 +603,12 @@ float chest_estimate_cfo(srslte_chest_dl_t *q)
}
void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, srslte_sf_t ch_mode){
if (q->cfo_estimate_enable && ((1<<sf_idx) & q->cfo_estimate_sf_mask)) {
if (q->cfo_estimate_enable && ((1<<sf_idx) & q->cfo_estimate_sf_mask) && ch_mode != SRSLTE_SF_MBSFN ) {
q->cfo = chest_estimate_cfo(q);
}
/* Estimate noise */
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS) {
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && ch_mode != SRSLTE_SF_MBSFN ) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode);
}

View File

@ -259,7 +259,7 @@ int main(int argc, char **argv) {
for (i = 0; i < cell.nof_ports; i++) {
tx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
bzero(tx_sf_symbols[i],sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
if (srslte_ofdm_tx_init_mbsfn(&ifft_mbsfn[i], SRSLTE_CP_EXT, tx_slot_symbols[i], tx_sf_symbols[i], cell.nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);
@ -271,7 +271,7 @@ int main(int argc, char **argv) {
for (i = 0; i < nof_rx_antennas; i++) {
rx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
bzero(rx_sf_symbols[i],sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
if (srslte_ofdm_rx_init_mbsfn(&fft_mbsfn[i], SRSLTE_CP_EXT, rx_sf_symbols[i], rx_slot_symbols[i], cell.nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);

View File

@ -81,6 +81,9 @@ bool radio::is_init() {
void radio::stop()
{
if (zeros) {
free(zeros);
}
if (is_initialized) {
srslte_rf_close(&rf_device);
}

View File

@ -34,7 +34,8 @@ n_prb = 50
#####################################################################
# eNB configuration files
#
# sib_config: SIB1, SIB2 and SIB3 configuration file
# sib_config: SIB1, SIB2 and SIB3 configuration file
# note: when enabling mbms, use the sib.conf.mbsfn configuration file which includes SIB13
# rr_config: Radio Resources configuration file
# drb_config: DRB configuration file
#####################################################################

View File

@ -37,6 +37,7 @@
#ifndef SRSENB_GTPU_H
#define SRSENB_GTPU_H
namespace srsenb {
/****************************************************************************
@ -64,6 +65,7 @@ typedef struct{
uint32_t teid;
}gtpu_header_t;
class gtpu
:public gtpu_interface_rrc
,public gtpu_interface_pdcp
@ -71,6 +73,8 @@ class gtpu
{
public:
gtpu();
bool init(std::string gtp_bind_addr_, std::string mme_addr_, pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_, bool enable_mbsfn = false);
void stop();
@ -82,7 +86,6 @@ public:
// gtpu_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *pdu);
private:
static const int THREAD_PRIO = 65;
static const int GTPU_PORT = 2152;
@ -90,14 +93,39 @@ private:
bool running;
bool run_enable;
bool mch_running;
bool mch_run_enable;
bool _enable_mbsfn;
bool enable_mbsfn;
std::string gtp_bind_addr;
std::string mme_addr;
srsenb::pdcp_interface_gtpu *pdcp;
srslte::log *gtpu_log;
pthread_t mch_thread;
// Class to create
class mch_thread : public thread {
public:
mch_thread() : initiated(false),running(false),run_enable(false),pool(NULL) {}
bool init(pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_);
void stop();
private:
void run_thread();
bool initiated;
bool running;
bool run_enable;
static const int MCH_THREAD_PRIO = 65;
pdcp_interface_gtpu *pdcp;
srslte::log *gtpu_log;
int m1u_sd;
int lcid_counter;
srslte::byte_buffer_pool *pool;
};
// MCH thread insteance
mch_thread mchthread;
typedef struct{
uint32_t teids_in[SRSENB_N_RADIO_BEARERS];
@ -109,22 +137,10 @@ private:
// Socket file descriptors
int snk_fd;
int src_fd;
int m1u_sd;
//Init functions
bool init_m1u(srslte::log *gtpu_log_);
//Threading
void run_thread();
void run_mch_thread();
int mch_lcid_counter;
static void *mch_thread_routine(void *_this)
{
((srsenb::gtpu*)_this)->run_mch_thread();
return _this;
}
pthread_mutex_t mutex;
/****************************************************************************

View File

@ -0,0 +1,153 @@
sib1 =
{
intra_freq_reselection = "Allowed";
q_rx_lev_min = -130;
//p_max = 3;
cell_barred = "Not Barred"
si_window_length = 20;
sched_info =
(
{
si_periodicity = 16;
si_mapping_info = [13]; // comma-separated array of SIB-indexes (from 3 to 13).
// Leave empty or commented to just scheduler sib2
}
);
system_info_value_tag = 0;
};
sib2 =
{
rr_config_common_sib =
{
rach_cnfg =
{
num_ra_preambles = 52;
preamble_init_rx_target_pwr = -108;
pwr_ramping_step = 6; // in dB
preamble_trans_max = 7;
ra_resp_win_size = 10; // in ms
mac_con_res_timer = 64; // in ms
max_harq_msg3_tx = 4;
};
bcch_cnfg =
{
modification_period_coeff = 16; // in ms
};
pcch_cnfg =
{
default_paging_cycle = 32; // in rf
nB = "1";
};
prach_cnfg =
{
root_sequence_index = 128;
prach_cnfg_info =
{
high_speed_flag = false;
prach_config_index = 3;
prach_freq_offset = 0;
zero_correlation_zone_config = 11;
};
};
pdsch_cnfg =
{
p_b = 0;
rs_power = -4;
};
pusch_cnfg =
{
n_sb = 1;
hopping_mode = "inter-subframe";
pusch_hopping_offset = 2;
enable_64_qam = false;
ul_rs =
{
cyclic_shift = 0;
group_assignment_pusch = 0;
group_hopping_enabled = false;
sequence_hopping_enabled = false;
};
};
pucch_cnfg =
{
delta_pucch_shift = 1;
n_rb_cqi = 1;
n_cs_an = 0;
n1_pucch_an = 2;
};
ul_pwr_ctrl =
{
p0_nominal_pusch = -108;
alpha = 1.0;
p0_nominal_pucch = -88;
delta_flist_pucch =
{
format_1 = 2;
format_1b = 3;
format_2 = 0;
format_2a = 0;
format_2b = 0;
};
delta_preamble_msg3 = 4;
};
ul_cp_length = "Normal";
};
ue_timers_and_constants =
{
t300 = 2000; // in ms
t301 = 100; // in ms
t310 = 1000; // in ms
n310 = 1;
t311 = 1000; // in ms
n311 = 1;
};
freqInfo =
{
ul_carrier_freq_present = true;
ul_bw_present = true;
additional_spectrum_emission = 1;
};
mbsfnSubframeConfigList =
{
radioframeAllocationPeriod = "1";
subframeAllocationNumFrames = "1";
radioframeAllocationOffset = 0;
subframeAllocation = 63;
};
mbsfnSubframeConfigListLength = 1;
time_alignment_timer = "INFINITY"; // use "sf500", "sf750", etc.
};
sib13 =
{
mbsfn_notification_config =
{
mbsfn_notification_repetition_coeff = "2";
mbsfn_notification_offset = 0;
mbsfn_notification_sf_index = 1;
};
mbsfn_area_info_list_size = 1;
mbsfn_area_info_list =
{
non_mbsfn_region_length = "2";
mcch_repetition_period = "64";
mcch_modification_period = "512";
signalling_mcs = "2";
mbsfn_area_id = 1;
notification_indicator = 0;
mcch_offset = 0;
sf_alloc_info = 32;
};
};

View File

@ -34,6 +34,10 @@ using namespace srslte;
namespace srsenb {
gtpu::gtpu():mchthread()
{
}
bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_interface_gtpu* pdcp_, srslte::log* gtpu_log_, bool enable_mbsfn)
{
pdcp = pdcp_;
@ -89,127 +93,26 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
return false;
}
//Setup M1-u
init_m1u(gtpu_log_);
_enable_mbsfn = enable_mbsfn;
// Setup a thread to receive packets from the src socket
start(THREAD_PRIO);
if(_enable_mbsfn){
mch_lcid_counter = 1;
pthread_create(&mch_thread ,NULL ,mch_thread_routine , this);
// Start MCH thread if enabled
this->enable_mbsfn = enable_mbsfn;
if(enable_mbsfn) {
mchthread.init(pdcp, gtpu_log);
}
return true;
}
bool gtpu::init_m1u(srslte::log* gtpu_log_)
{
struct sockaddr_in bindaddr;
// Set up sink socket
m1u_sd = socket(AF_INET, SOCK_DGRAM, 0);
if (m1u_sd < 0) {
gtpu_log->error("Failed to create M1-U sink socket\n");
return false;
}
/* Bind socket */
bzero((char *)&bindaddr, sizeof(struct sockaddr_in));
bindaddr.sin_family = AF_INET;
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); //Multicast sockets require bind to INADDR_ANY
bindaddr.sin_port = htons(GTPU_PORT+1);
size_t addrlen = sizeof(bindaddr);
if (bind(m1u_sd, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) < 0) {
gtpu_log->error("Failed to bind multicast socket\n");
return false;
}
/* Send an ADD MEMBERSHIP message via setsockopt */
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("239.255.0.1"); //Multicast address of the service
mreq.imr_interface.s_addr = inet_addr("127.0.1.200"); //Address of the IF the socket will listen to.
if (setsockopt(m1u_sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
gtpu_log->error("Register musticast group for M1-U\n");
return false;
}
gtpu_log->info("M1-U initialized\n");
return true;
}
void gtpu::run_mch_thread()
{
byte_buffer_t *pdu;
mch_run_enable = true;
int n;
socklen_t addrlen;
sockaddr_in src_addr;
bzero((char *)&src_addr, sizeof(src_addr));
src_addr.sin_family = AF_INET;
src_addr.sin_addr.s_addr = htonl(INADDR_ANY);
src_addr.sin_port = htons(GTPU_PORT+1);
addrlen = sizeof(src_addr);
pdu = pool->allocate();
mch_running=true;
pthread_mutex_lock(&mutex);
uint16_t lcid = mch_lcid_counter;
mch_lcid_counter++;
pthread_mutex_unlock(&mutex);
while(mch_run_enable) {
pdu->reset();
do{
n = recvfrom(m1u_sd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0, (struct sockaddr *) &src_addr, &addrlen);
} while (n == -1 && errno == EAGAIN);
pdu->N_bytes = (uint32_t) n;
gtpu_header_t header;
gtpu_read_header(pdu, &header);
uint16_t rnti = 0xFFFD;
pthread_mutex_lock(&mutex);
bool user_exists = (rnti_bearers.count(rnti) > 0);
pthread_mutex_unlock(&mutex);
if(!user_exists) {
gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti);
continue;
}
if(lcid == 0 || lcid >= SRSENB_N_RADIO_BEARERS) {
gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid);
continue;
}
pdcp->write_sdu(rnti, lcid, pdu);
do {
pdu = pool_allocate;
if (!pdu) {
gtpu_log->console("GTPU Buffer pool empty. Trying again...\n");
usleep(10000);
}
} while(!pdu);
}
mch_running=false;
}
void gtpu::stop()
{
if(enable_mbsfn){
mchthread.stop();
}
if (run_enable) {
run_enable = false;
if(mch_run_enable) {
mch_run_enable = false;
}
// Wait thread to exit gracefully otherwise might leave a mutex locked
int cnt=0;
while(running && cnt<100) {
@ -218,16 +121,10 @@ void gtpu::stop()
}
if (running) {
thread_cancel();
if(mch_running) {
pthread_cancel(mch_thread);
}
}
wait_thread_finish();
if(_enable_mbsfn) {
pthread_join(mch_thread, NULL);
}
}
if (snk_fd) {
close(snk_fd);
}
@ -332,7 +229,6 @@ void gtpu::run_thread()
pdu->N_bytes = (uint32_t) n;
gtpu_header_t header;
gtpu_read_header(pdu, &header);
@ -366,7 +262,7 @@ void gtpu::run_thread()
}
} while(!pdu);
}
running=false;
running = false;
}
/****************************************************************************
@ -446,4 +342,119 @@ void gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t *teidin)
*teidin = (rnti << 16) | lcid;
}
/****************************************************************************
* Class to run the MCH thread
***************************************************************************/
bool gtpu::mch_thread::init(pdcp_interface_gtpu *pdcp, srslte::log *gtpu_log)
{
pool = byte_buffer_pool::get_instance();
this->pdcp = pdcp;
this->gtpu_log = gtpu_log;
struct sockaddr_in bindaddr;
// Set up sink socket
m1u_sd = socket(AF_INET, SOCK_DGRAM, 0);
if (m1u_sd < 0) {
gtpu_log->error("Failed to create M1-U sink socket\n");
return false;
}
/* Bind socket */
bzero((char *)&bindaddr, sizeof(struct sockaddr_in));
bindaddr.sin_family = AF_INET;
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); //Multicast sockets require bind to INADDR_ANY
bindaddr.sin_port = htons(GTPU_PORT+1);
size_t addrlen = sizeof(bindaddr);
if (bind(m1u_sd, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) < 0) {
gtpu_log->error("Failed to bind multicast socket\n");
return false;
}
/* Send an ADD MEMBERSHIP message via setsockopt */
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("239.255.0.1"); //Multicast address of the service
mreq.imr_interface.s_addr = inet_addr("127.0.1.200"); //Address of the IF the socket will listen to.
if (setsockopt(m1u_sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
gtpu_log->error("Register musticast group for M1-U\n");
return false;
}
gtpu_log->info("M1-U initialized\n");
initiated = true;
lcid_counter = 1;
// Start thread
start(MCH_THREAD_PRIO);
return true;
}
void gtpu::mch_thread::run_thread()
{
if (!initiated) {
fprintf(stderr, "Fatal error running mch_thread without initialization\n");
return;
}
byte_buffer_t *pdu;
int n;
socklen_t addrlen;
sockaddr_in src_addr;
bzero((char *)&src_addr, sizeof(src_addr));
src_addr.sin_family = AF_INET;
src_addr.sin_addr.s_addr = htonl(INADDR_ANY);
src_addr.sin_port = htons(GTPU_PORT+1);
addrlen = sizeof(src_addr);
run_enable = true;
running=true;
pdu = pool->allocate();
// Warning: Use mutex here if creating multiple services each with a different thread
uint16_t lcid = lcid_counter;
lcid_counter++;
while(run_enable) {
pdu->reset();
do{
n = recvfrom(m1u_sd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0, (struct sockaddr *) &src_addr, &addrlen);
} while (n == -1 && errno == EAGAIN);
pdu->N_bytes = (uint32_t) n;
pdcp->write_sdu(SRSLTE_MRNTI, lcid, pdu);
do {
pdu = pool_allocate;
if (!pdu) {
gtpu_log->console("GTPU Buffer pool empty. Trying again...\n");
usleep(10000);
}
} while(!pdu);
}
running = false;
}
void gtpu::mch_thread::stop()
{
if (run_enable) {
run_enable = false;
// Wait thread to exit gracefully otherwise might leave a mutex locked
int cnt = 0;
while(running && cnt < 100) {
usleep(10000);
cnt++;
}
if (running) {
thread_cancel();
}
wait_thread_finish();
}
}
} // namespace srsenb