Merge branch 'embms_merge_final' into next

This commit is contained in:
Andre Puschmann 2018-05-23 21:25:37 +02:00
commit cb15dee3d4
101 changed files with 4773 additions and 979 deletions

View File

@ -32,10 +32,10 @@ target_link_libraries(synch_file srslte_phy)
if(RF_FOUND)
add_executable(pdsch_ue pdsch_ue.c)
target_link_libraries(pdsch_ue srslte_phy srslte_rf pthread)
target_link_libraries(pdsch_ue srslte_phy srslte_common srslte_rf pthread)
add_executable(pdsch_enodeb pdsch_enodeb.c)
target_link_libraries(pdsch_enodeb srslte_phy srslte_rf pthread)
target_link_libraries(pdsch_enodeb srslte_phy srslte_common srslte_rf pthread)
else(RF_FOUND)
add_definitions(-DDISABLE_RF)

View File

@ -35,7 +35,7 @@
#include <signal.h>
#include <srslte/phy/common/phy_common.h>
#include <srslte/phy/phch/pdsch_cfg.h>
#include "srslte/common/gen_mch_tables.h"
#include "srslte/srslte.h"
@ -79,10 +79,10 @@ char mimo_type_str[32] = "single";
uint32_t nof_tb = 1;
uint32_t multiplex_pmi = 0;
uint32_t multiplex_nof_layers = 1;
uint8_t mbsfn_sf_mask = 32;
int mbsfn_area_id = -1;
char *rf_args = "";
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
float rf_amp = 0.8, rf_gain = 60.0, rf_freq = 2400000000;
float output_file_snr = +INFINITY;
@ -123,7 +123,7 @@ int prbset_orig = 0;
#define DATA_BUFF_SZ 1024*1024
uint8_t *data[2], data2[DATA_BUFF_SZ];
uint8_t *data_mbms, *data[2], data2[DATA_BUFF_SZ];
uint8_t data_tmp[DATA_BUFF_SZ];
void usage(char *prog) {
@ -145,7 +145,7 @@ void usage(char *prog) {
printf("\t-x Transmission mode[single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str);
printf("\t-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi);
printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers);
printf("\t-u listen TCP port for input data (-1 is random) [Default %d]\n", net_port);
printf("\t-u listen TCP/UDP port for input data (if mbsfn is active then the stream is over mbsfn only) (-1 is random) [Default %d]\n", net_port);
printf("\t-v [set srslte_verbose to debug, default none]\n");
printf("\t-s output file SNR [Default %f]\n", output_file_snr);
printf("\n");
@ -154,7 +154,7 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "aglfmoncpvutxbwMs")) != -1) {
while ((opt = getopt(argc, argv, "aglfmoncpvutxbwMsB")) != -1) {
switch (opt) {
case 'a':
@ -206,6 +206,9 @@ void parse_args(int argc, char **argv) {
case 's':
output_file_snr = atof(argv[optind]);
break;
case 'B':
mbsfn_sf_mask = atoi(argv[optind]);
break;
default:
usage(argv[0]);
exit(-1);
@ -256,6 +259,8 @@ void base_init() {
}
bzero(data[i], sizeof(uint8_t) * SOFTBUFFER_SIZE);
}
data_mbms = srslte_vec_malloc(sizeof(uint8_t) * SOFTBUFFER_SIZE);
/* init memory */
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
@ -301,7 +306,7 @@ void base_init() {
}
if (net_port > 0) {
if (srslte_netsource_init(&net_source, "0.0.0.0", net_port, SRSLTE_NETSOURCE_TCP)) {
if (srslte_netsource_init(&net_source, "127.0.0.1", net_port, SRSLTE_NETSOURCE_UDP)) {
fprintf(stderr, "Error creating input UDP socket at port %d\n", net_port);
exit(-1);
}
@ -659,15 +664,21 @@ void *net_thread_fnc(void *arg) {
n = srslte_netsource_read(&net_source, &data2[rpm], DATA_BUFF_SZ-rpm);
if (n > 0) {
// FIXME: I assume that both transport blocks have same size in case of 2 tb are active
int nbytes = 1 + (pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs - 1) / 8;
int nbytes = 1 + (((mbsfn_area_id > -1)?(pmch_cfg.grant.mcs[0].tbs):(pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs)) - 1) / 8;
rpm += n;
INFO("received %d bytes. rpm=%d/%d\n",n,rpm,nbytes);
wpm = 0;
while (rpm >= nbytes) {
// wait for packet to be transmitted
sem_wait(&net_sem);
memcpy(data[0], &data2[wpm], nbytes / (size_t) 2);
memcpy(data[1], &data2[wpm], nbytes / (size_t) 2);
if(mbsfn_area_id > -1){
memcpy(data_mbms, &data2[wpm], nbytes);
}
else{
memcpy(data[0], &data2[wpm], nbytes / (size_t) 2);
memcpy(data[1], &data2[wpm], nbytes / (size_t) 2);
}
INFO("Sent %d/%d bytes ready\n", nbytes, rpm);
rpm -= nbytes;
wpm += nbytes;
@ -714,6 +725,11 @@ int main(int argc, char **argv) {
parse_args(argc, argv);
uint8_t mch_table[10];
bzero(&mch_table[0], sizeof(uint8_t)*10);
if(mbsfn_area_id < -1) {
generate_mcch_table(mch_table, mbsfn_sf_mask);
}
N_id_2 = cell.id % 3;
sf_n_re = 2 * SRSLTE_CP_NORM_NSYMB * cell.nof_prb * SRSLTE_NRE;
sf_n_samples = 2 * SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb));
@ -739,10 +755,15 @@ int main(int argc, char **argv) {
exit(-1);
}
if(mbsfn_area_id > -1) {
if(srslte_refsignal_mbsfn_init(&mbsfn_refs, cell, mbsfn_area_id)) {
if(srslte_refsignal_mbsfn_init(&mbsfn_refs, cell.nof_prb)) {
fprintf(stderr, "Error initializing equalizer\n");
exit(-1);
}
if (srslte_refsignal_mbsfn_set_cell(&mbsfn_refs, cell, mbsfn_area_id)) {
fprintf(stderr, "Error initializing MBSFNR signal\n");
exit(-1);
}
}
if(srslte_refsignal_cs_set_cell(&csr_refs, cell)){
@ -801,7 +822,7 @@ int main(int argc, char **argv) {
exit(-1);
}
}
pmch_cfg.grant.mcs[0].tbs = 1096;
/* Initiate valid DCI locations */
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
srslte_pdcch_ue_locations(&pdcch, locations[i], 30, i, cfi, UE_CRNTI);
@ -830,13 +851,13 @@ int main(int argc, char **argv) {
srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb,
SRSLTE_CP_NORM);
}
/* Copy zeros, SSS, PSS into the rest of antenna ports */
for (i = 1; i < cell.nof_ports; i++) {
memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re);
}
if(sf_idx == 1 && mbsfn_area_id > -1){
if(mch_table[sf_idx] == 1 && mbsfn_area_id > -1){
srslte_refsignal_mbsfn_put_sf(cell, 0,csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]);
} else {
for (i = 0; i < cell.nof_ports; i++) {
@ -857,10 +878,10 @@ int main(int argc, char **argv) {
}
/* Transmit PDCCH + PDSCH only when there is data to send */
if (net_port > 0) {
if ((net_port > 0) && (mch_table[sf_idx] == 1 && mbsfn_area_id > -1)) {
send_data = net_packet_ready;
if (net_packet_ready) {
INFO("Transmitting packet\n");
INFO("Transmitting packet from port\n");
}
} else {
INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs);
@ -878,9 +899,8 @@ int main(int argc, char **argv) {
send_data = false;
}
}
if (send_data) {
if(sf_idx != 1 || mbsfn_area_id < 0) { // PDCCH + PDSCH
if(mch_table[sf_idx] == 0 || mbsfn_area_id < 0) { // PDCCH + PDSCH
srslte_dci_format_t dci_format;
switch(pdsch_cfg.mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
@ -932,41 +952,46 @@ int main(int argc, char **argv) {
}
}
}
net_packet_ready = false;
sem_post(&net_sem);
if(mbsfn_area_id < 0){
net_packet_ready = false;
sem_post(&net_sem);
}
}
}else{ // We're sending MCH on subframe 1 - PDCCH + PMCH
/* Encode PDCCH */
INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_msg, cell.nof_prb, cell.nof_ports, false);
if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], M_CRNTI, sf_symbols, sf_idx, cfi)) {
fprintf(stderr, "Error encoding DCI message\n");
exit(-1);
}
//INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
//srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_msg, cell.nof_prb, cell.nof_ports, false);
//if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], M_CRNTI, sf_symbols, sf_idx, cfi)) {
// fprintf(stderr, "Error encoding DCI message\n");
// exit(-1);
// }
/* Configure pmch_cfg parameters */
srslte_ra_dl_grant_t grant;
grant.tb_en[0] = true;
grant.tb_en[1] = false;
grant.mcs[0].idx = 2;
grant.mcs[0].mod = SRSLTE_MOD_QPSK;
grant.nof_prb = cell.nof_prb;
grant.sf_type = SRSLTE_SF_MBSFN;
grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod);
srslte_dl_fill_ra_mcs(&grant.mcs[0], cell.nof_prb);
grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod);
for(int i = 0; i < 2; i++){
for(int j = 0; j < grant.nof_prb; j++){
grant.prb_idx[i][j] = true;
}
}
for(int i = 0; i < grant.mcs[0].tbs/8;i++)
{
data_mbms[i] = i%255;
}
if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, sf_idx)) {
fprintf(stderr, "Error configuring PMCH\n");
exit(-1);
}
}
/* Encode PMCH */
if (srslte_pmch_encode(&pmch, &pmch_cfg, softbuffers[0], data[0], mbsfn_area_id, sf_symbols)) {
if (srslte_pmch_encode(&pmch, &pmch_cfg, softbuffers[0], data_mbms, mbsfn_area_id, sf_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n");
exit(-1);
}
@ -984,13 +1009,14 @@ int main(int argc, char **argv) {
}
/* Transform to OFDM symbols */
if(sf_idx != 1 || mbsfn_area_id < 0){
if(mch_table[sf_idx] == 0 || mbsfn_area_id < 0){
for (i = 0; i < cell.nof_ports; i++) {
srslte_ofdm_tx_sf(&ifft[i]);
}
}else{
srslte_ofdm_tx_sf(&ifft_mbsfn);
}
/* send to file or usrp */
if (output_file_name) {
@ -1006,10 +1032,10 @@ int main(int argc, char **argv) {
}
usleep(1000);
} else {
#ifndef DISABLE_RF
#ifndef DISABLE_RF
float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb);
for (i = 0; i < cell.nof_ports; i++) {
srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb));
srslte_vec_sc_prod_cfc(output_buffer[i], 0.01, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
srslte_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false);
start_of_burst=false;

View File

@ -36,6 +36,7 @@
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include "srslte/common/gen_mch_tables.h"
#include <srslte/phy/common/phy_common.h>
#include "srslte/phy/io/filesink.h"
#include "srslte/srslte.h"
@ -103,6 +104,7 @@ typedef struct {
int decimate;
int32_t mbsfn_area_id;
uint8_t non_mbsfn_region;
uint8_t mbsfn_sf_mask;
int verbose;
}prog_args_t;
@ -138,6 +140,7 @@ void args_default(prog_args_t *args) {
args->cpu_affinity = -1;
args->mbsfn_area_id = -1;
args->non_mbsfn_region = 2;
args->mbsfn_sf_mask = 32;
}
void usage(prog_args_t *args, char *prog) {
@ -185,7 +188,7 @@ void usage(prog_args_t *args, char *prog) {
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDFRnvrfuUsSZyWMN")) != -1) {
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDFRnvrfuUsSZyWMNB")) != -1) {
switch (opt) {
case 'i':
args->input_file_name = argv[optind];
@ -275,6 +278,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
case 'N':
args->non_mbsfn_region = atoi(argv[optind]);
break;
case 'B':
args->mbsfn_sf_mask = atoi(argv[optind]);
break;
default:
usage(args, argv[0]);
exit(-1);
@ -364,8 +370,11 @@ int main(int argc, char **argv) {
go_exit = true;
}
}
uint8_t mch_table[10];
bzero(&mch_table[0], sizeof(uint8_t)*10);
if(prog_args.mbsfn_area_id < -1) {
generate_mcch_table(mch_table, prog_args.mbsfn_sf_mask);
}
if(prog_args.cpu_affinity > -1) {
cpu_set_t cpuset;
@ -385,7 +394,7 @@ int main(int argc, char **argv) {
}
if (prog_args.net_port > 0) {
if (srslte_netsink_init(&net_sink, prog_args.net_address, prog_args.net_port, SRSLTE_NETSINK_TCP)) {
if (srslte_netsink_init(&net_sink, prog_args.net_address, prog_args.net_port, SRSLTE_NETSINK_UDP)) {
fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address, prog_args.net_port);
exit(-1);
}
@ -668,7 +677,7 @@ int main(int argc, char **argv) {
decode_pdsch = true;
} else {
/* We are looking for SIB1 Blocks, search only in appropiate places */
if ((sfidx == 5 && (sfn%2)==0) || sfidx == 1) {
if ((sfidx == 5 && (sfn%2)==0) ||mch_table[sfidx] == 1) {
decode_pdsch = true;
} else {
decode_pdsch = false;
@ -677,7 +686,7 @@ int main(int argc, char **argv) {
gettimeofday(&t[1], NULL);
if (decode_pdsch) {
if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe
if(mch_table[sfidx] == 0 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe
if (cell.nof_ports == 1) {
/* Transmission mode 1 */
n = srslte_ue_dl_decode(&ue_dl, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
@ -864,6 +873,8 @@ int main(int argc, char **argv) {
PRINT_LINE_ADVANCE_CURSOR();
ue_dl.pdsch_pkt_errors = 0;
ue_dl.pdsch_pkts_total = 0;
ue_dl.pmch_pkt_errors = 0;
ue_dl.pmch_pkts_total = 0;
/*
ue_dl.pkt_errors = 0;
ue_dl.pkts_total = 0;
@ -944,7 +955,7 @@ int main(int argc, char **argv) {
plot_real_t p_sync, pce;
plot_scatter_t pscatequal, pscatequal_pdcch;
plot_scatter_t pscatequal, pscatequal_pdcch, pscatequal_pmch;
float tmp_plot[110*15*2048];
float tmp_plot2[110*15*2048];
@ -963,6 +974,15 @@ void *plot_thread_run(void *arg) {
plot_scatter_setYAxisScale(&pscatequal, -4, 4);
plot_scatter_addToWindowGrid(&pscatequal, (char*)"pdsch_ue", 0, 0);
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);
@ -979,7 +999,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, 1);
plot_real_addToWindowGrid(&pce, (char*)"pdsch_ue", 0, 2);
plot_real_addToWindowGrid(&pscatequal_pdcch, (char*)"pdsch_ue", 1, 0);
plot_real_addToWindowGrid(&p_sync, (char*)"pdsch_ue", 1, 1);
}
@ -988,6 +1008,7 @@ void *plot_thread_run(void *arg) {
sem_wait(&plot_sem);
uint32_t nof_symbols = ue_dl.pdsch_cfg.nbits[0].nof_re;
uint32_t nof_symbols_pmch = ue_dl.pmch_cfg.nbits[0].nof_re;
if (!prog_args.disable_plots_except_constellation) {
for (i = 0; i < nof_re; i++) {
tmp_plot[i] = 20 * log10f(cabsf(ue_dl.sf_symbols[i]));
@ -1031,6 +1052,7 @@ 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 (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

@ -213,17 +213,111 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_subframe_config_ie(uint8
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *mbsfn_subfr_cnfg);
/*********************************************************************
IE Name: PMCH Info List
IE Name: TMGI
Description: Specifies configuration of all PMCHs of an MBSFN area
Description: Temporary Mobile Group Identity (PLMN + MBMS service ID)
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
// Enums
// Structs
typedef struct{
uint16 mcc;
uint16 mnc;
}LIBLTE_RRC_PLMN_IDENTITY_STRUCT;
typedef struct{
LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id_r9;
uint8 plmn_index_r9;
bool plmn_id_explicit;
uint32 serviceid_r9;
}LIBLTE_RRC_TMGI_R9_STRUCT;
// Functions
// FIXME
LIBLTE_ERROR_ENUM liblte_rrc_pack_tmgi_r9_ie(LIBLTE_RRC_TMGI_R9_STRUCT *tmgi,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_tmgi_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_TMGI_R9_STRUCT *tmgi);
/*********************************************************************
IE Name: MBMS Session Info
Description: Information about an individual MBMS session
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
// Enums
// Structs
typedef struct{
LIBLTE_RRC_TMGI_R9_STRUCT tmgi_r9;
uint8 sessionid_r9;
bool sessionid_r9_present;
uint8 logicalchannelid_r9;
}LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_rrc_pack_mbms_session_info_r9_ie(LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbms_session_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info);
/*********************************************************************
IE Name: PMCH Config
Description: Contains configuration parameters of the sessions
carried by a PMCH
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
// Enums
typedef enum{
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF8 = 0,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF16,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF32,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF64,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF128,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF256,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF512,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF1024,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS,
}LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM;
static const char liblte_rrc_mch_scheduling_period_r9_text[LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS][20] = {"8", "16", "32", "64", "128", "256", "512", "1024"};
static const uint16 liblte_rrc_mch_scheduling_period_r9_num[LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS] = {8, 16, 32, 64, 128, 256, 512, 1024};
// Structs
typedef struct{
uint16 sf_alloc_end_r9;
uint8 datamcs_r9;
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM mch_schedulingperiod_r9;
}LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_config_r9_ie(LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_config_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg);
/*********************************************************************
IE Name: PMCH Info
Description: Specifies configuration of PMCH of an MBSFN area
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
#define LIBLTE_RRC_MAX_SESSION_PER_PMCH 29
// Enums
// Structs
typedef struct{
LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT pmch_config_r9;
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT mbms_sessioninfolist_r9[LIBLTE_RRC_MAX_SESSION_PER_PMCH];
uint8 mbms_sessioninfolist_r9_size;
}LIBLTE_RRC_PMCH_INFO_R9_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_info_r9_ie(LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info);
/*********************************************************************
IE Name: C-RNTI
@ -2227,10 +2321,6 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_registration_param_1xrtt_v920_ie(uint8
// Defines
// Enums
// Structs
typedef struct{
uint16 mcc;
uint16 mnc;
}LIBLTE_RRC_PLMN_IDENTITY_STRUCT;
typedef struct{
LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id;
uint32 cell_id;
@ -5135,7 +5225,7 @@ typedef struct{
LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT ue_timers_and_constants;
LIBLTE_RRC_ARFCN_VALUE_EUTRA_STRUCT arfcn_value_eutra;
LIBLTE_RRC_UL_BW_STRUCT ul_bw;
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS];
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg_list[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS];
LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM time_alignment_timer;
uint32 mbsfn_subfr_cnfg_list_size;
uint8 additional_spectrum_emission;
@ -5545,7 +5635,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_9_ie(uint8
// Structs
typedef struct{
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT mbsfn_area_info_list_r9[LIBLTE_RRC_MAX_MBSFN_AREAS];
LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbms_notification_config;
LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbsfn_notification_config;
uint8 mbsfn_area_info_list_r9_size;
}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT;
// Functions
@ -5771,18 +5861,18 @@ typedef enum{
LIBLTE_RRC_SIB_TYPE_11,
LIBLTE_RRC_SIB_TYPE_12_v920,
LIBLTE_RRC_SIB_TYPE_13_v920,
LIBLTE_RRC_SIB_TYPE_SPARE_5,
LIBLTE_RRC_SIB_TYPE_SPARE_4,
LIBLTE_RRC_SIB_TYPE_SPARE_3,
LIBLTE_RRC_SIB_TYPE_SPARE_2,
LIBLTE_RRC_SIB_TYPE_SPARE_1,
LIBLTE_RRC_SIB_TYPE_14_v1130,
LIBLTE_RRC_SIB_TYPE_15_v1130,
LIBLTE_RRC_SIB_TYPE_16_v1130,
LIBLTE_RRC_SIB_TYPE_17_v1250,
LIBLTE_RRC_SIB_TYPE_18_v1250,
LIBLTE_RRC_SIB_TYPE_N_ITEMS,
}LIBLTE_RRC_SIB_TYPE_ENUM;
static const char liblte_rrc_sib_type_text[LIBLTE_RRC_SIB_TYPE_N_ITEMS][20] = { "3", "4", "5", "6",
"7", "8", "9", "10",
"11", "12", "13", "SPARE",
"SPARE", "SPARE", "SPARE", "SPARE"};
static const uint8 liblte_rrc_sib_type_num[LIBLTE_RRC_SIB_TYPE_N_ITEMS] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0};
static const char liblte_rrc_sib_type_text[LIBLTE_RRC_SIB_TYPE_N_ITEMS][20] = { "3", "4", "5", "6",
"7", "8", "9", "10",
"11", "12_v920", "13_v920", "14_v1130",
"15_v1130", "16_v1130", "17_v1250", "18_v1250"};
static const uint8 liblte_rrc_sib_type_num[LIBLTE_RRC_SIB_TYPE_N_ITEMS] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
// Structs
typedef struct{
LIBLTE_RRC_PLMN_IDENTITY_STRUCT id;
@ -5846,14 +5936,20 @@ typedef enum{
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_11,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_12,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_14,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_15,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_16,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_17,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_18,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1, // Intentionally not first
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS,
}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_ENUM;
static const char liblte_rrc_sys_info_block_type_text[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS][20] = { "2", "3", "4", "5",
"6", "7", "8", "9",
"10", "11", "12", "13",
"1"};
static const uint8 liblte_rrc_sys_info_block_type_num[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1};
"10", "11", "12", "13",
"14", "15", "16", "17",
"18", "1"};
static const uint8 liblte_rrc_sys_info_block_type_num[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1};
// Structs
typedef union{
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
@ -6551,10 +6647,37 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_measurement_report_msg(LIBLTE_BIT_MSG_STRUCT
Document Reference: 36.331 v10.0.0 Section 6.2.2
*********************************************************************/
// Defines
#define LIBLTE_RRC_MAX_PMCH_PER_MBSFN 15
// Enums
typedef enum{
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF4 = 0,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF8,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF16,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF32,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF64,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF128,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF256,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS,
}LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM;
static const char liblte_rrc_mbsfn_common_sf_alloc_period_r9_text[LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS][20] = {"4", "8", "16", "32",
"64", "128", "256"};
static const uint32 liblte_rrc_mbsfn_common_sf_alloc_period_r9_num[LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS] = {4, 8, 16, 32,
64, 128, 256};
// Structs
typedef struct{
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT commonsf_allocpatternlist_r9[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS];
uint8 commonsf_allocpatternlist_r9_size;
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM commonsf_allocperiod_r9;
LIBLTE_RRC_PMCH_INFO_R9_STRUCT pmch_infolist_r9[LIBLTE_RRC_MAX_PMCH_PER_MBSFN];
uint8 pmch_infolist_r9_size;
}LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT;
// Functions
// FIXME
LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg,
LIBLTE_BIT_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *msg,
LIBLTE_RRC_PAGING_STRUCT *mbsfn_area_cnfg);
/*********************************************************************
Message Name: Master Information Block
@ -6783,8 +6906,12 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_dlsch_msg(LIBLTE_BIT_MSG_STRUCT
// Defines
// Enums
// Structs
typedef LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT LIBLTE_RRC_MCCH_MSG_STRUCT;
// Functions
// FIXME
LIBLTE_ERROR_ENUM liblte_rrc_pack_mcch_msg(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg,
LIBLTE_BIT_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mcch_msg(LIBLTE_BIT_MSG_STRUCT *msg,
LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg);
/*********************************************************************
Message Name: PCCH Message

View File

@ -44,6 +44,8 @@
#define SRSLTE_N_DRB 8
#define SRSLTE_N_RADIO_BEARERS 11
#define SRSLTE_N_MCH_LCIDS 32
#define HARQ_DELAY_MS 4
#define MSG3_DELAY_MS 2 // Delay added to HARQ_DELAY_MS
#define TTI_RX(tti) (tti>HARQ_DELAY_MS?((tti-HARQ_DELAY_MS)%10240):(10240+tti-HARQ_DELAY_MS))

View File

@ -0,0 +1,52 @@
/**
*
* \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 GEN_MCH_TALBES_H
#define GEN_MCH_TALBES_H
/******************************************************************************
* Common mch table generation - used in phch_common of UE and ENB for MBMS
*****************************************************************************/
#include <pthread.h>
#include <string.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void generate_frame_mch_table(uint8_t *table, uint8_t alloc);
void generate_mch_table(uint8_t *table, uint32_t sf_alloc, uint8_t num_frames);
void generate_mcch_table(uint8_t *table, uint32_t sf_alloc);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // SECURITY_H

View File

@ -50,6 +50,7 @@ public:
void write_dl_sirnti(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti);
void write_dl_bch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti);
void write_dl_pch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti);
void write_dl_mch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti);
private:
bool enable_write;

View File

@ -34,10 +34,10 @@
#include <stdio.h>
/* MAC PDU Packing/Unpacking functions. Section 6 of 36.321 */
class subh;
namespace srslte {
template<class SubH>
class pdu
{
@ -147,10 +147,11 @@ public:
}
}
protected:
std::vector<SubH> subheaders;
uint32_t pdu_len;
uint32_t rem_len;
uint32_t rem_len;
int cur_idx;
int nof_subheaders;
uint32_t max_subheaders;
@ -159,11 +160,10 @@ protected:
uint32_t total_sdu_len;
uint32_t sdu_offset_start;
int last_sdu_idx;
private:
/* Prepares the PDU for parsing or writing by setting the number of subheaders to 0 and the pdu length */
void init_(uint8_t *buffer_tx_ptr, uint32_t pdu_len_bytes, bool is_ulsch) {
virtual void init_(uint8_t *buffer_tx_ptr, uint32_t pdu_len_bytes, bool is_ulsch) {
nof_subheaders = 0;
pdu_len = pdu_len_bytes;
rem_len = pdu_len;
@ -180,55 +180,80 @@ private:
}
};
typedef enum {
SCH_SUBH_TYPE = 0,
MCH_SUBH_TYPE = 1,
RAR_SUBH_TYPE = 2
} subh_type;
template<class SubH>
class subh
{
public:
public:
subh(){}
virtual ~subh(){}
virtual bool read_subheader(uint8_t** ptr) = 0;
virtual void read_payload(uint8_t **ptr) = 0;
virtual void write_subheader(uint8_t** ptr, bool is_last) = 0;
virtual void write_payload(uint8_t **ptr) = 0;
virtual void fprint(FILE *stream) = 0;
pdu<SubH>* parent;
private:
private:
virtual void init() = 0;
};
class sch_subh : public subh<sch_subh>
{
public:
sch_subh(subh_type type_ = SCH_SUBH_TYPE) {
lcid = 0;
nof_bytes = 0;
payload = NULL;
nof_mch_sched_ce = 0;
cur_mch_sched_ce = 0;
F_bit = false;
type = type_;
parent = NULL;
bzero(&w_payload_ce, sizeof(w_payload_ce));
}
public:
virtual ~sch_subh(){}
typedef enum {
PHR_REPORT = 26,
CRNTI = 27,
CON_RES_ID = 28,
TRUNC_BSR = 28,
TA_CMD = 29,
SHORT_BSR = 29,
DRX_CMD = 30,
LONG_BSR = 30,
PADDING = 31,
SDU = 0
} cetype;
PHR_REPORT = 26,
CRNTI = 27,
CON_RES_ID = 28,
MTCH_MAX_LCID = 28,
TRUNC_BSR = 28,
TA_CMD = 29,
SHORT_BSR = 29,
DRX_CMD = 30,
LONG_BSR = 30,
MCH_SCHED_INFO = 30,
PADDING = 31,
SDU = 0
} cetype;
// Size of MAC CEs
const static int MAC_CE_CONTRES_LEN = 6;
// Reading functions
bool is_sdu();
cetype ce_type();
bool is_var_len_ce();
cetype ce_type();
uint32_t size_plus_header();
void set_payload_size(uint32_t size);
bool read_subheader(uint8_t** ptr);
void read_payload(uint8_t **ptr);
bool read_subheader(uint8_t** ptr);
void read_payload(uint8_t **ptr);
uint32_t get_sdu_lcid();
int get_payload_size();
uint32_t get_payload_size();
uint32_t get_header_size(bool is_last);
uint8_t* get_sdu_ptr();
@ -237,10 +262,13 @@ public:
uint8_t get_ta_cmd();
float get_phr();
int get_bsr(uint32_t buff_size[4]);
bool get_next_mch_sched_info(uint8_t *lcid, uint16_t *mtch_stop);
// Writing functions
void write_subheader(uint8_t** ptr, bool is_last);
void write_payload(uint8_t **ptr);
void write_subheader(uint8_t** ptr, bool is_last);
void write_payload(uint8_t **ptr);
int set_sdu(uint32_t lcid, uint32_t nof_bytes, uint8_t *payload);
int set_sdu(uint32_t lcid, uint32_t requested_bytes, read_pdu_interface *sdu_itf);
bool set_c_rnti(uint16_t crnti);
@ -251,46 +279,62 @@ public:
void set_padding();
void set_padding(uint32_t padding_len);
void init();
void fprint(FILE *stream);
void init();
void fprint(FILE *stream);
bool set_next_mch_sched_info(uint8_t lcid, uint16_t mtch_stop);
protected:
static const int MAX_CE_PAYLOAD_LEN = 8;
uint32_t lcid;
int nof_bytes;
uint8_t* payload;
uint8_t w_payload_ce[64];
uint8_t nof_mch_sched_ce;
uint8_t cur_mch_sched_ce;
bool F_bit;
subh_type type;
private:
static const int MAX_CE_PAYLOAD_LEN = 8;
uint32_t lcid;
uint32_t nof_bytes;
uint8_t* payload;
uint8_t w_payload_ce[8];
bool F_bit;
uint32_t sizeof_ce(uint32_t lcid, bool is_ul);
static uint8_t buff_size_table(uint32_t buffer_size);
static uint8_t phr_report_table(float phr_value);
};
class sch_pdu : public pdu<sch_subh>
{
public:
sch_pdu(uint32_t max_subh): pdu(max_subh) {}
sch_pdu(uint32_t max_subh) : pdu(max_subh) {}
void parse_packet(uint8_t *ptr);
uint8_t* write_packet();
uint8_t* write_packet(srslte::log *log_h);
bool has_space_ce(uint32_t nbytes);
bool has_space_ce(uint32_t nbytes, bool var_len=false);
bool has_space_sdu(uint32_t nbytes);
int get_pdu_len();
int rem_size();
int get_sdu_space();
static uint32_t size_header_sdu(uint32_t nbytes);
bool update_space_ce(uint32_t nbytes);
bool update_space_sdu(uint32_t nbytes);
bool update_space_ce(uint32_t nbytes, bool var_len=false);
bool update_space_sdu(uint32_t nbytes);
void fprint(FILE *stream);
};
class rar_subh : public subh<rar_subh>
{
public:
rar_subh() {
bzero(&grant, sizeof(grant));
ta = 0;
temp_rnti = 0;
preamble = 0;
parent = NULL;
}
static const uint32_t RAR_GRANT_LEN = 20;
@ -333,11 +377,50 @@ public:
bool write_packet(uint8_t* ptr);
void fprint(FILE *stream);
private:
private:
bool has_backoff_indicator;
uint8_t backoff_indicator;
};
} // namespace srslte
class mch_subh : public sch_subh
{
public:
mch_subh():sch_subh(MCH_SUBH_TYPE){}
// Size of MAC CEs
const static int MAC_CE_CONTRES_LEN = 6;
};
class mch_pdu : public sch_pdu
{
public:
mch_pdu(uint32_t max_subh) : sch_pdu(max_subh) {}
private:
/* Prepares the PDU for parsing or writing by setting the number of subheaders to 0 and the pdu length */
virtual void init_(uint8_t *buffer_tx_ptr, uint32_t pdu_len_bytes, bool is_ulsch) {
nof_subheaders = 0;
pdu_len = pdu_len_bytes;
rem_len = pdu_len;
pdu_is_ul = is_ulsch;
buffer_tx = buffer_tx_ptr;
sdu_offset_start = max_subheaders*2 + 13; // Assuming worst-case 2 bytes per sdu subheader + all possible CE
total_sdu_len = 0;
last_sdu_idx = -1;
reset();
for (uint32_t i=0;i<max_subheaders;i++) {
mch_subh mch_subh1;
subheaders[i] = mch_subh1;
subheaders[i].parent = this;
subheaders[i].init();
}
}
};
} // namespace srsue
#endif // MACPDU_H
#endif // SRSLTE_PDU_H

View File

@ -72,6 +72,7 @@ public:
virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) = 0;
virtual int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) = 0;
virtual int get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res) = 0;
virtual int get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) = 0;
// Radio-Link status
@ -95,6 +96,20 @@ public:
class phy_interface_rrc
{
public:
typedef struct {
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg;
LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbsfn_notification_cnfg;
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT mbsfn_area_info;
LIBLTE_RRC_MCCH_MSG_STRUCT mcch;
} phy_cfg_mbsfn_t;
typedef struct {
phy_cfg_mbsfn_t mbsfn;
} phy_rrc_cfg_t;
virtual void configure_mbsfn(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT mcch) = 0;
virtual void set_conf_dedicated_ack(uint16_t rnti, bool rrc_completed) = 0;
virtual void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) = 0;
@ -116,7 +131,7 @@ public:
virtual int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) = 0;
virtual int set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) = 0;
virtual void phy_config_enabled(uint16_t rnti, bool enabled) = 0;
virtual void write_mcch(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT *mcch) = 0;
};
class mac_interface_rlc
@ -164,6 +179,7 @@ public:
virtual void rem_user(uint16_t rnti) = 0;
virtual void add_bearer(uint16_t rnti, uint32_t lcid) = 0;
virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0;
virtual void add_bearer_mrb(uint16_t rnti, uint32_t lcid) = 0;
};
// PDCP interface for GTPU

View File

