mirror of https://github.com/PentHertz/srsLTE.git
Merge branch 'embms_merge_final' into next
This commit is contained in:
commit
cb15dee3d4
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -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})
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(){}
|
||||
|
|
|
@ -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(){}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
};
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 ***************/
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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})
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
/********************/
|
||||
|
|
|
@ -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() {
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue