Merge branch 'next' into mbms_tun

master
Pedro Alvarez 6 years ago
commit 7454097611

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

@ -1,57 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_CONFIG_H
#define SRSLTE_CONFIG_H
// Generic helper definitions for shared library support
#if defined _WIN32 || defined __CYGWIN__
#define SRSAPPS_IMPORT __declspec(dllimport)
#define SRSAPPS_EXPORT __declspec(dllexport)
#define SRSAPPS_LOCAL
#else
#if __GNUC__ >= 4
#define SRSAPPS_IMPORT __attribute__ ((visibility ("default")))
#define SRSAPPS_EXPORT __attribute__ ((visibility ("default")))
#else
#define SRSAPPS_IMPORT
#define SRSAPPS_EXPORT
#define SRSAPPS_LOCAL
#endif
#endif
// Define SRSAPPS_API
// is used for the public API symbols.
#ifdef SRSAPPS_DLL_EXPORTS // defined if we are building the SRSAPPS DLL (instead of using it)
#define SRSAPPS_EXPORT
#else
#define SRSAPPS_IMPORT
#endif
// cf_t definition
typedef _Complex float cf_t;
#endif // SRSLTE_CONFIG_H

@ -80,7 +80,10 @@ public:
uint32_t maxharq_msg3tx;
uint32_t n1pucch_an;
uint32_t delta_pucch_shift;
// If non-negative, statically allocate N prbs at the edges of the uplink for PUCCH
int nrb_pucch;
uint32_t nrb_cqi;
uint32_t ncs_an;

@ -127,7 +127,11 @@ SRSLTE_API srslte_prach_sfn_t srslte_prach_get_sfn(uint32_t config_idx);
SRSLTE_API bool srslte_prach_tti_opportunity(srslte_prach_t *p,
uint32_t current_tti,
int allowed_subframe);
int allowed_subframe);
SRSLTE_API bool srslte_prach_tti_opportunity_config(uint32_t config_idx,
uint32_t current_tti,
int allowed_subframe);
SRSLTE_API void srslte_prach_sf_config(uint32_t config_idx,
srslte_prach_sf_config_t *sf_config);

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

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