@ -129,6 +129,22 @@ public:
uint32_t nbytes;
} dl_sched_pdu_t;
typedef struct {
uint32_t lcid;
uint32_t lcid_buffer_size;
uint32_t stop;
uint8_t *mtch_payload;
} dl_mtch_sched_t;
typedef struct {
dl_sched_pdu_t pdu[20];
dl_mtch_sched_t mtch_sched[8];
uint32_t num_mtch_sched;
uint8_t *mcch_payload;
uint32_t current_sf_allocation_num;
} dl_pdu_mch_t;
typedef struct {
uint32_t rnti;
srslte_dci_format_t dci_format;

View File

@ -107,11 +107,19 @@ public:
virtual srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str) = 0;
};
// GW interface for RRC
class gw_interface_rrc
{
public:
virtual void add_mch_port(uint32_t lcid, uint32_t port) = 0;
};
// GW interface for PDCP
class gw_interface_pdcp
{
public:
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
};
// NAS interface for RRC
@ -204,6 +212,7 @@ public:
virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
};
@ -253,6 +262,7 @@ public:
virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu) = 0;
virtual void write_pdu_pcch(srslte::byte_buffer_t *sdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
};
// RLC interface for RRC
@ -263,6 +273,7 @@ public:
virtual void reestablish() = 0;
virtual void add_bearer(uint32_t lcid) = 0;
virtual void add_bearer(uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0;
virtual void add_bearer_mrb(uint32_t lcid) = 0;
};
// RLC interface for PDCP
@ -297,6 +308,7 @@ public:
virtual void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0;
};
@ -333,6 +345,11 @@ public:
class mac_interface_phy
{
public:
typedef struct {
uint32_t nof_mbsfn_services;
} mac_phy_cfg_mbsfn_t;
typedef struct {
uint32_t pid;
@ -385,21 +402,35 @@ public:
/* Indicate reception of UL grant + HARQ information throught PHICH in the same TTI. */
virtual void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) = 0;
/* Obtain action for a new MCH subframe. */
virtual void new_mch_dl(srslte_ra_dl_grant_t phy_grant, tb_action_dl_t *action) = 0;
/* Indicate reception of HARQ information only through PHICH. */
virtual void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) = 0;
/* Indicate reception of DL grant. */
virtual void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) = 0;
/* Indicate successfull decoding of PDSCH TB. */
/* Indicate successful decoding of PDSCH TB. */
virtual void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0;
/* Indicate successfull decoding of BCH TB through PBCH */
/* Indicate successful decoding of BCH TB through PBCH */
virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0;
/* Indicate successfull decoding of PCH TB through PDSCH */
/* Indicate successful decoding of PCH TB through PDSCH */
virtual void pch_decoded_ok(uint32_t len) = 0;
/* Indicate successful decoding of MCH TB through PMCH */
virtual void mch_decoded_ok(uint32_t len) = 0;
/* Communicate the number of mbsfn services available */
virtual void set_mbsfn_config(uint32_t nof_mbsfn_services) = 0;
/* Function called every start of a subframe (TTI). Warning, this function is called
* from a high priority thread and should terminate asap
*/
};
/* Interface RRC -> MAC shared between different RATs */
@ -445,6 +476,9 @@ public:
/* RRC configures a logical channel */
virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0;
/* Instructs the MAC to start receiving an MCH */
virtual void mch_start_rx(uint32_t lcid) = 0;
virtual uint32_t get_current_tti() = 0;
virtual void set_config(mac_cfg_t *mac_cfg) = 0;
@ -466,8 +500,6 @@ public:
};
/** PHY interface
*
*/
@ -540,12 +572,12 @@ public:
class phy_interface_mac : public phy_interface_mac_common
{
public:
/* Configure PRACH using parameters written by RRC */
virtual void configure_prach_params() = 0;
virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) = 0;
virtual int prach_tx_tti() = 0;
virtual int prach_tx_tti() = 0;
/* Indicates the transmission of a SR signal in the next opportunity */
virtual void sr_send() = 0;
virtual int sr_last_tx_tti() = 0;
@ -555,6 +587,9 @@ public:
virtual void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0;
virtual void pdcch_ul_search_reset() = 0;
virtual void pdcch_dl_search_reset() = 0;
virtual void set_mch_period_stop(uint32_t stop) = 0;
};
class phy_interface_rrc
@ -572,10 +607,19 @@ public:
LIBLTE_RRC_TDD_CONFIG_STRUCT tdd_cnfg;
LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM ant_info;
} phy_cfg_common_t;
typedef struct {
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg;
LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbsfn_notification_cnfg;
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT mbsfn_area_info;
LIBLTE_RRC_MCCH_MSG_STRUCT mcch;
} phy_cfg_mbsfn_t;
typedef struct {
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated;
phy_cfg_common_t common;
phy_cfg_mbsfn_t mbsfn;
bool enable_64qam;
} phy_cfg_t;
@ -589,6 +633,9 @@ public:
virtual void set_config_common(phy_cfg_common_t *common) = 0;
virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0;
virtual void set_config_64qam_en(bool enable) = 0;
virtual void set_config_mbsfn_sib2(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) = 0;
virtual void set_config_mbsfn_sib13(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13) = 0;
virtual void set_config_mbsfn_mcch(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch) = 0;
/* Measurements interface */
virtual void meas_reset() = 0;

View File

@ -93,8 +93,10 @@ SRSLTE_API uint32_t srslte_refsignal_cs_v(uint32_t port_id,
SRSLTE_API uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id);
SRSLTE_API int srslte_refsignal_mbsfn_init(srslte_refsignal_t *q, srslte_cell_t cell,
uint16_t mbsfn_area_id);
SRSLTE_API int srslte_refsignal_mbsfn_init(srslte_refsignal_t *q, uint32_t max_prb);
SRSLTE_API int srslte_refsignal_mbsfn_set_cell(srslte_refsignal_t * q,
srslte_cell_t cell, uint16_t mbsfn_area_id);
SRSLTE_API int srslte_refsignal_mbsfn_get_sf(srslte_cell_t cell,
uint32_t port_id,

View File

@ -92,7 +92,7 @@ SRSLTE_API int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q,
srslte_cp_t cp_type,
cf_t *in_buffer,
cf_t *out_buffer,
uint32_t nof_prb);
uint32_t max_prb);
SRSLTE_API int srslte_ofdm_rx_init(srslte_ofdm_t *q,
srslte_cp_t cp_type,

View File

@ -69,15 +69,20 @@ typedef struct SRSLTE_API {
cf_t *slot1_symbols[SRSLTE_MAX_PORTS];
srslte_ofdm_t ifft[SRSLTE_MAX_PORTS];
srslte_ofdm_t ifft_mbsfn;
srslte_pbch_t pbch;
srslte_pcfich_t pcfich;
srslte_regs_t regs;
srslte_pdcch_t pdcch;
srslte_pdsch_t pdsch;
srslte_pmch_t pmch;
srslte_phich_t phich;
srslte_refsignal_t csr_signal;
srslte_pdsch_cfg_t pdsch_cfg;
srslte_refsignal_t mbsfnr_signal;
srslte_pdsch_cfg_t pdsch_cfg;
srslte_pdsch_cfg_t pmch_cfg;
srslte_ra_dl_dci_t dl_dci;
srslte_dci_format_t dci_format;
@ -134,6 +139,8 @@ SRSLTE_API void srslte_enb_dl_prepare_power_allocation(srslte_enb_dl_t *q);
SRSLTE_API void srslte_enb_dl_set_amp(srslte_enb_dl_t *q,
float amp);
SRSLTE_API void srslte_enb_dl_set_non_mbsfn_region(srslte_enb_dl_t *q, uint8_t non_mbsfn_region);
SRSLTE_API void srslte_enb_dl_clear_sf(srslte_enb_dl_t *q);
SRSLTE_API void srslte_enb_dl_put_sync(srslte_enb_dl_t *q,
@ -157,8 +164,13 @@ SRSLTE_API void srslte_enb_dl_put_phich(srslte_enb_dl_t *q,
SRSLTE_API void srslte_enb_dl_put_base(srslte_enb_dl_t *q,
uint32_t tti);
SRSLTE_API void srslte_enb_dl_put_mbsfn_base(srslte_enb_dl_t *q,
uint32_t tti);
SRSLTE_API void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q);
SRSLTE_API void srslte_enb_dl_gen_signal_mbsfn(srslte_enb_dl_t *q);
SRSLTE_API int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q,
uint16_t rnti);
@ -174,6 +186,12 @@ SRSLTE_API int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q,
uint8_t *data[SRSLTE_MAX_CODEWORDS],
srslte_mimo_type_t mimo_type);
SRSLTE_API int srslte_enb_dl_put_pmch(srslte_enb_dl_t *q,
srslte_ra_dl_grant_t *grant,
srslte_softbuffer_tx_t *softbuffer,
uint32_t sf_idx,
uint8_t *data_mbms);
SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q,
srslte_ra_dl_dci_t *grant,
srslte_dci_format_t format,

View File

@ -94,7 +94,7 @@ SRSLTE_API int srslte_pmch_init_multi(srslte_pmch_t *q,
SRSLTE_API void srslte_pmch_free(srslte_pmch_t *q);
SRSLTE_API int srslte_pmch_set_cell(srslte_pmch_t *q, srslte_cell_t cell);
SRSLTE_API int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id);

View File

@ -57,7 +57,9 @@ public:
void reestablish();
void reset();
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu);
void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void config_security(uint32_t lcid,
uint8_t *k_enc,
uint8_t *k_int,
@ -72,9 +74,11 @@ public:
// RLC interface
void write_pdu(uint32_t lcid, byte_buffer_t *sdu);
void write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu);
void write_pdu_bcch_bch(byte_buffer_t *sdu);
void write_pdu_bcch_dlsch(byte_buffer_t *sdu);
void write_pdu_pcch(byte_buffer_t *sdu);
private:
srsue::rlc_interface_pdcp *rlc;
@ -83,10 +87,12 @@ private:
log *pdcp_log;
pdcp_entity pdcp_array[SRSLTE_N_RADIO_BEARERS];
pdcp_entity pdcp_array_mrb[SRSLTE_N_MCH_LCIDS];
uint32_t lcid; // default LCID that is maintained active by PDCP instance
uint8_t direction;
bool valid_lcid(uint32_t lcid);
bool valid_mch_lcid(uint32_t lcid);
};
} // namespace srslte

View File

@ -63,17 +63,21 @@ public:
// PDCP interface
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu);
bool rb_is_um(uint32_t lcid);
// MAC interface
uint32_t get_buffer_state(uint32_t lcid);
uint32_t get_total_buffer_state(uint32_t lcid);
uint32_t get_total_mch_buffer_state(uint32_t lcid);
int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
int read_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
int get_increment_sequence_num();
void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes);
void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes);
void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes);
void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
// RRC interface
void reestablish();
@ -81,7 +85,8 @@ public:
void empty_queue();
void add_bearer(uint32_t lcid);
void add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg);
void add_bearer_mrb(uint32_t lcid);
void add_bearer_mrb_enb(uint32_t lcid);
private:
void reset_metrics();
@ -92,13 +97,16 @@ private:
srslte::mac_interface_timers *mac_timers;
srsue::ue_interface *ue;
srslte::rlc_entity rlc_array[SRSLTE_N_RADIO_BEARERS];
srslte::rlc_um rlc_array_mrb[SRSLTE_N_MCH_LCIDS];
uint32_t default_lcid;
long ul_tput_bytes[SRSLTE_N_RADIO_BEARERS];
long dl_tput_bytes[SRSLTE_N_RADIO_BEARERS];
long dl_tput_bytes_mrb[SRSLTE_N_MCH_LCIDS];
struct timeval metrics_time[3];
bool valid_lcid(uint32_t lcid);
bool valid_lcid_mrb(uint32_t lcid);
};
} // namespace srsue

View File

@ -47,12 +47,12 @@ class rlc_entity
{
public:
rlc_entity();
void init(rlc_mode_t mode,
log *rlc_entity_log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers_);
void init(rlc_mode_t mode,
log *rlc_entity_log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers_);
void configure(srslte_rlc_config_t cnfg);
void reset();

View File

@ -73,6 +73,7 @@ typedef struct {
uint32_t rx_window_size;
uint32_t rx_mod; // Rx counter modulus
uint32_t tx_mod; // Tx counter modulus
bool is_mrb; // Whether this is a multicast bearer
} srslte_rlc_um_config_t;
@ -122,6 +123,21 @@ public:
break;
}
}
// Factory for MCH
static srslte_rlc_config_t mch_config()
{
srslte_rlc_config_t cfg;
cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_UNI_DL;
cfg.um.t_reordering = 0;
cfg.um.rx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS;
cfg.um.rx_window_size = 0;
cfg.um.rx_mod = 32;
cfg.um.tx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS;
cfg.um.tx_mod = 32;
cfg.um.is_mrb = true;
return cfg;
}
};
} // namespace srslte

View File

@ -41,11 +41,11 @@ class rlc_tm
{
public:
rlc_tm();
void init(log *rlc_entity_log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers);
void init(log *rlc_entity_log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers);
void configure(srslte_rlc_config_t cnfg);
void reset();
void stop();

View File

@ -75,6 +75,10 @@ public:
return queue.try_pop(msg);
}
void resize(uint32_t capacity)
{
queue.resize(capacity);
}
uint32_t size()
{
return (uint32_t) queue.size();
@ -102,10 +106,10 @@ public:
}
private:
bool is_empty() { return queue.empty(); }
bool is_empty() { return queue.empty(); }
block_queue<byte_buffer_t*> queue;
uint32_t unread_bytes;
uint32_t unread_bytes;
};
} // namespace srslte

View File

@ -50,17 +50,18 @@ class rlc_um
{
public:
rlc_um();
~rlc_um();
void init(log *rlc_entity_log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers_);
~rlc_um();
void init(log *rlc_entity_log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers_);
void configure(srslte_rlc_config_t cnfg);
void reset();
void stop();
void empty_queue();
bool is_mrb();
rlc_mode_t get_mode();
uint32_t get_bearer();
@ -73,7 +74,7 @@ public:
uint32_t get_total_buffer_state();
int read_pdu(uint8_t *payload, uint32_t nof_bytes);
void write_pdu(uint8_t *payload, uint32_t nof_bytes);
int get_increment_sequence_num();
// Timeout callback interface
void timer_expired(uint32_t timeout_id);
@ -86,11 +87,12 @@ private:
uint32_t lcid;
srsue::pdcp_interface_rlc *pdcp;
srsue::rrc_interface_rlc *rrc;
mac_interface_timers *mac_timers;
mac_interface_timers *mac_timers;
// TX SDU buffers
rlc_tx_queue tx_sdu_queue;
byte_buffer_t *tx_sdu;
byte_buffer_t tx_sdu_temp;
// Rx window
std::map<uint32_t, rlc_umd_pdu_t> rx_window;
@ -136,6 +138,8 @@ private:
void reassemble_rx_sdus();
bool inside_reordering_window(uint16_t sn);
void debug_state();
std::string rb_name();
};
/****************************************************************************

View File

@ -327,13 +327,218 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_subframe_config_ie(uint8
}
/*********************************************************************
IE Name: PMCH Info List
IE Name: TMGI
Description: Specifies configuration of all PMCHs of an MBSFN area
Description: Temporary Mobile Group Identity (PLMN + MBMS service ID)
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// FIXME
LIBLTE_ERROR_ENUM liblte_rrc_pack_tmgi_r9_ie(LIBLTE_RRC_TMGI_R9_STRUCT *tmgi,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(tmgi != NULL &&
ie_ptr != NULL)
{
liblte_value_2_bits(tmgi->plmn_id_explicit?1:0, ie_ptr, 1);
if(tmgi->plmn_id_explicit){
liblte_rrc_pack_plmn_identity_ie(&tmgi->plmn_id_r9, ie_ptr);
}else{
liblte_value_2_bits(tmgi->plmn_index_r9-1, ie_ptr, 3);
}
liblte_value_2_bits(tmgi->serviceid_r9, ie_ptr, 24);
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_tmgi_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_TMGI_R9_STRUCT *tmgi)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(ie_ptr != NULL &&
tmgi != NULL)
{
tmgi->plmn_id_explicit = liblte_bits_2_value(ie_ptr, 1);
if(tmgi->plmn_id_explicit){
liblte_rrc_unpack_plmn_identity_ie(ie_ptr, &tmgi->plmn_id_r9);
}else{
tmgi->plmn_index_r9 = liblte_bits_2_value(ie_ptr, 3) + 1;
}
tmgi->serviceid_r9 = liblte_bits_2_value(ie_ptr, 24);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: MBMS Session Info
Description: Information about an individual MBMS session
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_mbms_session_info_r9_ie(LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(mbms_session_info != NULL &&
ie_ptr != NULL)
{
// ext
liblte_value_2_bits(0, ie_ptr, 1);
liblte_value_2_bits(mbms_session_info->sessionid_r9_present?1:0, ie_ptr, 1);
liblte_rrc_pack_tmgi_r9_ie(&mbms_session_info->tmgi_r9, ie_ptr);
if(mbms_session_info->sessionid_r9_present){
liblte_value_2_bits(mbms_session_info->sessionid_r9, ie_ptr, 8);
}
liblte_value_2_bits(mbms_session_info->logicalchannelid_r9, ie_ptr, 5);
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbms_session_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(ie_ptr != NULL &&
mbms_session_info != NULL)
{
// ext
bool ext = liblte_bits_2_value(ie_ptr, 1);
mbms_session_info->sessionid_r9_present = liblte_bits_2_value(ie_ptr, 1);
liblte_rrc_unpack_tmgi_r9_ie(ie_ptr, &mbms_session_info->tmgi_r9);
if(mbms_session_info->sessionid_r9_present){
mbms_session_info->sessionid_r9 = liblte_bits_2_value(ie_ptr, 8);
}
mbms_session_info->logicalchannelid_r9 = liblte_bits_2_value(ie_ptr, 5);
liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: PMCH Config
Description: Contains configuration parameters of the sessions
carried by a PMCH
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_config_r9_ie(LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(pmch_cnfg != NULL &&
ie_ptr != NULL)
{
// ext
liblte_value_2_bits(0, ie_ptr, 1);
liblte_value_2_bits(pmch_cnfg->sf_alloc_end_r9, ie_ptr, 11);
liblte_value_2_bits(pmch_cnfg->datamcs_r9, ie_ptr, 5);
liblte_value_2_bits(pmch_cnfg->mch_schedulingperiod_r9, ie_ptr, 3);
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_config_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(ie_ptr != NULL &&
pmch_cnfg != NULL)
{
// ext
bool ext = liblte_bits_2_value(ie_ptr, 1);
pmch_cnfg->sf_alloc_end_r9 = liblte_bits_2_value(ie_ptr, 11);
pmch_cnfg->datamcs_r9 = liblte_bits_2_value(ie_ptr, 5);
pmch_cnfg->mch_schedulingperiod_r9 = (LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM)liblte_bits_2_value(ie_ptr, 3);
liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: PMCH Info
Description: Specifies configuration of PMCH of an MBSFN area
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_info_r9_ie(LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i;
if(pmch_info != NULL &&
ie_ptr != NULL)
{
// ext
liblte_value_2_bits(0, ie_ptr, 1);
liblte_rrc_pack_pmch_config_r9_ie(&pmch_info->pmch_config_r9, ie_ptr);
liblte_value_2_bits(pmch_info->mbms_sessioninfolist_r9_size, ie_ptr, 5);
for(i=0; i<pmch_info->mbms_sessioninfolist_r9_size; i++){
liblte_rrc_pack_mbms_session_info_r9_ie(&pmch_info->mbms_sessioninfolist_r9[i], ie_ptr);
}
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i;
if(ie_ptr != NULL &&
pmch_info != NULL)
{
// ext
bool ext = liblte_bits_2_value(ie_ptr, 1);
liblte_rrc_unpack_pmch_config_r9_ie(ie_ptr, &pmch_info->pmch_config_r9);
pmch_info->mbms_sessioninfolist_r9_size = liblte_bits_2_value(ie_ptr, 5);
for(i=0; i<pmch_info->mbms_sessioninfolist_r9_size; i++){
liblte_rrc_unpack_mbms_session_info_r9_ie(ie_ptr, &pmch_info->mbms_sessioninfolist_r9[i]);
}
liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: C-RNTI
@ -8896,7 +9101,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_2_ie(LIBLTE_RRC_SYS_INFO_B
liblte_value_2_bits(sib2->mbsfn_subfr_cnfg_list_size - 1, ie_ptr, 3);
for(i=0; i<sib2->mbsfn_subfr_cnfg_list_size; i++)
{
liblte_rrc_pack_mbsfn_subframe_config_ie(&sib2->mbsfn_subfr_cnfg[i], ie_ptr);
liblte_rrc_pack_mbsfn_subframe_config_ie(&sib2->mbsfn_subfr_cnfg_list[i], ie_ptr);
}
}
@ -8994,7 +9199,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_2_ie(uint8
sib2->mbsfn_subfr_cnfg_list_size = liblte_bits_2_value(ie_ptr, 3) + 1;
for(i=0; i<sib2->mbsfn_subfr_cnfg_list_size; i++)
{
liblte_rrc_unpack_mbsfn_subframe_config_ie(ie_ptr, &sib2->mbsfn_subfr_cnfg[i]);
liblte_rrc_unpack_mbsfn_subframe_config_ie(ie_ptr, &sib2->mbsfn_subfr_cnfg_list[i]);
}
}else{
sib2->mbsfn_subfr_cnfg_list_size = 0;
@ -10288,7 +10493,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_13_ie(LIBLTE_RRC_SYS_INFO_
{
liblte_rrc_pack_mbsfn_area_info_ie(&sib13->mbsfn_area_info_list_r9[i], ie_ptr);
}
liblte_rrc_pack_mbsfn_notification_config_ie(&sib13->mbms_notification_config, ie_ptr);
liblte_rrc_pack_mbsfn_notification_config_ie(&sib13->mbsfn_notification_config, ie_ptr);
err = LIBLTE_SUCCESS;
}
@ -10317,7 +10522,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_13_ie(uint8
{
liblte_rrc_unpack_mbsfn_area_info_ie(ie_ptr, &sib13->mbsfn_area_info_list_r9[i]);
}
liblte_rrc_unpack_mbsfn_notification_config_ie(ie_ptr, &sib13->mbms_notification_config);
liblte_rrc_unpack_mbsfn_notification_config_ie(ie_ptr, &sib13->mbsfn_notification_config);
liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr);
@ -13001,9 +13206,82 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_measurement_report_msg(LIBLTE_BIT_MSG_STRUCT
Description: Contains the MBMS control information applicable for
an MBSFN area
Document Reference: 36.331 v10.0.0 Section 6.2.2
Document Reference: 36.331 v10.0.0 Section 6.2.2
*********************************************************************/
// FIXME
LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg,
LIBLTE_BIT_MSG_STRUCT *msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint32 i;
if(mbsfn_area_cnfg != NULL &&
msg != NULL)
{
// Non-critical extension
liblte_value_2_bits(0, &msg_ptr, 1);
// commonsf_allocpatternlist_r9
liblte_value_2_bits(mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size-1, &msg_ptr, 3);
for(i=0; i<mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size; i++){
liblte_rrc_pack_mbsfn_subframe_config_ie(&mbsfn_area_cnfg->commonsf_allocpatternlist_r9[i], &msg_ptr);
}
// commonsf_allocperiod_r9
liblte_value_2_bits(mbsfn_area_cnfg->commonsf_allocperiod_r9, &msg_ptr, 3);
// pmch_infolist_r9
liblte_value_2_bits(mbsfn_area_cnfg->pmch_infolist_r9_size, &msg_ptr, 4);
for(i=0; i<mbsfn_area_cnfg->pmch_infolist_r9_size; i++){
liblte_rrc_pack_pmch_info_r9_ie(&mbsfn_area_cnfg->pmch_infolist_r9[i], &msg_ptr);
}
// Fill in the number of bits used
msg->N_bits = msg_ptr - msg->msg;
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(LIBLTE_BIT_MSG_STRUCT *msg,
LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint32 i;
bool ext;
if(msg != NULL &&
mbsfn_area_cnfg != NULL)
{
// Non-critical extension
ext = liblte_bits_2_value(&msg_ptr, 1);
liblte_rrc_warning_not_handled(ext, __func__);
// commonsf_allocpatternlist_r9
mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size = liblte_bits_2_value(&msg_ptr, 3) + 1;
for(i=0; i<mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size; i++){
liblte_rrc_unpack_mbsfn_subframe_config_ie(&msg_ptr, &mbsfn_area_cnfg->commonsf_allocpatternlist_r9[i]);
}
// commonsf_allocperiod_r9
mbsfn_area_cnfg->commonsf_allocperiod_r9 = (LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM)liblte_bits_2_value(&msg_ptr, 3);
// pmch_infolist_r9
mbsfn_area_cnfg->pmch_infolist_r9_size = liblte_bits_2_value(&msg_ptr, 4);
for(i=0; i<mbsfn_area_cnfg->pmch_infolist_r9_size; i++){
liblte_rrc_unpack_pmch_info_r9_ie(&msg_ptr, &mbsfn_area_cnfg->pmch_infolist_r9[i]);
}
liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
Message Name: Master Information Block
@ -13104,7 +13382,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_dl_information_transfer_msg(LIBLTE_BIT_MSG_S
liblte_bits_2_value(&msg_ptr, 2);
// Optional indicator
liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);;
liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);
// Dedicated info type choice
dl_info_transfer->dedicated_info_type = (LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 2);
@ -13373,6 +13651,66 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_dlsch_msg(LIBLTE_BIT_MSG_STRUCT
return(err);
}
/*********************************************************************
Message Name: MCCH Message
Description: Contains the set of RRC messages that may be sent
from the E-UTRAN to the UE on the MCCH logical
channel
Document Reference: 36.331 v10.0.0 Section 6.2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_mcch_msg(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg,
LIBLTE_BIT_MSG_STRUCT *msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint8 ext = false;
if(mcch_msg != NULL &&
msg != NULL)
{
// MCCH choice
liblte_value_2_bits(0, &msg_ptr, 1);
err = liblte_rrc_pack_mbsfn_area_configuration_r9_msg(mcch_msg,
&global_msg);
if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 1))
{
memcpy(msg_ptr, global_msg.msg, global_msg.N_bits);
msg->N_bits = global_msg.N_bits + 1;
}else{
msg->N_bits = 0;
err = LIBLTE_ERROR_INVALID_INPUTS;
}
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mcch_msg(LIBLTE_BIT_MSG_STRUCT *msg,
LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint32 N_bits_used;
if(msg != NULL &&
mcch_msg != NULL)
{
// MCCH choice
liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);;
if((msg->N_bits-(msg_ptr-msg->msg)) <= (LIBLTE_MAX_MSG_SIZE_BITS - 1))
{
memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg));
err = liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(&global_msg,
mcch_msg);
}
}
return(err);
}
/*********************************************************************
Message Name: PCCH Message

View File

@ -0,0 +1,62 @@
/**
*
* \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/.
*
*/
#include "srslte/common/gen_mch_tables.h"
/******************************************************************************
* Key Generation
*****************************************************************************/
void generate_frame_table(uint8_t *table, uint8_t alloc)
{
table[1] = (alloc >> 5) & 0x01;
table[2] = (alloc >> 4) & 0x01;
table[3] = (alloc >> 3) & 0x01;
table[6] = (alloc >> 2) & 0x01;
table[7] = (alloc >> 1) & 0x01;
table[8] = (alloc >> 0) & 0x01;
}
void generate_mch_table(uint8_t *table, uint32_t sf_alloc, uint8_t num_frames)
{
if(num_frames == 1){
uint8_t alloc = (sf_alloc) & 0x3F;
generate_frame_table(table, alloc);
} else if(num_frames == 4){
for(uint32_t j=0; j<4; j++){
uint8_t alloc = (sf_alloc >> 6*(3-j)) & 0x3F;
generate_frame_table(&table[j*10], alloc);
}
}
}
void generate_mcch_table(uint8_t *table, uint32_t sf_alloc)
{
uint8_t alloc = (sf_alloc) & 0x3F;
generate_frame_table(table, alloc);
}

View File

@ -94,6 +94,10 @@ void mac_pcap::write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, u
{
pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_PRNTI, DIRECTION_DOWNLINK, P_RNTI);
}
void mac_pcap::write_dl_mch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_MRNTI, DIRECTION_DOWNLINK, M_RNTI);
}
void mac_pcap::write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_SIRNTI, DIRECTION_DOWNLINK, SI_RNTI);

View File

