mirror of https://github.com/PentHertz/srsLTE.git
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:
parent
0321a967f2
commit
50589108c6
|
@ -67,6 +67,7 @@ pthread_t plot_thread;
|
||||||
sem_t plot_sem;
|
sem_t plot_sem;
|
||||||
uint32_t plot_sf_idx=0;
|
uint32_t plot_sf_idx=0;
|
||||||
bool plot_track = true;
|
bool plot_track = true;
|
||||||
|
bool enable_mbsfn_plot = false;
|
||||||
#endif
|
#endif
|
||||||
char *output_file_name;
|
char *output_file_name;
|
||||||
#define PRINT_CHANGE_SCHEDULIGN
|
#define PRINT_CHANGE_SCHEDULIGN
|
||||||
|
@ -363,6 +364,12 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
parse_args(&prog_args, argc, 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++) {
|
for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) {
|
||||||
data[i] = srslte_vec_malloc(sizeof(uint8_t)*1500*8);
|
data[i] = srslte_vec_malloc(sizeof(uint8_t)*1500*8);
|
||||||
if (!data[i]) {
|
if (!data[i]) {
|
||||||
|
@ -981,13 +988,13 @@ void *plot_thread_run(void *arg) {
|
||||||
plot_scatter_addToWindowGrid(&pscatequal, (char*)"pdsch_ue", 0, 0);
|
plot_scatter_addToWindowGrid(&pscatequal, (char*)"pdsch_ue", 0, 0);
|
||||||
|
|
||||||
|
|
||||||
|
if(enable_mbsfn_plot) {
|
||||||
plot_scatter_init(&pscatequal_pmch);
|
plot_scatter_init(&pscatequal_pmch);
|
||||||
plot_scatter_setTitle(&pscatequal_pmch, "PMCH - Equalized Symbols");
|
plot_scatter_setTitle(&pscatequal_pmch, "PMCH - Equalized Symbols");
|
||||||
plot_scatter_setXAxisScale(&pscatequal_pmch, -4, 4);
|
plot_scatter_setXAxisScale(&pscatequal_pmch, -4, 4);
|
||||||
plot_scatter_setYAxisScale(&pscatequal_pmch, -4, 4);
|
plot_scatter_setYAxisScale(&pscatequal_pmch, -4, 4);
|
||||||
|
|
||||||
plot_scatter_addToWindowGrid(&pscatequal_pmch, (char*)"pdsch_ue", 0, 1);
|
plot_scatter_addToWindowGrid(&pscatequal_pmch, (char*)"pdsch_ue", 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (!prog_args.disable_plots_except_constellation) {
|
if (!prog_args.disable_plots_except_constellation) {
|
||||||
plot_real_init(&pce);
|
plot_real_init(&pce);
|
||||||
|
@ -1004,7 +1011,7 @@ void *plot_thread_run(void *arg) {
|
||||||
plot_scatter_setXAxisScale(&pscatequal_pdcch, -4, 4);
|
plot_scatter_setXAxisScale(&pscatequal_pdcch, -4, 4);
|
||||||
plot_scatter_setYAxisScale(&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(&pscatequal_pdcch, (char*)"pdsch_ue", 1, 0);
|
||||||
plot_real_addToWindowGrid(&p_sync, (char*)"pdsch_ue", 1, 1);
|
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, ue_dl.pdsch.d[0], nof_symbols);
|
||||||
|
|
||||||
|
if(enable_mbsfn_plot) {
|
||||||
plot_scatter_setNewData(&pscatequal_pmch, ue_dl.pmch.d, nof_symbols_pmch);
|
plot_scatter_setNewData(&pscatequal_pmch, ue_dl.pmch.d, nof_symbols_pmch);
|
||||||
|
}
|
||||||
|
|
||||||
if (plot_sf_idx == 1) {
|
if (plot_sf_idx == 1) {
|
||||||
if (prog_args.net_port_signal > 0) {
|
if (prog_args.net_port_signal > 0) {
|
||||||
srslte_netsink_write(&net_sink_signal, &sf_buffer[srslte_ue_sync_sf_len(&ue_sync)/7],
|
srslte_netsink_write(&net_sink_signal, &sf_buffer[srslte_ue_sync_sf_len(&ue_sync)/7],
|
||||||
|
|
|
@ -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) {
|
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(&rf_device, sizeof(srslte_rf_t));
|
||||||
bzero(&end_of_burst_time, sizeof(srslte_timestamp_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));
|
bzero(zeros, burst_preamble_max_samples * sizeof(cf_t));
|
||||||
|
|
||||||
burst_preamble_sec = 0;
|
burst_preamble_sec = 0;
|
||||||
|
@ -145,7 +146,7 @@ class radio {
|
||||||
bool is_start_of_burst;
|
bool is_start_of_burst;
|
||||||
uint32_t burst_preamble_samples;
|
uint32_t burst_preamble_samples;
|
||||||
double burst_preamble_time_rounded; // preamble time rounded to sample time
|
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 cur_tx_srate;
|
||||||
|
|
||||||
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay
|
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay
|
||||||
|
|
|
@ -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){
|
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);
|
q->cfo = chest_estimate_cfo(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Estimate noise */
|
/* 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);
|
q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -259,7 +259,7 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
for (i = 0; i < cell.nof_ports; i++) {
|
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));
|
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)) {
|
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");
|
fprintf(stderr, "Error creating iFFT object\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
@ -271,7 +271,7 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
for (i = 0; i < nof_rx_antennas; i++) {
|
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));
|
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)) {
|
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");
|
fprintf(stderr, "Error creating iFFT object\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
|
|
@ -81,6 +81,9 @@ bool radio::is_init() {
|
||||||
|
|
||||||
void radio::stop()
|
void radio::stop()
|
||||||
{
|
{
|
||||||
|
if (zeros) {
|
||||||
|
free(zeros);
|
||||||
|
}
|
||||||
if (is_initialized) {
|
if (is_initialized) {
|
||||||
srslte_rf_close(&rf_device);
|
srslte_rf_close(&rf_device);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ n_prb = 50
|
||||||
# eNB configuration files
|
# 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
|
# rr_config: Radio Resources configuration file
|
||||||
# drb_config: DRB configuration file
|
# drb_config: DRB configuration file
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#ifndef SRSENB_GTPU_H
|
#ifndef SRSENB_GTPU_H
|
||||||
#define SRSENB_GTPU_H
|
#define SRSENB_GTPU_H
|
||||||
|
|
||||||
|
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -64,6 +65,7 @@ typedef struct{
|
||||||
uint32_t teid;
|
uint32_t teid;
|
||||||
}gtpu_header_t;
|
}gtpu_header_t;
|
||||||
|
|
||||||
|
|
||||||
class gtpu
|
class gtpu
|
||||||
:public gtpu_interface_rrc
|
:public gtpu_interface_rrc
|
||||||
,public gtpu_interface_pdcp
|
,public gtpu_interface_pdcp
|
||||||
|
@ -71,6 +73,8 @@ class gtpu
|
||||||
{
|
{
|
||||||
public:
|
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);
|
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();
|
void stop();
|
||||||
|
|
||||||
|
@ -82,7 +86,6 @@ public:
|
||||||
// gtpu_interface_pdcp
|
// gtpu_interface_pdcp
|
||||||
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *pdu);
|
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *pdu);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int THREAD_PRIO = 65;
|
static const int THREAD_PRIO = 65;
|
||||||
static const int GTPU_PORT = 2152;
|
static const int GTPU_PORT = 2152;
|
||||||
|
@ -90,14 +93,39 @@ private:
|
||||||
bool running;
|
bool running;
|
||||||
bool run_enable;
|
bool run_enable;
|
||||||
|
|
||||||
bool mch_running;
|
|
||||||
bool mch_run_enable;
|
|
||||||
bool _enable_mbsfn;
|
bool enable_mbsfn;
|
||||||
std::string gtp_bind_addr;
|
std::string gtp_bind_addr;
|
||||||
std::string mme_addr;
|
std::string mme_addr;
|
||||||
srsenb::pdcp_interface_gtpu *pdcp;
|
srsenb::pdcp_interface_gtpu *pdcp;
|
||||||
srslte::log *gtpu_log;
|
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{
|
typedef struct{
|
||||||
uint32_t teids_in[SRSENB_N_RADIO_BEARERS];
|
uint32_t teids_in[SRSENB_N_RADIO_BEARERS];
|
||||||
|
@ -109,22 +137,10 @@ private:
|
||||||
// Socket file descriptors
|
// Socket file descriptors
|
||||||
int snk_fd;
|
int snk_fd;
|
||||||
int src_fd;
|
int src_fd;
|
||||||
int m1u_sd;
|
|
||||||
|
|
||||||
//Init functions
|
|
||||||
bool init_m1u(srslte::log *gtpu_log_);
|
|
||||||
|
|
||||||
//Threading
|
//Threading
|
||||||
void run_thread();
|
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;
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
|
@ -34,6 +34,10 @@ using namespace srslte;
|
||||||
|
|
||||||
namespace srsenb {
|
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)
|
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_;
|
pdcp = pdcp_;
|
||||||
|
@ -89,127 +93,26 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Setup M1-u
|
|
||||||
init_m1u(gtpu_log_);
|
|
||||||
|
|
||||||
_enable_mbsfn = enable_mbsfn;
|
|
||||||
// Setup a thread to receive packets from the src socket
|
// Setup a thread to receive packets from the src socket
|
||||||
start(THREAD_PRIO);
|
start(THREAD_PRIO);
|
||||||
if(_enable_mbsfn){
|
|
||||||
mch_lcid_counter = 1;
|
// Start MCH thread if enabled
|
||||||
pthread_create(&mch_thread ,NULL ,mch_thread_routine , this);
|
this->enable_mbsfn = enable_mbsfn;
|
||||||
|
if(enable_mbsfn) {
|
||||||
|
mchthread.init(pdcp, gtpu_log);
|
||||||
}
|
}
|
||||||
return true;
|
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()
|
void gtpu::stop()
|
||||||
{
|
{
|
||||||
if (run_enable) {
|
|
||||||
run_enable = false;
|
if(enable_mbsfn){
|
||||||
if(mch_run_enable) {
|
mchthread.stop();
|
||||||
mch_run_enable = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (run_enable) {
|
||||||
|
run_enable = false;
|
||||||
// Wait thread to exit gracefully otherwise might leave a mutex locked
|
// Wait thread to exit gracefully otherwise might leave a mutex locked
|
||||||
int cnt=0;
|
int cnt=0;
|
||||||
while(running && cnt<100) {
|
while(running && cnt<100) {
|
||||||
|
@ -218,14 +121,8 @@ void gtpu::stop()
|
||||||
}
|
}
|
||||||
if (running) {
|
if (running) {
|
||||||
thread_cancel();
|
thread_cancel();
|
||||||
if(mch_running) {
|
|
||||||
pthread_cancel(mch_thread);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
wait_thread_finish();
|
wait_thread_finish();
|
||||||
if(_enable_mbsfn) {
|
|
||||||
pthread_join(mch_thread, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snk_fd) {
|
if (snk_fd) {
|
||||||
|
@ -332,7 +229,6 @@ void gtpu::run_thread()
|
||||||
|
|
||||||
pdu->N_bytes = (uint32_t) n;
|
pdu->N_bytes = (uint32_t) n;
|
||||||
|
|
||||||
|
|
||||||
gtpu_header_t header;
|
gtpu_header_t header;
|
||||||
gtpu_read_header(pdu, &header);
|
gtpu_read_header(pdu, &header);
|
||||||
|
|
||||||
|
@ -446,4 +342,119 @@ void gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t *teidin)
|
||||||
*teidin = (rnti << 16) | lcid;
|
*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
|
} // namespace srsenb
|
||||||
|
|
Loading…
Reference in New Issue