@ -252,9 +252,12 @@ void srslte_rm_turbo_gentables() {
}
void srslte_rm_turbo_free_tables () {
for (int i = 0; i < SRSLTE_NOF_TC_CB_SIZES; i++) {
srslte_bit_interleaver_free(&bit_interleavers_systematic_bits[i]);
srslte_bit_interleaver_free(&bit_interleavers_parity_bits[i]);
if (rm_turbo_tables_generated) {
for (int i = 0; i < SRSLTE_NOF_TC_CB_SIZES; i++) {
srslte_bit_interleaver_free(&bit_interleavers_systematic_bits[i]);
srslte_bit_interleaver_free(&bit_interleavers_parity_bits[i]);
}
rm_turbo_tables_generated = false;
}
}

@ -60,12 +60,15 @@ int srslte_tcod_init(srslte_tcod_t *h, uint32_t max_long_cb) {
}
void srslte_tcod_free(srslte_tcod_t *h) {
h->max_long_cb = 0;
if (h->temp) {
free(h->temp);
}
for (int i = 0; i < 188; i++) {
srslte_bit_interleaver_free(&tcod_interleavers[i]);
if (table_initiated) {
h->max_long_cb = 0;
if (h->temp) {
free(h->temp);
}
for (int i = 0; i < 188; i++) {
srslte_bit_interleaver_free(&tcod_interleavers[i]);
}
table_initiated = false;
}
}

@ -193,6 +193,11 @@ srslte_prach_sfn_t srslte_prach_get_sfn(uint32_t config_idx) {
*/
bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int allowed_subframe) {
uint32_t config_idx = p->config_idx;
return srslte_prach_tti_opportunity_config(config_idx,current_tti,allowed_subframe);
}
bool srslte_prach_tti_opportunity_config(uint32_t config_idx, uint32_t current_tti, int allowed_subframe)
{
// Get SFN and sf_idx from the PRACH configuration index
srslte_prach_sfn_t prach_sfn = srslte_prach_get_sfn(config_idx);
@ -213,6 +218,7 @@ bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int a
}
}
return false;
}
void srslte_prach_sf_config(uint32_t config_idx, srslte_prach_sf_config_t *sf_config) {

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

@ -27,28 +27,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/time.h>
#include "srslte/srslte.h"
srslte_cell_t cell = {
.nof_prb = 6, // nof_prb
.nof_ports = 1, // nof_ports
.id = 0, // cell_id
.cp = SRSLTE_CP_NORM, // cyclic prefix
.phich_length = SRSLTE_PHICH_NORM, // PHICH length
.phich_resources = SRSLTE_PHICH_R_1_6 // PHICH resources
static srslte_cell_t cell = {
.nof_prb = 6, // nof_prb
.nof_ports = 1, // nof_ports
.id = 0, // cell_id
.cp = SRSLTE_CP_NORM, // cyclic prefix
.phich_length = SRSLTE_PHICH_NORM, // PHICH length
.phich_resources = SRSLTE_PHICH_R_1_6 // PHICH resources
};
srslte_uci_cfg_t uci_cfg = {
static srslte_uci_cfg_t uci_cfg = {
.I_offset_cqi = 6,
.I_offset_ri = 2,
.I_offset_ack = 9,
};
srslte_uci_data_t uci_data_tx = {
static srslte_uci_data_t uci_data_tx = {
.uci_cqi = {0},
.uci_cqi_len = 0,
.uci_ri = 0,
@ -64,14 +63,14 @@ srslte_uci_data_t uci_data_tx = {
uint32_t cfi = 2;
uint32_t tbs = 0;
uint32_t subframe = 1;
uint32_t subframe = 10;
srslte_mod_t modulation = SRSLTE_MOD_QPSK;
uint32_t rv_idx = 0;
uint32_t L_prb = 2;
uint32_t n_prb = 0;
int freq_hop = -1;
int riv = -1;
uint32_t mcs_idx = 0;
uint32_t L_prb = 2;
uint32_t n_prb = 0;
int freq_hop = -1;
int riv = -1;
uint32_t mcs_idx = 0;
srslte_cqi_value_t cqi_value;
void usage(char *prog) {
@ -95,56 +94,52 @@ void usage(char *prog) {
printf("\t\t-p I_offset_ack (0-15) [Default %d]\n", uci_cfg.I_offset_ack);
printf("\n\tCQI/RI/ACK Reporting contents:\n");
printf("\t\t-p uci_cqi (zeros, ones, random) [Default zeros]\n");
printf("\t\t-p uci_cqi_len (0-64) [Default %d]\n", uci_data_tx.uci_cqi_len);
printf("\t\t-p uci_cqi (none, wideband) [Default none]\n");
printf("\t\t-p uci_ri (0-1) (zeros, ones, random) [Default none]\n");
printf("\t\t-p uci_ack (0-1) [Default none]\n");
printf("\t\t-p uci_ack_2 (0-1) [Default none]\n");
printf("\n\tOther parameters:\n");
printf("\t\t-s subframe [Default %d]\n", subframe);
printf("\t\t-s number of subframes [Default %d]\n", subframe);
printf("\t-v [set srslte_verbose to debug, default none]\n");
}
void parse_extensive_param (char *param, char *arg) {
void parse_extensive_param(char *param, char *arg) {
int ext_code = SRSLTE_SUCCESS;
if (!strcmp(param, "I_offset_cqi")) {
uci_cfg.I_offset_cqi = (uint32_t) atoi(arg);
uci_cfg.I_offset_cqi = (uint32_t) strtol(arg, NULL, 10);
if (uci_cfg.I_offset_cqi > 15) {
ext_code = SRSLTE_ERROR;
}
} else if (!strcmp(param, "I_offset_ri")) {
uci_cfg.I_offset_ri = (uint32_t) atoi(arg);
uci_cfg.I_offset_ri = (uint32_t) strtol(arg, NULL, 10);
if (uci_cfg.I_offset_ri > 15) {
ext_code = SRSLTE_ERROR;
}
} else if (!strcmp(param, "I_offset_ack")) {
uci_cfg.I_offset_ack = (uint32_t) atoi(arg);
uci_cfg.I_offset_ack = (uint32_t) strtol(arg, NULL, 10);
if (uci_cfg.I_offset_ack > 15) {
ext_code = SRSLTE_ERROR;
}
} else if (!strcmp(param, "uci_cqi")) {
if (!strcmp(arg, "wideband")) {
cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND;
cqi_value.wideband.wideband_cqi = (uint8_t) (rand() & 0x03);
uci_data_tx.uci_cqi_len = (uint32_t) srslte_cqi_value_unpack(uci_data_tx.uci_cqi, &cqi_value);
cqi_value.wideband.wideband_cqi = (uint8_t) (random() & 0x0f);
uci_data_tx.uci_cqi_len = (uint32_t) srslte_cqi_value_pack(&cqi_value, uci_data_tx.uci_cqi);
} else if (!strcmp(arg, "none")) {
uci_data_tx.uci_cqi_len = 0;
} else {
ext_code = SRSLTE_ERROR;
}
} else if (!strcmp(param, "uci_cqi_len")) {
uci_data_tx.uci_cqi_len = (uint32_t) atol(arg);
if (uci_data_tx.uci_cqi_len >= SRSLTE_CQI_MAX_BITS) {
ext_code = SRSLTE_ERROR;
}
} else if (!strcmp(param, "uci_ri")) {
uci_data_tx.uci_ri = (uint8_t) atol(arg);
uci_data_tx.uci_ri = (uint8_t) strtol(arg, NULL, 10);
if (uci_data_tx.uci_ri > 1) {
ext_code = SRSLTE_ERROR;
} else {
uci_data_tx.uci_ri_len = 1;
}
} else if (!strcmp(param, "uci_ack")) {
uci_data_tx.uci_ack = (uint8_t) atol(arg);
uci_data_tx.uci_ack = (uint8_t) strtol(arg, NULL, 10);
if (uci_data_tx.uci_ack > 1) {
ext_code = SRSLTE_ERROR;
} else {
@ -154,7 +149,7 @@ void parse_extensive_param (char *param, char *arg) {
}
}
} else if (!strcmp(param, "uci_ack_2")) {
uci_data_tx.uci_ack_2 = (uint8_t) atol(arg);
uci_data_tx.uci_ack_2 = (uint8_t) strtol(arg, NULL, 10);
if (uci_data_tx.uci_ack_2 > 1) {
ext_code = SRSLTE_ERROR;
} else {
@ -175,45 +170,48 @@ void parse_extensive_param (char *param, char *arg) {
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "msLNRFrncpv")) != -1) {
switch(opt) {
case 'm':
mcs_idx = atoi(argv[optind]);
break;
case 's':
subframe = atoi(argv[optind]);
break;
case 'L':
L_prb = atoi(argv[optind]);
break;
case 'N':
n_prb = atoi(argv[optind]);
break;
case 'R':
riv = atoi(argv[optind]);
break;
case 'F':
freq_hop = atoi(argv[optind]);
break;
case 'r':
rv_idx = atoi(argv[optind]);
break;
case 'n':
cell.nof_prb = atoi(argv[optind]);
break;
case 'c':
cell.id = atoi(argv[optind]);
break;
case 'p':
parse_extensive_param(argv[optind], argv[optind + 1]);
optind++;
break;
case 'v':
srslte_verbose++;
break;
default:
usage(argv[0]);
exit(-1);
while ((opt = getopt(argc, argv, "msLNRFrncpvf")) != -1) {
switch (opt) {
case 'm':
mcs_idx = (uint32_t) strtol(argv[optind], NULL, 10);
break;
case 's':
subframe = (uint32_t) strtol(argv[optind], NULL, 10);
break;
case 'f':
cfi = (uint32_t) strtol(argv[optind], NULL, 10);
break;
case 'L':
L_prb = (uint32_t) strtol(argv[optind], NULL, 10);
break;
case 'N':
n_prb = (uint32_t) strtol(argv[optind], NULL, 10);
break;
case 'R':
riv = (int) strtol(argv[optind], NULL, 10);
break;
case 'F':
freq_hop = (int) strtol(argv[optind], NULL, 10);
break;
case 'r':
rv_idx = (uint32_t) strtol(argv[optind], NULL, 10);
break;
case 'n':
cell.nof_prb = (uint32_t) strtol(argv[optind], NULL, 10);
break;
case 'c':
cell.id = (uint32_t) strtol(argv[optind], NULL, 10);
break;
case 'p':
parse_extensive_param(argv[optind], argv[optind + 1]);
optind++;
break;
case 'v':
srslte_verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
@ -222,15 +220,16 @@ int main(int argc, char **argv) {
srslte_pusch_t pusch_tx;
srslte_pusch_t pusch_rx;
uint8_t *data = NULL;
uint8_t *data_rx = NULL;
cf_t *sf_symbols = NULL;
cf_t *ce = NULL;
cf_t *ce = NULL;
int ret = -1;
struct timeval t[3];
srslte_pusch_cfg_t cfg;
srslte_pusch_cfg_t cfg;
srslte_softbuffer_tx_t softbuffer_tx;
srslte_softbuffer_rx_t softbuffer_rx;
parse_args(argc,argv);
srslte_softbuffer_rx_t softbuffer_rx;
parse_args(argc, argv);
bzero(&cfg, sizeof(srslte_pusch_cfg_t));
@ -239,24 +238,24 @@ int main(int argc, char **argv) {
srslte_ra_ul_dci_t dci;
dci.freq_hop_fl = freq_hop;
if (riv < 0) {
dci.type2_alloc.L_crb = L_prb;
dci.type2_alloc.RB_start = n_prb;
dci.type2_alloc.L_crb = L_prb;
dci.type2_alloc.RB_start = n_prb;
} else {
dci.type2_alloc.riv = riv;
dci.type2_alloc.riv = (uint32_t) riv;
}
dci.mcs_idx = mcs_idx;
srslte_ra_ul_grant_t grant;
srslte_ra_ul_grant_t grant;
if (srslte_ra_ul_dci_to_grant(&dci, cell.nof_prb, 0, &grant)) {
fprintf(stderr, "Error computing resource allocation\n");
return ret;
}
srslte_pusch_hopping_cfg_t ul_hopping;
ul_hopping.n_sb = 1;
srslte_pusch_hopping_cfg_t ul_hopping;
ul_hopping.n_sb = 1;
ul_hopping.hopping_offset = 0;
ul_hopping.hop_mode = SRSLTE_PUSCH_HOP_MODE_INTER_SF;
ul_hopping.hop_mode = 1;
if (srslte_pusch_init_ue(&pusch_tx, cell.nof_prb)) {
fprintf(stderr, "Error creating PUSCH object\n");
goto quit;
@ -274,139 +273,188 @@ int main(int argc, char **argv) {
goto quit;
}
/* Configure PUSCH */
if (srslte_pusch_cfg(&pusch_tx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, subframe, 0, 0)) {
fprintf(stderr, "Error configuring PDSCH\n");
exit(-1);
}
if (srslte_pusch_cfg(&pusch_rx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, subframe, 0, 0)) {
fprintf(stderr, "Error configuring PDSCH\n");
exit(-1);
}
uint16_t rnti = 1234;
uint16_t rnti = 1234;
srslte_pusch_set_rnti(&pusch_tx, rnti);
srslte_pusch_set_rnti(&pusch_rx, rnti);
srslte_uci_data_t uci_data_rx;
memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t));
uint32_t nof_re = SRSLTE_NRE*cell.nof_prb*2*SRSLTE_CP_NSYMB(cell.cp);
uint32_t nof_re = SRSLTE_NRE * cell.nof_prb * 2 * SRSLTE_CP_NSYMB(cell.cp);
sf_symbols = srslte_vec_malloc(sizeof(cf_t) * nof_re);
if (!sf_symbols) {
perror("malloc");
exit(-1);
}
data = srslte_vec_malloc(sizeof(uint8_t) * (cfg.grant.mcs.tbs+24));
data = srslte_vec_malloc(sizeof(uint8_t) * 150000);
if (!data) {
perror("malloc");
exit(-1);
}
for (uint32_t i=0;i<cfg.grant.mcs.tbs/8;i++) {
data[i] = 1;
data_rx = srslte_vec_malloc(sizeof(uint8_t) * 150000);
if (!data_rx) {
perror("malloc");
exit(-1);
}
if (srslte_softbuffer_tx_init(&softbuffer_tx, 100)) {
fprintf(stderr, "Error initiating soft buffer\n");
goto quit;
}
srslte_softbuffer_tx_reset(&softbuffer_tx);
if (srslte_softbuffer_rx_init(&softbuffer_rx, 100)) {
fprintf(stderr, "Error initiating soft buffer\n");
goto quit;
}
srslte_softbuffer_rx_reset(&softbuffer_rx);
uint32_t ntrials = 100;
if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) {
fprintf(stderr, "Error encoding TB\n");
exit(-1);
}
if (rv_idx > 0) {
cfg.rv = rv_idx;
if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) {
fprintf(stderr, "Error encoding TB\n");
exit(-1);
}
}
ce = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
if (!ce) {
perror("srslte_vec_malloc");
goto quit;
}
for (int j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) {
for (int j = 0; j < SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); j++) {
ce[j] = 1;
}
gettimeofday(&t[1], NULL);
int r = srslte_pusch_decode(&pusch_rx,
&cfg,
&softbuffer_rx,
sf_symbols,
ce,
0,
rnti,
data,
(uci_data_tx.uci_cqi_len) ? &cqi_value : NULL,
&uci_data_rx);
gettimeofday(&t[2], NULL);
get_time_interval(t);
if (r) {
printf("Error decoding\n");
ret = -1;
} else {
ret = 0;
printf("DECODED OK in %d:%d (TBS: %d bits, TX: %.2f Mbps, Processing: %.2f Mbps)\n", (int) t[0].tv_sec,
(int) t[0].tv_usec/ntrials,
cfg.grant.mcs.tbs,
(float) cfg.grant.mcs.tbs/1000,
(float) cfg.grant.mcs.tbs/t[0].tv_usec*ntrials);
}
if (uci_data_tx.uci_ack_len) {
if (uci_data_tx.uci_ack != uci_data_rx.uci_ack) {
printf("UCI ACK bit error: %d != %d\n", uci_data_tx.uci_ack, uci_data_rx.uci_ack);
ret = SRSLTE_ERROR;
for (int n = 0; n < subframe; n++) {
ret = SRSLTE_SUCCESS;
/* Configure PUSCH */
if (srslte_pusch_cfg(&pusch_tx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, (uint32_t) n % 10, 0, 0)) {
fprintf(stderr, "Error configuring PDSCH\n");
exit(-1);
}
}
if (uci_data_tx.uci_ack_len > 1) {
if (uci_data_tx.uci_ack_2 != uci_data_rx.uci_ack_2) {
printf("UCI ACK 2 bit error: %d != %d\n", uci_data_tx.uci_ack_2, uci_data_rx.uci_ack_2);
ret = SRSLTE_ERROR;
if (srslte_pusch_cfg(&pusch_rx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, (uint32_t) n % 10, 0, 0)) {
fprintf(stderr, "Error configuring PDSCH\n");
exit(-1);
}
}
if (uci_data_tx.uci_ri_len) {
if (uci_data_tx.uci_ri != uci_data_rx.uci_ri) {
printf("UCI RI bit error: %d != %d\n", uci_data_tx.uci_ri, uci_data_rx.uci_ri);
ret = SRSLTE_ERROR;
srslte_softbuffer_tx_reset(&softbuffer_tx);
srslte_softbuffer_rx_reset(&softbuffer_rx);
for (uint32_t i = 0; i < cfg.grant.mcs.tbs / 8; i++) {
data[i] = (uint8_t) (random() & 0xff);
}
}
if (uci_data_tx.uci_cqi_len) {
if (memcmp(uci_data_tx.uci_cqi, uci_data_rx.uci_cqi, uci_data_tx.uci_cqi_len)) {
printf("cqi_tx=");
srslte_vec_fprint_b(stdout, uci_data_tx.uci_cqi, uci_data_tx.uci_cqi_len);
printf("cqi_rx=");
srslte_vec_fprint_b(stdout, uci_data_rx.uci_cqi, uci_data_rx.uci_cqi_len);
ret = SRSLTE_ERROR;
for (uint32_t i = 0; i < uci_data_tx.uci_cqi_len; i++) {
uci_data_tx.uci_cqi[i] = (uint8_t) (random() & 0x1);
}
if (uci_data_tx.uci_ack_len > 0) {
uci_data_tx.uci_ack = (uint8_t) (random() & 0x1);
}
if (uci_data_tx.uci_ack_len > 1) {
uci_data_tx.uci_ack_2 = (uint8_t) (random() & 0x1);
}
if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) {
fprintf(stderr, "Error encoding TB\n");
exit(-1);
}
if (rv_idx > 0) {
cfg.rv = rv_idx;
if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) {
fprintf(stderr, "Error encoding TB\n");
exit(-1);
}
}
gettimeofday(&t[1], NULL);
int r = srslte_pusch_decode(&pusch_rx,
&cfg,
&softbuffer_rx,
sf_symbols,
ce,
0,
rnti,
data_rx,
(uci_data_tx.uci_cqi_len) ? &cqi_value : NULL,
&uci_data_rx);
gettimeofday(&t[2], NULL);
if (r) {
printf("Error returned while decoding\n");
goto quit;
}
if (memcmp(data_rx, data, (size_t) cfg.grant.mcs.tbs / 8) != 0) {
printf("Unmatched data detected\n");
goto quit;
} else {
INFO("Rx Data is Ok\n");
}
if (uci_data_tx.uci_ack_len) {
if (uci_data_tx.uci_ack != uci_data_rx.uci_ack) {
printf("UCI ACK bit error: %d != %d\n", uci_data_tx.uci_ack, uci_data_rx.uci_ack);
ret = SRSLTE_ERROR;
} else {
INFO("Rx ACK is Ok\n");
}
}
if (uci_data_tx.uci_ack_len > 1) {
if (uci_data_tx.uci_ack_2 != uci_data_rx.uci_ack_2) {
printf("UCI ACK 2 bit error: %d != %d\n", uci_data_tx.uci_ack_2, uci_data_rx.uci_ack_2);
ret = SRSLTE_ERROR;
} else {
INFO("Rx ACK2 is Ok\n");
}
}
if (uci_data_tx.uci_ri_len) {
if (uci_data_tx.uci_ri != uci_data_rx.uci_ri) {
printf("UCI RI bit error: %d != %d\n", uci_data_tx.uci_ri, uci_data_rx.uci_ri);
ret = SRSLTE_ERROR;
} else {
INFO("Rx RI is Ok\n");
}
}
if (uci_data_tx.uci_cqi_len) {
if (memcmp(uci_data_tx.uci_cqi, uci_data_rx.uci_cqi, uci_data_tx.uci_cqi_len) != 0) {
printf("CQI Decode failed at subframe %d\n", n);
printf("cqi_tx=");
srslte_vec_fprint_b(stdout, uci_data_tx.uci_cqi, uci_data_tx.uci_cqi_len);
printf("cqi_rx=");
srslte_vec_fprint_b(stdout, uci_data_rx.uci_cqi, uci_data_rx.uci_cqi_len);
ret = SRSLTE_ERROR;
} else {
INFO("Rx CQI is Ok\n");
}
}
if (ret) {
goto quit;
}
get_time_interval(t);
printf("DECODED OK in %d:%d (TBS: %d bits, TX: %.2f Mbps, Processing: %.2f Mbps)\n", (int) t[0].tv_sec,
(int) t[0].tv_usec,
cfg.grant.mcs.tbs,
(float) cfg.grant.mcs.tbs / 1000,
(float) cfg.grant.mcs.tbs / t[0].tv_usec);
}
quit:
quit:
srslte_pusch_free(&pusch_tx);
srslte_pusch_free(&pusch_rx);
srslte_softbuffer_tx_free(&softbuffer_tx);
srslte_softbuffer_rx_free(&softbuffer_rx);
if (sf_symbols) {
free(sf_symbols);
}
if (data) {
free(data);
}
if (data_rx) {
free(data_rx);
}
if (ce) {
free(ce);
}

@ -331,7 +331,7 @@ int decode_cqi_short(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, uin
for (uint32_t w=0;w<(1<<nof_bits);w++) {
// Calculate correlation with pregenerated word and select maximum
int32_t corr = srslte_vec_dot_prod_sss(&q->cqi_table_s[nof_bits-1][w*32], q_bits, 32);
int32_t corr = srslte_vec_dot_prod_sss(&q->cqi_table_s[nof_bits-1][w*32], q_bits, SRSLTE_MIN(32, Q));
if (corr > max_corr) {
max_corr = corr;
max_w = w;

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

@ -20,4 +20,5 @@
add_subdirectory(asn1)
add_subdirectory(common)
add_subdirectory(phy)
add_subdirectory(upper)

@ -0,0 +1,27 @@
#
# Copyright 2013-2017 Software Radio Systems Limited
#
# This file is part of srsLTE
#
# srsLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# srsLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# A copy of the GNU Affero General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
#######################################################################
# PHY TESTS
#######################################################################
add_executable(phy_dl_test phy_dl_test.c)
target_link_libraries(phy_dl_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
add_test(phy_dl_test phy_dl_test)

@ -0,0 +1,377 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "srslte/srslte.h"
srslte_cell_t cell = {
.nof_prb = 100,
.nof_ports = 1,
.id = 1,
.cp = SRSLTE_CP_NORM,
.phich_resources = SRSLTE_PHICH_R_1,
.phich_length = SRSLTE_PHICH_NORM
};
uint32_t tm = 0;
srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
uint32_t sf_idx = 5;
uint32_t cfi = 3;
uint32_t nof_rx_ant = 1;
uint32_t nof_subframes = 10;
uint16_t rnti = 0x1234;
bool print_dci_table;
void usage(char *prog) {
printf("Usage: %s [cfpndvs]\n", prog);
printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-f cfi [Default %d]\n", cfi);
printf("\t-p cell.nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-s number of subframes to simulate [Default %d]\n", nof_subframes);
printf("\t-d Print DCI table [Default %s]\n", print_dci_table ? "yes" : "no");
printf("\t-x MIMO Type: single, diversity, cdd, multiplex [Default %s]\n", srslte_mimotype2str(mimo_type));
printf("\t-v [set srslte_verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "cfpndvsx")) != -1) {
switch (opt) {
case 'x':
if (srslte_str2mimotype(argv[optind], &mimo_type)) {
fprintf(stderr, "'%s' is not a valid MIMO type\n", argv[optind]);
usage(argv[0]);
exit(SRSLTE_ERROR);
}
if (mimo_type == SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) {
cell.nof_ports = 1;
nof_rx_ant = 1;
tm = 0;
} else {
cell.nof_ports = 2;
nof_rx_ant = 2;
if (mimo_type == SRSLTE_MIMO_TYPE_TX_DIVERSITY) {
tm = 2;
}
}
break;
case 'f':
cfi = (uint32_t) atoi(argv[optind]);
break;
case 'p':
cell.nof_prb = (uint32_t) atoi(argv[optind]);
break;
case 'c':
cell.id = (uint32_t) atoi(argv[optind]);
break;
case 's':
nof_subframes = (uint32_t) atoi(argv[optind]);
break;
case 'd':
print_dci_table = true;
break;
case 'v':
srslte_verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int prbset_num = 1, last_prbset_num = 1;
int prbset_orig = 0;
unsigned int
reverse(register unsigned int x) {
x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
return ((x >> 16) | (x << 16));
}
uint32_t prbset_to_bitmask() {
uint32_t mask = 0;
int nb = (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb));
for (int i = 0; i < nb; i++) {
if (i >= prbset_orig && i < prbset_orig + prbset_num) {
mask = mask | (0x1 << i);
}
}
return reverse(mask) >> (32 - nb);
}
int main(int argc, char **argv) {
srslte_enb_dl_t enb_dl = {};
srslte_ue_dl_t ue_dl = {};
srslte_softbuffer_tx_t *softbuffer_tx[SRSLTE_MAX_TB] = {};
srslte_softbuffer_rx_t *softbuffer_rx[SRSLTE_MAX_TB] = {};
uint8_t *data_tx[SRSLTE_MAX_TB] = {};
uint8_t *data_rx[SRSLTE_MAX_TB] = {};
uint32_t count_failures = 0;
int ret = -1;
parse_args(argc, argv);
cf_t *signal_buffer[SRSLTE_MAX_PORTS] = {NULL};
/*
* Allocate Memory
*/
for (int i = 0; i < cell.nof_ports; i++) {
signal_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
if (!signal_buffer[i]) {
fprintf(stderr, "Error allocating buffer\n");
goto quit;
}
}
for (int i = 0; i < SRSLTE_MAX_TB; i++) {
softbuffer_tx[i] = (srslte_softbuffer_tx_t *) calloc(sizeof(srslte_softbuffer_tx_t), 1);
if (!softbuffer_tx[i]) {
fprintf(stderr, "Error allocating softbuffer_tx\n");
goto quit;
}
if (srslte_softbuffer_tx_init(softbuffer_tx[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating softbuffer_tx\n");
goto quit;
}
softbuffer_rx[i] = (srslte_softbuffer_rx_t *) calloc(sizeof(srslte_softbuffer_rx_t), 1);
if (!softbuffer_rx[i]) {
fprintf(stderr, "Error allocating softbuffer_rx\n");
goto quit;
}
if (srslte_softbuffer_rx_init(softbuffer_rx[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating softbuffer_rx\n");
goto quit;
}
data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * 150000);
if (!data_tx[i]) {
fprintf(stderr, "Error allocating data tx\n");
goto quit;
}
data_rx[i] = srslte_vec_malloc(sizeof(uint8_t) * 150000);
if (!data_rx[i]) {
fprintf(stderr, "Error allocating data tx\n");
goto quit;
}
}
/*
* Initialise eNb
*/
if (srslte_enb_dl_init(&enb_dl, signal_buffer, cell.nof_prb)) {
fprintf(stderr, "Error initiating eNb downlink\n");
goto quit;
}
if (srslte_enb_dl_set_cell(&enb_dl, cell)) {
fprintf(stderr, "Error setting eNb DL cell\n");
goto quit;
}
srslte_enb_dl_set_cfi(&enb_dl, cfi);
srslte_enb_dl_set_power_allocation(&enb_dl, 0.0f, 0.0f); /* Default: none */
/*
* Initialise UE
*/
if (srslte_ue_dl_init(&ue_dl, signal_buffer, cell.nof_prb, nof_rx_ant)) {
fprintf(stderr, "Error initiating UE downlink\n");
goto quit;
}
if (srslte_ue_dl_set_cell(&ue_dl, cell)) {
fprintf(stderr, "Error setting UE downlink cell\n");
goto quit;
}
srslte_ue_dl_set_rnti(&ue_dl, rnti);
/*
* Loop
*/
for (uint32_t sf_idx = 0; sf_idx < nof_subframes; sf_idx++) {
bool acks[SRSLTE_MAX_TB] = {};
/* Run eNodeB */
srslte_enb_dl_clear_sf(&enb_dl);
srslte_enb_dl_put_base(&enb_dl, sf_idx);
srslte_ra_dl_dci_t dci = {};
srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A;
srslte_ra_dl_grant_t grant = {};
/* Pupulate TB Common */
dci.harq_process = 0;
/* Pupulate TB0 */
dci.mcs_idx = 0;
dci.ndi = 0;
dci.rv_idx = 0;
dci.tb_en[0] = true;
if (mimo_type == SRSLTE_MIMO_TYPE_CDD || mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
dci_format = SRSLTE_DCI_FORMAT2B;
/* Pupulate TB1 */
dci.mcs_idx_1 = 0;
dci.ndi_1 = 0;
dci.rv_idx_1 = 0;
dci.tb_en[1] = true;
/* Pupulate Allocation */
dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
dci.type0_alloc.rbg_bitmask = prbset_to_bitmask();
} else {
dci_format = SRSLTE_DCI_FORMAT1A;
dci.alloc_type = SRSLTE_RA_ALLOC_TYPE2;
dci.type2_alloc.riv = 0;
dci.type2_alloc.L_crb = 4;
dci.type2_alloc.RB_start = 0;
dci.type2_alloc.n_prb1a = 1;
dci.type2_alloc.n_gap = 0;
dci.type2_alloc.mode = 0;
}
dci.dci_is_1a = (dci_format == SRSLTE_DCI_FORMAT1A);
dci.dci_is_1c = (dci_format == SRSLTE_DCI_FORMAT1C);
srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant);
srslte_dci_location_t location = {
.ncce = 0,
.L = 2
};
for (int t = 0; t < SRSLTE_RA_DL_GRANT_NOF_TB(&grant); t++) {
for (int i = 0; i < grant.mcs->tbs; i++) {
data_tx[t][i] = (uint8_t) (rand() & 0xff);
}
}
if (srslte_enb_dl_put_pdcch_dl(&enb_dl,
&dci,
dci_format,
location,
rnti,
sf_idx % 10) < 0) {
fprintf(stderr, "Error putting PDCCH\n");
goto quit;
}
if (srslte_enb_dl_put_pdsch(&enb_dl,
&grant,
softbuffer_tx,
rnti,
(int[SRSLTE_MAX_CODEWORDS]) {dci.rv_idx, dci.rv_idx_1},
sf_idx % 10,
data_tx,
mimo_type) < 0) {
fprintf(stderr, "Error putting PDSCH\n");
goto quit;
}
srslte_enb_dl_gen_signal(&enb_dl);
/* Run UE */
int n = srslte_ue_dl_decode(&ue_dl, data_rx, tm, sf_idx, acks);
if (n < 0) {
fprintf(stderr, "Error decoding PDSCH\n");
goto quit;
}
for (int i = 0; i < SRSLTE_RA_DL_GRANT_NOF_TB(&grant); i++) {
if (!acks[i]) {
INFO("UE Failed decoding subframe %d\n", sf_idx);
count_failures++;
}
}
}
printf("Finished! The UE failed decoding %d of %d.\n", count_failures, nof_subframes);
if (!count_failures) {
ret = SRSLTE_SUCCESS;
}
quit:
srslte_enb_dl_free(&enb_dl);
srslte_ue_dl_free(&ue_dl);
for (
int i = 0;
i < cell.
nof_ports;
i++) {
if (signal_buffer[i]) {
free(signal_buffer[i]);
}
}
for (
int i = 0;
i < SRSLTE_MAX_TB; i++) {
if (softbuffer_tx[i]) {
srslte_softbuffer_tx_free(softbuffer_tx[i]);
free(softbuffer_tx[i]);
}
if (softbuffer_rx[i]) {
srslte_softbuffer_rx_free(softbuffer_rx[i]);
free(softbuffer_rx[i]);
}
if (data_tx[i]) {
free(data_tx[i]);
}
if (data_rx[i]) {
free(data_rx[i]);
}
}
if (ret) {
printf("Error\n");
} else {
printf("Ok\n");
}
srslte_dft_exit();
exit(ret);
}

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

@ -66,9 +66,10 @@ public:
public:
/* Virtual methods for user metric calculation */
virtual void reset_allocation(uint32_t nof_rb_) = 0;
virtual void new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t nof_rb, uint32_t tti) = 0;
virtual ul_harq_proc* get_user_allocation(sched_ue *user) = 0;
virtual void update_allocation(ul_harq_proc::ul_alloc_t alloc) = 0;
virtual bool update_allocation(ul_harq_proc::ul_alloc_t alloc) = 0;
};
@ -120,7 +121,6 @@ public:
int dl_sched(uint32_t tti, dl_sched_res_t *sched_result);
int ul_sched(uint32_t tti, ul_sched_res_t *sched_result);
/* Custom TPC functions
*/
void tpc_inc(uint16_t rnti);

@ -93,10 +93,11 @@ class ul_harq_proc : public harq_proc
{
public:
typedef struct {
struct ul_alloc_t {
uint32_t RB_start;
uint32_t L;
} ul_alloc_t;
inline void set(uint32_t start, uint32_t len) {RB_start = start; L = len;}
};
void new_tx(uint32_t tti, int mcs, int tbs);

@ -64,20 +64,22 @@ class ul_metric_rr : public sched::metric_ul
public:
void new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t nof_rb, uint32_t tti);
ul_harq_proc* get_user_allocation(sched_ue *user);
void update_allocation(ul_harq_proc::ul_alloc_t alloc);
bool update_allocation(ul_harq_proc::ul_alloc_t alloc);
void reset_allocation(uint32_t nof_rb_);
private:
const static int MAX_PRB = 100;
bool new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t *alloc);
bool allocation_is_valid(ul_harq_proc::ul_alloc_t alloc);
ul_harq_proc* apply_user_allocation(sched_ue *user);
ul_harq_proc* apply_user_allocation(sched_ue *user, bool retx_only);
ul_harq_proc* allocate_user_newtx_prbs(sched_ue* user);
ul_harq_proc* allocate_user_retx_prbs(sched_ue *user);
bool used_rb[MAX_PRB];
uint32_t current_tti;
uint32_t nof_rb;
uint32_t available_rb;
};

@ -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;
/****************************************************************************

@ -46,14 +46,14 @@ sib2 =
{
high_speed_flag = false;
prach_config_index = 3;
prach_freq_offset = 0;
prach_freq_offset = 2;
zero_correlation_zone_config = 11;
};
};
pdsch_cnfg =
{
p_b = 0;
rs_power = 20;
rs_power = -10;
};
pusch_cnfg =
{

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

@ -792,6 +792,7 @@ int sched::dl_sched(uint32_t tti, sched_interface::dl_sched_res_t* sched_result)
// Uplink sched
int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched_result)
{
typedef std::map<uint16_t, sched_ue>::iterator it_t;
if (!configured) {
return 0;
}
@ -816,66 +817,103 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
// current_cfi is set in dl_sched()
bzero(sched_result, sizeof(sched_interface::ul_sched_res_t));
ul_metric->reset_allocation(cfg.cell.nof_prb);
// Get HARQ process for this TTI
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
user->has_pucch = false;
ul_harq_proc *h = user->get_ul_harq(current_tti);
/* Indicate PHICH acknowledgment if needed */
if (h->has_pending_ack()) {
sched_result->phich[nof_phich_elems].phich = h->get_ack(0)?ul_sched_phich_t::ACK:ul_sched_phich_t::NACK;
sched_result->phich[nof_phich_elems].rnti = rnti;
nof_phich_elems++;
}
}
}
ul_metric->new_tti(ue_db, cfg.cell.nof_prb, current_tti);
// Update available allocation if there's a pending RAR
if (pending_msg3[tti%10].enabled) {
ul_harq_proc::ul_alloc_t msg3 = {pending_msg3[tti%10].n_prb, pending_msg3[tti%10].L};
ul_metric->update_allocation(msg3);
ul_harq_proc::ul_alloc_t msg3 = {pending_msg3[tti%10].n_prb, pending_msg3[tti%10].L};
if(ul_metric->update_allocation(msg3)) {
log_h->debug("SCHED: Allocated msg3 RBs within (%d,%d)\n", msg3.RB_start, msg3.RB_start + msg3.L);
}
else {
log_h->warning("SCHED: Could not allocate msg3 within (%d,%d)\n", msg3.RB_start, msg3.RB_start + msg3.L);
}
}
// Allocate PUCCH resources
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
uint32_t prb_idx[2] = {0, 0};
if (user->get_pucch_sched(current_tti, prb_idx)) {
user->has_pucch = true;
// allocate PUCCH
for (int i=0;i<2;i++) {
ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], 1};
ul_metric->update_allocation(pucch);
// Allocate PUCCH resources
if (cfg.nrb_pucch >= 0) {
ul_harq_proc::ul_alloc_t pucch = {0, (uint32_t) cfg.nrb_pucch};
if(!ul_metric->update_allocation(pucch)) {
log_h->warning("SCHED: Failed to allocate PUCCH\n");
}
pucch.RB_start = cfg.cell.nof_prb-cfg.nrb_pucch;
pucch.L = (uint32_t) cfg.nrb_pucch;
if(!ul_metric->update_allocation(pucch)) {
log_h->warning("SCHED: Failed to allocate PUCCH\n");
}
for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue *) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
uint32_t prb_idx[2] = {0, 0};
if(user->get_pucch_sched(current_tti, prb_idx)) {
user->has_pucch = true;
}
}
} else {
for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
uint32_t prb_idx[2] = {0, 0};
if (user->get_pucch_sched(current_tti, prb_idx)) {
user->has_pucch = true;
// allocate PUCCH
for (int i=0;i<2;i++) {
ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], 1};
ul_metric->update_allocation(pucch);
}
}
}
}
// reserve PRBs for PRACH
if(srslte_prach_tti_opportunity_config(cfg.prach_config, tti, -1)) {
ul_harq_proc::ul_alloc_t prach = {cfg.prach_freq_offset, 6};
if(!ul_metric->update_allocation(prach)) {
log_h->warning("SCHED: Failed to allocate PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L);
}
else {
log_h->debug("SCHED: Allocated PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L);
}
}
ul_metric->new_tti(ue_db, cfg.cell.nof_prb, current_tti);
// Now allocate PUSCH
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
ul_harq_proc *h = NULL;
ul_harq_proc *h = NULL;
// Check if there are pending Msg3 transmissions
bool is_rar = false;
if (pending_msg3[tti%10].enabled && pending_msg3[tti%10].rnti == rnti) {
h = user->get_ul_harq(tti);
h = user->get_ul_harq(tti);
if (h) {
ul_harq_proc::ul_alloc_t alloc;
alloc.L = pending_msg3[tti%10].L;
alloc.RB_start = pending_msg3[tti%10].n_prb;
ul_harq_proc::ul_alloc_t alloc;
alloc.L = pending_msg3[tti%10].L;
alloc.RB_start = pending_msg3[tti%10].n_prb;
h->set_alloc(alloc);
h->set_rar_mcs(pending_msg3[tti%10].mcs);
h->set_rar_mcs(pending_msg3[tti%10].mcs);
is_rar = true;
pending_msg3[tti%10].enabled = false;
pending_msg3[tti%10].enabled = false;
} else {
Warning("No HARQ pid available for transmission of Msg3\n");
}
@ -950,7 +988,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
}
// Update pending data counters after this TTI
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue *) &iter->second;
uint16_t rnti = (uint16_t) iter->first;

@ -208,28 +208,50 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
*
* Uplink Metric
*
*****************************************************************/
*****************************************************************/
void ul_metric_rr::reset_allocation(uint32_t nof_rb_)
{
nof_rb = nof_rb_;
bzero(used_rb, nof_rb*sizeof(bool));
}
void ul_metric_rr::new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t nof_rb_, uint32_t tti)
{
typedef std::map<uint16_t, sched_ue>::iterator it_t;
current_tti = tti;
nof_rb = nof_rb_;
available_rb = nof_rb_;
bzero(used_rb, nof_rb*sizeof(bool));
if(ue_db.size()==0)
return;
for(it_t it = ue_db.begin(); it != ue_db.end(); ++it) {
it->second.ul_next_alloc = NULL;
}
// give priority in a time-domain RR basis
uint32_t priority_idx = (current_tti+ue_db.size()/2) % ue_db.size(); // make DL and UL interleaved
std::map<uint16_t, sched_ue>::iterator iter = ue_db.begin();
uint32_t priority_idx = (current_tti+(uint32_t)ue_db.size()/2) % (uint32_t)ue_db.size(); // make DL and UL interleaved
// allocate reTxs first
it_t iter = ue_db.begin();
for(uint32_t ue_count = 0 ; ue_count < ue_db.size() ; ++iter, ++ue_count) {
if(iter==ue_db.end()) {
iter = ue_db.begin(); // wrap around
}
sched_ue *user = (sched_ue *) &iter->second;
user->ul_next_alloc = allocate_user_retx_prbs(user);
}
// give priority in a time-domain RR basis
iter = ue_db.begin();
std::advance(iter,priority_idx);
for(uint32_t ue_count = 0 ; ue_count < ue_db.size() ; ++iter, ++ue_count) {
if(iter==ue_db.end()) {
iter = ue_db.begin(); // wrap around
}
sched_ue *user = (sched_ue*) &iter->second;
user->ul_next_alloc = apply_user_allocation(user);
if (!user->ul_next_alloc) {
user->ul_next_alloc = allocate_user_newtx_prbs(user);
}
}
}
@ -266,8 +288,8 @@ bool ul_metric_rr::new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t* alloc)
}
}
}
if (!alloc->L) {
return 0;
if (alloc->L==0) {
return false;
}
// Make sure L is allowed by SC-FDMA modulation
@ -277,21 +299,64 @@ bool ul_metric_rr::new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t* alloc)
return alloc->L == L;
}
void ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc)
bool ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc)
{
if (alloc.L > available_rb) {
return;
if(allocation_is_valid(alloc)) {
for (uint32_t n=alloc.RB_start;n<alloc.RB_start+alloc.L;n++) {
used_rb[n] = true;
}
return true;
}
if (alloc.RB_start + alloc.L > nof_rb) {
return;
return false;
}
ul_harq_proc* ul_metric_rr::allocate_user_retx_prbs(sched_ue *user)
{
ul_harq_proc *h = user->get_ul_harq(current_tti);
// if there are procedures and we have space
if(!h->is_empty(0)) {
ul_harq_proc::ul_alloc_t alloc = h->get_alloc();
// If can schedule the same mask, do it
if (update_allocation(alloc)) {
return h;
}
// If not, try to find another mask in the current tti
if (new_allocation(alloc.L, &alloc)) {
if(not update_allocation(alloc)) {
printf("SCHED: Computed UL allocation is not valid!\n");
}
h->set_alloc(alloc);
return h;
}
}
for (uint32_t n=alloc.RB_start;n<alloc.RB_start+alloc.L;n++) {
used_rb[n] = true;
return NULL;
}
ul_harq_proc* ul_metric_rr::allocate_user_newtx_prbs(sched_ue* user)
{
uint32_t pending_data = user->get_pending_ul_new_data(current_tti);
ul_harq_proc *h = user->get_ul_harq(current_tti);
// find an empty PID
if (h->is_empty(0) and pending_data) {
uint32_t pending_rb = user->get_required_prb_ul(pending_data);
ul_harq_proc::ul_alloc_t alloc;
new_allocation(pending_rb, &alloc);
if (alloc.L) {
if(!update_allocation(alloc)) {
printf("SCHED: Computed UL allocation is not valid!\n");
}
h->set_alloc(alloc);
return h;
}
}
available_rb -= alloc.L;
return NULL;
}
ul_harq_proc* ul_metric_rr::apply_user_allocation(sched_ue *user) {
ul_harq_proc* ul_metric_rr::apply_user_allocation(sched_ue *user, bool retx_only) {
// Time-domain RR scheduling
uint32_t pending_data = user->get_pending_ul_new_data(current_tti);
ul_harq_proc *h = user->get_ul_harq(current_tti);
@ -314,6 +379,10 @@ ul_harq_proc* ul_metric_rr::apply_user_allocation(sched_ue *user) {
}
}
if (retx_only) {
return NULL;
}
// If could not schedule the reTx, or there wasn't any pending retx, find an empty PID
if (h->is_empty(0)) {
// Allocate resources based on pending data

@ -111,8 +111,8 @@ void metrics_stdout::print_metrics()
{
n_reports = 0;
cout << endl;
cout << "------DL-------------------------------UL--------------------------------" << endl;
cout << "rnti cqi ri mcs brate bler snr phr mcs brate bler bsr" << endl;
cout << "------DL------------------------------UL----------------------------------" << endl;
cout << "rnti cqi ri mcs brate bler snr phr mcs brate bler bsr" << endl;
}
if (metrics.rrc.n_ues > 0) {
@ -126,13 +126,9 @@ void metrics_stdout::print_metrics()
cout << std::hex << metrics.mac[i].rnti << " ";
cout << float_to_string(metrics.mac[i].dl_cqi, 2);
cout << float_to_string(metrics.mac[i].dl_ri, 3);
cout << float_to_string(metrics.mac[i].dl_ri, 1);
cout << float_to_string(metrics.phy[i].dl.mcs, 2);
if (metrics.mac[i].tx_brate > 0 && metrics_report_period) {
cout << float_to_eng_string((float) metrics.mac[i].tx_brate/metrics_report_period, 2);
} else {
cout << float_to_string(0, 2);
}
cout << float_to_eng_string((float) metrics.mac[i].tx_brate/metrics_report_period, 2);
if (metrics.mac[i].tx_pkts > 0 && metrics.mac[i].tx_errors) {
cout << float_to_string((float) 100*metrics.mac[i].tx_errors/metrics.mac[i].tx_pkts, 1) << "%";
} else {
@ -144,7 +140,7 @@ void metrics_stdout::print_metrics()
if (metrics.mac[i].rx_brate > 0 && metrics_report_period) {
cout << float_to_eng_string((float) metrics.mac[i].rx_brate/metrics_report_period, 2);
} else {
cout << float_to_string(0, 2);
cout << " " << float_to_string(0, 2);
}
if (metrics.mac[i].rx_pkts > 0 && metrics.mac[i].rx_errors > 0) {
cout << float_to_string((float) 100*metrics.mac[i].rx_errors/metrics.mac[i].rx_pkts, 1) << "%";
@ -174,7 +170,14 @@ void metrics_stdout::print_disconnect()
std::string metrics_stdout::float_to_string(float f, int digits)
{
std::ostringstream os;
const int precision = (f == 0.0) ? digits-1 : digits - log10(fabs(f))-2*DBL_EPSILON;
int precision;
if(isnan(f) or abs(f) < 0.0001) {
f = 0.0;
precision = digits-1;
}
else {
precision = digits - (int)(log10(fabs(f))-2*DBL_EPSILON);
}
os << std::setw(6) << std::fixed << std::setprecision(precision) << f;
return os.str();
}

@ -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_;
@ -51,10 +55,6 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
gtpu_log->error("Failed to create sink socket\n");
return false;
}
if (fcntl(snk_fd, F_SETFL, O_NONBLOCK)) {
gtpu_log->error("Failed to set non-blocking sink socket\n");
return false;
}
int enable = 1;
#if defined (SO_REUSEADDR)
if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
@ -89,130 +89,30 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
if (bind(src_fd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in))) {
gtpu_log->error("Failed to bind on address %s, port %d\n", gtp_bind_addr.c_str(), GTPU_PORT);
gtpu_log->console("Failed to bind on address %s, port %d\n", gtp_bind_addr.c_str(), GTPU_PORT);
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);
}
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;
// Start MCH thread if enabled
this->enable_mbsfn = enable_mbsfn;
if(enable_mbsfn) {
mchthread.init(pdcp, gtpu_log);
}
/* 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) {
@ -221,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);
}
@ -335,7 +229,6 @@ void gtpu::run_thread()
pdu->N_bytes = (uint32_t) n;
gtpu_header_t header;
gtpu_read_header(pdu, &header);
@ -369,7 +262,7 @@ void gtpu::run_thread()
}
} while(!pdu);
}
running=false;
running = false;
}
/****************************************************************************
@ -449,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

@ -637,8 +637,12 @@ void rrc::config_mac()
}
sched_cfg.si_window_ms = liblte_rrc_si_window_length_num[cfg.sibs[0].sib.sib1.si_window_length];
sched_cfg.prach_rar_window = liblte_rrc_ra_response_window_size_num[cfg.sibs[1].sib.sib2.rr_config_common_sib.rach_cnfg.ra_resp_win_size];
sched_cfg.prach_freq_offset = cfg.sibs[1].sib.sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset;
sched_cfg.maxharq_msg3tx = cfg.sibs[1].sib.sib2.rr_config_common_sib.rach_cnfg.max_harq_msg3_tx;
sched_cfg.nrb_pucch = SRSLTE_MAX(cfg.sr_cfg.nof_prb, cfg.cqi_cfg.nof_prb);
rrc_log->info("Allocating %d PRBs for PUCCH\n", sched_cfg.nrb_pucch);
// Copy Cell configuration
memcpy(&sched_cfg.cell, &cfg.cell, sizeof(srslte_cell_t));
@ -804,8 +808,7 @@ void rrc::run_thread()
break;
}
} else {
printf("Discarting rnti=0x%xn", p.rnti);
rrc_log->warning("Discarting PDU for removed rnti=0x%x\n", p.rnti);
rrc_log->warning("Discarding PDU for removed rnti=0x%x\n", p.rnti);
}
pthread_mutex_unlock(&user_mutex);
}

@ -363,8 +363,14 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
exit(1);
}
bpo::store(bpo::parse_config_file(conf, common), vm);
bpo::notify(vm);
// parse config file and handle errors gracefully
try {
bpo::store(bpo::parse_config_file(conf, common), vm);
bpo::notify(vm);
} catch (const boost::program_options::error& e) {
cerr << e.what() << endl;
exit(1);
}
//Check conflicting OP/OPc options and which is being used
if (vm.count("usim.op") && !vm["usim.op"].defaulted() &&
@ -373,14 +379,8 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
cout << "Conflicting options OP and OPc. Please configure either one or the other." << endl;
exit(1);
}
else
{
if(vm["usim.op"].defaulted()){
args->usim.using_op = true;
}
else{
args->usim.using_op = false;
}
else {
args->usim.using_op = vm.count("usim.op");
}
// Apply all_level to any unset layers

@ -783,7 +783,7 @@ bool rrc::si_acquire(uint32_t sib_index)
si_win_len = liblte_rrc_si_window_length_num[sib1->si_window_length];
if (last_win_start == 0 ||
(srslte_tti_interval(tti, last_win_start) > period*10 && srslte_tti_interval(tti, last_win_start) < 1000))
(srslte_tti_interval(tti, last_win_start) > period*5 && srslte_tti_interval(tti, last_win_start) < 1000))
{
last_win_start = si_win_start;
instruct_phy = true;

@ -53,8 +53,7 @@ int usim::init(usim_args_t *args, srslte::log *usim_log_)
usim_log->console("Invalid length for K: %zu should be %d\n", args->k.length(), 32);
}
if(args->using_op)
{
if(args->using_op) {
if(32 == args->op.length()) {
str_to_hex(args->op, op);
compute_opc(k,op,opc);
@ -63,7 +62,7 @@ int usim::init(usim_args_t *args, srslte::log *usim_log_)
usim_log->console("Invalid length for OP: %zu should be %d\n", args->op.length(), 32);
}
}
else{
else {
if(32 == args->opc.length()) {
str_to_hex(args->opc, opc);
} else {

Loading…
Cancel
Save