@ -40,60 +40,15 @@ static uint32_t btable[64] = {
namespace srslte {
void sch_pdu::fprint(FILE* stream)
{
fprintf(stream, "MAC SDU for UL/DL-SCH. ");
pdu::fprint(stream);
}
void sch_subh::fprint(FILE* stream)
{
if (is_sdu()) {
fprintf(stream, "SDU LCHID=%d, SDU nof_bytes=%d\n", lcid, nof_bytes);
} else {
if (parent->is_ul()) {
switch(lcid) {
case CRNTI:
fprintf(stream, "C-RNTI CE\n");
break;
case PHR_REPORT:
fprintf(stream, "PHR\n");
break;
case TRUNC_BSR:
fprintf(stream, "Truncated BSR CE\n");
break;
case SHORT_BSR:
fprintf(stream, "Short BSR CE\n");
break;
case LONG_BSR:
fprintf(stream, "Long BSR CE\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
} else {
switch(lcid) {
case CON_RES_ID:
fprintf(stream, "Contention Resolution ID CE: 0x%lx\n", get_con_res_id());
break;
case TA_CMD:
fprintf(stream, "Time Advance Command CE: %d\n", get_ta_cmd());
break;
case DRX_CMD:
fprintf(stream, "DRX Command CE: Not implemented\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
}
}
}
void sch_pdu::parse_packet(uint8_t *ptr)
{
pdu::parse_packet(ptr);
// Correct size for last SDU
@ -157,7 +112,8 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
onetwo_padding = rem_len;
rem_len = 0;
}
/* Determine the header size and CE payload size */
uint32_t header_sz = 0;
uint32_t ce_payload_sz = 0;
@ -173,12 +129,12 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
header_sz += onetwo_padding;
}
if (ce_payload_sz + header_sz >= sdu_offset_start) {
fprintf(stderr, "Writting PDU: header sz + ce_payload_sz >= sdu_offset_start (%d>=%d). pdu_len=%d, total_sdu_len=%d\n",
fprintf(stderr, "Writing PDU: header sz + ce_payload_sz >= sdu_offset_start (%d>=%d). pdu_len=%d, total_sdu_len=%d\n",
header_sz + ce_payload_sz, sdu_offset_start, pdu_len, total_sdu_len);
return NULL;
}
/* Start writting header and CE payload before the start of the SDU payload */
/* Start writing header and CE payload before the start of the SDU payload */
uint8_t *ptr = &buffer_tx[sdu_offset_start-header_sz-ce_payload_sz];
uint8_t *pdu_start_ptr = ptr;
@ -213,7 +169,6 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
subheaders[i].write_payload(&ptr);
}
}
// Set padding to zeros (if any)
if (rem_len > 0) {
bzero(&pdu_start_ptr[pdu_len-rem_len], rem_len*sizeof(uint8_t));
@ -277,19 +232,22 @@ uint32_t sch_pdu::size_header_sdu(uint32_t nbytes)
return 3;
}
}
bool sch_pdu::has_space_ce(uint32_t nbytes)
bool sch_pdu::has_space_ce(uint32_t nbytes, bool var_len)
{
if (rem_len >= nbytes + 1) {
uint32_t head_len = var_len ? size_header_sdu(nbytes) : 1;
if (rem_len >= nbytes + head_len) {
return true;
} else {
return false;
}
}
bool sch_pdu::update_space_ce(uint32_t nbytes)
bool sch_pdu::update_space_ce(uint32_t nbytes, bool var_len)
{
uint32_t head_len = var_len ? size_header_sdu(nbytes) : 1;
if (has_space_ce(nbytes)) {
rem_len -= nbytes + 1;
rem_len -= nbytes + head_len;
return true;
} else {
return false;
@ -336,18 +294,22 @@ int sch_pdu::get_sdu_space()
void sch_subh::init()
{
lcid = 0;
nof_bytes = 0;
payload = NULL;
lcid = 0;
nof_bytes = 0;
payload = NULL;
nof_mch_sched_ce = 0;
cur_mch_sched_ce = 0;
}
sch_subh::cetype sch_subh::ce_type()
{
if (lcid >= PHR_REPORT) {
return (cetype) lcid;
} else {
return SDU;
if (lcid >= PHR_REPORT && type == SCH_SUBH_TYPE) {
return (cetype)lcid;
}
if(lcid >= MCH_SCHED_INFO && type == MCH_SUBH_TYPE) {
return (cetype)lcid;
}
return (cetype)SDU;
}
void sch_subh::set_payload_size(uint32_t size) {
@ -355,48 +317,65 @@ void sch_subh::set_payload_size(uint32_t size) {
}
uint32_t sch_subh::size_plus_header() {
if (is_sdu()) {
if (is_sdu() || is_var_len_ce()) {
return sch_pdu::size_header_sdu(nof_bytes) + nof_bytes;
} else {
return nof_bytes + 1;
}
// All others are 1-byte headers
return 1 + nof_bytes;
}
uint32_t sch_subh::sizeof_ce(uint32_t lcid, bool is_ul)
{
if (is_ul) {
switch(lcid) {
case PHR_REPORT:
return 1;
case CRNTI:
return 2;
case TRUNC_BSR:
return 1;
case SHORT_BSR:
return 1;
case LONG_BSR:
return 3;
case PADDING:
return 0;
}
} else {
switch(lcid) {
case CON_RES_ID:
return 6;
case TA_CMD:
return 1;
case DRX_CMD:
return 0;
case PADDING:
return 0;
}
if (type == SCH_SUBH_TYPE) {
if (is_ul) {
switch(lcid) {
case PHR_REPORT:
return 1;
case CRNTI:
return 2;
case TRUNC_BSR:
return 1;
case SHORT_BSR:
return 1;
case LONG_BSR:
return 3;
case PADDING:
return 0;
}
} else {
switch(lcid) {
case CON_RES_ID:
return 6;
case TA_CMD:
return 1;
case DRX_CMD:
return 0;
case PADDING:
return 0;
}
}
}
if (type == MCH_SUBH_TYPE) {
switch (lcid) {
case MCH_SCHED_INFO:
return nof_mch_sched_ce*2;
case PADDING:
return 0;
}
}
return 0;
}
bool sch_subh::is_sdu()
{
return ce_type() == SDU;
}
bool sch_subh::is_var_len_ce()
{
return (MCH_SCHED_INFO == ce_type()) && (MCH_SUBH_TYPE == type);
}
uint16_t sch_subh::get_c_rnti()
{
if (payload) {
@ -405,6 +384,7 @@ uint16_t sch_subh::get_c_rnti()
return (uint16_t) w_payload_ce[0]<<8 | w_payload_ce[1];
}
}
uint64_t sch_subh::get_con_res_id()
{
if (payload) {
@ -416,6 +396,7 @@ uint64_t sch_subh::get_con_res_id()
return 0;
}
}
float sch_subh::get_phr()
{
if (payload) {
@ -453,6 +434,21 @@ int sch_subh::get_bsr(uint32_t buff_size[4])
}
}
bool sch_subh::get_next_mch_sched_info(uint8_t *lcid_, uint16_t *mtch_stop)
{
if(payload) {
nof_mch_sched_ce = nof_bytes/2;
if(cur_mch_sched_ce < nof_mch_sched_ce) {
*lcid_ = (payload[cur_mch_sched_ce*2]&0xF8) >> 3;
*mtch_stop = ((uint16_t)(payload[cur_mch_sched_ce*2]&0x07)) << 8;
*mtch_stop += payload[cur_mch_sched_ce*2+1];
cur_mch_sched_ce++;
return true;
}
}
return false;
}
uint8_t sch_subh::get_ta_cmd()
{
if (payload) {
@ -461,42 +457,49 @@ uint8_t sch_subh::get_ta_cmd()
return 0;
}
}
uint32_t sch_subh::get_sdu_lcid()
{
return lcid;
}
int sch_subh::get_payload_size()
uint32_t sch_subh::get_payload_size()
{
return nof_bytes;
}
uint32_t sch_subh::get_header_size(bool is_last) {
if (!is_last) {
// For all subheaders, size can be 1, 2 or 3 bytes
if (is_sdu()) {
return sch_pdu::size_header_sdu(get_payload_size());
} else {
return 1;
return sch_pdu::size_header_sdu(nof_bytes);
}
if (lcid == MCH_SCHED_INFO && type == MCH_SUBH_TYPE) {
return sch_pdu::size_header_sdu(nof_bytes);
}
return 1; // All others are 1-byte
} else {
// Last subheader (CE or SDU) has always 1 byte header
return 1;
return 1; // Last subheader (CE or SDU) has always 1 byte header
}
}
uint8_t* sch_subh::get_sdu_ptr()
{
return payload;
}
void sch_subh::set_padding(uint32_t padding_len)
{
lcid = PADDING;
nof_bytes = padding_len;
}
void sch_subh::set_padding()
{
set_padding(0);
}
bool sch_subh::set_bsr(uint32_t buff_size[4], sch_subh::cetype format)
{
uint32_t nonzero_lcg=0;
@ -579,6 +582,20 @@ bool sch_subh::set_ta_cmd(uint8_t ta_cmd)
}
}
bool sch_subh::set_next_mch_sched_info(uint8_t lcid_, uint16_t mtch_stop)
{
if (((sch_pdu*)parent)->has_space_ce(2, true)) {
w_payload_ce[nof_mch_sched_ce*2] = (lcid_&0x1F) << 3 | (uint8_t) ((mtch_stop&0x0700)>>8);
w_payload_ce[nof_mch_sched_ce*2+1] = (uint8_t) (mtch_stop&0xff);
nof_mch_sched_ce++;
lcid = MCH_SCHED_INFO;
((sch_pdu*)parent)->update_space_ce(2, true);
nof_bytes += 2;
return true;
}
return false;
}
int sch_subh::set_sdu(uint32_t lcid_, uint32_t requested_bytes, read_pdu_interface *sdu_itf)
{
if (((sch_pdu*)parent)->has_space_sdu(requested_bytes)) {
@ -598,7 +615,7 @@ int sch_subh::set_sdu(uint32_t lcid_, uint32_t requested_bytes, read_pdu_interfa
// Save final number of written bytes
nof_bytes = sdu_sz;
if(nof_bytes > requested_bytes) {
if(nof_bytes > (int32_t)requested_bytes) {
return -1;
}
}
@ -634,7 +651,7 @@ void sch_subh::write_subheader(uint8_t** ptr, bool is_last)
{
*(*ptr) = (uint8_t) (is_last?0:(1<<5)) | ((uint8_t) lcid & 0x1f);
*ptr += 1;
if (is_sdu()) {
if (is_sdu() || is_var_len_ce()) {
// MAC SDU: R/R/E/LCID/F/L subheader
// 2nd and 3rd octet
if (!is_last) {
@ -656,8 +673,8 @@ void sch_subh::write_payload(uint8_t** ptr)
if (is_sdu()) {
// SDU is written directly during subheader creation
} else {
nof_bytes = sizeof_ce(lcid, parent->is_ul());
memcpy(*ptr, w_payload_ce, nof_bytes*sizeof(uint8_t));
nof_bytes = sizeof_ce(lcid, parent->is_ul());
memcpy(*ptr, w_payload_ce, nof_bytes*sizeof(uint8_t));
}
*ptr += nof_bytes;
}
@ -668,7 +685,7 @@ bool sch_subh::read_subheader(uint8_t** ptr)
bool e_bit = (bool) (*(*ptr) & 0x20)?true:false;
lcid = (uint8_t) *(*ptr) & 0x1f;
*ptr += 1;
if (is_sdu()) {
if (is_sdu() || is_var_len_ce()) {
if (e_bit) {
F_bit = (bool) (*(*ptr) & 0x80)?true:false;
nof_bytes = (uint32_t)*(*ptr) & 0x7f;
@ -686,12 +703,64 @@ bool sch_subh::read_subheader(uint8_t** ptr)
}
return e_bit;
}
void sch_subh::read_payload(uint8_t** ptr)
{
payload = *ptr;
*ptr += nof_bytes;
}
void sch_subh::fprint(FILE* stream)
{
if (is_sdu()) {
fprintf(stream, "SDU LCHID=%d, SDU nof_bytes=%d\n", lcid, nof_bytes);
} else if (type == SCH_SUBH_TYPE) {
if (parent->is_ul()) {
switch(lcid) {
case CRNTI:
fprintf(stream, "C-RNTI CE\n");
break;
case PHR_REPORT:
fprintf(stream, "PHR\n");
break;
case TRUNC_BSR:
fprintf(stream, "Truncated BSR CE\n");
break;
case SHORT_BSR:
fprintf(stream, "Short BSR CE\n");
break;
case LONG_BSR:
fprintf(stream, "Long BSR CE\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
} else {
switch(lcid) {
case CON_RES_ID:
fprintf(stream, "Contention Resolution ID CE: 0x%lx\n", get_con_res_id());
break;
case TA_CMD:
fprintf(stream, "Time Advance Command CE: %d\n", get_ta_cmd());
break;
case DRX_CMD:
fprintf(stream, "DRX Command CE: Not implemented\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
}
} else if (type == MCH_SUBH_TYPE) {
switch(lcid) {
case MCH_SCHED_INFO:
fprintf(stream, "MCH Scheduling Info CE\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
}
}
uint8_t sch_subh::buff_size_table(uint32_t buffer_size) {
if (buffer_size == 0) {
return 0;
@ -719,12 +788,6 @@ uint8_t sch_subh::phr_report_table(float phr_value)
return (uint8_t) floor(phr_value+23);
}
void rar_pdu::fprint(FILE* stream)
{
fprintf(stream, "MAC PDU for RAR. ");
@ -734,26 +797,22 @@ void rar_pdu::fprint(FILE* stream)
pdu::fprint(stream);
}
void rar_subh::fprint(FILE* stream)
{
fprintf(stream, "RAPID: %d, Temp C-RNTI: %d, TA: %d, UL Grant: ", preamble, temp_rnti, ta);
srslte_vec_fprint_hex(stream, grant, 20);
}
rar_pdu::rar_pdu(uint32_t max_rars_) : pdu(max_rars_)
{
backoff_indicator = 0;
has_backoff_indicator = false;
}
uint8_t rar_pdu::get_backoff()
{
return backoff_indicator;
}
bool rar_pdu::has_backoff()
{
return has_backoff_indicator;
}
void rar_pdu::set_backoff(uint8_t bi)
{
has_backoff_indicator = true;
@ -786,7 +845,11 @@ bool rar_pdu::write_packet(uint8_t* ptr)
return true;
}
void rar_subh::fprint(FILE* stream)
{
fprintf(stream, "RAPID: %d, Temp C-RNTI: %d, TA: %d, UL Grant: ", preamble, temp_rnti, ta);
srslte_vec_fprint_hex(stream, grant, 20);
}
void rar_subh::init()
{
@ -794,38 +857,47 @@ void rar_subh::init()
ta = 0;
temp_rnti = 0;
}
uint32_t rar_subh::get_rapid()
{
return preamble;
}
void rar_subh::get_sched_grant(uint8_t grant_[RAR_GRANT_LEN])
{
memcpy(grant_, grant, sizeof(uint8_t)*RAR_GRANT_LEN);
}
uint32_t rar_subh::get_ta_cmd()
{
return ta;
}
uint16_t rar_subh::get_temp_crnti()
{
return temp_rnti;
}
void rar_subh::set_rapid(uint32_t rapid)
{
preamble = rapid;
}
void rar_subh::set_sched_grant(uint8_t grant_[RAR_GRANT_LEN])
{
memcpy(grant, grant_, sizeof(uint8_t)*RAR_GRANT_LEN);
}
void rar_subh::set_ta_cmd(uint32_t ta_)
{
ta = ta_;
}
void rar_subh::set_temp_crnti(uint16_t temp_rnti_)
{
temp_rnti = temp_rnti_;
}
// Section 6.2.2
void rar_subh::write_subheader(uint8_t** ptr, bool is_last)
{
@ -873,150 +945,3 @@ bool rar_subh::read_subheader(uint8_t** ptr)
}
}
//int main()
//{
// /* Test 1st message: CCCH + Short BSR + PHR */
// uint8_t buffer[10240];
// uint8_t ccch_payload[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60};
// uint32_t bsr_st[4] = {1, 2, 3, 4};
// srsue::sch_pdu pdu(10);
// uint8_t *ptr;
// printf("------- CCCH + Short BSR + PHR no padding ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 11, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(0,6,ccch_payload);
// pdu.new_subh();
// pdu.get()->set_phr(10);
// pdu.new_subh();
// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// /* Test single SDU: SDU 15 + 1 byte header */
// printf("------- Single SDU no padding ----------\n");
// uint8_t dlsch_payload[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 16, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(1, 15, dlsch_payload);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// /* Test multiple SDU + multiword padding: SDU 8 + SDU 2 byte*/
// printf("------- Multiple SDU + multiword padding ----------\n");
// uint8_t dlsch_payload1[8] = {1,2,3,4,5,6,7,8};
// uint8_t dlsch_payload2[2] = {0xA, 0xB};
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 18, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(2, 8, dlsch_payload1);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 2, dlsch_payload2);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// printf("------- Multiple SDU + 2word padding ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 15, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(2, 8, dlsch_payload1);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 2, dlsch_payload2);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// printf("------- Multiple SDU + 1word padding ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 14, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(2, 8, dlsch_payload1);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 2, dlsch_payload2);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// printf("------- Multiple SDU + 0word padding ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 13, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(2, 8, dlsch_payload1);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 2, dlsch_payload2);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// printf("------- Multiple SDU + no space ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 12, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(2, 8, dlsch_payload1);
// pdu.new_subh();
// if (pdu.get()->set_sdu(3, 2, dlsch_payload2) < 0) {
// pdu.del_subh();
// }
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// /* CE only */
// printf("------- CE only ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 125, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_phr(15);
// pdu.new_subh();
// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// /* Another test */
// printf("------- Another test ----------\n");
// uint8_t dlsch_payload3[602];
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 75, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 2, dlsch_payload3);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 66, dlsch_payload3);
// pdu.new_subh();
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// //srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// return 0;
//}

View File

@ -124,7 +124,7 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
perror("malloc");
goto clean_exit;
}
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
if (!q->pilot_recv_signal) {
perror("malloc");
@ -154,7 +154,7 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
q->noise_alg = SRSLTE_NOISE_ALG_REFS;
q->rsrp_neighbour = false;
q->average_subframe = false;
q->smooth_filter_auto = false;
q->smooth_filter_len = 3;
srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1);
@ -212,9 +212,12 @@ int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_
if (mbsfn_area_id < SRSLTE_MAX_MBSFN_AREA_IDS) {
if(!q->mbsfn_refs[mbsfn_area_id]) {
q->mbsfn_refs[mbsfn_area_id] = calloc(1, sizeof(srslte_refsignal_t));
if(srslte_refsignal_mbsfn_init(q->mbsfn_refs[mbsfn_area_id], q->cell.nof_prb)) {
return SRSLTE_ERROR;
}
}
if(q->mbsfn_refs[mbsfn_area_id]) {
if(srslte_refsignal_mbsfn_init(q->mbsfn_refs[mbsfn_area_id], q->cell, mbsfn_area_id)) {
if(srslte_refsignal_mbsfn_set_cell(q->mbsfn_refs[mbsfn_area_id], q->cell, mbsfn_area_id)) {
return SRSLTE_ERROR;
}
}
@ -267,11 +270,10 @@ static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id, srslt
const float weight = 1.0f;
float sum_power = 0.0f;
uint32_t count = 0;
uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
uint32_t nsymbols =
(ch_mode == SRSLTE_SF_MBSFN) ? srslte_refsignal_mbsfn_nof_symbols() : srslte_refsignal_cs_nof_symbols(port_id);
uint32_t npilots = (ch_mode == SRSLTE_SF_MBSFN)?SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id):SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN) ? srslte_refsignal_mbsfn_nof_symbols() : srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = npilots / nsymbols;
uint32_t fidx = srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0);
uint32_t fidx = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_fidx(1):srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0);
cf_t *input2d[nsymbols + 2];
cf_t *tmp_noise = q->tmp_noise;
@ -330,7 +332,7 @@ static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce)
{
/* Get PSS from received signal */
srslte_pss_get_slot(input, q->tmp_pss, q->cell.nof_prb, q->cell.cp);
/* Get channel estimates for PSS position */
srslte_pss_get_slot(ce, q->tmp_pss_noisy, q->cell.nof_prb, q->cell.cp);
@ -339,7 +341,7 @@ static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce)
/* Substract received signal */
srslte_vec_sub_ccc(q->tmp_pss_noisy, q->tmp_pss, q->tmp_pss_noisy, SRSLTE_PSS_LEN);
/* Compute average power */
float power = q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_pss_noisy, SRSLTE_PSS_LEN)/sqrt(2);
return power;
@ -348,14 +350,14 @@ static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce)
/* Uses the 5 empty transmitted SC before and after the SSS and PSS sequences for noise estimation */
static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) {
int k_sss = (SRSLTE_CP_NSYMB(q->cell.cp) - 2) * q->cell.nof_prb * SRSLTE_NRE + q->cell.nof_prb * SRSLTE_NRE / 2 - 31;
float noise_power = 0;
float noise_power = 0;
noise_power += srslte_vec_avg_power_cf(&input[k_sss-5], 5); // 5 empty SC before SSS
noise_power += srslte_vec_avg_power_cf(&input[k_sss+62], 5); // 5 empty SC after SSS
int k_pss = (SRSLTE_CP_NSYMB(q->cell.cp) - 1) * q->cell.nof_prb * SRSLTE_NRE + q->cell.nof_prb * SRSLTE_NRE / 2 - 31;
noise_power += srslte_vec_avg_power_cf(&input[k_pss-5], 5); // 5 empty SC before PSS
noise_power += srslte_vec_avg_power_cf(&input[k_pss+62], 5); // 5 empty SC after PSS
return noise_power;
return noise_power;
}
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)]
@ -497,8 +499,9 @@ void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t *q, bool enable) {
uint32_t srslte_chest_dl_interleave_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *tmp, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) {
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
if (srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0) < 3) {
uint32_t fidx = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_fidx(1):srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0);
if (fidx < 3) {
srslte_vec_interleave(input, &input[nref], tmp, nref);
for (int l = 2; l < nsymbols - 1; l += 2) {
srslte_vec_interleave_add(&input[l * nref], &input[(l + 1) * nref], tmp, nref);
@ -549,9 +552,16 @@ static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint
}
}
uint32_t skip = (ch_mode == SRSLTE_SF_MBSFN)?2*q->cell.nof_prb:0;
if(ch_mode == SRSLTE_SF_MBSFN){
memcpy(&output[0],&input[0],skip*sizeof(cf_t));
}
// Average in the frequency domain
for (int l=0;l<nsymbols;l++) {
srslte_conv_same_cf(&input[l*nref], q->smooth_filter, &output[l*nref], nref, q->smooth_filter_len);
srslte_conv_same_cf(&input[l*nref + skip], q->smooth_filter, &output[l*nref + skip], nref, q->smooth_filter_len);
}
}
@ -660,11 +670,10 @@ int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx],
q->pilot_estimates, (2*q->cell.nof_prb));
srslte_vec_prod_conj_ccc(q->pilot_recv_signal+(2*q->cell.nof_prb), q->mbsfn_refs[mbsfn_area_id]->pilots[port_id/2][sf_idx],
q->pilot_estimates+(2*q->cell.nof_prb), SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id)-(2*q->cell.nof_prb));
srslte_vec_prod_conj_ccc(&q->pilot_recv_signal[(2*q->cell.nof_prb)], q->mbsfn_refs[mbsfn_area_id]->pilots[port_id/2][sf_idx],
&q->pilot_estimates[(2*q->cell.nof_prb)], SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id)-(2*q->cell.nof_prb));
chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_MBSFN);
return 0;

View File

@ -120,6 +120,7 @@ inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t
return 1+l*SRSLTE_CP_NSYMB(cp);
}
}
inline uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l)
{
uint32_t ret = 0;
@ -176,22 +177,21 @@ free_and_exit:
}
int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, srslte_cell_t cell, uint16_t mbsfn_area_id)
int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, uint32_t max_prb)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
uint32_t i, p;
if (q != NULL &&
srslte_cell_isvalid(&cell))
if (q != NULL)
{
ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_refsignal_t));
q->cell = cell;
q->type = SRSLTE_SF_MBSFN;
q->mbsfn_area_id = mbsfn_area_id;
for (p=0;p<2;p++) {
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * q->cell.nof_prb * 18);
q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * max_prb * 18);
if (!q->pilots[p][i]) {
perror("malloc");
goto free_and_exit;
@ -199,9 +199,7 @@ int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, srslte_cell_t cell, uint
}
}
if(srslte_refsignal_mbsfn_gen_seq(q, q->cell, q->mbsfn_area_id)) {
goto free_and_exit;
}
ret = SRSLTE_SUCCESS;
}
@ -212,7 +210,24 @@ free_and_exit:
return ret;
}
int srslte_refsignal_mbsfn_set_cell(srslte_refsignal_t * q, srslte_cell_t cell, uint16_t mbsfn_area_id){
int ret = SRSLTE_ERROR_INVALID_INPUTS;
q->cell = cell;
q->mbsfn_area_id = mbsfn_area_id;
if(srslte_refsignal_mbsfn_gen_seq(q, q->cell, q->mbsfn_area_id)) {
goto free_and_exit;
}
ret = SRSLTE_SUCCESS;
free_and_exit:
if (ret == SRSLTE_ERROR) {
srslte_refsignal_free(q);
}
return ret;
}
/** Allocates memory for the 20 slots in a subframe

View File

@ -149,6 +149,7 @@ int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof
q->symbol_sz = (uint32_t) symbol_sz;
q->nof_symbols = SRSLTE_CP_NSYMB(cp);
q->nof_symbols_mbsfn = SRSLTE_CP_NSYMB(SRSLTE_CP_EXT);
q->cp = cp;
q->nof_re = (uint32_t) nof_prb * SRSLTE_NRE;
q->nof_guards = ((symbol_sz - q->nof_re) / 2);
@ -246,14 +247,15 @@ int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t
return srslte_ofdm_init_(q, cp, in_buffer, out_buffer, symbol_sz, max_prb, SRSLTE_DFT_FORWARD);
}
int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, uint32_t nof_prb)
int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, uint32_t max_prb)
{
int symbol_sz = srslte_symbol_sz(nof_prb);
int symbol_sz = srslte_symbol_sz(max_prb);
if (symbol_sz < 0) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
fprintf(stderr, "Error: Invalid nof_prb=%d\n", max_prb);
return -1;
}
return srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, nof_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN);
q->max_prb = max_prb;
return srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, max_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN);
}
@ -292,7 +294,7 @@ int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer,
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1;
}
q->max_prb = nof_prb;
ret = srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, nof_prb, SRSLTE_DFT_BACKWARD, SRSLTE_SF_MBSFN);
if (ret == SRSLTE_SUCCESS) {
@ -559,7 +561,6 @@ void srslte_ofdm_tx_slot(srslte_ofdm_t *q, int slot_in_sf) {
void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output)
{
uint32_t i, cp_len;
for(i=0;i<q->nof_symbols_mbsfn;i++) {
cp_len = ( i>(q->non_mbsfn_region-1) )?SRSLTE_CP_LEN_EXT(q->symbol_sz):SRSLTE_CP_LEN_NORM(i, q->symbol_sz);
memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t));

View File

@ -69,6 +69,13 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, cf_t *out_buffer[SRSLTE_MAX_PORTS], u
goto clean_exit;
}
}
if (srslte_ofdm_tx_init_mbsfn(&q->ifft_mbsfn, SRSLTE_CP_EXT, q->sf_symbols[0], out_buffer[0], max_prb)) {
fprintf(stderr, "Error initiating FFT \n");
goto clean_exit;
}
if (srslte_pbch_init(&q->pbch)) {
fprintf(stderr, "Error creating PBCH object\n");
@ -82,7 +89,15 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, cf_t *out_buffer[SRSLTE_MAX_PORTS], u
fprintf(stderr, "Error creating PHICH object\n");
goto clean_exit;
}
int mbsfn_area_id = 1;
if (srslte_pmch_init(&q->pmch, max_prb)) {
fprintf(stderr, "Error creating PMCH object\n");
}
srslte_pmch_set_area_id(&q->pmch, mbsfn_area_id);
if (srslte_pdcch_init_enb(&q->pdcch, max_prb)) {
fprintf(stderr, "Error creating PDCCH object\n");
goto clean_exit;
@ -97,7 +112,11 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, cf_t *out_buffer[SRSLTE_MAX_PORTS], u
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
goto clean_exit;
}
if (srslte_refsignal_mbsfn_init(&q->mbsfnr_signal, max_prb)) {
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
goto clean_exit;
}
ret = SRSLTE_SUCCESS;
} else {
@ -117,15 +136,16 @@ void srslte_enb_dl_free(srslte_enb_dl_t *q)
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
srslte_ofdm_tx_free(&q->ifft[i]);
}
srslte_ofdm_tx_free(&q->ifft_mbsfn);
srslte_regs_free(&q->regs);
srslte_pbch_free(&q->pbch);
srslte_pcfich_free(&q->pcfich);
srslte_phich_free(&q->phich);
srslte_pdcch_free(&q->pdcch);
srslte_pdsch_free(&q->pdsch);
srslte_pmch_free(&q->pmch);
srslte_refsignal_free(&q->csr_signal);
srslte_refsignal_free(&q->mbsfnr_signal);
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
if (q->sf_symbols[i]) {
free(q->sf_symbols[i]);
@ -159,6 +179,15 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell)
return SRSLTE_ERROR;
}
}
if (srslte_ofdm_tx_set_prb(&q->ifft_mbsfn, SRSLTE_CP_EXT, q->cell.nof_prb)) {
fprintf(stderr, "Error re-planning ifft_mbsfn\n");
return SRSLTE_ERROR;
}
srslte_ofdm_set_non_mbsfn_region(&q->ifft_mbsfn, 2);
//srslte_ofdm_set_normalize(&q->ifft_mbsfn, true);
if (srslte_pbch_set_cell(&q->pbch, q->cell)) {
fprintf(stderr, "Error creating PBCH object\n");
return SRSLTE_ERROR;
@ -181,11 +210,21 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell)
fprintf(stderr, "Error creating PDSCH object\n");
return SRSLTE_ERROR;
}
if (srslte_pmch_set_cell(&q->pmch, q->cell)) {
fprintf(stderr, "Error creating PMCH object\n");
return SRSLTE_ERROR;
}
if (srslte_refsignal_cs_set_cell(&q->csr_signal, q->cell)) {
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
return SRSLTE_ERROR;
}
int mbsfn_area_id = 1;
if (srslte_refsignal_mbsfn_set_cell(&q->mbsfnr_signal, q->cell, mbsfn_area_id)) {
fprintf(stderr, "Error initializing MBSFNR signal (%d)\n",ret);
return SRSLTE_ERROR;
}
/* Generate PSS/SSS signals */
srslte_pss_generate(q->pss_signal, cell.id%3);
srslte_sss_generate(q->sss_signal0, q->sss_signal5, cell.id);
@ -201,6 +240,11 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell)
void srslte_enb_dl_set_non_mbsfn_region(srslte_enb_dl_t *q, uint8_t non_mbsfn_region)
{
srslte_ofdm_set_non_mbsfn_region(&q->ifft_mbsfn, non_mbsfn_region);
}
void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, float amp)
{
q->tx_amp = amp;
@ -334,17 +378,30 @@ void srslte_enb_dl_put_base(srslte_enb_dl_t *q, uint32_t tti)
}
void srslte_enb_dl_put_mbsfn_base(srslte_enb_dl_t *q, uint32_t tti)
{
uint32_t sf_idx1 = tti%10;
srslte_enb_dl_put_pcfich(q, sf_idx1);
srslte_refsignal_mbsfn_put_sf(q->cell, 0,q->csr_signal.pilots[0][sf_idx1], q->mbsfnr_signal.pilots[0][sf_idx1], q->sf_symbols[0]);
}
void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q)
{
// TODO: PAPR control
float norm_factor = (float) sqrt(q->cell.nof_prb)/15/sqrt(q->ifft[0].symbol_sz);
for (int i = 0; i < q->cell.nof_ports; i++) {
srslte_ofdm_tx_sf(&q->ifft[i]);
srslte_vec_sc_prod_cfc(q->ifft[i].out_buffer, q->tx_amp*norm_factor, q->ifft[i].out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
srslte_ofdm_tx_sf(&q->ifft[i]);
srslte_vec_sc_prod_cfc(q->ifft[i].out_buffer, norm_factor, q->ifft[i].out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
}
}
void srslte_enb_dl_gen_signal_mbsfn(srslte_enb_dl_t *q)
{
float norm_factor = (float) sqrt(q->cell.nof_prb)/15/sqrt(q->ifft_mbsfn.symbol_sz);
srslte_ofdm_tx_sf(&q->ifft_mbsfn);
srslte_vec_sc_prod_cfc(q->ifft_mbsfn.out_buffer, norm_factor, q->ifft_mbsfn.out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
}
int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, uint16_t rnti)
{
return srslte_pdsch_set_rnti(&q->pdsch, rnti);
@ -438,7 +495,23 @@ int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srs
return SRSLTE_SUCCESS;
}
int srslte_enb_dl_put_pmch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer, uint32_t sf_idx, uint8_t *data_mbms)
{
/* Encode PMCH */
int mbsfn_area_id = 1;
if (srslte_pmch_cfg(&q->pmch_cfg, q->cell, grant, q->cfi, sf_idx)) {
fprintf(stderr, "Error configuring PMCH\n");
return SRSLTE_ERROR;
}
/* Encode PMCH */
if (srslte_pmch_encode(&q->pmch, &q->pmch_cfg, softbuffer, data_mbms, mbsfn_area_id, q->sf_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
void srslte_enb_dl_save_signal(srslte_enb_dl_t *q, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, uint32_t tti, uint32_t rv_idx, uint16_t rnti, uint32_t cfi)
{

View File

@ -264,12 +264,29 @@ void srslte_pmch_free(srslte_pmch_t *q) {
}
int srslte_pmch_set_cell(srslte_pmch_t *q, srslte_cell_t cell)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
srslte_cell_isvalid(&cell))
{
memcpy(&q->cell, &cell, sizeof(srslte_cell_t));
q->max_re = q->cell.nof_prb * MAX_PMCH_RE;
INFO("PMCH: Cell config PCI=%d, %d ports, %d PRBs, max_symbols: %d\n", q->cell.nof_ports,
q->cell.id, q->cell.nof_prb, q->max_re);
ret = SRSLTE_SUCCESS;
}
return ret;
}
/* Precalculate the scramble sequences for a given MBSFN area ID. This function takes a while
* to execute.
*/
int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id) {
uint32_t i;
uint32_t i;
if (!q->seqs[area_id]) {
q->seqs[area_id] = calloc(1, sizeof(srslte_pmch_seq_t));
if (q->seqs[area_id]) {
@ -347,7 +364,6 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q,
data != NULL &&
cfg != NULL)
{
INFO("Decoding PMCH SF: %d, MBSFN area ID: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d, cfi=%d\n",
cfg->sf_idx, area_id, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, cfg->nbits[0].nof_re,
cfg->nbits[0].nof_bits, 0, cfg->grant.nof_prb, cfg->nbits[0].lstart-1);
@ -362,6 +378,7 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q,
/* extract symbols */
n = srslte_pmch_get(q, sf_symbols[j], q->symbols[j], cfg->nbits[0].lstart);
if (n != cfg->nbits[0].nof_re) {
fprintf(stderr, "PMCH 1 extract symbols error expecting %d symbols but got %d, lstart %d\n", cfg->nbits[0].nof_re, n, cfg->nbits[0].lstart);
return SRSLTE_ERROR;
}
@ -416,7 +433,6 @@ int srslte_pmch_encode(srslte_pmch_t *q,
/* Set pointers for layermapping & precoding */
cf_t *x[SRSLTE_MAX_LAYERS];
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && cfg != NULL)
{
for (i=0;i<q->cell.nof_ports;i++) {

View File

@ -199,8 +199,10 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell)
if (q != NULL &&
srslte_cell_isvalid(&cell))
{
q->pkt_errors = 0;
q->pkts_total = 0;
q->pdsch_pkt_errors = 0;
q->pdsch_pkts_total = 0;
q->pmch_pkt_errors = 0;
q->pmch_pkts_total = 0;
q->pending_ul_dci_rnti = 0;
if (q->cell.id != cell.id || q->cell.nof_prb == 0) {
@ -218,6 +220,12 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell)
return SRSLTE_ERROR;
}
}
if (srslte_ofdm_rx_set_prb(&q->fft_mbsfn, SRSLTE_CP_EXT, q->cell.nof_prb)) {
fprintf(stderr, "Error resizing MBSFN FFT\n");
return SRSLTE_ERROR;
}
if (srslte_chest_dl_set_cell(&q->chest, q->cell)) {
fprintf(stderr, "Error resizing channel estimator\n");
return SRSLTE_ERROR;
@ -237,9 +245,15 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell)
}
if (srslte_pdsch_set_cell(&q->pdsch, q->cell)) {
fprintf(stderr, "Error creating PDSCH object\n");
fprintf(stderr, "Error resizing PDSCH object\n");
return SRSLTE_ERROR;
}
if (srslte_pmch_set_cell(&q->pmch, q->cell)) {
fprintf(stderr, "Error resizing PMCH object\n");
return SRSLTE_ERROR;
}
q->current_rnti = 0;
}
ret = SRSLTE_SUCCESS;
@ -644,6 +658,7 @@ int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q,
noise_estimate,
q->current_mbsfn_area_id, data);
if (ret == SRSLTE_ERROR) {
q->pmch_pkt_errors++;
} else if (ret == SRSLTE_ERROR_INVALID_INPUTS) {

View File

@ -139,7 +139,7 @@ void srslte_vec_fprint_c(FILE *stream, cf_t *x, const uint32_t len) {
int i;
fprintf(stream, "[");
for (i=0;i<len;i++) {
fprintf(stream, "%+2.2f%+2.2fi, ", __real__ x[i], __imag__ x[i]);
fprintf(stream, "%+2.5f%+2.5fi, ", __real__ x[i], __imag__ x[i]);
}
fprintf(stream, "];\n");
}

View File

@ -100,6 +100,12 @@ void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
}
}
void pdcp::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu)
{
if(valid_mch_lcid(lcid)){
pdcp_array_mrb[lcid].write_sdu(sdu);
}
}
void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg)
{
if(lcid >= SRSLTE_N_RADIO_BEARERS) {
@ -114,6 +120,21 @@ void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg)
}
}
void pdcp::add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cfg)
{
if(lcid >= SRSLTE_N_RADIO_BEARERS) {
pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid);
return;
}
if (!pdcp_array_mrb[lcid].is_active()) {
pdcp_array_mrb[lcid].init(rlc, rrc, gw, pdcp_log, lcid, cfg);
pdcp_log->info("Added bearer %s\n", rrc->get_rb_name(lcid).c_str());
} else {
pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str());
}
}
void pdcp::config_security(uint32_t lcid,
uint8_t *k_enc,
uint8_t *k_int,
@ -175,6 +196,15 @@ void pdcp::write_pdu_pcch(byte_buffer_t *sdu)
rrc->write_pdu_pcch(sdu);
}
void pdcp::write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu)
{
if(0 == lcid) {
rrc->write_pdu_mch(lcid, sdu);
} else {
gw->write_pdu_mch(lcid, sdu);
}
}
/*******************************************************************************
Helpers
*******************************************************************************/
@ -191,4 +221,17 @@ bool pdcp::valid_lcid(uint32_t lcid)
return true;
}
bool pdcp::valid_mch_lcid(uint32_t lcid)
{
if(lcid >= SRSLTE_N_MCH_LCIDS) {
pdcp_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid);
return false;
}
if(!pdcp_array_mrb[lcid].is_active()) {
pdcp_log->error("PDCP entity for logical channel %d has not been activated\n", lcid);
return false;
}
return true;
}
} // namespace srsue

View File

@ -100,6 +100,16 @@ void rlc::get_metrics(rlc_metrics_t &m)
}
}
// Add multicast metrics
for (int i=0;i<SRSLTE_N_MCH_LCIDS;i++) {
m.dl_tput_mbps += (dl_tput_bytes_mrb[i]*8/(double)1e6)/secs;
if(rlc_array_mrb[i].is_mrb()) {
rlc_log->info("MCH_LCID=%d, RX throughput: %4.6f Mbps.\n",
i,
(dl_tput_bytes_mrb[i]*8/(double)1e6)/secs);
}
}
memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval));
reset_metrics();
}
@ -139,6 +149,12 @@ void rlc::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
rlc_array[lcid].write_sdu(sdu);
}
}
void rlc::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu)
{
if(valid_lcid_mrb(lcid)) {
rlc_array_mrb[lcid].write_sdu(sdu);
}
}
bool rlc::rb_is_um(uint32_t lcid) {
return rlc_array[lcid].get_mode()==RLC_MODE_UM;
@ -165,6 +181,15 @@ uint32_t rlc::get_total_buffer_state(uint32_t lcid)
}
}
uint32_t rlc::get_total_mch_buffer_state(uint32_t lcid)
{
if(valid_lcid_mrb(lcid)) {
return rlc_array_mrb[lcid].get_total_buffer_state();
} else {
return 0;
}
}
int rlc::read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
{
if(valid_lcid(lcid)) {
@ -174,6 +199,15 @@ int rlc::read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
return 0;
}
int rlc::read_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
{
if(valid_lcid_mrb(lcid)) {
ul_tput_bytes[lcid] += nof_bytes;
return rlc_array_mrb[lcid].read_pdu(payload, nof_bytes);
}
return 0;
}
void rlc::write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
{
if(valid_lcid(lcid)) {
@ -227,6 +261,14 @@ void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes)
}
}
void rlc::write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
{
if(valid_lcid_mrb(lcid)) {
dl_tput_bytes_mrb[lcid] += nof_bytes;
rlc_array_mrb[lcid].write_pdu(payload, nof_bytes);
}
}
/*******************************************************************************
RRC interface
*******************************************************************************/
@ -283,10 +325,31 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg)
} else {
rlc_log->warning("Bearer %s already created.\n", rrc->get_rb_name(lcid).c_str());
}
rlc_array[lcid].configure(cnfg);
rlc_array[lcid].configure(cnfg);
}
void rlc::add_bearer_mrb(uint32_t lcid)
{
// 36.321 Table 6.2.1-4
if(lcid >= SRSLTE_N_MCH_LCIDS) {
rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid);
return;
}
rlc_array_mrb[lcid].init(rlc_log, lcid, pdcp, rrc, mac_timers);
rlc_array_mrb[lcid].configure(srslte_rlc_config_t::mch_config());
}
void rlc::add_bearer_mrb_enb(uint32_t lcid)
{
if(lcid >= SRSLTE_N_MCH_LCIDS) {
rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid);
return;
}
rlc_array_mrb[lcid].init(rlc_log,lcid,pdcp,rrc,mac_timers);
rlc_array_mrb[lcid].configure(srslte_rlc_config_t::mch_config());
}
/*******************************************************************************
Helpers
*******************************************************************************/
@ -301,5 +364,16 @@ bool rlc::valid_lcid(uint32_t lcid)
return true;
}
bool rlc::valid_lcid_mrb(uint32_t lcid)
{
if(lcid >= SRSLTE_N_MCH_LCIDS) {
return false;
}
if(!rlc_array_mrb[lcid].is_mrb()) {
return false;
}
return true;
}
} // namespace srsue

View File

@ -81,11 +81,10 @@ rlc_am::~rlc_am()
pool->deallocate(tx_sdu);
}
}
void rlc_am::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
void rlc_am::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
srslte::mac_interface_timers *mac_timers)
{
log = log_;

View File

@ -26,6 +26,8 @@
#include "srslte/upper/rlc_um.h"
#include <sstream>
#include <srslte/upper/rlc_interface.h>
#define RX_MOD_BASE(x) (x-vr_uh-cfg.rx_window_size)%cfg.rx_mod
@ -42,6 +44,7 @@ rlc_um::rlc_um() : tx_sdu_queue(32)
bzero(&cfg, sizeof(srslte_rlc_um_config_t));
tx_sdu = NULL;
rx_sdu = NULL;
pool = byte_buffer_pool::get_instance();
@ -54,7 +57,7 @@ rlc_um::rlc_um() : tx_sdu_queue(32)
vr_ur_in_rx_sdu = 0;
mac_timers = NULL;
mac_timers = NULL;
pdu_lost = false;
}
@ -63,11 +66,10 @@ rlc_um::~rlc_um()
{
stop();
}
void rlc_um::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
void rlc_um::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
srsue::rrc_interface_rlc *rrc_,
srslte::mac_interface_timers *mac_timers_)
{
log = log_;
@ -82,24 +84,27 @@ void rlc_um::init(srslte::log *log_,
void rlc_um::configure(srslte_rlc_config_t cnfg_)
{
cfg = cnfg_.um;
if(cnfg_.um.is_mrb){
tx_sdu_queue.resize(512);
}
switch(cnfg_.rlc_mode)
{
case LIBLTE_RRC_RLC_MODE_UM_BI:
log->warning("%s configured in %s mode: "
"t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
rb_name().c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
break;
case LIBLTE_RRC_RLC_MODE_UM_UNI_UL:
log->warning("%s configured in %s mode: tx_sn_field_length=%u bits\n",
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
break;
case LIBLTE_RRC_RLC_MODE_UM_UNI_DL:
log->warning("%s configured in %s mode: "
"t_reordering=%d ms, rx_sn_field_length=%u bits\n",
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
rb_name().c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
break;
default:
@ -116,6 +121,11 @@ void rlc_um::empty_queue() {
}
}
bool rlc_um::is_mrb()
{
return cfg.is_mrb;
}
void rlc_um::stop()
{
reset();
@ -184,6 +194,7 @@ uint32_t rlc_um::get_buffer_state()
{
// Bytes needed for tx SDUs
uint32_t n_sdus = tx_sdu_queue.size();
uint32_t n_bytes = tx_sdu_queue.size_bytes();
if(tx_sdu)
{
@ -197,7 +208,7 @@ uint32_t rlc_um::get_buffer_state()
// Room needed for fixed header?
if(n_bytes > 0)
n_bytes += 3;
n_bytes += (cfg.is_mrb)?2:3;
return n_bytes;
}
@ -209,9 +220,10 @@ uint32_t rlc_um::get_total_buffer_state()
int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes)
{
int r;
log->debug("MAC opportunity - %d bytes\n", nof_bytes);
pthread_mutex_lock(&mutex);
int r = build_data_pdu(payload, nof_bytes);
r = build_data_pdu(payload, nof_bytes);
pthread_mutex_unlock(&mutex);
return r;
}
@ -235,7 +247,7 @@ void rlc_um::timer_expired(uint32_t timeout_id)
// 36.322 v10 Section 5.1.2.2.4
log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n",
rrc->get_rb_name(lcid).c_str());
rb_name().c_str());
log->warning("Lost PDU SN: %d\n", vr_ur);
pdu_lost = true;
@ -300,7 +312,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{
pool->deallocate(pdu);
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len);
rb_name().c_str(), nof_bytes, head_len);
return 0;
}
@ -310,7 +322,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
uint32_t space = pdu_space-head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n",
rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes);
rb_name().c_str(), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move;
pdu_ptr += to_move;
@ -321,6 +333,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu);
tx_sdu = NULL;
}
@ -339,7 +352,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
uint32_t space = pdu_space-head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
log->debug("%s adding new SDU segment - %d bytes of %d remaining\n",
rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes);
rb_name().c_str(), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move;
pdu_ptr += to_move;
@ -350,6 +363,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
{
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
pool->deallocate(tx_sdu);
tx_sdu = NULL;
}
@ -360,14 +374,16 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU
// Set SN
header.sn = vt_us;
vt_us = (vt_us + 1)%cfg.tx_mod;
// Add header and TX
log->debug("%s packing PDU with length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
log->debug("%s packing PDU with length %d\n", rb_name().c_str(), pdu->N_bytes);
rlc_um_write_data_pdu_header(&header, pdu);
memcpy(payload, pdu->msg, pdu->N_bytes);
uint32_t ret = pdu->N_bytes;
log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
pool->deallocate(pdu);
@ -382,20 +398,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header);
log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d",
rrc->get_rb_name(lcid).c_str(), header.sn);
rb_name().c_str(), header.sn);
if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur))
{
log->info("%s SN: %d outside rx window [%d:%d] - discarding\n",
rrc->get_rb_name(lcid).c_str(), header.sn, vr_ur, vr_uh);
rb_name().c_str(), header.sn, vr_ur, vr_uh);
return;
}
it = rx_window.find(header.sn);
if(rx_window.end() != it)
{
log->info("%s Discarding duplicate SN: %d\n",
rrc->get_rb_name(lcid).c_str(), header.sn);
rb_name().c_str(), header.sn);
return;
}
@ -486,9 +502,13 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
rx_sdu->reset();
} else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i);
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rb_name().c_str(), vr_ur, i);
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
if(cfg.is_mrb){
pdcp->write_pdu_mch(lcid, rx_sdu);
} else {
pdcp->write_pdu(lcid, rx_sdu);
}
rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
@ -499,6 +519,7 @@ void rlc_um::reassemble_rx_sdus()
}
// Handle last segment
if (rx_sdu->N_bytes > 0 || rlc_um_start_aligned(rx_window[vr_ur].header.fi)) {
log->debug("Writing last segment in SDU buffer. Lower edge vr_ur=%d, Buffer size=%d, segment size=%d\n",
vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes);
@ -514,7 +535,11 @@ void rlc_um::reassemble_rx_sdus()
} else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur);
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
if(cfg.is_mrb){
pdcp->write_pdu_mch(lcid, rx_sdu);
} else {
pdcp->write_pdu(lcid, rx_sdu);
}
rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
@ -569,9 +594,13 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
rx_sdu->reset();
} else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i);
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rb_name().c_str(), vr_ur, i);
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
if(cfg.is_mrb){
pdcp->write_pdu_mch(lcid, rx_sdu);
} else {
pdcp->write_pdu(lcid, rx_sdu);
}
rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
@ -608,9 +637,13 @@ void rlc_um::reassemble_rx_sdus()
log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n");
rx_sdu->reset();
} else {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur);
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rb_name().c_str(), vr_ur);
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
if(cfg.is_mrb){
pdcp->write_pdu_mch(lcid, rx_sdu);
} else {
pdcp->write_pdu(lcid, rx_sdu);
}
rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
@ -632,6 +665,9 @@ clean_up_rx_window:
bool rlc_um::inside_reordering_window(uint16_t sn)
{
if(cfg.rx_window_size == 0) {
return true;
}
if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
RX_MOD_BASE(sn) < RX_MOD_BASE(vr_uh))
{
@ -644,10 +680,20 @@ bool rlc_um::inside_reordering_window(uint16_t sn)
void rlc_um::debug_state()
{
log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n",
rrc->get_rb_name(lcid).c_str(), vt_us, vr_ur, vr_ux, vr_uh);
rb_name().c_str(), vt_us, vr_ur, vr_ux, vr_uh);
}
std::string rlc_um::rb_name() {
if(cfg.is_mrb) {
std::stringstream ss;
ss << "MRB" << lcid;
return ss.str();
} else {
return rrc->get_rb_name(lcid);
}
}
/****************************************************************************
* Header pack/unpack helper functions
* Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1
@ -662,7 +708,6 @@ void rlc_um_read_data_pdu_header(uint8_t *payload, uint32_t nof_bytes, rlc_umd_s
{
uint8_t ext;
uint8_t *ptr = payload;
// Fixed part
if(RLC_UMD_SN_SIZE_5_BITS == sn_size)
{
@ -709,7 +754,6 @@ void rlc_um_write_data_pdu_header(rlc_umd_pdu_header_t *header, byte_buffer_t *p
{
uint32_t i;
uint8_t ext = (header->N_li > 0) ? 1 : 0;
// Make room for the header
uint32_t len = rlc_um_packed_length(header);
pdu->msg -= len;

View File

@ -18,6 +18,10 @@
# and at http://www.gnu.org/licenses/.
#
add_executable(rrc_meas_test rrc_meas_test.cc)
target_link_libraries(rrc_meas_test srslte_common srslte_phy srslte_asn1)
add_test(rrc_meas_test rrc_meas_test)
add_executable(srslte_asn1_rrc_mcch_test srslte_asn1_rrc_mcch_test.cc)
target_link_libraries(srslte_asn1_rrc_mcch_test srslte_asn1 srslte_common)
add_test(srslte_asn1_rrc_mcch_test srslte_asn1_rrc_mcch_test)
add_executable(srslte_asn1_rrc_meas_test srslte_asn1_rrc_meas_test.cc)
target_link_libraries(srslte_asn1_rrc_meas_test srslte_common srslte_phy srslte_asn1)
add_test(srslte_asn1_rrc_meas_test srslte_asn1_rrc_meas_test)

View File

@ -0,0 +1,160 @@
/**
*
* \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/.
*
*/
#include <assert.h>
#include "srslte/asn1/liblte_rrc.h"
#include "srslte/common/log_filter.h"
#include "srslte/phy/utils/bit.h"
void pack_test()
{
srslte::log_filter log1("RRC");
log1.set_level(srslte::LOG_LEVEL_DEBUG);
log1.set_hex_limit(1024);
uint32_t known_reference_len = 30;
uint8_t known_reference[256] = {0x0d, 0x8f, 0xdf, 0xff, 0xff, 0xff, 0xe2, 0x2f,
0xfc, 0x38, 0x5e, 0x61, 0xec, 0xa8, 0x00, 0x00,
0x02, 0x02, 0x10, 0x00, 0x20, 0x05, 0xe6, 0x1e,
0xca, 0x80, 0x00, 0x00, 0x40, 0x42};
LIBLTE_BYTE_MSG_STRUCT byte_buf;
LIBLTE_BIT_MSG_STRUCT bit_buf;
LIBLTE_RRC_MCCH_MSG_STRUCT mcch_msg;
mcch_msg.commonsf_allocpatternlist_r9_size = 2;
mcch_msg.commonsf_allocpatternlist_r9[0].radio_fr_alloc_offset = 4;
mcch_msg.commonsf_allocpatternlist_r9[0].radio_fr_alloc_period = LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N32;
mcch_msg.commonsf_allocpatternlist_r9[0].subfr_alloc_num_frames = LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE;
mcch_msg.commonsf_allocpatternlist_r9[0].subfr_alloc = 0x3F;
mcch_msg.commonsf_allocpatternlist_r9[1].radio_fr_alloc_offset = 7;
mcch_msg.commonsf_allocpatternlist_r9[1].radio_fr_alloc_period = LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N8;
mcch_msg.commonsf_allocpatternlist_r9[1].subfr_alloc_num_frames = LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_FOUR;
mcch_msg.commonsf_allocpatternlist_r9[1].subfr_alloc = 0xFFFFFF;
mcch_msg.commonsf_allocperiod_r9 = LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF256;
mcch_msg.pmch_infolist_r9_size = 2;
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size = 1;
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].logicalchannelid_r9 = 1;
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9_present = true;
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9 = 1;
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_explicit = true;
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mcc = 0xF987;
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mnc = 0xF654;
mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.serviceid_r9 = 1;
mcch_msg.pmch_infolist_r9[0].pmch_config_r9.datamcs_r9 = 16;
mcch_msg.pmch_infolist_r9[0].pmch_config_r9.mch_schedulingperiod_r9 = LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF1024;
mcch_msg.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9 = 1535;
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9_size = 1;
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].logicalchannelid_r9 = 2;
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].sessionid_r9_present = true;
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].sessionid_r9 = 2;
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_explicit = true;
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mcc = 0xF987;
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mnc = 0xF654;
mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.serviceid_r9 = 2;
mcch_msg.pmch_infolist_r9[1].pmch_config_r9.datamcs_r9 = 8;
mcch_msg.pmch_infolist_r9[1].pmch_config_r9.mch_schedulingperiod_r9 = LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF8;
mcch_msg.pmch_infolist_r9[1].pmch_config_r9.sf_alloc_end_r9 = 0;
liblte_rrc_pack_mcch_msg(&mcch_msg, &bit_buf);
liblte_pack(bit_buf.msg, bit_buf.N_bits, byte_buf.msg);
byte_buf.N_bytes = (bit_buf.N_bits+7)/8;
//log1.info_hex(byte_buf.msg, byte_buf.N_bytes, "MCCH packed message:");
assert(byte_buf.N_bytes == known_reference_len);
for(uint32 i=0; i<known_reference_len; i++) {
assert(byte_buf.msg[i] == known_reference[i]);
}
}
void unpack_test()
{
uint32_t known_reference_len = 30;
uint8_t known_reference[256] = {0x0d, 0x8f, 0xdf, 0xff, 0xff, 0xff, 0xe2, 0x2f,
0xfc, 0x38, 0x5e, 0x61, 0xec, 0xa8, 0x00, 0x00,
0x02, 0x02, 0x10, 0x00, 0x20, 0x05, 0xe6, 0x1e,
0xca, 0x80, 0x00, 0x00, 0x40, 0x42};
LIBLTE_BYTE_MSG_STRUCT byte_buf;
LIBLTE_BIT_MSG_STRUCT bit_buf;
LIBLTE_RRC_MCCH_MSG_STRUCT mcch_msg;
liblte_unpack(known_reference, known_reference_len, bit_buf.msg);
bit_buf.N_bits = known_reference_len*8;
liblte_rrc_unpack_mcch_msg(&bit_buf, &mcch_msg);
assert(mcch_msg.commonsf_allocpatternlist_r9_size == 2);
assert(mcch_msg.commonsf_allocpatternlist_r9[0].radio_fr_alloc_offset == 4);
assert(mcch_msg.commonsf_allocpatternlist_r9[0].radio_fr_alloc_period == LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N32);
assert(mcch_msg.commonsf_allocpatternlist_r9[0].subfr_alloc_num_frames == LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE);
assert(mcch_msg.commonsf_allocpatternlist_r9[0].subfr_alloc == 0x3F);
assert(mcch_msg.commonsf_allocpatternlist_r9[1].radio_fr_alloc_offset == 7);
assert(mcch_msg.commonsf_allocpatternlist_r9[1].radio_fr_alloc_period == LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N8);
assert(mcch_msg.commonsf_allocpatternlist_r9[1].subfr_alloc_num_frames == LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_FOUR);
assert(mcch_msg.commonsf_allocpatternlist_r9[1].subfr_alloc == 0xFFFFFF);
assert(mcch_msg.commonsf_allocperiod_r9 == LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF256);
assert(mcch_msg.pmch_infolist_r9_size == 2);
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size == 1);
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].logicalchannelid_r9 == 1);
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9_present == true);
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9 == 1);
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_explicit == true);
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mcc == 0xF987);
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mnc == 0xF654);
assert(mcch_msg.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.serviceid_r9 == 1);
assert(mcch_msg.pmch_infolist_r9[0].pmch_config_r9.datamcs_r9 == 16);
assert(mcch_msg.pmch_infolist_r9[0].pmch_config_r9.mch_schedulingperiod_r9 == LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF1024);
assert(mcch_msg.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9 == 1535);
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9_size == 1);
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].logicalchannelid_r9 == 2);
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].sessionid_r9_present == true);
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].sessionid_r9 == 2);
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_explicit == true);
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mcc == 0xF987);
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mnc == 0xF654);
assert(mcch_msg.pmch_infolist_r9[1].mbms_sessioninfolist_r9[0].tmgi_r9.serviceid_r9 == 2);
assert(mcch_msg.pmch_infolist_r9[1].pmch_config_r9.datamcs_r9 == 8);
assert(mcch_msg.pmch_infolist_r9[1].pmch_config_r9.mch_schedulingperiod_r9 == LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF8);
assert(mcch_msg.pmch_infolist_r9[1].pmch_config_r9.sf_alloc_end_r9 == 0);
}
int main(int argc, char **argv)
{
pack_test();
unpack_test();
}

View File

@ -0,0 +1,91 @@
/**
*
* \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/.
*
*/
#include <assert.h>
#include <iostream>
#include <srslte/srslte.h>
#include "srslte/common/log_filter.h"
#include "srslte/asn1/liblte_rrc.h"
void basic_test() {
srslte::log_filter log1("RRC");
log1.set_level(srslte::LOG_LEVEL_DEBUG);
log1.set_hex_limit(128);
LIBLTE_BIT_MSG_STRUCT bit_buf;
LIBLTE_BIT_MSG_STRUCT bit_buf2;
LIBLTE_BYTE_MSG_STRUCT byte_buf;
LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg;
uint32_t rrc_message_len = 18;
uint8_t rrc_message[] = {0x08, 0x10, 0x49, 0x3C, 0x0D, 0x97, 0x89, 0x83,
0xC0, 0x84, 0x20, 0x82, 0x08, 0x21, 0x00, 0x01,
0xBC, 0x48};
srslte_bit_unpack_vector(rrc_message, bit_buf.msg, rrc_message_len*8);
bit_buf.N_bits = rrc_message_len*8;
liblte_rrc_unpack_ul_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &ul_dcch_msg);
assert(ul_dcch_msg.msg_type == LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT);
LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *rep = &ul_dcch_msg.msg.measurement_report;
assert(rep->meas_id == 1);
assert(rep->pcell_rsrp_result == 73);
assert(rep->pcell_rsrq_result == 15);
assert(rep->have_meas_result_neigh_cells);
assert(rep->meas_result_neigh_cells_choice == LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA);
LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA_STRUCT *eutra = &rep->meas_result_neigh_cells.eutra;
assert(eutra->n_result == 1);
assert(eutra->result_eutra_list[0].phys_cell_id == 357);
assert(eutra->result_eutra_list[0].have_cgi_info);
assert(eutra->result_eutra_list[0].cgi_info.have_plmn_identity_list);
assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.plmn_id.mcc == 0xF898);
assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.plmn_id.mnc == 0xFF78);
assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.cell_id == 0x1084104);
assert(eutra->result_eutra_list[0].cgi_info.tracking_area_code == 0x1042);
assert(eutra->result_eutra_list[0].cgi_info.have_plmn_identity_list);
assert(eutra->result_eutra_list[0].cgi_info.n_plmn_identity_list == 1);
assert(eutra->result_eutra_list[0].cgi_info.plmn_identity_list[0].mcc == 0xFFFF);
assert(eutra->result_eutra_list[0].cgi_info.plmn_identity_list[0].mnc == 0xFF00);
assert(eutra->result_eutra_list[0].meas_result.have_rsrp);
assert(eutra->result_eutra_list[0].meas_result.rsrp_result == 60);
assert(eutra->result_eutra_list[0].meas_result.have_rsrp);
assert(eutra->result_eutra_list[0].meas_result.rsrq_result == 18);
liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf2);
srslte_bit_pack_vector(bit_buf2.msg, byte_buf.msg, bit_buf2.N_bits);
byte_buf.N_bytes = (bit_buf2.N_bits+7)/8;
log1.info_hex(byte_buf.msg, byte_buf.N_bytes, "UL_DCCH Packed message\n");
for(uint32_t i=0; i<rrc_message_len; i++) {
assert(byte_buf.msg[i] == rrc_message[i]);
}
}
int main(int argc, char **argv) {
basic_test();
}

View File

@ -19,7 +19,7 @@
#
#######################################################################
# LOGGER TEST
# COMMON TESTS
#######################################################################
add_executable(logger_test logger_test.cc)
target_link_libraries(logger_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})

View File

@ -49,8 +49,8 @@ void* write_thread(void *a) {
int main(int argc, char **argv) {
bool result;
rlc_tx_queue q;
byte_buffer_t *b;
rlc_tx_queue q;
byte_buffer_t *b;
pthread_t thread;
args_t args;
u_int32_t r;
@ -71,6 +71,10 @@ int main(int argc, char **argv) {
pthread_join(thread, NULL);
if (q.size() != 0 || q.size_bytes() != 0) {
result = false;
}
if(result) {
printf("Passed\n");
exit(0);

View File

@ -80,6 +80,7 @@ public:
void write_pdu_bcch_bch(byte_buffer_t *sdu) {}
void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {}
void write_pdu_pcch(byte_buffer_t *sdu) {}
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu){}
// RRC interface
void max_retx_attempted(){}

View File

@ -263,6 +263,7 @@ public:
void write_pdu_bcch_bch(byte_buffer_t *sdu) {}
void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {}
void write_pdu_pcch(byte_buffer_t *sdu) {}
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu) {}
// RRC interface
void max_retx_attempted(){}

View File

@ -85,12 +85,18 @@ public:
void write_pdu_bcch_bch(byte_buffer_t *sdu) {}
void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {}
void write_pdu_pcch(byte_buffer_t *sdu) {}
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu)
{
assert(lcid == 3);
sdus[n_sdus++] = sdu;
}
// RRC interface
void max_retx_attempted(){}
std::string get_rb_name(uint32_t lcid) { return std::string(""); }
void set_expected_sdu_len(uint32_t len) { expected_sdu_len = len; }
byte_buffer_t *sdus[MAX_NBUFS];
int n_sdus;
uint32_t expected_sdu_len;
@ -235,7 +241,72 @@ void loss_test()
}
// This test checks the reassembly routines when a PDU
void basic_mbsfn_test()
{
srslte::log_filter log1("RLC_UM_1");
srslte::log_filter log2("RLC_UM_2");
log1.set_level(srslte::LOG_LEVEL_DEBUG);
log2.set_level(srslte::LOG_LEVEL_DEBUG);
log1.set_hex_limit(-1);
log2.set_hex_limit(-1);
rlc_um_tester tester;
mac_dummy_timers timers;
rlc_um rlc1;
rlc_um rlc2;
int len;
log1.set_level(srslte::LOG_LEVEL_DEBUG);
log2.set_level(srslte::LOG_LEVEL_DEBUG);
rlc1.init(&log1, 3, &tester, &tester, &timers);
rlc2.init(&log2, 3, &tester, &tester, &timers);
rlc1.configure(srslte_rlc_config_t::mch_config());
rlc2.configure(srslte_rlc_config_t::mch_config());
tester.set_expected_sdu_len(1);
// Push 5 SDUs into RLC1
byte_buffer_t sdu_bufs[NBUFS*2];
for(int i=0;i<NBUFS;i++)
{
*sdu_bufs[i].msg = i; // Write the index into the buffer
sdu_bufs[i].N_bytes = 1; // Give each buffer a size of 1 byte
rlc1.write_sdu(&sdu_bufs[i]);
}
assert(13 == rlc1.get_buffer_state());
// Read 5 PDUs from RLC1 (1 byte each)
byte_buffer_t pdu_bufs[NBUFS*2];
for(int i=0;i<NBUFS;i++)
{
len = rlc1.read_pdu(pdu_bufs[i].msg, 3); // 2 bytes for header + payload
pdu_bufs[i].N_bytes = len;
}
assert(0 == rlc1.get_buffer_state());
// Write 5 PDUs into RLC2
for(int i=0;i<NBUFS;i++)
{
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
}
assert(0 == rlc2.get_buffer_state());
assert(NBUFS == tester.n_sdus);
for(int i=0; i<tester.n_sdus; i++)
{
assert(tester.sdus[i]->N_bytes == 1);
assert(*(tester.sdus[i]->msg) == i);
}
}
// This test checks the reassembly routines when a PDU
// is lost that contains the beginning of SDU segment.
// The PDU that contains the end of this SDU _also_ contains
// a segment of another SDU.
@ -460,13 +531,14 @@ void reassmble_test2()
}
}
int main(int argc, char **argv) {
basic_test();
byte_buffer_pool::get_instance()->cleanup();
loss_test();
byte_buffer_pool::get_instance()->cleanup();
basic_mbsfn_test();
byte_buffer_pool::get_instance()->cleanup();
reassmble_test();
byte_buffer_pool::get_instance()->cleanup();
@ -474,3 +546,4 @@ int main(int argc, char **argv) {
reassmble_test2();
byte_buffer_pool::get_instance()->cleanup();
}

View File

@ -157,6 +157,7 @@ nof_ctrl_symbols = 3
#link_failure_nof_err = 50
#rrc_inactivity_timer = 10000
#max_prach_offset_us = 30
#enable_mbsfn = false
#####################################################################
# Manual RF calibration

View File

@ -126,6 +126,7 @@ typedef struct {
mac_args_t mac;
uint32_t rrc_inactivity_timer;
float metrics_period_secs;
bool enable_mbsfn;
bool print_buffer_state;
}expert_args_t;
@ -213,6 +214,7 @@ private:
int parse_sib3(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *data);
int parse_sib4(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data);
int parse_sib9(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *data);
int parse_sib13(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *data);
int parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_common);
int parse_rr(all_args_t *args, rrc_cfg_t *rrc_cfg);
int parse_drb(all_args_t *args, rrc_cfg_t *rrc_cfg);

View File

@ -83,7 +83,8 @@ public:
int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res);
int get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res);
int get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res);
void build_mch_sched(uint32_t tbs);
void rl_failure(uint16_t rnti);
void rl_ok(uint16_t rnti);
void tti_clock();
@ -114,7 +115,7 @@ public:
uint32_t get_current_tti();
void get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]);
void write_mcch(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT *mcch);
private:
static const int MAX_LOCATIONS = 20;
@ -141,7 +142,12 @@ private:
sched scheduler;
dl_metric_rr sched_metric_dl_rr;
ul_metric_rr sched_metric_ul_rr;
sched_interface::cell_cfg_t cell_config;
sched_interface::dl_pdu_mch_t mch;
/* Map of active UEs */
std::map<uint16_t, ue*> ue_db;
uint16_t last_rnti;
@ -171,6 +177,16 @@ private:
srslte_softbuffer_tx_t pcch_softbuffer_tx;
srslte_softbuffer_tx_t rar_softbuffer_tx;
const static int mcch_payload_len = 3000; //TODO FIND OUT MAX LENGTH
int current_mcch_length;
uint8_t mcch_payload_buffer[mcch_payload_len];
LIBLTE_RRC_MCCH_MSG_STRUCT mcch;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13;
const static int mtch_payload_len = 10000;
uint8_t mtch_payload_buffer[mtch_payload_len];
/* Functions for MAC Timers */
srslte::timers timers_db;
void setup_timers();

View File

@ -43,7 +43,7 @@ class ue : public srslte::read_pdu_interface,
{
public:
ue() : mac_msg_dl(20), mac_msg_ul(20), conres_id_available(false),
ue() : mac_msg_dl(20), mch_mac_msg_dl(10), mac_msg_ul(20), conres_id_available(false),
dl_ri_counter(0),
dl_pmi_counter(0),
conres_id(0),
@ -89,6 +89,7 @@ public:
void config(uint16_t rnti, uint32_t nof_prb, sched_interface *sched, rrc_interface_mac *rrc_, rlc_interface_mac *rlc, srslte::log *log_h);
uint8_t* generate_pdu(uint32_t tb_idx, sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST],
uint32_t nof_pdu_elems, uint32_t grant_size);
uint8_t* generate_mch_pdu(sched_interface::dl_pdu_mch_t sched, uint32_t nof_pdu_elems, uint32_t grant_size);
srslte_softbuffer_tx_t* get_tx_softbuffer(uint32_t harq_process, uint32_t tb_idx);
srslte_softbuffer_rx_t* get_rx_softbuffer(uint32_t tti);
@ -114,9 +115,9 @@ public:
bool is_phy_added;
int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t requested_bytes);
private:
int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t requested_bytes);
void allocate_sdu(srslte::sch_pdu *pdu, uint32_t lcid, uint32_t sdu_len);
bool process_ce(srslte::sch_subh *subh);
void allocate_ce(srslte::sch_pdu *pdu, uint32_t lcid);
@ -152,6 +153,7 @@ private:
// For UL there are multiple buffers per PID and are managed by pdu_queue
srslte::pdu_queue pdus;
srslte::sch_pdu mac_msg_dl, mac_msg_ul;
srslte::mch_pdu mch_mac_msg_dl;
rlc_interface_mac *rlc;
rrc_interface_mac* rrc;

View File

@ -30,12 +30,12 @@
#include <map>
#include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/enb_metrics_interface.h"
#include "srslte/common/gen_mch_tables.h"
#include "srslte/common/log.h"
#include "srslte/common/threads.h"
#include "srslte/common/thread_pool.h"
#include "srslte/radio/radio.h"
#include <string.h>
namespace srsenb {
typedef struct {
@ -48,6 +48,26 @@ typedef struct {
bool pregenerate_signals;
} phy_args_t;
typedef enum{
SUBFRAME_TYPE_REGULAR = 0,
SUBFRAME_TYPE_MBSFN,
SUBFRAME_TYPE_N_ITEMS,
} subframe_type_t;
static const char subframe_type_text[SUBFRAME_TYPE_N_ITEMS][20] = {"Regular", "MBSFN"};
/* Subframe config */
typedef struct {
subframe_type_t sf_type;
uint8_t mbsfn_area_id;
uint8_t non_mbsfn_region_length;
uint8_t mbsfn_mcs;
bool mbsfn_encode;
bool is_mcch;
} subframe_cfg_t;
class phch_common
{
public:
@ -119,6 +139,12 @@ public:
srslte_mod_t ue_db_get_last_ul_mod(uint16_t rnti, uint32_t tti);
void ue_db_set_last_ul_tbs(uint16_t rnti, uint32_t tti, int tbs);
int ue_db_get_last_ul_tbs(uint16_t rnti, uint32_t tti);
void configure_mbsfn(phy_interface_rrc::phy_cfg_mbsfn_t *cfg);
void build_mch_table();
void build_mcch_table();
void get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti);
private:
std::vector<pthread_mutex_t> tx_mutex;
@ -129,6 +155,17 @@ private:
uint32_t nof_mutex;
uint32_t max_mutex;
phy_interface_rrc::phy_cfg_mbsfn_t mbsfn;
bool sib13_configured;
bool mcch_configured;
uint8_t mch_table[40];
uint8_t mcch_table[10];
uint8_t mch_sf_idx_lut[10];
bool is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti);
bool is_mcch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti);
};
} // namespace srsenb

View File

@ -76,6 +76,7 @@ private:
void work_imp();
int encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants);
int encode_pmch(srslte_enb_dl_pdsch_t *grant, srslte_ra_dl_grant_t *phy_grant);
int decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch);
int encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks);
int encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants);
@ -96,7 +97,7 @@ private:
uint32_t t_rx, t_tx_dl, t_tx_ul;
srslte_enb_dl_t enb_dl;
srslte_enb_ul_t enb_ul;
srslte_softbuffer_tx_t temp_mbsfn_softbuffer;
srslte_timestamp_t tx_time;
// Class to store user information

View File

@ -49,6 +49,7 @@ typedef struct {
LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT srs_ul_cnfg;
} phy_cfg_t;
class phy : public phy_interface_mac,
public phy_interface_rrc
{
@ -62,6 +63,9 @@ public:
/* MAC->PHY interface */
int add_rnti(uint16_t rnti);
void rem_rnti(uint16_t rnti);
/*RRC-PHY interface*/
void configure_mbsfn(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT mcch);
static uint32_t tti_to_SFN(uint32_t tti);
static uint32_t tti_to_subf(uint32_t tti);
@ -73,7 +77,7 @@ public:
void get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]);
private:
phy_rrc_cfg_t phy_rrc_config;
uint32_t nof_workers;
const static int MAX_WORKERS = 4;
@ -84,7 +88,7 @@ private:
const static int WORKERS_THREAD_PRIO = 0;
srslte::radio *radio_handler;
srslte::log *log_h;
srslte::thread_pool workers_pool;
std::vector<phch_worker> workers;
phch_common workers_common;

View File

@ -89,11 +89,15 @@ private:
srslte::byte_buffer_pool *pool;
bool running;
bool run_enable;
bool mch_running;
bool mch_run_enable;
std::string gtp_bind_addr;
std::string mme_addr;
srsenb::pdcp_interface_gtpu *pdcp;
srslte::log *gtpu_log;
pthread_t mch_thread;
typedef struct{
uint32_t teids_in[SRSENB_N_RADIO_BEARERS];
@ -105,9 +109,22 @@ 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

@ -44,7 +44,8 @@ public:
void stop();
// pdcp_interface_rlc
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu);
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu){}
// pdcp_interface_rrc
void reset(uint16_t rnti);
@ -77,7 +78,8 @@ private:
uint16_t rnti;
srsenb::gtpu_interface_pdcp *gtpu;
// gw_interface_pdcp
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu);
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu){}
};
class user_interface_rrc : public srsue::rrc_interface_pdcp
@ -90,6 +92,7 @@ private:
void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu);
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu);
void write_pdu_pcch(srslte::byte_buffer_t *pdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu){}
std::string get_rb_name(uint32_t lcid);
};

View File

@ -32,6 +32,13 @@
#ifndef SRSENB_RLC_H
#define SRSENB_RLC_H
typedef struct {
uint32_t lcid;
uint32_t plmn;
uint16_t mtch_stop;
uint8_t *payload;
}mch_service_t;
namespace srsenb {
class rlc : public rlc_interface_mac,
@ -51,6 +58,7 @@ public:
void rem_user(uint16_t rnti);
void add_bearer(uint16_t rnti, uint32_t lcid);
void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t cnfg);
void add_bearer_mrb(uint16_t rnti, uint32_t lcid);
// rlc_interface_pdcp
void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu);
@ -73,7 +81,8 @@ private:
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu);
void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu);
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu);
void write_pdu_pcch(srslte::byte_buffer_t *sdu);
void write_pdu_pcch(srslte::byte_buffer_t *sdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu){}
void max_retx_attempted();
std::string get_rb_name(uint32_t lcid);
uint16_t rnti;
@ -85,7 +94,8 @@ private:
};
std::map<uint32_t,user_interface> users;
std::vector<mch_service_t> mch_services;
mac_interface_rlc *mac;
pdcp_interface_rlc *pdcp;
rrc_interface_rlc *rrc;

View File

@ -78,6 +78,7 @@ typedef struct {
typedef struct {
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT sibs[LIBLTE_RRC_MAX_SIB];
LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT mac_cnfg;
LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT pusch_cfg;
LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT antenna_info;
LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM pdsch_cfg;
@ -85,6 +86,7 @@ typedef struct {
rrc_cfg_cqi_t cqi_cfg;
rrc_cfg_qci_t qci_cfg[MAX_NOF_QCI];
srslte_cell_t cell;
bool enable_mbsfn;
uint32_t inactivity_timeout_ms;
}rrc_cfg_t;
@ -138,6 +140,9 @@ public:
void stop();
void get_metrics(rrc_metrics_t &m);
//rrc_interface_phy
void configure_mbsfn_sibs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13);
// rrc_interface_mac
void rl_failure(uint16_t rnti);
void add_user(uint16_t rnti);
@ -351,7 +356,8 @@ private:
sr_sched_t sr_sched;
sr_sched_t cqi_sched;
LIBLTE_RRC_MCCH_MSG_STRUCT mcch;
bool enable_mbms;
rrc_cfg_t cfg;
uint32_t nof_si_messages;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;

View File

@ -111,6 +111,17 @@ sib2 =
additional_spectrum_emission = 1;
};
mbsfnSubframeConfigList =
{
radioframeAllocationPeriod = "1";
subframeAllocationNumFrames = "1";
radioframeAllocationOffset = 0;
subframeAllocation = 63;
};
mbsfnSubframeConfigListLength = 0;
time_alignment_timer = "INFINITY"; // use "sf500", "sf750", etc.
};

View File

@ -206,6 +206,7 @@ bool enb::init(all_args_t *args_)
return false;
}
rrc_cfg.inactivity_timeout_ms = args->expert.rrc_inactivity_timer;
rrc_cfg.enable_mbsfn = args->expert.enable_mbsfn;
// Copy cell struct to rrc and phy
memcpy(&rrc_cfg.cell, &cell_cfg, sizeof(srslte_cell_t));

View File

@ -210,7 +210,39 @@ int enb::parse_sib2(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUC
("time_alignment_timer", &data->time_alignment_timer,
liblte_rrc_time_alignment_timer_text, LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS)
);
sib2.add_field(
new parser::field<uint32>
("mbsfnSubframeConfigListLength", &data->mbsfn_subfr_cnfg_list_size)
);
parser::section mbsfnSubframeConfigList("mbsfnSubframeConfigList");
sib2.add_subsection(&mbsfnSubframeConfigList);
mbsfnSubframeConfigList.add_field(
new parser::field<uint32>
("subframeAllocation", &data->mbsfn_subfr_cnfg_list[0].subfr_alloc)
);
mbsfnSubframeConfigList.add_field(
new parser::field<uint8>
("radioframeAllocationOffset", &data->mbsfn_subfr_cnfg_list[0].radio_fr_alloc_offset)
);
mbsfnSubframeConfigList.add_field(
new parser::field_enum_str<LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ENUM>
("subframeAllocationNumFrames", &data->mbsfn_subfr_cnfg_list[0].subfr_alloc_num_frames,
liblte_rrc_subframe_allocation_num_frames_text,LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_N_ITEMS)
);
mbsfnSubframeConfigList.add_field(
new parser::field_enum_str<LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_ENUM>
("radioframeAllocationPeriod", &data->mbsfn_subfr_cnfg_list[0].radio_fr_alloc_period,
liblte_rrc_radio_frame_allocation_period_text, LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N_ITEMS)
);
parser::section freqinfo("freqInfo");
sib2.add_subsection(&freqinfo);
freqinfo.add_field(
@ -701,6 +733,7 @@ uint32_t HexToBytes(const std::string& str, uint8_t *char_value, uint32_t buff_l
return i/2;
}
int enb::parse_sib9(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *data)
{
parser::section sib9("sib9");
@ -729,6 +762,86 @@ int enb::parse_sib9(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUC
}
}
int enb::parse_sib13(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *data)
{
parser::section sib13("sib13");
sib13.add_field(
new parser::field<uint8>
("mbsfn_area_info_list_size", &data->mbsfn_area_info_list_r9_size)
);
parser::section mbsfn_notification_config("mbsfn_notification_config");
sib13.add_subsection(&mbsfn_notification_config);
mbsfn_notification_config.add_field(
new parser::field_enum_str<LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_ENUM>
("mbsfn_notification_repetition_coeff", &data->mbsfn_notification_config.repetition_coeff, liblte_rrc_notification_repetition_coeff_r9_text,LIBLTE_RRC_NOTIFICATION_REPETITION_COEFF_R9_N_ITEMS)
);
mbsfn_notification_config.add_field(
new parser::field<uint8>
("mbsfn_notification_offset", &data->mbsfn_notification_config.offset)
);
mbsfn_notification_config.add_field(
new parser::field<uint8>
("mbsfn_notification_sf_index", &data->mbsfn_notification_config.sf_index)
);
parser::section mbsfn_area_info_list("mbsfn_area_info_list");
sib13.add_subsection(&mbsfn_area_info_list);
mbsfn_area_info_list.add_field(
new parser::field_enum_str<LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_ENUM>
("non_mbsfn_region_length", &data->mbsfn_area_info_list_r9[0].non_mbsfn_region_length,
liblte_rrc_non_mbsfn_region_length_text,LIBLTE_RRC_NON_MBSFN_REGION_LENGTH_N_ITEMS)
);
mbsfn_area_info_list.add_field(
new parser::field_enum_str<LIBLTE_RRC_MCCH_REPETITION_PERIOD_ENUM>
("mcch_repetition_period", &data->mbsfn_area_info_list_r9[0].mcch_repetition_period_r9,
liblte_rrc_mcch_repetition_period_r9_text,LIBLTE_RRC_MCCH_REPETITION_PERIOD_N_ITEMS)
);
mbsfn_area_info_list.add_field(
new parser::field_enum_str<LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_ENUM>
("mcch_modification_period", &data->mbsfn_area_info_list_r9[0].mcch_modification_period_r9,
liblte_rrc_mcch_modification_period_r9_text,LIBLTE_RRC_MCCH_MODIFICATION_PERIOD_N_ITEMS)
);
mbsfn_area_info_list.add_field(
new parser::field_enum_str<LIBLTE_RRC_MCCH_SIGNALLING_MCS_ENUM>
("signalling_mcs", &data->mbsfn_area_info_list_r9[0].signalling_mcs_r9,
liblte_rrc_mcch_signalling_mcs_r9_text,LIBLTE_RRC_MCCH_SIGNALLING_MCS_N_ITEMS)
);
mbsfn_area_info_list.add_field(
new parser::field<uint8>
("mbsfn_area_id", &data->mbsfn_area_info_list_r9[0].mbsfn_area_id_r9)
);
mbsfn_area_info_list.add_field(
new parser::field<uint8>
("notification_indicator", &data->mbsfn_area_info_list_r9[0].notification_indicator_r9)
);
mbsfn_area_info_list.add_field(
new parser::field<uint8>
("mcch_offset", &data->mbsfn_area_info_list_r9[0].mcch_offset_r9)
);
mbsfn_area_info_list.add_field(
new parser::field<uint8>
("sf_alloc_info", &data->mbsfn_area_info_list_r9[0].sf_alloc_info_r9)
);
return parser::parse_section(filename, &sib13);
}
int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_common)
{
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1 = &rrc_cfg->sibs[0].sib.sib1;
@ -741,7 +854,8 @@ int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_
rrc_cfg->sibs[3].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *sib9 = &rrc_cfg->sibs[8].sib.sib9;
rrc_cfg->sibs[8].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13 = &rrc_cfg->sibs[12].sib.sib13;
rrc_cfg->sibs[12].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13;
// Read SIB1 configuration from file
bzero(sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT));
@ -765,7 +879,7 @@ int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_
if (parse_sib2(args->enb_files.sib_config, sib2)) {
return -1;
}
// SRS not yet supported
sib2->rr_config_common_sib.srs_ul_cnfg.present = false;
if (sib2->ul_bw.present) {
@ -817,7 +931,13 @@ int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_
return -1;
}
}
if (sib_is_present(sib1->sched_info, sib1->N_sched_info, LIBLTE_RRC_SIB_TYPE_13_v920)) {
bzero(sib13, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT));
if (parse_sib13(args->enb_files.sib_config, sib13)) {
return -1;
}
}
// Copy PHY common configuration
bzero(phy_config_common, sizeof(phy_cfg_t));
memcpy(&phy_config_common->prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT));

View File

@ -149,10 +149,19 @@ void mac::start_pcap(srslte::mac_pcap* pcap_)
*******************************************************/
int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue)
{
if (ue_db.count(rnti)) {
return scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue);
if (ue_db.count(rnti)) {
if(rnti != SRSLTE_MRNTI){
return scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue);
} else {
for(uint32_t i = 0; i < mch.num_mtch_sched; i++){
if(lc_id == mch.mtch_sched[i].lcid){
mch.mtch_sched[i].lcid_buffer_size = tx_queue;
}
}
return 0;
}
} else {
Error("User rnti=0x%x not found\n", rnti);
Error("User rnti=0x%x not found- this\n", rnti);
return -1;
}
}
@ -230,6 +239,7 @@ int mac::ue_rem(uint16_t rnti)
int mac::cell_cfg(sched_interface::cell_cfg_t* cell_cfg)
{
memcpy(&this->cell_config, cell_cfg, sizeof(sched_interface::cell_cfg_t));
return scheduler.cell_cfg(cell_cfg);
}
@ -238,14 +248,14 @@ void mac::get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS])
int cnt=0;
for(std::map<uint16_t, ue*>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
ue *u = iter->second;
u->metrics_read(&metrics[cnt]);
cnt++;
if(iter->first != SRSLTE_MRNTI) {
u->metrics_read(&metrics[cnt]);
cnt++;
}
}
}
/********************************************************
*
* PHY interface
@ -439,7 +449,6 @@ int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv)
// Register new user in RRC
rrc_h->add_user(last_rnti);
// Trigger scheduler RACH
scheduler.dl_rach_info(tti, ra_id, last_rnti, 7);
@ -578,6 +587,96 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
return SRSLTE_SUCCESS;
}
void mac::build_mch_sched(uint32_t tbs)
{
int sfs_per_sched_period = mcch.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9;
int bytes_per_sf = tbs/8 - 6;// leave 6 bytes for header
int total_space_avail_bytes = sfs_per_sched_period*bytes_per_sf;
int total_bytes_to_tx = 0;
// calculate total bytes to be scheduled
for (uint32_t i = 0; i < mch.num_mtch_sched; i++) {
total_bytes_to_tx += mch.mtch_sched[i].lcid_buffer_size;
mch.mtch_sched[i].stop = 0;
}
int last_mtch_stop = 0;
if(total_bytes_to_tx >= total_space_avail_bytes){
for(uint32_t i = 0; i < mch.num_mtch_sched;i++){
double ratio = mch.mtch_sched[i].lcid_buffer_size/total_bytes_to_tx;
float assigned_sfs = floor(sfs_per_sched_period*ratio);
mch.mtch_sched[i].stop = last_mtch_stop + (uint32_t)assigned_sfs;
last_mtch_stop = mch.mtch_sched[i].stop;
}
}else {
for(uint32_t i = 0; i < mch.num_mtch_sched;i++){
float assigned_sfs = ceil(((float)mch.mtch_sched[i].lcid_buffer_size)/((float)bytes_per_sf));
mch.mtch_sched[i].stop = last_mtch_stop + (uint32_t)assigned_sfs;
last_mtch_stop = mch.mtch_sched[i].stop;
}
}
}
int mac::get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res)
{
srslte_ra_mcs_t mcs;
srslte_ra_mcs_t mcs_data;
mcs.idx = this->sib13.mbsfn_area_info_list_r9[0].signalling_mcs_r9;
mcs_data.idx = this->mcch.pmch_infolist_r9[0].pmch_config_r9.datamcs_r9;
srslte_dl_fill_ra_mcs(&mcs, this->cell_config.cell.nof_prb);
srslte_dl_fill_ra_mcs(&mcs_data, this->cell_config.cell.nof_prb);
if(is_mcch){
build_mch_sched(mcs_data.tbs);
mch.mcch_payload = mcch_payload_buffer;
mch.current_sf_allocation_num = 1;
Info("MCH Sched Info: LCID: %d, Stop: %d, tti is %d \n", mch.mtch_sched[0].lcid, mch.mtch_sched[0].stop, tti);
for(uint32_t i = 0; i < mch.num_mtch_sched; i++) {
mch.pdu[i].lcid = srslte::sch_subh::MCH_SCHED_INFO;
// mch.mtch_sched[i].lcid = 1+i;
}
mch.pdu[mch.num_mtch_sched].lcid = 0;
mch.pdu[mch.num_mtch_sched].nbytes = current_mcch_length;
dl_sched_res->sched_grants[0].rnti = SRSLTE_MRNTI;
dl_sched_res->sched_grants[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, mch.num_mtch_sched + 1, mcs.tbs/8);
} else {
uint32_t current_lcid = 1;
uint32_t mtch_index = 0;
uint32_t mtch_stop = mch.mtch_sched[mch.num_mtch_sched -1].stop;
for(uint32_t i = 0;i < mch.num_mtch_sched;i++) {
if(mch.current_sf_allocation_num <= mch.mtch_sched[i].stop){
current_lcid = mch.mtch_sched[i].lcid;
mtch_index = i;
break;
}
}
if(mch.current_sf_allocation_num <= mtch_stop) {
int requested_bytes = (mcs_data.tbs/8 > (int)mch.mtch_sched[mtch_index].lcid_buffer_size)?(mch.mtch_sched[mtch_index].lcid_buffer_size):((mcs_data.tbs/8) - 2);
int bytes_received = ue_db[SRSLTE_MRNTI]->read_pdu(current_lcid, mtch_payload_buffer, requested_bytes);
mch.pdu[0].lcid = current_lcid;
mch.pdu[0].nbytes = bytes_received;
mch.mtch_sched[0].mtch_payload = mtch_payload_buffer;
dl_sched_res->sched_grants[0].rnti = SRSLTE_MRNTI;
if(bytes_received){
dl_sched_res->sched_grants[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, 1, mcs_data.tbs/8);
}
} else {
//TRANSMIT NOTHING
}
mch.current_sf_allocation_num++;
}
return SRSLTE_SUCCESS;
}
uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32_t nof_grants, int rar_idx, uint32_t pdu_len)
{
uint8_t grant_buffer[64];
@ -605,7 +704,7 @@ uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32
}
uint8_t* mac::assemble_si(uint32_t index)
{
{
rlc_h->read_pdu_bcch_dlsch(index, bcch_dlsch_payload);
return bcch_dlsch_payload;
}
@ -675,9 +774,6 @@ void mac::tti_clock()
timers_thread.tti_clock();
}
/********************************************************
*
* Interface for upper layer timers
@ -700,7 +796,6 @@ srslte::timers::timer* mac::timer_get(uint32_t timer_id)
}
/********************************************************
*
* Class to run timers with normal priority
@ -790,8 +885,33 @@ bool mac::process_pdus()
}
void mac::write_mcch(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT *mcch)
{
bzero(&mcch_payload_buffer[0],sizeof(uint8_t)*3000);
LIBLTE_BIT_MSG_STRUCT bitbuffer;
liblte_rrc_pack_mcch_msg(mcch, &bitbuffer);
memcpy(&this->mcch ,mcch, sizeof(LIBLTE_RRC_MCCH_MSG_STRUCT));
mch.num_mtch_sched = this->mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size;
for(uint32_t i = 0; i < mch.num_mtch_sched; i++){
mch.mtch_sched[i].lcid = this->mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[i].logicalchannelid_r9;
}
memcpy(&this->sib2,sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT));
memcpy(&this->sib2,sib13, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT)); // TODO: consolidate relevant parts into 1 struct
current_mcch_length = floor(bitbuffer.N_bits/8);
if(bitbuffer.N_bits%8 != 0) {
current_mcch_length++;
}
int rlc_header_len = 1;
current_mcch_length = current_mcch_length + rlc_header_len;
srslte_bit_pack_vector(&bitbuffer.msg[0], &mcch_payload_buffer[rlc_header_len], bitbuffer.N_bits);
ue_db[SRSLTE_MRNTI] = new ue;
ue_db[SRSLTE_MRNTI]->config(SRSLTE_MRNTI, cell.nof_prb, &scheduler, rrc_h, rlc_h, log_h);
rrc_h->add_user(SRSLTE_MRNTI);
}
}

View File

@ -545,7 +545,7 @@ int sched::dl_sched_bc(dl_sched_bc_t bc[MAX_BC_LIST])
}
uint32_t n_sf = (current_tti-pending_sibs[i].window_start);
if ((i == 0 && (sfn%2) == 0 && sf_idx == 5) ||
(i > 0 && n_sf >= (cfg.si_window_ms/nof_tx)*pending_sibs[i].n_tx && sf_idx==1))
(i > 0 && n_sf >= (cfg.si_window_ms/nof_tx)*pending_sibs[i].n_tx && sf_idx==9))
{
uint32_t rv = get_rvidx(pending_sibs[i].n_tx);
@ -775,10 +775,10 @@ int sched::dl_sched(uint32_t tti, sched_interface::dl_sched_res_t* sched_result)
/* Schedule Broadcast data */
sched_result->nof_bc_elems += dl_sched_bc(sched_result->bc);
/* Schedule RAR */
sched_result->nof_rar_elems += dl_sched_rar(sched_result->rar);
/* Schedule pending RLC data */
sched_result->nof_data_elems += dl_sched_data(sched_result->data);

View File

@ -173,7 +173,7 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channe
if (mac_msg_ul.get()->get_sdu_lcid() == 0) {
uint8_t *x = mac_msg_ul.get()->get_sdu_ptr();
uint32_t sum = 0;
for (int i = 0; i < mac_msg_ul.get()->get_payload_size(); i++) {
for (uint32_t i = 0; i < mac_msg_ul.get()->get_payload_size(); i++) {
sum += x[i];
}
if (sum == 0) {
@ -200,7 +200,7 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channe
// Save contention resolution if lcid == 0
if (mac_msg_ul.get()->get_sdu_lcid() == 0 && route_pdu) {
int nbytes = srslte::sch_subh::MAC_CE_CONTRES_LEN;
if (mac_msg_ul.get()->get_payload_size() >= nbytes) {
if (mac_msg_ul.get()->get_payload_size() >= (uint32_t)nbytes) {
uint8_t *ue_cri_ptr = (uint8_t *) &conres_id;
uint8_t *pkt_ptr = mac_msg_ul.get()->get_sdu_ptr(); // Warning here: we want to include the
for (int i = 0; i < nbytes; i++) {
@ -329,7 +329,7 @@ void ue::allocate_sdu(srslte::sch_pdu *pdu, uint32_t lcid, uint32_t total_sdu_le
while(sdu_len > 3 && n > 0) {
if (pdu->new_subh()) { // there is space for a new subheader
log_h->debug("SDU: set_sdu(), lcid=%d, sdu_len=%d, sdu_space=%d\n", lcid, sdu_len, sdu_space);
n = pdu->get()->set_sdu(lcid, sdu_len, this);
n = pdu->get()->set_sdu(lcid, sdu_len, this);
if (n > 0) { // new SDU could be added
sdu_len -= n;
log_h->debug("SDU: rnti=0x%x, lcid=%d, nbytes=%d, rem_len=%d\n",
@ -390,6 +390,29 @@ uint8_t* ue::generate_pdu(uint32_t tb_idx, sched_interface::dl_sched_pdu_t pdu[s
return ret;
}
uint8_t* ue::generate_mch_pdu(sched_interface::dl_pdu_mch_t sched, uint32_t nof_pdu_elems , uint32_t grant_size)
{
uint8_t *ret = NULL;
pthread_mutex_lock(&mutex);
mch_mac_msg_dl.init_tx(tx_payload_buffer[0],grant_size);
for(uint32_t i = 0; i <nof_pdu_elems;i++){
if(sched.pdu[i].lcid == srslte::mch_subh::MCH_SCHED_INFO) {
mch_mac_msg_dl.new_subh();
mch_mac_msg_dl.get()->set_next_mch_sched_info(sched.mtch_sched[i].lcid,sched.mtch_sched[i].stop);
} else if (sched.pdu[i].lcid == 0) {
mch_mac_msg_dl.new_subh();
mch_mac_msg_dl.get()->set_sdu(0, sched.pdu[i].nbytes, sched.mcch_payload);
} else if (sched.pdu[i].lcid <= srslte::mch_subh::MTCH_MAX_LCID) {
mch_mac_msg_dl.new_subh();
mch_mac_msg_dl.get()->set_sdu(sched.pdu[i].lcid, sched.pdu[i].nbytes,sched.mtch_sched[i].mtch_payload);
}
}
ret = mch_mac_msg_dl.write_packet(log_h);
pthread_mutex_unlock(&mutex);
return ret;
}
/******* METRICS interface ***************/

View File

@ -183,6 +183,10 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
("expert.rrc_inactivity_timer",
bpo::value<uint32_t>(&args->expert.rrc_inactivity_timer)->default_value(10000),
"Inactivity timer in ms")
("expert.enable_mbsfn",
bpo::value<bool>(&args->expert.enable_mbsfn)->default_value(false),
"enables mbms in the enodeb")
("expert.print_buffer_state",
bpo::value<bool>(&args->expert.print_buffer_state)->default_value(false),

View File

@ -26,7 +26,7 @@
#include "srslte/common/threads.h"
#include "srslte/common/log.h"
#include <sstream>
#include "srsenb/hdr/phy/txrx.h"
#include <assert.h>
@ -57,6 +57,8 @@ bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interf
mac = mac_;
memcpy(&cell, cell_, sizeof(srslte_cell_t));
is_first_of_burst = true;
is_first_tx = true;
for (uint32_t i=0;i<max_mutex;i++) {
@ -177,5 +179,144 @@ int phch_common::ue_db_get_last_ul_tbs(uint16_t rnti, uint32_t tti) {
}
return ret;
}
void phch_common::configure_mbsfn(phy_interface_rrc::phy_cfg_mbsfn_t *cfg) {
memcpy(&mbsfn, cfg, sizeof(phy_interface_rrc::phy_cfg_mbsfn_t));
build_mch_table();
build_mcch_table();
sib13_configured = true;
mcch_configured = true;
}
void phch_common::build_mch_table() {
// First reset tables
bzero(&mch_table[0], sizeof(uint8_t)*40);
// 40 element table represents 4 frames (40 subframes)
generate_mch_table(&mch_table[0], mbsfn.mbsfn_subfr_cnfg.subfr_alloc,(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE == mbsfn.mbsfn_subfr_cnfg.subfr_alloc_num_frames)?1:4);
// Debug
std::stringstream ss;
ss << "|";
for(uint32_t j=0; j<40; j++) {
ss << (int) mch_table[j] << "|";
}
}
void phch_common::build_mcch_table() {
bzero(&mcch_table[0], sizeof(uint8_t)*10);
generate_mcch_table(&mcch_table[0], mbsfn.mbsfn_area_info.sf_alloc_info_r9);
std::stringstream ss;
ss << "|";
for(uint32_t j=0; j<10; j++) {
ss << (int) mcch_table[j] << "|";
}
}
bool phch_common::is_mcch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti)
{
uint32_t sfn; // System Frame Number
uint8_t sf; // Subframe
uint8_t offset;
uint8_t period;
sfn = phy_tti/10;
sf = phy_tti%10;
if(sib13_configured) {
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *subfr_cnfg = &mbsfn.mbsfn_subfr_cnfg;
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *area_info = &mbsfn.mbsfn_area_info;
offset = area_info->mcch_offset_r9;
period = liblte_rrc_mcch_repetition_period_r9_num[area_info->mcch_repetition_period_r9];
if((sfn%period == offset) && mcch_table[sf] > 0) {
cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9;
cfg->non_mbsfn_region_length = liblte_rrc_non_mbsfn_region_length_num[area_info->non_mbsfn_region_length];
cfg->mbsfn_mcs = liblte_rrc_mcch_signalling_mcs_r9_num[area_info->signalling_mcs_r9];
cfg->mbsfn_encode = true;
cfg->is_mcch = true;
return true;
}
}
return false;
}
bool phch_common::is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti)
{
uint32_t sfn; // System Frame Number
uint8_t sf; // Subframe
uint8_t offset;
uint8_t period;
sfn = phy_tti/10;
sf = phy_tti%10;
// Set some defaults
cfg->mbsfn_area_id = 0;
cfg->non_mbsfn_region_length = 1;
cfg->mbsfn_mcs = 2;
cfg->mbsfn_encode = false;
cfg->is_mcch = false;
// Check for MCCH
if(is_mcch_subframe(cfg, phy_tti)) {
return true;
}
// Not MCCH, check for MCH
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *subfr_cnfg = &mbsfn.mbsfn_subfr_cnfg;
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *area_info = &mbsfn.mbsfn_area_info;
offset = subfr_cnfg->radio_fr_alloc_offset;
period = liblte_rrc_radio_frame_allocation_period_num[subfr_cnfg->radio_fr_alloc_period];
if(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE == subfr_cnfg->subfr_alloc_num_frames) {
if((sfn%period == offset) && (mch_table[sf] > 0)) {
if(sib13_configured) {
cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9;
cfg->non_mbsfn_region_length = liblte_rrc_non_mbsfn_region_length_num[area_info->non_mbsfn_region_length];
if(mcch_configured) {
// Iterate through PMCH configs to see which one applies in the current frame
LIBLTE_RRC_MCCH_MSG_STRUCT *mcch = &mbsfn.mcch;
uint32_t sf_alloc_idx = sfn%liblte_rrc_mbsfn_common_sf_alloc_period_r9_num[mcch->commonsf_allocperiod_r9];
for(uint32_t i=0; i<mcch->pmch_infolist_r9_size; i++) {
//if(sf_alloc_idx < mch_period_stop) {
cfg->mbsfn_mcs = mcch->pmch_infolist_r9[i].pmch_config_r9.datamcs_r9;
cfg->mbsfn_encode = true;
//}
}
}
}
return true;
}
}else if(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_FOUR == subfr_cnfg->subfr_alloc_num_frames) {
uint8_t idx = sfn%period;
if((idx >= offset) && (idx < offset+4)) {
if(mch_table[(idx*10)+sf] > 0){
if(sib13_configured) {
cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9;
cfg->non_mbsfn_region_length = liblte_rrc_non_mbsfn_region_length_num[area_info->non_mbsfn_region_length];
// TODO: check for MCCH configuration, set MCS and decode
}
return true;
}
}
}
return false;
}
void phch_common::get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti)
{
if(is_mch_subframe(cfg, phy_tti)) {
cfg->sf_type = SUBFRAME_TYPE_MBSFN;
}else{
cfg->sf_type = SUBFRAME_TYPE_REGULAR;
}
}
}

View File

@ -140,7 +140,14 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_)
for (int i=0;i<10;i++) {
add_rnti(1+i);
}
if (srslte_softbuffer_tx_init(&temp_mbsfn_softbuffer, phy->cell.nof_prb)) {
fprintf(stderr, "Error initiating soft buffer\n");
exit(-1);
}
srslte_softbuffer_tx_reset(&temp_mbsfn_softbuffer);
srslte_pucch_set_threshold(&enb_ul.pucch, 0.8);
srslte_sch_set_max_noi(&enb_ul.pusch.ul_sch, phy->params.pusch_max_its);
srslte_enb_dl_set_amp(&enb_dl, phy->params.tx_amplitude);
@ -159,7 +166,7 @@ void phch_worker::stop()
{
running = false;
pthread_mutex_lock(&mutex);
srslte_softbuffer_tx_free(&temp_mbsfn_softbuffer);
srslte_enb_dl_free(&enb_dl);
srslte_enb_ul_free(&enb_ul);
for (int p = 0; p < SRSLTE_MAX_PORTS; p++) {
@ -351,9 +358,11 @@ void phch_worker::work_imp()
if (!running) {
return;
}
subframe_cfg_t sf_cfg;
phy->get_sf_config(&sf_cfg, tti_tx_dl);// TODO difference between tti_tx_dl and t_tx_dl
pthread_mutex_lock(&mutex);
mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants;
mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants;
mac_interface_phy *mac = phy->mac;
@ -377,9 +386,19 @@ void phch_worker::work_imp()
decode_pucch();
// Get DL scheduling for the TX TTI from MAC
if (mac->get_dl_sched(tti_tx_dl, &dl_grants[t_tx_dl]) < 0) {
Error("Getting DL scheduling from MAC\n");
goto unlock;
if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) {
if (mac->get_dl_sched(tti_tx_dl, &dl_grants[t_tx_dl]) < 0) {
Error("Getting DL scheduling from MAC\n");
goto unlock;
}
} else {
dl_grants[t_tx_dl].cfi = sf_cfg.non_mbsfn_region_length;
srslte_enb_dl_set_non_mbsfn_region(&enb_dl, sf_cfg.non_mbsfn_region_length);
if(mac->get_mch_sched(sf_cfg.is_mcch, &dl_grants[t_tx_dl])){
Error("Getting MCH packets from MAC\n");
goto unlock;
}
}
if (dl_grants[t_tx_dl].cfi < 1 || dl_grants[t_tx_dl].cfi > 3) {
@ -396,18 +415,30 @@ void phch_worker::work_imp()
// Put base signals (references, PBCH, PCFICH and PSS/SSS) into the resource grid
srslte_enb_dl_clear_sf(&enb_dl);
srslte_enb_dl_set_cfi(&enb_dl, dl_grants[t_tx_dl].cfi);
srslte_enb_dl_put_base(&enb_dl, tti_tx_dl);
// Put UL/DL grants to resource grid. PDSCH data will be encoded as well.
encode_pdcch_dl(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants);
if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) {
srslte_enb_dl_put_base(&enb_dl, tti_tx_dl);
} else if (sf_cfg.mbsfn_encode){
srslte_enb_dl_put_mbsfn_base(&enb_dl, tti_tx_dl);
}
if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) {
// Put UL/DL grants to resource grid. PDSCH data will be encoded as well.
encode_pdcch_dl(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants);
encode_pdsch(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants);
}else {
srslte_ra_dl_grant_t phy_grant;
phy_grant.mcs[0].idx = sf_cfg.mbsfn_mcs;
encode_pmch(&dl_grants[t_tx_dl].sched_grants[0], &phy_grant);
}
encode_pdcch_ul(ul_grants[t_tx_ul].sched_grants, ul_grants[t_tx_ul].nof_grants);
encode_pdsch(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants);
// Put pending PHICH HARQ ACK/NACK indications into subframe
encode_phich(ul_grants[t_tx_ul].phich, ul_grants[t_tx_ul].nof_phich);
// Prepare for receive ACK for DL grants in t_tx_dl+4
phy->ue_db_clear(TTIMOD(TTI_TX(t_tx_dl)));
for (uint32_t i=0;i<dl_grants[t_tx_dl].nof_grants;i++) {
// SI-RNTI and RAR-RNTI do not have ACK
uint16_t rnti = dl_grants[t_tx_dl].sched_grants[i].rnti;
@ -424,10 +455,14 @@ void phch_worker::work_imp()
}
}
}
// Generate signal and transmit
srslte_enb_dl_gen_signal(&enb_dl);
Debug("Sending to radio\n");
if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) {
srslte_enb_dl_gen_signal(&enb_dl);
} else {
srslte_enb_dl_gen_signal_mbsfn(&enb_dl);
}
Debug("Sending to radio\n");
phy->worker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time);
#ifdef DEBUG_WRITE_FILE
@ -837,6 +872,25 @@ int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_gra
return 0;
}
int phch_worker::encode_pmch(srslte_enb_dl_pdsch_t *grant, srslte_ra_dl_grant_t *phy_grant)
{
phy_grant->tb_en[0] = true;
phy_grant->tb_en[1] = false;
phy_grant->nof_prb = enb_dl.cell.nof_prb;
phy_grant->sf_type = SRSLTE_SF_MBSFN;
srslte_dl_fill_ra_mcs(&phy_grant->mcs[0], enb_dl.cell.nof_prb);
phy_grant->Qm[0] = srslte_mod_bits_x_symbol(phy_grant->mcs[0].mod);
for(int i = 0; i < 2; i++){
for(uint32_t j = 0; j < phy_grant->nof_prb; j++){
phy_grant->prb_idx[i][j] = true;
}
}
srslte_enb_dl_put_pmch(&enb_dl, phy_grant, &temp_mbsfn_softbuffer, sf_tx, &grant->data[0][0]);
return SRSLTE_SUCCESS;
}
int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants) {
/* Scales the Resources Elements affected by the power allocation (p_b) */
@ -1002,18 +1056,6 @@ void phch_worker::ue::metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t
}
void phch_worker::start_plot() {
#ifdef ENABLE_GUI

View File

@ -95,7 +95,9 @@ bool phy::init(phy_args_t *args,
mac_interface_phy *mac,
srslte::log_filter* log_h)
{
std::vector<srslte::log_filter*> log_vec;
this->log_h = log_h;
for (int i=0;i<args->nof_phy_threads;i++) {
log_vec.push_back(log_h);
}
@ -114,7 +116,7 @@ bool phy::init(phy_args_t *args,
radio_handler = radio_handler_;
nof_workers = args->nof_phy_threads;
this->log_h = (srslte::log*)log_vec[0];
workers_common.params = *args;
workers_common.init(&cfg->cell, radio_handler, mac);
@ -227,6 +229,28 @@ void phy::set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICAT
}
}
void phy::configure_mbsfn(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT mcch)
{
if(sib2->mbsfn_subfr_cnfg_list_size > 1) {
Warning("SIB2 has %d MBSFN subframe configs - only 1 supported\n", sib2->mbsfn_subfr_cnfg_list_size);
}
if(sib2->mbsfn_subfr_cnfg_list_size > 0) {
memcpy(&phy_rrc_config.mbsfn.mbsfn_subfr_cnfg, &sib2->mbsfn_subfr_cnfg_list[0], sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT));
}
memcpy(&phy_rrc_config.mbsfn.mbsfn_notification_cnfg, &sib13->mbsfn_notification_config, sizeof(LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT));
if(sib13->mbsfn_area_info_list_r9_size > 1) {
Warning("SIB13 has %d MBSFN area info elements - only 1 supported\n", sib13->mbsfn_area_info_list_r9_size);
}
if(sib13->mbsfn_area_info_list_r9_size > 0) {
memcpy(&phy_rrc_config.mbsfn.mbsfn_area_info, &sib13->mbsfn_area_info_list_r9[0], sizeof(LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT));
}
memcpy(&phy_rrc_config.mbsfn.mcch, &mcch, sizeof(LIBLTE_RRC_MCCH_MSG_STRUCT));
workers_common.configure_mbsfn(&phy_rrc_config.mbsfn);
}
// Start GUI
void phy::start_plot() {
((phch_worker) workers[0]).start_plot();

View File

@ -92,241 +92,355 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
return false;
}
//Setup M1-u
init_m1u(gtpu_log_);
mch_lcid_counter = 1;
// Setup a thread to receive packets from the src socket
start(THREAD_PRIO);
return true;
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;
}
/* 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 (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();
}
if (run_enable) {
run_enable = false;
if(mch_run_enable)
mch_run_enable = false;
if (snk_fd) {
close(snk_fd);
// Wait thread to exit gracefully otherwise might leave a mutex locked
int cnt=0;
while(running && cnt<100) {
usleep(10000);
cnt++;
}
if (src_fd) {
close(src_fd);
if (running) {
thread_cancel();
if(mch_running)
pthread_cancel(mch_thread);
}
wait_thread_finish();
pthread_join(mch_thread, NULL);
}
if (snk_fd) {
close(snk_fd);
}
if (src_fd) {
close(src_fd);
}
}
// gtpu_interface_pdcp
void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu)
{
gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU, RNTI: 0x%x, LCID: %d, n_bytes=%d", rnti, lcid, pdu->N_bytes);
gtpu_header_t header;
header.flags = 0x30;
header.message_type = 0xFF;
header.length = pdu->N_bytes;
header.teid = rnti_bearers[rnti].teids_out[lcid];
gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU, RNTI: 0x%x, LCID: %d, n_bytes=%d", rnti, lcid, pdu->N_bytes);
gtpu_header_t header;
header.flags = 0x30;
header.message_type = 0xFF;
header.length = pdu->N_bytes;
header.teid = rnti_bearers[rnti].teids_out[lcid];
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]);
servaddr.sin_port = htons(GTPU_PORT);
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]);
servaddr.sin_port = htons(GTPU_PORT);
gtpu_write_header(&header, pdu);
if (sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))<0) {
perror("sendto");
}
gtpu_write_header(&header, pdu);
if (sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))<0) {
perror("sendto");
}
pool->deallocate(pdu);
pool->deallocate(pdu);
}
// gtpu_interface_rrc
void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in)
{
// Allocate a TEID for the incoming tunnel
rntilcid_to_teidin(rnti, lcid, teid_in);
gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, addr, teid_out, *teid_in);
// Allocate a TEID for the incoming tunnel
rntilcid_to_teidin(rnti, lcid, teid_in);
//gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, addr, teid_out, *teid_in);
// Initialize maps if it's a new RNTI
if(rnti_bearers.count(rnti) == 0) {
for(int i=0;i<SRSENB_N_RADIO_BEARERS;i++) {
rnti_bearers[rnti].teids_in[i] = 0;
rnti_bearers[rnti].teids_out[i] = 0;
rnti_bearers[rnti].spgw_addrs[i] = 0;
}
// Initialize maps if it's a new RNTI
if(rnti_bearers.count(rnti) == 0) {
for(int i=0;i<SRSENB_N_RADIO_BEARERS;i++) {
rnti_bearers[rnti].teids_in[i] = 0;
rnti_bearers[rnti].teids_out[i] = 0;
rnti_bearers[rnti].spgw_addrs[i] = 0;
}
}
rnti_bearers[rnti].teids_in[lcid] = *teid_in;
rnti_bearers[rnti].teids_out[lcid] = teid_out;
rnti_bearers[rnti].spgw_addrs[lcid] = addr;
rnti_bearers[rnti].teids_in[lcid] = *teid_in;
rnti_bearers[rnti].teids_out[lcid] = teid_out;
rnti_bearers[rnti].spgw_addrs[lcid] = addr;
}
void gtpu::rem_bearer(uint16_t rnti, uint32_t lcid)
{
gtpu_log->info("Removing bearer for rnti: 0x%x, lcid: %d\n", rnti, lcid);
gtpu_log->info("Removing bearer for rnti: 0x%x, lcid: %d\n", rnti, lcid);
rnti_bearers[rnti].teids_in[lcid] = 0;
rnti_bearers[rnti].teids_out[lcid] = 0;
rnti_bearers[rnti].teids_in[lcid] = 0;
rnti_bearers[rnti].teids_out[lcid] = 0;
// Remove RNTI if all bearers are removed
bool rem = true;
for(int i=0;i<SRSENB_N_RADIO_BEARERS; i++) {
if(rnti_bearers[rnti].teids_in[i] != 0) {
rem = false;
}
}
if(rem) {
rnti_bearers.erase(rnti);
// Remove RNTI if all bearers are removed
bool rem = true;
for(int i=0;i<SRSENB_N_RADIO_BEARERS; i++) {
if(rnti_bearers[rnti].teids_in[i] != 0) {
rem = false;
}
}
if(rem) {
rnti_bearers.erase(rnti);
}
}
void gtpu::rem_user(uint16_t rnti)
{
pthread_mutex_lock(&mutex);
rnti_bearers.erase(rnti);
pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&mutex);
rnti_bearers.erase(rnti);
pthread_mutex_unlock(&mutex);
}
void gtpu::run_thread()
{
byte_buffer_t *pdu = pool_allocate;
if (!pdu) {
gtpu_log->error("Fatal Error: Couldn't allocate buffer in gtpu::run_thread().\n");
return;
byte_buffer_t *pdu = pool_allocate;
if (!pdu) {
gtpu_log->error("Fatal Error: Couldn't allocate buffer in gtpu::run_thread().\n");
return;
}
run_enable = true;
running=true;
while(run_enable) {
pdu->reset();
gtpu_log->debug("Waiting for read...\n");
int n = 0;
do{
n = recv(src_fd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0);
} while (n == -1 && errno == EAGAIN);
if (n < 0) {
gtpu_log->error("Failed to read from socket\n");
}
run_enable = true;
running=true;
while(run_enable) {
pdu->N_bytes = (uint32_t) n;
pdu->reset();
gtpu_log->debug("Waiting for read...\n");
int n = 0;
do{
n = recv(src_fd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0);
} while (n == -1 && errno == EAGAIN);
if (n < 0) {
gtpu_log->error("Failed to read from socket\n");
}
gtpu_header_t header;
gtpu_read_header(pdu, &header);
pdu->N_bytes = (uint32_t) n;
gtpu_header_t header;
gtpu_read_header(pdu, &header);
uint16_t rnti = 0;
uint16_t lcid = 0;
teidin_to_rntilcid(header.teid, &rnti, &lcid);
uint16_t rnti = 0;
uint16_t lcid = 0;
teidin_to_rntilcid(header.teid, &rnti, &lcid);
pthread_mutex_lock(&mutex);
bool user_exists = (rnti_bearers.count(rnti) > 0);
pthread_mutex_unlock(&mutex);
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 < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) {
gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid);
continue;
}
gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "RX GTPU PDU rnti=0x%x, lcid=%d, n_bytes=%d", rnti, lcid, pdu->N_bytes);
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);
if(!user_exists) {
gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti);
continue;
}
running=false;
if(lcid < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) {
gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid);
continue;
}
gtpu_log->info_hex(pdu->msg, pdu->N_bytes, "RX GTPU PDU rnti=0x%x, lcid=%d, n_bytes=%d", rnti, lcid, pdu->N_bytes);
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);
}
running=false;
}
/****************************************************************************
* Header pack/unpack helper functions
* Ref: 3GPP TS 29.281 v10.1.0 Section 5
***************************************************************************/
* Header pack/unpack helper functions
* Ref: 3GPP TS 29.281 v10.1.0 Section 5
***************************************************************************/
bool gtpu::gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu)
{
if(header->flags != 0x30) {
gtpu_log->error("gtpu_write_header - Unhandled header flags: 0x%x\n", header->flags);
return false;
}
if(header->message_type != 0xFF) {
gtpu_log->error("gtpu_write_header - Unhandled message type: 0x%x\n", header->message_type);
return false;
}
if(pdu->get_headroom() < GTPU_HEADER_LEN) {
gtpu_log->error("gtpu_write_header - No room in PDU for header\n");
return false;
}
if(header->flags != 0x30) {
gtpu_log->error("gtpu_write_header - Unhandled header flags: 0x%x\n", header->flags);
return false;
}
if(header->message_type != 0xFF) {
gtpu_log->error("gtpu_write_header - Unhandled message type: 0x%x\n", header->message_type);
return false;
}
if(pdu->get_headroom() < GTPU_HEADER_LEN) {
gtpu_log->error("gtpu_write_header - No room in PDU for header\n");
return false;
}
pdu->msg -= GTPU_HEADER_LEN;
pdu->N_bytes += GTPU_HEADER_LEN;
pdu->msg -= GTPU_HEADER_LEN;
pdu->N_bytes += GTPU_HEADER_LEN;
uint8_t *ptr = pdu->msg;
uint8_t *ptr = pdu->msg;
*ptr = header->flags;
ptr++;
*ptr = header->message_type;
ptr++;
uint16_to_uint8(header->length, ptr);
ptr += 2;
uint32_to_uint8(header->teid, ptr);
*ptr = header->flags;
ptr++;
*ptr = header->message_type;
ptr++;
uint16_to_uint8(header->length, ptr);
ptr += 2;
uint32_to_uint8(header->teid, ptr);
return true;
return true;
}
bool gtpu::gtpu_read_header(srslte::byte_buffer_t *pdu, gtpu_header_t *header)
{
uint8_t *ptr = pdu->msg;
uint8_t *ptr = pdu->msg;
pdu->msg += GTPU_HEADER_LEN;
pdu->N_bytes -= GTPU_HEADER_LEN;
pdu->msg += GTPU_HEADER_LEN;
pdu->N_bytes -= GTPU_HEADER_LEN;
header->flags = *ptr;
ptr++;
header->message_type = *ptr;
ptr++;
uint8_to_uint16(ptr, &header->length);
ptr += 2;
uint8_to_uint32(ptr, &header->teid);
header->flags = *ptr;
ptr++;
header->message_type = *ptr;
ptr++;
uint8_to_uint16(ptr, &header->length);
ptr += 2;
uint8_to_uint32(ptr, &header->teid);
if(header->flags != 0x30) {
gtpu_log->error("gtpu_read_header - Unhandled header flags: 0x%x\n", header->flags);
return false;
}
if(header->message_type != 0xFF) {
gtpu_log->error("gtpu_read_header - Unhandled message type: 0x%x\n", header->message_type);
return false;
}
if(header->flags != 0x30) {
gtpu_log->error("gtpu_read_header - Unhandled header flags: 0x%x\n", header->flags);
return false;
}
if(header->message_type != 0xFF) {
gtpu_log->error("gtpu_read_header - Unhandled message type: 0x%x\n", header->message_type);
return false;
}
return true;
return true;
}
/****************************************************************************
* TEID to RNIT/LCID helper functions
***************************************************************************/
* TEID to RNIT/LCID helper functions
***************************************************************************/
void gtpu::teidin_to_rntilcid(uint32_t teidin, uint16_t *rnti, uint16_t *lcid)
{
*lcid = teidin & 0xFFFF;
*rnti = (teidin >> 16) & 0xFFFF;
*lcid = teidin & 0xFFFF;
*rnti = (teidin >> 16) & 0xFFFF;
}
void gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t *teidin)
{
*teidin = (rnti << 16) | lcid;
*teidin = (rnti << 16) | lcid;
}
} // namespace srsenb

View File

@ -76,7 +76,11 @@ void pdcp::rem_user(uint16_t rnti)
void pdcp::add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_pdcp_config_t cfg)
{
if (users.count(rnti)) {
users[rnti].pdcp->add_bearer(lcid, cfg);
if(rnti != SRSLTE_MRNTI){
users[rnti].pdcp->add_bearer(lcid, cfg);
} else {
users[rnti].pdcp->add_bearer_mrb(lcid, cfg);
}
}
}
@ -110,7 +114,11 @@ void pdcp::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
{
if (users.count(rnti)) {
users[rnti].pdcp->write_sdu(lcid, sdu);
if(rnti != SRSLTE_MRNTI){
users[rnti].pdcp->write_sdu(lcid, sdu);
}else {
users[rnti].pdcp->write_sdu_mch(lcid, sdu);
}
} else {
pool->deallocate(sdu);
}
@ -123,6 +131,7 @@ void pdcp::user_interface_gtpu::write_pdu(uint32_t lcid, srslte::byte_buffer_t *
void pdcp::user_interface_rlc::write_sdu(uint32_t lcid, srslte::byte_buffer_t* sdu)
{
rlc->write_sdu(rnti, lcid, sdu);
}

View File

@ -105,6 +105,13 @@ void rlc::add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t c
}
}
void rlc::add_bearer_mrb(uint16_t rnti, uint32_t lcid)
{
if (users.count(rnti)) {
users[rnti].rlc->add_bearer_mrb_enb(lcid);
}
}
void rlc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size)
{
rrc->read_pdu_pcch(payload, buffer_size);
@ -112,16 +119,27 @@ void rlc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size)
int rlc::read_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes)
{
int ret = users[rnti].rlc->read_pdu(lcid, payload, nof_bytes);
// In the eNodeB, there is no polling for buffer state from the scheduler, thus
// communicate buffer state every time a PDU is read
uint32_t tx_queue = users[rnti].rlc->get_total_buffer_state(lcid);
uint32_t retx_queue = 0;
log_h->debug("Buffer state PDCP: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue);
mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue);
return ret;
int ret;
uint32_t tx_queue;
if(users.count(rnti)){
if(rnti != SRSLTE_MRNTI){
ret = users[rnti].rlc->read_pdu(lcid, payload, nof_bytes);
tx_queue = users[rnti].rlc->get_total_buffer_state(lcid);
}else{
ret = users[rnti].rlc->read_pdu_mch(lcid, payload, nof_bytes);
tx_queue = users[rnti].rlc->get_total_mch_buffer_state(lcid);
}
// In the eNodeB, there is no polling for buffer state from the scheduler, thus
// communicate buffer state every time a PDU is read
uint32_t retx_queue = 0;
log_h->debug("Buffer state PDCP: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue);
mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue);
return ret;
}else{
return SRSLTE_ERROR;
}
}
void rlc::write_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes)
@ -146,12 +164,19 @@ void rlc::read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t *payload)
void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu)
{
uint32_t tx_queue;
if (users.count(rnti)) {
users[rnti].rlc->write_sdu(lcid, sdu);
if(rnti != SRSLTE_MRNTI){
users[rnti].rlc->write_sdu(lcid, sdu);
tx_queue = users[rnti].rlc->get_total_buffer_state(lcid);
}else {
users[rnti].rlc->write_sdu_mch(lcid, sdu);
tx_queue = users[rnti].rlc->get_total_mch_buffer_state(lcid);
}
// In the eNodeB, there is no polling for buffer state from the scheduler, thus
// communicate buffer state every time a new SDU is written
uint32_t tx_queue = users[rnti].rlc->get_total_buffer_state(lcid);
uint32_t retx_queue = 0;
mac->rlc_buffer_state(rnti, lcid, tx_queue, retx_queue);
log_h->info("Buffer state: rnti=0x%x, lcid=%d, tx_queue=%d\n", rnti, lcid, tx_queue);

View File

@ -30,6 +30,7 @@
#include "srslte/srslte.h"
#include "srslte/asn1/liblte_mme.h"
using srslte::byte_buffer_t;
using srslte::bit_buffer_t;
@ -57,6 +58,11 @@ void rrc::init(rrc_cfg_t *cfg_,
pool = srslte::byte_buffer_pool::get_instance();
memcpy(&cfg, cfg_, sizeof(rrc_cfg_t));
if(cfg.sibs[12].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13 && cfg_->enable_mbsfn) {
configure_mbsfn_sibs(&cfg.sibs[1].sib.sib2,&cfg.sibs[12].sib.sib13);
}
nof_si_messages = generate_sibs();
config_mac();
@ -69,6 +75,53 @@ void rrc::init(rrc_cfg_t *cfg_,
start(RRC_THREAD_PRIO);
}
void rrc::configure_mbsfn_sibs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13)
{
// Temp assignment of MCCH, this will eventually come from a cfg file
mcch.pmch_infolist_r9_size = 1;
mcch.commonsf_allocpatternlist_r9_size = 1;
mcch.commonsf_allocperiod_r9 = LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF64;
mcch.commonsf_allocpatternlist_r9[0].radio_fr_alloc_offset = 0;
mcch.commonsf_allocpatternlist_r9[0].radio_fr_alloc_period = LIBLTE_RRC_RADIO_FRAME_ALLOCATION_PERIOD_N1;
mcch.commonsf_allocpatternlist_r9[0].subfr_alloc = 32+31;
mcch.commonsf_allocpatternlist_r9[0].subfr_alloc_num_frames = LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size = 1;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].logicalchannelid_r9 = 1;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9 = 0;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].sessionid_r9_present = true;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_explicit = true;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mcc = 0;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_id_r9.mnc = 3;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.plmn_index_r9 = 0;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[0].tmgi_r9.serviceid_r9 = 0;
if(mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size > 1) {
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].logicalchannelid_r9 = 2;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].sessionid_r9 = 1;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].sessionid_r9_present = true;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].tmgi_r9.plmn_id_explicit = true;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].tmgi_r9.plmn_id_r9.mcc = 0;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].tmgi_r9.plmn_id_r9.mnc = 3;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].tmgi_r9.plmn_index_r9 = 0;
mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[1].tmgi_r9.serviceid_r9 = 1;
}
mcch.pmch_infolist_r9[0].pmch_config_r9.datamcs_r9 = 10;
mcch.pmch_infolist_r9[0].pmch_config_r9.mch_schedulingperiod_r9 = LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF64;
mcch.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9 = 64*6;
phy->configure_mbsfn(sib2,sib13,mcch);
mac->write_mcch(sib2,sib13,&mcch);
}
rrc::activity_monitor::activity_monitor(rrc* parent_)
{
running = true;
@ -108,11 +161,14 @@ void rrc::get_metrics(rrc_metrics_t &m)
m.n_ues = 0;
for(std::map<uint16_t, ue>::iterator iter=users.begin(); m.n_ues < ENB_METRICS_MAX_USERS &&iter!=users.end(); ++iter) {
ue *u = (ue*) &iter->second;
m.ues[m.n_ues++].state = u->get_state();
if(iter->first != SRSLTE_MRNTI){
m.ues[m.n_ues++].state = u->get_state();
}
}
pthread_mutex_unlock(&user_mutex);
}
uint32_t rrc::generate_sibs()
{
// nof_messages includes SIB2 by default, plus all configured SIBs
@ -218,6 +274,7 @@ void rrc::add_user(uint16_t rnti)
{
pthread_mutex_lock(&user_mutex);
if (users.count(rnti) == 0) {
users[rnti].parent = this;
users[rnti].rnti = rnti;
rlc->add_user(rnti);
@ -226,6 +283,22 @@ void rrc::add_user(uint16_t rnti)
} else {
rrc_log->error("Adding user rnti=0x%x (already exists)\n", rnti);
}
if(rnti == SRSLTE_MRNTI){
srslte::srslte_pdcp_config_t cfg;
cfg.is_control = false;
cfg.is_data = true;
cfg.direction = SECURITY_DIRECTION_DOWNLINK;
uint32_t teid_in = 1;
for(uint32_t i = 0; i <mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size; i++) {
uint32_t lcid = mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9[i].logicalchannelid_r9;
rlc->add_bearer_mrb(SRSLTE_MRNTI,lcid);
pdcp->add_bearer(SRSLTE_MRNTI,lcid,cfg);
gtpu->add_bearer(SRSLTE_MRNTI,lcid, 1, 1, &teid_in);
}
}
pthread_mutex_unlock(&user_mutex);
}
@ -666,25 +739,28 @@ void rrc::activity_monitor::run_thread()
pthread_mutex_lock(&parent->user_mutex);
uint16_t rem_rnti = 0;
for(std::map<uint16_t, ue>::iterator iter=parent->users.begin(); rem_rnti == 0 && iter!=parent->users.end(); ++iter) {
ue *u = (ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
if(iter->first != SRSLTE_MRNTI){
ue *u = (ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
if (parent->cnotifier && u->is_connected() && !u->connect_notified) {
parent->cnotifier->user_connected(rnti);
u->connect_notified = true;
}
if (u->is_timeout()) {
parent->rrc_log->info("User rnti=0x%x timed out. Exists in s1ap=%s\n", rnti, parent->s1ap->user_exists(rnti)?"yes":"no");
rem_rnti = rnti;
}
}
if (parent->cnotifier && u->is_connected() && !u->connect_notified) {
parent->cnotifier->user_connected(rnti);
u->connect_notified = true;
}
if (u->is_timeout()) {
parent->rrc_log->info("User rnti=0x%x timed out. Exists in s1ap=%s\n", rnti, parent->s1ap->user_exists(rnti)?"yes":"no");
rem_rnti = rnti;
}
}
}
pthread_mutex_unlock(&parent->user_mutex);
if (rem_rnti) {
if (parent->s1ap->user_exists(rem_rnti)) {
parent->s1ap->user_inactivity(rem_rnti);
} else {
parent->rem_user(rem_rnti);
if(rem_rnti != SRSLTE_MRNTI)
parent->rem_user(rem_rnti);
}
}
}
@ -1240,7 +1316,7 @@ void rrc::ue::send_connection_setup(bool is_setup)
sched_cfg.pucch_cfg.N_cs = parent->sib2.rr_config_common_sib.pucch_cnfg.n_cs_an;
sched_cfg.pucch_cfg.n_rb_2 = parent->sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi;
sched_cfg.pucch_cfg.n1_pucch_an = parent->sib2.rr_config_common_sib.pucch_cnfg.n1_pucch_an;
// Configure MAC
parent->mac->ue_cfg(rnti, &sched_cfg);

View File

@ -174,6 +174,7 @@ public:
void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu) {}
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu) {}
void write_pdu_pcch(srslte::byte_buffer_t *sdu) {}
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu){}
void max_retx_attempted(){}
void add_user(uint16_t rnti) {}
void release_user(uint16_t rnti) {}

View File

@ -0,0 +1,101 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* 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/.
*
*/
/******************************************************************************
* File: mbms-gw.h
* Description: Top-level MBMS-GW class. Creates and links all
* interfaces and helpers.
*****************************************************************************/
#ifndef MBMS_GW_H
#define MBMS_GW_H
#include <cstddef>
#include "srslte/common/log.h"
#include "srslte/common/logger_file.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/threads.h"
#include "srslte/asn1/gtpc.h"
namespace srsepc{
const uint16_t GTPU_RX_PORT = 2152;
typedef struct {
std::string name;
std::string sgi_mb_if_addr;
std::string m1u_multi_addr;
} mbms_gw_args_t;
struct pseudo_hdr
{
uint32_t src_addr;
uint32_t dst_addr;
uint8_t placeholder;
uint8_t protocol;
uint16_t udp_len;
};
class mbms_gw:
public thread
{
public:
static mbms_gw* get_instance(void);
static void cleanup(void);
int init(mbms_gw_args_t* args, srslte::log_filter *mbms_gw_log);
void stop();
void run_thread();
private:
/* Methods */
mbms_gw();
virtual ~mbms_gw();
static mbms_gw *m_instance;
srslte::error_t init_sgi_mb_if(mbms_gw_args_t *args);
srslte::error_t init_m1_u(mbms_gw_args_t *args);
void handle_sgi_md_pdu(srslte::byte_buffer_t *msg);
uint16_t in_cksum(uint16_t *iphdr, int count);
/* Members */
bool m_running;
srslte::byte_buffer_pool *m_pool;
srslte::log_filter *m_mbms_gw_log;
bool m_sgi_mb_up;
int m_sgi_mb_if;
bool m_m1u_up;
int m_m1u;
struct sockaddr_in m_m1u_multi_addr;
};
} // namespace srsepc
#endif // SGW_H

39
srsepc/mbms.conf.example Normal file
View File

@ -0,0 +1,39 @@
#####################################################################
# srsEPC configuration file
#####################################################################
#####################################################################
# MBMS-GW configuration
#
# name: MBMS-GW name
# sgi_mb_if_addr: SGi-mb interface IP address
# m1u_addr: Multicast group for eNBs (FIXME this should be setup with M2/M3)
#
#####################################################################
[mbms_gw]
name = srsmbmsgw01
sgi_mb_if_addr = 172.16.1.1
m1u_multi_addr = 239.255.0.1
####################################################################
# Log configuration
#
# Log levels can be set for individual layers. "all_level" sets log
# level for all layers unless otherwise configured.
# Format: e.g. s1ap_level = info
#
# In the same way, packet hex dumps can be limited for each level.
# "all_hex_limit" sets the hex limit for all layers unless otherwise
# configured.
# Format: e.g. s1ap_hex_limit = 32
#
# Logging layers: mbms_gw, all
# Logging levels: debug, info, warning, error, none
#
# filename: File path to use for log output. Can be set to stdout
# to print logs to standard output
#####################################################################
[log]
all_level = debug
all_hex_limit = 32
filename = /tmp/mbms.log

View File

@ -1,7 +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/.
#
add_subdirectory(mme)
add_subdirectory(hss)
add_subdirectory(spgw)
add_subdirectory(mbms-gw)
# Link libstdc++ and libgcc
if(BUILD_STATIC)
@ -26,11 +46,22 @@ target_link_libraries(srsepc srsepc_mme
${LIBCONFIGPP_LIBRARIES}
${SCTP_LIBRARIES})
add_executable(srsmbms mbms-gw/main.cc )
target_link_libraries(srsmbms srsepc_mbms_gw
srslte_upper
srslte_common
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES}
${SEC_LIBRARIES}
${LIBCONFIGPP_LIBRARIES}
${SCTP_LIBRARIES})
if (RPATH)
set_target_properties(srsepc PROPERTIES INSTALL_RPATH ".")
set_target_properties(srsmbms PROPERTIES INSTALL_RPATH ".")
endif (RPATH)
install(TARGETS srsepc DESTINATION ${RUNTIME_DIR})
install(TARGETS srsmbms DESTINATION ${RUNTIME_DIR})
########################################################################
# Option to run command after build (useful for remote builds)

View File

@ -0,0 +1,23 @@
#
# 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/.
#
file(GLOB SOURCES "*.cc")
add_library(srsepc_mbms_gw STATIC ${SOURCES})
install(TARGETS srsepc_mbms_gw DESTINATION ${LIBRARY_DIR})

216
srsepc/src/mbms-gw/main.cc Normal file
View File

@ -0,0 +1,216 @@
/**
*
* \section COPYRIGHT
*
* \section LICENSE
*
* 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/.
*
*/
#include <iostream>
#include <fstream>
#include <errno.h>
#include <signal.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include "srsepc/hdr/mbms-gw/mbms-gw.h"
using namespace std;
using namespace srsepc;
namespace bpo = boost::program_options;
bool running = true;
void
sig_int_handler(int signo){
running = false;
}
typedef struct {
std::string mbms_gw_level;
int mbms_gw_hex_limit;
std::string all_level;
int all_hex_limit;
std::string filename;
}log_args_t;
typedef struct {
mbms_gw_args_t mbms_gw_args;
log_args_t log_args;
}all_args_t;
srslte::LOG_LEVEL_ENUM
level(std::string l)
{
boost::to_upper(l);
if("NONE" == l){
return srslte::LOG_LEVEL_NONE;
}else if("ERROR" == l){
return srslte::LOG_LEVEL_ERROR;
}else if("WARNING" == l){
return srslte::LOG_LEVEL_WARNING;
}else if("INFO" == l){
return srslte::LOG_LEVEL_INFO;
}else if("DEBUG" == l){
return srslte::LOG_LEVEL_DEBUG;
}else{
return srslte::LOG_LEVEL_NONE;
}
}
/**********************************************************************
* Program arguments processing
***********************************************************************/
string config_file;
void
parse_args(all_args_t *args, int argc, char* argv[]) {
string mbms_gw_name;
string mbms_gw_sgi_mb_if_addr;
string mbms_gw_m1u_multi_addr;
string log_filename;
// Command line only options
bpo::options_description general("General options");
general.add_options()
("help,h", "Produce help message")
("version,v", "Print version information and exit")
;
// Command line or config file options
bpo::options_description common("Configuration options");
common.add_options()
("mbms_gw.name", bpo::value<string>(&mbms_gw_name)->default_value("srsmbmsgw01"), "MBMS-GW Name")
("mbms_gw.sgi_mb_if_addr", bpo::value<string>(&mbms_gw_sgi_mb_if_addr)->default_value("172.16.1.1"), "SGi-mb TUN interface Address")
("mbms_gw.m1u_multi_addr", bpo::value<string>(&mbms_gw_m1u_multi_addr)->default_value("239.255.0.1"), "M1-u GTPu destination multicast address")
("log.all_level", bpo::value<string>(&args->log_args.all_level)->default_value("info"), "ALL log level")
("log.all_hex_limit", bpo::value<int>(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit")
("log.filename", bpo::value<string>(&args->log_args.filename)->default_value("/tmp/mbms.log"),"Log filename")
;
// Positional options - config file location
bpo::options_description position("Positional options");
position.add_options()
("config_file", bpo::value< string >(&config_file), "MBMS-GW configuration file")
;
bpo::positional_options_description p;
p.add("config_file", -1);
// these options are allowed on the command line
bpo::options_description cmdline_options;
cmdline_options.add(common).add(position).add(general);
// parse the command line and store result in vm
bpo::variables_map vm;
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm);
bpo::notify(vm);
// help option was given - print usage and exit
if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl;
exit(0);
}
//Parsing Config File
if (!vm.count("config_file")) {
cout << "Error: Configuration file not provided" << endl;
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
exit(0);
} else {
cout << "Reading configuration file " << config_file << "..." << endl;
ifstream conf(config_file.c_str(), ios::in);
if(conf.fail()) {
cout << "Failed to read configuration file " << config_file << " - exiting" << endl;
exit(1);
}
bpo::store(bpo::parse_config_file(conf, common), vm);
bpo::notify(vm);
}
args->mbms_gw_args.name = mbms_gw_name;
args->mbms_gw_args.sgi_mb_if_addr = mbms_gw_sgi_mb_if_addr;
args->mbms_gw_args.m1u_multi_addr = mbms_gw_m1u_multi_addr;
// Apply all_level to any unset layers
if (vm.count("log.all_level")) {
if(!vm.count("log.mbms_gw_level")) {
args->log_args.mbms_gw_level = args->log_args.all_level;
}
}
// Apply all_hex_limit to any unset layers
if (vm.count("log.all_hex_limit")) {
if(!vm.count("log.mbms_gw_hex_limit")) {
args->log_args.mbms_gw_hex_limit = args->log_args.all_hex_limit;
}
}
return;
}
int
main (int argc,char * argv[] )
{
cout << endl <<"--- Software Radio Systems MBMS ---" << endl << endl;
signal(SIGINT, sig_int_handler);
signal(SIGTERM, sig_int_handler);
signal(SIGKILL, sig_int_handler);
all_args_t args;
parse_args(&args, argc, argv);
srslte::logger_stdout logger_stdout;
srslte::logger_file logger_file;
srslte::logger *logger;
/*Init logger*/
if (!args.log_args.filename.compare("stdout")) {
logger = &logger_stdout;
} else {
logger_file.init(args.log_args.filename);
logger_file.log("\n--- Software Radio Systems MBMS log ---\n\n");
logger = &logger_file;
}
srslte::log_filter mbms_gw_log;
mbms_gw_log.init("MBMS",logger);
mbms_gw_log.set_level(level(args.log_args.mbms_gw_level));
mbms_gw_log.set_hex_limit(args.log_args.mbms_gw_hex_limit);
mbms_gw *mbms_gw = mbms_gw::get_instance();
if(mbms_gw->init(&args.mbms_gw_args,&mbms_gw_log)) {
cout << "Error initializing MBMS-GW" << endl;
exit(1);
}
mbms_gw->start();
while(running) {
sleep(1);
}
mbms_gw->stop();
mbms_gw->cleanup();
cout << std::endl <<"--- exiting ---" << endl;
return 0;
}

View File

@ -0,0 +1,385 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* 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/.
*
*/
#include <iostream>
#include <algorithm>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <netinet/udp.h>
#include <linux/ip.h>
#include "srsepc/hdr/mbms-gw/mbms-gw.h"
#include "srslte/upper/gtpu.h"
namespace srsepc{
mbms_gw* mbms_gw::m_instance = NULL;
pthread_mutex_t mbms_gw_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
const uint16_t MBMS_GW_BUFFER_SIZE = 2500;
mbms_gw::mbms_gw():
m_running(false),
m_sgi_mb_up(false)
{
return;
}
mbms_gw::~mbms_gw()
{
return;
}
mbms_gw*
mbms_gw::get_instance(void)
{
pthread_mutex_lock(&mbms_gw_instance_mutex);
if(NULL == m_instance) {
m_instance = new mbms_gw();
}
pthread_mutex_unlock(&mbms_gw_instance_mutex);
return(m_instance);
}
void
mbms_gw::cleanup(void)
{
pthread_mutex_lock(&mbms_gw_instance_mutex);
if(NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
pthread_mutex_unlock(&mbms_gw_instance_mutex);
}
int
mbms_gw::init(mbms_gw_args_t* args, srslte::log_filter *mbms_gw_log)
{
srslte::error_t err;
m_pool = srslte::byte_buffer_pool::get_instance();
//Init log
m_mbms_gw_log = mbms_gw_log;
err = init_sgi_mb_if(args);
if (err != srslte::ERROR_NONE)
{
m_mbms_gw_log->console("Error initializing SGi-MB.\n");
m_mbms_gw_log->error("Error initializing SGi-MB.\n");
return -1;
}
err = init_m1_u(args);
if (err != srslte::ERROR_NONE)
{
m_mbms_gw_log->console("Error initializing SGi-MB.\n");
m_mbms_gw_log->error("Error initializing SGi-MB.\n");
return -1;
}
m_mbms_gw_log->info("MBMS GW Initiated\n");
m_mbms_gw_log->console("MBMS GW Initiated\n");
return 0;
}
void
mbms_gw::stop()
{
if(m_running)
{
if(m_sgi_mb_up)
{
close(m_sgi_mb_if);
m_mbms_gw_log->info("Closed SGi-MB interface\n");
}
m_running = false;
thread_cancel();
wait_thread_finish();
}
return;
}
srslte::error_t
mbms_gw::init_sgi_mb_if(mbms_gw_args_t *args)
{
char dev[IFNAMSIZ] = "sgi_mb";
struct ifreq ifr;
if(m_sgi_mb_up)
{
return(srslte::ERROR_ALREADY_STARTED);
}
// Construct the TUN device
m_sgi_mb_if = open("/dev/net/tun", O_RDWR);
m_mbms_gw_log->info("TUN file descriptor = %d\n", m_sgi_mb_if);
if(m_sgi_mb_if < 0)
{
m_mbms_gw_log->error("Failed to open TUN device: %s\n", strerror(errno));
return(srslte::ERROR_CANT_START);
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ-1);
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1]='\0';
if(ioctl(m_sgi_mb_if, TUNSETIFF, &ifr) < 0)
{
m_mbms_gw_log->error("Failed to set TUN device name: %s\n", strerror(errno));
close(m_sgi_mb_if);
return(srslte::ERROR_CANT_START);
}
// Bring up the interface
int sgi_mb_sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sgi_mb_sock<0)
{
m_mbms_gw_log->error("Failed to bring up socket: %s\n", strerror(errno));
close(m_sgi_mb_if);
return(srslte::ERROR_CANT_START);
}
if(ioctl(sgi_mb_sock, SIOCGIFFLAGS, &ifr) < 0)
{
m_mbms_gw_log->error("Failed to bring up interface: %s\n", strerror(errno));
close(m_sgi_mb_if);
close(sgi_mb_sock);
return(srslte::ERROR_CANT_START);
}
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if(ioctl(sgi_mb_sock, SIOCSIFFLAGS, &ifr) < 0)
{
m_mbms_gw_log->error("Failed to set socket flags: %s\n", strerror(errno));
close(sgi_mb_sock);
close(m_sgi_mb_if);
return(srslte::ERROR_CANT_START);
}
//Set IP of the interface
struct sockaddr_in *addr = (struct sockaddr_in*)&ifr.ifr_addr;
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr(args->sgi_mb_if_addr.c_str());
addr->sin_port = 0;
if (ioctl(sgi_mb_sock, SIOCSIFADDR, &ifr) < 0) {
m_mbms_gw_log->error("Failed to set TUN interface IP. Address: %s, Error: %s\n", args->sgi_mb_if_addr.c_str(), strerror(errno));
close(m_sgi_mb_if);
close(sgi_mb_sock);
return srslte::ERROR_CANT_START;
}
ifr.ifr_netmask.sa_family = AF_INET;
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0");
if (ioctl(sgi_mb_sock, SIOCSIFNETMASK, &ifr) < 0) {
m_mbms_gw_log->error("Failed to set TUN interface Netmask. Error: %s\n", strerror(errno));
close(m_sgi_mb_if);
close(sgi_mb_sock);
return srslte::ERROR_CANT_START;
}
m_sgi_mb_up = true;
close(sgi_mb_sock);
return(srslte::ERROR_NONE);
}
srslte::error_t
mbms_gw::init_m1_u(mbms_gw_args_t *args)
{
int addrlen;
struct sockaddr_in addr;
m_m1u = socket(AF_INET, SOCK_DGRAM, 0);
if(m_m1u<0)
{
m_mbms_gw_log->error("Failed to open socket: %s\n", strerror(errno));
return srslte::ERROR_CANT_START;
}
m_m1u_up = true;
/* set no loopback */
char loopch = 0;
if(setsockopt(m_m1u, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&loopch, sizeof(char))<0){
m_mbms_gw_log->error("Failed to disable loopback: %s\n", strerror(errno));
return srslte::ERROR_CANT_START;
} else {
m_mbms_gw_log->debug("Loopback disabled\n");
}
/* Set local interface for outbound multicast packets*/
/* The IP must be associated with a local multicast capable interface */
struct in_addr local_if;
local_if.s_addr = inet_addr("127.0.1.200");
if(setsockopt(m_m1u, IPPROTO_IP, IP_MULTICAST_IF, (char*)&local_if, sizeof(struct in_addr))<0){
perror("Error setting multicast interface.\n");
} else {
printf("Multicast interface specified.\n");
}
bzero(&m_m1u_multi_addr,sizeof(m_m1u_multi_addr));
m_m1u_multi_addr.sin_family = AF_INET;
m_m1u_multi_addr.sin_port = htons(GTPU_RX_PORT+1);
m_m1u_multi_addr.sin_addr.s_addr = inet_addr(args->m1u_multi_addr.c_str());
m_mbms_gw_log->info("Initialized M1-U\n");
return srslte::ERROR_NONE;
}
void
mbms_gw::run_thread()
{
//Mark the thread as running
m_running=true;
srslte::byte_buffer_t *msg;
msg = m_pool->allocate();
uint8_t seq = 0;
while(m_running)
{
msg->reset();
int n;
do{
n = read(m_sgi_mb_if, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES);
}while(n == -1 && errno == EAGAIN);
if(n<0){
m_mbms_gw_log->error("Error reading from TUN interface. Error: %s\n", strerror(errno));
}
else{
msg->N_bytes = n;
handle_sgi_md_pdu(msg);
}
}
m_pool->deallocate(msg);
return;
}
void
mbms_gw::handle_sgi_md_pdu(srslte::byte_buffer_t *msg)
{
uint8_t version;
srslte::gtpu_header_t header;
in_addr_t baddr = inet_addr("172.16.0.255");
in_addr_t saddr = inet_addr("172.16.0.254");
//Setup GTP-U header
header.flags = 0x30;
header.message_type = 0xFF;
header.length = msg->N_bytes;
header.teid = 0xAAAA; //FIXME Harcoded TEID for now
//Sanity Check IP packet
if(msg->N_bytes < 20)
{
m_mbms_gw_log->error("IPv4 min len: %d, drop msg len %d\n", 20, msg->N_bytes);
return;
}
//IP+UDP Headers
struct iphdr *iph = (struct iphdr *) msg->msg;
struct udphdr *udph = (struct udphdr *) (msg->msg + iph->ihl*4);
if(iph->version != 4)
{
m_mbms_gw_log->warning("IPv6 not supported yet.\n");
return;
}
//Replace Destination IP with broadcast address
iph->daddr = baddr;
//Replace Source IP with address in same subnet
iph->saddr = saddr;
//Replace IP cheksum
iph->check = 0;
iph->check = in_cksum((uint16_t*)msg->msg,4*(msg->msg[0] & 0x0F));
//Set Pseudo Header
struct pseudo_hdr phdr;
phdr.src_addr = iph->saddr;
phdr.dst_addr = iph->daddr;
phdr.protocol = IPPROTO_UDP;
phdr.placeholder = 0;
phdr.udp_len = udph->len;
//Set Pseudo Datagram
udph->check = 0;
int psize = sizeof(struct pseudo_hdr) + ntohs(udph->len);
uint8_t * pseudo_dgram = (uint8_t*) malloc(psize);
memcpy(pseudo_dgram, &phdr,sizeof(struct pseudo_hdr));
memcpy(pseudo_dgram+sizeof(pseudo_hdr),udph,ntohs(udph->len));
//Recompute UDP checksum
udph->check = in_cksum((uint16_t*) pseudo_dgram, psize);
free(pseudo_dgram);
//Write GTP-U header into packet
if(!srslte::gtpu_write_header(&header, msg))
{
m_mbms_gw_log->console("Error writing GTP-U header on PDU\n");
}
int n = sendto(m_m1u, msg->msg, msg->N_bytes, 0,
(sockaddr *) &m_m1u_multi_addr, sizeof(struct sockaddr));
if(n<0){
m_mbms_gw_log->console("Error writting to M1-U socket.\n");
}
else{
m_mbms_gw_log->debug("Sent %d Bytes\n", msg->N_bytes);
}
}
uint16_t
mbms_gw::in_cksum(uint16_t *iphdr, int count)
{
//RFC 1071
uint32_t sum = 0;
uint16_t padd = 0;
uint16_t result;
while(count > 1)
{
sum+= *iphdr++;
count -= 2;
}
if( count > 0 )
{
padd = * (uint8_t *) iphdr;
sum += padd;
}
/*Fold 32-bit sum to 16-bit*/
// while(sum>>16)
// sum = (sum & 0xffff) + (sum >> 16);
sum = (sum>>16)+(sum & 0xFFFF);
sum = sum + (sum >> 16);
result = (uint16_t) ~sum;
return result;
}
} //namespace srsepc

View File

@ -58,7 +58,7 @@ public:
bool get_uecrid_successful();
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp);
void mch_start_rx(uint32_t lcid);
private:
const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps
const static int NOF_BUFFER_PDUS = 64; // Number of PDU buffers per HARQ pid
@ -69,9 +69,13 @@ private:
void *uecrid_callback_arg;
srslte::sch_pdu mac_msg;
srslte::mch_pdu mch_mac_msg;
srslte::sch_pdu pending_mac_msg;
uint8_t mch_lcids[SRSLTE_N_MCH_LCIDS];
void process_sch_pdu(srslte::sch_pdu *pdu);
void process_mch_pdu(srslte::mch_pdu *pdu);
bool process_ce(srslte::sch_subh *subheader);
bool is_uecrid_successful;

View File

@ -65,17 +65,23 @@ public:
void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action);
void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action);
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action);
void new_mch_dl(srslte_ra_dl_grant_t phy_grant, tb_action_dl_t *action);
void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
void bch_decoded_ok(uint8_t *payload, uint32_t len);
void pch_decoded_ok(uint32_t len);
void pch_decoded_ok(uint32_t len);
void mch_decoded_ok(uint32_t len);
void process_mch_pdu(uint32_t len);
void set_mbsfn_config(uint32_t nof_mbsfn_services);
/******** Interface from RLC (RLC -> MAC) ****************/
/******** Interface from RRC (RRC -> MAC) ****************/
void bcch_start_rx();
void bcch_start_rx(int si_window_start, int si_window_length);
void pcch_start_rx();
void clear_rntis();
void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD);
void mch_start_rx(uint32_t lcid);
void reconfiguration();
void reset();
void wait_uplink();
@ -119,6 +125,7 @@ private:
rlc_interface_mac *rlc_h;
rrc_interface_mac *rrc_h;
srslte::log *log_h;
mac_interface_phy::mac_phy_cfg_mbsfn_t phy_mbsfn_cfg;
// MAC configuration
mac_cfg_t config;
@ -147,6 +154,13 @@ private:
srslte_softbuffer_rx_t pch_softbuffer;
uint8_t pch_payload_buffer[pch_payload_buffer_sz];
/* Buffers for MCH reception (not included in DL HARQ) */
const static uint32_t mch_payload_buffer_sz = SRSLTE_MAX_BUFFER_SIZE_BYTES;
srslte_softbuffer_rx_t mch_softbuffer;
uint8_t mch_payload_buffer[mch_payload_buffer_sz];
srslte::mch_pdu mch_msg;
/* Functions for MAC Timers */
uint32_t timer_alignment;

View File

@ -27,6 +27,9 @@
#ifndef SRSUE_PHCH_COMMON_H
#define SRSUE_PHCH_COMMON_H
#define TX_MODE_CONTINUOUS 1
#include <pthread.h>
#include <string.h>
#include <vector>
@ -34,12 +37,12 @@
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio.h"
#include "srslte/common/log.h"
#include "srslte/common/gen_mch_tables.h"
#include "phy_metrics.h"
namespace srsue {
class chest_feedback_itf
{
public:
@ -48,139 +51,188 @@ public:
virtual void set_cfo(float cfo) = 0;
};
typedef enum{
SUBFRAME_TYPE_REGULAR = 0,
SUBFRAME_TYPE_MBSFN,
SUBFRAME_TYPE_N_ITEMS,
} subframe_type_t;
static const char subframe_type_text[SUBFRAME_TYPE_N_ITEMS][20] = {"Regular", "MBSFN"};
/* Subframe config */
typedef struct {
subframe_type_t sf_type;
uint8_t mbsfn_area_id;
uint8_t non_mbsfn_region_length;
uint8_t mbsfn_mcs;
bool mbsfn_decode;
bool is_mcch;
} subframe_cfg_t;
/* Subclass that manages variables common to all workers */
class phch_common {
public:
class phch_common {
public:
/* Common variables used by all phy workers */
phy_interface_rrc::phy_cfg_t *config;
phy_args_t *args;
rrc_interface_phy *rrc;
mac_interface_phy *mac;
srslte_ue_ul_t ue_ul;
/* Power control variables */
float pathloss;
float cur_pathloss;
float p0_preamble;
float cur_radio_power;
float cur_pusch_power;
float avg_rsrp;
float avg_rsrp_cqi;
float avg_rsrp_dbm;
float avg_rsrp_sync_dbm;
float avg_rsrq_db;
float avg_rssi_dbm;
float last_radio_rssi;
float rx_gain_offset;
float avg_snr_db_cqi;
float avg_snr_db_sync;
/* Common variables used by all phy workers */
phy_interface_rrc::phy_cfg_t *config;
phy_args_t *args;
rrc_interface_phy *rrc;
mac_interface_phy *mac;
float avg_noise;
bool pcell_meas_enabled;
/* Power control variables */
float pathloss;
float cur_pathloss;
float p0_preamble;
float cur_radio_power;
float cur_pusch_power;
float avg_rsrp;
float avg_rsrp_dbm;
float avg_rsrq_db;
float avg_rssi_dbm;
float last_radio_rssi;
float rx_gain_offset;
float avg_snr_db_cqi;
float avg_noise;
uint32_t pcell_report_period;
bool pcell_first_measurement;
uint32_t pcell_report_period;
// Save last TBS for mcs>28 cases
int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS];
uint32_t last_dl_tti[2*HARQ_DELAY_MS];
// Save last TBS for mcs>28 cases
int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS];
uint32_t last_dl_tti[2*HARQ_DELAY_MS];
int last_ul_tbs[2*HARQ_DELAY_MS];
uint32_t last_ul_tti[2*HARQ_DELAY_MS];
srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS];
uint8_t last_ri;
uint8_t last_pmi;
int last_ul_tbs[2*HARQ_DELAY_MS];
uint32_t last_ul_tti[2*HARQ_DELAY_MS];
srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS];
phch_common(uint32_t max_mutex = 3);
void init(phy_interface_rrc::phy_cfg_t *config,
phy_args_t *args,
srslte::log *_log,
srslte::radio *_radio,
rrc_interface_phy *rrc,
mac_interface_phy *_mac);
uint8_t last_ri;
uint8_t last_pmi;
/* For RNTI searches, -1 means now or forever */
void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_ul_rnti(uint32_t tti);
srslte_rnti_type_t get_ul_rnti_type();
phch_common(uint32_t max_mutex = 3);
void init(phy_interface_rrc::phy_cfg_t *config,
phy_args_t *args,
srslte::log *_log,
srslte::radio *_radio,
rrc_interface_phy *rrc,
mac_interface_phy *_mac);
void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_dl_rnti(uint32_t tti);
srslte_rnti_type_t get_dl_rnti_type();
/* For RNTI searches, -1 means now or forever */
void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_ul_rnti(uint32_t tti);
srslte_rnti_type_t get_ul_rnti_type();
void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]);
bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL);
void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_dl_rnti(uint32_t tti);
srslte_rnti_type_t get_dl_rnti_type();
void reset_pending_ack(uint32_t tti);
void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs);
bool get_pending_ack(uint32_t tti);
bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs);
bool is_any_pending_ack();
void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]);
bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL);
void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
void reset_pending_ack(uint32_t tti);
void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs);
bool get_pending_ack(uint32_t tti);
bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs);
bool is_any_pending_ack();
void set_nof_mutex(uint32_t nof_mutex);
void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
void set_nof_mutex(uint32_t nof_mutex);
bool sr_enabled;
int sr_last_tx_tti;
srslte::radio* get_radio();
void set_cell(const srslte_cell_t &c);
uint32_t get_nof_prb();
void set_dl_metrics(const dl_metrics_t &m);
void get_dl_metrics(dl_metrics_t &m);
void set_ul_metrics(const ul_metrics_t &m);
void get_ul_metrics(ul_metrics_t &m);
void set_sync_metrics(const sync_metrics_t &m);
void get_sync_metrics(sync_metrics_t &m);
void reset_ul();
void reset();
private:
std::vector<pthread_mutex_t> tx_mutex;
bool is_first_of_burst;
srslte::radio *radio_h;
float cfo;
srslte::log *log_h;
bool sr_enabled;
int sr_last_tx_tti;
bool ul_rnti_active(uint32_t tti);
bool dl_rnti_active(uint32_t tti);
uint16_t ul_rnti, dl_rnti;
srslte_rnti_type_t ul_rnti_type, dl_rnti_type;
int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end;
srslte::radio* get_radio();
float time_adv_sec;
void set_cell(const srslte_cell_t &c);
uint32_t get_nof_prb();
void set_dl_metrics(const dl_metrics_t &m);
void get_dl_metrics(dl_metrics_t &m);
void set_ul_metrics(const ul_metrics_t &m);
void get_ul_metrics(ul_metrics_t &m);
void set_sync_metrics(const sync_metrics_t &m);
void get_sync_metrics(sync_metrics_t &m);
srslte_dci_rar_grant_t rar_grant;
bool rar_grant_pending;
uint32_t rar_grant_tti;
void reset_ul();
void reset();
typedef struct {
bool enabled;
uint32_t I_lowest;
uint32_t n_dmrs;
} pending_ack_t;
pending_ack_t pending_ack[TTIMOD_SZ];
// MBSFN helpers
void build_mch_table();
void build_mcch_table();
void set_mcch();
void get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti);
void set_mch_period_stop(uint32_t stop);
private:
bool have_mtch_stop;
pthread_mutex_t mtch_mutex;
pthread_cond_t mtch_cvar;
bool is_first_tx;
std::vector<pthread_mutex_t> tx_mutex;
uint32_t nof_workers;
uint32_t nof_mutex;
uint32_t max_mutex;
bool is_first_of_burst;
srslte::radio *radio_h;
float cfo;
srslte::log *log_h;
srslte_cell_t cell;
bool ul_rnti_active(uint32_t tti);
bool dl_rnti_active(uint32_t tti);
uint16_t ul_rnti, dl_rnti;
srslte_rnti_type_t ul_rnti_type, dl_rnti_type;
int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end;
float time_adv_sec;
srslte_dci_rar_grant_t rar_grant;
bool rar_grant_pending;
uint32_t rar_grant_tti;
typedef struct {
bool enabled;
uint32_t I_lowest;
uint32_t n_dmrs;
} pending_ack_t;
pending_ack_t pending_ack[TTIMOD_SZ];
bool is_first_tx;
dl_metrics_t dl_metrics;
uint32_t dl_metrics_count;
bool dl_metrics_read;
ul_metrics_t ul_metrics;
uint32_t ul_metrics_count;
bool ul_metrics_read;
sync_metrics_t sync_metrics;
uint32_t sync_metrics_count;
bool sync_metrics_read;
};
uint32_t nof_workers;
uint32_t nof_mutex;
uint32_t max_mutex;
srslte_cell_t cell;
dl_metrics_t dl_metrics;
uint32_t dl_metrics_count;
bool dl_metrics_read;
ul_metrics_t ul_metrics;
uint32_t ul_metrics_count;
bool ul_metrics_read;
sync_metrics_t sync_metrics;
uint32_t sync_metrics_count;
bool sync_metrics_read;
// MBSFN
bool sib13_configured;
bool mcch_configured;
uint32_t mch_period_stop;
uint8_t mch_table[40];
uint8_t mcch_table[10];
bool is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti);
bool is_mcch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti);
};
} // namespace srsue
#endif // SRSUE_PDCH_COMMON_H

View File

@ -89,9 +89,10 @@ private:
/* Internal methods */
bool extract_fft_and_pdcch_llr();
void compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr);
void compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr);
bool extract_fft_and_pdcch_llr(subframe_cfg_t sf_cfg);
/* ... for DL */
bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant);
bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant);
@ -105,6 +106,11 @@ private:
uint32_t pid,
bool acks[SRSLTE_MAX_CODEWORDS]);
bool decode_pmch(srslte_ra_dl_grant_t *grant,
uint8_t *payload,
srslte_softbuffer_rx_t* softbuffer,
uint16_t mbsfn_area_id);
/* ... for UL */
void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer,
uint32_t rv, uint16_t rnti, bool is_from_rar);

View File

@ -120,7 +120,7 @@ public:
void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1);
void pdcch_ul_search_reset();
void pdcch_dl_search_reset();
/* Get/Set PHY parameters interface from RRC */
void get_config(phy_cfg_t *phy_cfg);
void set_config(phy_cfg_t *phy_cfg);
@ -128,7 +128,13 @@ public:
void set_config_common(phy_cfg_common_t *common);
void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd);
void set_config_64qam_en(bool enable);
void set_config_mbsfn_sib2(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2);
void set_config_mbsfn_sib13(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13);
void set_config_mbsfn_mcch(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch);
/*Set MAC->PHY MCH period stopping point*/
void set_mch_period_stop(uint32_t stop);
float get_phr();
float get_pathloss_db();

View File

@ -73,6 +73,8 @@ public:
bool deattach();
bool is_attached();
void start_plot();
void print_mbms();
bool mbms_service_start(uint32_t serv, uint32_t port);
void print_pool();

View File

@ -116,6 +116,7 @@ typedef struct {
bool print_buffer_state;
bool metrics_csv_enable;
std::string metrics_csv_filename;
int mbms_service;
}expert_args_t;
typedef struct {
@ -167,6 +168,9 @@ public:
virtual void print_pool() = 0;
virtual void radio_overflow() = 0;
virtual void print_mbms() = 0;
virtual bool mbms_service_start(uint32_t serv, uint32_t port) = 0;
void handle_rf_msg(srslte_rf_error_t error);

View File

@ -42,6 +42,7 @@ namespace srsue {
class gw
:public gw_interface_pdcp
,public gw_interface_nas
,public gw_interface_rrc
,public thread
{
public:
@ -50,14 +51,17 @@ public:
void stop();
void get_metrics(gw_metrics_t &m);
void set_netmask(std::string netmask);
// PDCP interface
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu);
// NAS interface
srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str);
void set_netmask(std::string netmask);
// RRC interface
void add_mch_port(uint32_t lcid, uint32_t port);
private:
@ -70,9 +74,10 @@ private:
nas_interface_gw *nas;
srslte::byte_buffer_pool *pool;
srslte::log *gw_log;
srslte::srslte_gw_config_t cfg;
bool running;
bool run_enable;
int32 tun_fd;
@ -88,6 +93,12 @@ private:
void run_thread();
srslte::error_t init_if(char *err_str);
// MBSFN
int mbsfn_sock_fd; // Sink UDP socket file descriptor
struct sockaddr_in mbsfn_sock_addr; // Target address
uint32_t mbsfn_ports[SRSLTE_N_MCH_LCIDS]; // Target ports for MBSFN data
};
} // namespace srsue

View File

@ -181,6 +181,9 @@ class cell_t
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3ptr() {
return &sib3;
}
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13ptr() {
return &sib13;
}
uint32_t get_cell_id() {
return sib1.cell_id;
@ -232,20 +235,23 @@ class cell_t
}
phy_interface_rrc::phy_cell_t phy_cell;
bool in_sync;
bool in_sync;
bool has_mcch;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13;
LIBLTE_RRC_MCCH_MSG_STRUCT mcch;
private:
private:
float rsrp;
struct timeval last_update;
bool has_valid_sib1;
bool has_valid_sib2;
bool has_valid_sib3;
bool has_valid_sib13;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13;
};
class rrc
@ -267,6 +273,7 @@ public:
pdcp_interface_rrc *pdcp_,
nas_interface_rrc *nas_,
usim_interface_rrc *usim_,
gw_interface_rrc *gw_,
srslte::mac_interface_timers *mac_timers_,
srslte::log *rrc_log_);
@ -278,6 +285,9 @@ public:
// Timeout callback interface
void timer_expired(uint32_t timeout_id);
void liblte_rrc_log(char *str);
void print_mbms();
bool mbms_service_start(uint32_t serv, uint32_t port);
// NAS interface
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
@ -310,7 +320,7 @@ public:
void write_pdu_bcch_bch(byte_buffer_t *pdu);
void write_pdu_bcch_dlsch(byte_buffer_t *pdu);
void write_pdu_pcch(byte_buffer_t *pdu);
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu);
private:
@ -336,7 +346,8 @@ private:
pdcp_interface_rrc *pdcp;
nas_interface_rrc *nas;
usim_interface_rrc *usim;
gw_interface_rrc *gw;
LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg;
LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg;
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
@ -436,7 +447,7 @@ private:
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf);
const static int SIB_SEARCH_TIMEOUT_MS = 1000;
const static uint32_t NOF_REQUIRED_SIBS = 3; // SIB1, SIB2 and SIB3
const static uint32_t NOF_REQUIRED_SIBS = 13; // SIB1, SIB2 and SIB3
bool initiated;
bool ho_start;
@ -619,12 +630,14 @@ private:
void handle_sib13();
void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2);
void apply_sib13_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13);
void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup);
void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup);
void handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig);
void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg);
void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg);
void release_drb(uint8_t lcid);
void add_mrb(uint32_t lcid, uint32_t port);
bool apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg);
void apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults);
void apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg, bool apply_defaults);

View File

@ -36,7 +36,7 @@
namespace srsue {
demux::demux() : mac_msg(20), pending_mac_msg(20), rlc(NULL)
demux::demux() : mac_msg(20), mch_mac_msg(20), pending_mac_msg(20), rlc(NULL)
{
}
@ -47,6 +47,7 @@ void demux::init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc_, srsl
rlc = rlc_;
time_alignment_timer = time_alignment_timer_;
pdus.init(this, log_h);
bzero(&mch_lcids, SRSLTE_N_MCH_LCIDS);
}
void demux::set_uecrid_callback(bool (*callback)(void*,uint64_t), void *arg) {
@ -129,7 +130,10 @@ void demux::push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) {
}
void demux::push_pdu_mch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) {
pdus.push(buff, nof_bytes, srslte::pdu_queue::MCH, tstamp);
uint8_t *mch_buffer_ptr = request_buffer(nof_bytes);
memcpy(mch_buffer_ptr, buff, nof_bytes);
pdus.push(mch_buffer_ptr, nof_bytes, srslte::pdu_queue::MCH, tstamp);
mch_buffer_ptr = NULL;
}
bool demux::process_pdus()
@ -145,16 +149,17 @@ void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes, srslte::pdu_queue:
// Unpack DLSCH MAC PDU
mac_msg.init_rx(nof_bytes);
mac_msg.parse_packet(mac_pdu);
process_sch_pdu(&mac_msg);
//srslte_vec_fprint_byte(stdout, mac_pdu, nof_bytes);
pdus.deallocate(mac_pdu);
break;
case srslte::pdu_queue::BCH:
rlc->write_pdu_bcch_dlsch(mac_pdu, nof_bytes);
break;
case srslte::pdu_queue::MCH:
mch_mac_msg.init_rx(nof_bytes);
mch_mac_msg.parse_packet(mac_pdu);
deallocate(mac_pdu);
process_mch_pdu(&mch_mac_msg);
// Process downlink MCH
break;
}
@ -168,7 +173,7 @@ void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg)
if (pdu_msg->get()->get_sdu_lcid() == 0) {
uint8_t *x = pdu_msg->get()->get_sdu_ptr();
uint32_t sum = 0;
for (int i=0;i<pdu_msg->get()->get_payload_size();i++) {
for (uint32_t i=0;i<pdu_msg->get()->get_payload_size();i++) {
sum += x[i];
}
if (sum == 0) {
@ -196,6 +201,41 @@ void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg)
}
}
}
void demux::process_mch_pdu(srslte::mch_pdu *mch_msg){
//disgarding headers that have already been processed
while(mch_msg->next()){
if(srslte::mch_subh::MCH_SCHED_INFO == mch_msg->get()->ce_type()){
uint16_t stop;
uint8_t lcid;
if(mch_msg->get()->get_next_mch_sched_info(&lcid, &stop)) {
Info("MCH Sched Info: LCID: %d, Stop: %d, tti is %d \n", lcid, stop, phy_h->get_current_tti());
}
}
if(mch_msg->get()->is_sdu()) {
uint32_t lcid = mch_msg->get()->get_sdu_lcid();
if(lcid >= SRSLTE_N_MCH_LCIDS) {
Error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid);
return;
}
Debug("Wrote MCH LCID=%d to RLC\n", lcid);
if(1 == mch_lcids[lcid]) {
rlc->write_pdu_mch(lcid, mch_msg->get()->get_sdu_ptr(), mch_msg->get()->get_payload_size());
}
}
}
}
void demux::mch_start_rx(uint32_t lcid)
{
if(lcid < 32) {
Info("MCH Channel Setup: LCID=%d\n", lcid);
mch_lcids[lcid] = 1;
} else {
Error("MCH Channel Setup: invalid LCID=%d\n", lcid);
}
}
bool demux::process_ce(srslte::sch_subh *subh) {
switch(subh->ce_type()) {

View File

@ -43,7 +43,8 @@ namespace srsue {
mac::mac() : timers(64),
mux_unit(MAC_NOF_HARQ_PROC),
pdu_process_thread(&demux_unit)
pdu_process_thread(&demux_unit),
mch_msg(10)
{
pcap = NULL;
bzero(&metrics, sizeof(mac_metrics_t));
@ -58,6 +59,7 @@ bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac
tti = 0;
srslte_softbuffer_rx_init(&pch_softbuffer, 100);
srslte_softbuffer_rx_init(&mch_softbuffer, 100);
timer_alignment = timers.get_unique_id();
contention_resolution_timer = timers.get_unique_id();
@ -220,6 +222,34 @@ void mac::pch_decoded_ok(uint32_t len)
}
}
void mac::mch_decoded_ok(uint32_t len)
{
// Parse MAC header
mch_msg.init_rx(len);
mch_msg.parse_packet(mch_payload_buffer);
while(mch_msg.next()) {
for(uint32_t i = 0; i < phy_mbsfn_cfg.nof_mbsfn_services;i++) {
if(srslte::mch_subh::MCH_SCHED_INFO == mch_msg.get()->ce_type()) {
uint16_t stop;
uint8_t lcid;
if(mch_msg.get()->get_next_mch_sched_info(&lcid, &stop)) {
phy_h->set_mch_period_stop(stop);
Info("MCH Sched Info: LCID: %d, Stop: %d, tti is %d \n", lcid, stop, phy_h->get_current_tti());
}
}
}
}
demux_unit.push_pdu_mch(mch_payload_buffer, len, 0);
pdu_process_thread.notify();
if (pcap) {
pcap->write_dl_mch(mch_payload_buffer, len, true, phy_h->get_current_tti());
}
metrics.rx_brate += len*8;
}
void mac::tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_RAR) {
@ -303,6 +333,16 @@ void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_i
}
}
void mac::new_mch_dl(srslte_ra_dl_grant_t phy_grant, tb_action_dl_t *action)
{
memcpy(&action->phy_grant, &phy_grant, sizeof(srslte_phy_grant_t));
action->generate_ack = false;
action->decode_enabled[0] = true;
srslte_softbuffer_rx_reset_cb(&mch_softbuffer, 1);
action->payload_ptr[0] = mch_payload_buffer;
action->softbuffers[0] = &mch_softbuffer;
}
void mac::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
int tbs = ul_harq.get_current_tbs(tti);
@ -383,6 +423,13 @@ void mac::get_config(mac_cfg_t* mac_cfg)
memcpy(mac_cfg, &config, sizeof(mac_cfg_t));
}
void mac::set_mbsfn_config(uint32_t nof_mbsfn_services)
{
//cfg->nof_mbsfn_services = config.mbsfn.mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size;
phy_mbsfn_cfg.nof_mbsfn_services = nof_mbsfn_services;
}
void mac::set_config(mac_cfg_t* mac_cfg)
{
memcpy(&config, mac_cfg, sizeof(mac_cfg_t));
@ -415,6 +462,11 @@ void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_t
bsr_procedure.set_priority(lcid, priority);
}
void mac::mch_start_rx(uint32_t lcid)
{
demux_unit.mch_start_rx(lcid);
}
void mac::get_metrics(mac_metrics_t &m)
{
Info("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f\n",

View File

@ -188,7 +188,7 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32
bsr_proc::bsr_t bsr;
bool regular_bsr = bsr_procedure->need_to_send_bsr_on_ul_grant(pdu_msg.rem_size(), &bsr);
bool bsr_is_inserted = false;
bool bsr_is_inserted = false;
// MAC control element for BSR, with exception of BSR included for padding;
if (regular_bsr) {

View File

@ -271,8 +271,9 @@ void ra_proc::step_preamble_transmission() {
}
void ra_proc::step_pdcch_setup() {
int ra_tti = phy_h->prach_tx_tti();
if (ra_tti > 0) {
if (ra_tti > 0) {
ra_rnti = 1+ra_tti%10;
rInfo("seq=%d, ra-rnti=0x%x, ra-tti=%d\n", sel_preamble, ra_rnti, ra_tti);
log_h->console("Random Access Transmission: seq=%d, ra-rnti=0x%x\n", sel_preamble, ra_rnti);
@ -387,7 +388,7 @@ void ra_proc::step_response_reception() {
if (ra_tti >= 0 && !rar_received) {
uint32_t interval = srslte_tti_interval(phy_h->get_current_tti(), ra_tti+3+responseWindowSize);
if (interval > 1 && interval < 100) {
rDebug("RA response not received within the response window\n");
Error("RA response not received within the response window\n");
state = RESPONSE_ERROR;
}
}

View File

@ -139,7 +139,11 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
("expert.ip_netmask",
bpo::value<string>(&args->expert.ip_netmask)->default_value("255.255.255.0"),
"Netmask of the tun_srsue device")
("expert.mbms_service",
bpo::value<int>(&args->expert.mbms_service)->default_value(-1),
"automatically starts an mbms service of the number given")
("expert.phy.worker_cpu_mask",
bpo::value<int>(&args->expert.phy.worker_cpu_mask)->default_value(-1),
"cpu bit mask (eg 255 = 1111 1111)")
@ -420,6 +424,9 @@ static int sigcnt = 0;
static bool running = true;
static bool do_metrics = false;
metrics_stdout metrics_screen;
static bool show_mbms = false;
static bool mbms_service_start = false;
uint32_t serv, port;
void sig_int_handler(int signo) {
sigcnt++;
@ -431,14 +438,14 @@ void sig_int_handler(int signo) {
}
void *input_loop(void *m) {
char key;
string key;
while (running) {
cin >> key;
getline(cin, key);
if (cin.eof() || cin.bad()) {
cout << "Closing stdin thread." << endl;
break;
} else {
if ('t' == key) {
if (0 == key.compare("t")) {
do_metrics = !do_metrics;
if (do_metrics) {
cout << "Enter t to stop trace." << endl;
@ -447,10 +454,31 @@ void *input_loop(void *m) {
}
metrics_screen.toggle_print(do_metrics);
} else
if ('q' == key) {
if (0 == key.compare("q")) {
running = false;
}
else if (0 == key.compare("mbms")) {
show_mbms = true;
} else if (key.find("mbms_service_start") != string::npos) {
char *dup = strdup(key.c_str());
strtok(dup, " ");
char *s = strtok(NULL, " ");
if(NULL == s) {
cout << "Usage: mbms_service_start <service_id> <port_number>" << endl;
continue;
}
serv = atoi(s);
char* p = strtok(NULL, " ");
if(NULL == p) {
cout << "Usage: mbms_service_start <service_id> <port_number>" << endl;
continue;
}
port = atoi(p);
mbms_service_start = true;
free(dup);
}
}
}
return NULL;
}
@ -502,17 +530,36 @@ int main(int argc, char *argv[])
if (args.gui.enable) {
ue->start_plot();
}
if(args.expert.mbms_service > -1){
//ue->mbms_service_start(args.expert.mbms_service, 4321);
serv = args.expert.mbms_service;
port = 4321;
mbms_service_start = true;
}
}
int cnt=0;
while (running) {
if(mbms_service_start) {
if(ue->mbms_service_start(serv, port)){
mbms_service_start = false;
}
}
if(show_mbms) {
show_mbms = false;
ue->print_mbms();
}
sleep(1);
if (args.expert.print_buffer_state) {
cnt++;
if (cnt==10) {
cnt=0;
ue->print_pool();
}
} else {
while (!ue->attach() && running) {
sleep(1);
}
}
sleep(1);
}
pthread_cancel(input);
metricshub.stop();

View File

@ -26,6 +26,7 @@
#include <assert.h>
#include <string.h>
#include <sstream>
#include "srslte/srslte.h"
#include "srsue/hdr/phy/phch_common.h"
@ -50,7 +51,8 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_)
rx_gain_offset = 0;
last_ri = 0;
last_pmi = 0;
//have_mtch_stop = false;
bzero(&dl_metrics, sizeof(dl_metrics_t));
dl_metrics_read = true;
dl_metrics_count = 0;
@ -71,6 +73,8 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_)
reset();
sib13_configured = false;
mcch_configured = false;
}
void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac)
@ -367,4 +371,172 @@ void phch_common::reset_ul()
*/
}
/* Convert 6-bit maps to 10-element subframe tables
bitmap = |0|0|0|0|0|0|
subframe index = |1|2|3|6|7|8|
*/
void phch_common::build_mch_table()
{
// First reset tables
bzero(&mch_table[0], sizeof(uint8_t)*40);
// 40 element table represents 4 frames (40 subframes)
generate_mch_table(&mch_table[0], config->mbsfn.mbsfn_subfr_cnfg.subfr_alloc,(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE == config->mbsfn.mbsfn_subfr_cnfg.subfr_alloc_num_frames)?1:4);
// Debug
std::stringstream ss;
ss << "|";
for(uint32_t j=0; j<40; j++) {
ss << (int) mch_table[j] << "|";
}
Info("MCH table: %s\n", ss.str().c_str());
}
void phch_common::build_mcch_table()
{
// First reset tables
bzero(&mcch_table[0], sizeof(uint8_t)*10);
generate_mcch_table(&mcch_table[0], config->mbsfn.mbsfn_area_info.sf_alloc_info_r9);
// Debug
std::stringstream ss;
ss << "|";
for(uint32_t j=0; j<10; j++) {
ss << (int) mcch_table[j] << "|";
}
Info("MCCH table: %s\n", ss.str().c_str());
sib13_configured = true;
}
void phch_common::set_mcch()
{
mcch_configured = true;
}
void phch_common::set_mch_period_stop(uint32_t stop)
{
pthread_mutex_lock(&mtch_mutex);
have_mtch_stop = true;
mch_period_stop = stop;
pthread_cond_signal(&mtch_cvar);
pthread_mutex_unlock(&mtch_mutex);
}
bool phch_common::is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti)
{
uint32_t sfn; // System Frame Number
uint8_t sf; // Subframe
uint8_t offset;
uint8_t period;
sfn = phy_tti/10;
sf = phy_tti%10;
// Set some defaults
cfg->mbsfn_area_id = 0;
cfg->non_mbsfn_region_length = 1;
cfg->mbsfn_mcs = 2;
cfg->mbsfn_decode = false;
cfg->is_mcch = false;
// Check for MCCH
if(is_mcch_subframe(cfg, phy_tti)) {
cfg->is_mcch = true;
return true;
}
// Not MCCH, check for MCH
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *subfr_cnfg = &config->mbsfn.mbsfn_subfr_cnfg;
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *area_info = &config->mbsfn.mbsfn_area_info;
offset = subfr_cnfg->radio_fr_alloc_offset;
period = liblte_rrc_radio_frame_allocation_period_num[subfr_cnfg->radio_fr_alloc_period];
if(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_ONE == subfr_cnfg->subfr_alloc_num_frames) {
if((sfn%period == offset) && (mch_table[sf] > 0)) {
if(sib13_configured) {
cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9;
cfg->non_mbsfn_region_length = liblte_rrc_non_mbsfn_region_length_num[area_info->non_mbsfn_region_length];
if(mcch_configured) {
// Iterate through PMCH configs to see which one applies in the current frame
LIBLTE_RRC_MCCH_MSG_STRUCT *mcch = &config->mbsfn.mcch;
uint32_t mbsfn_per_frame = mcch->pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9/liblte_rrc_mch_scheduling_period_r9_num[mcch->pmch_infolist_r9[0].pmch_config_r9.mch_schedulingperiod_r9];
uint32_t frame_alloc_idx = sfn%liblte_rrc_mbsfn_common_sf_alloc_period_r9_num[mcch->commonsf_allocperiod_r9];
uint32_t sf_alloc_idx = frame_alloc_idx*mbsfn_per_frame + ((sf<4)?sf-1:sf-3);
pthread_mutex_lock(&mtch_mutex);
while(!have_mtch_stop) {
pthread_cond_wait(&mtch_cvar, &mtch_mutex);
}
pthread_mutex_unlock(&mtch_mutex);
for(uint32_t i=0; i<mcch->pmch_infolist_r9_size; i++) {
if(sf_alloc_idx <= mch_period_stop) {
//trigger conditional variable, has ot be untriggered by mtch stop location
cfg->mbsfn_mcs = mcch->pmch_infolist_r9[i].pmch_config_r9.datamcs_r9;
cfg->mbsfn_decode = true;
} else {
//have_mtch_stop = false;
}
}
Debug("MCH subframe TTI:%d\n", phy_tti);
}
}
return true;
}
}else if(LIBLTE_RRC_SUBFRAME_ALLOCATION_NUM_FRAMES_FOUR == subfr_cnfg->subfr_alloc_num_frames) {
uint8_t idx = sfn%period;
if((idx >= offset) && (idx < offset+4)) {
if(mch_table[(idx*10)+sf] > 0){
if(sib13_configured) {
cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9;
cfg->non_mbsfn_region_length = liblte_rrc_non_mbsfn_region_length_num[area_info->non_mbsfn_region_length];
// TODO: check for MCCH configuration, set MCS and decode
}
return true;
}
}
}
return false;
}
bool phch_common::is_mcch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti)
{
uint32_t sfn; // System Frame Number
uint8_t sf; // Subframe
uint8_t offset;
uint8_t period;
sfn = phy_tti/10;
sf = phy_tti%10;
if(sib13_configured) {
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *subfr_cnfg = &config->mbsfn.mbsfn_subfr_cnfg;
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT *area_info = &config->mbsfn.mbsfn_area_info;
offset = area_info->mcch_offset_r9;
period = liblte_rrc_mcch_repetition_period_r9_num[area_info->mcch_repetition_period_r9];
if((sfn%period == offset) && mcch_table[sf] > 0) {
cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9;
cfg->non_mbsfn_region_length = liblte_rrc_non_mbsfn_region_length_num[area_info->non_mbsfn_region_length];
cfg->mbsfn_mcs = liblte_rrc_mcch_signalling_mcs_r9_num[area_info->signalling_mcs_r9];
cfg->mbsfn_decode = true;
have_mtch_stop = false;
Debug("MCCH subframe TTI:%d\n", phy_tti);
return true;
}
}
return false;
}
void phch_common::get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti)
{
if(is_mch_subframe(cfg, phy_tti)) {
cfg->sf_type = SUBFRAME_TYPE_MBSFN;
}else{
cfg->sf_type = SUBFRAME_TYPE_REGULAR;
}
}
}

View File

@ -392,6 +392,7 @@ void phch_recv::run_thread()
phy_state.state_exit();
break;
case sync_state::SFN_SYNC:
/* SFN synchronization using MIB. run_subframe() receives and processes 1 subframe
* and returns
*/
@ -473,6 +474,7 @@ void phch_recv::run_thread()
is_end_of_burst = true;
// Start worker
workers_pool->start_worker(worker);
@ -500,6 +502,7 @@ void phch_recv::run_thread()
}
break;
case sync_state::IDLE:
if (radio_h->is_init()) {
uint32_t nsamples = 1920;
if (current_srate > 0) {

View File

@ -133,6 +133,7 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, srslte::log *log_ph
return false;
}
srslte_chest_dl_set_rsrp_neighbour(&ue_dl.chest, true);
srslte_chest_dl_average_subframe(&ue_dl.chest, phy->args->average_subframe_enabled);
srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, phy->args->cfo_ref_mask!=0, phy->args->cfo_ref_mask);
@ -157,7 +158,11 @@ bool phch_worker::set_cell(srslte_cell_t cell_)
Error("Initiating UE DL\n");
goto unlock;
}
if(srslte_ue_dl_set_mbsfn_area_id(&ue_dl, 1)){
Error("Setting mbsfn id\n");
}
if (srslte_ue_ul_set_cell(&ue_ul, cell)) {
Error("Initiating UE UL\n");
goto unlock;
@ -247,6 +252,10 @@ void phch_worker::work_imp()
reset_uci();
subframe_cfg_t sf_cfg;
phy->get_sf_config(&sf_cfg, tti);
Debug("TTI: %d, Subframe type: %s\n", tti, subframe_type_text[sf_cfg.sf_type]);
bool dl_grant_available = false;
bool ul_grant_available = false;
bool dl_ack[SRSLTE_MAX_CODEWORDS] = {false};
@ -270,47 +279,100 @@ void phch_worker::work_imp()
phy->avg_rssi_dbm = SRSLTE_VEC_EMA(rssi_dbm, phy->avg_rssi_dbm, phy->args->snr_ema_coeff);
}
/* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */
bool chest_ok = extract_fft_and_pdcch_llr();
bool mch_decoded = false;
srslte_ra_dl_grant_t mch_grant;
// Call feedback loop for chest
if (chest_loop && ((1<<(tti%10)) & phy->args->cfo_ref_mask)) {
chest_loop->set_cfo(srslte_chest_dl_get_cfo(&ue_dl.chest));
}
bool chest_ok = false;
bool snr_th_ok = false;
if (chest_ok) {
/***** Downlink Processing *******/
if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type) {
/* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */
chest_ok = extract_fft_and_pdcch_llr(sf_cfg);
/***** Downlink Processing *******/
snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0;
/* PDCCH DL + PDSCH */
dl_grant_available = decode_pdcch_dl(&dl_mac_grant);
if(dl_grant_available) {
/* Send grant to MAC and get action for this TB */
if (chest_ok && snr_th_ok) {
/***** Downlink Processing *******/
/* PDCCH DL + PDSCH */
dl_grant_available = decode_pdcch_dl(&dl_mac_grant);
if(dl_grant_available) {
/* Send grant to MAC and get action for this TB */
phy->mac->new_grant_dl(dl_mac_grant, &dl_action);
/* Set DL ACKs to default */
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
dl_ack[tb] = dl_action.default_ack[tb];
}
/* Decode PDSCH if instructed to do so */
if (dl_action.decode_enabled[0] || dl_action.decode_enabled[1]) {
decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr,
dl_action.softbuffers, dl_action.rv, dl_action.rnti,
dl_mac_grant.pid, dl_ack);
}
if (dl_action.generate_ack_callback) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (dl_action.decode_enabled[tb]) {
phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid);
dl_ack[tb] = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg);
Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack[tb]);
}
}
}
Debug("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack);
if (dl_action.generate_ack) {
set_uci_ack(dl_ack, dl_mac_grant.tb_en);
}
}
}
} else if(SUBFRAME_TYPE_MBSFN == sf_cfg.sf_type) {
srslte_ue_dl_set_non_mbsfn_region(&ue_dl, sf_cfg.non_mbsfn_region_length);
/* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */
if (extract_fft_and_pdcch_llr(sf_cfg)) {
dl_grant_available = decode_pdcch_dl(&dl_mac_grant);
phy->mac->new_grant_dl(dl_mac_grant, &dl_action);
/* Set DL ACKs to default */
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
dl_ack[tb] = dl_action.default_ack[tb];
}
/* Decode PDSCH if instructed to do so */
if (dl_action.decode_enabled[0] || dl_action.decode_enabled[1]) {
decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr,
dl_action.softbuffers, dl_action.rv, dl_action.rnti,
dl_mac_grant.pid, dl_ack);
}
if (dl_action.generate_ack_callback) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (dl_action.decode_enabled[tb]) {
phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid);
dl_ack[tb] = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg);
Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack[tb]);
}
if(sf_cfg.mbsfn_decode) {
mch_grant.sf_type = SRSLTE_SF_MBSFN;
mch_grant.mcs[0].idx = sf_cfg.mbsfn_mcs;
mch_grant.tb_en[0] = true;
for(uint32_t i=1;i<SRSLTE_MAX_CODEWORDS;i++) {
mch_grant.tb_en[i] = false;
}
mch_grant.nof_prb = ue_dl.pmch.cell.nof_prb;
srslte_dl_fill_ra_mcs(&mch_grant.mcs[0], mch_grant.nof_prb);
for(int j = 0; j < 2; j++){
for(uint32_t f = 0; f < mch_grant.nof_prb; f++){
mch_grant.prb_idx[j][f] = true;
}
}
}
Debug("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack);
if (dl_action.generate_ack) {
set_uci_ack(dl_ack, dl_mac_grant.tb_en);
mch_grant.Qm[0] = srslte_mod_bits_x_symbol(mch_grant.mcs[0].mod);
/* Get MCH action for this TB */
phy->mac->new_mch_dl(mch_grant, &dl_action);
srslte_softbuffer_rx_reset_tbs(dl_action.softbuffers[0], mch_grant.mcs[0].tbs);
Debug("TBS=%d, Softbuffer max_cb=%d\n", mch_grant.mcs[0].tbs, dl_action.softbuffers[0]->max_cb);
if(dl_action.decode_enabled[0]) {
mch_decoded = decode_pmch(&mch_grant, dl_action.payload_ptr[0], dl_action.softbuffers[0], sf_cfg.mbsfn_area_id);
}
}
}
}
@ -394,21 +456,31 @@ void phch_worker::work_imp()
phy->worker_end(tx_tti, signal_ready, &signal_ptr[-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
}
if (!dl_action.generate_ack_callback) {
if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) {
if (dl_ack[0]) {
phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]);
}
} else if (!rar_delivered) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (dl_action.decode_enabled[tb]) {
phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid);
if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type) {
if (!dl_action.generate_ack_callback) {
if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) {
if (dl_ack[0]) {
phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]);
}
} else if (!rar_delivered) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (dl_action.decode_enabled[tb]) {
phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid);
}
}
}
}
} else if (SUBFRAME_TYPE_MBSFN == sf_cfg.sf_type && sf_cfg.mbsfn_decode) {
if(mch_decoded) {
phy->mac->mch_decoded_ok(mch_grant.mcs[0].tbs/8);
} else if(sf_cfg.is_mcch) {
//release lock in phch_common
phy->set_mch_period_stop(0);
}
}
if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type){
update_measurements();
}
update_measurements();
if (chest_ok) {
if (phy->avg_rsrp_dbm > -130.0 && phy->avg_snr_db_cqi > -6.0) {
@ -456,7 +528,9 @@ void phch_worker::compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr) {
}
}
bool phch_worker::extract_fft_and_pdcch_llr() {
bool phch_worker::extract_fft_and_pdcch_llr(subframe_cfg_t sf_cfg) {
bool decode_pdcch = true;
// Do always channel estimation to keep track of out-of-sync and send measurements to RRC
@ -475,18 +549,21 @@ bool phch_worker::extract_fft_and_pdcch_llr() {
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS);
}
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
}
chest_done = true;
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
}
int decode_fft = 0;
if(SUBFRAME_TYPE_MBSFN == sf_cfg.sf_type) {
srslte_ue_dl_set_non_mbsfn_region(&ue_dl, sf_cfg.non_mbsfn_region_length);
decode_fft = srslte_ue_dl_decode_fft_estimate_mbsfn(&ue_dl, tti%10, &cfi, SRSLTE_SF_MBSFN);
}else{
decode_fft = srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi);
}
if (decode_fft < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
}
chest_done = true;
chest_done = true;
if (chest_done && decode_pdcch) { /* and not in DRX mode */
@ -752,6 +829,73 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL
return ret;
}
bool phch_worker::decode_pmch(srslte_ra_dl_grant_t *grant, uint8_t *payload,
srslte_softbuffer_rx_t* softbuffer, uint16_t mbsfn_area_id)
{
char timestr[64];
timestr[0]='\0';
Debug("DL Buffer TTI %d: Decoding PMCH\n", tti);
/* Setup PMCH configuration */
srslte_ue_dl_set_mbsfn_area_id(&ue_dl, mbsfn_area_id);
if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, SRSLTE_PMCH_RV, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA)) {
if (ue_dl.pmch_cfg.grant.mcs[0].mod > 0 && ue_dl.pmch_cfg.grant.mcs[0].tbs >= 0) {
Debug("Decoding PMCH SF: %d, MBSFN area ID: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d, cfi=%d\n",
ue_dl.pmch_cfg.sf_idx, mbsfn_area_id, srslte_mod_string(ue_dl.pmch_cfg.grant.mcs[0].mod), ue_dl.pmch_cfg.grant.mcs[0].tbs, ue_dl.pmch_cfg.nbits[0].nof_re,
ue_dl.pmch_cfg.nbits[0].nof_bits, 0, ue_dl.pmch_cfg.grant.nof_prb, ue_dl.pmch_cfg.nbits[0].lstart-1);
float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest);
if (!phy->args->equalizer_mode.compare("zf")) {
noise_estimate = 0;
}
/* Set decoder iterations */
// TODO: Add separate arg for pmch_max_its
if (phy->args->pdsch_max_its > 0) {
srslte_sch_set_max_noi(&ue_dl.pmch.dl_sch, phy->args->pdsch_max_its);
}
#ifdef LOG_EXECTIME
struct timeval t[3];
gettimeofday(&t[1], NULL);
#endif
bool ack = srslte_pmch_decode_multi(&ue_dl.pmch, &ue_dl.pmch_cfg, softbuffer, ue_dl.sf_symbols_m,
ue_dl.ce_m, noise_estimate, mbsfn_area_id, payload) == 0;
#ifdef LOG_EXECTIME
gettimeofday(&t[2], NULL);
get_time_interval(t);
snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec);
#endif
Info("PMCH: l_crb=%2d, tbs=%d, mcs=%d, crc=%s, snr=%.1f dB, n_iter=%d%s\n",
grant->nof_prb,
grant->mcs[0].tbs/8, grant->mcs[0].idx,
ack?"OK":"KO",
10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)),
srslte_pmch_last_noi(&ue_dl.pmch),
timestr);
//printf("tti=%d, cfo=%f\n", tti, cfo*15000);
//srslte_vec_save_file("pdsch", signal_buffer, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb));
// Store metrics
dl_metrics.mcs = grant->mcs[0].idx;
return ack;
} else {
Warning("Received grant for TBS=0\n");
}
} else {
Error("Error configuring DL grant\n");
}
return true;
}
bool phch_worker::decode_phich(bool *ack)
{
uint32_t I_lowest, n_dmrs;

View File

@ -354,6 +354,7 @@ uint32_t phy::get_current_tti()
return sf_recv.get_current_tti();
}
void phy::sr_send()
{
workers_common.sr_enabled = true;
@ -437,4 +438,40 @@ void phy::set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT* tdd)
memcpy(&config.common.tdd_cnfg, tdd, sizeof(LIBLTE_RRC_TDD_CONFIG_STRUCT));
}
void phy::set_config_mbsfn_sib2(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2)
{
if(sib2->mbsfn_subfr_cnfg_list_size > 1) {
Warning("SIB2 has %d MBSFN subframe configs - only 1 supported\n", sib2->mbsfn_subfr_cnfg_list_size);
}
if(sib2->mbsfn_subfr_cnfg_list_size > 0) {
memcpy(&config.mbsfn.mbsfn_subfr_cnfg, &sib2->mbsfn_subfr_cnfg_list[0], sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT));
workers_common.build_mch_table();
}
}
void phy::set_config_mbsfn_sib13(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13)
{
memcpy(&config.mbsfn.mbsfn_notification_cnfg, &sib13->mbsfn_notification_config, sizeof(LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT));
if(sib13->mbsfn_area_info_list_r9_size > 1) {
Warning("SIB13 has %d MBSFN area info elements - only 1 supported\n", sib13->mbsfn_area_info_list_r9_size);
}
if(sib13->mbsfn_area_info_list_r9_size > 0) {
memcpy(&config.mbsfn.mbsfn_area_info, &sib13->mbsfn_area_info_list_r9[0], sizeof(LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT));
workers_common.build_mcch_table();
}
}
void phy::set_config_mbsfn_mcch(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch)
{
memcpy(&config.mbsfn.mcch, mcch, sizeof(LIBLTE_RRC_MCCH_MSG_STRUCT));
mac->set_mbsfn_config(config.mbsfn.mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size);
workers_common.set_mch_period_stop(config.mbsfn.mcch.pmch_infolist_r9[0].pmch_config_r9.sf_alloc_end_r9);
workers_common.set_mcch();
}
void phy::set_mch_period_stop(uint32_t stop)
{
workers_common.set_mch_period_stop(stop);
}
}

View File

@ -208,11 +208,9 @@ bool ue::init(all_args_t *args_) {
srslte_nas_config_t nas_cfg(1, args->apn_name, args->apn_user, args->apn_pass); /* RB_ID_SRB1 */
nas.init(usim, &rrc, &gw, &nas_log, nas_cfg);
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */);
gw.set_netmask(args->expert.ip_netmask);
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, usim, &mac, &rrc_log);
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, usim, &gw, &mac, &rrc_log);
// Get current band from provided EARFCN
args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn);
args->rrc.nof_supported_bands = 1;
@ -323,9 +321,19 @@ bool ue::get_metrics(ue_metrics_t &m)
return false;
}
void ue::radio_overflow() {
phy.radio_overflow();
}
void ue::print_mbms()
{
rrc.print_mbms();
}
bool ue::mbms_service_start(uint32_t serv, uint32_t port)
{
return rrc.mbms_service_start(serv, port);
}
void ue::rf_msg(srslte_rf_error_t error)
{

View File

@ -59,6 +59,19 @@ void gw::init(pdcp_interface_gw *pdcp_, nas_interface_gw *nas_, srslte::log *gw_
gettimeofday(&metrics_time[1], NULL);
dl_tput_bytes = 0;
ul_tput_bytes = 0;
// MBSFN
mbsfn_sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (mbsfn_sock_fd < 0) {
gw_log->error("Failed to create MBSFN sink socket\n");
}
if (fcntl(mbsfn_sock_fd, F_SETFL, O_NONBLOCK)) {
gw_log->error("Failed to set non-blocking MBSFN sink socket\n");
}
mbsfn_sock_addr.sin_family = AF_INET;
mbsfn_sock_addr.sin_addr.s_addr =inet_addr("127.0.0.1");
bzero(mbsfn_ports, SRSLTE_N_MCH_LCIDS*sizeof(uint32_t));
}
void gw::stop()
@ -83,14 +96,15 @@ void gw::stop()
current_ip_addr = 0;
}
// TODO: tear down TUN device?
}
if (mbsfn_sock_fd) {
close(mbsfn_sock_fd);
}
}
void gw::get_metrics(gw_metrics_t &m)
{
gettimeofday(&metrics_time[2], NULL);
get_time_interval(metrics_time);
double secs = (double) metrics_time[0].tv_sec+metrics_time[0].tv_usec*1e-6;
@ -105,7 +119,8 @@ void gw::get_metrics(gw_metrics_t &m)
ul_tput_bytes = 0;
}
void gw::set_netmask(std::string netmask) {
void gw::set_netmask(std::string netmask)
{
default_netmask = false;
this->netmask = netmask;
}
@ -116,8 +131,7 @@ void gw::set_netmask(std::string netmask) {
*******************************************************************************/
void gw::write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu)
{
gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX PDU");
gw_log->info("RX PDU. Stack latency: %ld us\n", pdu->get_latency_us());
gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX PDU. Stack latency: %ld us\n", pdu->get_latency_us());
dl_tput_bytes += pdu->N_bytes;
if(!if_up)
{
@ -132,6 +146,46 @@ void gw::write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu)
pool->deallocate(pdu);
}
void gw::write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu)
{
if(pdu->N_bytes>2)
{
gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX MCH PDU (%d B). Stack latency: %ld us\n", pdu->N_bytes, pdu->get_latency_us());
dl_tput_bytes += pdu->N_bytes;
//Hack to drop initial 2 bytes
pdu->msg +=2;
pdu->N_bytes-=2;
struct in_addr dst_addr;
memcpy(&dst_addr.s_addr, &pdu->msg[16],4);
if(!if_up)
{
gw_log->warning("TUN/TAP not up - dropping gw RX message\n");
}else{
int n = write(tun_fd, pdu->msg, pdu->N_bytes);
if(n > 0 && (pdu->N_bytes != (uint32_t)n))
{
gw_log->warning("DL TUN/TAP write failure\n");
}
}
/*
// Strip IP/UDP header
pdu->msg += 28;
pdu->N_bytes -= 28;
if(mbsfn_sock_fd) {
if(lcid > 0 && lcid < SRSLTE_N_MCH_LCIDS) {
mbsfn_sock_addr.sin_port = htons(mbsfn_ports[lcid]);
if(sendto(mbsfn_sock_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&mbsfn_sock_addr, sizeof(struct sockaddr_in))<0) {
gw_log->error("Failed to send MCH PDU to port %d\n", mbsfn_ports[lcid]);
}
}
}*/
}
pool->deallocate(pdu);
}
/*******************************************************************************
NAS interface
*******************************************************************************/
@ -234,6 +288,19 @@ srslte::error_t gw::init_if(char *err_str)
return(srslte::ERROR_NONE);
}
/*******************************************************************************
RRC interface
*******************************************************************************/
void gw::add_mch_port(uint32_t lcid, uint32_t port)
{
if(lcid > 0 && lcid < SRSLTE_N_MCH_LCIDS) {
mbsfn_ports[lcid] = port;
}
}
/********************/
/* GW Receive */
/********************/

View File

@ -80,6 +80,67 @@ void rrc::liblte_rrc_log(char *str) {
printf("[ASN]: %s\n", str);
}
}
void rrc::print_mbms()
{
if(rrc_log) {
if(serving_cell->has_mcch) {
LIBLTE_RRC_MCCH_MSG_STRUCT msg;
memcpy(&msg, &serving_cell->mcch, sizeof(LIBLTE_RRC_MCCH_MSG_STRUCT));
std::stringstream ss;
for(uint32_t i=0;i<msg.pmch_infolist_r9_size; i++){
ss << "PMCH: " << i << std::endl;
LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch = &msg.pmch_infolist_r9[i];
for(uint32_t j=0;j<pmch->mbms_sessioninfolist_r9_size; j++) {
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *sess = &pmch->mbms_sessioninfolist_r9[j];
ss << " Service ID: " << sess->tmgi_r9.serviceid_r9;
if(sess->sessionid_r9_present) {
ss << ", Session ID: " << (uint32_t)sess->sessionid_r9;
}
if(sess->tmgi_r9.plmn_id_explicit) {
std::string tmp;
if(mcc_to_string(sess->tmgi_r9.plmn_id_r9.mcc, &tmp)) {
ss << ", MCC: " << tmp;
}
if(mnc_to_string(sess->tmgi_r9.plmn_id_r9.mnc, &tmp)) {
ss << ", MNC: " << tmp;
}
} else {
ss << ", PLMN index: " << (uint32_t)sess->tmgi_r9.plmn_index_r9;
}
ss << ", LCID: " << (uint32_t)sess->logicalchannelid_r9;
ss << std::endl;
}
}
//rrc_log->console(ss.str());
std::cout << ss.str();
} else {
rrc_log->console("MCCH not available for current cell\n");
}
}
}
bool rrc::mbms_service_start(uint32_t serv, uint32_t port)
{
bool ret = false;
if(serving_cell->has_mcch) {
LIBLTE_RRC_MCCH_MSG_STRUCT msg;
memcpy(&msg, &serving_cell->mcch, sizeof(LIBLTE_RRC_MCCH_MSG_STRUCT));
for(uint32_t i=0;i<msg.pmch_infolist_r9_size; i++){
LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch = &msg.pmch_infolist_r9[i];
for(uint32_t j=0;j<pmch->mbms_sessioninfolist_r9_size; j++) {
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *sess = &pmch->mbms_sessioninfolist_r9[j];
if(serv == sess->tmgi_r9.serviceid_r9) {
rrc_log->console("MBMS service started. Service id:%d, port: %d\n", serv, port);
ret = true;
add_mrb(sess->logicalchannelid_r9, port);
}
}
}
}
return ret;
}
void rrc::init(phy_interface_rrc *phy_,
mac_interface_rrc *mac_,
@ -87,6 +148,7 @@ void rrc::init(phy_interface_rrc *phy_,
pdcp_interface_rrc *pdcp_,
nas_interface_rrc *nas_,
usim_interface_rrc *usim_,
gw_interface_rrc *gw_,
mac_interface_timers *mac_timers_,
srslte::log *rrc_log_) {
pool = byte_buffer_pool::get_instance();
@ -96,6 +158,7 @@ void rrc::init(phy_interface_rrc *phy_,
pdcp = pdcp_;
nas = nas_;
usim = usim_;
gw = gw_;
rrc_log = rrc_log_;
// Use MAC timers
@ -474,6 +537,7 @@ bool rrc::configure_serving_cell() {
rrc_log->error("Trying to configure Cell while not camping on it\n");
return false;
}
serving_cell->has_mcch = false;
// Apply configurations if already retrieved SIB2
if (serving_cell->has_sib2()) {
apply_sib2_configs(serving_cell->sib2ptr());
@ -490,6 +554,9 @@ bool rrc::configure_serving_cell() {
}
} else {
rrc_log->info("Cell has SIB%d\n", i+1);
if(i+1 == 13){
apply_sib13_configs(serving_cell->sib13ptr());
}
}
}
return true;
@ -1759,7 +1826,23 @@ void rrc::process_pcch(byte_buffer_t *pdu) {
}
void rrc::write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu)
{
if (pdu->N_bytes > 0 && pdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BITS) {
rrc_log->info_hex(pdu->msg, pdu->N_bytes, "MCH message received %d bytes on lcid:%d\n", pdu->N_bytes, lcid);
rrc_log->info("MCH message Stack latency: %ld us\n", pdu->get_latency_us());
//TODO: handle MCCH notifications and update MCCH
if(0 == lcid && !serving_cell->has_mcch) {
srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8);
bit_buf.N_bits = pdu->N_bytes * 8;
liblte_rrc_unpack_mcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &serving_cell->mcch);
serving_cell->has_mcch = true;
phy->set_config_mbsfn_mcch(&serving_cell->mcch);
}
pool->deallocate(pdu);
}
}
@ -2134,6 +2217,9 @@ void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) {
// for(uint8_t i=0;i<sib2->mbsfn_subfr_cnfg_list_size;i++) {
// memcpy(&cfg.mbsfn_subfr_cnfg_list[i], &sib2->mbsfn_subfr_cnfg_list[i], sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT));
// }
// Set MBSFN configs
phy->set_config_mbsfn_sib2(sib2);
mac->set_config(&cfg);
@ -2198,6 +2284,12 @@ void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) {
}
void rrc::apply_sib13_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13)
{
phy->set_config_mbsfn_sib13(&serving_cell->sib13);
add_mrb(0, 0); // Add MRB0
}
// Go through all information elements and apply defaults (9.2.4) if not defined
void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults) {
// Get current configuration
@ -2585,6 +2677,14 @@ void rrc::release_drb(uint8_t lcid) {
// TODO
}
void rrc::add_mrb(uint32_t lcid, uint32_t port)
{
gw->add_mch_port(lcid, port);
rlc->add_bearer_mrb(lcid);
mac->mch_start_rx(lcid);
rrc_log->info("Added MRB bearer for lcid:%d\n", lcid);
}
// PHY CONFIG DEDICATED Defaults (3GPP 36.331 v10 9.2.4)
void rrc::set_phy_default_pucch_srs() {

View File

@ -418,6 +418,7 @@ public:
}
void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) {}
void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) {}
private:
LIBLTE_BIT_MSG_STRUCT bit_msg;

View File

@ -77,6 +77,7 @@ public:
void write_pdu_bcch_bch(byte_buffer_t *pdu) {}
void write_pdu_bcch_dlsch(byte_buffer_t *pdu) {}
void write_pdu_pcch(byte_buffer_t *pdu) {}
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu) {}
std::string get_rb_name(uint32_t lcid) { return std::string("lcid"); }
};
@ -126,6 +127,7 @@ class gw_dummy : public gw_interface_nas, public gw_interface_pdcp
{
error_t setup_if_addr(uint32_t ip_addr, char *err_str) { return ERROR_NONE; }
void write_pdu(uint32_t lcid, byte_buffer_t *pdu) {}
void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu) {}
};
}

Some files were not shown because too many files have changed in this diff Show More