diff --git a/CHANGELOG b/CHANGELOG index 7dfff7d89..2acd0c4a3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,11 @@ Change Log for Releases ============================== +## 17.09 + * Added MIMO 2x2 in the PHY layer and srsUE (i.e. TM3/TM4) + * eMBMS support in the PHY layer + * Many bug-fixes and improved stability and performance in srsUE/srsENB + ## 002.000.000 * Added fully functional srsENB to srsLTE code * Merged srsUE code into srsLTE and reestructured PHY code diff --git a/CMakeLists.txt b/CMakeLists.txt index c4904e5f6..d72bb5fef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,7 +120,7 @@ else(POLARSSL_FOUND) endif(BUILD_STATIC) add_definitions(-DHAVE_MBEDTLS) else(MBEDTLS_FOUND) - message(FATAL_ERROR "Either polarssl or mbedtls is required to compile srsLTE") + message(FATAL_ERROR "Either PolarSSL or mbedTLS are required to build srsLTE") endif (MBEDTLS_FOUND) endif(POLARSSL_FOUND) diff --git a/README.md b/README.md index f7c699ed3..ad87ad149 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,13 @@ srsLTE is released under the AGPLv3 license and uses software from the OpenLTE p Common Features --------------- - * LTE Release 8 compliant + * LTE Release 8 compliant (with selected features of Release 9) * FDD configuration * Tested bandwidths: 1.4, 3, 5, 10, 15 and 20 MHz - * Transmission mode 1 (single antenna) and 2 (transmit diversity) + * Transmission mode 1 (single antenna), 2 (transmit diversity), 3 (CCD) and 4 (closed-loop spatial multiplexing) * Frequency-based ZF and MMSE equalizer - * Highly optimized Turbo Decoder available in Intel SSE4.1/AVX (+100 Mbps) and standard C (+25 Mbps) + * Evolved multimedia broadcast and multicast service (eMBMS) + * Highly optimized Turbo Decoder available in Intel SSE4.1/AVX2 (+100 Mbps) and standard C (+25 Mbps) * MAC, RLC, PDCP, RRC, NAS, S1AP and GW layers * Detailed log system with per-layer log levels and hex dumps * MAC layer wireshark packet capture @@ -33,6 +34,7 @@ srsUE Features * Cell search and synchronization procedure for the UE * Soft USIM supporting Milenage and XOR authentication * Virtual network interface *tun_srsue* created upon network attach + * +100 Mbps DL in 20 MHz MIMO TM4 configuration in i7 Quad-Core CPU. * 75 Mbps DL in 20 MHz SISO configuration in i7 Quad-Core CPU. * 36 Mbps DL in 10 MHz SISO configuration in i5 Dual-Core CPU. @@ -55,6 +57,8 @@ srsENB has been tested and validated with the following handsets: * LG Nexus 5 * LG Nexus 4 * Motorola Moto G4 plus + * Huawei P9/P9lite + * Huawei dongles: E3276 and E398 Hardware -------- @@ -65,13 +69,14 @@ We have tested the following hardware: * USRP B210 * USRP X300 * bladeRF - * limeSDR + * limeSDR (currently, only the PHY-layer examples, i.e., pdsch_enodeb/ue are supported) Build Instructions ------------------ * Mandatory requirements: * Common: + * cmake https://cmake.org/ * libfftw http://www.fftw.org/ * PolarSSL/mbedTLS https://tls.mbed.org * srsUE: @@ -83,7 +88,7 @@ Build Instructions For example, on Ubuntu 17.04, one can install the required libraries with: ``` -sudo apt-get install libfftw3-dev libmbedtls-dev libboost-all-dev libconfig++-dev libsctp-dev +sudo apt-get install cmake libfftw3-dev libmbedtls-dev libboost-all-dev libconfig++-dev libsctp-dev ``` Note that depending on your flavor and version of Linux, the actual package names may be different. diff --git a/cmake/modules/FindUHD.cmake b/cmake/modules/FindUHD.cmake index a5b8834cd..0c0eb742e 100644 --- a/cmake/modules/FindUHD.cmake +++ b/cmake/modules/FindUHD.cmake @@ -16,6 +16,7 @@ FIND_LIBRARY( HINTS $ENV{UHD_DIR}/lib PATHS /usr/local/lib /usr/lib + /usr/lib/x86_64-linux-gnu /usr/local/lib64 /usr/local/lib32 ) diff --git a/cmake/modules/SRSLTEVersion.cmake b/cmake/modules/SRSLTEVersion.cmake index d2ab204f5..b52e47fe5 100644 --- a/cmake/modules/SRSLTEVersion.cmake +++ b/cmake/modules/SRSLTEVersion.cmake @@ -18,7 +18,7 @@ # and at http://www.gnu.org/licenses/. # -SET(SRSLTE_VERSION_MAJOR 002) -SET(SRSLTE_VERSION_MINOR 000) -SET(SRSLTE_VERSION_PATCH 000) +SET(SRSLTE_VERSION_MAJOR 17) +SET(SRSLTE_VERSION_MINOR 9) +SET(SRSLTE_VERSION_PATCH 0) SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}") diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index cb6a9b78d..37796682f 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -241,19 +241,31 @@ int main(int argc, char **argv) { srslte_rf_stop_rx_stream(&rf); srslte_rf_flush_buffer(&rf); - if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, 1, (void*) &rf)) { + if (srslte_ue_sync_init_multi(&ue_sync, cell.nof_prb, cell.id==1000, srslte_rf_recv_wrapper, 1, (void*) &rf)) { fprintf(stderr, "Error initiating ue_sync\n"); return -1; } - if (srslte_ue_dl_init(&ue_dl, cell, 1)) { + if (srslte_ue_sync_set_cell(&ue_sync, cell)) { + fprintf(stderr, "Error initiating ue_sync\n"); + return -1; + } + if (srslte_ue_dl_init(&ue_dl, cell.nof_prb, 1)) { + fprintf(stderr, "Error initiating UE downlink processing module\n"); + return -1; + } + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { fprintf(stderr, "Error initiating UE downlink processing module\n"); return -1; } - if (srslte_ue_mib_init(&ue_mib, cell)) { + if (srslte_ue_mib_init(&ue_mib, cell.nof_prb)) { fprintf(stderr, "Error initaiting UE MIB decoder\n"); return -1; } - + if (srslte_ue_mib_set_cell(&ue_mib, cell)) { + fprintf(stderr, "Error initaiting UE MIB decoder\n"); + return -1; + } + /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ srslte_ue_dl_set_rnti(&ue_dl, SRSLTE_SIRNTI); @@ -264,11 +276,15 @@ int main(int argc, char **argv) { fprintf(stderr, "Error initiating FFT\n"); return -1; } - if (srslte_chest_dl_init(&chest, cell)) { + if (srslte_chest_dl_init(&chest, cell.nof_prb)) { fprintf(stderr, "Error initiating channel estimator\n"); return -1; } - + if (srslte_chest_dl_set_cell(&chest, cell)) { + fprintf(stderr, "Error initiating channel estimator\n"); + return -1; + } + int sf_re = SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); cf_t *sf_symbols = srslte_vec_malloc(sf_re * sizeof(cf_t)); @@ -319,10 +335,9 @@ int main(int argc, char **argv) { fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); return -1; } else if (n == 0) { - printf("CFO: %+6.4f kHz, SFO: %+6.4f kHz, NOI: %.2f, PDCCH-Det: %.3f\r", + printf("CFO: %+6.4f kHz, SFO: %+6.4f kHz, PDCCH-Det: %.3f\r", srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_sfo(&ue_sync)/1000, - srslte_pdsch_average_noi(&ue_dl.pdsch), - (float) ue_dl.nof_detected/nof_trials); + (float) ue_dl.nof_detected/nof_trials); nof_trials++; } else { printf("Decoded SIB1. Payload: "); diff --git a/lib/examples/cell_search.c b/lib/examples/cell_search.c index 8ab560e0c..281e3d102 100644 --- a/lib/examples/cell_search.c +++ b/lib/examples/cell_search.c @@ -188,6 +188,18 @@ int main(int argc, char **argv) { sigprocmask(SIG_UNBLOCK, &sigset, NULL); signal(SIGINT, sig_int_handler); + if (srslte_ue_cellsearch_init_multi(&cs, cell_detect_config.max_frames_pss, srslte_rf_recv_wrapper, 1, (void*) &rf)) { + fprintf(stderr, "Error initiating UE cell detect\n"); + exit(-1); + } + + if (cell_detect_config.max_frames_pss) { + srslte_ue_cellsearch_set_nof_valid_frames(&cs, cell_detect_config.nof_valid_pss_frames); + } + if (cell_detect_config.init_agc) { + srslte_ue_sync_start_agc(&cs.ue_sync, srslte_rf_set_rx_gain_wrapper, cell_detect_config.init_agc); + } + for (freq=0;freq #include #include +#include #include +#include #include #include #include @@ -38,10 +40,11 @@ #define UE_CRNTI 0x1234 - +#define M_CRNTI 0xFFFD #ifndef DISABLE_RF #include "srslte/phy/rf/rf.h" +#include "srslte/phy/common/phy_common.h" srslte_rf_t rf; #else #warning Compiling pdsch_ue with no RF support @@ -55,52 +58,67 @@ char *output_file_name = NULL; #define DOWN_KEY 66 srslte_cell_t cell = { - 25, // nof_prb - 1, // nof_ports - 0, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_NORM, // PHICH length - SRSLTE_PHICH_R_1 // PHICH resources + 25, // nof_prb + 1, // nof_ports + 0, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1 // PHICH resources }; +uint16_t c = -1; + int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device -uint32_t cfi = 1; +uint32_t cfi = 2; uint32_t mcs_idx = 1, last_mcs_idx = 1; int nof_frames = -1; + + char mimo_type_str[32] = "single"; uint32_t nof_tb = 1; uint32_t multiplex_pmi = 0; uint32_t multiplex_nof_layers = 1; +int mbsfn_area_id = -1; char *rf_args = ""; float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000; bool null_file_sink=false; srslte_filesink_t fsink; srslte_ofdm_t ifft; +srslte_ofdm_t ifft_mbsfn; srslte_pbch_t pbch; srslte_pcfich_t pcfich; srslte_pdcch_t pdcch; srslte_pdsch_t pdsch; -srslte_pdsch_cfg_t pdsch_cfg; +srslte_pdsch_cfg_t pdsch_cfg; +srslte_pmch_t pmch; +srslte_pdsch_cfg_t pmch_cfg; srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_regs_t regs; -srslte_ra_dl_dci_t ra_dl; +srslte_ra_dl_dci_t ra_dl; int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0}; cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL}; + + int sf_n_re, sf_n_samples; -pthread_t net_thread; +pthread_t net_thread; void *net_thread_fnc(void *arg); sem_t net_sem; bool net_packet_ready = false; srslte_netsource_t net_source; srslte_netsink_t net_sink; + int prbset_num = 1, last_prbset_num = 1; int prbset_orig = 0; +//#define DATA_BUFF_SZ 1024*128 +//uint8_t data[8*DATA_BUFF_SZ], data2[DATA_BUFF_SZ]; +//uint8_t data_tmp[DATA_BUFF_SZ]; + #define DATA_BUFF_SZ 1024*1024 uint8_t *data[2], data2[DATA_BUFF_SZ]; @@ -121,6 +139,7 @@ void usage(char *prog) { printf("\t-n number of frames [Default %d]\n", nof_frames); printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-M MBSFN area id [Default %d]\n", mbsfn_area_id); 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); @@ -132,7 +151,8 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "aglfmoncpvutxbw")) != -1) { + while ((opt = getopt(argc, argv, "aglfmoncpvutxbwM")) != -1) { + switch (opt) { case 'a': rf_args = argv[optind]; @@ -173,6 +193,9 @@ void parse_args(int argc, char **argv) { case 'w': multiplex_nof_layers = (uint32_t) atoi(argv[optind]); break; + case 'M': + mbsfn_area_id = atoi(argv[optind]); + break; case 'v': srslte_verbose++; break; @@ -188,7 +211,7 @@ void parse_args(int argc, char **argv) { } #endif } - + void base_init() { int i; @@ -245,6 +268,7 @@ void base_init() { bzero(output_buffer[i], sizeof(cf_t) * sf_n_samples); } + /* open file or USRP */ if (output_file_name) { if (strcmp(output_file_name, "NULL")) { @@ -291,18 +315,36 @@ void base_init() { fprintf(stderr, "Error creating iFFT object\n"); exit(-1); } + if (srslte_ofdm_tx_init_mbsfn(&ifft_mbsfn, SRSLTE_CP_EXT, cell.nof_prb)) { + fprintf(stderr, "Error creating iFFT object\n"); + exit(-1); + } + srslte_ofdm_set_non_mbsfn_region(&ifft_mbsfn, 2); + srslte_ofdm_set_normalize(&ifft_mbsfn, true); srslte_ofdm_set_normalize(&ifft, true); - if (srslte_pbch_init(&pbch, cell)) { + + + if (srslte_pbch_init(&pbch)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } + if (srslte_pbch_set_cell(&pbch, cell)) { + fprintf(stderr, "Error creating PBCH object\n"); + exit(-1); + } + + + if (srslte_regs_init(®s, cell)) { fprintf(stderr, "Error initiating regs\n"); exit(-1); } - - if (srslte_pcfich_init(&pcfich, ®s, cell)) { + if (srslte_pcfich_init(&pcfich, 1)) { + fprintf(stderr, "Error creating PBCH object\n"); + exit(-1); + } + if (srslte_pcfich_set_cell(&pcfich, ®s, cell)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } @@ -312,19 +354,34 @@ void base_init() { exit(-1); } - if (srslte_pdcch_init_tx(&pdcch, ®s, cell)) { + if (srslte_pdcch_init_enb(&pdcch, cell.nof_prb)) { + fprintf(stderr, "Error creating PDCCH object\n"); + exit(-1); + } + if (srslte_pdcch_set_cell(&pdcch, ®s, cell)) { fprintf(stderr, "Error creating PDCCH object\n"); exit(-1); } - bzero(&pdsch, sizeof(srslte_pdsch_t)); - if (srslte_pdsch_init_tx(&pdsch, cell)) { + if (srslte_pdsch_init_enb(&pdsch, cell.nof_prb)) { + fprintf(stderr, "Error creating PDSCH object\n"); + exit(-1); + } + if (srslte_pdsch_set_cell(&pdsch, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); exit(-1); } srslte_pdsch_set_rnti(&pdsch, UE_CRNTI); + + if(mbsfn_area_id > -1){ + if (srslte_pmch_init(&pmch, cell.nof_prb)) { + fprintf(stderr, "Error creating PMCH object\n"); + } + srslte_pmch_set_area_id(&pmch, mbsfn_area_id); + } + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { softbuffers[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1); if (!softbuffers[i]) { @@ -339,6 +396,7 @@ void base_init() { } } + void base_free() { int i; for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { @@ -351,8 +409,12 @@ void base_free() { srslte_pdcch_free(&pdcch); srslte_regs_free(®s); srslte_pbch_free(&pbch); - + if(mbsfn_area_id > -1){ + srslte_pmch_free(&pmch); + } + srslte_ofdm_tx_free(&ifft_mbsfn); srslte_ofdm_tx_free(&ifft); + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { if (data[i]) { @@ -466,7 +528,7 @@ int update_radl() { srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &dummy_grant); srslte_ra_dl_grant_to_nbits(&dummy_grant, cfi, cell, 0, &dummy_nbits); srslte_ra_dl_grant_fprint(stdout, &dummy_grant); - + dummy_grant.sf_type = SRSLTE_SF_NORM; if (pdsch_cfg.mimo_type != SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) { printf("\nTransmission mode key table:\n"); printf(" Mode | 1TB | 2TB |\n"); @@ -581,6 +643,7 @@ int update_control() { } } + /** Function run in a separate thread to receive UDP data */ void *net_thread_fnc(void *arg) { int n; @@ -618,6 +681,7 @@ void *net_thread_fnc(void *arg) { return NULL; } + int main(int argc, char **argv) { int nf=0, sf_idx=0, N_id_2=0; cf_t pss_signal[SRSLTE_PSS_LEN]; @@ -630,7 +694,8 @@ int main(int argc, char **argv) { srslte_dci_msg_t dci_msg; srslte_dci_location_t locations[SRSLTE_NSUBFRAMES_X_FRAME][30]; uint32_t sfn; - srslte_chest_dl_t est; + srslte_refsignal_t csr_refs; + srslte_refsignal_t mbsfn_refs; #ifdef DISABLE_RF if (argc < 3) { @@ -659,17 +724,31 @@ int main(int argc, char **argv) { srslte_pss_generate(pss_signal, N_id_2); srslte_sss_generate(sss_signal0, sss_signal5, cell.id); - /* Generate CRS signals */ - if (srslte_chest_dl_init(&est, cell)) { + + /* Generate reference signals */ + if(srslte_refsignal_cs_init(&csr_refs, cell.nof_prb)) { fprintf(stderr, "Error initializing equalizer\n"); exit(-1); } - + if(mbsfn_area_id > -1) { + if(srslte_refsignal_mbsfn_init(&mbsfn_refs, cell, mbsfn_area_id)) { + fprintf(stderr, "Error initializing equalizer\n"); + exit(-1); + } + } + + if(srslte_refsignal_cs_set_cell(&csr_refs, cell)){ + fprintf(stderr, "Error setting cell\n"); + exit(-1); + } + + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { sf_symbols[i] = sf_buffer[i%cell.nof_ports]; slot1_symbols[i] = &sf_buffer[i%cell.nof_ports][SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)]; } + #ifndef DISABLE_RF @@ -718,48 +797,51 @@ int main(int argc, char **argv) { /* Initiate valid DCI locations */ for (i=0;i -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++) { + srslte_refsignal_cs_put_sf(cell, (uint32_t) i, csr_refs.pilots[i / 2][sf_idx], sf_symbols[i]); + } } - + srslte_pbch_mib_pack(&cell, sfn, bch_payload); if (sf_idx == 0) { srslte_pbch_encode(&pbch, bch_payload, slot1_symbols, nf%4); } - srslte_pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx); + srslte_pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx); /* Update DL resource allocation from control port */ if (update_control(sf_idx)) { @@ -774,9 +856,11 @@ int main(int argc, char **argv) { } } else { INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs); - for (uint32_t tb = 0; tb < pdsch_cfg.grant.nof_tb; tb++) { - for (i = 0; i < pdsch_cfg.grant.mcs[tb].tbs / 8; i++) { - data[tb][i] = (uint8_t) rand(); + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (pdsch_cfg.grant.tb_en[tb]) { + for (i = 0; i < pdsch_cfg.grant.mcs[tb].tbs / 8; i++) { + data[tb][i] = (uint8_t) rand(); + } } } /* Uncomment this to transmit on sf 0 and 5 only */ @@ -785,84 +869,134 @@ int main(int argc, char **argv) { } else { send_data = false; } - } + } if (send_data) { - srslte_dci_format_t dci_format; - switch(pdsch_cfg.mimo_type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - dci_format = SRSLTE_DCI_FORMAT1; - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - case SRSLTE_MIMO_TYPE_CDD: - dci_format = SRSLTE_DCI_FORMAT2A; - break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - dci_format = SRSLTE_DCI_FORMAT2; - if (multiplex_nof_layers == 1) { - ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1); - } else { - ra_dl.pinfo = (uint8_t) multiplex_pmi; + if(sf_idx != 1 || mbsfn_area_id < 0) { // PDCCH + PDSCH + srslte_dci_format_t dci_format; + switch(pdsch_cfg.mimo_type) { + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + dci_format = SRSLTE_DCI_FORMAT1; + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + case SRSLTE_MIMO_TYPE_CDD: + dci_format = SRSLTE_DCI_FORMAT2A; + break; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + dci_format = SRSLTE_DCI_FORMAT2; + if (multiplex_nof_layers == 1) { + ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1); + } else { + ra_dl.pinfo = (uint8_t) multiplex_pmi; + } + break; + default: + fprintf(stderr, "Wrong MIMO configuration\n"); + exit(SRSLTE_ERROR); + } + /* 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, dci_format, &dci_msg, cell.nof_prb, cell.nof_ports, false); + if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], UE_CRNTI, sf_symbols, sf_idx, cfi)) { + fprintf(stderr, "Error encoding DCI message\n"); + exit(-1); + } + + /* Configure pdsch_cfg parameters */ + srslte_ra_dl_grant_t grant; + srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant); + if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) { + fprintf(stderr, "Error configuring PDSCH\n"); + exit(-1); + } + + /* Encode PDSCH */ + if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, sf_symbols)) { + fprintf(stderr, "Error encoding PDSCH\n"); + exit(-1); + } + if (net_port > 0 && net_packet_ready) { + if (null_file_sink) { + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + srslte_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.mcs[tb].tbs); + if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.mcs[tb].tbs - 1) / 8) < 0) { + fprintf(stderr, "Error sending data through UDP socket\n"); + } + } } - break; - default: - fprintf(stderr, "Wrong MIMO configuration\n"); - exit(SRSLTE_ERROR); - } - /* 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, dci_format, &dci_msg, cell.nof_prb, cell.nof_ports, false); - if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], UE_CRNTI, sf_symbols, sf_idx, cfi)) { - fprintf(stderr, "Error encoding DCI message\n"); - exit(-1); - } + 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); + } + /* Configure pmch_cfg parameters */ + srslte_ra_dl_grant_t grant; + grant.nof_tb = 1; + 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); + for(int i = 0; i < 2; i++){ + for(int j = 0; j < grant.nof_prb; j++){ + grant.prb_idx[i][j] = true; + } + } + - /* Configure pdsch_cfg parameters */ - srslte_ra_dl_grant_t grant; - srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant); - if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) { - fprintf(stderr, "Error configuring PDSCH\n"); - exit(-1); - } - - /* Encode PDSCH */ - if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, sf_symbols)) { - fprintf(stderr, "Error encoding PDSCH\n"); - exit(-1); - } - if (net_port > 0 && net_packet_ready) { - if (null_file_sink) { - for (uint32_t tb = 0; tb < pdsch_cfg.grant.nof_tb; tb++) { - srslte_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.mcs[tb].tbs); - if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.mcs[tb].tbs - 1) / 8) < 0) { + 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)) { + fprintf(stderr, "Error encoding PDSCH\n"); + exit(-1); + } + if (net_port > 0 && net_packet_ready) { + if (null_file_sink) { + srslte_bit_pack_vector(data[0], data_tmp, pmch_cfg.grant.mcs[0].tbs); + if (srslte_netsink_write(&net_sink, data_tmp, 1+(pmch_cfg.grant.mcs[0].tbs-1)/8) < 0) { fprintf(stderr, "Error sending data through UDP socket\n"); } } + net_packet_ready = false; + sem_post(&net_sem); } - net_packet_ready = false; - sem_post(&net_sem); } } - + /* Transform to OFDM symbols */ - for (i = 0; i < cell.nof_ports; i++) { - srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]); + if(sf_idx != 1 || mbsfn_area_id < 0){ + for (i = 0; i < cell.nof_ports; i++) { + srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]); + } + }else{ + srslte_ofdm_tx_sf(&ifft_mbsfn, sf_buffer[0], output_buffer[0]); } - + /* send to file or usrp */ if (output_file_name) { if (!null_file_sink) { - srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports); + srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports); } usleep(1000); } else { #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_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false); - start_of_burst=false; + 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_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false); + start_of_burst=false; #endif } } diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 2ace49d6d..9d7282cdd 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -36,10 +36,8 @@ #include #include #include -#include -#include -#include - +#include +#include "srslte/phy/io/filesink.h" #include "srslte/srslte.h" #define ENABLE_AGC_DEFAULT @@ -69,7 +67,7 @@ sem_t plot_sem; uint32_t plot_sf_idx=0; bool plot_track = true; #endif - +char *output_file_name; #define PRINT_CHANGE_SCHEDULIGN //#define CORRECT_SAMPLE_OFFSET @@ -101,6 +99,8 @@ typedef struct { int net_port_signal; char *net_address_signal; int decimate; + int32_t mbsfn_area_id; + uint8_t non_mbsfn_region; int verbose; }prog_args_t; @@ -132,10 +132,12 @@ void args_default(prog_args_t *args) { args->net_address_signal = "127.0.0.1"; args->decimate = 0; args->cpu_affinity = -1; + args->mbsfn_area_id = -1; + args->non_mbsfn_region = 2; } void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [agpPoOcildDnruv] -f rx_frequency (in Hz) | -i input_file\n", prog); + printf("Usage: %s [agpPoOcildDnruMNv] -f rx_frequency (in Hz) | -i input_file\n", prog); #ifndef DISABLE_RF printf("\t-a RF args [Default %s]\n", args->rf_args); printf("\t-A Number of RX antennas [Default %d]\n", args->rf_nof_rx_ant); @@ -169,13 +171,15 @@ void usage(prog_args_t *args, char *prog) { printf("\t-S remote UDP address to send input signal [Default %s]\n", args->net_address_signal); printf("\t-u remote TCP port to send data (-1 does nothing with it) [Default %d]\n", args->net_port); printf("\t-U remote TCP address to send data [Default %s]\n", args->net_address); + printf("\t-M MBSFN area id [Default %d]\n", args->mbsfn_area_id); + printf("\t-N Non-MBSFN region [Default %d]\n", args->non_mbsfn_region); printf("\t-v [set srslte_verbose to debug, default none]\n"); } void parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); - while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZy")) != -1) { + while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZyWMN")) != -1) { switch (opt) { case 'i': args->input_file_name = argv[optind]; @@ -250,6 +254,15 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'y': args->cpu_affinity = atoi(argv[optind]); break; + case 'W': + output_file_name = argv[optind]; + break; + case 'M': + args->mbsfn_area_id = atoi(argv[optind]); + break; + case 'N': + args->non_mbsfn_region = atoi(argv[optind]); + break; default: usage(args, argv[0]); exit(-1); @@ -278,6 +291,7 @@ void sig_int_handler(int signo) cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}; + #ifndef DISABLE_RF int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); @@ -303,9 +317,9 @@ srslte_ue_sync_t ue_sync; prog_args_t prog_args; uint32_t sfn = 0; // system frame number -srslte_netsink_t net_sink, net_sink_signal; - +srslte_netsink_t net_sink, net_sink_signal; /* Useful macros for printing lines which will disappear */ + #define PRINT_LINE_INIT() int this_nof_lines = 0; static int prev_nof_lines = 0 #define PRINT_LINE(_fmt, ...) printf("\033[K" _fmt "\n", ##__VA_ARGS__); this_nof_lines++ #define PRINT_LINE_RESET_CURSOR() printf("\033[%dA", this_nof_lines); prev_nof_lines = this_nof_lines @@ -317,6 +331,7 @@ int main(int argc, char **argv) { srslte_cell_t cell; int64_t sf_cnt; srslte_ue_mib_t ue_mib; + #ifndef DISABLE_RF srslte_rf_t rf; #endif @@ -324,7 +339,7 @@ int main(int argc, char **argv) { uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; int sfn_offset; float cfo = 0; - + parse_args(&prog_args, argc, argv); for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) { @@ -335,6 +350,7 @@ int main(int argc, char **argv) { } } + if(prog_args.cpu_affinity > -1) { cpu_set_t cpuset; @@ -403,6 +419,7 @@ int main(int argc, char **argv) { srslte_rf_set_rx_freq(&rf, prog_args.rf_freq + prog_args.file_offset_freq); srslte_rf_rx_wait_lo_locked(&rf); + uint32_t ntrial=0; do { ret = rf_search_and_decode_mib(&rf, prog_args.rf_nof_rx_ant, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo); @@ -455,7 +472,7 @@ int main(int argc, char **argv) { cell.nof_ports = prog_args.file_nof_ports; cell.nof_prb = prog_args.file_nof_prb; - if (srslte_ue_sync_init_file_multi(&ue_sync, prog_args.file_nof_prb, + if (srslte_ue_sync_init_file_multi(&ue_sync, prog_args.file_nof_prb, prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq, prog_args.rf_nof_rx_ant)) { fprintf(stderr, "Error initiating ue_sync\n"); exit(-1); @@ -475,23 +492,42 @@ int main(int argc, char **argv) { //ue_sync.decimate = prog_args.decimate; } } - if (srslte_ue_sync_init_multi_decim(&ue_sync, cell, srslte_rf_recv_wrapper, prog_args.rf_nof_rx_ant, (void*) &rf,decimate)) { + if (srslte_ue_sync_init_multi_decim(&ue_sync, + cell.nof_prb, + cell.id==1000, + srslte_rf_recv_wrapper, + prog_args.rf_nof_rx_ant, + (void*) &rf,decimate)) + { fprintf(stderr, "Error initiating ue_sync\n"); exit(-1); } + if (srslte_ue_sync_set_cell(&ue_sync, cell)) + { + fprintf(stderr, "Error initiating ue_sync\n"); + exit(-1); + } #endif } - if (srslte_ue_mib_init(&ue_mib, cell)) { + if (srslte_ue_mib_init(&ue_mib, cell.nof_prb)) { + fprintf(stderr, "Error initaiting UE MIB decoder\n"); + exit(-1); + } + if (srslte_ue_mib_set_cell(&ue_mib, cell)) { fprintf(stderr, "Error initaiting UE MIB decoder\n"); exit(-1); - } + } - if (srslte_ue_dl_init(&ue_dl, cell, prog_args.rf_nof_rx_ant)) { // This is the User RNTI + if (srslte_ue_dl_init(&ue_dl, cell.nof_prb, prog_args.rf_nof_rx_ant)) { fprintf(stderr, "Error initiating UE downlink processing module\n"); exit(-1); } - + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { + fprintf(stderr, "Error initiating UE downlink processing module\n"); + exit(-1); + } + for (int i=0;i -1) { + srslte_ue_dl_set_mbsfn_area_id(&ue_dl, prog_args.mbsfn_area_id); + srslte_ue_dl_set_non_mbsfn_region(&ue_dl, prog_args.non_mbsfn_region); + } /* Initialize subframe counter */ sf_cnt = 0; @@ -518,7 +559,7 @@ int main(int argc, char **argv) { // Variables for measurements uint32_t nframes=0; - uint32_t ri = 0, pmi = 0; + uint8_t ri = 0, pmi = 0; float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS], cn = 0.0; bool decode_pdsch = false; @@ -566,10 +607,13 @@ int main(int argc, char **argv) { /* If a new line is detected set verbose level to Debug */ if (fgets(input, sizeof(input), stdin)) { srslte_verbose = SRSLTE_VERBOSE_DEBUG; + ue_dl.pkt_errors = 0; + ue_dl.pkts_total = 0; + ue_dl.nof_detected = 0; + nof_trials = 0; } } - ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); @@ -582,9 +626,12 @@ int main(int argc, char **argv) { /* srslte_ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */ if (ret == 1) { + + uint32_t sfidx = srslte_ue_sync_get_sfidx(&ue_sync); + switch (state) { case DECODE_MIB: - if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) { + if (sfidx == 0) { n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset); if (n < 0) { fprintf(stderr, "Error decoding UE MIB\n"); @@ -603,50 +650,64 @@ int main(int argc, char **argv) { decode_pdsch = true; } else { /* We are looking for SIB1 Blocks, search only in appropiate places */ - if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { + if ((sfidx == 5 && (sfn%2)==0) || sfidx == 1) { decode_pdsch = true; } else { decode_pdsch = false; } } - - INFO("Attempting DL decode SFN=%d\n", sfn); if (decode_pdsch) { - if (cell.nof_ports == 1) { - /* Transmission mode 1 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); - } else { - if (prog_args.rf_nof_rx_ant == 1) { - /* Transmission mode 2 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), - acks); + if(sfidx != 1 || 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, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); } else { - /* Transmission mode 3 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), - acks); - if (n < 1) { - /* Transmission mode 4 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + if (prog_args.rf_nof_rx_ant == 1) { + /* Transmission mode 2 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + acks); + } else { + /* Transmission mode 3 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), acks); + if (n < 1) { + /* Transmission mode 4 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + acks); + } + } + } + }else{ // MBSFN subframe + n = srslte_ue_dl_decode_mbsfn(&ue_dl, + sf_buffer, + data[0], + sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); + if(n>0){ + if(output_file_name){ + //srslte_filesink_init(&sink, output_file_name, SRSLTE_BYTE_BIN); + // srslte_filesink_write(&sink, data, n); + //srslte_filesink_free(&sink); } + INFO("mbsfn PDU size is %d\n", n); } } - - - if (n < 0) { // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); } else if (n > 0) { /* Send data if socket active */ if (prog_args.net_port > 0) { + if(sfidx == 1) { + srslte_netsink_write(&net_sink, data[0], 1+(n-1)/8); + } else { // FIXME: UDP Data transmission does not work - for (uint32_t tb = 0; tb < ue_dl.pdsch_cfg.grant.nof_tb; tb++) { - srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8); - + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (ue_dl.pdsch_cfg.grant.tb_en[tb]) { + srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8); + } + } } } - #ifdef PRINT_CHANGE_SCHEDULIGN if (ue_dl.dl_dci.mcs_idx != old_dl_dci.mcs_idx || memcmp(&ue_dl.dl_dci.type0_alloc, &old_dl_dci.type0_alloc, sizeof(srslte_ra_type0_t)) || @@ -665,6 +726,7 @@ int main(int argc, char **argv) { nof_trials++; + rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f); rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05f); rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f); @@ -672,6 +734,7 @@ int main(int argc, char **argv) { enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f, enodebrate, 0.05f); uerate = SRSLTE_VEC_EMA(((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0))/1000.0f, uerate, 0.01f); + nframes++; if (isnan(rsrq)) { rsrq = 0; @@ -680,20 +743,20 @@ int main(int argc, char **argv) { noise = 0; } if (isnan(rsrp0)) { - rsrp1 = 0; + rsrp0 = 0; } - if (isnan(rsrp0)) { - rsrp1 = 0; + if (isnan(rsrp1)) { + rsrp1 = 0; } } // Plot and Printf - if (srslte_ue_sync_get_sfidx(&ue_sync) == 5 && sfn % 20 == 0) { + if (sfidx == 5) { float gain = prog_args.rf_gain; if (gain < 0) { gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc)); } - + /* Print transmission scheme */ if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { PRINT_LINE(" Tx scheme: %s (codebook_idx=%d)", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type), @@ -704,12 +767,15 @@ int main(int argc, char **argv) { /* Print basic Parameters */ PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers); - PRINT_LINE("nof codewords: %d", ue_dl.pdsch_cfg.grant.nof_tb); + PRINT_LINE("nof codewords: %d", SRSLTE_RA_DL_GRANT_NOF_TB(&ue_dl.pdsch_cfg.grant)); PRINT_LINE(" CFO: %+5.2f kHz", srslte_ue_sync_get_cfo(&ue_sync) / 1000); PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); PRINT_LINE(" Rb: %6.2f / %6.2f Mbps (net/maximum)", uerate, enodebrate); PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); - PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pdsch_pkt_errors / ue_dl.pdsch_pkts_total); + if(prog_args.mbsfn_area_id > -1){ + PRINT_LINE(" PMCH-BLER: %5.2f%%", (float) 100 * ue_dl.pmch_pkt_errors/ue_dl.pmch_pkts_total); + } PRINT_LINE(" TB 0: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[0].idx, ue_dl.pdsch_cfg.grant.mcs[0].tbs); PRINT_LINE(" TB 1: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[1].idx, @@ -751,24 +817,29 @@ int main(int argc, char **argv) { PRINT_LINE("Press enter maximum printing debug log of 1 subframe."); PRINT_LINE(""); PRINT_LINE_RESET_CURSOR(); + } break; } - if (srslte_ue_sync_get_sfidx(&ue_sync) == 9) { + if (sfidx == 9) { sfn++; if (sfn == 1024) { sfn = 0; PRINT_LINE_ADVANCE_CURSOR(); + ue_dl.pdsch_pkt_errors = 0; + ue_dl.pdsch_pkts_total = 0; + /* ue_dl.pkt_errors = 0; - ue_dl.pkts_total = 0; + ue_dl.pkts_total = 0; ue_dl.nof_detected = 0; - nof_trials = 0; + nof_trials = 0; + */ } } #ifndef DISABLE_GRAPHICS if (!prog_args.disable_plots) { - if ((sfn%4) == 0 && decode_pdsch) { + if ((sfn%3) == 0 && decode_pdsch) { plot_sf_idx = srslte_ue_sync_get_sfidx(&ue_sync); plot_track = true; sem_post(&plot_sem); @@ -790,8 +861,7 @@ int main(int argc, char **argv) { sf_cnt++; } // Main loop - printf("\033[30B\n"); - + #ifndef DISABLE_GRAPHICS if (!prog_args.disable_plots) { if (!pthread_kill(plot_thread, 0)) { @@ -812,13 +882,14 @@ int main(int argc, char **argv) { free(sf_buffer[i]); } } - + #ifndef DISABLE_RF if (!prog_args.input_file_name) { srslte_ue_mib_free(&ue_mib); srslte_rf_close(&rf); } #endif + printf("\nBye\n"); exit(0); } diff --git a/lib/examples/usrp_capture_sync.c b/lib/examples/usrp_capture_sync.c index 41c233be7..bac17698a 100644 --- a/lib/examples/usrp_capture_sync.c +++ b/lib/examples/usrp_capture_sync.c @@ -165,11 +165,15 @@ int main(int argc, char **argv) { cell.nof_prb = nof_prb; cell.nof_ports = 1; - if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, nof_rx_antennas, (void*) &rf)) { + if (srslte_ue_sync_init_multi(&ue_sync, cell.nof_prb, cell.id==1000, srslte_rf_recv_wrapper, nof_rx_antennas, (void*) &rf)) { fprintf(stderr, "Error initiating ue_sync\n"); exit(-1); } - + if (srslte_ue_sync_set_cell(&ue_sync, cell)) { + fprintf(stderr, "Error initiating ue_sync\n"); + exit(-1); + } + uint32_t subframe_count = 0; bool start_capture = false; bool stop_capture = false; diff --git a/lib/include/srslte/common/bcd_helpers.h b/lib/include/srslte/common/bcd_helpers.h index d44a66483..b696954c2 100644 --- a/lib/include/srslte/common/bcd_helpers.h +++ b/lib/include/srslte/common/bcd_helpers.h @@ -30,6 +30,7 @@ #include #include #include +#include namespace srslte { @@ -112,6 +113,12 @@ inline bool mnc_to_string(uint16_t mnc, std::string *str) *str += (mnc & 0x000F) + '0'; return true; } +inline std::string plmn_id_to_string(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { + std::string mcc_str, mnc_str; + mnc_to_string(plmn_id.mnc, &mnc_str); + mcc_to_string(plmn_id.mcc, &mcc_str); + return mcc_str + mnc_str; +} } // namespace srslte diff --git a/lib/include/srslte/common/buffer_pool.h b/lib/include/srslte/common/buffer_pool.h index 94439387a..1c6dfc53a 100644 --- a/lib/include/srslte/common/buffer_pool.h +++ b/lib/include/srslte/common/buffer_pool.h @@ -93,7 +93,7 @@ public: available.pop(); if (available.size() < capacity/20) { - printf("Warning buffer pool capacity is %f %%\n", (float) available.size()/capacity); + printf("Warning buffer pool capacity is %f %%\n", (float) 100*available.size()/capacity); } #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED if (debug_name) { diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index ad88d9dcc..7156fbfc9 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -50,7 +50,7 @@ #define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756 #define SRSLTE_BUFFER_HEADER_OFFSET 1024 -#define SRSLTE_BUFFER_POOL_LOG_ENABLED +//#define SRSLTE_BUFFER_POOL_LOG_ENABLED #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #define pool_allocate (pool->allocate(__FUNCTION__)) diff --git a/lib/include/srslte/common/interfaces_common.h b/lib/include/srslte/common/interfaces_common.h index d919d9fe5..a027b6230 100644 --- a/lib/include/srslte/common/interfaces_common.h +++ b/lib/include/srslte/common/interfaces_common.h @@ -71,8 +71,9 @@ public: /* Timer services with ms resolution. * timer_id must be lower than MAC_NOF_UPPER_TIMERS */ - virtual timers::timer* get(uint32_t timer_id) = 0; - virtual uint32_t get_unique_id() = 0; + virtual timers::timer* timer_get(uint32_t timer_id) = 0; + virtual void timer_release_id(uint32_t timer_id) = 0; + virtual uint32_t timer_get_unique_id() = 0; }; class read_pdu_interface diff --git a/lib/include/srslte/common/metrics_hub.h b/lib/include/srslte/common/metrics_hub.h index 9575347a2..66cc4acbd 100644 --- a/lib/include/srslte/common/metrics_hub.h +++ b/lib/include/srslte/common/metrics_hub.h @@ -24,20 +24,26 @@ template class metrics_listener { public: - virtual void set_metrics(metrics_t &m) = 0; + virtual void set_metrics(metrics_t &m, float report_period_secs=1.0) = 0; }; template class metrics_hub : public periodic_thread { public: - bool init(metrics_interface *m_, float report_period_secs=1.0) { - m = m_; + metrics_hub() + :m(NULL) + ,report_period_secs(1) + {} + bool init(metrics_interface *m_, float report_period_secs_=1.0) { + m = m_; + report_period_secs = report_period_secs_; start_periodic(report_period_secs*1e6); return true; } void stop() { thread_cancel(); + wait_thread_finish(); } void add_listener(metrics_listener *listener) { @@ -46,15 +52,18 @@ public: private: void run_period() { - metrics_t metric; - m->get_metrics(metric); - for (uint32_t i=0;iset_metrics(metric); + if (m) { + metrics_t metric; + bzero(&metric, sizeof(metrics_t)); + m->get_metrics(metric); + for (uint32_t i=0;iset_metrics(metric, report_period_secs); + } } } metrics_interface *m; - std::vector*> listeners; - + std::vector*> listeners; + float report_period_secs; }; } // namespace srslte diff --git a/lib/include/srslte/common/timers.h b/lib/include/srslte/common/timers.h index 377df7b1d..a8563af37 100644 --- a/lib/include/srslte/common/timers.h +++ b/lib/include/srslte/common/timers.h @@ -74,7 +74,7 @@ public: } void step() { if (running) { - counter++; + counter++; if (is_expired()) { running = false; if (callback) { @@ -145,7 +145,7 @@ public: } uint32_t get_unique_id() { if (nof_used_timers >= nof_timers) { - fprintf(stderr, "Error getting uinque timer id: no more timers available\n"); + fprintf(stderr, "Error getting unique timer id: no more timers available\n"); return 0; } else { while(used_timers[next_timer]) { diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index ed2478896..9c85814f8 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -244,7 +244,7 @@ public: class gtpu_interface_rrc { public: - virtual void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) = 0; + virtual void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in) = 0; virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0; virtual void rem_user(uint16_t rnti) = 0; }; diff --git a/lib/include/srslte/interfaces/enb_metrics_interface.h b/lib/include/srslte/interfaces/enb_metrics_interface.h index 6893b4c2f..ee00e3453 100644 --- a/lib/include/srslte/interfaces/enb_metrics_interface.h +++ b/lib/include/srslte/interfaces/enb_metrics_interface.h @@ -32,7 +32,7 @@ #include "upper/common_enb.h" #include "upper/s1ap_metrics.h" #include "upper/rrc_metrics.h" -#include "srslte/upper/gw_metrics.h" +#include "../../../../srsue/hdr/upper/gw_metrics.h" #include "srslte/upper/rlc_metrics.h" #include "mac/mac_metrics.h" #include "phy/phy_metrics.h" diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 879118021..8561ba55c 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -54,6 +54,7 @@ class usim_interface_nas public: virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0; + virtual int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0; virtual void generate_authentication_response(uint8_t *rand, uint8_t *autn_enb, uint16_t mcc, @@ -98,10 +99,28 @@ class nas_interface_rrc { public: virtual bool is_attached() = 0; + virtual bool is_attaching() = 0; virtual void notify_connection_setup() = 0; virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual uint32_t get_ul_count() = 0; virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0; + virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0; + virtual void plmn_search_end() = 0; +}; + +// NAS interface for UE +class nas_interface_ue +{ +public: + virtual void attach_request() = 0; + virtual void deattach_request() = 0; +}; + +// NAS interface for UE +class nas_interface_gw +{ +public: + virtual void attach_request() = 0; }; // RRC interface for MAC @@ -123,6 +142,8 @@ class rrc_interface_phy public: virtual void in_sync() = 0; virtual void out_of_sync() = 0; + virtual void earfcn_end() = 0; + virtual void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) = 0; }; // RRC interface for NAS @@ -133,18 +154,11 @@ public: virtual uint16_t get_mcc() = 0; virtual uint16_t get_mnc() = 0; virtual void enable_capabilities() = 0; + virtual void plmn_search() = 0; + virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0; virtual std::string get_rb_name(uint32_t lcid) = 0; }; -// RRC interface for GW -class rrc_interface_gw -{ -public: - virtual bool rrc_connected() = 0; - virtual void rrc_connect() = 0; - virtual bool have_drb() = 0; -}; - // RRC interface for PDCP class rrc_interface_pdcp { @@ -169,6 +183,7 @@ class pdcp_interface_gw { public: virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual bool is_drb_enabled(uint32_t lcid) = 0; }; // PDCP interface for RRC @@ -281,6 +296,8 @@ public: bool last_ndi[SRSLTE_MAX_CODEWORDS]; uint32_t n_bytes[SRSLTE_MAX_CODEWORDS]; int rv[SRSLTE_MAX_CODEWORDS]; + bool tb_en[SRSLTE_MAX_CODEWORDS]; + bool tb_cw_swap; uint16_t rnti; bool is_from_rar; bool is_sps_release; @@ -290,11 +307,11 @@ public: } mac_grant_t; typedef struct { - bool decode_enabled; + bool decode_enabled[SRSLTE_MAX_TB]; int rv[SRSLTE_MAX_TB]; uint16_t rnti; bool generate_ack; - bool default_ack; + bool default_ack[SRSLTE_MAX_TB]; // If non-null, called after tb_decoded_ok to determine if ack needs to be sent bool (*generate_ack_callback)(void*); void *generate_ack_callback_arg; @@ -421,8 +438,8 @@ typedef struct { int worker_cpu_mask; int sync_cpu_affinity; - uint32_t nof_rx_ant; - std::string equalizer_mode; + uint32_t nof_rx_ant; + std::string equalizer_mode; int cqi_max; int cqi_fixed; float snr_ema_coeff; @@ -442,9 +459,8 @@ class phy_interface_mac_common { public: /* Start synchronization with strongest cell in the current carrier frequency */ - virtual void sync_start() = 0; - virtual void sync_stop() = 0; - + virtual bool sync_status() = 0; + /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ virtual void set_crnti(uint16_t rnti) = 0; @@ -511,16 +527,21 @@ 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; - + + /* Cell search and selection procedures */ + virtual void cell_search_start() = 0; + virtual void cell_search_stop() = 0; + virtual void cell_search_next() = 0; + virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0; + /* Is the PHY downlink synchronized? */ - virtual bool status_is_sync() = 0; + virtual bool sync_status() = 0; + virtual void sync_reset() = 0; /* Configure UL using parameters written with set_param() */ virtual void configure_ul_params(bool pregen_disabled = false) = 0; virtual void reset() = 0; - - virtual void resync_sfn() = 0; }; diff --git a/lib/include/srslte/phy/ch_estimation/chest_dl.h b/lib/include/srslte/phy/ch_estimation/chest_dl.h index 5d0820aa4..0e43d113c 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -60,7 +60,10 @@ typedef enum { typedef struct { srslte_cell_t cell; - srslte_refsignal_cs_t csr_signal; + srslte_refsignal_t csr_refs; + srslte_refsignal_t **mbsfn_refs; + + cf_t *pilot_estimates; cf_t *pilot_estimates_average; cf_t *pilot_recv_signal; @@ -75,7 +78,7 @@ typedef struct { srslte_interp_linsrslte_vec_t srslte_interp_linvec; srslte_interp_lin_t srslte_interp_lin; - + srslte_interp_lin_t srslte_interp_lin_mbsfn; float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; @@ -92,9 +95,16 @@ typedef struct { SRSLTE_API int srslte_chest_dl_init(srslte_chest_dl_t *q, - srslte_cell_t cell); + uint32_t max_prb); + +SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t *q); + + +SRSLTE_API int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, + uint16_t mbsfn_area_id); +SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, + srslte_cell_t cell); -SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t *q); SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, @@ -106,6 +116,8 @@ SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q, srslte_chest_dl_noise_alg_t noise_estimation_alg); + + SRSLTE_API int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], @@ -117,6 +129,14 @@ SRSLTE_API int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *ce[SRSLTE_MAX_PORTS], uint32_t sf_idx); +SRSLTE_API int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + uint32_t sf_idx, + uint32_t nof_rx_antennas, + uint16_t mbsfn_area_id); + + SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, diff --git a/lib/include/srslte/phy/ch_estimation/chest_ul.h b/lib/include/srslte/phy/ch_estimation/chest_ul.h index 1e505210c..0571fec8c 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_ul.h +++ b/lib/include/srslte/phy/ch_estimation/chest_ul.h @@ -77,9 +77,13 @@ typedef struct { SRSLTE_API int srslte_chest_ul_init(srslte_chest_ul_t *q, - srslte_cell_t cell); + uint32_t max_prb); + +SRSLTE_API void srslte_chest_ul_free(srslte_chest_ul_t *q); + +SRSLTE_API int srslte_chest_ul_set_cell(srslte_chest_ul_t *q, + srslte_cell_t cell); -SRSLTE_API void srslte_chest_ul_free(srslte_chest_ul_t *q); SRSLTE_API void srslte_chest_ul_set_cfg(srslte_chest_ul_t *q, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, diff --git a/lib/include/srslte/phy/ch_estimation/refsignal_dl.h b/lib/include/srslte/phy/ch_estimation/refsignal_dl.h index 3cdf7901e..9263073a9 100644 --- a/lib/include/srslte/phy/ch_estimation/refsignal_dl.h +++ b/lib/include/srslte/phy/ch_estimation/refsignal_dl.h @@ -40,22 +40,34 @@ // Number of references in a subframe: there are 2 symbols for port_id=0,1 x 2 slots x 2 refs per prb #define SRSLTE_REFSIGNAL_NUM_SF(nof_prb, port_id) (((port_id)<2?8:4)*(nof_prb)) +#define SRSLTE_REFSIGNAL_NUM_SF_MBSFN(nof_prb, port_id) ((2 + 18)*(nof_prb)) + #define SRSLTE_REFSIGNAL_MAX_NUM_SF(nof_prb) SRSLTE_REFSIGNAL_NUM_SF(nof_prb, 0) +#define SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(nof_prb) SRSLTE_REFSIGNAL_NUM_SF_MBSFN(nof_prb,0) #define SRSLTE_REFSIGNAL_PILOT_IDX(i,l,cell) (2*cell.nof_prb*(l)+(i)) +#define SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i,l,cell) ((6*cell.nof_prb*(l)+(i))) + + /** Cell-Specific Reference Signal */ typedef struct SRSLTE_API { srslte_cell_t cell; - cf_t *pilots[2][SRSLTE_NSUBFRAMES_X_FRAME]; // Saves the reference signal per subframe for ports 0,1 and ports 2,3 -} srslte_refsignal_cs_t; + cf_t *pilots[2][SRSLTE_NSUBFRAMES_X_FRAME]; // Saves the reference signal per subframe for ports 0,1 and ports 2,3 + srslte_sf_t type; + uint16_t mbsfn_area_id; +} srslte_refsignal_t; + -SRSLTE_API int srslte_refsignal_cs_init(srslte_refsignal_cs_t *q, - srslte_cell_t cell); +SRSLTE_API int srslte_refsignal_cs_init(srslte_refsignal_t *q, + uint32_t max_prb); -SRSLTE_API void srslte_refsignal_cs_free(srslte_refsignal_cs_t *q); +SRSLTE_API int srslte_refsignal_cs_set_cell(srslte_refsignal_t * q, + srslte_cell_t cell); + +SRSLTE_API void srslte_refsignal_free(srslte_refsignal_t *q); SRSLTE_API int srslte_refsignal_cs_put_sf(srslte_cell_t cell, uint32_t port_id, @@ -81,4 +93,29 @@ 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_get_sf(srslte_cell_t cell, + uint32_t port_id, + cf_t *sf_symbols, + cf_t *pilots); + +SRSLTE_API uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l); + +SRSLTE_API uint32_t srslte_refsignal_mbsfn_fidx(uint32_t l); + +SRSLTE_API uint32_t srslte_refsignal_mbsfn_nof_symbols(); + +SRSLTE_API int srslte_refsignal_mbsfn_put_sf(srslte_cell_t cell, + uint32_t port_id, + cf_t *cs_pilots, + cf_t *mbsfn_pilots, + cf_t *sf_symbols); + +SRSLTE_API int srslte_refsignal_mbsfn_gen_seq(srslte_refsignal_t * q, + srslte_cell_t cell, + uint32_t N_mbsfn_id); + + #endif diff --git a/lib/include/srslte/phy/ch_estimation/refsignal_ul.h b/lib/include/srslte/phy/ch_estimation/refsignal_ul.h index 72bfb5d94..9e1da9e50 100644 --- a/lib/include/srslte/phy/ch_estimation/refsignal_ul.h +++ b/lib/include/srslte/phy/ch_estimation/refsignal_ul.h @@ -94,7 +94,10 @@ typedef struct { } srslte_refsignal_srs_pregen_t; SRSLTE_API int srslte_refsignal_ul_init(srslte_refsignal_ul_t *q, - srslte_cell_t cell); + uint32_t max_prb); + +SRSLTE_API int srslte_refsignal_ul_set_cell(srslte_refsignal_ul_t *q, + srslte_cell_t cell); SRSLTE_API void srslte_refsignal_ul_free(srslte_refsignal_ul_t *q); @@ -115,9 +118,13 @@ SRSLTE_API uint32_t srslte_refsignal_dmrs_pucch_symbol(uint32_t m, SRSLTE_API bool srslte_refsignal_dmrs_pusch_cfg_isvalid(srslte_refsignal_ul_t *q, srslte_refsignal_dmrs_pusch_cfg_t *cfg, - uint32_t nof_prb); + uint32_t nof_prb); + +SRSLTE_API int srslte_refsignal_dmrs_pusch_pregen_init(srslte_refsignal_ul_t *q, + srslte_refsignal_ul_dmrs_pregen_t *pregen, + uint32_t max_prb); -SRSLTE_API int srslte_refsignal_dmrs_pusch_pregen(srslte_refsignal_ul_t *q, +SRSLTE_API int srslte_refsignal_dmrs_pusch_pregen(srslte_refsignal_ul_t *q, srslte_refsignal_ul_dmrs_pregen_t *pregen); SRSLTE_API void srslte_refsignal_dmrs_pusch_pregen_free(srslte_refsignal_ul_t *q, diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 29bf8d3a4..148a12974 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -63,7 +63,11 @@ #define SRSLTE_LTE_CRC16 0x11021 #define SRSLTE_LTE_CRC8 0x19B +#define SRSLTE_MAX_MBSFN_AREA_IDS 256 +#define SRSLTE_PMCH_RV 0 + typedef enum {SRSLTE_CP_NORM, SRSLTE_CP_EXT} srslte_cp_t; +typedef enum {SRSLTE_SF_NORM, SRSLTE_SF_MBSFN} srslte_sf_t; #define SRSLTE_CRNTI_START 0x000B @@ -130,6 +134,13 @@ typedef enum {SRSLTE_CP_NORM, SRSLTE_CP_EXT} srslte_cp_t; || l == SRSLTE_CP_NSYMB(cp) - 3) + +#define SRSLTE_SYMBOL_HAS_REF_MBSFN(l, s) ((l == 2 && s == 0) || (l == 0 && s == 1) || (l == 4 && s == 1)) + +#define SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(non_mbsfn_region,symbol_sz) ((non_mbsfn_region == 1)?(SRSLTE_CP_LEN_EXT(symbol_sz) - SRSLTE_CP_LEN_NORM(0, symbol_sz)):(2*SRSLTE_CP_LEN_EXT(symbol_sz) - SRSLTE_CP_LEN_NORM(0, symbol_sz)- SRSLTE_CP_LEN_NORM(1, symbol_sz))) + + + #define SRSLTE_NOF_LTE_BANDS 38 #define SRSLTE_DEFAULT_MAX_FRAMES_PBCH 500 @@ -157,6 +168,7 @@ typedef enum { SRSLTE_RNTI_TEMP, /* Temporary C-RNTI */ SRSLTE_RNTI_SPS, /* Semi-Persistent Scheduling C-RNTI */ SRSLTE_RNTI_PCH, /* Paging RNTI */ + SRSLTE_RNTI_MBSFN, SRSLTE_RNTI_NOF_TYPES } srslte_rnti_type_t; diff --git a/lib/include/srslte/phy/common/sequence.h b/lib/include/srslte/phy/common/sequence.h index dbeba5ff4..62934c7e0 100644 --- a/lib/include/srslte/phy/common/sequence.h +++ b/lib/include/srslte/phy/common/sequence.h @@ -44,7 +44,8 @@ typedef struct SRSLTE_API { uint8_t *c_bytes; float *c_float; short *c_short; - uint32_t len; + uint32_t cur_len; + uint32_t max_len; } srslte_sequence_t; SRSLTE_API int srslte_sequence_init(srslte_sequence_t *q, uint32_t len); @@ -55,8 +56,9 @@ SRSLTE_API int srslte_sequence_LTE_pr(srslte_sequence_t *q, uint32_t len, uint32_t seed); -SRSLTE_API void srslte_sequence_set_LTE_pr(srslte_sequence_t *q, - uint32_t seed); +SRSLTE_API int srslte_sequence_set_LTE_pr(srslte_sequence_t *q, + uint32_t len, + uint32_t seed); SRSLTE_API int srslte_sequence_pbch(srslte_sequence_t *seq, srslte_cp_t cp, @@ -92,4 +94,10 @@ SRSLTE_API int srslte_sequence_pucch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id); + +SRSLTE_API int srslte_sequence_pmch(srslte_sequence_t *seq, + uint32_t nslot, + uint32_t mbsfn_id, + uint32_t len); + #endif diff --git a/lib/include/srslte/phy/dft/dft.h b/lib/include/srslte/phy/dft/dft.h index b90aab2e5..b7fc663d8 100644 --- a/lib/include/srslte/phy/dft/dft.h +++ b/lib/include/srslte/phy/dft/dft.h @@ -58,6 +58,7 @@ typedef enum { }srslte_dft_dir_t; typedef struct SRSLTE_API { + int init_size; // DFT length used in the first initialization int size; // DFT length void *in; // Input buffer void *out; // Output buffer @@ -80,7 +81,7 @@ SRSLTE_API int srslte_dft_plan(srslte_dft_plan_t *plan, srslte_dft_dir_t dir, srslte_dft_mode_t type); -SRSLTE_API int srslte_dft_plan_c(srslte_dft_plan_t *plan, +SRSLTE_API int srslte_dft_plan_c(srslte_dft_plan_t *plan, int dft_points, srslte_dft_dir_t dir); @@ -88,6 +89,16 @@ SRSLTE_API int srslte_dft_plan_r(srslte_dft_plan_t *plan, int dft_points, srslte_dft_dir_t dir); +SRSLTE_API int srslte_dft_replan(srslte_dft_plan_t *plan, + const int new_dft_points); + +SRSLTE_API int srslte_dft_replan_c(srslte_dft_plan_t *plan, + int new_dft_points); + +SRSLTE_API int srslte_dft_replan_r(srslte_dft_plan_t *plan, + int new_dft_points); + + SRSLTE_API void srslte_dft_plan_free(srslte_dft_plan_t *plan); /* Set options */ diff --git a/lib/include/srslte/phy/dft/dft_precoding.h b/lib/include/srslte/phy/dft/dft_precoding.h index 6e5c5dc40..022593aa7 100644 --- a/lib/include/srslte/phy/dft/dft_precoding.h +++ b/lib/include/srslte/phy/dft/dft_precoding.h @@ -45,12 +45,18 @@ typedef struct SRSLTE_API { uint32_t max_prb; srslte_dft_plan_t dft_plan[SRSLTE_MAX_PRB+1]; - srslte_dft_plan_t idft_plan[SRSLTE_MAX_PRB+1]; - + }srslte_dft_precoding_t; -SRSLTE_API int srslte_dft_precoding_init(srslte_dft_precoding_t *q, - uint32_t max_prb); +SRSLTE_API int srslte_dft_precoding_init(srslte_dft_precoding_t *q, + uint32_t max_prb, + bool is_tx); + +SRSLTE_API int srslte_dft_precoding_init_tx(srslte_dft_precoding_t *q, + uint32_t max_prb); + +SRSLTE_API int srslte_dft_precoding_init_rx(srslte_dft_precoding_t *q, + uint32_t max_prb); SRSLTE_API void srslte_dft_precoding_free(srslte_dft_precoding_t *q); @@ -62,10 +68,4 @@ SRSLTE_API int srslte_dft_precoding(srslte_dft_precoding_t *q, uint32_t nof_prb, uint32_t nof_symbols); -SRSLTE_API int srslte_dft_predecoding(srslte_dft_precoding_t *q, - cf_t *input, - cf_t *output, - uint32_t nof_prb, - uint32_t nof_symbols); - #endif diff --git a/lib/include/srslte/phy/dft/ofdm.h b/lib/include/srslte/phy/dft/ofdm.h index 990d7a8cc..1363f5638 100644 --- a/lib/include/srslte/phy/dft/ofdm.h +++ b/lib/include/srslte/phy/dft/ofdm.h @@ -47,6 +47,7 @@ /* This is common for both directions */ typedef struct SRSLTE_API{ srslte_dft_plan_t fft_plan; + uint32_t max_prb; uint32_t nof_symbols; uint32_t symbol_sz; uint32_t nof_guards; @@ -55,7 +56,14 @@ typedef struct SRSLTE_API{ srslte_cp_t cp; cf_t *tmp; // for removing zero padding + bool mbsfn_subframe; + uint32_t mbsfn_guard_len; + uint32_t nof_symbols_mbsfn; + uint8_t non_mbsfn_region; + + bool freq_shift; + float freq_shift_f; cf_t *shift_buffer; }srslte_ofdm_t; @@ -63,11 +71,32 @@ SRSLTE_API int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb, - srslte_dft_dir_t dir); + srslte_dft_dir_t dir); + +SRSLTE_API int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, + srslte_cp_t cp, + int symbol_sz, + int nof_prb, + srslte_dft_dir_t dir, + srslte_sf_t sf_type); + +SRSLTE_API int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, + srslte_cp_t cp_type, + uint32_t nof_prb); + + SRSLTE_API int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp_type, - uint32_t nof_prb); + uint32_t max_prb); + +SRSLTE_API int srslte_ofdm_tx_set_prb(srslte_ofdm_t *q, + srslte_cp_t cp, + uint32_t nof_prb); + +SRSLTE_API int srslte_ofdm_rx_set_prb(srslte_ofdm_t *q, + srslte_cp_t cp, + uint32_t nof_prb); SRSLTE_API void srslte_ofdm_rx_free(srslte_ofdm_t *q); @@ -85,12 +114,22 @@ SRSLTE_API int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp_type, uint32_t nof_prb); +SRSLTE_API int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, + srslte_cp_t cp, + uint32_t nof_prb); + + SRSLTE_API void srslte_ofdm_tx_free(srslte_ofdm_t *q); SRSLTE_API void srslte_ofdm_tx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output); +SRSLTE_API void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, + cf_t *input, + cf_t *output); + + SRSLTE_API void srslte_ofdm_tx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output); @@ -101,4 +140,8 @@ SRSLTE_API int srslte_ofdm_set_freq_shift(srslte_ofdm_t *q, SRSLTE_API void srslte_ofdm_set_normalize(srslte_ofdm_t *q, bool normalize_enable); -#endif +SRSLTE_API void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t *q, + uint8_t non_mbsfn_region); + + +#endif \ No newline at end of file diff --git a/lib/include/srslte/phy/enb/enb_dl.h b/lib/include/srslte/phy/enb/enb_dl.h index d39eed1e1..7c3166e5c 100644 --- a/lib/include/srslte/phy/enb/enb_dl.h +++ b/lib/include/srslte/phy/enb/enb_dl.h @@ -76,7 +76,7 @@ typedef struct SRSLTE_API { srslte_pdsch_t pdsch; srslte_phich_t phich; - srslte_refsignal_cs_t csr_signal; + srslte_refsignal_t csr_signal; srslte_pdsch_cfg_t pdsch_cfg; srslte_ra_dl_dci_t dl_dci; @@ -88,6 +88,8 @@ typedef struct SRSLTE_API { float sss_signal5[SRSLTE_SSS_LEN]; float tx_amp; + + uint8_t tmp[1024*128]; } srslte_enb_dl_t; @@ -108,11 +110,14 @@ typedef struct { /* This function shall be called just after the initial synchronization */ SRSLTE_API int srslte_enb_dl_init(srslte_enb_dl_t *q, - srslte_cell_t cell); + uint32_t max_prb); SRSLTE_API void srslte_enb_dl_free(srslte_enb_dl_t *q); -SRSLTE_API void srslte_enb_dl_set_cfi(srslte_enb_dl_t *q, +SRSLTE_API int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, + srslte_cell_t cell); + +SRSLTE_API void srslte_enb_dl_set_cfi(srslte_enb_dl_t *q, uint32_t cfi); SRSLTE_API void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, @@ -154,16 +159,18 @@ SRSLTE_API int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS], uint16_t rnti, - uint32_t rv_idx, + int rv_idx[SRSLTE_MAX_CODEWORDS], uint32_t sf_idx, - uint8_t *data[SRSLTE_MAX_CODEWORDS]); + uint8_t *data[SRSLTE_MAX_CODEWORDS], + srslte_mimo_type_t mimo_type, + uint32_t pmi); 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, srslte_dci_location_t location, uint16_t rnti, - uint32_t sf_idx); + uint32_t sf_idx); SRSLTE_API int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant, @@ -171,5 +178,12 @@ SRSLTE_API int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, uint16_t rnti, uint32_t sf_idx); +SRSLTE_API 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); #endif diff --git a/lib/include/srslte/phy/enb/enb_ul.h b/lib/include/srslte/phy/enb/enb_ul.h index 486566a1c..855b645ca 100644 --- a/lib/include/srslte/phy/enb/enb_ul.h +++ b/lib/include/srslte/phy/enb/enb_ul.h @@ -100,15 +100,18 @@ typedef struct { } srslte_enb_ul_pusch_t; /* This function shall be called just after the initial synchronization */ -SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t *q, - srslte_cell_t cell, - srslte_prach_cfg_t* prach_cfg, - srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, - srslte_pusch_hopping_cfg_t *hopping_cfg, - srslte_pucch_cfg_t *pucch_cfg); +SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t *q, + uint32_t max_prb); SRSLTE_API void srslte_enb_ul_free(srslte_enb_ul_t *q); +SRSLTE_API int srslte_enb_ul_set_cell(srslte_enb_ul_t *q, + srslte_cell_t cell, + srslte_prach_cfg_t* prach_cfg, + srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, + srslte_pusch_hopping_cfg_t *hopping_cfg, + srslte_pucch_cfg_t *pucch_cfg); + SRSLTE_API int srslte_enb_ul_add_rnti(srslte_enb_ul_t *q, uint16_t rnti); diff --git a/lib/include/srslte/phy/fec/turbodecoder.h b/lib/include/srslte/phy/fec/turbodecoder.h index d42a20ae6..ac05422bc 100644 --- a/lib/include/srslte/phy/fec/turbodecoder.h +++ b/lib/include/srslte/phy/fec/turbodecoder.h @@ -50,20 +50,14 @@ #define SRSLTE_TCOD_MAX_LEN_CODED (SRSLTE_TCOD_RATE*SRSLTE_TCOD_MAX_LEN_CB+SRSLTE_TCOD_TOTALTAIL) #include "srslte/phy/fec/turbodecoder_gen.h" - -#ifdef LV_HAVE_SSE #include "srslte/phy/fec/turbodecoder_simd.h" -#else -#define SRSLTE_TDEC_NPAR 1 -#endif typedef struct SRSLTE_API { -#ifdef LV_HAVE_SSE - srslte_tdec_simd_t tdec_simd; -#else - float *input_conv; - srslte_tdec_gen_t tdec_gen; -#endif + float *input_conv; + union { + srslte_tdec_simd_t tdec_simd; + srslte_tdec_gen_t tdec_gen; + }; } srslte_tdec_t; SRSLTE_API int srslte_tdec_init(srslte_tdec_t * h, @@ -80,7 +74,7 @@ SRSLTE_API int srslte_tdec_reset_cb(srslte_tdec_t * h, SRSLTE_API int srslte_tdec_get_nof_iterations_cb(srslte_tdec_t * h, uint32_t cb_idx); -SRSLTE_API int srslte_tdec_get_nof_parallel(srslte_tdec_t * h); +SRSLTE_API uint32_t srslte_tdec_get_nof_parallel(srslte_tdec_t * h); SRSLTE_API void srslte_tdec_iteration(srslte_tdec_t * h, int16_t* input, @@ -101,15 +95,15 @@ SRSLTE_API int srslte_tdec_run_all(srslte_tdec_t * h, uint32_t long_cb); SRSLTE_API void srslte_tdec_iteration_par(srslte_tdec_t * h, - int16_t* input[SRSLTE_TDEC_NPAR], + int16_t* input[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_decision_par(srslte_tdec_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_decision_byte_par(srslte_tdec_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_decision_byte_par_cb(srslte_tdec_t * h, @@ -118,8 +112,8 @@ SRSLTE_API void srslte_tdec_decision_byte_par_cb(srslte_tdec_t * h, uint32_t long_cb); SRSLTE_API int srslte_tdec_run_all_par(srslte_tdec_t * h, - int16_t * input[SRSLTE_TDEC_NPAR], - uint8_t *output[SRSLTE_TDEC_NPAR], + int16_t * input[SRSLTE_TDEC_MAX_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_iterations, uint32_t long_cb); diff --git a/lib/include/srslte/phy/fec/turbodecoder_simd.h b/lib/include/srslte/phy/fec/turbodecoder_simd.h index d7bc284d2..a899a5964 100644 --- a/lib/include/srslte/phy/fec/turbodecoder_simd.h +++ b/lib/include/srslte/phy/fec/turbodecoder_simd.h @@ -43,23 +43,8 @@ #include "srslte/phy/fec/tc_interl.h" #include "srslte/phy/fec/cbsegm.h" -//#define ENABLE_SIMD_INTER - -// The constant SRSLTE_TDEC_NPAR defines the maximum number of parallel CB supported by all SIMD decoders -#ifdef ENABLE_SIMD_INTER - #include "srslte/phy/fec/turbodecoder_simd_inter.h" - #ifdef LV_HAVE_AVX2 - #define SRSLTE_TDEC_NPAR_INTRA 2 - #else - #define SRSLTE_TDEC_NPAR_INTRA 1 - #endif -#else - #ifdef LV_HAVE_AVX2 - #define SRSLTE_TDEC_NPAR 2 - #else - #define SRSLTE_TDEC_NPAR 1 - #endif -#endif +// Define maximum number of CB decoded in parallel (2 for AVX2) +#define SRSLTE_TDEC_MAX_NPAR 2 #define SRSLTE_TCOD_RATE 3 #define SRSLTE_TCOD_TOTALTAIL 12 @@ -80,18 +65,18 @@ typedef struct SRSLTE_API { map_gen_t dec; - int16_t *app1[SRSLTE_TDEC_NPAR]; - int16_t *app2[SRSLTE_TDEC_NPAR]; - int16_t *ext1[SRSLTE_TDEC_NPAR]; - int16_t *ext2[SRSLTE_TDEC_NPAR]; - int16_t *syst[SRSLTE_TDEC_NPAR]; - int16_t *parity0[SRSLTE_TDEC_NPAR]; - int16_t *parity1[SRSLTE_TDEC_NPAR]; + int16_t *app1[SRSLTE_TDEC_MAX_NPAR]; + int16_t *app2[SRSLTE_TDEC_MAX_NPAR]; + int16_t *ext1[SRSLTE_TDEC_MAX_NPAR]; + int16_t *ext2[SRSLTE_TDEC_MAX_NPAR]; + int16_t *syst[SRSLTE_TDEC_MAX_NPAR]; + int16_t *parity0[SRSLTE_TDEC_MAX_NPAR]; + int16_t *parity1[SRSLTE_TDEC_MAX_NPAR]; int cb_mask; int current_cbidx; srslte_tc_interl_t interleaver[SRSLTE_NOF_TC_CB_SIZES]; - int n_iter[SRSLTE_TDEC_NPAR]; + int n_iter[SRSLTE_TDEC_MAX_NPAR]; } srslte_tdec_simd_t; SRSLTE_API int srslte_tdec_simd_init(srslte_tdec_simd_t * h, @@ -103,6 +88,8 @@ SRSLTE_API void srslte_tdec_simd_free(srslte_tdec_simd_t * h); SRSLTE_API int srslte_tdec_simd_reset(srslte_tdec_simd_t * h, uint32_t long_cb); +SRSLTE_API + SRSLTE_API int srslte_tdec_simd_get_nof_iterations_cb(srslte_tdec_simd_t * h, uint32_t cb_idx); @@ -110,15 +97,15 @@ SRSLTE_API int srslte_tdec_simd_reset_cb(srslte_tdec_simd_t * h, uint32_t cb_idx); SRSLTE_API void srslte_tdec_simd_iteration(srslte_tdec_simd_t * h, - int16_t * input[SRSLTE_TDEC_NPAR], + int16_t * input[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_simd_decision(srslte_tdec_simd_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_simd_decision_byte_cb(srslte_tdec_simd_t * h, @@ -127,8 +114,8 @@ SRSLTE_API void srslte_tdec_simd_decision_byte_cb(srslte_tdec_simd_t * h, uint32_t long_cb); SRSLTE_API int srslte_tdec_simd_run_all(srslte_tdec_simd_t * h, - int16_t * input[SRSLTE_TDEC_NPAR], - uint8_t *output[SRSLTE_TDEC_NPAR], + int16_t * input[SRSLTE_TDEC_MAX_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_iterations, uint32_t long_cb); diff --git a/lib/include/srslte/phy/fec/turbodecoder_simd_inter.h b/lib/include/srslte/phy/fec/turbodecoder_simd_inter.h index 402faa314..c80785809 100644 --- a/lib/include/srslte/phy/fec/turbodecoder_simd_inter.h +++ b/lib/include/srslte/phy/fec/turbodecoder_simd_inter.h @@ -49,9 +49,9 @@ #include "srslte/phy/fec/cbsegm.h" #if LV_HAVE_AVX2 - #define SRSLTE_TDEC_NPAR 16 + #define SRSLTE_TDEC_MAX_NPAR 16 #else - #define SRSLTE_TDEC_NPAR 8 + #define SRSLTE_TDEC_MAX_NPAR 8 #endif @@ -71,7 +71,7 @@ typedef struct SRSLTE_API { int current_cbidx; uint32_t current_long_cb; srslte_tc_interl_t interleaver[SRSLTE_NOF_TC_CB_SIZES]; - int n_iter[SRSLTE_TDEC_NPAR]; + int n_iter[SRSLTE_TDEC_MAX_NPAR]; } srslte_tdec_simd_inter_t; SRSLTE_API int srslte_tdec_simd_inter_init(srslte_tdec_simd_inter_t * h, @@ -90,17 +90,17 @@ SRSLTE_API int srslte_tdec_simd_inter_reset_cb(srslte_tdec_simd_inter_t * h, uint32_t cb_idx); SRSLTE_API void srslte_tdec_simd_inter_iteration(srslte_tdec_simd_inter_t * h, - int16_t * input[SRSLTE_TDEC_NPAR], + int16_t * input[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb); SRSLTE_API void srslte_tdec_simd_inter_decision(srslte_tdec_simd_inter_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb); SRSLTE_API void srslte_tdec_simd_inter_decision_byte(srslte_tdec_simd_inter_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb); @@ -110,8 +110,8 @@ SRSLTE_API void srslte_tdec_simd_inter_decision_byte_cb(srslte_tdec_simd_inter_t uint32_t long_cb); SRSLTE_API int srslte_tdec_simd_inter_run_all(srslte_tdec_simd_inter_t * h, - int16_t *input[SRSLTE_TDEC_NPAR], - uint8_t *output[SRSLTE_TDEC_NPAR], + int16_t *input[SRSLTE_TDEC_MAX_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_iterations, uint32_t nof_cb, uint32_t long_cb); diff --git a/lib/include/srslte/phy/phch/cqi.h b/lib/include/srslte/phy/phch/cqi.h index 593592f1c..cfc9e92e7 100644 --- a/lib/include/srslte/phy/phch/cqi.h +++ b/lib/include/srslte/phy/phch/cqi.h @@ -41,11 +41,14 @@ #include "srslte/phy/common/phy_common.h" #define SRSLTE_CQI_MAX_BITS 64 +#define SRSLTE_DIF_CQI_MAX_BITS 3 +#define SRSLTE_PMI_MAX_BITS 4 typedef struct { bool configured; uint32_t pmi_idx; uint32_t ri_idx; + bool ri_idx_present; bool simul_cqi_ack; bool format_is_subband; uint32_t subband_size; diff --git a/lib/include/srslte/phy/phch/pbch.h b/lib/include/srslte/phy/phch/pbch.h index 8489df05a..4dc7ec727 100644 --- a/lib/include/srslte/phy/phch/pbch.h +++ b/lib/include/srslte/phy/phch/pbch.h @@ -53,6 +53,8 @@ #define SRSLTE_BCH_PAYLOADCRC_LEN (SRSLTE_BCH_PAYLOAD_LEN+16) #define SRSLTE_BCH_ENCODED_LEN 3*(SRSLTE_BCH_PAYLOADCRC_LEN) +#define SRSLTE_PBCH_MAX_RE 256 // make it avx2-aligned + /* PBCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; @@ -83,12 +85,14 @@ typedef struct SRSLTE_API { } srslte_pbch_t; -SRSLTE_API int srslte_pbch_init(srslte_pbch_t *q, - srslte_cell_t cell); +SRSLTE_API int srslte_pbch_init(srslte_pbch_t *q); SRSLTE_API void srslte_pbch_free(srslte_pbch_t *q); -SRSLTE_API int srslte_pbch_decode(srslte_pbch_t *q, +SRSLTE_API int srslte_pbch_set_cell(srslte_pbch_t *q, + srslte_cell_t cell); + +SRSLTE_API int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRSLTE_MAX_PORTS], float noise_estimate, diff --git a/lib/include/srslte/phy/phch/pcfich.h b/lib/include/srslte/phy/phch/pcfich.h index 672caed2c..fbbb82c88 100644 --- a/lib/include/srslte/phy/phch/pcfich.h +++ b/lib/include/srslte/phy/phch/pcfich.h @@ -78,14 +78,12 @@ typedef struct SRSLTE_API { } srslte_pcfich_t; -SRSLTE_API int srslte_pcfich_init(srslte_pcfich_t *q, - srslte_regs_t *regs, - srslte_cell_t cell); - -SRSLTE_API int srslte_pcfich_init_multi(srslte_pcfich_t *q, - srslte_regs_t *regs, - srslte_cell_t cell, - uint32_t nof_rx_antennas); +SRSLTE_API int srslte_pcfich_init(srslte_pcfich_t *q, + uint32_t nof_rx_antennas); + +SRSLTE_API int srslte_pcfich_set_cell(srslte_pcfich_t *q, + srslte_regs_t *regs, + srslte_cell_t cell); SRSLTE_API void srslte_pcfich_free(srslte_pcfich_t *q); diff --git a/lib/include/srslte/phy/phch/pdcch.h b/lib/include/srslte/phy/phch/pdcch.h index f67d29dcb..9bb896b34 100644 --- a/lib/include/srslte/phy/phch/pdcch.h +++ b/lib/include/srslte/phy/phch/pdcch.h @@ -64,6 +64,7 @@ typedef struct SRSLTE_API { uint32_t nof_cce; uint32_t max_bits; uint32_t nof_rx_antennas; + bool is_ue; srslte_regs_t *regs; @@ -84,29 +85,16 @@ typedef struct SRSLTE_API { } srslte_pdcch_t; -SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q, - srslte_regs_t *regs, - srslte_cell_t cell); - -SRSLTE_API int srslte_pdcch_init_tx(srslte_pdcch_t *q, - srslte_regs_t *regs, - srslte_cell_t cell); - -SRSLTE_API int srslte_pdcch_init_rx(srslte_pdcch_t *q, - srslte_regs_t *regs, - srslte_cell_t cell, - uint32_t nof_rx_antennas); - -SRSLTE_API int srslte_pdcch_init_multi(srslte_pdcch_t *q, - srslte_regs_t *regs, - srslte_cell_t cell, - uint32_t nof_rx_antennas); - -SRSLTE_API int srslte_pdcch_init_txrx(srslte_pdcch_t *q, - srslte_regs_t *regs, - srslte_cell_t cell, - uint32_t nof_rx_antennas, - bool isReceiver); +SRSLTE_API int srslte_pdcch_init_ue(srslte_pdcch_t *q, + uint32_t max_prb, + uint32_t nof_rx_antennas); + +SRSLTE_API int srslte_pdcch_init_enb(srslte_pdcch_t *q, + uint32_t max_prb); + +SRSLTE_API int srslte_pdcch_set_cell(srslte_pdcch_t *q, + srslte_regs_t *regs, + srslte_cell_t cell); SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q); diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 44ed161e8..459bcc209 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -49,6 +49,7 @@ typedef struct { srslte_sequence_t seq[SRSLTE_MAX_CODEWORDS][SRSLTE_NSUBFRAMES_X_FRAME]; + uint32_t cell_id; bool sequence_generated; } srslte_pdsch_user_t; @@ -57,9 +58,13 @@ typedef struct SRSLTE_API { srslte_cell_t cell; uint32_t nof_rx_antennas; - + uint32_t last_nof_iterations[SRSLTE_MAX_CODEWORDS]; + uint32_t max_re; - + + uint16_t ue_rnti; + bool is_ue; + /* buffers */ // void buffers are shared for tx and rx cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */ @@ -73,21 +78,27 @@ typedef struct SRSLTE_API { // This is to generate the scrambling seq for multiple CRNTIs srslte_pdsch_user_t **users; - + + srslte_sequence_t tmp_seq; + srslte_sch_t dl_sch; } srslte_pdsch_t; -SRSLTE_API int srslte_pdsch_init_tx(srslte_pdsch_t *q, - srslte_cell_t cell); -SRSLTE_API int srslte_pdsch_init_rx(srslte_pdsch_t *q, - srslte_cell_t cell, - uint32_t nof_antennas); +SRSLTE_API int srslte_pdsch_init_ue(srslte_pdsch_t *q, + uint32_t max_prb, + uint32_t nof_rx_antennas); + +SRSLTE_API int srslte_pdsch_init_enb(srslte_pdsch_t *q, + uint32_t max_prb); SRSLTE_API void srslte_pdsch_free(srslte_pdsch_t *q); -SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q, +SRSLTE_API int srslte_pdsch_set_cell(srslte_pdsch_t *q, + srslte_cell_t cell); + +SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti); SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q, @@ -139,10 +150,12 @@ SRSLTE_API int srslte_pdsch_cn_compute(srslte_pdsch_t *q, uint32_t nof_ce, float *cn); -SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter); +SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, + uint32_t max_iter); -SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); +SRSLTE_API float srslte_pdsch_last_noi(srslte_pdsch_t *q); -SRSLTE_API uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q); +SRSLTE_API uint32_t srslte_pdsch_last_noi_cw(srslte_pdsch_t *q, + uint32_t cw_idx); #endif diff --git a/lib/include/srslte/phy/phch/phich.h b/lib/include/srslte/phy/phch/phich.h index 18454a2d5..0645e22b1 100644 --- a/lib/include/srslte/phy/phch/phich.h +++ b/lib/include/srslte/phy/phch/phich.h @@ -85,26 +85,24 @@ typedef struct SRSLTE_API { } srslte_phich_t; -SRSLTE_API int srslte_phich_init(srslte_phich_t *q, - srslte_regs_t *regs, - srslte_cell_t cell); - -SRSLTE_API int srslte_phich_init_multi(srslte_phich_t *q, - srslte_regs_t *regs, - srslte_cell_t cell, - uint32_t nof_rx_antennas); +SRSLTE_API int srslte_phich_init(srslte_phich_t *q, + uint32_t nof_rx_antennas); SRSLTE_API void srslte_phich_free(srslte_phich_t *q); -SRSLTE_API void srslte_phich_calc(srslte_phich_t *q, +SRSLTE_API int srslte_phich_set_cell(srslte_phich_t *q, + srslte_regs_t *regs, + srslte_cell_t cell); + +SRSLTE_API void srslte_phich_calc(srslte_phich_t *q, uint32_t n_prb_lowest, uint32_t n_dmrs, uint32_t *ngroup, uint32_t *nseq); SRSLTE_API int srslte_phich_decode(srslte_phich_t *q, - cf_t *slot_symbols, - cf_t *ce[SRSLTE_MAX_PORTS], + cf_t *slot_symbols[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t ngroup, uint32_t nseq, @@ -112,16 +110,6 @@ SRSLTE_API int srslte_phich_decode(srslte_phich_t *q, uint8_t *ack, float *distance); -SRSLTE_API int srslte_phich_decode_multi(srslte_phich_t *q, - cf_t *slot_symbols[SRSLTE_MAX_PORTS], - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - float noise_estimate, - uint32_t ngroup, - uint32_t nseq, - uint32_t nsubframe, - uint8_t *ack, - float *distance); - SRSLTE_API int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, diff --git a/lib/include/srslte/phy/phch/pmch.h b/lib/include/srslte/phy/phch/pmch.h new file mode 100644 index 000000000..dfff956f1 --- /dev/null +++ b/lib/include/srslte/phy/phch/pmch.h @@ -0,0 +1,152 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: pmch.h + * + * Description: Physical multicast channel + * + * Reference: 3GPP TS 36.211 version 10.0.0 Release 10 Sec. 6.5 + *****************************************************************************/ + +#ifndef PMCH_ +#define PMCH_ + +#include "srslte/config.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/mimo/layermap.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/regs.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/common/sequence.h" + +typedef struct { + srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; +} srslte_pmch_seq_t; + +typedef struct SRSLTE_API { + srslte_cbsegm_t cb_segm; + srslte_ra_dl_grant_t grant; + srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]; + uint32_t sf_idx; +} srslte_pmch_cfg_t; + +/* PMCH object */ +typedef struct SRSLTE_API { + srslte_cell_t cell; + + uint32_t nof_rx_antennas; + + uint32_t max_re; + + /* buffers */ + // void buffers are shared for tx and rx + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + cf_t *symbols[SRSLTE_MAX_PORTS]; + cf_t *x[SRSLTE_MAX_PORTS]; + cf_t *d; + void *e; + + /* tx & rx objects */ + srslte_modem_table_t mod[4]; + + // This is to generate the scrambling seq for multiple MBSFN Area IDs + srslte_pmch_seq_t **seqs; + + srslte_sch_t dl_sch; + +} srslte_pmch_t; + + +SRSLTE_API int srslte_pmch_init(srslte_pmch_t *q, + uint32_t max_prb); + +SRSLTE_API int srslte_pmch_init_multi(srslte_pmch_t *q, + uint32_t max_prb, + uint32_t nof_rx_antennas); + +SRSLTE_API void srslte_pmch_free(srslte_pmch_t *q); + + + +SRSLTE_API int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id); + +SRSLTE_API void srslte_pmch_free_area_id(srslte_pmch_t *q, uint16_t area_id); + + + +SRSLTE_API int srslte_pmch_get(srslte_pmch_t *q, cf_t *sf_symbols, cf_t *symbols, uint32_t lstart); + +SRSLTE_API int srslte_pmch_put(srslte_pmch_t *q, cf_t *symbols, cf_t *sf_symbols, uint32_t lstart); + +SRSLTE_API int srslte_pmch_cp(srslte_pmch_t *q, cf_t *input, cf_t *output, uint32_t lstart_grant, bool put); + + + +SRSLTE_API float srslte_pmch_coderate(uint32_t tbs, + uint32_t nof_re); + + +SRSLTE_API int srslte_pmch_cfg(srslte_pdsch_cfg_t *cfg, + srslte_cell_t cell, + srslte_ra_dl_grant_t *grant, + uint32_t cfi, + uint32_t sf_idx); + +SRSLTE_API int srslte_pmch_encode(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_tx_t *softbuffer, + uint8_t *data, + uint16_t area_id, + cf_t *sf_symbols[SRSLTE_MAX_PORTS]); + +SRSLTE_API int srslte_pmch_decode(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols, + cf_t *ce[SRSLTE_MAX_PORTS], + float noise_estimate, + uint16_t area_id, + uint8_t *data); + +SRSLTE_API int srslte_pmch_decode_multi(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + float noise_estimate, + uint16_t area_id, + uint8_t *data); + +SRSLTE_API float srslte_pmch_average_noi(srslte_pmch_t *q); + +SRSLTE_API uint32_t srslte_pmch_last_noi(srslte_pmch_t *q); + +#endif diff --git a/lib/include/srslte/phy/phch/prach.h b/lib/include/srslte/phy/phch/prach.h index a08256a57..3e3df01bb 100644 --- a/lib/include/srslte/phy/phch/prach.h +++ b/lib/include/srslte/phy/phch/prach.h @@ -44,6 +44,8 @@ #include "srslte/phy/common/phy_common.h" +#define SRSLTE_PRACH_MAX_LEN (2*24576+21024) // Maximum Tcp + Tseq + /** Generation and detection of RACH signals for uplink. * Currently only supports preamble formats 0-3. * Does not currently support high speed flag. @@ -60,6 +62,8 @@ typedef struct SRSLTE_API { uint32_t N_ifft_ul; // IFFT size for uplink uint32_t N_ifft_prach; // IFFT size for PRACH generation + uint32_t max_N_ifft_ul; + // Working parameters uint32_t N_zc; // PRACH sequence length uint32_t N_cs; // Cyclic shift size @@ -82,12 +86,12 @@ typedef struct SRSLTE_API { float *corr; // PRACH IFFT - srslte_dft_plan_t *fft; - srslte_dft_plan_t *ifft; + srslte_dft_plan_t fft; + srslte_dft_plan_t ifft; // ZC-sequence FFT and IFFT - srslte_dft_plan_t *zc_fft; - srslte_dft_plan_t *zc_ifft; + srslte_dft_plan_t zc_fft; + srslte_dft_plan_t zc_ifft; cf_t *signal_fft; float detect_factor; @@ -129,11 +133,14 @@ SRSLTE_API void srslte_prach_sf_config(uint32_t config_idx, srslte_prach_sf_config_t *sf_config); SRSLTE_API int srslte_prach_init(srslte_prach_t *p, - uint32_t N_ifft_ul, - uint32_t config_idx, - uint32_t root_seq_index, - bool high_speed_flag, - uint32_t zero_corr_zone_config); + uint32_t max_N_ifft_ul); + +SRSLTE_API int srslte_prach_set_cell(srslte_prach_t *p, + uint32_t N_ifft_ul, + uint32_t config_idx, + uint32_t root_seq_index, + bool high_speed_flag, + uint32_t zero_corr_zone_config); SRSLTE_API int srslte_prach_init_cfg(srslte_prach_t* p, srslte_prach_cfg_t* cfg, diff --git a/lib/include/srslte/phy/phch/pucch.h b/lib/include/srslte/phy/phch/pucch.h index da0b5b81e..8aa1495c8 100644 --- a/lib/include/srslte/phy/phch/pucch.h +++ b/lib/include/srslte/phy/phch/pucch.h @@ -45,7 +45,7 @@ #define SRSLTE_PUCCH_N_SEQ 12 #define SRSLTE_PUCCH2_NOF_BITS SRSLTE_UCI_CQI_CODED_PUCCH_B #define SRSLTE_PUCCH_MAX_BITS SRSLTE_CQI_MAX_BITS -#define SRSLTE_PUCCH_MAX_SYMBOLS 120 +#define SRSLTE_PUCCH_MAX_SYMBOLS 128 typedef enum SRSLTE_API { SRSLTE_PUCCH_FORMAT_1 = 0, @@ -115,12 +115,14 @@ typedef struct SRSLTE_API { }srslte_pucch_t; -SRSLTE_API int srslte_pucch_init(srslte_pucch_t *q, - srslte_cell_t cell); +SRSLTE_API int srslte_pucch_init(srslte_pucch_t *q); SRSLTE_API void srslte_pucch_free(srslte_pucch_t *q); -SRSLTE_API bool srslte_pucch_set_cfg(srslte_pucch_t* q, +SRSLTE_API int srslte_pucch_set_cell(srslte_pucch_t *q, + srslte_cell_t cell); + +SRSLTE_API bool srslte_pucch_set_cfg(srslte_pucch_t* q, srslte_pucch_cfg_t* cfg, bool group_hopping_en); diff --git a/lib/include/srslte/phy/phch/pusch.h b/lib/include/srslte/phy/phch/pusch.h index e5ee43995..2328c8ff3 100644 --- a/lib/include/srslte/phy/phch/pusch.h +++ b/lib/include/srslte/phy/phch/pusch.h @@ -62,13 +62,16 @@ typedef struct { typedef struct { srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; - bool sequences_generated; -} srslte_pusch_user_t; + uint32_t cell_id; + bool sequence_generated; +} srslte_pusch_user_t; /* PUSCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; + bool is_ue; + uint16_t ue_rnti; uint32_t max_re; srslte_dft_precoding_t dft_precoding; @@ -96,12 +99,18 @@ typedef struct SRSLTE_API { }srslte_pusch_t; -SRSLTE_API int srslte_pusch_init(srslte_pusch_t *q, - srslte_cell_t cell); +SRSLTE_API int srslte_pusch_init_ue(srslte_pusch_t *q, + uint32_t max_prb); + +SRSLTE_API int srslte_pusch_init_enb(srslte_pusch_t *q, + uint32_t max_prb); SRSLTE_API void srslte_pusch_free(srslte_pusch_t *q); -SRSLTE_API int srslte_pusch_cfg(srslte_pusch_t *q, +SRSLTE_API int srslte_pusch_set_cell(srslte_pusch_t *q, + srslte_cell_t cell); + +SRSLTE_API int srslte_pusch_cfg(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_ra_ul_grant_t *grant, srslte_uci_cfg_t *uci_cfg, @@ -114,7 +123,7 @@ SRSLTE_API int srslte_pusch_cfg(srslte_pusch_t *q, SRSLTE_API int srslte_pusch_set_rnti(srslte_pusch_t *q, uint16_t rnti); -SRSLTE_API void srslte_pusch_clear_rnti(srslte_pusch_t *q, +SRSLTE_API void srslte_pusch_free_rnti(srslte_pusch_t *q, uint16_t rnti); SRSLTE_API int srslte_pusch_encode(srslte_pusch_t *q, diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index 9f31a0218..3039455ed 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -103,11 +103,17 @@ typedef struct SRSLTE_API { bool prb_idx[2][SRSLTE_MAX_PRB]; uint32_t nof_prb; uint32_t Qm[SRSLTE_MAX_CODEWORDS]; + uint32_t Qm2[SRSLTE_MAX_CODEWORDS]; srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS]; + srslte_ra_mcs_t mcs2[SRSLTE_MAX_CODEWORDS]; uint32_t nof_tb; + srslte_sf_t sf_type; + bool tb_en[SRSLTE_MAX_CODEWORDS]; uint32_t pinfo; } srslte_ra_dl_grant_t; +#define SRSLTE_RA_DL_GRANT_NOF_TB(G) ((((G)->tb_en[0])?1:0)+(((G)->tb_en[1])?1:0)) + /** Unpacked DCI message for DL grant */ typedef struct SRSLTE_API { @@ -288,4 +294,9 @@ SRSLTE_API void srslte_ra_pusch_fprint(FILE *f, SRSLTE_API void srslte_ra_ul_grant_fprint(FILE *f, srslte_ra_ul_grant_t *grant); +SRSLTE_API int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb); + +SRSLTE_API int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb); + + #endif /* RB_ALLOC_H_ */ diff --git a/lib/include/srslte/phy/phch/sch.h b/lib/include/srslte/phy/phch/sch.h index a03387448..e8066e4cd 100644 --- a/lib/include/srslte/phy/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -56,10 +56,9 @@ /* DL-SCH AND UL-SCH common functions */ typedef struct SRSLTE_API { - uint32_t max_iterations; - uint32_t nof_iterations; - float average_nof_iterations; - + uint32_t max_iterations; + uint32_t nof_iterations; + /* buffers */ uint8_t *cb_in; uint8_t *parity_bits; @@ -77,6 +76,7 @@ typedef struct SRSLTE_API { srslte_uci_cqi_pusch_t uci_cqi; } srslte_sch_t; +#include "srslte/phy/phch/pmch.h" SRSLTE_API int srslte_sch_init(srslte_sch_t *q); @@ -86,8 +86,6 @@ SRSLTE_API void srslte_sch_free(srslte_sch_t *q); SRSLTE_API void srslte_sch_set_max_noi(srslte_sch_t *q, uint32_t max_iterations); -SRSLTE_API float srslte_sch_average_noi(srslte_sch_t *q); - SRSLTE_API uint32_t srslte_sch_last_noi(srslte_sch_t *q); SRSLTE_API int srslte_dlsch_encode(srslte_sch_t *q, diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index 01eae8e89..ff315384e 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -64,6 +64,10 @@ typedef struct SRSLTE_API { typedef struct SRSLTE_API { uint8_t uci_cqi[SRSLTE_CQI_MAX_BITS]; uint32_t uci_cqi_len; + uint8_t uci_dif_cqi[SRSLTE_DIF_CQI_MAX_BITS]; + uint32_t uci_dif_cqi_len; + uint8_t uci_pmi[SRSLTE_PMI_MAX_BITS]; + uint8_t uci_pmi_len; uint8_t uci_ri; // Only 1-bit supported for RI uint32_t uci_ri_len; uint8_t uci_ack; // 1st codeword bit for HARQ-ACK @@ -119,8 +123,9 @@ SRSLTE_API int srslte_uci_decode_cqi_pusch(srslte_uci_cqi_pusch_t *q, bool *cqi_ack); SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, - uint8_t data, - uint32_t O_cqi, + uint8_t acks[2], + uint32_t nof_acks, + uint32_t O_cqi, float beta, uint32_t H_prime_total, srslte_uci_bit_t *ri_bits); @@ -132,7 +137,8 @@ SRSLTE_API int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, uint32_t H_prime_total, uint32_t O_cqi, srslte_uci_bit_t *ack_bits, - uint8_t *data); + uint8_t acks[2], + uint32_t nof_acks); SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, uint8_t data, diff --git a/lib/include/srslte/phy/resampling/interp.h b/lib/include/srslte/phy/resampling/interp.h index 0bc2a6e39..508b6e957 100644 --- a/lib/include/srslte/phy/resampling/interp.h +++ b/lib/include/srslte/phy/resampling/interp.h @@ -67,7 +67,8 @@ SRSLTE_API void srslte_interp_linear_f(float *input, typedef struct { cf_t *diff_vec; - uint32_t vector_len; + uint32_t vector_len; + uint32_t max_vector_len; } srslte_interp_linsrslte_vec_t; SRSLTE_API int srslte_interp_linear_vector_init(srslte_interp_linsrslte_vec_t *q, @@ -75,6 +76,9 @@ SRSLTE_API int srslte_interp_linear_vector_init(srslte_interp_linsrslte_vec_t *q SRSLTE_API void srslte_interp_linear_vector_free(srslte_interp_linsrslte_vec_t *q); +SRSLTE_API int srslte_interp_linear_vector_resize(srslte_interp_linsrslte_vec_t *q, + uint32_t vector_len); + SRSLTE_API void srslte_interp_linear_vector(srslte_interp_linsrslte_vec_t *q, cf_t *in0, cf_t *in1, @@ -107,7 +111,9 @@ typedef struct { cf_t *diff_vec2; float *ramp; uint32_t vector_len; - uint32_t M; + uint32_t M; + uint32_t max_vector_len; + uint32_t max_M; } srslte_interp_lin_t; SRSLTE_API int srslte_interp_linear_init(srslte_interp_lin_t *q, @@ -116,6 +122,10 @@ SRSLTE_API int srslte_interp_linear_init(srslte_interp_lin_t *q, SRSLTE_API void srslte_interp_linear_free(srslte_interp_lin_t *q); +SRSLTE_API int srslte_interp_linear_resize(srslte_interp_lin_t *q, + uint32_t vector_len, + uint32_t M); + SRSLTE_API void srslte_interp_linear_offset(srslte_interp_lin_t *q, cf_t *input, cf_t *output, diff --git a/lib/include/srslte/phy/sync/cfo.h b/lib/include/srslte/phy/sync/cfo.h index 642e81fc4..fd2ab4d83 100644 --- a/lib/include/srslte/phy/sync/cfo.h +++ b/lib/include/srslte/phy/sync/cfo.h @@ -49,6 +49,7 @@ typedef struct SRSLTE_API { float last_freq; float tol; int nsamples; + int max_samples; srslte_cexptab_t tab; cf_t *cur_cexp; }srslte_cfo_t; @@ -58,8 +59,8 @@ SRSLTE_API int srslte_cfo_init(srslte_cfo_t *h, SRSLTE_API void srslte_cfo_free(srslte_cfo_t *h); -SRSLTE_API int srslte_cfo_realloc(srslte_cfo_t *h, - uint32_t samples); +SRSLTE_API int srslte_cfo_resize(srslte_cfo_t *h, + uint32_t samples); SRSLTE_API void srslte_cfo_set_tol(srslte_cfo_t *h, float tol); diff --git a/lib/include/srslte/phy/sync/cp.h b/lib/include/srslte/phy/sync/cp.h index 211479030..9daf7d4f6 100644 --- a/lib/include/srslte/phy/sync/cp.h +++ b/lib/include/srslte/phy/sync/cp.h @@ -35,6 +35,7 @@ typedef struct { cf_t *corr; uint32_t symbol_sz; + uint32_t max_symbol_sz; } srslte_cp_synch_t; SRSLTE_API int srslte_cp_synch_init(srslte_cp_synch_t *q, @@ -42,6 +43,9 @@ SRSLTE_API int srslte_cp_synch_init(srslte_cp_synch_t *q, SRSLTE_API void srslte_cp_synch_free(srslte_cp_synch_t *q); +SRSLTE_API int srslte_cp_synch_resize(srslte_cp_synch_t *q, + uint32_t symbol_sz); + SRSLTE_API uint32_t srslte_cp_synch(srslte_cp_synch_t *q, cf_t *input, uint32_t max_offset, diff --git a/lib/include/srslte/phy/sync/pss.h b/lib/include/srslte/phy/sync/pss.h index f18c5b6af..9760a178c 100644 --- a/lib/include/srslte/phy/sync/pss.h +++ b/lib/include/srslte/phy/sync/pss.h @@ -79,6 +79,10 @@ typedef struct SRSLTE_API { #endif int decimate; + + uint32_t max_frame_size; + uint32_t max_fft_size; + uint32_t frame_size; uint32_t N_id_2; uint32_t fft_size; @@ -113,6 +117,10 @@ SRSLTE_API int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, int cfo_i, int decimate); +SRSLTE_API int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, + uint32_t fft_size, + int offset); + SRSLTE_API int srslte_pss_synch_init(srslte_pss_synch_t *q, uint32_t frame_size); diff --git a/lib/include/srslte/phy/sync/sss.h b/lib/include/srslte/phy/sync/sss.h index aca57e860..35eedac8f 100644 --- a/lib/include/srslte/phy/sync/sss.h +++ b/lib/include/srslte/phy/sync/sss.h @@ -70,6 +70,7 @@ typedef struct SRSLTE_API { srslte_dft_plan_t dftp_input; uint32_t fft_size; + uint32_t max_fft_size; float corr_peak_threshold; uint32_t symbol_sz; @@ -89,7 +90,7 @@ typedef struct SRSLTE_API { SRSLTE_API int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size); -SRSLTE_API int srslte_sss_synch_realloc(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size); SRSLTE_API void srslte_sss_synch_free(srslte_sss_synch_t *q); diff --git a/lib/include/srslte/phy/sync/sync.h b/lib/include/srslte/phy/sync/sync.h index ab22d64fc..1c70b2449 100644 --- a/lib/include/srslte/phy/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -75,6 +75,8 @@ typedef struct SRSLTE_API { uint32_t frame_size; uint32_t max_offset; bool enable_cfo_corr; + bool mean_cfo2_isunset; + bool mean_cfo_isunset; float mean_cfo; float mean_cfo2; int cfo_i; @@ -85,6 +87,7 @@ typedef struct SRSLTE_API { uint32_t cp_len; srslte_cfo_t cfocorr; srslte_cfo_t cfocorr2; + float current_cfo_tol; sss_alg_t sss_alg; bool detect_cp; bool sss_en; @@ -97,6 +100,8 @@ typedef struct SRSLTE_API { float M_ext_avg; cf_t *temp; + uint32_t max_frame_size; + }srslte_sync_t; typedef enum { @@ -121,6 +126,11 @@ SRSLTE_API int srslte_sync_init_decim(srslte_sync_t *q, SRSLTE_API void srslte_sync_free(srslte_sync_t *q); +SRSLTE_API int srslte_sync_resize(srslte_sync_t *q, + uint32_t frame_size, + uint32_t max_offset, + uint32_t fft_size); + SRSLTE_API void srslte_sync_reset(srslte_sync_t *q); /* Finds a correlation peak in the input signal around position find_offset */ @@ -138,6 +148,9 @@ SRSLTE_API srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, SRSLTE_API void srslte_sync_set_threshold(srslte_sync_t *q, float threshold); +SRSLTE_API void srslte_sync_set_cfo_tol(srslte_sync_t *q, + float tol); + /* Gets the subframe idx (0 or 5) */ SRSLTE_API uint32_t srslte_sync_get_sf_idx(srslte_sync_t *q); diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index d0723fae7..0b0fc44d2 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -48,6 +48,7 @@ #include "srslte/phy/phch/pcfich.h" #include "srslte/phy/phch/pdcch.h" #include "srslte/phy/phch/pdsch.h" +#include "srslte/phy/phch/pmch.h" #include "srslte/phy/phch/pdsch_cfg.h" #include "srslte/phy/phch/phich.h" #include "srslte/phy/phch/ra.h" @@ -76,14 +77,17 @@ typedef struct SRSLTE_API { srslte_pcfich_t pcfich; srslte_pdcch_t pdcch; srslte_pdsch_t pdsch; + srslte_pmch_t pmch; srslte_phich_t phich; srslte_regs_t regs; srslte_ofdm_t fft; + srslte_ofdm_t fft_mbsfn; srslte_chest_dl_t chest; srslte_cfo_t sfo_correct; - srslte_pdsch_cfg_t pdsch_cfg; + srslte_pdsch_cfg_t pdsch_cfg; + srslte_pdsch_cfg_t pmch_cfg; srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_dci_t dl_dci; srslte_cell_t cell; @@ -103,9 +107,14 @@ typedef struct SRSLTE_API { srslte_dci_format_t dci_format; uint64_t pkt_errors; uint64_t pkts_total; + uint64_t pdsch_pkt_errors; + uint64_t pdsch_pkts_total; + uint64_t pmch_pkt_errors; + uint64_t pmch_pkts_total; uint64_t nof_detected; uint16_t current_rnti; + uint16_t current_mbsfn_area_id; dci_blind_search_t current_ss_ue[3][10]; dci_blind_search_t current_ss_common[3]; srslte_dci_location_t last_location; @@ -119,19 +128,34 @@ typedef struct SRSLTE_API { /* This function shall be called just after the initial synchronization */ SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q, - srslte_cell_t cell, + uint32_t max_prb, uint32_t nof_rx_antennas); SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q); -SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], +SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, + srslte_cell_t cell); + +int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + uint32_t sf_idx, + uint32_t *cfi); + +SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, - uint32_t *cfi); + uint32_t *cfi, + srslte_sf_t sf_type); + -SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, +int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, + uint32_t sf_idx, + uint32_t *cfi); + +SRSLTE_API int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, - uint32_t *cfi); + uint32_t *cfi, + srslte_sf_t sf_type); SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, @@ -181,13 +205,25 @@ SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, uint16_t rnti, bool acks[SRSLTE_MAX_CODEWORDS]); +/* Used by example applications - full PMCH decode for a given MBSFN area ID + * srslte_ue_dl_decode_fft_estimate_multi, + * srslte_chest_dl_get_noise_estimate, + * srslte_ue_dl_cfg_grant, + * srslte_pmch_decode_multi + */ +SRSLTE_API int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, + cf_t *input[SRSLTE_MAX_PORTS], + uint8_t *data, + uint32_t tti); + + SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, - uint32_t *ri, - uint32_t *pmi, + uint8_t *ri, + uint8_t *pmi, float *current_sinr); SRSLTE_API int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, - uint32_t *ri, + uint8_t *ri, float *cn); SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, @@ -200,6 +236,15 @@ SRSLTE_API void srslte_ue_dl_reset(srslte_ue_dl_t *q); SRSLTE_API void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti); +/* Generate signals if required, store in q->current_mbsfn_area_id */ +SRSLTE_API int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q, + uint16_t mbsfn_area_id); + +SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, + uint8_t non_mbsfn_region_length); + + + SRSLTE_API void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuffer, uint32_t tti, diff --git a/lib/include/srslte/phy/ue/ue_mib.h b/lib/include/srslte/phy/ue/ue_mib.h index abefa014f..5d2ef14fa 100644 --- a/lib/include/srslte/phy/ue/ue_mib.h +++ b/lib/include/srslte/phy/ue/ue_mib.h @@ -79,10 +79,13 @@ typedef struct SRSLTE_API { } srslte_ue_mib_t; SRSLTE_API int srslte_ue_mib_init(srslte_ue_mib_t *q, - srslte_cell_t cell); + uint32_t max_prb); SRSLTE_API void srslte_ue_mib_free(srslte_ue_mib_t *q); +SRSLTE_API int srslte_ue_mib_set_cell(srslte_ue_mib_t * q, + srslte_cell_t cell); + SRSLTE_API void srslte_ue_mib_reset(srslte_ue_mib_t * q); SRSLTE_API int srslte_ue_mib_decode(srslte_ue_mib_t * q, @@ -104,21 +107,17 @@ typedef struct { uint32_t nof_rx_antennas; } srslte_ue_mib_sync_t; -SRSLTE_API int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, - uint32_t cell_id, - srslte_cp_t cp, - int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t *), - void *stream_handler); - -SRSLTE_API int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, - uint32_t cell_id, - srslte_cp_t cp, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t *), +SRSLTE_API int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t *), uint32_t nof_rx_antennas, void *stream_handler); SRSLTE_API void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q); +SRSLTE_API int srslte_ue_mib_sync_set_cell(srslte_ue_mib_sync_t *q, + uint32_t cell_id, + srslte_cp_t cp); + SRSLTE_API void srslte_ue_mib_sync_reset(srslte_ue_mib_sync_t * q); SRSLTE_API int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q, diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index 3570e5a30..bd280acd0 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -69,6 +69,8 @@ typedef enum SRSLTE_API { SF_FIND, SF_TRACK} srslte_ue_sync_state_t; typedef struct SRSLTE_API { srslte_sync_t sfind; srslte_sync_t strack; + + uint32_t max_prb; srslte_agc_t agc; bool do_agc; @@ -125,22 +127,25 @@ typedef struct SRSLTE_API { } srslte_ue_sync_t; SRSLTE_API int srslte_ue_sync_init(srslte_ue_sync_t *q, - srslte_cell_t cell, + uint32_t max_prb, + bool search_cell, int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*), void *stream_handler); -SRSLTE_API int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, - srslte_cell_t cell, +SRSLTE_API int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, + uint32_t max_prb, + bool search_cell, int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), uint32_t nof_rx_antennas, void *stream_handler); -SRSLTE_API int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, - srslte_cell_t cell, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), - uint32_t nof_rx_antennas, - void *stream_handler, - int decimate); +SRSLTE_API int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, + uint32_t max_prb, + bool search_cell, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler, + int decimate); SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, @@ -157,6 +162,9 @@ SRSLTE_API int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, SRSLTE_API void srslte_ue_sync_free(srslte_ue_sync_t *q); +SRSLTE_API int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, + srslte_cell_t cell); + SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(void*, double), float init_gain_value); @@ -173,6 +181,9 @@ SRSLTE_API int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, SRSLTE_API int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]); +SRSLTE_API void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, + float tol); + SRSLTE_API void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo); diff --git a/lib/include/srslte/phy/ue/ue_ul.h b/lib/include/srslte/phy/ue/ue_ul.h index 2afa8068a..3492180e3 100644 --- a/lib/include/srslte/phy/ue/ue_ul.h +++ b/lib/include/srslte/phy/ue/ue_ul.h @@ -75,7 +75,8 @@ typedef struct SRSLTE_API { bool normalize_en; bool cfo_en; - + + float current_cfo_tol; float current_cfo; srslte_pucch_format_t last_pucch_format; @@ -106,15 +107,21 @@ typedef struct SRSLTE_API { /* This function shall be called just after the initial synchronization */ -SRSLTE_API int srslte_ue_ul_init(srslte_ue_ul_t *q, - srslte_cell_t cell); +SRSLTE_API int srslte_ue_ul_init(srslte_ue_ul_t *q, + uint32_t max_prb); SRSLTE_API void srslte_ue_ul_free(srslte_ue_ul_t *q); -SRSLTE_API void srslte_ue_ul_set_cfo(srslte_ue_ul_t *q, +SRSLTE_API int srslte_ue_ul_set_cell(srslte_ue_ul_t *q, + srslte_cell_t cell); + +SRSLTE_API void srslte_ue_ul_set_cfo_tol(srslte_ue_ul_t *q, + float tol); + +SRSLTE_API void srslte_ue_ul_set_cfo(srslte_ue_ul_t *q, float cur_cfo); -SRSLTE_API void srslte_ue_ul_set_cfo_enable(srslte_ue_ul_t *q, +SRSLTE_API void srslte_ue_ul_set_cfo_enable(srslte_ue_ul_t *q, bool enabled); SRSLTE_API void srslte_ue_ul_set_normalization(srslte_ue_ul_t *q, diff --git a/lib/include/srslte/phy/utils/convolution.h b/lib/include/srslte/phy/utils/convolution.h index 27ea7e590..fcb321ce5 100644 --- a/lib/include/srslte/phy/utils/convolution.h +++ b/lib/include/srslte/phy/utils/convolution.h @@ -46,6 +46,8 @@ typedef struct SRSLTE_API { uint32_t input_len; uint32_t filter_len; uint32_t output_len; + uint32_t max_input_len; + uint32_t max_filter_len; srslte_dft_plan_t input_plan; srslte_dft_plan_t filter_plan; srslte_dft_plan_t output_plan; @@ -58,6 +60,9 @@ SRSLTE_API int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_t filter_len); +SRSLTE_API int srslte_conv_fft_cc_replan(srslte_conv_fft_cc_t *q, + uint32_t input_len, + uint32_t filter_len); SRSLTE_API void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q); diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index 849c1c0e9..329dd825a 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -57,8 +57,7 @@ namespace srslte { bzero(&end_of_burst_time, sizeof(srslte_timestamp_t)); bzero(zeros, burst_preamble_max_samples*sizeof(cf_t)); - sf_len = 0; - burst_preamble_sec = 0; + burst_preamble_sec = 0; is_start_of_burst = false; burst_preamble_samples = 0; burst_preamble_time_rounded = 0; @@ -72,13 +71,12 @@ namespace srslte { rx_freq = 0; trace_enabled = false; tti = 0; - agc_enabled = false; - offset = 0; - + agc_enabled = false; }; bool init(char *args = NULL, char *devname = NULL); - void stop(); + void stop(); + void reset(); bool start_agc(bool tx_gain_same_rx); void set_burst_preamble(double preamble_us); @@ -98,15 +96,16 @@ namespace srslte { void set_tx_rx_gain_offset(float offset); double set_rx_gain_th(float gain); - void set_tx_freq(float freq); - void set_rx_freq(float freq); + void set_freq_offset(double freq); + void set_tx_freq(double freq); + void set_rx_freq(double freq); - float get_tx_freq(); - float get_rx_freq(); + double get_tx_freq(); + double get_rx_freq(); - void set_master_clock_rate(float rate); - void set_tx_srate(float srate); - void set_rx_srate(float srate); + void set_master_clock_rate(double rate); + void set_tx_srate(double srate); + void set_rx_srate(double srate); float get_tx_gain(); float get_rx_gain(); @@ -122,9 +121,8 @@ namespace srslte { void stop_rx(); void set_tti(uint32_t tti); - void tx_offset(int offset); - void set_tti_len(uint32_t sf_len); - uint32_t get_tti_len(); + + bool is_first_of_burst(); void register_error_handler(srslte_rf_error_handler_t h); @@ -156,9 +154,9 @@ namespace srslte { const static double blade_default_burst_preamble_sec = 0.0; const static double blade_default_tx_adv_samples = 27; - const static double blade_default_tx_adv_offset_sec = 1e-6; - - float tx_freq, rx_freq; + const static double blade_default_tx_adv_offset_sec = 1e-6; + + double tx_freq, rx_freq, freq_offset; trace tr_local_time; trace tr_usrp_time; @@ -167,8 +165,10 @@ namespace srslte { bool trace_enabled; uint32_t tti; bool agc_enabled; - int offset; - uint32_t sf_len; + + char saved_args[128]; + char saved_devname[128]; + }; } diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index abdbeeaea..ce6ece151 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -50,6 +50,9 @@ public: uint8_t direction_); void stop(); + // GW interface + bool is_drb_enabled(uint32_t lcid); + // RRC interface void reset(); void write_sdu(uint32_t lcid, byte_buffer_t *sdu); diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h index a92c9a0ad..afbd18544 100644 --- a/lib/include/srslte/upper/rlc_am.h +++ b/lib/include/srslte/upper/rlc_am.h @@ -78,6 +78,7 @@ public: mac_interface_timers *mac_timers); void configure(srslte_rlc_config_t cnfg); void reset(); + void stop(); void empty_queue(); rlc_mode_t get_mode(); diff --git a/lib/include/srslte/upper/rlc_common.h b/lib/include/srslte/upper/rlc_common.h index c68e3e6f3..494cc6174 100644 --- a/lib/include/srslte/upper/rlc_common.h +++ b/lib/include/srslte/upper/rlc_common.h @@ -158,6 +158,7 @@ public: srslte::mac_interface_timers *mac_timers_) = 0; virtual void configure(srslte_rlc_config_t cnfg) = 0; virtual void reset() = 0; + virtual void stop() = 0; virtual void empty_queue() = 0; virtual rlc_mode_t get_mode() = 0; diff --git a/lib/include/srslte/upper/rlc_entity.h b/lib/include/srslte/upper/rlc_entity.h index 651af72fb..e9c41fa30 100644 --- a/lib/include/srslte/upper/rlc_entity.h +++ b/lib/include/srslte/upper/rlc_entity.h @@ -56,6 +56,7 @@ public: void configure(srslte_rlc_config_t cnfg); void reset(); + void stop(); void empty_queue(); bool active(); diff --git a/lib/include/srslte/upper/rlc_tm.h b/lib/include/srslte/upper/rlc_tm.h index def968a92..4a55e33dd 100644 --- a/lib/include/srslte/upper/rlc_tm.h +++ b/lib/include/srslte/upper/rlc_tm.h @@ -48,6 +48,7 @@ public: mac_interface_timers *mac_timers); void configure(srslte_rlc_config_t cnfg); void reset(); + void stop(); void empty_queue(); rlc_mode_t get_mode(); diff --git a/lib/include/srslte/upper/rlc_um.h b/lib/include/srslte/upper/rlc_um.h index 4325bd029..0a2469a7c 100644 --- a/lib/include/srslte/upper/rlc_um.h +++ b/lib/include/srslte/upper/rlc_um.h @@ -58,6 +58,7 @@ public: mac_interface_timers *mac_timers_); void configure(srslte_rlc_config_t cnfg); void reset(); + void stop(); void empty_queue(); rlc_mode_t get_mode(); @@ -124,7 +125,8 @@ private: * Timers * Ref: 3GPP TS 36.322 v10.0.0 Section 7 ***************************************************************************/ - uint32_t reordering_timeout_id; + srslte::timers::timer *reordering_timer; + uint32_t reordering_timer_id; bool pdu_lost; diff --git a/lib/src/common/logger_file.cc b/lib/src/common/logger_file.cc index 94e5e8405..739eded8b 100644 --- a/lib/src/common/logger_file.cc +++ b/lib/src/common/logger_file.cc @@ -55,7 +55,7 @@ void logger_file::init(std::string file) { filename = file; logfile = fopen(filename.c_str(), "w"); if(logfile==NULL) { - printf("Error: could not create log file, no messages will be logged"); + printf("Error: could not create log file, no messages will be logged!\n"); } start(); inited = true; diff --git a/lib/src/common/pdu_queue.cc b/lib/src/common/pdu_queue.cc index a1bf7cd59..6b4c8bfd9 100644 --- a/lib/src/common/pdu_queue.cc +++ b/lib/src/common/pdu_queue.cc @@ -66,7 +66,7 @@ uint8_t* pdu_queue::request(uint32_t len) void pdu_queue::deallocate(uint8_t* pdu) { if (!pool.deallocate((pdu_t*) pdu)) { - log_h->warning("Error deallocating from buffer pool: buffer not created in this pool.\n"); + log_h->warning("Error deallocating from buffer pool in deallocate(): buffer not created in this pool.\n"); } } @@ -92,7 +92,7 @@ bool pdu_queue::process_pdus() callback->process_pdu(pdu->ptr, pdu->len, pdu->tstamp); } if (!pool.deallocate(pdu)) { - log_h->warning("Error deallocating from buffer pool: buffer not created in this pool.\n"); + log_h->warning("Error deallocating from buffer pool in process_pdus(): buffer not created in this pool.\n"); } cnt++; have_data = true; diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index 3c2f4210c..0f8ae8074 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "srslte/config.h" @@ -72,54 +74,70 @@ static void set_default_filter(srslte_chest_dl_t *q, int filter_len) { * * This object depends on the srslte_refsignal_t object for creating the LTE CSR signal. */ - -int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell) +int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL) { bzero(q, sizeof(srslte_chest_dl_t)); - ret = srslte_refsignal_cs_init(&q->csr_signal, cell); + + ret = srslte_refsignal_cs_init(&q->csr_refs, max_prb); if (ret != SRSLTE_SUCCESS) { fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); goto clean_exit; } - q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); + q->mbsfn_refs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_refsignal_t*)); + if (!q->mbsfn_refs) { + fprintf(stderr, "Calloc error initializing mbsfn_refs (%d)\n", ret); + goto clean_exit; + } + + int pilot_vec_size; + if(SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(max_prb)>SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb)) { + pilot_vec_size = SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(max_prb); + }else{ + pilot_vec_size = SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb); + } + + q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + + if (!q->tmp_noise) { perror("malloc"); goto clean_exit; } - q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); + q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + if (!q->pilot_estimates) { perror("malloc"); goto clean_exit; } - q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); + q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); if (!q->pilot_estimates_average) { perror("malloc"); goto clean_exit; } - q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); + q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + if (!q->pilot_recv_signal) { perror("malloc"); goto clean_exit; } - if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, SRSLTE_NRE*cell.nof_prb)) { + if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, SRSLTE_NRE*max_prb)) { fprintf(stderr, "Error initializing vector interpolator\n"); goto clean_exit; } - if (srslte_interp_linear_init(&q->srslte_interp_lin, 2*cell.nof_prb, SRSLTE_NRE/2)) { + if (srslte_interp_linear_init(&q->srslte_interp_lin, 2*max_prb, SRSLTE_NRE/2)) { fprintf(stderr, "Error initializing interpolator\n"); goto clean_exit; } - - if (srslte_pss_generate(q->pss_signal, cell.id%3)) { - fprintf(stderr, "Error initializing PSS signal for noise estimation\n"); + + if (srslte_interp_linear_init(&q->srslte_interp_lin_mbsfn, 6*max_prb, SRSLTE_NRE/6)) { + fprintf(stderr, "Error initializing interpolator\n"); goto clean_exit; } @@ -128,7 +146,6 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell) q->smooth_filter_len = 3; srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1); - q->cell = cell; } ret = SRSLTE_SUCCESS; @@ -142,14 +159,25 @@ clean_exit: void srslte_chest_dl_free(srslte_chest_dl_t *q) { - srslte_refsignal_cs_free(&q->csr_signal); + int i; + if(&q->csr_refs) + srslte_refsignal_free(&q->csr_refs); + + if (q->mbsfn_refs) { + for (i=0; imbsfn_refs[i]) { + srslte_refsignal_free(q->mbsfn_refs[i]); + } + } + free(q->mbsfn_refs); + } if (q->tmp_noise) { free(q->tmp_noise); } srslte_interp_linear_vector_free(&q->srslte_interp_linvec); srslte_interp_linear_free(&q->srslte_interp_lin); - + srslte_interp_linear_free(&q->srslte_interp_lin_mbsfn); if (q->pilot_estimates) { free(q->pilot_estimates); } @@ -162,10 +190,57 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q) bzero(q, sizeof(srslte_chest_dl_t)); } + +int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_id){ + if(!q->mbsfn_refs[mbsfn_area_id]){ + q->mbsfn_refs[mbsfn_area_id] = calloc(1, sizeof(srslte_refsignal_t)); + } + if(q->mbsfn_refs[mbsfn_area_id]) { + if(srslte_refsignal_mbsfn_init(q->mbsfn_refs[mbsfn_area_id], q->cell, mbsfn_area_id)) { + return SRSLTE_ERROR; + } + } + return SRSLTE_SUCCESS; +} + +int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL && + srslte_cell_isvalid(&cell)) + { + if (q->cell.id != cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + ret = srslte_refsignal_cs_set_cell(&q->csr_refs, cell); + if (ret != SRSLTE_SUCCESS) { + fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); + return SRSLTE_ERROR; + } + if (srslte_pss_generate(q->pss_signal, cell.id%3)) { + fprintf(stderr, "Error initializing PSS signal for noise estimation\n"); + return SRSLTE_ERROR; + } + if (srslte_interp_linear_vector_resize(&q->srslte_interp_linvec, SRSLTE_NRE*q->cell.nof_prb)) { + fprintf(stderr, "Error initializing vector interpolator\n"); + return SRSLTE_ERROR; + } + + if (srslte_interp_linear_resize(&q->srslte_interp_lin, 2*q->cell.nof_prb, SRSLTE_NRE/2)) { + fprintf(stderr, "Error initializing interpolator\n"); + return SRSLTE_ERROR; + } + + } + ret = SRSLTE_SUCCESS; + } + return ret; +} + /* Uses the difference between the averaged and non-averaged pilot estimates */ static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id) { int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); + /* Substract noisy pilot estimates */ srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref); @@ -223,46 +298,70 @@ static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) { #define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)] -static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id) +static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id, srslte_sf_t ch_mode) { /* interpolate the symbols with references in the freq domain */ uint32_t l; - uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); - + uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN ) ? srslte_refsignal_mbsfn_nof_symbols() + 1 : srslte_refsignal_cs_nof_symbols(port_id); + uint32_t fidx_offset = 0; /* Interpolate in the frequency domain */ - for (l=0;lcell, l, port_id, 0); - srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l], - &ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE], - fidx_offset, SRSLTE_NRE/2-fidx_offset); + + // we add one to nsymbols to allow for inclusion of the non-mbms references in the channel estimation + for (l=0;l<(nsymbols);l++) { + if (ch_mode == SRSLTE_SF_MBSFN) { + if (l == 0) { + fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0); + srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l], + &ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE], + fidx_offset, SRSLTE_NRE/2-fidx_offset); + } else { + fidx_offset = srslte_refsignal_mbsfn_fidx(l - 1); + srslte_interp_linear_offset(&q->srslte_interp_lin_mbsfn, &pilot_estimates[(2*q->cell.nof_prb) + 6*q->cell.nof_prb*(l - 1)], + &ce[srslte_refsignal_mbsfn_nsymbol(l - 1) * q->cell.nof_prb * SRSLTE_NRE], + fidx_offset, SRSLTE_NRE/6-fidx_offset); + } + } else { + fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0); + srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l], + &ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE], + fidx_offset, SRSLTE_NRE/2-fidx_offset); + } } - + /* Now interpolate in the time domain between symbols */ - if (SRSLTE_CP_ISNORM(q->cell.cp)) { - if (nsymbols == 4) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); - } else { - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5); - } - } else { - if (nsymbols == 4) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2); + if (ch_mode == SRSLTE_SF_MBSFN) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1); + } else { + if (SRSLTE_CP_ISNORM(q->cell.cp)) { + if (nsymbols == 4) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); + } else { + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5); + } } else { - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4); - } + if (nsymbols == 4) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2); + } else { + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4); + } + } } } + void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) { if (filter_len < SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN) { if (filter) { @@ -289,9 +388,9 @@ void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w) q->smooth_filter[1] = 1-2*w; } -static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id) { - uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); - uint32_t nref = 2*q->cell.nof_prb; +static void average_pilots(srslte_chest_dl_t *q, cf_t *input, 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; // Average in the frequency domain for (int l=0;lcell, port_id, input, q->pilot_recv_signal); - - /* Use the known CSR signal to compute Least-squares estimates */ - srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_signal.pilots[port_id/2][sf_idx], - q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); - if (ce != NULL) { - +void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, srslte_sf_t ch_mode){ + if (ce != NULL) { /* Smooth estimates (if applicable) and interpolate */ if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) { - interpolate_pilots(q, q->pilot_estimates, ce, port_id); + interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode); } else { - average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id); - interpolate_pilots(q, q->pilot_estimates_average, ce, port_id); + average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id, ch_mode); + interpolate_pilots(q, q->pilot_estimates_average, ce, port_id, ch_mode); } - + /* Estimate noise power */ if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) { q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id); @@ -340,8 +431,7 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u if (sf_idx == 0 || sf_idx == 5) { q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); } - } - + } } /* Compute RSRP for the channel estimates in this port */ @@ -350,10 +440,44 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u /* compute rssi only for port 0 */ q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); } +} + +int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id) +{ + /* Get references from the input signal */ + srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal); + + /* Use the known CSR signal to compute Least-squares estimates */ + srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx], + q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + + chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_NORM); + + return 0; +} +int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, uint16_t mbsfn_area_id) +{ + + /* Use the known CSR signal to compute Least-squares estimates */ + srslte_refsignal_mbsfn_get_sf(q->cell, port_id, input, q->pilot_recv_signal); + // estimate for non-mbsfn section of subframe + 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)); + + + + chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_MBSFN); return 0; } + + + + int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas) { for (uint32_t rxant_id=0;rxant_idcell.nof_ports;port_id++) { if (srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id, 0)) { return SRSLTE_ERROR; @@ -380,6 +504,21 @@ int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, cf_t *ce[SRSLTE_ return SRSLTE_SUCCESS; } +int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas, uint16_t mbsfn_area_id) +{ + for (uint32_t rxant_id=0;rxant_idcell.nof_ports;port_id++) { + if (srslte_chest_dl_estimate_port_mbsfn(q, input[rxant_id], ce[port_id][rxant_id], sf_idx, port_id, rxant_id, mbsfn_area_id)) { + return SRSLTE_ERROR; + } + } + } + q->last_nof_antennas = nof_rx_antennas; + return SRSLTE_SUCCESS; +} + + + float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) { float n = 0; for (int i=0;ilast_nof_antennas;i++) { diff --git a/lib/src/phy/ch_estimation/chest_ul.c b/lib/src/phy/ch_estimation/chest_ul.c index 9996fc9c3..ac4831cc9 100644 --- a/lib/src/phy/ch_estimation/chest_ul.c +++ b/lib/src/phy/ch_estimation/chest_ul.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "srslte/config.h" @@ -43,6 +45,9 @@ #define NOF_REFS_SYM (q->cell.nof_prb*SRSLTE_NRE) #define NOF_REFS_SF (NOF_REFS_SYM*2) // 2 reference symbols per subframe +#define MAX_REFS_SYM (max_prb*SRSLTE_NRE) +#define MAX_REFS_SF (max_prb*SRSLTE_NRE*2) // 2 reference symbols per subframe + /** 3GPP LTE Downlink channel estimator and equalizer. * Estimates the channel in the resource elements transmitting references and interpolates for the rest * of the resource grid. @@ -52,52 +57,49 @@ * This object depends on the srslte_refsignal_t object for creating the LTE CSR signal. */ -int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell) +int srslte_chest_ul_init(srslte_chest_ul_t *q, uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL) { bzero(q, sizeof(srslte_chest_ul_t)); - q->cell = cell; - - ret = srslte_refsignal_ul_init(&q->dmrs_signal, cell); + ret = srslte_refsignal_ul_init(&q->dmrs_signal, max_prb); if (ret != SRSLTE_SUCCESS) { fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); goto clean_exit; } - q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF); + q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * MAX_REFS_SF); if (!q->tmp_noise) { perror("malloc"); goto clean_exit; } - q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF); + q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * MAX_REFS_SF); if (!q->pilot_estimates) { perror("malloc"); goto clean_exit; } for (int i=0;i<4;i++) { - q->pilot_estimates_tmp[i] = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF); + q->pilot_estimates_tmp[i] = srslte_vec_malloc(sizeof(cf_t) * MAX_REFS_SF); if (!q->pilot_estimates_tmp[i]) { perror("malloc"); goto clean_exit; } } - q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * (NOF_REFS_SF+1)); + q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * (MAX_REFS_SF+1)); if (!q->pilot_recv_signal) { perror("malloc"); goto clean_exit; } - q->pilot_known_signal = srslte_vec_malloc(sizeof(cf_t) * (NOF_REFS_SF+1)); + q->pilot_known_signal = srslte_vec_malloc(sizeof(cf_t) * (MAX_REFS_SF+1)); if (!q->pilot_known_signal) { perror("malloc"); goto clean_exit; } - if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, NOF_REFS_SYM)) { + if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, MAX_REFS_SYM)) { fprintf(stderr, "Error initializing vector interpolator\n"); goto clean_exit; } @@ -105,12 +107,17 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell) q->smooth_filter_len = 3; srslte_chest_ul_set_smooth_filter3_coeff(q, 0.3333); - q->dmrs_signal_configured = false; + q->dmrs_signal_configured = false; + + if (srslte_refsignal_dmrs_pusch_pregen_init(&q->dmrs_signal, &q->dmrs_pregen, max_prb)) { + fprintf(stderr, "Error allocating memory for pregenerated signals\n"); + goto clean_exit; + } } ret = SRSLTE_SUCCESS; - + clean_exit: if (ret != SRSLTE_SUCCESS) { srslte_chest_ul_free(q); @@ -120,9 +127,8 @@ clean_exit: void srslte_chest_ul_free(srslte_chest_ul_t *q) { - if (q->dmrs_signal_configured) { - srslte_refsignal_dmrs_pusch_pregen_free(&q->dmrs_signal, &q->dmrs_pregen); - } + srslte_refsignal_dmrs_pusch_pregen_free(&q->dmrs_signal, &q->dmrs_pregen); + srslte_refsignal_ul_free(&q->dmrs_signal); if (q->tmp_noise) { free(q->tmp_noise); @@ -146,6 +152,30 @@ void srslte_chest_ul_free(srslte_chest_ul_t *q) bzero(q, sizeof(srslte_chest_ul_t)); } +int srslte_chest_ul_set_cell(srslte_chest_ul_t *q, srslte_cell_t cell) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL && + srslte_cell_isvalid(&cell)) + { + if (cell.id != q->cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + ret = srslte_refsignal_ul_set_cell(&q->dmrs_signal, cell); + if (ret != SRSLTE_SUCCESS) { + fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); + return SRSLTE_ERROR; + } + + if (srslte_interp_linear_vector_resize(&q->srslte_interp_linvec, NOF_REFS_SYM)) { + fprintf(stderr, "Error initializing vector interpolator\n"); + return SRSLTE_ERROR; + } + } + ret = SRSLTE_SUCCESS; + } + return ret; +} + void srslte_chest_ul_set_cfg(srslte_chest_ul_t *q, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, srslte_pucch_cfg_t *pucch_cfg, diff --git a/lib/src/phy/ch_estimation/refsignal_dl.c b/lib/src/phy/ch_estimation/refsignal_dl.c index ec0f0b4e0..308be6877 100644 --- a/lib/src/phy/ch_estimation/refsignal_dl.c +++ b/lib/src/phy/ch_estimation/refsignal_dl.c @@ -75,17 +75,40 @@ uint32_t srslte_refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_idx) uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id) { + uint32_t ret; if (port_id < 2) { - return 4; + ret = 4; } else { - return 2; + ret = 2; } + return ret; } +uint32_t srslte_refsignal_mbsfn_nof_symbols() +{ + return 3; +} + + inline uint32_t srslte_refsignal_cs_fidx(srslte_cell_t cell, uint32_t l, uint32_t port_id, uint32_t m) { return 6*m + ((srslte_refsignal_cs_v(port_id, l) + (cell.id % 6)) % 6); } +inline uint32_t srslte_refsignal_mbsfn_fidx(uint32_t l) +{ + + uint32_t ret = 0; + if(l == 0){ + ret = 0; + }else if (l == 1){ + ret = 1; + }else if(l == 2){ + ret = 0; + } + + return ret; +} + inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t port_id) { if (port_id < 2) { if (l % 2) { @@ -97,100 +120,205 @@ inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t return 1+l*SRSLTE_CP_NSYMB(cp); } } - - -/** Allocates and precomputes the Cell-Specific Reference (CSR) signal for - * the 20 slots in a subframe - */ -int srslte_refsignal_cs_init(srslte_refsignal_cs_t * q, srslte_cell_t cell) +inline uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l) { + uint32_t ret = 0; + if(l == 0){ + ret = 2; + } else if (l == 1) { + ret = 6; + } else if (l == 2){ + ret = 10; + } + + return ret; +} +int srslte_refsignal_mbsfn_gen_seq(srslte_refsignal_t * q, srslte_cell_t cell, uint32_t N_mbsfn_id) +{ uint32_t c_init; uint32_t i, ns, l, p; - uint32_t N_cp, mp; - srslte_sequence_t seq; - int ret = SRSLTE_ERROR_INVALID_INPUTS; + uint32_t mp; + int ret = SRSLTE_ERROR; - if (q != NULL && - srslte_cell_isvalid(&cell)) - { - ret = SRSLTE_ERROR; - - bzero(q, sizeof(srslte_refsignal_cs_t)); - bzero(&seq, sizeof(srslte_sequence_t)); - if (srslte_sequence_init(&seq, 2 * 2 * SRSLTE_MAX_PRB)) { - goto free_and_exit; - } - - if (SRSLTE_CP_ISNORM(cell.cp)) { - N_cp = 1; - } else { - N_cp = 0; + srslte_sequence_t seq_mbsfn; + bzero(&seq_mbsfn, sizeof(srslte_sequence_t)); + if (srslte_sequence_init(&seq_mbsfn, 20* SRSLTE_MAX_PRB)) { + goto free_and_exit; + } + + for(ns=0; nscell.nof_prb;i++) { + mp = i + 3*(SRSLTE_MAX_PRB - cell.nof_prb); + q->pilots[p][ns][ SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i, l ,q->cell)] = (1 - 2 * (float) seq_mbsfn.c[2 * mp]) / sqrt(2) +_Complex_I * (1 - 2 * (float) seq_mbsfn.c[2 * mp + 1]) / sqrt(2); + } + } } + } + + srslte_sequence_free(&seq_mbsfn); + ret = SRSLTE_SUCCESS; - q->cell = cell; - +free_and_exit: + if (ret == SRSLTE_ERROR) { + srslte_sequence_free(&seq_mbsfn); + srslte_refsignal_free(q); + } + return ret; + +} + + +int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, srslte_cell_t cell, uint16_t mbsfn_area_id) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + uint32_t i, p; + if (q != NULL && + srslte_cell_isvalid(&cell)) + { + 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;ipilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, 2*p)); + q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * q->cell.nof_prb * 18); if (!q->pilots[p][i]) { perror("malloc"); goto free_and_exit; } - } + } } - - for (ns=0;nscell.nof_prb; i++) { - mp = i + SRSLTE_MAX_PRB - cell.nof_prb; - /* save signal */ - q->pilots[p][ns/2][SRSLTE_REFSIGNAL_PILOT_IDX(i,(ns%2)*nsymbols+l,q->cell)] = - (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2) + - _Complex_I * (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); - } + + 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 + */ +int srslte_refsignal_cs_init(srslte_refsignal_t * q, uint32_t max_prb) +{ + + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) + { + ret = SRSLTE_ERROR; + bzero(q, sizeof(srslte_refsignal_t)); + for (int p=0;p<2;p++) { + for (int i=0;ipilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(max_prb, 2*p)); + if (!q->pilots[p][i]) { + perror("malloc"); + goto free_and_exit; } - - } + } } - srslte_sequence_free(&seq); ret = SRSLTE_SUCCESS; } free_and_exit: if (ret == SRSLTE_ERROR) { - srslte_sequence_free(&seq); - srslte_refsignal_cs_free(q); + srslte_refsignal_free(q); + } + return ret; +} + +/** Allocates and precomputes the Cell-Specific Reference (CSR) signal for + * the 20 slots in a subframe + */ +int srslte_refsignal_cs_set_cell(srslte_refsignal_t * q, srslte_cell_t cell) +{ + + uint32_t c_init; + uint32_t i, ns, l, p; + uint32_t N_cp, mp; + srslte_sequence_t seq; + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + srslte_cell_isvalid(&cell)) + { + if (cell.id != q->cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + + bzero(&seq, sizeof(srslte_sequence_t)); + if (srslte_sequence_init(&seq, 2*2*SRSLTE_MAX_PRB)) { + return SRSLTE_ERROR; + } + + if (SRSLTE_CP_ISNORM(cell.cp)) { + N_cp = 1; + } else { + N_cp = 0; + } + + for (ns=0;nscell.nof_prb; i++) { + mp = i + SRSLTE_MAX_PRB - cell.nof_prb; + /* save signal */ + q->pilots[p][ns/2][SRSLTE_REFSIGNAL_PILOT_IDX(i,(ns%2)*nsymbols+l,q->cell)] = + (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2) + + _Complex_I * (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); + } + } + } + } + srslte_sequence_free(&seq); + } + ret = SRSLTE_SUCCESS; } return ret; } /** Deallocates a srslte_refsignal_cs_t object allocated with srslte_refsignal_cs_init */ -void srslte_refsignal_cs_free(srslte_refsignal_cs_t * q) +void srslte_refsignal_free(srslte_refsignal_t * q) { - int i, p; - - for (p=0;p<2;p++) { - for (i=0;ipilots[p][i]) { free(q->pilots[p][i]); } } } - bzero(q, sizeof(srslte_refsignal_cs_t)); + bzero(q, sizeof(srslte_refsignal_t)); } + + /* Maps a reference signal initialized with srslte_refsignal_cs_init() into an array of subframe symbols */ int srslte_refsignal_cs_put_sf(srslte_cell_t cell, uint32_t port_id, cf_t *pilots, cf_t *sf_symbols) { @@ -218,6 +346,45 @@ int srslte_refsignal_cs_put_sf(srslte_cell_t cell, uint32_t port_id, cf_t *pilot } } +SRSLTE_API int srslte_refsignal_mbsfn_put_sf(srslte_cell_t cell, + uint32_t port_id, + cf_t *cs_pilots, + cf_t *mbsfn_pilots, + cf_t *sf_symbols) +{ + uint32_t i, l; + uint32_t fidx; + + if (srslte_cell_isvalid(&cell) && + srslte_portid_isvalid(port_id) && + cs_pilots != NULL && + mbsfn_pilots != NULL && + sf_symbols != NULL) + { + // adding CS refs for the non-mbsfn section of the sub-frame + fidx = ((srslte_refsignal_cs_v(port_id, 0) + (cell.id % 6)) % 6); + for (i = 0; i < 2*cell.nof_prb; i++) { + sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, 0, fidx)] = cs_pilots[SRSLTE_REFSIGNAL_PILOT_IDX(i,0,cell)]; + fidx += SRSLTE_NRE/2; // 1 reference every 6 RE + } + + for (l = 0; l #include #include +#include #include "srslte/phy/common/phy_common.h" #include "srslte/phy/ch_estimation/refsignal_ul.h" @@ -138,8 +139,8 @@ static int generate_n_prs(srslte_refsignal_ul_t * q) { } q->n_prs_pusch[delta_ss][ns] = n_prs; } - srslte_sequence_free(&seq); } + srslte_sequence_free(&seq); return SRSLTE_SUCCESS; } @@ -160,9 +161,9 @@ static int generate_srslte_sequence_hopping_v(srslte_refsignal_ul_t *q) { return SRSLTE_ERROR; } q->v_pusch[ns][delta_ss] = seq.c[ns]; - srslte_sequence_free(&seq); } } + srslte_sequence_free(&seq); return SRSLTE_SUCCESS; } @@ -170,46 +171,24 @@ static int generate_srslte_sequence_hopping_v(srslte_refsignal_ul_t *q) { /** Initializes srslte_refsignal_ul_t object according to 3GPP 36.211 5.5 * */ -int srslte_refsignal_ul_init(srslte_refsignal_ul_t * q, srslte_cell_t cell) +int srslte_refsignal_ul_init(srslte_refsignal_ul_t * q, uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && srslte_cell_isvalid(&cell)) { + if (q != NULL) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_refsignal_ul_t)); - q->cell = cell; - + // Allocate temporal buffer for computing signal argument - q->tmp_arg = srslte_vec_malloc(SRSLTE_NRE * q->cell.nof_prb * sizeof(cf_t)); + q->tmp_arg = srslte_vec_malloc(SRSLTE_NRE * max_prb * sizeof(cf_t)); if (!q->tmp_arg) { perror("malloc"); goto free_and_exit; } - srslte_pucch_cfg_default(&q->pucch_cfg); - - // Precompute n_prs - if (generate_n_prs(q)) { - goto free_and_exit; - } - - // Precompute group hopping values u. - if (srslte_group_hopping_f_gh(q->f_gh, q->cell.id)) { - goto free_and_exit; - } - - // Precompute sequence hopping values v. Uses f_ss_pusch - if (generate_srslte_sequence_hopping_v(q)) { - goto free_and_exit; - } - - if (srslte_pucch_n_cs_cell(q->cell, q->n_cs_cell)) { - goto free_and_exit; - } - ret = SRSLTE_SUCCESS; } free_and_exit: @@ -226,6 +205,45 @@ void srslte_refsignal_ul_free(srslte_refsignal_ul_t * q) { bzero(q, sizeof(srslte_refsignal_ul_t)); } +/** Initializes srslte_refsignal_ul_t object according to 3GPP 36.211 5.5 + * + */ +int srslte_refsignal_ul_set_cell(srslte_refsignal_ul_t * q, srslte_cell_t cell) +{ + + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && srslte_cell_isvalid(&cell)) { + + if (cell.id != q->cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + + srslte_pucch_cfg_default(&q->pucch_cfg); + + // Precompute n_prs + if (generate_n_prs(q)) { + return SRSLTE_ERROR; + } + + // Precompute group hopping values u. + if (srslte_group_hopping_f_gh(q->f_gh, q->cell.id)) { + return SRSLTE_ERROR; + } + + // Precompute sequence hopping values v. Uses f_ss_pusch + if (generate_srslte_sequence_hopping_v(q)) { + return SRSLTE_ERROR; + } + + if (srslte_pucch_n_cs_cell(q->cell, q->n_cs_cell)) { + return SRSLTE_ERROR; + } + } + ret = SRSLTE_SUCCESS; + } + return ret; +} + void srslte_refsignal_ul_set_cfg(srslte_refsignal_ul_t *q, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, srslte_pucch_cfg_t *pucch_cfg, @@ -363,15 +381,38 @@ void compute_r(srslte_refsignal_ul_t *q, uint32_t nof_prb, uint32_t ns, uint32_t } +int srslte_refsignal_dmrs_pusch_pregen_init(srslte_refsignal_ul_t *q, srslte_refsignal_ul_dmrs_pregen_t *pregen, + uint32_t max_prb) +{ + for (uint32_t sf_idx=0;sf_idxr[cs][sf_idx] = (cf_t**) calloc(sizeof(cf_t*), max_prb + 1); + if (pregen->r[cs][sf_idx]) { + for (uint32_t n=0;n<=max_prb;n++) { + if (srslte_dft_precoding_valid_prb(n)) { + pregen->r[cs][sf_idx][n] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*n*2*SRSLTE_NRE); + if (pregen->r[cs][sf_idx][n]) { + } else { + return SRSLTE_ERROR; + } + } + } + } else { + return SRSLTE_ERROR; + } + } + } + return SRSLTE_SUCCESS; +} + + int srslte_refsignal_dmrs_pusch_pregen(srslte_refsignal_ul_t *q, srslte_refsignal_ul_dmrs_pregen_t *pregen) { for (uint32_t sf_idx=0;sf_idxr[cs][sf_idx] = (cf_t**) calloc(sizeof(cf_t*), q->cell.nof_prb + 1); if (pregen->r[cs][sf_idx]) { for (uint32_t n=0;n<=q->cell.nof_prb;n++) { if (srslte_dft_precoding_valid_prb(n)) { - pregen->r[cs][sf_idx][n] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*n*2*SRSLTE_NRE); if (pregen->r[cs][sf_idx][n]) { if (srslte_refsignal_dmrs_pusch_gen(q, n, sf_idx, cs, pregen->r[cs][sf_idx][n])) { return SRSLTE_ERROR; diff --git a/lib/src/phy/ch_estimation/test/chest_test_dl.c b/lib/src/phy/ch_estimation/test/chest_test_dl.c index c60e94d96..0f5a6d6ea 100644 --- a/lib/src/phy/ch_estimation/test/chest_test_dl.c +++ b/lib/src/phy/ch_estimation/test/chest_test_dl.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "srslte/srslte.h" @@ -128,10 +129,13 @@ int main(int argc, char **argv) { cid = cell.id; max_cid = cell.id; } - + if (srslte_chest_dl_init(&est, cell.nof_prb)) { + fprintf(stderr, "Error initializing equalizer\n"); + goto do_exit; + } while(cid <= max_cid) { cell.id = cid; - if (srslte_chest_dl_init(&est, cell)) { + if (srslte_chest_dl_set_cell(&est, cell)) { fprintf(stderr, "Error initializing equalizer\n"); goto do_exit; } @@ -148,7 +152,7 @@ int main(int argc, char **argv) { bzero(h, sizeof(cf_t) * num_re); srslte_refsignal_cs_put_sf(cell, n_port, - est.csr_signal.pilots[n_port/2][sf_idx], input); + est.csr_refs.pilots[n_port/2][sf_idx], input); for (i=0;i<2*SRSLTE_CP_NSYMB(cell.cp);i++) { for (j=0;j tti2) { + if (tti1 >= tti2) { return tti1-tti2; } else { return 10240-tti2+tti1; diff --git a/lib/src/phy/common/sequence.c b/lib/src/phy/common/sequence.c index 2a863bcee..0ecf9f159 100644 --- a/lib/src/phy/common/sequence.c +++ b/lib/src/phy/common/sequence.c @@ -27,7 +27,8 @@ #include #include #include -#include +#include +#include #include "srslte/phy/common/sequence.h" #include "srslte/phy/utils/vector.h" @@ -35,26 +36,75 @@ #define Nc 1600 +#define MAX_SEQ_LEN (128*1024) + +#define static_memory /* * Pseudo Random Sequence generation. * It follows the 3GPP Release 8 (LTE) 36.211 * Section 7.2 */ -void srslte_sequence_set_LTE_pr(srslte_sequence_t *q, uint32_t seed) { +#ifdef static_memory +static uint8_t x1[Nc+MAX_SEQ_LEN+31]; +static uint8_t x2[Nc+MAX_SEQ_LEN+31]; + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +int srslte_sequence_set_LTE_pr(srslte_sequence_t *q, uint32_t len, uint32_t seed) { + int n; + + if (len > q->max_len) { + fprintf(stderr, "Error generating pseudo-random sequence: len %d exceeds maximum len %d\n", + len, MAX_SEQ_LEN); + return -1; + } + + if (len > q->max_len) { + fprintf(stderr, "Error generating pseudo-random sequence: len %d is greater than allocated len %d\n", + len, q->max_len); + return -1; + } + pthread_mutex_lock(&mutex); + + for (n = 0; n < 31; n++) { + x2[n] = (seed >> n) & 0x1; + } + x1[0] = 1; + + for (n = 0; n < Nc + len; n++) { + x1[n + 31] = (x1[n + 3] + x1[n]) & 0x1; + x2[n + 31] = (x2[n + 3] + x2[n + 2] + x2[n+1] + x2[n]) & 0x1; + } + + for (n = 0; n < len; n++) { + q->c[n] = (x1[n + Nc] + x2[n + Nc]) & 0x1; + } + pthread_mutex_unlock(&mutex); + + return 0; +} + +#else +int srslte_sequence_set_LTE_pr(srslte_sequence_t *q, uint32_t len, uint32_t seed) { int n; uint32_t *x1, *x2; - x1 = calloc(Nc + q->len + 31, sizeof(uint32_t)); + if (len > q->max_len) { + fprintf(stderr, "Error generating pseudo-random sequence: len %d is greater than allocated len %d\n", + len, q->max_len); + return -1; + } + + x1 = calloc(Nc + len + 31, sizeof(uint32_t)); if (!x1) { perror("calloc"); - return; + return -1; } - x2 = calloc(Nc + q->len + 31, sizeof(uint32_t)); + x2 = calloc(Nc + len + 31, sizeof(uint32_t)); if (!x2) { free(x1); perror("calloc"); - return; + return -1; } for (n = 0; n < 31; n++) { @@ -62,25 +112,29 @@ void srslte_sequence_set_LTE_pr(srslte_sequence_t *q, uint32_t seed) { } x1[0] = 1; - for (n = 0; n < Nc + q->len; n++) { + for (n = 0; n < Nc + len; n++) { x1[n + 31] = (x1[n + 3] + x1[n]) & 0x1; x2[n + 31] = (x2[n + 3] + x2[n + 2] + +x2[n+1] + x2[n]) & 0x1; } - for (n = 0; n < q->len; n++) { + for (n = 0; n < len; n++) { q->c[n] = (x1[n + Nc] + x2[n + Nc]) & 0x1; } free(x1); free(x2); + + return 0; } +#endif + int srslte_sequence_LTE_pr(srslte_sequence_t *q, uint32_t len, uint32_t seed) { if (srslte_sequence_init(q, len)) { return SRSLTE_ERROR; } - q->len = len; - srslte_sequence_set_LTE_pr(q, seed); + q->cur_len = len; + srslte_sequence_set_LTE_pr(q, len, seed); srslte_bit_pack_vector(q->c, q->c_bytes, len); for (int i=0;ic_float[i] = (1-2*q->c[i]); @@ -90,17 +144,8 @@ int srslte_sequence_LTE_pr(srslte_sequence_t *q, uint32_t len, uint32_t seed) { } int srslte_sequence_init(srslte_sequence_t *q, uint32_t len) { - if (q->c && (q->len != len)) { - free(q->c); - if (q->c_bytes) { - free(q->c_bytes); - } - if (q->c_float) { - free(q->c_float); - } - if (q->c_short) { - free(q->c_short); - } + if (q->c && len > q->max_len) { + srslte_sequence_free(q); } if (!q->c) { q->c = srslte_vec_malloc(len * sizeof(uint8_t)); @@ -119,7 +164,7 @@ int srslte_sequence_init(srslte_sequence_t *q, uint32_t len) { if (!q->c_short) { return SRSLTE_ERROR; } - q->len = len; + q->max_len = len; } return SRSLTE_SUCCESS; } diff --git a/lib/src/phy/dft/dft_fftw.c b/lib/src/phy/dft/dft_fftw.c index 5fb34bb3c..b4a627742 100644 --- a/lib/src/phy/dft/dft_fftw.c +++ b/lib/src/phy/dft/dft_fftw.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "srslte/phy/dft/dft.h" #include "srslte/phy/utils/vector.h" @@ -38,14 +39,27 @@ #define FFTW_WISDOM_FILE ".fftw_wisdom" +#ifdef FFTW_WISDOM_FILE +#define FFTW_TYPE FFTW_MEASURE +#else +#define FFTW_TYPE 0 +#endif + + void srslte_dft_load() { +#ifdef FFTW_WISDOM_FILE fftwf_import_wisdom_from_filename(FFTW_WISDOM_FILE); +#else + printf("Warning: FFTW Wisdom file not defined\n"); +#endif } void srslte_dft_exit() { +#ifdef FFTW_WISDOM_FILE if (!fftwf_export_wisdom_to_filename(FFTW_WISDOM_FILE)) { fprintf(stderr, "Error saving FFTW wisdom to file %s\n", FFTW_WISDOM_FILE); } +#endif } int srslte_dft_plan(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir, @@ -58,19 +72,50 @@ int srslte_dft_plan(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_di return 0; } +int srslte_dft_replan(srslte_dft_plan_t *plan, const int new_dft_points) { + if (new_dft_points <= plan->init_size) { + if(plan->mode == SRSLTE_DFT_COMPLEX){ + return srslte_dft_replan_c(plan,new_dft_points); + } else { + return srslte_dft_replan_r(plan,new_dft_points); + } + } else { + fprintf(stderr, "DFT: Error calling replan: new_dft_points (%d) must be lower or equal " + "dft_size passed initially (%d)\n", new_dft_points, plan->init_size); + return -1; + } +} + + + static void allocate(srslte_dft_plan_t *plan, int size_in, int size_out, int len) { plan->in = fftwf_malloc(size_in*len); plan->out = fftwf_malloc(size_out*len); } +int srslte_dft_replan_c(srslte_dft_plan_t *plan, const int new_dft_points) { + int sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD; + if (plan->p) { + fftwf_destroy_plan(plan->p); + plan->p = NULL; + } + plan->p = fftwf_plan_dft_1d(new_dft_points, plan->in, plan->out, sign, FFTW_TYPE); + if (!plan->p) { + return -1; + } + plan->size = new_dft_points; + return 0; +} + int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) { allocate(plan,sizeof(fftwf_complex),sizeof(fftwf_complex), dft_points); int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD; - plan->p = fftwf_plan_dft_1d(dft_points, plan->in, plan->out, sign, FFTW_MEASURE); + plan->p = fftwf_plan_dft_1d(dft_points, plan->in, plan->out, sign, FFTW_TYPE); if (!plan->p) { return -1; } plan->size = dft_points; + plan->init_size = plan->size; plan->mode = SRSLTE_DFT_COMPLEX; plan->dir = dir; plan->forward = (dir==SRSLTE_DFT_FORWARD)?true:false; @@ -82,14 +127,29 @@ int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_ return 0; } +int srslte_dft_replan_r(srslte_dft_plan_t *plan, const int new_dft_points) { + int sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R; + if (plan->p) { + fftwf_destroy_plan(plan->p); + plan->p = NULL; + } + plan->p = fftwf_plan_r2r_1d(new_dft_points, plan->in, plan->out, sign, FFTW_TYPE); + if (!plan->p) { + return -1; + } + plan->size = new_dft_points; + return 0; +} + int srslte_dft_plan_r(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) { allocate(plan,sizeof(float),sizeof(float), dft_points); int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R; - plan->p = fftwf_plan_r2r_1d(dft_points, plan->in, plan->out, sign, FFTW_MEASURE); + plan->p = fftwf_plan_r2r_1d(dft_points, plan->in, plan->out, sign, FFTW_TYPE); if (!plan->p) { return -1; } plan->size = dft_points; + plan->init_size = plan->size; plan->mode = SRSLTE_REAL; plan->dir = dir; plan->forward = (dir==SRSLTE_DFT_FORWARD)?true:false; diff --git a/lib/src/phy/dft/dft_precoding.c b/lib/src/phy/dft/dft_precoding.c index 3bec5b96e..a43d79406 100644 --- a/lib/src/phy/dft/dft_precoding.c +++ b/lib/src/phy/dft/dft_precoding.c @@ -40,37 +40,42 @@ #include "srslte/phy/dft/dft_precoding.h" /* Create DFT plans for transform precoding */ -int srslte_dft_precoding_init(srslte_dft_precoding_t *q, uint32_t max_prb) + +int srslte_dft_precoding_init(srslte_dft_precoding_t *q, uint32_t max_prb, bool is_tx) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; + int ret = SRSLTE_ERROR_INVALID_INPUTS; bzero(q, sizeof(srslte_dft_precoding_t)); - + if (max_prb <= SRSLTE_MAX_PRB) { - ret = SRSLTE_ERROR; + ret = SRSLTE_ERROR; for (uint32_t i=1;i<=max_prb;i++) { - if(srslte_dft_precoding_valid_prb(i)) { + if(srslte_dft_precoding_valid_prb(i)) { DEBUG("Initiating DFT precoding plan for %d PRBs\n", i); - if (srslte_dft_plan_c(&q->dft_plan[i], i*SRSLTE_NRE, SRSLTE_DFT_FORWARD)) { + if (srslte_dft_plan_c(&q->dft_plan[i], i*SRSLTE_NRE, is_tx?SRSLTE_DFT_FORWARD:SRSLTE_DFT_BACKWARD)) { fprintf(stderr, "Error: Creating DFT plan %d\n",i); goto clean_exit; } srslte_dft_plan_set_norm(&q->dft_plan[i], true); - if (srslte_dft_plan_c(&q->idft_plan[i], i*SRSLTE_NRE, SRSLTE_DFT_BACKWARD)) { - fprintf(stderr, "Error: Creating DFT plan %d\n",i); - goto clean_exit; - } - srslte_dft_plan_set_norm(&q->idft_plan[i], true); } } q->max_prb = max_prb; ret = SRSLTE_SUCCESS; - } + } -clean_exit: + clean_exit: if (ret == SRSLTE_ERROR) { srslte_dft_precoding_free(q); } - return ret; + return ret; +} + +int srslte_dft_precoding_init_rx(srslte_dft_precoding_t *q, uint32_t max_prb) +{ + return srslte_dft_precoding_init(q, max_prb, false); +} + +int srslte_dft_precoding_init_tx(srslte_dft_precoding_t *q, uint32_t max_prb) { + return srslte_dft_precoding_init(q, max_prb, true); } /* Free DFT plans for transform precoding */ @@ -79,7 +84,6 @@ void srslte_dft_precoding_free(srslte_dft_precoding_t *q) for (uint32_t i=1;i<=q->max_prb;i++) { if(srslte_dft_precoding_valid_prb(i)) { srslte_dft_plan_free(&q->dft_plan[i]); - srslte_dft_plan_free(&q->idft_plan[i]); } } bzero(q, sizeof(srslte_dft_precoding_t)); @@ -98,7 +102,7 @@ bool srslte_dft_precoding_valid_prb(uint32_t nof_prb) { } int srslte_dft_precoding(srslte_dft_precoding_t *q, cf_t *input, cf_t *output, - uint32_t nof_prb, uint32_t nof_symbols) + uint32_t nof_prb, uint32_t nof_symbols) { if (!srslte_dft_precoding_valid_prb(nof_prb) && nof_prb <= q->max_prb) { @@ -112,19 +116,3 @@ int srslte_dft_precoding(srslte_dft_precoding_t *q, cf_t *input, cf_t *output, return SRSLTE_SUCCESS; } - -int srslte_dft_predecoding(srslte_dft_precoding_t *q, cf_t *input, cf_t *output, - uint32_t nof_prb, uint32_t nof_symbols) -{ - if (!srslte_dft_precoding_valid_prb(nof_prb) && nof_prb <= q->max_prb) { - fprintf(stderr, "Error invalid number of PRB (%d)\n", nof_prb); - return SRSLTE_ERROR; - } - - for (uint32_t i=0;iidft_plan[nof_prb], &input[i*SRSLTE_NRE*nof_prb], &output[i*SRSLTE_NRE*nof_prb]); - } - - return SRSLTE_SUCCESS; - -} diff --git a/lib/src/phy/dft/ofdm.c b/lib/src/phy/dft/ofdm.c index 69b7e9161..db5939274 100644 --- a/lib/src/phy/dft/ofdm.c +++ b/lib/src/phy/dft/ofdm.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "srslte/phy/common/phy_common.h" #include "srslte/phy/dft/dft.h" @@ -36,7 +37,13 @@ #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" + int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb, srslte_dft_dir_t dir) { + return srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, dir, SRSLTE_SF_NORM); +} + + +int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb, srslte_dft_dir_t dir, srslte_sf_t sf_type) { if (srslte_dft_plan_c(&q->fft_plan, symbol_sz, dir)) { fprintf(stderr, "Error: Creating DFT plan\n"); @@ -48,14 +55,20 @@ int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_p return -1; } + q->shift_buffer = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN(symbol_sz)); + if (!q->shift_buffer) { + perror("malloc"); + return -1; + } + srslte_dft_plan_set_mirror(&q->fft_plan, true); srslte_dft_plan_set_dc(&q->fft_plan, true); 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->freq_shift = false; - q->shift_buffer = NULL; q->nof_re = nof_prb * SRSLTE_NRE; q->nof_guards = ((symbol_sz - q->nof_re) / 2); q->slot_sz = SRSLTE_SLOT_LEN(symbol_sz); @@ -63,6 +76,42 @@ int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_p DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n", dir==SRSLTE_DFT_FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols, q->cp==SRSLTE_CP_NORM?"Normal":"Extended", q->nof_re, q->nof_guards); + + // MBSFN logic + if (sf_type == SRSLTE_SF_MBSFN) { + q->mbsfn_subframe = true; + q->non_mbsfn_region = 2; // default set to 2 + } + + return SRSLTE_SUCCESS; +} + +void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t *q, uint8_t non_mbsfn_region) +{ + q->non_mbsfn_region = non_mbsfn_region; +} + +int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb) { + + if (srslte_dft_replan_c(&q->fft_plan, symbol_sz)) { + fprintf(stderr, "Error: Creating DFT plan\n"); + return -1; + } + + q->symbol_sz = (uint32_t) symbol_sz; + q->nof_symbols = SRSLTE_CP_NSYMB(cp); + q->cp = cp; + q->nof_re = nof_prb * SRSLTE_NRE; + q->nof_guards = ((symbol_sz - q->nof_re) / 2); + q->slot_sz = SRSLTE_SLOT_LEN(symbol_sz); + + if (q->freq_shift) { + srslte_ofdm_set_freq_shift(q, q->freq_shift_f); + } + + DEBUG("Replan symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n", + q->symbol_sz, q->nof_symbols, + q->cp==SRSLTE_CP_NORM?"Normal":"Extended", q->nof_re, q->nof_guards); return SRSLTE_SUCCESS; } @@ -78,30 +127,64 @@ void srslte_ofdm_free_(srslte_ofdm_t *q) { bzero(q, sizeof(srslte_ofdm_t)); } -int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { +int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) { + int symbol_sz = srslte_symbol_sz(max_prb); + if (symbol_sz < 0) { + fprintf(stderr, "Error: Invalid nof_prb=%d\n", max_prb); + return -1; + } + q->max_prb = max_prb; + return srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_FORWARD); +} + +int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) +{ int symbol_sz = srslte_symbol_sz(nof_prb); if (symbol_sz < 0) { fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); return -1; } - return srslte_ofdm_init_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_FORWARD); + return srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN); } -void srslte_ofdm_rx_free(srslte_ofdm_t *q) { - srslte_ofdm_free_(q); + +int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) { + uint32_t i; + int ret; + + int symbol_sz = srslte_symbol_sz(max_prb); + if (symbol_sz < 0) { + fprintf(stderr, "Error: Invalid nof_prb=%d\n", max_prb); + return -1; + } + q->max_prb = max_prb; + ret = srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_BACKWARD); + + + if (ret == SRSLTE_SUCCESS) { + srslte_dft_plan_set_norm(&q->fft_plan, false); + + /* set now zeros at CP */ + for (i=0;inof_symbols;i++) { + bzero(q->tmp, q->nof_guards * sizeof(cf_t)); + bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t)); + } + } + return ret; } -int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { +int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) +{ uint32_t i; int ret; int symbol_sz = srslte_symbol_sz(nof_prb); - if (symbol_sz < 0) { + if (symbol_sz < 0) { fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); return -1; } - ret = srslte_ofdm_init_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_BACKWARD); + ret = srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_BACKWARD, SRSLTE_SF_MBSFN); if (ret == SRSLTE_SUCCESS) { srslte_dft_plan_set_norm(&q->fft_plan, false); @@ -115,16 +198,56 @@ int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { return ret; } +int srslte_ofdm_rx_set_prb(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { + if (nof_prb <= q->max_prb) { + int symbol_sz = srslte_symbol_sz(nof_prb); + if (symbol_sz < 0) { + fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); + return -1; + } + return srslte_ofdm_replan_(q, cp, symbol_sz, nof_prb); + } else { + fprintf(stderr, "OFDM: Error calling set_prb: nof_prb must be equal or lower initialized max_prb\n"); + return -1; + } +} + +int srslte_ofdm_tx_set_prb(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { + uint32_t i; + int ret; + + if (nof_prb <= q->max_prb) { + int symbol_sz = srslte_symbol_sz(nof_prb); + if (symbol_sz < 0) { + fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); + return -1; + } + + ret = srslte_ofdm_replan_(q, cp, symbol_sz, nof_prb); + + if (ret == SRSLTE_SUCCESS) { + /* set now zeros at CP */ + for (i=0;inof_symbols;i++) { + bzero(q->tmp, q->nof_guards * sizeof(cf_t)); + bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t)); + } + } + return ret; + } else { + fprintf(stderr, "OFDM: Error calling set_prb: nof_prb must be equal or lower initialized max_prb\n"); + return -1; + } +} + + +void srslte_ofdm_rx_free(srslte_ofdm_t *q) { + srslte_ofdm_free_(q); +} /* Shifts the signal after the iFFT or before the FFT. * Freq_shift is relative to inter-carrier spacing. * Caution: This function shall not be called during run-time */ int srslte_ofdm_set_freq_shift(srslte_ofdm_t *q, float freq_shift) { - q->shift_buffer = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN(q->symbol_sz)); - if (!q->shift_buffer) { - perror("malloc"); - return -1; - } cf_t *ptr = q->shift_buffer; for (uint32_t n=0;n<2;n++) { for (uint32_t i=0;inof_symbols;i++) { @@ -140,7 +263,7 @@ int srslte_ofdm_set_freq_shift(srslte_ofdm_t *q, float freq_shift) { srslte_dft_plan_set_dc(&q->fft_plan, false); q->freq_shift = true; - + q->freq_shift_f = freq_shift; return SRSLTE_SUCCESS; } @@ -162,6 +285,23 @@ void srslte_ofdm_rx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output) { } } +void srslte_ofdm_rx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output) +{ + uint32_t i; + for(i = 0; i < q->nof_symbols_mbsfn; i++){ + if(i == q->non_mbsfn_region) { + input += SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(q->non_mbsfn_region,q->symbol_sz); + } + input += (i>=q->non_mbsfn_region)?SRSLTE_CP_LEN_EXT(q->symbol_sz):SRSLTE_CP_LEN_NORM(i, q->symbol_sz); + srslte_dft_run_c(&q->fft_plan, input, q->tmp); + memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t)); + input += q->symbol_sz; + output += q->nof_re; + } +} + + + void srslte_ofdm_rx_slot_zerocopy(srslte_ofdm_t *q, cf_t *input, cf_t *output) { uint32_t i; for (i=0;inof_symbols;i++) { @@ -179,8 +319,14 @@ void srslte_ofdm_rx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) { if (q->freq_shift) { srslte_vec_prod_ccc(input, q->shift_buffer, input, 2*q->slot_sz); } - for (n=0;n<2;n++) { - srslte_ofdm_rx_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); + if(!q->mbsfn_subframe){ + for (n=0;n<2;n++) { + srslte_ofdm_rx_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); + } + } + else{ + srslte_ofdm_rx_slot_mbsfn(q, &input[0*q->slot_sz], &output[0*q->nof_re*q->nof_symbols]); + srslte_ofdm_rx_slot(q, &input[1*q->slot_sz], &output[1*q->nof_re*q->nof_symbols]); } } @@ -200,16 +346,43 @@ void srslte_ofdm_tx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output) { } } +void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output) +{ + uint32_t i, cp_len; + + for(i=0;inof_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)); + srslte_dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]); + input += q->nof_re; + /* add CP */ + memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t)); + output += q->symbol_sz + cp_len; + + /*skip the small section between the non mbms region and the mbms region*/ + if(i == (q->non_mbsfn_region - 1)) + output += SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(q->non_mbsfn_region,q->symbol_sz); + } +} + void srslte_ofdm_set_normalize(srslte_ofdm_t *q, bool normalize_enable) { srslte_dft_plan_set_norm(&q->fft_plan, normalize_enable); } -void srslte_ofdm_tx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) { +void srslte_ofdm_tx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) +{ uint32_t n; - for (n=0;n<2;n++) { - srslte_ofdm_tx_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]); + if(!q->mbsfn_subframe){ + for (n=0;n<2;n++) { + srslte_ofdm_tx_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]); + } + } + else{ + srslte_ofdm_tx_slot_mbsfn(q, &input[0*q->nof_re*q->nof_symbols], &output[0*q->slot_sz]); + srslte_ofdm_tx_slot(q, &input[1*q->nof_re*q->nof_symbols], &output[1*q->slot_sz]); } if (q->freq_shift) { srslte_vec_prod_ccc(output, q->shift_buffer, output, 2*q->slot_sz); } } + diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index 39606ff7f..2ba179399 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb) @@ -39,78 +41,67 @@ #define SRSLTE_ENB_RF_AMP 0.1 -int srslte_enb_dl_init(srslte_enb_dl_t *q, srslte_cell_t cell) +int srslte_enb_dl_init(srslte_enb_dl_t *q, uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_enb_dl_t)); - q->cell = cell; - q->cfi = 3; + q->cfi = 3; q->tx_amp = SRSLTE_ENB_RF_AMP; - if (srslte_ofdm_tx_init(&q->ifft, q->cell.cp, q->cell.nof_prb)) { + if (srslte_ofdm_tx_init(&q->ifft, SRSLTE_CP_NORM, max_prb)) { fprintf(stderr, "Error initiating FFT\n"); goto clean_exit; } srslte_ofdm_set_normalize(&q->ifft, true); - if (srslte_regs_init(&q->regs, q->cell)) { - fprintf(stderr, "Error initiating REGs\n"); - goto clean_exit; - } - if (srslte_pbch_init(&q->pbch, q->cell)) { + if (srslte_pbch_init(&q->pbch)) { fprintf(stderr, "Error creating PBCH object\n"); goto clean_exit; } - if (srslte_pcfich_init(&q->pcfich, &q->regs, q->cell)) { + if (srslte_pcfich_init(&q->pcfich, 0)) { fprintf(stderr, "Error creating PCFICH object\n"); goto clean_exit; } - if (srslte_phich_init(&q->phich, &q->regs, q->cell)) { + if (srslte_phich_init(&q->phich, 0)) { fprintf(stderr, "Error creating PHICH object\n"); goto clean_exit; } - if (srslte_pdcch_init(&q->pdcch, &q->regs, q->cell)) { + if (srslte_pdcch_init_enb(&q->pdcch, max_prb)) { fprintf(stderr, "Error creating PDCCH object\n"); goto clean_exit; } - if (srslte_pdsch_init_tx(&q->pdsch, q->cell)) { + if (srslte_pdsch_init_enb(&q->pdsch, max_prb)) { fprintf(stderr, "Error creating PDSCH object\n"); goto clean_exit; } - if (srslte_refsignal_cs_init(&q->csr_signal, q->cell)) { + if (srslte_refsignal_cs_init(&q->csr_signal, max_prb)) { fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); goto clean_exit; } - for (int i=0;icell.nof_ports;i++) { - q->sf_symbols[i] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + for (int i=0;isf_symbols[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); if (!q->sf_symbols[i]) { perror("malloc"); goto clean_exit; } - q->slot1_symbols[i] = &q->sf_symbols[i][CURRENT_SLOTLEN_RE]; + q->slot1_symbols[i] = &q->sf_symbols[i][SRSLTE_SLOT_LEN_RE(max_prb, SRSLTE_CP_NORM)]; } - /* Generate PSS/SSS signals */ - srslte_pss_generate(q->pss_signal, cell.id%3); - srslte_sss_generate(q->sss_signal0, q->sss_signal5, cell.id); - ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", - cell.id, cell.nof_ports, cell.nof_prb); + fprintf(stderr, "Invalid parameters\n"); } clean_exit: @@ -125,12 +116,13 @@ void srslte_enb_dl_free(srslte_enb_dl_t *q) if (q) { srslte_ofdm_tx_free(&q->ifft); 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_refsignal_cs_free(&q->csr_signal); + srslte_refsignal_free(&q->csr_signal); for (int i=0;isf_symbols[i]) { @@ -141,6 +133,71 @@ void srslte_enb_dl_free(srslte_enb_dl_t *q) } } +int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + srslte_cell_isvalid(&cell)) + { + srslte_enb_dl_set_cfi(q, 3); + q->tx_amp = SRSLTE_ENB_RF_AMP; + + if (q->cell.id != cell.id || q->cell.nof_prb == 0) { + if (q->cell.nof_prb != 0) { + srslte_regs_free(&q->regs); + } + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + if (srslte_regs_init(&q->regs, q->cell)) { + fprintf(stderr, "Error resizing REGs\n"); + return SRSLTE_ERROR; + } + if (srslte_ofdm_rx_set_prb(&q->ifft, q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error initiating FFT\n"); + return SRSLTE_ERROR; + } + if (srslte_pbch_set_cell(&q->pbch, q->cell)) { + fprintf(stderr, "Error creating PBCH object\n"); + return SRSLTE_ERROR; + } + if (srslte_pcfich_set_cell(&q->pcfich, &q->regs, q->cell)) { + fprintf(stderr, "Error creating PCFICH object\n"); + return SRSLTE_ERROR; + } + if (srslte_phich_set_cell(&q->phich, &q->regs, q->cell)) { + fprintf(stderr, "Error creating PHICH object\n"); + return SRSLTE_ERROR; + } + + if (srslte_pdcch_set_cell(&q->pdcch, &q->regs, q->cell)) { + fprintf(stderr, "Error creating PDCCH object\n"); + return SRSLTE_ERROR; + } + + if (srslte_pdsch_set_cell(&q->pdsch, q->cell)) { + fprintf(stderr, "Error creating PDSCH 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; + } + /* Generate PSS/SSS signals */ + srslte_pss_generate(q->pss_signal, cell.id%3); + srslte_sss_generate(q->sss_signal0, q->sss_signal5, cell.id); + } + ret = SRSLTE_SUCCESS; + + } else { + fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + cell.id, cell.nof_ports, cell.nof_prb); + } + return ret; +} + + + void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, float amp) { q->tx_amp = amp; @@ -263,11 +320,11 @@ int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant, } int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS], - uint16_t rnti, uint32_t rv_idx, uint32_t sf_idx, - uint8_t *data[SRSLTE_MAX_CODEWORDS]) + uint16_t rnti, int rv_idx[SRSLTE_MAX_CODEWORDS], uint32_t sf_idx, + uint8_t *data[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, uint32_t pmi) { /* Configure pdsch_cfg parameters */ - if (srslte_pdsch_cfg(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx)) { + if (srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx, mimo_type, pmi)) { fprintf(stderr, "Error configuring PDSCH\n"); return SRSLTE_ERROR; } @@ -279,3 +336,33 @@ int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srs } 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) +{ + char tmpstr[64]; + + snprintf(tmpstr,64,"output/sf_symbols_%d",tti); + srslte_vec_save_file(tmpstr, q->sf_symbols[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + + snprintf(tmpstr,64,"output/e_%d",tti); + srslte_bit_unpack_vector(q->pdsch.e[0], q->tmp, q->pdsch_cfg.nbits[0].nof_bits); + srslte_vec_save_file(tmpstr, q->tmp, q->pdsch_cfg.nbits[0].nof_bits*sizeof(uint8_t)); + + /* + int cb_len = q->pdsch_cfg.cb_segm[0].K1; + for (int i=0;ipdsch_cfg.cb_segm[0].C;i++) { + snprintf(tmpstr,64,"output/rmout_%d_%d",i,tti); + srslte_bit_unpack_vector(softbuffer->buffer_b[i], q->tmp, (3*cb_len+12)); + srslte_vec_save_file(tmpstr, q->tmp, (3*cb_len+12)*sizeof(uint8_t)); + }*/ + + snprintf(tmpstr,64,"output/data_%d",tti); + srslte_bit_unpack_vector(data, q->tmp, q->pdsch_cfg.grant.mcs[0].tbs); + srslte_vec_save_file(tmpstr, q->tmp, q->pdsch_cfg.grant.mcs[0].tbs*sizeof(uint8_t)); + + //printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, tbs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, + // q->pdsch_cfg.grant.mcs[0].idx, q->pdsch_cfg.grant.mcs[0].tbs, rv_idx, rnti); +} + diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index 9d773d6d5..db05d44ea 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -39,78 +39,54 @@ #define MAX_CANDIDATES 16 -int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, - srslte_prach_cfg_t *prach_cfg, - srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, - srslte_pusch_hopping_cfg_t *hopping_cfg, - srslte_pucch_cfg_t *pucch_cfg) +int srslte_enb_ul_init(srslte_enb_ul_t *q, + uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_enb_ul_t)); - q->cell = cell; - - if (hopping_cfg) { - memcpy(&q->hopping_cfg, hopping_cfg, sizeof(srslte_pusch_hopping_cfg_t)); - } - - q->users = calloc(sizeof(srslte_enb_ul_user_t*), SRSLTE_SIRNTI); + q->users = calloc(sizeof(srslte_enb_ul_user_t*), (1+SRSLTE_SIRNTI)); if (!q->users) { perror("malloc"); goto clean_exit; } - if (srslte_ofdm_rx_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { + if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, max_prb)) { fprintf(stderr, "Error initiating FFT\n"); goto clean_exit; } srslte_ofdm_set_normalize(&q->fft, false); srslte_ofdm_set_freq_shift(&q->fft, -0.5); - if (srslte_pucch_init(&q->pucch, q->cell)) { + if (srslte_pucch_init(&q->pucch)) { fprintf(stderr, "Error creating PUCCH object\n"); goto clean_exit; } - if (srslte_pusch_init(&q->pusch, q->cell)) { + if (srslte_pusch_init_enb(&q->pusch, max_prb)) { fprintf(stderr, "Error creating PUSCH object\n"); goto clean_exit; } - - if (prach_cfg) { - if (srslte_prach_init_cfg(&q->prach, prach_cfg, q->cell.nof_prb)) { - fprintf(stderr, "Error initiating PRACH\n"); - goto clean_exit; - } - srslte_prach_set_detect_factor(&q->prach, 60); - } - + srslte_pucch_set_threshold(&q->pucch, 0.8); - - if (srslte_chest_ul_init(&q->chest, cell)) { + + if (srslte_chest_ul_init(&q->chest, max_prb)) { fprintf(stderr, "Error initiating channel estimator\n"); goto clean_exit; } - - // Configure common PUCCH configuration - srslte_pucch_set_cfg(&q->pucch, pucch_cfg, pusch_cfg->group_hopping_en); - - // SRS is a dedicated configuration - srslte_chest_ul_set_cfg(&q->chest, pusch_cfg, pucch_cfg, NULL); - - q->sf_symbols = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + + q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); if (!q->sf_symbols) { perror("malloc"); goto clean_exit; } - q->ce = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + q->ce = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); if (!q->ce) { perror("malloc"); goto clean_exit; @@ -119,8 +95,7 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", - cell.id, cell.nof_ports, cell.nof_prb); + fprintf(stderr, "Invalid parameters\n"); } clean_exit: @@ -135,7 +110,7 @@ void srslte_enb_ul_free(srslte_enb_ul_t *q) if (q) { if (q->users) { - for (int i=0;iusers[i]) { free(q->users[i]); } @@ -158,11 +133,73 @@ void srslte_enb_ul_free(srslte_enb_ul_t *q) } } +int srslte_enb_ul_set_cell(srslte_enb_ul_t *q, srslte_cell_t cell, + srslte_prach_cfg_t *prach_cfg, + srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, + srslte_pusch_hopping_cfg_t *hopping_cfg, + srslte_pucch_cfg_t *pucch_cfg) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + srslte_cell_isvalid(&cell)) + { + if (cell.id != q->cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + + if (hopping_cfg) { + memcpy(&q->hopping_cfg, hopping_cfg, sizeof(srslte_pusch_hopping_cfg_t)); + } + + if (srslte_ofdm_rx_set_prb(&q->fft, q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error initiating FFT\n"); + return SRSLTE_ERROR; + } + + if (srslte_pucch_set_cell(&q->pucch, q->cell)) { + fprintf(stderr, "Error creating PUCCH object\n"); + return SRSLTE_ERROR; + } + + if (srslte_pusch_set_cell(&q->pusch, q->cell)) { + fprintf(stderr, "Error creating PUSCH object\n"); + return SRSLTE_ERROR; + } + + if (prach_cfg) { + if (srslte_prach_init_cfg(&q->prach, prach_cfg, q->cell.nof_prb)) { + fprintf(stderr, "Error initiating PRACH\n"); + return SRSLTE_ERROR; + } + srslte_prach_set_detect_factor(&q->prach, 60); + } + + if (srslte_chest_ul_set_cell(&q->chest, cell)) { + fprintf(stderr, "Error initiating channel estimator\n"); + return SRSLTE_ERROR; + } + + // Configure common PUCCH configuration + srslte_pucch_set_cfg(&q->pucch, pucch_cfg, pusch_cfg->group_hopping_en); + + // SRS is a dedicated configuration + srslte_chest_ul_set_cfg(&q->chest, pusch_cfg, pucch_cfg, NULL); + + ret = SRSLTE_SUCCESS; + } + } else { + fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + cell.id, cell.nof_ports, cell.nof_prb); + } + return ret; +} + + int srslte_enb_ul_add_rnti(srslte_enb_ul_t *q, uint16_t rnti) { if (!q->users[rnti]) { - q->users[rnti] = malloc(sizeof(srslte_enb_ul_user_t)); - + q->users[rnti] = calloc(1, sizeof(srslte_enb_ul_user_t)); + if (srslte_pucch_set_crnti(&q->pucch, rnti)) { fprintf(stderr, "Error setting PUCCH rnti\n"); return -1; @@ -183,7 +220,7 @@ void srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint16_t rnti) if (q->users[rnti]) { free(q->users[rnti]); q->users[rnti] = NULL; - srslte_pusch_clear_rnti(&q->pusch, rnti); + srslte_pusch_free_rnti(&q->pusch, rnti); } } diff --git a/lib/src/phy/fec/test/turbodecoder_test.c b/lib/src/phy/fec/test/turbodecoder_test.c index df1d4b884..aeac21433 100644 --- a/lib/src/phy/fec/test/turbodecoder_test.c +++ b/lib/src/phy/fec/test/turbodecoder_test.c @@ -117,7 +117,7 @@ int main(int argc, char **argv) { float *llr; short *llr_s; uint8_t *llr_c; - uint8_t *data_tx, *data_rx, *data_rx_bytes[SRSLTE_TDEC_NPAR], *symbols; + uint8_t *data_tx, *data_rx, *data_rx_bytes[SRSLTE_TDEC_MAX_NPAR], *symbols; uint32_t i, j; float var[SNR_POINTS]; uint32_t snr_points; @@ -159,7 +159,7 @@ int main(int argc, char **argv) { perror("malloc"); exit(-1); } - for (int cb=0;cbtdec_simd, SRSLTE_TDEC_NPAR, max_long_cb); + return srslte_tdec_simd_init(&h->tdec_simd, SRSLTE_TDEC_MAX_NPAR, max_long_cb); #else h->input_conv = srslte_vec_malloc(sizeof(float) * (3*max_long_cb+12)); if (!h->input_conv) { @@ -91,7 +91,7 @@ int srslte_tdec_get_nof_iterations_cb(srslte_tdec_t * h, uint32_t cb_idx) #endif } -void srslte_tdec_iteration_par(srslte_tdec_t * h, int16_t* input[SRSLTE_TDEC_NPAR], uint32_t long_cb) { +void srslte_tdec_iteration_par(srslte_tdec_t * h, int16_t* input[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { #ifdef LV_HAVE_SSE srslte_tdec_simd_iteration(&h->tdec_simd, input, long_cb); #else @@ -101,12 +101,12 @@ void srslte_tdec_iteration_par(srslte_tdec_t * h, int16_t* input[SRSLTE_TDEC_NPA } void srslte_tdec_iteration(srslte_tdec_t * h, int16_t* input, uint32_t long_cb) { - int16_t *input_par[SRSLTE_TDEC_NPAR]; + int16_t *input_par[SRSLTE_TDEC_MAX_NPAR]; input_par[0] = input; return srslte_tdec_iteration_par(h, input_par, long_cb); } -void srslte_tdec_decision_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_NPAR], uint32_t long_cb) { +void srslte_tdec_decision_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { #ifdef LV_HAVE_SSE return srslte_tdec_simd_decision(&h->tdec_simd, output, long_cb); #else @@ -114,13 +114,21 @@ void srslte_tdec_decision_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_NPA #endif } +uint32_t srslte_tdec_get_nof_parallel(srslte_tdec_t *h) { +#ifdef LV_HAVE_AVX2 + return 2; +#else + return 1; +#endif +} + void srslte_tdec_decision(srslte_tdec_t * h, uint8_t *output, uint32_t long_cb) { - uint8_t *output_par[SRSLTE_TDEC_NPAR]; + uint8_t *output_par[SRSLTE_TDEC_MAX_NPAR]; output_par[0] = output; srslte_tdec_decision_par(h, output_par, long_cb); } -void srslte_tdec_decision_byte_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_NPAR], uint32_t long_cb) { +void srslte_tdec_decision_byte_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { #ifdef LV_HAVE_SSE srslte_tdec_simd_decision_byte(&h->tdec_simd, output, long_cb); #else @@ -137,13 +145,13 @@ void srslte_tdec_decision_byte_par_cb(srslte_tdec_t * h, uint8_t *output, uint32 } void srslte_tdec_decision_byte(srslte_tdec_t * h, uint8_t *output, uint32_t long_cb) { - uint8_t *output_par[SRSLTE_TDEC_NPAR]; + uint8_t *output_par[SRSLTE_TDEC_MAX_NPAR]; output_par[0] = output; srslte_tdec_decision_byte_par(h, output_par, long_cb); } -int srslte_tdec_run_all_par(srslte_tdec_t * h, int16_t * input[SRSLTE_TDEC_NPAR], - uint8_t *output[SRSLTE_TDEC_NPAR], +int srslte_tdec_run_all_par(srslte_tdec_t * h, int16_t * input[SRSLTE_TDEC_MAX_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_iterations, uint32_t long_cb) { #ifdef LV_HAVE_SSE return srslte_tdec_simd_run_all(&h->tdec_simd, input, output, nof_iterations, long_cb); @@ -155,9 +163,9 @@ int srslte_tdec_run_all_par(srslte_tdec_t * h, int16_t * input[SRSLTE_TDEC_NPAR] int srslte_tdec_run_all(srslte_tdec_t * h, int16_t * input, uint8_t *output, uint32_t nof_iterations, uint32_t long_cb) { - uint8_t *output_par[SRSLTE_TDEC_NPAR]; + uint8_t *output_par[SRSLTE_TDEC_MAX_NPAR]; output_par[0] = output; - int16_t *input_par[SRSLTE_TDEC_NPAR]; + int16_t *input_par[SRSLTE_TDEC_MAX_NPAR]; input_par[0] = input; return srslte_tdec_run_all_par(h, input_par, output_par, nof_iterations, long_cb); diff --git a/lib/src/phy/fec/turbodecoder_avx.c b/lib/src/phy/fec/turbodecoder_avx.c index 2a2f6f925..2e877cbde 100644 --- a/lib/src/phy/fec/turbodecoder_avx.c +++ b/lib/src/phy/fec/turbodecoder_avx.c @@ -81,7 +81,7 @@ static inline int16_t hMax1(__m256i masked_value) } /* Computes beta values */ -void map_avx_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_NPAR], uint32_t long_cb) +void map_avx_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { int k; uint32_t end = long_cb + 3; diff --git a/lib/src/phy/fec/turbodecoder_simd.c b/lib/src/phy/fec/turbodecoder_simd.c index e245c84a4..a32d52962 100644 --- a/lib/src/phy/fec/turbodecoder_simd.c +++ b/lib/src/phy/fec/turbodecoder_simd.c @@ -54,13 +54,13 @@ void map_sse_alpha(map_gen_t * s, uint32_t long_cb); void map_sse_gamma(map_gen_t * h, int16_t *input, int16_t *app, int16_t *parity, uint32_t long_cb); #ifdef LV_HAVE_AVX2 -void map_avx_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_NPAR], uint32_t long_cb); +void map_avx_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); void map_avx_alpha(map_gen_t * s, uint32_t long_cb); void map_avx_gamma(map_gen_t * h, int16_t *input, int16_t *app, int16_t *parity, uint32_t cbidx, uint32_t long_cb); #endif -void map_simd_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_NPAR], uint32_t nof_cb, uint32_t long_cb) +void map_simd_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb) { if (nof_cb == 1) { map_sse_beta(s, output[0], long_cb); @@ -128,12 +128,12 @@ void map_simd_free(map_gen_t * h) } /* Runs one instance of a decoder */ -void map_simd_dec(map_gen_t * h, int16_t * input[SRSLTE_TDEC_NPAR], int16_t *app[SRSLTE_TDEC_NPAR], int16_t * parity[SRSLTE_TDEC_NPAR], - int16_t *output[SRSLTE_TDEC_NPAR], uint32_t cb_mask, uint32_t long_cb) +void map_simd_dec(map_gen_t * h, int16_t * input[SRSLTE_TDEC_MAX_NPAR], int16_t *app[SRSLTE_TDEC_MAX_NPAR], int16_t * parity[SRSLTE_TDEC_MAX_NPAR], + int16_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t cb_mask, uint32_t long_cb) { uint32_t nof_cb = 1; - int16_t *outptr[SRSLTE_TDEC_NPAR]; + int16_t *outptr[SRSLTE_TDEC_MAX_NPAR]; // Compute branch metrics switch(cb_mask) { @@ -354,21 +354,21 @@ void deinterleave_input_simd(srslte_tdec_simd_t *h, int16_t *input, uint32_t cbi } /* Runs 1 turbo decoder iteration */ -void srslte_tdec_simd_iteration(srslte_tdec_simd_t * h, int16_t * input[SRSLTE_TDEC_NPAR], uint32_t long_cb) +void srslte_tdec_simd_iteration(srslte_tdec_simd_t * h, int16_t * input[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { - int16_t *tmp_app[SRSLTE_TDEC_NPAR]; + int16_t *tmp_app[SRSLTE_TDEC_MAX_NPAR]; if (h->current_cbidx >= 0) { uint16_t *inter = h->interleaver[h->current_cbidx].forward; uint16_t *deinter = h->interleaver[h->current_cbidx].reverse; -#if SRSLTE_TDEC_NPAR == 2 - h->cb_mask = (input[0]?1:0) | (input[1]?2:0); -#else - h->cb_mask = input[0]?1:0; +#ifndef LV_HAVE_AVX2 + input[1] = NULL; #endif - + + h->cb_mask = (input[0]?1:0) | (input[1]?2:0); + for (int i=0;imax_par_cb;i++) { if (h->n_iter[i] == 0 && input[i]) { //printf("deinterleaveing %d\n",i); @@ -484,7 +484,7 @@ void tdec_simd_decision(srslte_tdec_simd_t * h, uint8_t *output, uint32_t cbidx, } } -void srslte_tdec_simd_decision(srslte_tdec_simd_t * h, uint8_t *output[SRSLTE_TDEC_NPAR], uint32_t long_cb) +void srslte_tdec_simd_decision(srslte_tdec_simd_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { for (int i=0;imax_par_cb;i++) { tdec_simd_decision(h, output[i], i, long_cb); @@ -510,7 +510,7 @@ void srslte_tdec_simd_decision_byte_cb(srslte_tdec_simd_t * h, uint8_t *output, } } -void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, uint8_t *output[SRSLTE_TDEC_NPAR], uint32_t long_cb) +void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { for (int i=0;imax_par_cb;i++) { srslte_tdec_simd_decision_byte_cb(h, output[i], i, long_cb); @@ -519,7 +519,7 @@ void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, uint8_t *output[SRSL /* Runs nof_iterations iterations and decides the output bits */ -int srslte_tdec_simd_run_all(srslte_tdec_simd_t * h, int16_t * input[SRSLTE_TDEC_NPAR], uint8_t *output[SRSLTE_TDEC_NPAR], +int srslte_tdec_simd_run_all(srslte_tdec_simd_t * h, int16_t * input[SRSLTE_TDEC_MAX_NPAR], uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_iterations, uint32_t long_cb) { if (srslte_tdec_simd_reset(h, long_cb)) { diff --git a/lib/src/phy/fec/turbodecoder_simd_inter.c b/lib/src/phy/fec/turbodecoder_simd_inter.c index 05d8b2cf5..3c04e2136 100644 --- a/lib/src/phy/fec/turbodecoder_simd_inter.c +++ b/lib/src/phy/fec/turbodecoder_simd_inter.c @@ -172,7 +172,7 @@ void extract_input(srslte_tdec_simd_inter_t *h, int16_t *input, uint32_t cbidx, } } -void srslte_tdec_simd_inter_iteration(srslte_tdec_simd_inter_t * h, int16_t *input[SRSLTE_TDEC_NPAR], uint32_t nof_cb, uint32_t long_cb) +void srslte_tdec_simd_inter_iteration(srslte_tdec_simd_inter_t * h, int16_t *input[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb) { if (h->current_cbidx >= 0) { @@ -239,7 +239,7 @@ void srslte_tdec_simd_inter_decision_cb(srslte_tdec_simd_inter_t * h, uint8_t *o } } -void srslte_tdec_simd_inter_decision(srslte_tdec_simd_inter_t * h, uint8_t *output[SRSLTE_TDEC_NPAR], uint32_t nof_cb, uint32_t long_cb) +void srslte_tdec_simd_inter_decision(srslte_tdec_simd_inter_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb) { for (int i=0;i -#include "srslte/phy/utils/mat.h" int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols); #endif #ifdef LV_HAVE_AVX #include -#include "srslte/phy/utils/mat.h" int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); #endif +#include "srslte/phy/utils/mat.h" static srslte_mimo_decoder_t mimo_decoder = SRSLTE_MIMO_DECODER_MMSE; @@ -1368,7 +1367,7 @@ int srslte_predecoding_multiplex(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_P int nof_rxant, int nof_ports, int nof_layers, int codebook_idx, int nof_symbols, float noise_estimate) { - if (nof_ports == 2 && nof_rxant == 2) { + if (nof_ports == 2 && nof_rxant <= 2) { if (nof_layers == 2) { switch (mimo_decoder) { case SRSLTE_MIMO_DECODER_ZF: @@ -1408,7 +1407,7 @@ int srslte_predecoding_multiplex(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_P } else if (nof_ports == 4) { ERROR("Error predecoding multiplex: not implemented for %d Tx ports", nof_ports); } else { - ERROR("Error predecoding multiplex: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); + ERROR("Error predecoding multiplex: Invalid combination of ports %d and rx antennas %d\n", nof_ports, nof_rxant); } return SRSLTE_ERROR; } diff --git a/lib/src/phy/phch/pbch.c b/lib/src/phy/phch/pbch.c index 783ae1e04..2eaa20501 100644 --- a/lib/src/phy/phch/pbch.c +++ b/lib/src/phy/phch/pbch.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "prb_dl.h" #include "srslte/phy/phch/pbch.h" @@ -43,7 +45,6 @@ #define PBCH_RE_CP_NORM 240 #define PBCH_RE_CP_EXT 216 - const uint8_t srslte_crc_mask[4][16] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, @@ -139,33 +140,18 @@ int srslte_pbch_get(cf_t *slot1_data, cf_t *pbch, srslte_cell_t cell) { * At the receiver, the field nof_ports in the cell structure indicates the * maximum number of BS transmitter ports to look for. */ -int srslte_pbch_init(srslte_pbch_t *q, srslte_cell_t cell) { +int srslte_pbch_init(srslte_pbch_t *q) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_pbch_t)); - - if (cell.nof_ports == 0) { - q->search_all_ports = true; - cell.nof_ports = SRSLTE_MAX_PORTS; - } else { - q->search_all_ports = false; - } - - q->cell = cell; - q->nof_symbols = (SRSLTE_CP_ISNORM(q->cell.cp)) ? PBCH_RE_CP_NORM : PBCH_RE_CP_EXT; - + if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { goto clean; } - if (srslte_sequence_pbch(&q->seq, q->cell.cp, q->cell.id)) { - goto clean; - } - int poly[3] = { 0x6D, 0x4F, 0x57 }; if (srslte_viterbi_init(&q->decoder, SRSLTE_VITERBI_37, poly, 40, true)) { goto clean; @@ -178,12 +164,14 @@ int srslte_pbch_init(srslte_pbch_t *q, srslte_cell_t cell) { q->encoder.tail_biting = true; memcpy(q->encoder.poly, poly, 3 * sizeof(int)); + q->nof_symbols = PBCH_RE_CP_NORM; + q->d = srslte_vec_malloc(sizeof(cf_t) * q->nof_symbols); if (!q->d) { goto clean; } int i; - for (i = 0; i < q->cell.nof_ports; i++) { + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->nof_symbols); if (!q->ce[i]) { goto clean; @@ -209,6 +197,7 @@ int srslte_pbch_init(srslte_pbch_t *q, srslte_cell_t cell) { if (!q->rm_b) { goto clean; } + ret = SRSLTE_SUCCESS; } clean: @@ -219,11 +208,11 @@ clean: } void srslte_pbch_free(srslte_pbch_t *q) { - if (q->d) { - free(q->d); - } + srslte_sequence_free(&q->seq); + srslte_modem_table_free(&q->mod); + srslte_viterbi_free(&q->decoder); int i; - for (i = 0; i < q->cell.nof_ports; i++) { + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { if (q->ce[i]) { free(q->ce[i]); } @@ -243,12 +232,36 @@ void srslte_pbch_free(srslte_pbch_t *q) { if (q->rm_b) { free(q->rm_b); } - srslte_sequence_free(&q->seq); - srslte_modem_table_free(&q->mod); - srslte_viterbi_free(&q->decoder); - + if (q->d) { + free(q->d); + } bzero(q, sizeof(srslte_pbch_t)); +} +int srslte_pbch_set_cell(srslte_pbch_t *q, srslte_cell_t cell) { + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + srslte_cell_isvalid(&cell)) + { + if (cell.nof_ports == 0) { + q->search_all_ports = true; + cell.nof_ports = SRSLTE_MAX_PORTS; + } else { + q->search_all_ports = false; + } + + if (q->cell.id != cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + if (srslte_sequence_pbch(&q->seq, q->cell.cp, q->cell.id)) { + return SRSLTE_ERROR; + } + } + q->nof_symbols = (SRSLTE_CP_ISNORM(q->cell.cp)) ? PBCH_RE_CP_NORM : PBCH_RE_CP_EXT; + + ret = SRSLTE_SUCCESS; + } + return ret; } @@ -476,6 +489,7 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS } else { nant = q->cell.nof_ports; } + do { if (nant != 3) { DEBUG("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); @@ -486,7 +500,7 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate); } else { srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant, - q->nof_symbols); + q->nof_symbols); srslte_layerdemap_diversity(x, q->d, nant, q->nof_symbols / nant); } @@ -577,7 +591,7 @@ int srslte_pbch_encode(srslte_pbch_t *q, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_ if (q->cell.nof_ports > 1) { srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, - q->nof_symbols / q->cell.nof_ports); + q->nof_symbols / q->cell.nof_ports); } else { memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/pcfich.c b/lib/src/phy/phch/pcfich.c index ec1e13abc..d960504fe 100644 --- a/lib/src/phy/phch/pcfich.c +++ b/lib/src/phy/phch/pcfich.c @@ -57,38 +57,24 @@ bool srslte_pcfich_exists(int nframe, int nslot) { return true; } -int srslte_pcfich_init(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t cell) { - return srslte_pcfich_init_multi(q, regs, cell, 1); -} - /** Initializes the pcfich channel receiver. * On error, returns -1 and frees the structrure */ -int srslte_pcfich_init_multi(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) { +int srslte_pcfich_init(srslte_pcfich_t *q, uint32_t nof_rx_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - regs != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_pcfich_t)); - q->cell = cell; - q->regs = regs; + q->nof_rx_antennas = nof_rx_antennas; q->nof_symbols = PCFICH_RE; - q->nof_rx_antennas = nof_rx_antennas; - + if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { goto clean; } - for (int nsf = 0; nsf < SRSLTE_NSUBFRAMES_X_FRAME; nsf++) { - if (srslte_sequence_pcfich(&q->seq[nsf], 2 * nsf, q->cell.id)) { - goto clean; - } - } - /* convert cfi bit tables to floats for demodulation */ for (int i=0;i<3;i++) { for (int j=0;jregs = regs; + if (cell.id != q->cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + for (int nsf = 0; nsf < SRSLTE_NSUBFRAMES_X_FRAME; nsf++) { + if (srslte_sequence_pcfich(&q->seq[nsf], 2 * nsf, q->cell.id)) { + return SRSLTE_ERROR; + } + } + } + ret = SRSLTE_SUCCESS; + } + return ret; +} + + /** Finds the CFI with minimum distance with the vector of received 32 bits. * Saves the CFI value in the cfi pointer and returns the distance. */ @@ -197,7 +205,7 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P } q_symbols[j] = q->symbols[j]; - + /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, ce[i][j], q->ce[i][j])) { diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index f4c59b321..215324e6b 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -61,41 +61,20 @@ float srslte_pdcch_coderate(uint32_t nof_bits, uint32_t l) { } /** Initializes the PDCCH transmitter and receiver */ -int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) { - return srslte_pdcch_init_multi(q, regs, cell, 1); -} - -int srslte_pdcch_init_tx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) { - return srslte_pdcch_init_txrx(q, regs, cell, 1, false); -} - -int srslte_pdcch_init_rx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) { - return srslte_pdcch_init_txrx(q, regs, cell, nof_rx_antennas, true); -} - -int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) { - return srslte_pdcch_init_txrx(q, regs, cell, nof_rx_antennas, true); -} - -int srslte_pdcch_init_txrx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas, bool isReceiver) +static int pdcch_init(srslte_pdcch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas, bool is_ue) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - regs != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_pdcch_t)); - q->cell = cell; - q->regs = regs; - q->nof_rx_antennas = nof_rx_antennas; - + q->nof_rx_antennas = nof_rx_antennas; + q->is_ue = is_ue; /* Allocate memory for the maximum number of PDCCH bits (CFI=3) */ - q->max_bits = (srslte_regs_pdcch_nregs(q->regs, 3) / 9) * 72; + q->max_bits = max_prb*3*12*2; - INFO("Init PDCCH: Max bits: %d, %d ports.\n", - q->max_bits, q->cell.nof_ports); + INFO("Init PDCCH: Max bits: %d\n", q->max_bits); if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { goto clean; @@ -104,14 +83,6 @@ int srslte_pdcch_init_txrx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t goto clean; } - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - // we need to pregenerate the sequence for the maximum number of bits, which is 8 times - // the maximum number of REGs (for CFI=3) - if (srslte_sequence_pdcch(&q->seq[i], 2 * i, q->cell.id, 8*srslte_regs_pdcch_nregs(q->regs, 3))) { - goto clean; - } - } - int poly[3] = { 0x6D, 0x4F, 0x57 }; if (srslte_viterbi_init(&q->decoder, SRSLTE_VITERBI_37, poly, SRSLTE_DCI_MAX_BITS + 16, true)) { goto clean; @@ -134,29 +105,23 @@ int srslte_pdcch_init_txrx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t goto clean; } - if (isReceiver) { - for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { - for (int j = 0; j < q->nof_rx_antennas; j++) { - q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); - if (!q->ce[i][j]) { - goto clean; - } - } - } - } - for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->x[i]) { goto clean; } - } - - for (int j = 0; j < ((isReceiver) ? q->nof_rx_antennas : cell.nof_ports); j++) { - q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); - if (!q->symbols[j]) { + q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->symbols[i]) { goto clean; } + if (q->is_ue) { + for (int j = 0; j < q->nof_rx_antennas; j++) { + q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->ce[i][j]) { + goto clean; + } + } + } } ret = SRSLTE_SUCCESS; @@ -168,6 +133,14 @@ int srslte_pdcch_init_txrx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t return ret; } +int srslte_pdcch_init_enb(srslte_pdcch_t *q, uint32_t max_prb) { + return pdcch_init(q, max_prb, 0, false); +} + +int srslte_pdcch_init_ue(srslte_pdcch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas) { + return pdcch_init(q, max_prb, nof_rx_antennas, true); +} + void srslte_pdcch_free(srslte_pdcch_t *q) { if (q->e) { @@ -180,18 +153,18 @@ void srslte_pdcch_free(srslte_pdcch_t *q) { free(q->d); } for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { - for (int j=0;jnof_rx_antennas;j++) { - if (q->ce[i][j]) { - free(q->ce[i][j]); - } - } if (q->x[i]) { free(q->x[i]); } - } - for (int j=0;jnof_rx_antennas;j++) { - if (q->symbols[j]) { - free(q->symbols[j]); + if (q->symbols[i]) { + free(q->symbols[i]); + } + if (q->is_ue) { + for (int j=0;jnof_rx_antennas;j++) { + if (q->ce[i][j]) { + free(q->ce[i][j]); + } + } } } for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { @@ -205,6 +178,39 @@ void srslte_pdcch_free(srslte_pdcch_t *q) { } +int srslte_pdcch_set_cell(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + regs != NULL && + srslte_cell_isvalid(&cell)) + { + q->regs = regs; + + /* Allocate memory for the maximum number of PDCCH bits (CFI=3) */ + q->max_bits = (srslte_regs_pdcch_nregs(q->regs, 3) / 9) * 72; + + INFO("PDCCH: Cell config PCI=%d, %d ports.\n", + q->cell.id, q->cell.nof_ports); + + if (q->cell.id != cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + // we need to pregenerate the sequence for the maximum number of bits, which is 8 times + // the maximum number of REGs (for CFI=3) + if (srslte_sequence_pdcch(&q->seq[i], 2 * i, q->cell.id, 8*srslte_regs_pdcch_nregs(q->regs, 3))) { + return SRSLTE_ERROR; + } + } + } + ret = SRSLTE_SUCCESS; + } + return ret; +} + + uint32_t srslte_pdcch_ue_locations(srslte_pdcch_t *q, srslte_dci_location_t *c, uint32_t max_candidates, uint32_t nsubframe, uint32_t cfi, uint16_t rnti) { @@ -490,7 +496,7 @@ int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MA /* descramble */ srslte_scrambling_f_offset(&q->seq[nsubframe], q->llr, 0, e_bits); - + ret = SRSLTE_SUCCESS; } return ret; diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index f761dbc3d..b438a2957 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -27,17 +27,11 @@ #include #include #include -#include #include #include -#include -#include #include "prb_dl.h" #include "srslte/phy/phch/pdsch.h" -#include "srslte/phy/phch/sch.h" -#include "srslte/phy/common/phy_common.h" -#include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" @@ -45,7 +39,6 @@ #define MAX_PDSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) - const static srslte_mod_t modulations[4] = { SRSLTE_MOD_BPSK, SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, SRSLTE_MOD_64QAM }; @@ -197,30 +190,24 @@ int srslte_pdsch_get(srslte_pdsch_t *q, cf_t *sf_symbols, cf_t *symbols, return srslte_pdsch_cp(q, sf_symbols, symbols, grant, lstart, subframe, false); } -/** Initializes the PDCCH transmitter or receiver */ -int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas, bool is_receiver) +/** Initializes the PDSCH transmitter and receiver */ +static int pdsch_init(srslte_pdsch_t *q, uint32_t max_prb, bool is_ue, uint32_t nof_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - int i; - if (q != NULL && - srslte_cell_isvalid(&cell) && - nof_antennas <= SRSLTE_MAX_PORTS) - { + if (q != NULL) + { bzero(q, sizeof(srslte_pdsch_t)); ret = SRSLTE_ERROR; - q->cell = cell; - q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); - if (is_receiver) { - q->nof_rx_antennas = nof_antennas; - } + q->max_re = max_prb * MAX_PDSCH_RE(q->cell.cp); + q->is_ue = is_ue; + q->nof_rx_antennas = nof_antennas; - INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, - q->cell.nof_prb, q->max_re); + INFO("Init PDSCH: %d PRBs, max_symbols: %d\n", max_prb, q->max_re); - for (i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) { if (srslte_modem_table_lte(&q->mod[i], modulations[i])) { goto clean; } @@ -232,7 +219,7 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antenn goto clean; } - for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { // Allocate int16_t for reception (LLRs) q->e[i] = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); if (!q->e[i]) { @@ -245,18 +232,17 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antenn } } - /* Layer mapped symbols memory allocation */ - for (i = 0; i < q->cell.nof_ports; i++) { + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); if (!q->x[i]) { goto clean; } - } - - /* If it is the receiver side, allocate estimated channel */ - if (is_receiver) { - for (i = 0; i < q->cell.nof_ports; i++) { - for (int j = 0; j < q->nof_rx_antennas; j++) { + q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->symbols[i]) { + goto clean; + } + if (q->is_ue) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); if (!q->ce[i][j]) { goto clean; @@ -264,42 +250,40 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antenn } } } - for (int j=0;jnof_rx_antennas, q->cell.nof_ports);j++) { - q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); - if (!q->symbols[j]) { - goto clean; - } - } - - /* Allocate User memory (all zeros) */ - q->users = calloc(sizeof(srslte_pdsch_user_t*), 1+SRSLTE_SIRNTI); + + q->users = calloc(sizeof(srslte_pdsch_user_t*), q->is_ue?1:(1+SRSLTE_SIRNTI)); if (!q->users) { perror("malloc"); goto clean; } - } - ret = SRSLTE_SUCCESS; + if (srslte_sequence_init(&q->tmp_seq, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { + goto clean; + } - clean: + ret = SRSLTE_SUCCESS; + } + + clean: if (ret == SRSLTE_ERROR) { srslte_pdsch_free(q); } return ret; } -int srslte_pdsch_init_tx(srslte_pdsch_t *q, srslte_cell_t cell) { - return srslte_pdsch_init(q, cell, 0, false); +int srslte_pdsch_init_ue(srslte_pdsch_t *q, uint32_t max_prb, uint32_t nof_antennas) +{ + return pdsch_init(q, max_prb, true, nof_antennas); } -int srslte_pdsch_init_rx(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas) { - return srslte_pdsch_init(q, cell, nof_antennas, true); +int srslte_pdsch_init_enb(srslte_pdsch_t *q, uint32_t max_prb) +{ + return pdsch_init(q, max_prb, false, 0); } void srslte_pdsch_free(srslte_pdsch_t *q) { - int i; - for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { if (q->e[i]) { free(q->e[i]); @@ -313,69 +297,107 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { /* Free sch objects */ srslte_sch_free(&q->dl_sch); - for (i = 0; i < q->cell.nof_ports; i++) { + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { if (q->x[i]) { free(q->x[i]); } - for (int j=0;jnof_rx_antennas;j++) { - if (q->ce[i][j]) { - free(q->ce[i][j]); + if (q->symbols[i]) { + free(q->symbols[i]); + } + if (q->is_ue) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { + if (q->ce[i][j]) { + free(q->ce[i][j]); + } } } } - for (int j=0;jsymbols[j]) { - free(q->symbols[j]); - } - } if (q->users) { - for (uint16_t u=0;uusers[u]) { - srslte_pdsch_free_rnti(q, u); + if (q->is_ue) { + srslte_pdsch_free_rnti(q, 0); + } else { + for (int u=0;u<=SRSLTE_SIRNTI;u++) { + if (q->users[u]) { + srslte_pdsch_free_rnti(q, u); + } } - } + } free(q->users); } - for (i = 0; i < 4; i++) { + + srslte_sequence_free(&q->tmp_seq); + + for (int i = 0; i < 4; i++) { srslte_modem_table_free(&q->mod[i]); } bzero(q, sizeof(srslte_pdsch_t)); } -/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while +int srslte_pdsch_set_cell(srslte_pdsch_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_PDSCH_RE(q->cell.cp); + + INFO("PDSCH: 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 PDSCH scramble sequences for a given RNTI. This function takes a while * to execute, so shall be called once the final C-RNTI has been allocated for the session. */ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { - uint32_t i, j; - if (!q->users[rnti]) { - q->users[rnti] = calloc(1, sizeof(srslte_pdsch_user_t)); - if (q->users[rnti]) { - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - for (j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { - if (srslte_sequence_pdsch(&q->users[rnti]->seq[j][i], rnti, j, 2 * i, q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - ERROR("Generating scrambling sequence"); - return SRSLTE_ERROR; - } + uint32_t rnti_idx = q->is_ue?0:rnti; + + if (!q->users[rnti_idx] || q->is_ue) { + if (!q->users[rnti_idx]) { + q->users[rnti_idx] = calloc(1, sizeof(srslte_pdsch_user_t)); + if(!q->users[rnti_idx]) { + perror("calloc"); + return -1; + } + } + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { + if (srslte_sequence_pdsch(&q->users[rnti_idx]->seq[j][i], rnti, j, 2 * i, q->cell.id, + q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) + { + fprintf(stderr, "Error initializing PDSCH scrambling sequence\n"); + srslte_pdsch_free_rnti(q, rnti); + return SRSLTE_ERROR; } } - q->users[rnti]->sequence_generated = true; } + q->ue_rnti = rnti; + q->users[rnti_idx]->cell_id = q->cell.id; + q->users[rnti_idx]->sequence_generated = true; + } else { + fprintf(stderr, "Error generating PDSCH sequence: rnti=0x%x already generated\n", rnti); } return SRSLTE_SUCCESS; } void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) { - if (q->users[rnti]) { + uint32_t rnti_idx = q->is_ue?0:rnti; + if (q->users[rnti_idx]) { for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { - srslte_sequence_free(&q->users[rnti]->seq[j][i]); + srslte_sequence_free(&q->users[rnti_idx]->seq[j][i]); } } - free(q->users[rnti]); - q->users[rnti] = NULL; + free(q->users[rnti_idx]); + q->users[rnti_idx] = NULL; + q->ue_rnti = 0; } } @@ -390,7 +412,7 @@ static void pdsch_decode_debug(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, break; } DEBUG("SAVED FILE %s: received subframe symbols\n", filename); - srslte_vec_save_file(filename, sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file(filename, sf_symbols[j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); for (int i = 0; i < q->cell.nof_ports; i++) { if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) { @@ -401,11 +423,21 @@ static void pdsch_decode_debug(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_vec_save_file(filename, ce[i][j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); } } - DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0); - srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits[0].nof_re*sizeof(cf_t)); + for (int i=0;inof_layers;i++) { + if (snprintf(filename, FILENAME_MAX, "pdsch_symbols_%d.dat", i) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: symbols after equalization\n", filename); + srslte_vec_save_file(filename, q->d[i], cfg->nbits[0].nof_re*sizeof(cf_t)); - DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); - srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); + if (snprintf(filename, FILENAME_MAX, "llr_%d.dat", i) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: LLR estimates after demodulation and descrambling\n", filename); + srslte_vec_save_file(filename, q->e[i], cfg->nbits[0].nof_bits*sizeof(int16_t)); + } } } @@ -427,15 +459,17 @@ int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_g int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, uint32_t pmi) { - if (cfg) { - if (grant) { - memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t)); - } + if (cfg && grant) { + uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant); + memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t)); - for (int i = 0; i < grant->nof_tb; i++) { - if (srslte_cbsegm(&cfg->cb_segm[i], (uint32_t) cfg->grant.mcs[i].tbs)) { - fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs[i].tbs); - return SRSLTE_ERROR; + + for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) { + if (grant->tb_en[cw]) { + if (srslte_cbsegm(&cfg->cb_segm[cw], (uint32_t) cfg->grant.mcs[cw].tbs)) { + fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs[cw].tbs); + return SRSLTE_ERROR; + } } } srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, cfg->nbits); @@ -447,33 +481,36 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra /* Check and configure PDSCH transmission modes */ switch(mimo_type) { case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - if (grant->nof_tb != 1) { - ERROR("Number of transport blocks is not supported for single transmission mode."); + if (nof_tb != 1) { + ERROR("Wrong number of transport blocks (%d) for single antenna.", nof_tb); return SRSLTE_ERROR; } cfg->nof_layers = 1; break; case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - if (grant->nof_tb != 1) { - ERROR("Number of transport blocks is not supported for transmit diversity mode."); + if (nof_tb != 1) { + ERROR("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb); return SRSLTE_ERROR; } cfg->nof_layers = 2; break; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - if (grant->nof_tb == 1) { + if (nof_tb == 1) { cfg->codebook_idx = pmi; cfg->nof_layers = 1; - } else { + } else if (nof_tb == 2) { cfg->codebook_idx = pmi + 1; cfg->nof_layers = 2; + } else { + ERROR("Wrong number of transport blocks (%d) for spatial multiplexing.", nof_tb); + return SRSLTE_ERROR; } INFO("PDSCH configured for Spatial Multiplex; nof_codewords=%d; nof_layers=%d; codebook_idx=%d;\n", - grant->nof_tb, cfg->nof_layers, cfg->codebook_idx); + nof_tb, cfg->nof_layers, cfg->codebook_idx); break; case SRSLTE_MIMO_TYPE_CDD: - if (grant->nof_tb != 2) { - ERROR("Number of transport blocks (%d) is not supported for CDD transmission mode.", grant->nof_tb); + if (nof_tb != 2) { + ERROR("Wrong number of transport blocks (%d) for CDD.", nof_tb); return SRSLTE_ERROR; } cfg->nof_layers = 2; @@ -486,7 +523,25 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra } } -static int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, +static srslte_sequence_t *get_user_sequence(srslte_pdsch_t *q, uint16_t rnti, + uint32_t codeword_idx, uint32_t sf_idx, uint32_t len) +{ + uint32_t rnti_idx = q->is_ue?0:rnti; + + // The scrambling sequence is pregenerated for all RNTIs in the eNodeB but only for C-RNTI in the UE + if (q->users[rnti_idx] && q->users[rnti_idx]->sequence_generated && + q->users[rnti_idx]->cell_id == q->cell.id && + q->ue_rnti == rnti && + ((rnti >= SRSLTE_CRNTI_START && rnti < SRSLTE_CRNTI_END) || !q->is_ue)) + { + return &q->users[rnti_idx]->seq[codeword_idx][sf_idx]; + } else { + srslte_sequence_pdsch(&q->tmp_seq, rnti, codeword_idx, 2 * sf_idx, q->cell.id, len); + return &q->tmp_seq; + } +} + +static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data, uint32_t codeword_idx) { srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; @@ -499,45 +554,36 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_ nbits->nof_re, nbits->nof_bits, rv); /* Channel coding */ - if (srslte_dlsch_encode2(&pdsch->dl_sch, cfg, softbuffer, data, pdsch->e[codeword_idx], codeword_idx)) { + if (srslte_dlsch_encode2(&q->dl_sch, cfg, softbuffer, data, q->e[codeword_idx], codeword_idx)) { ERROR("Error encoding TB %d", codeword_idx); return SRSLTE_ERROR; } - /* Bit scrambling */ - if (!pdsch->users[rnti]) { - srslte_sequence_t seq; + /* Select scrambling sequence */ + srslte_sequence_t *seq = get_user_sequence(q, rnti, codeword_idx, cfg->sf_idx, nbits->nof_bits); - if (srslte_sequence_pdsch(&seq, rnti, codeword_idx, 2 * cfg->sf_idx, pdsch->cell.id, nbits->nof_bits)) { - ERROR("Initialising scrambling sequence"); - return SRSLTE_ERROR; - } - srslte_scrambling_bytes(&seq, (uint8_t *) pdsch->e[codeword_idx], nbits->nof_bits); - srslte_sequence_free(&seq); - - } else { - srslte_scrambling_bytes(&pdsch->users[rnti]->seq[codeword_idx][cfg->sf_idx], - (uint8_t *) pdsch->e[codeword_idx], - nbits->nof_bits); - } + /* Bit scrambling */ + srslte_scrambling_bytes(seq, (uint8_t *) q->e[codeword_idx], nbits->nof_bits); /* Bit mapping */ - srslte_mod_modulate_bytes(&pdsch->mod[mcs->mod], - (uint8_t *) pdsch->e[codeword_idx], - pdsch->d[codeword_idx], nbits->nof_bits); + srslte_mod_modulate_bytes(&q->mod[mcs->mod], + (uint8_t *) q->e[codeword_idx], + q->d[codeword_idx], nbits->nof_bits); + } return SRSLTE_SUCCESS; } -static int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_t *cfg, +static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data, - uint32_t codeword_idx) { + uint32_t codeword_idx, bool *ack) { srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; uint32_t rv = cfg->rv[codeword_idx]; + int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (nbits->nof_bits) { + if (softbuffer && data && ack) { INFO("Decoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, nbits->nof_re, nbits->nof_bits, rv); @@ -546,25 +592,30 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *pdsch, srslte_pdsch_cfg_ * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * thus we don't need tot set it in the LLRs normalization */ - srslte_demod_soft_demodulate_s(mcs->mod, pdsch->d[codeword_idx], pdsch->e[codeword_idx], nbits->nof_re); + srslte_demod_soft_demodulate_s(mcs->mod, q->d[codeword_idx], q->e[codeword_idx], nbits->nof_re); - if (pdsch->users[rnti] && pdsch->users[rnti]->sequence_generated) { - srslte_scrambling_s_offset(&pdsch->users[rnti]->seq[codeword_idx][cfg->sf_idx], pdsch->e[codeword_idx], - 0, nbits->nof_bits); - } else { - srslte_sequence_t seq; - if (srslte_sequence_pdsch(&seq, rnti, codeword_idx, 2 * cfg->sf_idx, pdsch->cell.id, nbits->nof_bits)) { - ERROR("Initialising scrambling sequence"); - return SRSLTE_ERROR; - } - srslte_scrambling_s_offset(&seq, pdsch->e[codeword_idx], 0, nbits->nof_bits); - srslte_sequence_free(&seq); - } + /* Select scrambling sequence */ + srslte_sequence_t *seq = get_user_sequence(q, rnti, codeword_idx, cfg->sf_idx, nbits->nof_bits); - return srslte_dlsch_decode2(&pdsch->dl_sch, cfg, softbuffer, pdsch->e[codeword_idx], data, codeword_idx); + /* Bit scrambling */ + srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits); + + /* Return */ + ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, codeword_idx); + + q->last_nof_iterations[codeword_idx] = srslte_sch_last_noi(&q->dl_sch); + + if (ret == SRSLTE_SUCCESS) { + *ack = true; + } else if (ret == SRSLTE_ERROR) { + *ack = false; + ret = SRSLTE_SUCCESS; + } + } else { + ERROR("Detected NULL pointer in TB%d &softbuffer=%p &data=%p &ack=%p", codeword_idx, softbuffer, (void*)data, ack); } - return SRSLTE_SUCCESS; + return ret; } /** Decodes the PDSCH from the received symbols @@ -585,9 +636,10 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, data != NULL && cfg != NULL) { + uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant); INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, NofSymbols: %d, C_prb=%d, mimo_type=%d, nof_layers=%d, nof_tb=%d\n", - cfg->sf_idx, rnti, cfg->nbits[0].nof_re, cfg->grant.nof_prb, cfg->nof_layers, cfg->grant.nof_tb); + cfg->sf_idx, rnti, cfg->nbits[0].nof_re, cfg->grant.nof_prb, cfg->nof_layers, nof_tb); // Extract Symbols and Channel Estimates for (int j=0;jnof_rx_antennas;j++) { @@ -608,10 +660,10 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, // Prepare layers int nof_symbols [SRSLTE_MAX_CODEWORDS]; - nof_symbols[0] = cfg->nbits[0].nof_re * cfg->grant.nof_tb / cfg->nof_layers; - nof_symbols[1] = cfg->nbits[1].nof_re * cfg->grant.nof_tb / cfg->nof_layers; + nof_symbols[0] = cfg->nbits[0].nof_re * nof_tb / cfg->nof_layers; + nof_symbols[1] = cfg->nbits[1].nof_re * nof_tb / cfg->nof_layers; - if (cfg->nof_layers == cfg->grant.nof_tb) { + if (cfg->nof_layers == nof_tb) { /* Skip layer demap */ for (i = 0; i < cfg->nof_layers; i++) { x[i] = q->d[i]; @@ -629,21 +681,26 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate); // Layer demapping only if necessary - if (cfg->nof_layers != cfg->grant.nof_tb) { - srslte_layerdemap_type(x, q->d, cfg->nof_layers, cfg->grant.nof_tb, + if (cfg->nof_layers != nof_tb) { + srslte_layerdemap_type(x, q->d, cfg->nof_layers, nof_tb, nof_symbols[0], nof_symbols, cfg->mimo_type); } - // Codeword decoding - for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { - int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb); - acks[tb] = (ret == SRSLTE_SUCCESS); + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) { + /* Decode only if transport block is enabled and the default ACK is not true */ + if (cfg->grant.tb_en[tb] && !acks[tb]) { + int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb, &acks[tb]); + + /* Check if there has been any execution error */ + if (ret) { + return ret; + } + } } pdsch_decode_debug(q, cfg, sf_symbols, ce); return SRSLTE_SUCCESS; - } else { return SRSLTE_ERROR_INVALID_INPUTS; } @@ -654,8 +711,9 @@ int srslte_pdsch_pmi_select(srslte_pdsch_t *q, cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t nof_ce, uint32_t pmi[SRSLTE_MAX_LAYERS], float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]) { - if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { - for (int nof_layers = 1; nof_layers <= 2; nof_layers++ ) { + if (q->cell.nof_ports == 2 && q->nof_rx_antennas <= 2) { + int nof_layers = 1; + for (; nof_layers <= q->nof_rx_antennas; nof_layers++ ) { if (sinr[nof_layers - 1] && pmi) { if (srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, nof_layers, &pmi[nof_layers - 1], sinr[nof_layers - 1]) < 0) { @@ -664,6 +722,16 @@ int srslte_pdsch_pmi_select(srslte_pdsch_t *q, } } } + + /* FIXME: Set other layers to 0 */ + for (; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++ ) { + if (sinr[nof_layers - 1] && pmi) { + for (int cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb++) { + sinr[nof_layers - 1][cb] = -INFINITY; + } + pmi[nof_layers - 1] = 0; + } + } } else { ERROR("Not implemented configuration"); return SRSLTE_ERROR_INVALID_INPUTS; @@ -689,6 +757,8 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, if (q != NULL && cfg != NULL) { + uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant); + for (i = 0; i < q->cell.nof_ports; i++) { if (sf_symbols[i] == NULL) { @@ -708,15 +778,17 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, return SRSLTE_ERROR_INVALID_INPUTS; } - for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { - ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb], rnti, data[tb], tb); + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) { + if (cfg->grant.tb_en[tb]) { + ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb], rnti, data[tb], tb); + } } // Layer mapping & precode if necessary if (q->cell.nof_ports > 1) { int nof_symbols; /* If number of layers is equal to transport blocks (codewords) skip layer mapping */ - if (cfg->nof_layers == cfg->grant.nof_tb) { + if (cfg->nof_layers == nof_tb) { for (i = 0; i < cfg->nof_layers; i++) { x[i] = q->d[i]; } @@ -728,7 +800,7 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, } memset(&x[cfg->nof_layers], 0, sizeof(cf_t *) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); - nof_symbols = srslte_layermap_type(q->d, x, cfg->grant.nof_tb, cfg->nof_layers, + nof_symbols = srslte_layermap_type(q->d, x, nof_tb, cfg->nof_layers, (int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits[0].nof_re, cfg->nbits[1].nof_re}, cfg->mimo_type); } @@ -754,14 +826,13 @@ void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter) { srslte_sch_set_max_noi(&q->dl_sch, max_iter); } -float srslte_pdsch_average_noi(srslte_pdsch_t *q) { - return q->dl_sch.average_nof_iterations; +float srslte_pdsch_last_noi(srslte_pdsch_t *q) { + return srslte_pdsch_last_noi_cw(q, 0); } -uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q) { - return q->dl_sch.nof_iterations; +uint32_t srslte_pdsch_last_noi_cw(srslte_pdsch_t *q, uint32_t cw_idx) { + return q->last_nof_iterations[cw_idx]; } - diff --git a/lib/src/phy/phch/phich.c b/lib/src/phy/phch/phich.c index 7de2f5d37..14a0d5426 100644 --- a/lib/src/phy/phch/phich.c +++ b/lib/src/phy/phch/phich.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "srslte/phy/phch/regs.h" #include "srslte/phy/phch/phich.h" @@ -67,37 +68,22 @@ void srslte_phich_reset(srslte_phich_t *q, cf_t *slot_symbols[SRSLTE_MAX_PORTS]) } } -int srslte_phich_init(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell) -{ - return srslte_phich_init_multi(q, regs, cell, 1); -} - /** Initializes the phich channel receiver */ -int srslte_phich_init_multi(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) +int srslte_phich_init(srslte_phich_t *q, uint32_t nof_rx_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - regs != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL) { bzero(q, sizeof(srslte_phich_t)); ret = SRSLTE_ERROR; - q->cell = cell; - q->regs = regs; - q->nof_rx_antennas = nof_rx_antennas; + q->nof_rx_antennas = nof_rx_antennas; if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_BPSK)) { goto clean; } - - for (int nsf = 0; nsf < SRSLTE_NSUBFRAMES_X_FRAME; nsf++) { - if (srslte_sequence_phich(&q->seq[nsf], 2 * nsf, q->cell.id)) { - goto clean; - } - } ret = SRSLTE_SUCCESS; } clean: @@ -114,9 +100,34 @@ void srslte_phich_free(srslte_phich_t *q) { srslte_modem_table_free(&q->mod); bzero(q, sizeof(srslte_phich_t)); +} + +int srslte_phich_set_cell(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + regs != NULL && + srslte_cell_isvalid(&cell)) + { + q->regs = regs; + + if (cell.id != q->cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + for (int nsf = 0; nsf < SRSLTE_NSUBFRAMES_X_FRAME; nsf++) { + if (srslte_sequence_phich(&q->seq[nsf], 2 * nsf, q->cell.id)) { + return SRSLTE_ERROR; + } + } + } + ret = SRSLTE_SUCCESS; + } + return ret; } + + /* Computes n_group and n_seq according to Section 9.1.2 in 36.213 */ void srslte_phich_calc(srslte_phich_t *q, uint32_t n_prb_lowest, uint32_t n_dmrs, uint32_t *ngroup, uint32_t *nseq) @@ -162,26 +173,9 @@ void srslte_phich_ack_encode(uint8_t ack, uint8_t bits[SRSLTE_PHICH_NBITS]) { memset(bits, ack, 3 * sizeof(uint8_t)); } -int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) -{ - cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; - cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - - _sf_symbols[0] = sf_symbols; - for (int i=0;icell.nof_ports;i++) { - _ce[i][0] = ce[i]; - } - - return srslte_phich_decode_multi(q, _sf_symbols, _ce, noise_estimate, ngroup, nseq, subframe, ack, distance); -} -/* Decodes the phich channel and saves the CFI in the cfi pointer. - * - * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error - */ -int srslte_phich_decode_multi(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) -{ +int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) { /* Set pointers for layermapping & precoding */ int i, j; diff --git a/lib/src/phy/phch/pmch.c b/lib/src/phy/phch/pmch.c new file mode 100644 index 000000000..aa7fd77b1 --- /dev/null +++ b/lib/src/phy/phch/pmch.c @@ -0,0 +1,480 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "prb_dl.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" + + +#define MAX_PMCH_RE (2 * SRSLTE_CP_EXT_NSYMB * 12) + + +const static srslte_mod_t modulations[4] = + { SRSLTE_MOD_BPSK, SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, SRSLTE_MOD_64QAM }; + +//#define DEBUG_IDX + +#ifdef DEBUG_IDX +cf_t *offset_original=NULL; +extern int indices[100000]; +extern int indices_ptr; +#endif + +float srslte_pmch_coderate(uint32_t tbs, uint32_t nof_re) +{ + return (float) (tbs + 24)/(nof_re); +} + +int srslte_pmch_cp(srslte_pmch_t *q, cf_t *input, cf_t *output, uint32_t lstart_grant, bool put) +{ + uint32_t s, n, l, lp, lstart, lend, nof_refs; + cf_t *in_ptr = input, *out_ptr = output; + uint32_t offset = 0; + + #ifdef DEBUG_IDX + indices_ptr = 0; + if (put) { + offset_original = output; + } else { + offset_original = input; + } + #endif + nof_refs = 6; + for (s = 0; s < 2; s++) { + for (l = 0; l < SRSLTE_CP_EXT_NSYMB; l++) { + for (n = 0; n < q->cell.nof_prb; n++) { + // If this PRB is assigned + if (true) { + if (s == 0) { + lstart = lstart_grant; + } else { + lstart = 0; + } + lend = SRSLTE_CP_EXT_NSYMB; + lp = l + s * SRSLTE_CP_EXT_NSYMB; + if (put) { + out_ptr = &output[(lp * q->cell.nof_prb + n) * SRSLTE_NRE]; + } else { + in_ptr = &input[(lp * q->cell.nof_prb + n) * SRSLTE_NRE]; + } + // This is a symbol in a normal PRB with or without references + if (l >= lstart && l < lend) { + if (SRSLTE_SYMBOL_HAS_REF_MBSFN(l,s)) { + if (l == 0 && s == 1) { + offset = 1; + } else { + offset = 0; + } + prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs, put); + } else { + prb_cp(&in_ptr, &out_ptr, 1); + } + } + } + } + } + } + + int r; + if (put) { + r = abs((int) (input - in_ptr)); + } else { + r = abs((int) (output - out_ptr)); + } + + return r; +} + +/** + * Puts PMCH in slot number 1 + * + * Returns the number of symbols written to sf_symbols + * + * 36.211 10.3 section 6.3.5 + */ +int srslte_pmch_put(srslte_pmch_t *q, cf_t *symbols, cf_t *sf_symbols, uint32_t lstart) +{ + return srslte_pmch_cp(q, symbols, sf_symbols, lstart, true); +} + +/** + * Extracts PMCH from slot number 1 + * + * Returns the number of symbols written to PMCH + * + * 36.211 10.3 section 6.3.5 + */ +int srslte_pmch_get(srslte_pmch_t *q, cf_t *sf_symbols, cf_t *symbols, uint32_t lstart) +{ + return srslte_pmch_cp(q, sf_symbols, symbols, lstart, false); +} + +int srslte_pmch_init(srslte_pmch_t *q, uint32_t max_prb) +{ + return srslte_pmch_init_multi(q, max_prb, 1); +} + +int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + int i; + + if (q != NULL && + nof_rx_antennas <= SRSLTE_MAX_PORTS) + { + + bzero(q, sizeof(srslte_pmch_t)); + ret = SRSLTE_ERROR; + + q->cell.nof_prb = max_prb; + q->cell.nof_ports = 1; + q->max_re = max_prb * MAX_PMCH_RE; + q->nof_rx_antennas = nof_rx_antennas; + + INFO("Init PMCH: %d PRBs, max_symbols: %d\n", + max_prb, q->max_re); + + for (i = 0; i < 4; i++) { + if (srslte_modem_table_lte(&q->mod[i], modulations[i])) { + goto clean; + } + srslte_modem_table_bytes(&q->mod[i]); + } + + srslte_sch_init(&q->dl_sch); + + // Allocate int16_t for reception (LLRs) + q->e = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); + if (!q->e) { + goto clean; + } + + q->d = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->d) { + goto clean; + } + + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { + q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->x[i]) { + goto clean; + } + for (int j=0;jnof_rx_antennas;j++) { + q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->ce[i][j]) { + goto clean; + } + } + } + for (int j=0;jnof_rx_antennas;j++) { + q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->symbols[j]) { + goto clean; + } + } + + q->seqs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_pmch_seq_t*)); + if (!q->seqs) { + perror("calloc"); + goto clean; + } + + ret = SRSLTE_SUCCESS; + } + clean: + if (ret == SRSLTE_ERROR) { + srslte_pmch_free(q); + } + return ret; +} + +void srslte_pmch_free(srslte_pmch_t *q) { + uint16_t i; + + if (q->e) { + free(q->e); + } + if (q->d) { + free(q->d); + } + for (i = 0; i < q->cell.nof_ports; i++) { + if (q->x[i]) { + free(q->x[i]); + } + for (int j=0;jnof_rx_antennas;j++) { + if (q->ce[i][j]) { + free(q->ce[i][j]); + } + } + } + for (i=0;inof_rx_antennas;i++) { + if (q->symbols[i]) { + free(q->symbols[i]); + } + } + if (q->seqs) { + for (i=0; iseqs[i]) { + srslte_pmch_free_area_id(q, i); + } + } + free(q->seqs); + } + for (i = 0; i < 4; i++) { + srslte_modem_table_free(&q->mod[i]); + } + + srslte_sch_free(&q->dl_sch); + + bzero(q, sizeof(srslte_pmch_t)); + +} + + +/* 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; + if (!q->seqs[area_id]) { + q->seqs[area_id] = calloc(1, sizeof(srslte_pmch_seq_t)); + if (q->seqs[area_id]) { + for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + if (srslte_sequence_pmch(&q->seqs[area_id]->seq[i], 2 * i , area_id, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { + return SRSLTE_ERROR; + } + } + } + } + return SRSLTE_SUCCESS; +} + +void srslte_pmch_free_area_id(srslte_pmch_t* q, uint16_t area_id) +{ + if (q->seqs[area_id]) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + srslte_sequence_free(&q->seqs[area_id]->seq[i]); + } + free(q->seqs[area_id]); + q->seqs[area_id] = NULL; + } +} + +int srslte_pmch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx) +{ + if (cfg) { + if (grant) { + memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t)); + } + if (srslte_cbsegm(&cfg->cb_segm[0], cfg->grant.mcs[0].tbs)) { + fprintf(stderr, "Error computing Codeblock segmentation for TBS=%d\n", cfg->grant.mcs[0].tbs); + return SRSLTE_ERROR; + } + srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, cfg->nbits); + cfg->sf_idx = sf_idx; + cfg->rv[0] = SRSLTE_PMCH_RV; + + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + + +int srslte_pmch_decode(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint16_t area_id, uint8_t *data) +{ + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; + } + return srslte_pmch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, area_id, data); +} + +/** Decodes the pmch from the received symbols + */ +int srslte_pmch_decode_multi(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint16_t area_id, uint8_t *data) +{ + + /* Set pointers for layermapping & precoding */ + uint32_t i, n; + cf_t *x[SRSLTE_MAX_LAYERS]; + + if (q != NULL && + sf_symbols != NULL && + 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); + + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); + + for (int j=0;jnof_rx_antennas;j++) { + /* 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; + } + + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = srslte_pmch_get(q, ce[i][j], q->ce[i][j], cfg->nbits[0].lstart); + if (n != cfg->nbits[0].nof_re) { + fprintf(stderr, "PMCH 2 extract chest error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n); + return SRSLTE_ERROR; + } + } + } + + // No tx diversity in MBSFN + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, noise_estimate); + + if (SRSLTE_VERBOSE_ISDEBUG()) { + DEBUG("SAVED FILE subframe.dat: received subframe symbols\n"); + srslte_vec_save_file("subframe.dat", sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + DEBUG("SAVED FILE hest0.dat: channel estimates for port 4\n"); + srslte_vec_save_file("hest0.dat", ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + DEBUG("SAVED FILE pmch_symbols.dat: symbols after equalization\n"); + srslte_vec_save_file("pmch_symbols.bin", q->d, cfg->nbits[0].nof_re*sizeof(cf_t)); + } + + /* demodulate symbols + * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, + * thus we don't need tot set it in thde LLRs normalization + */ + srslte_demod_soft_demodulate_s(cfg->grant.mcs[0].mod, q->d, q->e, cfg->nbits[0].nof_re); + + /* descramble */ + srslte_scrambling_s_offset(&q->seqs[area_id]->seq[cfg->sf_idx], q->e, 0, cfg->nbits[0].nof_bits); + + if (SRSLTE_VERBOSE_ISDEBUG()) { + DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n"); + srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); + } + return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data); + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + +int srslte_pmch_encode(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, + uint8_t *data, uint16_t area_id, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) +{ + + int i; + /* 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;icell.nof_ports;i++) { + if (sf_symbols[i] == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + } + + if (cfg->grant.mcs[0].tbs == 0) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (cfg->nbits[0].nof_re > q->max_re) { + fprintf(stderr, + "Error too many RE per subframe (%d). PMCH configured for %d RE (%d PRB)\n", + cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + INFO("Encoding PMCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + cfg->sf_idx, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, + cfg->nbits[0].nof_re, cfg->nbits[0].nof_bits, 0); + + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); + + // TODO: use tb_encode directly + if (srslte_dlsch_encode(&q->dl_sch, cfg, softbuffer, data, q->e)) { + fprintf(stderr, "Error encoding TB\n"); + return SRSLTE_ERROR; + } + + /* scramble */ + srslte_scrambling_bytes(&q->seqs[area_id]->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits[0].nof_bits); + + srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs[0].mod], (uint8_t*) q->e, q->d, cfg->nbits[0].nof_bits); + + /* No tx diversity in MBSFN */ + memcpy(q->symbols[0], q->d, cfg->nbits[0].nof_re * sizeof(cf_t)); + + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + srslte_pmch_put(q, q->symbols[i], sf_symbols[i], cfg->nbits[0].lstart); + } + + ret = SRSLTE_SUCCESS; + } + return ret; +} + +uint32_t srslte_pmch_last_noi(srslte_pmch_t *q) { + return q->dl_sch.nof_iterations; +} + + + + diff --git a/lib/src/phy/phch/prach.c b/lib/src/phy/phch/prach.c index 5a2169fd9..ffd8b51e7 100644 --- a/lib/src/phy/phch/prach.c +++ b/lib/src/phy/phch/prach.c @@ -26,6 +26,7 @@ #include #include +#include #include "srslte/phy/common/phy_common.h" #include "srslte/phy/phch/prach.h" @@ -61,6 +62,8 @@ uint32_t prach_Tseq[5] = {24576, 24576, 2*24576, 2*24576, 4096}; // Table 5.7.2-2 - N_cs values for unrestricted sets uint32_t prach_Ncs_unrestricted[16] = {0,13,15,18,22,26,32,38,46,59,76,93,119,167,279,419}; +#define MAX_N_zc 839 + // Table 5.7.2-2 - N_cs values for restricted sets uint32_t prach_Ncs_restricted[15] = {15,18,22,26,32,38,46,55,68,82,100,128,158,202,237}; @@ -328,7 +331,10 @@ int srslte_prach_gen_seqs(srslte_prach_t *p) int srslte_prach_init_cfg(srslte_prach_t *p, srslte_prach_cfg_t *cfg, uint32_t nof_prb) { - return srslte_prach_init(p, + if (srslte_prach_init(p, srslte_symbol_sz(nof_prb))) { + return -1; + } + return srslte_prach_set_cell(p, srslte_symbol_sz(nof_prb), cfg->config_idx, cfg->root_seq_idx, @@ -336,28 +342,95 @@ int srslte_prach_init_cfg(srslte_prach_t *p, srslte_prach_cfg_t *cfg, uint32_t n cfg->zero_corr_zone); } -int srslte_prach_init(srslte_prach_t *p, - uint32_t N_ifft_ul, - uint32_t config_idx, - uint32_t root_seq_index, - bool high_speed_flag, - uint32_t zero_corr_zone_config) +int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul) +{ + int ret = SRSLTE_ERROR; + if(p != NULL && + max_N_ifft_ul < 2049) + { + bzero(p, sizeof(srslte_prach_t)); + + p->max_N_ifft_ul = max_N_ifft_ul; + + // Set up containers + p->prach_bins = srslte_vec_malloc(sizeof(cf_t)*MAX_N_zc); + p->corr_spec = srslte_vec_malloc(sizeof(cf_t)*MAX_N_zc); + p->corr = srslte_vec_malloc(sizeof(float)*MAX_N_zc); + + // Set up ZC FFTS + if(srslte_dft_plan(&p->zc_fft, MAX_N_zc, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)){ + return SRSLTE_ERROR; + } + srslte_dft_plan_set_mirror(&p->zc_fft, false); + srslte_dft_plan_set_norm(&p->zc_fft, true); + + if(srslte_dft_plan(&p->zc_ifft, MAX_N_zc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)){ + return SRSLTE_ERROR; + } + srslte_dft_plan_set_mirror(&p->zc_ifft, false); + srslte_dft_plan_set_norm(&p->zc_ifft, false); + + uint32_t fft_size_alloc = max_N_ifft_ul * DELTA_F/DELTA_F_RA; + + p->ifft_in = (cf_t*)srslte_vec_malloc(fft_size_alloc*sizeof(cf_t)); + p->ifft_out = (cf_t*)srslte_vec_malloc(fft_size_alloc*sizeof(cf_t)); + if(srslte_dft_plan(&p->ifft, fft_size_alloc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { + fprintf(stderr, "Error creating DFT plan\n"); + return -1; + } + srslte_dft_plan_set_mirror(&p->ifft, true); + srslte_dft_plan_set_norm(&p->ifft, true); + + if(srslte_dft_plan(&p->fft, fft_size_alloc, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)){ + fprintf(stderr, "Error creating DFT plan\n"); + return -1; + } + + p->signal_fft = srslte_vec_malloc(sizeof(cf_t)*fft_size_alloc); + if (!p->signal_fft) { + fprintf(stderr, "Error allocating memory\n"); + return -1; + } + + srslte_dft_plan_set_mirror(&p->fft, true); + srslte_dft_plan_set_norm(&p->fft, false); + + ret = SRSLTE_SUCCESS; + } else { + fprintf(stderr, "Invalid parameters\n"); + } + + return ret; +} + + +int srslte_prach_set_cell(srslte_prach_t *p, + uint32_t N_ifft_ul, + uint32_t config_idx, + uint32_t root_seq_index, + bool high_speed_flag, + uint32_t zero_corr_zone_config) { int ret = SRSLTE_ERROR; if(p != NULL && N_ifft_ul < 2049 && - config_idx < 64 && + config_idx < 64 && root_seq_index < MAX_ROOTS) { + if (N_ifft_ul > p->max_N_ifft_ul) { + fprintf(stderr, "PRACH: Error in set_cell(): N_ifft_ul must be lower or equal max_N_ifft_ul in init()\n"); + return -1; + } + uint32_t preamble_format = srslte_prach_get_preamble_format(config_idx); - p->config_idx = config_idx; + p->config_idx = config_idx; p->f = preamble_format; p->rsi = root_seq_index; p->hs = high_speed_flag; p->zczc = zero_corr_zone_config; - p->detect_factor = PRACH_DETECT_FACTOR; - - + p->detect_factor = PRACH_DETECT_FACTOR; + + // Determine N_zc and N_cs if(4 == preamble_format){ if (p->zczc < 7) { @@ -368,43 +441,33 @@ int srslte_prach_init(srslte_prach_t *p, return SRSLTE_ERROR; } }else{ - p->N_zc = 839; + p->N_zc = MAX_N_zc; if(p->hs){ if (p->zczc < 15) { p->N_cs = prach_Ncs_restricted[p->zczc]; } else { fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d for restricted set\n", p->zczc); return SRSLTE_ERROR; - } + } }else{ if (p->zczc < 16) { p->N_cs = prach_Ncs_unrestricted[p->zczc]; } else { fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d\n", p->zczc); return SRSLTE_ERROR; - } + } } } - - // Set up containers - p->prach_bins = srslte_vec_malloc(sizeof(cf_t)*p->N_zc); - p->corr_spec = srslte_vec_malloc(sizeof(cf_t)*p->N_zc); - p->corr = srslte_vec_malloc(sizeof(float)*p->N_zc); // Set up ZC FFTS - p->zc_fft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); - if(srslte_dft_plan(p->zc_fft, p->N_zc, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)){ - return SRSLTE_ERROR; - } - srslte_dft_plan_set_mirror(p->zc_fft, false); - srslte_dft_plan_set_norm(p->zc_fft, true); - - p->zc_ifft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); - if(srslte_dft_plan(p->zc_ifft, p->N_zc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)){ - return SRSLTE_ERROR; + if (p->N_zc != MAX_N_zc) { + if(srslte_dft_replan(&p->zc_fft, p->N_zc)){ + return SRSLTE_ERROR; + } + if(srslte_dft_replan(&p->zc_ifft, p->N_zc)){ + return SRSLTE_ERROR; + } } - srslte_dft_plan_set_mirror(p->zc_ifft, false); - srslte_dft_plan_set_norm(p->zc_ifft, false); // Generate our 64 sequences p->N_roots = 0; @@ -412,9 +475,9 @@ int srslte_prach_init(srslte_prach_t *p, // Generate sequence FFTs for(int i=0;izc_fft, p->seqs[i], p->dft_seqs[i]); + srslte_dft_run(&p->zc_fft, p->seqs[i], p->dft_seqs[i]); } - + // Create our FFT objects and buffers p->N_ifft_ul = N_ifft_ul; if(4 == preamble_format){ @@ -422,47 +485,31 @@ int srslte_prach_init(srslte_prach_t *p, }else{ p->N_ifft_prach = p->N_ifft_ul * DELTA_F/DELTA_F_RA; } - + /* The deadzone specifies the number of samples at the end of the correlation window * that will be considered as belonging to the next preamble */ - p->deadzone = 0; + p->deadzone = 0; /* if(p->N_cs != 0) { float samp_rate=15000*p->N_ifft_ul; p->deadzone = (uint32_t) ceil((float) samp_rate/((float) p->N_zc*subcarrier_spacing)); }*/ - p->ifft_in = (cf_t*)srslte_vec_malloc(p->N_ifft_prach*sizeof(cf_t)); - p->ifft_out = (cf_t*)srslte_vec_malloc(p->N_ifft_prach*sizeof(cf_t)); - p->ifft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); - if(srslte_dft_plan(p->ifft, p->N_ifft_prach, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { + if(srslte_dft_replan(&p->ifft, p->N_ifft_prach)) { fprintf(stderr, "Error creating DFT plan\n"); return -1; } - srslte_dft_plan_set_mirror(p->ifft, true); - srslte_dft_plan_set_norm(p->ifft, true); - - p->fft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); - if(srslte_dft_plan(p->fft, p->N_ifft_prach, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)){ + if(srslte_dft_replan(&p->fft, p->N_ifft_prach)){ fprintf(stderr, "Error creating DFT plan\n"); return -1; } - - p->signal_fft = srslte_vec_malloc(sizeof(cf_t)*p->N_ifft_prach); - if (!p->signal_fft) { - fprintf(stderr, "Error allocating memory\n"); - return -1; - } - - srslte_dft_plan_set_mirror(p->fft, true); - srslte_dft_plan_set_norm(p->fft, false); p->N_seq = prach_Tseq[p->f]*p->N_ifft_ul/2048; p->N_cp = prach_Tcp[p->f]*p->N_ifft_ul/2048; p->T_seq = prach_Tseq[p->f]*SRSLTE_LTE_TS; p->T_tot = (prach_Tseq[p->f]+prach_Tcp[p->f])*SRSLTE_LTE_TS; - + ret = SRSLTE_SUCCESS; } else { fprintf(stderr, "Invalid parameters\n"); @@ -500,7 +547,7 @@ int srslte_prach_gen(srslte_prach_t *p, memcpy(&p->ifft_in[begin], p->dft_seqs[seq_index], p->N_zc * sizeof(cf_t)); memset(&p->ifft_in[begin+p->N_zc], 0, (p->N_ifft_prach - begin - p->N_zc) * sizeof(cf_t)); - srslte_dft_run(p->ifft, p->ifft_in, p->ifft_out); + srslte_dft_run(&p->ifft, p->ifft_in, p->ifft_out); // Copy CP into buffer memcpy(signal, &p->ifft_out[p->N_ifft_prach-p->N_cp], p->N_cp*sizeof(cf_t)); @@ -552,7 +599,7 @@ int srslte_prach_detect_offset(srslte_prach_t *p, } // FFT incoming signal - srslte_dft_run(p->fft, signal, p->signal_fft); + srslte_dft_run(&p->fft, signal, p->signal_fft); *n_indices = 0; @@ -569,7 +616,7 @@ int srslte_prach_detect_offset(srslte_prach_t *p, srslte_vec_prod_conj_ccc(p->prach_bins, root_spec, p->corr_spec, p->N_zc); - srslte_dft_run(p->zc_ifft, p->corr_spec, p->corr_spec); + srslte_dft_run(&p->zc_ifft, p->corr_spec, p->corr_spec); srslte_vec_abs_square_cf(p->corr_spec, p->corr, p->N_zc); @@ -632,16 +679,12 @@ int srslte_prach_free(srslte_prach_t *p) { free(p->prach_bins); free(p->corr_spec); free(p->corr); - srslte_dft_plan_free(p->ifft); - free(p->ifft); + srslte_dft_plan_free(&p->ifft); free(p->ifft_in); free(p->ifft_out); - srslte_dft_plan_free(p->fft); - free(p->fft); - srslte_dft_plan_free(p->zc_fft); - free(p->zc_fft); - srslte_dft_plan_free(p->zc_ifft); - free(p->zc_ifft); + srslte_dft_plan_free(&p->fft); + srslte_dft_plan_free(&p->zc_fft); + srslte_dft_plan_free(&p->zc_ifft); if (p->signal_fft) { free(p->signal_fft); diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 56349dee4..498d34f3a 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -416,37 +416,24 @@ void srslte_pucch_set_threshold(srslte_pucch_t *q, float format1_threshold) { } /** Initializes the PDCCH transmitter and receiver */ -int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) { +int srslte_pucch_init(srslte_pucch_t *q) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && srslte_cell_isvalid(&cell)) { + if (q != NULL) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_pucch_t)); - q->cell = cell; - - srslte_pucch_cfg_default(&q->pucch_cfg); - if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { return SRSLTE_ERROR; } - - // Precompute group hopping values u. - if (srslte_group_hopping_f_gh(q->f_gh, q->cell.id)) { - return SRSLTE_ERROR; - } - - if (srslte_pucch_n_cs_cell(q->cell, q->n_cs_cell)) { - return SRSLTE_ERROR; - } - + q->users = calloc(sizeof(srslte_pucch_user_t*), 1+SRSLTE_SIRNTI); if (!q->users) { perror("malloc"); - return SRSLTE_ERROR; + goto clean_exit; } srslte_uci_cqi_pucch_init(&q->cqi); - + q->z = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS); q->z_tmp = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS); q->ce = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS); @@ -455,12 +442,16 @@ int srslte_pucch_init(srslte_pucch_t *q, srslte_cell_t cell) { ret = SRSLTE_SUCCESS; } +clean_exit: + if (ret == SRSLTE_ERROR) { + srslte_pucch_free(q); + } return ret; } void srslte_pucch_free(srslte_pucch_t *q) { if (q->users) { - for (int rnti=0;rntiusers); @@ -480,6 +471,31 @@ void srslte_pucch_free(srslte_pucch_t *q) { bzero(q, sizeof(srslte_pucch_t)); } +int srslte_pucch_set_cell(srslte_pucch_t *q, srslte_cell_t cell) { + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL && srslte_cell_isvalid(&cell)) { + + srslte_pucch_cfg_default(&q->pucch_cfg); + + if (cell.id != q->cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + + // Precompute group hopping values u. + if (srslte_group_hopping_f_gh(q->f_gh, q->cell.id)) { + return SRSLTE_ERROR; + } + + if (srslte_pucch_n_cs_cell(q->cell, q->n_cs_cell)) { + return SRSLTE_ERROR; + } + } + + ret = SRSLTE_SUCCESS; + } + return ret; +} + + void srslte_pucch_clear_rnti(srslte_pucch_t *q, uint16_t rnti) { if (q->users[rnti]) { for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { @@ -498,6 +514,7 @@ int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t rnti) { // Precompute scrambling sequence for pucch format 2 if (srslte_sequence_pucch(&q->users[rnti]->seq_f2[sf_idx], rnti, 2*sf_idx, q->cell.id)) { fprintf(stderr, "Error computing PUCCH Format 2 scrambling sequence\n"); + srslte_pucch_clear_rnti(q, rnti); return SRSLTE_ERROR; } } diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index 9e0df307b..ba1195507 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "srslte/phy/ch_estimation/refsignal_ul.h" #include "srslte/phy/phch/pusch.h" @@ -185,22 +187,18 @@ int pusch_get(srslte_pusch_t *q, srslte_ra_ul_grant_t *grant, cf_t *input, cf_t /** Initializes the PDCCH transmitter and receiver */ -int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) { +int pusch_init(srslte_pusch_t *q, uint32_t max_prb, bool is_ue) { int ret = SRSLTE_ERROR_INVALID_INPUTS; int i; - if (q != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL) { bzero(q, sizeof(srslte_pusch_t)); ret = SRSLTE_ERROR; - - q->cell = cell; - q->max_re = q->cell.nof_prb * MAX_PUSCH_RE(q->cell.cp); + q->max_re = max_prb * MAX_PUSCH_RE(SRSLTE_CP_NORM); - INFO("Init PUSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, - q->cell.nof_prb, q->max_re); + INFO("Init PUSCH: %d PRBs\n", max_prb); for (i = 0; i < 4; i++) { if (srslte_modem_table_lte(&q->mod[i], modulations[i])) { @@ -208,26 +206,26 @@ int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) { } srslte_modem_table_bytes(&q->mod[i]); } - - q->users = calloc(sizeof(srslte_pusch_user_t*), 1+SRSLTE_SIRNTI); + + q->is_ue = is_ue; + + q->users = calloc(sizeof(srslte_pusch_user_t*), q->is_ue?1:(1+SRSLTE_SIRNTI)); if (!q->users) { perror("malloc"); goto clean; } - /* Precompute sequence for type2 frequency hopping */ - if (srslte_sequence_LTE_pr(&q->seq_type2_fo, 210, q->cell.id)) { - fprintf(stderr, "Error initiating type2 frequency hopping sequence\n"); - goto clean; + if (srslte_sequence_init(&q->tmp_seq, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { + goto clean; } srslte_sch_init(&q->ul_sch); - - if (srslte_dft_precoding_init(&q->dft_precoding, cell.nof_prb)) { + + if (srslte_dft_precoding_init(&q->dft_precoding, max_prb, is_ue)) { fprintf(stderr, "Error initiating DFT transform precoding\n"); goto clean; } - + // Allocate int16 for reception (LLRs). Buffer casted to uint8_t for transmission q->q = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); if (!q->q) { @@ -244,9 +242,11 @@ int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) { goto clean; } - q->ce = srslte_vec_malloc(sizeof(cf_t) * q->max_re); - if (!q->ce) { - goto clean; + if (!q->is_ue) { + q->ce = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->ce) { + goto clean; + } } q->z = srslte_vec_malloc(sizeof(cf_t) * q->max_re); if (!q->z) { @@ -262,6 +262,14 @@ int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) { return ret; } +int srslte_pusch_init_ue(srslte_pusch_t *q, uint32_t max_prb) { + return pusch_init(q, max_prb, true); +} + +int srslte_pusch_init_enb(srslte_pusch_t *q, uint32_t max_prb) { + return pusch_init(q, max_prb, false); +} + void srslte_pusch_free(srslte_pusch_t *q) { int i; @@ -284,13 +292,20 @@ void srslte_pusch_free(srslte_pusch_t *q) { srslte_dft_precoding_free(&q->dft_precoding); if (q->users) { - for (int rnti=0;rntiis_ue) { + srslte_pusch_free_rnti(q, 0); + } else { + for (int rnti=0;rnti<=SRSLTE_SIRNTI;rnti++) { + srslte_pusch_free_rnti(q, rnti); + } } free(q->users); } + srslte_sequence_free(&q->seq_type2_fo); + srslte_sequence_free(&q->tmp_seq); + for (i = 0; i < 4; i++) { srslte_modem_table_free(&q->mod[i]); } @@ -300,6 +315,33 @@ void srslte_pusch_free(srslte_pusch_t *q) { } +int srslte_pusch_set_cell(srslte_pusch_t *q, srslte_cell_t cell) { + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && srslte_cell_isvalid(&cell)) + { + + q->max_re = cell.nof_prb * MAX_PUSCH_RE(q->cell.cp); + + INFO("PUSCH: Cell config PCI=%d, %d ports %d PRBs, max_symbols: %d\n", + q->cell.id, q->cell.nof_ports, q->cell.nof_prb, q->max_re); + + if (q->cell.id != cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + /* Precompute sequence for type2 frequency hopping */ + if (srslte_sequence_LTE_pr(&q->seq_type2_fo, 210, q->cell.id)) { + fprintf(stderr, "Error initiating type2 frequency hopping sequence\n"); + return SRSLTE_ERROR; + } + + } + ret = SRSLTE_SUCCESS; + } + return ret; +} + + + /* Configures the structure srslte_pusch_cfg_t from the UL DCI allocation dci_msg. * If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant */ @@ -391,29 +433,63 @@ int srslte_pusch_cfg(srslte_pusch_t *q, * For the connection procedure, use srslte_pusch_encode() functions */ int srslte_pusch_set_rnti(srslte_pusch_t *q, uint16_t rnti) { uint32_t i; - - if (!q->users[rnti]) { - q->users[rnti] = calloc(1, sizeof(srslte_pusch_user_t)); - if (q->users[rnti]) { - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - if (srslte_sequence_pusch(&q->users[rnti]->seq[i], rnti, 2 * i, q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - return SRSLTE_ERROR; - } + + uint32_t rnti_idx = q->is_ue?0:rnti; + + if (!q->users[rnti_idx] || q->is_ue) { + if (!q->users[rnti_idx]) { + q->users[rnti_idx] = calloc(1, sizeof(srslte_pusch_user_t)); + if (!q->users[rnti_idx]) { + perror("calloc"); + return -1; } - q->users[rnti]->sequences_generated = true; } + for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + if (srslte_sequence_pusch(&q->users[rnti_idx]->seq[i], rnti, 2 * i, q->cell.id, + q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) + { + fprintf(stderr, "Error initializing PUSCH scrambling sequence\n"); + srslte_pusch_free_rnti(q, rnti); + return SRSLTE_ERROR; + } + } + q->ue_rnti = rnti; + q->users[rnti_idx]->cell_id = q->cell.id; + q->users[rnti_idx]->sequence_generated = true; + } else { + fprintf(stderr, "Error generating PUSCH sequence: rnti=0x%x already generated\n", rnti); } return SRSLTE_SUCCESS; } -void srslte_pusch_clear_rnti(srslte_pusch_t *q, uint16_t rnti) { - if (q->users[rnti]) { +void srslte_pusch_free_rnti(srslte_pusch_t *q, uint16_t rnti) { + + uint32_t rnti_idx = q->is_ue?0:rnti; + + if (q->users[rnti_idx]) { for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { - srslte_sequence_free(&q->users[rnti]->seq[i]); + srslte_sequence_free(&q->users[rnti_idx]->seq[i]); } - free(q->users[rnti]); - q->users[rnti] = NULL; + free(q->users[rnti_idx]); + q->users[rnti_idx] = NULL; + q->ue_rnti = 0; + } +} + +static srslte_sequence_t *get_user_sequence(srslte_pusch_t *q, uint16_t rnti, uint32_t sf_idx, uint32_t len) +{ + uint32_t rnti_idx = q->is_ue?0:rnti; + + // The scrambling sequence is pregenerated for all RNTIs in the eNodeB but only for C-RNTI in the UE + if (q->users[rnti_idx] && q->users[rnti_idx]->sequence_generated && + q->users[rnti_idx]->cell_id == q->cell.id && + q->ue_rnti == rnti && + ((rnti >= SRSLTE_CRNTI_START && rnti < SRSLTE_CRNTI_END) || !q->is_ue)) + { + return &q->users[rnti_idx]->seq[sf_idx]; + } else { + srslte_sequence_pusch(&q->tmp_seq, rnti, 2 * sf_idx, q->cell.id, len); + return &q->tmp_seq; } } @@ -445,18 +521,13 @@ int srslte_pusch_encode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softb return SRSLTE_ERROR; } - if (q->users[rnti] && q->users[rnti]->sequences_generated) { - srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->q, cfg->nbits.nof_bits); - } else { - srslte_sequence_t seq; - if (srslte_sequence_pusch(&seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { - return SRSLTE_ERROR; - } - srslte_scrambling_bytes(&seq, (uint8_t*) q->q, cfg->nbits.nof_bits); - srslte_sequence_free(&seq); - } - - // Correct UCI placeholder/repetition bits + // Generate scrambling sequence if not pre-generated + srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits); + + // Run scrambling + srslte_scrambling_bytes(seq, (uint8_t*) q->q, cfg->nbits.nof_bits); + + // Correct UCI placeholder/repetition bits uint8_t *d = q->q; for (int i = 0; i < q->ul_sch.nof_ri_ack_bits; i++) { if (q->ul_sch.ack_ri_bits[i].type == UCI_BIT_PLACEHOLDER) { @@ -528,24 +599,15 @@ int srslte_pusch_decode(srslte_pusch_t *q, srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, noise_estimate); // DFT predecoding - srslte_dft_predecoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); + srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); // Soft demodulation srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->q, cfg->nbits.nof_re); - srslte_sequence_t *seq = NULL; + // Generate scrambling sequence if not pre-generated + srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits); - // Create sequence if does not exist - if (q->users[rnti] && q->users[rnti]->sequences_generated) { - seq = &q->users[rnti]->seq[cfg->sf_idx]; - } else { - seq = &q->tmp_seq; - if (srslte_sequence_pusch(seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { - return SRSLTE_ERROR; - } - } - - // Decode RI/HARQ bits before descrambling + // Decode RI/HARQ bits before descrambling if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) { fprintf(stderr, "Error decoding RI/HARQ bits\n"); return SRSLTE_ERROR; @@ -554,11 +616,7 @@ int srslte_pusch_decode(srslte_pusch_t *q, // Descrambling srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); - if (!(q->users[rnti] && q->users[rnti]->sequences_generated)) { - srslte_sequence_free(seq); - } - - return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); + return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); } else { return SRSLTE_ERROR_INVALID_INPUTS; } diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index 00713e6c1..be10c304c 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -41,15 +41,19 @@ /* Returns the number of RE in a PRB in a slot and subframe */ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_t nof_prb, - uint32_t nof_ports, uint32_t nof_ctrl_symbols, srslte_cp_t cp) { + uint32_t nof_ports, uint32_t nof_ctrl_symbols, srslte_cp_t cp, srslte_sf_t sf_type) { uint32_t re; - bool skip_refs = false; + bool skip_refs = true; + srslte_cp_t cp_ = cp; + if(SRSLTE_SF_MBSFN == sf_type) { + cp_ = SRSLTE_CP_EXT; + } if (slot == 0) { - re = (SRSLTE_CP_NSYMB(cp) - nof_ctrl_symbols) * SRSLTE_NRE; + re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols) * SRSLTE_NRE; } else { - re = SRSLTE_CP_NSYMB(cp) * SRSLTE_NRE; + re = SRSLTE_CP_NSYMB(cp_) * SRSLTE_NRE; } /* if it's the prb in the middle, there are less RE due to PBCH and PSS/SSS */ @@ -57,18 +61,18 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_ && (prb_idx >= nof_prb / 2 - 3 && prb_idx < nof_prb / 2 + 3 + (nof_prb%2))) { if (subframe == 0) { if (slot == 0) { - re = (SRSLTE_CP_NSYMB(cp) - nof_ctrl_symbols - 2) * SRSLTE_NRE; + re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols - 2) * SRSLTE_NRE; } else { - if (SRSLTE_CP_ISEXT(cp)) { - re = (SRSLTE_CP_NSYMB(cp) - 4) * SRSLTE_NRE; - skip_refs = true; + if (SRSLTE_CP_ISEXT(cp_)) { + re = (SRSLTE_CP_NSYMB(cp_) - 4) * SRSLTE_NRE; + skip_refs = false; } else { - re = (SRSLTE_CP_NSYMB(cp) - 4) * SRSLTE_NRE + 2 * nof_ports; + re = (SRSLTE_CP_NSYMB(cp_) - 4) * SRSLTE_NRE + 2 * nof_ports; } } } else if (subframe == 5) { if (slot == 0) { - re = (SRSLTE_CP_NSYMB(cp) - nof_ctrl_symbols - 2) * SRSLTE_NRE; + re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols - 2) * SRSLTE_NRE; } } if ((nof_prb % 2) @@ -77,7 +81,7 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_ re += 2 * SRSLTE_NRE / 2; } else if (subframe == 0) { re += 4 * SRSLTE_NRE / 2 - nof_ports; - if (SRSLTE_CP_ISEXT(cp)) { + if (SRSLTE_CP_ISEXT(cp_)) { re -= nof_ports > 2 ? 2 : nof_ports; } } @@ -85,22 +89,27 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_ } // remove references - if (!skip_refs) { - switch (nof_ports) { - case 1: - case 2: - re -= 2 * (slot + 1) * nof_ports; - break; - case 4: - if (slot == 1) { - re -= 12; - } else { - re -= 4; - if (nof_ctrl_symbols == 1) { + if (skip_refs) { + if(sf_type == SRSLTE_SF_NORM){ + switch (nof_ports) { + case 1: + case 2: + re -= 2 * (slot + 1) * nof_ports; + break; + case 4: + if (slot == 1) { + re -= 12; + } else { re -= 4; + if (nof_ctrl_symbols == 1) { + re -= 4; + } } + break; } - break; + } + if(sf_type == SRSLTE_SF_MBSFN){ + re -= 6*(slot + 1); } } return re; @@ -278,23 +287,23 @@ uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, uint32_t nof_prb, uint32 /* Computes the number of RE for each PRB in the prb_dist structure */ uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t cell, - uint32_t sf_idx, uint32_t nof_ctrl_symbols) + uint32_t sf_idx, uint32_t nof_ctrl_symbols) { uint32_t j, s; - // Compute number of RE per PRB uint32_t nof_re = 0; for (s = 0; s < 2; s++) { for (j = 0; j < cell.nof_prb; j++) { if (grant->prb_idx[s][j]) { - nof_re += ra_re_x_prb(sf_idx, s, j, - cell.nof_prb, cell.nof_ports, nof_ctrl_symbols, cell.cp); + nof_re += ra_re_x_prb(sf_idx, s, j, cell.nof_prb, cell.nof_ports, + nof_ctrl_symbols, cell.cp, grant->sf_type); } } - } + } return nof_re; } + /** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 * Decode dci->type?_alloc to grant * This function only reads dci->type?_alloc and dci->alloc_type fields. @@ -432,7 +441,7 @@ int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_ return SRSLTE_SUCCESS; } -int dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) { +int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) { uint32_t i_tbs = 0; int tbs = -1; if (mcs->idx < 10) { @@ -457,6 +466,53 @@ int dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) { tbs = 0; i_tbs = 0; } + + if (tbs == -1) { + tbs = srslte_ra_tbs_from_idx(i_tbs, nprb); + if (tbs >= 0) { + mcs->tbs = tbs; + } + } + return tbs; +} + +int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb) { + uint32_t i_tbs = 0; + int tbs = -1; + if (mcs->idx < 5) { + mcs->mod = SRSLTE_MOD_QPSK; + i_tbs = mcs->idx*2; + }else if (mcs->idx < 6) { + mcs->mod = SRSLTE_MOD_16QAM; + i_tbs = mcs->idx*2; + }else if (mcs->idx < 11) { + mcs->mod = SRSLTE_MOD_16QAM; + i_tbs = mcs->idx + 5; + }else if (mcs->idx < 20) { + mcs->mod = SRSLTE_MOD_64QAM; + i_tbs = mcs->idx + 5; + }else if (mcs->idx < 28) { + //mcs->mod = SRSLTE_MOD_256QAM; + i_tbs = mcs->idx + 5; + }else if (mcs->idx == 28) { + mcs->mod = SRSLTE_MOD_QPSK; + tbs = 0; + i_tbs = 0; + }else if (mcs->idx == 29) { + mcs->mod = SRSLTE_MOD_16QAM; + tbs = 0; + i_tbs = 0; + }else if (mcs->idx == 30) { + mcs->mod = SRSLTE_MOD_64QAM; + tbs = 0; + i_tbs = 0; + }else if (mcs->idx == 31) { + mcs->mod = SRSLTE_MOD_64QAM; + tbs = 0; + i_tbs = 0; + } + + if (tbs == -1) { tbs = srslte_ra_tbs_from_idx(i_tbs, nprb); if (tbs >= 0) { @@ -496,21 +552,23 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr grant->mcs[0].tbs = (uint32_t) tbs; } else { n_prb = grant->nof_prb; + grant->nof_tb = 0; if (dci->tb_en[0]) { grant->mcs[0].idx = dci->mcs_idx; - tbs = dl_fill_ra_mcs(&grant->mcs[0], n_prb); + tbs = srslte_dl_fill_ra_mcs(&grant->mcs[0], n_prb); if (tbs) { last_dl_tbs[dci->harq_process%8] = tbs; } else { // For mcs>=29, set last TBS received for this PID grant->mcs[0].tbs = last_dl_tbs[dci->harq_process%8]; } + grant->nof_tb++; } else { grant->mcs[0].tbs = 0; } if (dci->tb_en[1]) { grant->mcs[1].idx = dci->mcs_idx_1; - tbs = dl_fill_ra_mcs(&grant->mcs[1], n_prb); + tbs = srslte_dl_fill_ra_mcs(&grant->mcs[1], n_prb); if (tbs) { last_dl_tbs2[dci->harq_process%8] = tbs; } else { @@ -521,11 +579,10 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr grant->mcs[1].tbs = 0; } } - grant->nof_tb = 0; for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + grant->tb_en[tb] = dci->tb_en[tb]; if (dci->tb_en[tb]) { grant->Qm[tb] = srslte_mod_bits_x_symbol(grant->mcs[tb].mod); - grant->nof_tb++; } } grant->pinfo = dci->pinfo; @@ -541,19 +598,26 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl srslte_ra_nbits_t nbits [SRSLTE_MAX_CODEWORDS]) { // Compute number of RE - for (int i = 0; i < grant->nof_tb; i++) { - /* Compute number of RE for first transport block */ - nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi); - nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi; - nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; - nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i]; + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant->tb_en[i]) { + /* Compute number of RE for first transport block */ + nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi); + nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi; + if (SRSLTE_SF_NORM == grant->sf_type) { + nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; + } else if (SRSLTE_SF_MBSFN == grant->sf_type) { + nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart; + } + nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i]; + } } } /** Obtains a DL grant from a DCI grant for PDSCH */ int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci, uint32_t nof_prb, uint16_t msg_rnti, srslte_ra_dl_grant_t *grant) -{ +{ + grant->sf_type = SRSLTE_SF_NORM; bool crc_is_crnti = false; if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) { crc_is_crnti = true; @@ -820,11 +884,13 @@ void srslte_ra_pdsch_fprint(FILE *f, srslte_ra_dl_dci_t *dci, uint32_t nof_prb) void srslte_ra_dl_grant_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { srslte_ra_prb_fprint(f, grant); fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->nof_prb); - fprintf(f, " - Number of TBs:\t\t\t%d\n", grant->nof_tb); - for (int i = 0; i < grant->nof_tb; i++) { - fprintf(f, " - Transport block:\t\t\t%d\n", i); - fprintf(f, " -> Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs[i].mod)); - fprintf(f, " -> Transport block size:\t\t%d\n", grant->mcs[i].tbs); + fprintf(f, " - Number of TBs:\t\t\t%d\n", SRSLTE_RA_DL_GRANT_NOF_TB(grant)); + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant->tb_en[i]) { + fprintf(f, " - Transport block:\t\t\t%d\n", i); + fprintf(f, " -> Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs[i].mod)); + fprintf(f, " -> Transport block size:\t\t%d\n", grant->mcs[i].tbs); + } } } @@ -841,6 +907,4 @@ void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { } } -} - - +} \ No newline at end of file diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index e0002429e..e76fa6aef 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -32,12 +32,7 @@ #include #include #include - #include "srslte/phy/phch/pdsch.h" -#include "srslte/phy/phch/pusch.h" -#include "srslte/phy/phch/sch.h" -#include "srslte/phy/phch/uci.h" -#include "srslte/phy/common/phy_common.h" #include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" @@ -174,15 +169,10 @@ void srslte_sch_set_max_noi(srslte_sch_t *q, uint32_t max_iterations) { q->max_iterations = max_iterations; } -float srslte_sch_average_noi(srslte_sch_t *q) { - return q->average_nof_iterations; -} - uint32_t srslte_sch_last_noi(srslte_sch_t *q) { return q->nof_iterations; } - /* Encode a transport block according to 36.212 5.3.2 * */ @@ -320,8 +310,8 @@ bool decode_tb_cb(srslte_sch_t *q, bool cb_map[SRSLTE_MAX_CODEBLOCKS]; - uint32_t cb_idx[SRSLTE_TDEC_NPAR]; - int16_t *decoder_input[SRSLTE_TDEC_NPAR]; + uint32_t cb_idx[SRSLTE_TDEC_MAX_NPAR]; + int16_t *decoder_input[SRSLTE_TDEC_MAX_NPAR]; uint32_t nof_cb = cb_size_group?cb_segm->C2:cb_segm->C1; uint32_t first_cb = cb_size_group?cb_segm->C1:0; @@ -338,9 +328,9 @@ bool decode_tb_cb(srslte_sch_t *q, return false; } - for (int i=0;idecoder);i++) { cb_idx[i] = i+first_cb; - decoder_input[i] = false; + decoder_input[i] = NULL; } for (int i=0;idecoder, cb_len); - uint32_t remaining_cb = nof_cb; - + uint32_t remaining_cb = nof_cb; + + q->nof_iterations = 0; + while(remaining_cb>0) { // Unratematch the codeblocks left to decode - for (int i=0;idecoder);i++) { if (!decoder_input[i] && remaining_cb > 0) { // Find an unprocessed CB @@ -372,25 +364,23 @@ bool decode_tb_cb(srslte_sch_t *q, n_e2 = n_e+Qm; rp = (cb_segm->C - gamma)*n_e + (cb_idx[i]-(cb_segm->C - gamma))*n_e2; } - + INFO("CB %d: rp=%d, n_e=%d, i=%d\n", cb_idx[i], rp, n_e2, i); if (srslte_rm_turbo_rx_lut(&e_bits[rp], softbuffer->buffer_f[cb_idx[i]], n_e2, cb_len_idx, rv)) { fprintf(stderr, "Error in rate matching\n"); return SRSLTE_ERROR; } - decoder_input[i] = softbuffer->buffer_f[cb_idx[i]]; + decoder_input[i] = softbuffer->buffer_f[cb_idx[i]]; } } } - // Run 1 iteration for up to TDEC_NPAR codeblocks + // Run 1 iteration for the codeblocks in queue srslte_tdec_iteration_par(&q->decoder, decoder_input, cb_len); - q->nof_iterations = srslte_tdec_get_nof_iterations_cb(&q->decoder, 0); - // Decide output bits and compute CRC - for (int i=0;idecoder);i++) { if (decoder_input[i]) { srslte_tdec_decision_byte_par_cb(&q->decoder, q->cb_in, i, cb_len); @@ -409,24 +399,30 @@ bool decode_tb_cb(srslte_sch_t *q, if (!srslte_crc_checksum_byte(crc_ptr, q->cb_in, len_crc)) { memcpy(&data[(cb_idx[i]*rlen)/8], q->cb_in, rlen/8 * sizeof(uint8_t)); - + + q->nof_iterations += srslte_tdec_get_nof_iterations_cb(&q->decoder, i); + // Reset number of iterations for that CB in the decoder srslte_tdec_reset_cb(&q->decoder, i); remaining_cb--; decoder_input[i] = NULL; cb_idx[i] = 0; - - // CRC is error and exceeded maximum iterations for this CB. + + // CRC is error and exceeded maximum iterations for this CB. // Early stop the whole transport block. } else if (srslte_tdec_get_nof_iterations_cb(&q->decoder, i) >= q->max_iterations) { INFO("CB %d: Error. CB is erroneous. remaining_cb=%d, i=%d, first_cb=%d, nof_cb=%d\n", - cb_idx[i], remaining_cb, i, first_cb, nof_cb); - return false; + cb_idx[i], remaining_cb, i, first_cb, nof_cb); + + q->nof_iterations += q->max_iterations; + q->nof_iterations /= (nof_cb-remaining_cb+1); + return false; } } } } - + + q->nof_iterations /= nof_cb; return true; } @@ -478,7 +474,7 @@ static int decode_tb(srslte_sch_t *q, data[cb_segm->tbs/8+1] = 0; data[cb_segm->tbs/8+2] = 0; - // Process Codeblocks in groups of equal CB size to parallelize according to SRSLTE_TDEC_NPAR + // Process Codeblocks in groups of equal CB size to parallelize according to SRSLTE_TDEC_MAX_NPAR for (uint32_t i=0;inof_layers != cfg->grant.nof_tb) { + if (cfg->nof_layers != SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant)) { Nl = 2; } @@ -553,7 +549,7 @@ int srslte_dlsch_encode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbu uint8_t *data, uint8_t *e_bits, int codeword_idx) { uint32_t Nl = 1; - if (cfg->nof_layers != cfg->grant.nof_tb) { + if (cfg->nof_layers != SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant)) { Nl = 2; } @@ -657,14 +653,17 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs // Deinterleave and decode HARQ bits if (uci_data->uci_ack_len > 0) { + uint8_t acks[2] = {0, 0}; float beta = beta_harq_offset[cfg->uci_cfg.I_offset_ack]; if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_decode_ack(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ack); + ret = srslte_uci_decode_ack(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len); if (ret < 0) { return ret; } + uci_data->uci_ack = acks[0]; + uci_data->uci_ack_2 = acks[1]; Q_prime_ack = (uint32_t) ret; // Set zeros to HARQ bits @@ -805,11 +804,13 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q, // Encode (and interleave) ACK if (uci_data.uci_ack_len > 0) { + uint8_t acks [2] = {uci_data.uci_ack, uci_data.uci_ack_2}; float beta = beta_harq_offset[cfg->uci_cfg.I_offset_ack]; if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_encode_ack(cfg, uci_data.uci_ack, uci_data.uci_cqi_len, beta, nb_q/Qm, &q->ack_ri_bits[Q_prime_ri*Qm]); + ret = srslte_uci_encode_ack(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len, + beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm]); if (ret < 0) { return ret; } diff --git a/lib/src/phy/phch/sequences.c b/lib/src/phy/phch/sequences.c index 2816709b4..dc9e45a7f 100644 --- a/lib/src/phy/phch/sequences.c +++ b/lib/src/phy/phch/sequences.c @@ -33,7 +33,6 @@ * 36.211 6.6.1 */ int srslte_sequence_pbch(srslte_sequence_t *seq, srslte_cp_t cp, uint32_t cell_id) { - bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_LTE_pr(seq, SRSLTE_CP_ISNORM(cp)?1920:1728, cell_id); } @@ -41,7 +40,6 @@ int srslte_sequence_pbch(srslte_sequence_t *seq, srslte_cp_t cp, uint32_t cell_i * 36.211 6.7.1 */ int srslte_sequence_pcfich(srslte_sequence_t *seq, uint32_t nslot, uint32_t cell_id) { - bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_LTE_pr(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } @@ -50,7 +48,6 @@ int srslte_sequence_pcfich(srslte_sequence_t *seq, uint32_t nslot, uint32_t cell * 36.211 6.9.1 */ int srslte_sequence_phich(srslte_sequence_t *seq, uint32_t nslot, uint32_t cell_id) { - bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_LTE_pr(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } @@ -58,7 +55,6 @@ int srslte_sequence_phich(srslte_sequence_t *seq, uint32_t nslot, uint32_t cell_ * 36.211 6.8.2 */ int srslte_sequence_pdcch(srslte_sequence_t *seq, uint32_t nslot, uint32_t cell_id, uint32_t len) { - bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_LTE_pr(seq, len, (nslot/2) * 512 + cell_id); } @@ -66,7 +62,6 @@ int srslte_sequence_pdcch(srslte_sequence_t *seq, uint32_t nslot, uint32_t cell_ * 36.211 6.3.1 */ int srslte_sequence_pdsch(srslte_sequence_t *seq, uint16_t rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len) { - bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_LTE_pr(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); } @@ -74,7 +69,6 @@ int srslte_sequence_pdsch(srslte_sequence_t *seq, uint16_t rnti, int q, uint32_t * 36.211 5.3.1 */ int srslte_sequence_pusch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id, uint32_t len) { - bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_LTE_pr(seq, len, (rnti<<14) + ((nslot/2)<<9) + cell_id); } @@ -82,6 +76,11 @@ int srslte_sequence_pusch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, * 36.211 5.4.2 */ int srslte_sequence_pucch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id) { - bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_LTE_pr(seq, 20, ((((nslot/2)+1)*(2*cell_id+1))<<16)+rnti); } + +int srslte_sequence_pmch(srslte_sequence_t *seq, uint32_t nslot, uint32_t mbsfn_id , uint32_t len){ + bzero(seq,sizeof(srslte_sequence_t)); + return srslte_sequence_LTE_pr(seq, len, (((nslot/2)<<9) + mbsfn_id)); + +} \ No newline at end of file diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 832f18d1f..6e6b8c024 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -159,6 +159,19 @@ add_test(pdsch_test_multiplex2cw_p1_50 pdsch_test -x multiplex -a 2 -t 0 -p 1 - add_test(pdsch_test_multiplex2cw_p1_75 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 75) add_test(pdsch_test_multiplex2cw_p1_100 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 100) +######################################################################## +# PMCH TEST +######################################################################## + + +add_executable(pmch_test pmch_test.c) +target_link_libraries(pmch_test srslte_phy) + +add_test(pmch_test_qpsk pmch_test -m 6 -n 50) +add_test(pmch_test_qam16 pmch_test -m 15 -n 100) +add_test(pmch_test_qam64 pmch_test -m 25 -n 100) + + ######################################################################## # FILE TEST ######################################################################## @@ -178,11 +191,15 @@ target_link_libraries(pdcch_file_test srslte_phy) add_executable(pdsch_pdcch_file_test pdsch_pdcch_file_test.c) target_link_libraries(pdsch_pdcch_file_test srslte_phy) +add_executable(pmch_file_test pmch_file_test.c) +target_link_libraries(pmch_file_test srslte_phy) + add_test(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat) add_test(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) add_test(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) add_test(pdcch_file_test pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat) -add_test(pdsch_pdcch_file_test pdsch_pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat) +add_test(pdsch_pdcch_file_test pdsch_pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat) +add_test(pmch_file_test pmch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/pmch_100prbs_MCS2_SR0.bin) ######################################################################## # PUSCH TEST diff --git a/lib/src/phy/phch/test/pbch_file_test.c b/lib/src/phy/phch/test/pbch_file_test.c index f3e4b9b08..734640d55 100644 --- a/lib/src/phy/phch/test/pbch_file_test.c +++ b/lib/src/phy/phch/test/pbch_file_test.c @@ -131,7 +131,11 @@ int base_init() { return -1; } - if (srslte_chest_dl_init(&chest, cell)) { + if (srslte_chest_dl_init(&chest, cell.nof_prb)) { + fprintf(stderr, "Error initializing equalizer\n"); + return -1; + } + if (srslte_chest_dl_set_cell(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } @@ -141,7 +145,11 @@ int base_init() { return -1; } - if (srslte_pbch_init(&pbch, cell)) { + if (srslte_pbch_init(&pbch)) { + fprintf(stderr, "Error initiating PBCH\n"); + return -1; + } + if (srslte_pbch_set_cell(&pbch, cell)) { fprintf(stderr, "Error initiating PBCH\n"); return -1; } diff --git a/lib/src/phy/phch/test/pbch_test.c b/lib/src/phy/phch/test/pbch_test.c index c86e6f48a..a8c673714 100644 --- a/lib/src/phy/phch/test/pbch_test.c +++ b/lib/src/phy/phch/test/pbch_test.c @@ -104,7 +104,11 @@ int main(int argc, char **argv) { } } - if (srslte_pbch_init(&pbch, cell)) { + if (srslte_pbch_init(&pbch)) { + fprintf(stderr, "Error creating PBCH object\n"); + exit(-1); + } + if (srslte_pbch_set_cell(&pbch, cell)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } diff --git a/lib/src/phy/phch/test/pcfich_file_test.c b/lib/src/phy/phch/test/pcfich_file_test.c index 27b50baeb..dfb8d72e3 100644 --- a/lib/src/phy/phch/test/pcfich_file_test.c +++ b/lib/src/phy/phch/test/pcfich_file_test.c @@ -142,7 +142,11 @@ int base_init() { } } - if (srslte_chest_dl_init(&chest, cell)) { + if (srslte_chest_dl_init(&chest, cell.nof_prb)) { + fprintf(stderr, "Error initializing equalizer\n"); + return -1; + } + if (srslte_chest_dl_set_cell(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } @@ -157,7 +161,11 @@ int base_init() { return -1; } - if (srslte_pcfich_init(&pcfich, ®s, cell)) { + if (srslte_pcfich_init(&pcfich, 1)) { + fprintf(stderr, "Error creating PBCH object\n"); + return -1; + } + if (srslte_pcfich_set_cell(&pcfich, ®s, cell)) { fprintf(stderr, "Error creating PBCH object\n"); return -1; } diff --git a/lib/src/phy/phch/test/pcfich_test.c b/lib/src/phy/phch/test/pcfich_test.c index 5d90b645a..32e9925b2 100644 --- a/lib/src/phy/phch/test/pcfich_test.c +++ b/lib/src/phy/phch/test/pcfich_test.c @@ -124,7 +124,11 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_pcfich_init(&pcfich, ®s, cell)) { + if (srslte_pcfich_init(&pcfich, 1)) { + fprintf(stderr, "Error creating PBCH object\n"); + exit(-1); + } + if (srslte_pcfich_set_cell(&pcfich, ®s, cell)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } diff --git a/lib/src/phy/phch/test/pdcch_file_test.c b/lib/src/phy/phch/test/pdcch_file_test.c index b505e6b68..d4ceed4b6 100644 --- a/lib/src/phy/phch/test/pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdcch_file_test.c @@ -148,7 +148,11 @@ int base_init() { } } - if (srslte_chest_dl_init(&chest, cell)) { + if (srslte_chest_dl_init(&chest, cell.nof_prb)) { + fprintf(stderr, "Error initializing equalizer\n"); + return -1; + } + if (srslte_chest_dl_set_cell(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } @@ -167,11 +171,15 @@ int base_init() { fprintf(stderr, "Error setting CFI %d\n", cfi); return -1; } - if (srslte_pdcch_init(&pdcch, ®s, cell)) { + if (srslte_pdcch_init_ue(&pdcch, cell.nof_prb, 1)) { fprintf(stderr, "Error creating PDCCH object\n"); exit(-1); } - + if (srslte_pdcch_set_cell(&pdcch, ®s, cell)) { + fprintf(stderr, "Error creating PDCCH object\n"); + exit(-1); + } + DEBUG("Memory init OK\n",0); return 0; } diff --git a/lib/src/phy/phch/test/pdcch_test.c b/lib/src/phy/phch/test/pdcch_test.c index 9495c497b..d5c33a709 100644 --- a/lib/src/phy/phch/test/pdcch_test.c +++ b/lib/src/phy/phch/test/pdcch_test.c @@ -204,15 +204,23 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_pdcch_init_tx(&pdcch_tx, ®s, cell)) { + if (srslte_pdcch_init_enb(&pdcch_tx, cell.nof_prb)) { fprintf(stderr, "Error creating PDCCH object\n"); exit(-1); } + if (srslte_pdcch_set_cell(&pdcch_tx, ®s, cell)) { + fprintf(stderr, "Error setting cell in PDCCH object\n"); + exit(-1); + } - if (srslte_pdcch_init_rx(&pdcch_rx, ®s, cell, nof_rx_ant)) { + if (srslte_pdcch_init_ue(&pdcch_rx, cell.nof_prb, nof_rx_ant)) { fprintf(stderr, "Error creating PDCCH object\n"); exit(-1); } + if (srslte_pdcch_set_cell(&pdcch_rx, ®s, cell)) { + fprintf(stderr, "Error setting cell in PDCCH object\n"); + exit(-1); + } /* Resource allocate init */ nof_dcis = 0; diff --git a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c index c32f6ac76..90c0e1c17 100644 --- a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c @@ -137,11 +137,15 @@ int base_init() { exit(-1); } - if (srslte_ue_dl_init(&ue_dl, cell, 1)) { + if (srslte_ue_dl_init(&ue_dl, cell.nof_prb, 1)) { fprintf(stderr, "Error initializing UE DL\n"); return -1; } - + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { + fprintf(stderr, "Error initializing UE DL\n"); + return -1; + } + srslte_ue_dl_set_rnti(&ue_dl, rnti); DEBUG("Memory init OK\n",0); diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index b98d75c22..0c98079b9 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -153,7 +153,7 @@ int main(int argc, char **argv) { int ret = -1; struct timeval t[3]; srslte_softbuffer_tx_t *softbuffers_tx[SRSLTE_MAX_CODEWORDS]; - int M=10; + int M=1; bool acks[SRSLTE_MAX_CODEWORDS] = {false}; parse_args(argc,argv); @@ -213,8 +213,6 @@ int main(int argc, char **argv) { return ret; } - - #ifdef DO_OFDM srslte_ofdm_tx_init(&ofdm_tx, cell.cp, cell.nof_prb); srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb); @@ -257,8 +255,8 @@ int main(int argc, char **argv) { } - for (int i = 0; i < grant.nof_tb; i++) { - if (grant.mcs[i].tbs) { + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant.tb_en[i]) { data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs); if (!data_tx[i]) { perror("srslte_vec_malloc"); @@ -276,7 +274,11 @@ int main(int argc, char **argv) { } } - if (srslte_pdsch_init_rx(&pdsch_rx, cell, nof_rx_antennas)) { + if (srslte_pdsch_init_ue(&pdsch_rx, cell.nof_prb, nof_rx_antennas)) { + fprintf(stderr, "Error creating PDSCH object\n"); + goto quit; + } + if (srslte_pdsch_set_cell(&pdsch_rx, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); goto quit; } @@ -303,12 +305,11 @@ int main(int argc, char **argv) { INFO(" cp=%s\n", srslte_cp_string(cell.cp)); INFO(" phich_length=%d\n", (int) cell.phich_length); INFO(" phich_resources=%d\n", (int) cell.phich_resources); - INFO(" nof_tb=%d\n", pdsch_cfg.grant.nof_tb); INFO(" nof_prb=%d\n", pdsch_cfg.grant.nof_prb); INFO(" sf_idx=%d\n", pdsch_cfg.sf_idx); INFO(" mimo_type=%s\n", srslte_mimotype2str(pdsch_cfg.mimo_type)); INFO(" nof_layers=%d\n", pdsch_cfg.nof_layers); - INFO(" nof_tb=%d\n", pdsch_cfg.grant.nof_tb); + INFO(" nof_tb=%d\n", SRSLTE_RA_DL_GRANT_NOF_TB(&pdsch_cfg.grant)); for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { INFO(" Tranport block index %d:\n", i); INFO(" Qm=%d\n", pdsch_cfg.grant.Qm[i]); @@ -334,18 +335,26 @@ int main(int argc, char **argv) { srslte_filesource_read(&fsrc, rx_slot_symbols[0], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); #endif - srslte_chest_dl_t chest; - if (srslte_chest_dl_init(&chest, cell)) { + srslte_chest_dl_t chest; + if (srslte_chest_dl_init(&chest, cell.nof_prb)) { fprintf(stderr, "Error initializing equalizer\n"); exit(-1); } + if (srslte_chest_dl_set_cell(&chest, cell)) { + printf("Error initializing equalizer\n"); + exit(-1); + } srslte_chest_dl_estimate(&chest, rx_slot_symbols[0], ce[0], subframe); srslte_chest_dl_free(&chest); srslte_filesource_free(&fsrc); } else { - if (srslte_pdsch_init_tx(&pdsch_tx, cell)) { + if (srslte_pdsch_init_enb(&pdsch_tx, cell.nof_prb)) { + fprintf(stderr, "Error creating PDSCH object\n"); + goto quit; + } + if (srslte_pdsch_set_cell(&pdsch_tx, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); goto quit; } @@ -372,9 +381,11 @@ int main(int argc, char **argv) { } } - for (int tb = 0; tb < grant.nof_tb; tb++) { - for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) { - data_tx[tb][byte] = (uint8_t)(rand() % 256); + for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (grant.tb_en[tb]) { + for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) { + data_tx[tb][byte] = (uint8_t) (rand() % 256); + } } } @@ -444,11 +455,15 @@ int main(int argc, char **argv) { srslte_ofdm_rx_sf(&ofdm_rx, tx_sf_symbols[i], rx_slot_symbols[i]); } #endif - for (i = 0; i < grant.nof_tb; i++) { - if (grant.mcs[i].tbs) { + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant.tb_en[i]) { srslte_softbuffer_rx_reset_tbs(softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs); } } + + /* Set ACKs to zero, otherwise will not decode if there are positive ACKs*/ + bzero(acks, sizeof(acks)); + r = srslte_pdsch_decode(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data_rx, acks); } gettimeofday(&t[2], NULL); @@ -464,19 +479,23 @@ int main(int argc, char **argv) { } /* Check Tx and Rx bytes */ - for (int tb = 0; tb < grant.nof_tb; tb++) { - for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) { - if (data_tx[tb][byte] != data_rx[tb][byte]) { - ERROR("Found BYTE error in TB %d (%02X != %02X), quiting...", tb, data_tx[tb][byte], data_rx[tb][byte]); - ret = SRSLTE_ERROR; - goto quit; + for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (grant.tb_en[tb]) { + for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) { + if (data_tx[tb][byte] != data_rx[tb][byte]) { + ERROR("Found BYTE error in TB %d (%02X != %02X), quiting...", tb, data_tx[tb][byte], data_rx[tb][byte]); + ret = SRSLTE_ERROR; + goto quit; + } } } } /* Check all transport blocks have been decoded OK */ - for (int tb = 0; tb < grant.nof_tb; tb++) { - ret |= (acks[tb]) ? SRSLTE_SUCCESS : SRSLTE_ERROR; + for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (grant.tb_en[tb]) { + ret |= (acks[tb]) ? SRSLTE_SUCCESS : SRSLTE_ERROR; + } } ret = SRSLTE_SUCCESS; diff --git a/lib/src/phy/phch/test/phich_file_test.c b/lib/src/phy/phch/test/phich_file_test.c index f037a55da..d7078f933 100644 --- a/lib/src/phy/phch/test/phich_file_test.c +++ b/lib/src/phy/phch/test/phich_file_test.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "srslte/srslte.h" @@ -165,7 +166,11 @@ int base_init() { } } - if (srslte_chest_dl_init(&chest, cell)) { + if (srslte_chest_dl_init(&chest, cell.nof_prb)) { + fprintf(stderr, "Error initializing equalizer\n"); + return -1; + } + if (srslte_chest_dl_set_cell(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } @@ -180,7 +185,11 @@ int base_init() { return -1; } - if (srslte_phich_init(&phich, ®s, cell)) { + if (srslte_phich_init(&phich, 1)) { + fprintf(stderr, "Error creating PBCH object\n"); + return -1; + } + if (srslte_phich_set_cell(&phich, ®s, cell)) { fprintf(stderr, "Error creating PBCH object\n"); return -1; } @@ -254,7 +263,11 @@ int main(int argc, char **argv) { for (ngroup=0;ngroup +#include +#include +#include +#include + +#include "srslte/srslte.h" + +char *input_file_name = NULL; + +srslte_cell_t cell = { + 100, // nof_prb + 1, // nof_ports + 1, // cell_id + SRSLTE_CP_EXT, // cyclic prefix + SRSLTE_PHICH_R_1, // PHICH resources + SRSLTE_PHICH_NORM // PHICH length +}; + +int flen; + +uint32_t cfi = 2; +uint16_t rnti = SRSLTE_SIRNTI; + +int max_frames = 150; +uint32_t sf_idx = 1; + +uint8_t non_mbsfn_region = 2; +int mbsfn_area_id = 1; + +srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A; +srslte_filesource_t fsrc; +srslte_ue_dl_t ue_dl; +cf_t *input_buffer[SRSLTE_MAX_PORTS]; + +void usage(char *prog) { + printf("Usage: %s [rovfcenmps] -i input_file\n", prog); + printf("\t-o DCI format [Default %s]\n", srslte_dci_format_string(dci_format)); + printf("\t-c cell.id [Default %d]\n", cell.id); + printf("\t-s Start subframe_idx [Default %d]\n", sf_idx); + printf("\t-f cfi [Default %d]\n", cfi); + printf("\t-r rnti [Default 0x%x]\n",rnti); + printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); + printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-M mbsfn_area_id [Default %d]\n", mbsfn_area_id); + printf("\t-e Set extended prefix [Default Normal]\n"); + printf("\t-v [set srslte_verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "irovfcenmps")) != -1) { + switch(opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'c': + cell.id = atoi(argv[optind]); + break; + case 's': + sf_idx = atoi(argv[optind]); + break; + case 'r': + rnti = strtoul(argv[optind], NULL, 0); + break; + case 'f': + cfi = atoi(argv[optind]); + break; + case 'n': + cell.nof_prb = atoi(argv[optind]); + break; + case 'p': + cell.nof_ports = atoi(argv[optind]); + break; + case 'M': + mbsfn_area_id = atoi(argv[optind]); + break; + case 'o': + dci_format = srslte_dci_format_from_string(argv[optind]); + if (dci_format == SRSLTE_DCI_NOF_FORMATS) { + fprintf(stderr, "Error unsupported format %s\n", argv[optind]); + exit(-1); + } + break; + case 'v': + srslte_verbose++; + break; + case 'e': + cell.cp = SRSLTE_CP_EXT; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!input_file_name) { + usage(argv[0]); + exit(-1); + } +} + +int base_init() { + + if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", input_file_name); + exit(-1); + } + + flen = 2 * (SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb))); + + input_buffer[0] = malloc(flen * sizeof(cf_t)); + if (!input_buffer[0]) { + perror("malloc"); + exit(-1); + } + + if (srslte_ue_dl_init(&ue_dl, cell.nof_prb, 1)) { + fprintf(stderr, "Error initializing UE DL\n"); + return -1; + } + + + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { + fprintf(stderr, "Error initializing UE DL\n"); + return -1; + } + + srslte_ue_dl_set_rnti(&ue_dl, rnti); + + srslte_ue_dl_set_mbsfn_area_id(&ue_dl, mbsfn_area_id); + srslte_ue_dl_set_non_mbsfn_region(&ue_dl, non_mbsfn_region); + + + DEBUG("Memory init OK\n"); + return 0; +} + +void base_free() { + srslte_filesource_free(&fsrc); + srslte_ue_dl_free(&ue_dl); + free(input_buffer[0]); +} + +int main(int argc, char **argv) { + int ret; + + if (argc < 3) { + usage(argv[0]); + exit(-1); + } + parse_args(argc,argv); + + if (base_init()) { + fprintf(stderr, "Error initializing memory\n"); + exit(-1); + } + + uint8_t *data[] = {malloc(100000)}; + + ret = -1; + + srslte_filesource_read(&fsrc, input_buffer[0], flen); + INFO("Reading %d samples sub-frame %d\n", flen, sf_idx); + ret = srslte_ue_dl_decode_mbsfn(&ue_dl, input_buffer, data[0], sf_idx); + if(ret > 0) { + printf("PMCH Decoded OK!\n"); + } else if (ret < 0) { + printf("Error decoding PMCH\n"); + } + + base_free(); + free(data[0]); + if (ret > 0) { + exit(0); + } else { + exit(-1); + } +} diff --git a/lib/src/phy/phch/test/pmch_test.c b/lib/src/phy/phch/test/pmch_test.c new file mode 100644 index 000000000..a187ca2bb --- /dev/null +++ b/lib/src/phy/phch/test/pmch_test.c @@ -0,0 +1,469 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "srslte/srslte.h" + +// Enable to measure execution time +#define DO_OFDM + +#ifdef DO_OFDM +#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_PRB(cell.nof_prb) +#else +#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) +#endif + +srslte_cell_t cell = { + 100, // nof_prb + 1, // nof_ports + 1, // cell_id + SRSLTE_CP_EXT, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1_6 // PHICH resources +}; + +char mimo_type_str [32] = "single"; +srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; +uint32_t cfi = 2; +uint32_t mcs_idx = 2; +uint32_t subframe = 1; +int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1}; +uint16_t rnti = 1234; +uint32_t nof_rx_antennas = 1; +uint32_t pmi = 0; +char *input_file = NULL; +uint32_t mbsfn_area_id = 1; +uint32_t non_mbsfn_region = 2; +void usage(char *prog) { + printf("Usage: %s [fmMcsrtRFpnwav] \n", prog); + printf("\t-f read signal from file [Default generate it with pdsch_encode()]\n"); + printf("\t-m MCS [Default %d]\n", mcs_idx); + printf("\t-M mbsfn area id [Default %d]\n", mbsfn_area_id); + printf("\t-N non mbsfn region [Default %d]\n", non_mbsfn_region); + printf("\t-c cell id [Default %d]\n", cell.id); + printf("\t-s subframe [Default %d]\n", subframe); + printf("\t-r rv_idx [Default %d]\n", rv_idx[0]); + printf("\t-R rnti [Default %d]\n", rnti); + printf("\t-F cfi [Default %d]\n", cfi); + printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-a nof_rx_antennas [Default %d]\n", nof_rx_antennas); + printf("\t-v [set srslte_verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "fmMcsrtRFpnavx")) != -1) { + switch(opt) { + case 'f': + input_file = argv[optind]; + break; + case 'm': + mcs_idx = (uint32_t) atoi(argv[optind]); + break; + case 's': + subframe = atoi(argv[optind]); + break; + case 'r': + rv_idx[0] = (uint32_t) atoi(argv[optind]); + break; + case 'R': + rnti = atoi(argv[optind]); + break; + case 'F': + cfi = atoi(argv[optind]); + break; + case 'x': + strncpy(mimo_type_str, argv[optind], 32); + break; + case 'p': + pmi = (uint32_t) atoi(argv[optind]); + break; + case 'n': + cell.nof_prb = atoi(argv[optind]); + break; + case 'c': + cell.id = atoi(argv[optind]); + break; + case 'a': + nof_rx_antennas = (uint32_t) atoi(argv[optind]); + break; + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +static uint8_t *data_tx[SRSLTE_MAX_CODEWORDS] = {NULL}; +static uint8_t *data_rx[SRSLTE_MAX_CODEWORDS] = {NULL}; +cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; +srslte_softbuffer_rx_t *softbuffers_rx[SRSLTE_MAX_CODEWORDS]; +srslte_ra_dl_grant_t grant; +#ifdef DO_OFDM +cf_t *tx_sf_symbols[SRSLTE_MAX_PORTS]; +cf_t *rx_sf_symbols[SRSLTE_MAX_PORTS]; +#endif /* DO_OFDM */ +cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS]; +cf_t *rx_slot_symbols[SRSLTE_MAX_PORTS]; +srslte_pmch_t pmch_tx, pmch_rx; +srslte_pdsch_cfg_t pmch_cfg; +srslte_ofdm_t ifft_mbsfn, fft_mbsfn; + +int main(int argc, char **argv) { + uint32_t i, j, k; + int ret = -1; + struct timeval t[3]; + srslte_softbuffer_tx_t *softbuffers_tx[SRSLTE_MAX_CODEWORDS]; + int M=1; + + parse_args(argc,argv); + /* Initialise to zeros */ + bzero(&pmch_tx, sizeof(srslte_pmch_t)); + bzero(&pmch_rx, sizeof(srslte_pmch_t)); + bzero(&pmch_cfg, sizeof(srslte_pdsch_cfg_t)); + bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS); + bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); + bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); + + cell.nof_ports = 1; + + srslte_ra_dl_dci_t dci; + bzero(&dci, sizeof(srslte_ra_dl_dci_t)); + dci.type0_alloc.rbg_bitmask = 0xffffffff; + + + /* If transport block 0 is enabled */ + grant.tb_en[0] = true; + grant.tb_en[1] = false; + grant.nof_tb = 1; + grant.mcs[0].idx = mcs_idx; + + grant.nof_prb = cell.nof_prb; + grant.sf_type = SRSLTE_SF_MBSFN; + + 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; + } + } + + + +#ifdef DO_OFDM + + if (srslte_ofdm_tx_init_mbsfn(&ifft_mbsfn, SRSLTE_CP_EXT, cell.nof_prb)) { + fprintf(stderr, "Error creating iFFT object\n"); + exit(-1); + } + if (srslte_ofdm_rx_init_mbsfn(&fft_mbsfn, SRSLTE_CP_EXT, cell.nof_prb)) { + fprintf(stderr, "Error creating iFFT object\n"); + exit(-1); + } + + srslte_ofdm_set_non_mbsfn_region(&ifft_mbsfn, non_mbsfn_region); + srslte_ofdm_set_non_mbsfn_region(&fft_mbsfn, non_mbsfn_region); + srslte_ofdm_set_normalize(&ifft_mbsfn, true); + srslte_ofdm_set_normalize(&fft_mbsfn, true); + + + for (i = 0; i < cell.nof_ports; i++) { + tx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } + + for (i = 0; i < nof_rx_antennas; i++) { + rx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } +#endif /* DO_OFDM */ + + /* Configure PDSCH */ + + if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, subframe)) { + fprintf(stderr, "Error configuring PMCH\n"); + exit(-1); + } + + /* init memory */ + for (i=0;i 0) { cfg.rv = rv_idx; - if (srslte_pusch_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { + if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { fprintf(stderr, "Error encoding TB\n"); exit(-1); } @@ -233,7 +252,7 @@ int main(int argc, char **argv) { } gettimeofday(&t[1], NULL); - int r = srslte_pusch_decode(&pusch, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, &uci_data_rx); + int r = srslte_pusch_decode(&pusch_rx, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, &uci_data_rx); gettimeofday(&t[2], NULL); get_time_interval(t); if (r) { @@ -250,11 +269,19 @@ int main(int argc, char **argv) { if (uci_data_tx.uci_ack_len) { if (uci_data_tx.uci_ack != uci_data_rx.uci_ack) { printf("UCI ACK bit error: %d != %d\n", uci_data_tx.uci_ack, uci_data_rx.uci_ack); + ret = SRSLTE_ERROR; + } + } + if (uci_data_tx.uci_ack_len > 1) { + if (uci_data_tx.uci_ack_2 != uci_data_rx.uci_ack_2) { + printf("UCI ACK 2 bit error: %d != %d\n", uci_data_tx.uci_ack_2, uci_data_rx.uci_ack_2); + ret = SRSLTE_ERROR; } } if (uci_data_tx.uci_ri_len) { if (uci_data_tx.uci_ri != uci_data_rx.uci_ri) { printf("UCI RI bit error: %d != %d\n", uci_data_tx.uci_ri, uci_data_rx.uci_ri); + ret = SRSLTE_ERROR; } } if (uci_data_tx.uci_cqi_len) { @@ -265,7 +292,8 @@ int main(int argc, char **argv) { } quit: - srslte_pusch_free(&pusch); + srslte_pusch_free(&pusch_tx); + srslte_pusch_free(&pusch_rx); srslte_softbuffer_tx_free(&softbuffer_tx); if (sf_symbols) { diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index 3b22eb792..cb09ca08b 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -551,75 +551,150 @@ static uint32_t Q_prime_ri_ack(srslte_pusch_cfg_t *cfg, return Q_prime; } -static void encode_ri_ack(uint8_t data, srslte_uci_bit_type_t q_encoded_bits[6], uint8_t Qm) +static uint32_t encode_ri_ack(uint8_t data[2], uint32_t data_len, srslte_uci_bit_type_t q_encoded_bits[18], uint8_t Qm) { - q_encoded_bits[0] = data?UCI_BIT_1:UCI_BIT_0; - q_encoded_bits[1] = UCI_BIT_REPETITION; - for (uint32_t i=2;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); + rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, &ack_bits[cfg->grant.Qm*i]); + } + + if (acks) { + acks[0] = rx_ack>0; + } + return (int) Qprime; +} +#else + +static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3]) +{ + uint32_t p0 = pos[Qm * 0 + 0].position; + uint32_t p1 = pos[Qm * 0 + 1].position; + uint32_t p2 = pos[Qm * 1 + 0].position; + uint32_t p3 = pos[Qm * 1 + 1].position; + uint32_t p4 = pos[Qm * 2 + 0].position; + uint32_t p5 = pos[Qm * 2 + 1].position; + + int32_t q0 = c_seq[p0] ? q_bits[p0] : -q_bits[p0]; + int32_t q1 = c_seq[p1] ? q_bits[p1] : -q_bits[p1]; + int32_t q2 = c_seq[p2] ? q_bits[p2] : -q_bits[p2]; + int32_t q3 = c_seq[p3] ? q_bits[p3] : -q_bits[p3]; + int32_t q4 = c_seq[p4] ? q_bits[p4] : -q_bits[p4]; + int32_t q5 = c_seq[p5] ? q_bits[p5] : -q_bits[p5]; + + data[0] -= q0 + q3; + data[1] -= q1 + q4; + data[2] -= q2 + q5; +} -/* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 - * Currently only supporting 1-bit HARQ - */ int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, float beta, uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t *data) + uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks) { - int32_t rx_ack = 0; - + int32_t acks_sum[3] = {0, 0, 0}; + if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); return -1; } - uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); + uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta); // Use the same interleaver function to get the HARQ bit position - for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); - rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, ack_bits); + if ((i % 3 == 0) && i > 0) { + decode_ri_ack(q_bits, &c_seq[0], &ack_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, acks_sum); + } } - - if (data) { - *data = rx_ack>0; + + if (acks) { + acks[0] = (uint8_t)(acks_sum[0] > 0); + acks[1] = (uint8_t)(acks_sum[1] > 0); + // TODO: Do something with acks_sum[2] } return (int) Qprime; } +#endif /* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit HARQ */ -int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t data, +int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t acks[2], uint32_t nof_acks, uint32_t O_cqi, float beta, uint32_t H_prime_total, srslte_uci_bit_t *ack_bits) -{ +{ if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); return -1; } - uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); - srslte_uci_bit_type_t q_encoded_bits[6]; + uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta); + srslte_uci_bit_type_t q_encoded_bits[18]; - encode_ri_ack(data, q_encoded_bits, cfg->grant.Qm); + uint32_t nof_encoded_bits = encode_ri_ack(acks, nof_acks, q_encoded_bits, cfg->grant.Qm); for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); - uci_ulsch_interleave_put(q_encoded_bits, cfg->grant.Qm, &ack_bits[cfg->grant.Qm*i]); + uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ack_bits[cfg->grant.Qm*i]); } return (int) Qprime; @@ -632,7 +707,7 @@ int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_se float beta, uint32_t H_prime_total, uint32_t O_cqi, srslte_uci_bit_t *ri_bits, uint8_t *data) { - int32_t rx_ri = 0; + int32_t ri_sum[3] = {0, 0, 0}; if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); @@ -644,11 +719,13 @@ int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_se // Use the same interleaver function to get the HARQ bit position for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); - rx_ri += (int32_t) decode_ri_ack(q_bits, c_seq, ri_bits); + if ((i % 3 == 0) && i > 0) { + //decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum); + } } if (data) { - *data = rx_ri>0; + *data = (uint8_t) ((ri_sum[0] + ri_sum[1] + ri_sum[2]) > 0); } return (int) Qprime; @@ -659,22 +736,24 @@ int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_se * Currently only supporting 1-bit RI */ int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, - uint8_t data, + uint8_t ri, uint32_t O_cqi, float beta, uint32_t H_prime_total, srslte_uci_bit_t *ri_bits) { + // FIXME: It supports RI of 1 bit only + uint8_t data[2] = {ri, 0}; if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); return -1; } uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); - srslte_uci_bit_type_t q_encoded_bits[6]; + srslte_uci_bit_type_t q_encoded_bits[18]; - encode_ri_ack(data, q_encoded_bits, cfg->grant.Qm); + uint32_t nof_encoded_bits = encode_ri_ack(data, 1, q_encoded_bits, cfg->grant.Qm); for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); - uci_ulsch_interleave_put(q_encoded_bits, cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]); + uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]); } return (int) Qprime; diff --git a/lib/src/phy/resampling/interp.c b/lib/src/phy/resampling/interp.c index 553caf4b7..180b3f9fc 100644 --- a/lib/src/phy/resampling/interp.c +++ b/lib/src/phy/resampling/interp.c @@ -27,7 +27,8 @@ #include #include #include -#include +#include +#include #include "srslte/phy/resampling/interp.h" #include "srslte/phy/utils/vector.h" @@ -108,11 +109,23 @@ int srslte_interp_linear_vector_init(srslte_interp_linsrslte_vec_t *q, uint32_t perror("malloc"); return SRSLTE_ERROR; } - q->vector_len = vector_len; + q->vector_len = vector_len; + q->max_vector_len = vector_len; } return ret; } +int srslte_interp_linear_vector_resize(srslte_interp_linsrslte_vec_t *q, uint32_t vector_len) +{ + if (vector_len <= q->max_vector_len) { + q->vector_len = vector_len; + return SRSLTE_SUCCESS; + } else { + fprintf(stderr, "Error resizing interp_linear: vector_len must be lower or equal than initialized\n"); + return SRSLTE_ERROR; + } +} + void srslte_interp_linear_vector_free(srslte_interp_linsrslte_vec_t *q) { if (q->diff_vec) { free(q->diff_vec); @@ -189,7 +202,9 @@ int srslte_interp_linear_init(srslte_interp_lin_t *q, uint32_t vector_len, uint3 } q->vector_len = vector_len; - q->M = M; + q->M = M; + q->max_vector_len = vector_len; + q->max_M = M; } return ret; } @@ -209,6 +224,24 @@ void srslte_interp_linear_free(srslte_interp_lin_t *q) { } + +int srslte_interp_linear_resize(srslte_interp_lin_t *q, uint32_t vector_len, uint32_t M) +{ + if (vector_len <= q->max_vector_len && M <= q->max_M) { + + for (int i=0;iramp[i] = (float) i; + } + + q->vector_len = vector_len; + q->M = M; + return SRSLTE_SUCCESS; + } else { + fprintf(stderr, "Error resizing interp_linear: vector_len and M must be lower or equal than initialized\n"); + return SRSLTE_ERROR; + } +} + void srslte_interp_linear_offset(srslte_interp_lin_t *q, cf_t *input, cf_t *output, uint32_t off_st, uint32_t off_end) { diff --git a/lib/src/phy/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h index 00f157b6b..d41adbeed 100644 --- a/lib/src/phy/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -177,7 +177,7 @@ static rf_dev_t dev_soapy = { rf_soapy_recv_with_time, rf_soapy_recv_with_time_multi, rf_soapy_send_timed, - .srslte_rf_send_timed_multi = /* FIXME: Implement srslte_rf_send_timed_multi for Soapy SDR */ NULL, + .srslte_rf_send_timed_multi = rf_soapy_send_timed_multi, rf_soapy_set_tx_cal, rf_soapy_set_rx_cal }; diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index 31649af69..fef533ffc 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -88,12 +88,12 @@ void rf_soapy_register_error_handler(void *notused, srslte_rf_error_handler_t ne } - char* rf_soapy_devname(void* h) { return "soapy"; } + bool rf_soapy_rx_wait_lo_locked(void *h) { printf("TODO: implement rf_soapy_rx_wait_lo_locked()\n"); @@ -155,7 +155,6 @@ int rf_soapy_stop_tx_stream(void *h) if(SoapySDRDevice_deactivateStream(handler->device, handler->txStream, 0, 0) != 0) return SRSLTE_ERROR; - handler->tx_stream_active = false; return SRSLTE_SUCCESS; } @@ -175,7 +174,7 @@ void rf_soapy_flush_buffer(void *h) bool rf_soapy_has_rssi(void *h) { - printf("TODO: implement rf_soapy_has_rssi()\n"); + // TODO: implement rf_soapy_has_rssi() return false; } @@ -199,9 +198,8 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) } for (size_t i = 0; i < length; i++) { - printf("Soapy Has Found device #%d: ", (int)i); - for (size_t j = 0; j < soapy_args[i].size; j++) - { + printf("Soapy has Found device #%d: ", (int)i); + for (size_t j = 0; j < soapy_args[i].size; j++) { printf("%s=%s, ", soapy_args[i].keys[j], soapy_args[i].vals[j]); } printf("\n"); @@ -221,7 +219,6 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) handler->tx_stream_active = false; handler->rx_stream_active = false; - if(SoapySDRDevice_getNumChannels(handler->device,SOAPY_SDR_RX) > 0){ printf("setting up RX stream\n"); if(SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) { @@ -251,12 +248,12 @@ int rf_soapy_open(char *args, void **h) int rf_soapy_close(void *h) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; - if (handler->txStream) { + if (handler->tx_stream_active) { rf_soapy_stop_tx_stream(handler); SoapySDRDevice_closeStream(handler->device, handler->txStream); } - if (handler->rxStream) { + if (handler->rx_stream_active) { rf_soapy_stop_rx_stream(handler); SoapySDRDevice_closeStream(handler->device, handler->rxStream); } @@ -285,9 +282,15 @@ double rf_soapy_set_rx_srate(void *h, double rate) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0) { - printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError()); + printf("setSampleRate Rx fail: %s\n", SoapySDRDevice_lastError()); return SRSLTE_ERROR; } + + if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_RX, 0, rate) != 0) { + printf("setBandwidth Rx failed: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0); } @@ -295,9 +298,15 @@ double rf_soapy_set_tx_srate(void *h, double rate) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0) { - printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError()); + printf("setSampleRate Tx fail: %s\n", SoapySDRDevice_lastError()); return SRSLTE_ERROR; } + + if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_TX, 0, rate) != 0) { + printf("setBandwidth Tx failed: %s\n", SoapySDRDevice_lastError()); + return SRSLTE_ERROR; + } + return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0); } @@ -348,7 +357,15 @@ double rf_soapy_set_rx_freq(void *h, double freq) printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); return SRSLTE_ERROR; } - + + // Todo: expose antenna setting + if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_RX, 0, "LNAH") != 0) { + fprintf(stderr, "Failed to set Rx antenna.\n"); + } + + char *ant = SoapySDRDevice_getAntenna(handler->device, SOAPY_SDR_RX, 0); + printf("Rx antenna set to %s\n", ant); + return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0); } @@ -360,14 +377,25 @@ double rf_soapy_set_tx_freq(void *h, double freq) printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); return SRSLTE_ERROR; } + + // Todo: expose antenna name in arguments + if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_TX, 0, "BAND1") != 0) { + fprintf(stderr, "Failed to set Tx antenna.\n"); + } + + char *ant = SoapySDRDevice_getAntenna(handler->device, SOAPY_SDR_TX, 0); + printf("Tx antenna set to %s\n", ant); + return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0); } -void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs) { - +void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs) +{ + printf("Todo: implement rf_soapy_get_time()\n"); } + //TODO: add multi-channel support int rf_soapy_recv_with_time_multi(void *h, void **data, @@ -395,7 +423,7 @@ int rf_soapy_recv_with_time_multi(void *h, cf_t *data_c = (cf_t*) data[i]; buffs_ptr[i] = &data_c[n]; } - ret = SoapySDRDevice_readStream(handler->device, handler->rxStream, buffs_ptr , rx_samples, &flags, &timeNs, 1000000); + ret = SoapySDRDevice_readStream(handler->device, handler->rxStream, buffs_ptr, rx_samples, &flags, &timeNs, 10000); if(ret < 0) { // continue when getting overflows if (ret == SOAPY_SDR_OVERFLOW) { @@ -407,17 +435,23 @@ int rf_soapy_recv_with_time_multi(void *h, } } + // update rx time + if (secs != NULL && frac_secs != NULL) { + *secs = timeNs / 1e9; + *frac_secs = (timeNs % 1000000000)/1e9; + //printf("rx_time: secs=%d, frac_secs=%lf timeNs=%lld\n", *secs, *frac_secs, timeNs); + } + n += ret; trials++; } while (n < nsamples && trials < 100); - //*secs = timeNs / 1000000000; - //*frac_secs = (timeNs % 1000000000)/1000000000; - // printf("ret=%d, flags=%d, timeNs=%lld\n", ret, flags, timeNs); + return n; } + int rf_soapy_recv_with_time(void *h, void *data, uint32_t nsamples, @@ -430,49 +464,92 @@ int rf_soapy_recv_with_time(void *h, int rf_soapy_send_timed(void *h, - void *data, - int nsamples, - time_t secs, - double frac_secs, - bool has_time_spec, - bool blocking, - bool is_start_of_burst, - bool is_end_of_burst) + void *data, + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst) +{ + void *_data[SRSLTE_MAX_PORTS]= {data, zero_mem, zero_mem, zero_mem}; + return rf_soapy_send_timed_multi(h, _data, nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst, is_end_of_burst); +} + + +// Todo: Check correct handling of flags, use RF metrics API, fix timed transmissions +int rf_soapy_send_timed_multi(void *h, + void *data[SRSLTE_MAX_PORTS], + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst) { - - int flags; - long long timeNs; - int trials = 0; - int ret = 0; - rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + rf_soapy_handler_t *handler = (rf_soapy_handler_t *) h; + int flags = 0; + const long timeoutUs = 2000; // arbitrarily chosen + long long timeNs = 0; + int trials = 0; + int ret = 0; + int n = 0; + + + if (!handler->tx_stream_active) { + rf_soapy_start_tx_stream(h); + } + + if (is_start_of_burst && is_end_of_burst) { + flags |= SOAPY_SDR_ONE_PACKET; + } + + if (is_end_of_burst) { + flags |= SOAPY_SDR_END_BURST; + } + + if (has_time_spec) { + flags |= SOAPY_SDR_HAS_TIME; timeNs = secs * 1000000000; timeNs = timeNs + (frac_secs * 1000000000); - int n = 0; + //printf("time_spec: secs=%d, frac_secs=%lf timeNs=%lld\n", secs, frac_secs, timeNs); + } - if(!handler->tx_stream_active){ - rf_soapy_start_tx_stream(h); + do { + size_t tx_samples = nsamples; + if (tx_samples > nsamples - n) { + tx_samples = nsamples - n; } - - - cf_t *data_c = (cf_t*) data; - do{ - size_t tx_samples = nsamples; - if (tx_samples > nsamples - n) { - tx_samples = nsamples - n; - } - void *buff = (void*) &data_c[n]; - const void *buffs_ptr[1] = {buff}; - ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, buffs_ptr, tx_samples, &flags, timeNs, 10000); - if(ret < 0) - return SRSLTE_ERROR; - - n += ret; - trials++; - }while (n < nsamples && trials < 100); - - if(ret != nsamples) - return SRSLTE_ERROR; - - return ret; + ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, (const void *)data, tx_samples, &flags, timeNs, timeoutUs); + if (ret == SOAPY_SDR_TIMEOUT) { + printf("L"); + continue; + } + if (ret == SOAPY_SDR_OVERFLOW) { + printf("O"); + continue; + } + if (ret == SOAPY_SDR_UNDERFLOW) { + printf("U"); + continue; + } + if (ret < 0) { + fprintf(stderr, "Error during writeStream\n"); + exit(-1); + return SRSLTE_ERROR; + } + + n += ret; + trials++; + } while (n < nsamples && trials < 100); + + if (n != nsamples) { + fprintf(stderr, "Couldn't write all samples.\n"); + return SRSLTE_ERROR; + } + + return ret; } diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index 23b59a8b3..19de4536c 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -106,7 +106,7 @@ SRSLTE_API void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs); -SRSLTE_API int rf_soapy_send_timed(void *h, +SRSLTE_API int rf_soapy_send_timed(void *h, void *data, int nsamples, time_t secs, @@ -116,3 +116,12 @@ SRSLTE_API int rf_soapy_send_timed(void *h, bool is_start_of_burst, bool is_end_of_burst); +int rf_soapy_send_timed_multi(void *h, + void *data[4], + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst); diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 573400f4f..29aec5b44 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -76,9 +76,10 @@ static void log_overflow(rf_uhd_handler_t *h) { } } -static void log_late(rf_uhd_handler_t *h) { +static void log_late(rf_uhd_handler_t *h, bool is_rx) { if (h->uhd_error_handler) { - srslte_rf_error_t error; + srslte_rf_error_t error; + error.opt = is_rx?1:0; bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_LATE; h->uhd_error_handler(error); @@ -109,7 +110,7 @@ static void* async_thread(void *h) { event_code == UHD_ASYNC_METADATA_EVENT_CODE_UNDERFLOW_IN_PACKET) { log_underflow(handler); } else if (event_code == UHD_ASYNC_METADATA_EVENT_CODE_TIME_ERROR) { - log_late(handler); + log_late(handler, false); } } } else { @@ -117,6 +118,7 @@ static void* async_thread(void *h) { return NULL; } } + uhd_async_metadata_free(&md); return NULL; } @@ -226,7 +228,7 @@ int rf_uhd_start_rx_stream(void *h) .stream_now = false }; uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs); - stream_cmd.time_spec_frac_secs += 0.5; + stream_cmd.time_spec_frac_secs += 0.1; if (stream_cmd.time_spec_frac_secs > 1) { stream_cmd.time_spec_frac_secs -= 1; stream_cmd.time_spec_full_secs += 1; @@ -289,6 +291,13 @@ int rf_uhd_open(char *args, void **h) return rf_uhd_open_multi(args, h, 1); } +static void remove_substring(char *s,const char *toremove) +{ + while((s=strstr(s,toremove))) { + memmove(s,s+strlen(toremove),1+strlen(s+strlen(toremove))); + } +} + int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) { if (h) { @@ -323,7 +332,31 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) handler->uhd_error_handler = NULL; bzero(zero_mem, sizeof(cf_t)*64*1024); - + + // Check external clock argument + enum {DEFAULT, EXTERNAL, GPSDO} clock_src; + if (strstr(args, "clock=external")) { + remove_substring(args, "clock=external"); + clock_src = EXTERNAL; + } else if (strstr(args, "clock=gpsdo")) { + printf("Using GPSDO clock\n"); + remove_substring(args, "clock=gpsdo"); + clock_src = GPSDO; + } else { + clock_src = DEFAULT; + } + + // Set over the wire format + char *otw_format = "sc16"; + if (strstr(args, "otw_format=sc12")) { + otw_format = "sc12"; + } else if (strstr(args, "otw_format=sc16")) { + /* Do nothing */ + } else if (strstr(args, "otw_format=")) { + fprintf(stderr, "Wrong over the wire format. Valid formats: sc12, sc16\n"); + return -1; + } + /* If device type or name not given in args, choose a B200 */ if (args[0]=='\0') { if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) { @@ -378,15 +411,13 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) } // Set external clock reference - if (strstr(args, "clock=external")) { + if (clock_src == EXTERNAL) { uhd_usrp_set_clock_source(handler->usrp, "external", 0); - } else if (strstr(args, "clock=gpsdo")) { - printf("Using GPSDO clock\n"); - uhd_usrp_set_clock_source(handler->usrp, "gpsdo", 0); + } else if (clock_src == GPSDO) { + uhd_usrp_set_clock_source(handler->usrp, "gpsdo", 0); } - - handler->has_rssi = get_has_rssi(handler); + handler->has_rssi = get_has_rssi(handler); if (handler->has_rssi) { uhd_sensor_value_make_from_realnum(&handler->rssi_value, "rssi", 0, "dBm", "%f"); } @@ -394,7 +425,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) size_t channel[4] = {0, 1, 2, 3}; uhd_stream_args_t stream_args = { .cpu_format = "fc32", - .otw_format = "sc16", + .otw_format = otw_format, .args = "", .channel_list = channel, .n_channels = nof_channels, @@ -404,9 +435,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) handler->nof_tx_channels = nof_channels; /* Set default rate to avoid decimation warnings */ - uhd_usrp_set_rx_rate(handler->usrp, 1.92e6, 0); - uhd_usrp_set_tx_rate(handler->usrp, 1.92e6, 0); - + for (int i=0;iusrp, 1.92e6, i); + uhd_usrp_set_tx_rate(handler->usrp, 1.92e6, i); + } + /* Initialize rx and tx stremers */ uhd_rx_streamer_make(&handler->rx_stream); error = uhd_usrp_get_rx_stream(handler->usrp, &stream_args, handler->rx_stream); @@ -457,14 +490,17 @@ int rf_uhd_close(void *h) uhd_rx_metadata_free(&handler->rx_md_first); uhd_rx_metadata_free(&handler->rx_md); uhd_meta_range_free(&handler->rx_gain_range); - uhd_tx_streamer_free(&handler->tx_stream); - uhd_rx_streamer_free(&handler->rx_stream); if (handler->has_rssi) { uhd_sensor_value_free(&handler->rssi_value); } handler->async_thread_running = false; - pthread_join(handler->async_thread, NULL); + pthread_join(handler->async_thread, NULL); + + uhd_tx_streamer_free(&handler->tx_stream); + uhd_rx_streamer_free(&handler->rx_stream); uhd_usrp_free(&handler->usrp); + + free(handler); /** Something else to close the USRP?? */ return 0; @@ -488,8 +524,7 @@ double rf_uhd_set_rx_srate(void *h, double freq) for (int i=0;inof_rx_channels;i++) { uhd_usrp_set_rx_rate(handler->usrp, freq, i); } - uhd_usrp_get_rx_rate(handler->usrp, 0, &freq); - return freq; + return freq; } double rf_uhd_set_tx_srate(void *h, double freq) @@ -498,7 +533,6 @@ double rf_uhd_set_tx_srate(void *h, double freq) for (int i=0;inof_tx_channels;i++) { uhd_usrp_set_tx_rate(handler->usrp, freq, i); } - uhd_usrp_get_tx_rate(handler->usrp, 0, &freq); handler->tx_rate = freq; return freq; } @@ -509,7 +543,6 @@ double rf_uhd_set_rx_gain(void *h, double gain) for (int i=0;inof_rx_channels;i++) { uhd_usrp_set_rx_gain(handler->usrp, gain, i, ""); } - uhd_usrp_get_rx_gain(handler->usrp, 0, "", &gain); return gain; } @@ -519,7 +552,6 @@ double rf_uhd_set_tx_gain(void *h, double gain) for (int i=0;inof_tx_channels;i++) { uhd_usrp_set_tx_gain(handler->usrp, gain, i, ""); } - uhd_usrp_get_tx_gain(handler->usrp, 0, "", &gain); return gain; } @@ -551,7 +583,6 @@ double rf_uhd_set_rx_freq(void *h, double freq) for (int i=0;inof_rx_channels;i++) { uhd_usrp_set_rx_freq(handler->usrp, &tune_request, i, &tune_result); } - uhd_usrp_get_rx_freq(handler->usrp, 0, &freq); return freq; } @@ -567,7 +598,6 @@ double rf_uhd_set_tx_freq(void *h, double freq) for (int i=0;inof_tx_channels;i++) { uhd_usrp_set_tx_freq(handler->usrp, &tune_request, i, &tune_result); } - uhd_usrp_get_tx_freq(handler->usrp, 0, &freq); return freq; } @@ -619,17 +649,22 @@ int rf_uhd_recv_with_time_multi(void *h, fprintf(stderr, "Error receiving from UHD: %d\n", error); return -1; } - md = &handler->rx_md; + + uhd_rx_metadata_error_code_t error_code = 0; + uhd_rx_metadata_error_code(*md, &error_code); + + md = &handler->rx_md; n += rxd_samples; trials++; - - uhd_rx_metadata_error_code_t error_code; - uhd_rx_metadata_error_code(*md, &error_code); + if (error_code == UHD_RX_METADATA_ERROR_CODE_OVERFLOW) { log_overflow(handler); } else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) { - log_late(handler); - } else if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE) { + log_late(handler, true); + } else if (error_code == UHD_RX_METADATA_ERROR_CODE_TIMEOUT) { + fprintf(stderr, "Error timed out while receiving samples from UHD.\n"); + return -1; + } else if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE ) { fprintf(stderr, "Error code 0x%x was returned during streaming. Aborting.\n", error_code); } @@ -677,11 +712,11 @@ int rf_uhd_send_timed_multi(void *h, } size_t txd_samples; - if (has_time_spec) { - uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs); - } - int trials = 0; + int trials = 0; if (blocking) { + if (has_time_spec) { + uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs); + } int n = 0; cf_t *data_c[4]; for (int i = 0; i < 4; i++) { @@ -689,8 +724,8 @@ int rf_uhd_send_timed_multi(void *h, } do { size_t tx_samples = handler->tx_nof_samples; - - // First packet is start of burst if so defined, others are never + + // First packet is start of burst if so defined, others are never if (n == 0) { uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst); } else { @@ -727,9 +762,15 @@ int rf_uhd_send_timed_multi(void *h, for (int i = 0; i < 4; i++) { buffs_ptr[i] = data[i]; } + uhd_tx_metadata_set_has_time_spec(&handler->tx_md, is_start_of_burst); uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst); uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); - return uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples); + uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 3.0, &txd_samples); + if (error) { + fprintf(stderr, "Error sending to UHD: %d\n", error); + return -1; + } + return txd_samples; } } diff --git a/lib/src/phy/rf/rf_utils.c b/lib/src/phy/rf/rf_utils.c index f4a2c6790..ce288b5c5 100644 --- a/lib/src/phy/rf/rf_utils.c +++ b/lib/src/phy/rf/rf_utils.c @@ -103,11 +103,16 @@ int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t * srslte_ue_mib_sync_t ue_mib; uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - if (srslte_ue_mib_sync_init_multi(&ue_mib, cell->id, cell->cp, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*) rf)) { + if (srslte_ue_mib_sync_init_multi(&ue_mib, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*) rf)) { fprintf(stderr, "Error initiating srslte_ue_mib_sync\n"); goto clean_exit; } - + + if (srslte_ue_mib_sync_set_cell(&ue_mib, cell->id, cell->cp)) { + fprintf(stderr, "Error initiating srslte_ue_mib_sync\n"); + goto clean_exit; + } + if (config->init_agc > 0) { srslte_ue_sync_start_agc(&ue_mib.ue_sync, srslte_rf_set_rx_gain_th_wrapper, config->init_agc); } @@ -168,7 +173,6 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, fprintf(stderr, "Error initiating UE cell detect\n"); return SRSLTE_ERROR; } - if (config->nof_valid_pss_frames) { srslte_ue_cellsearch_set_nof_valid_frames(&cs, config->nof_valid_pss_frames); } diff --git a/lib/src/phy/rf/uhd_c_api.cpp b/lib/src/phy/rf/uhd_c_api.cpp index da348c17b..d98c3c92a 100644 --- a/lib/src/phy/rf/uhd_c_api.cpp +++ b/lib/src/phy/rf/uhd_c_api.cpp @@ -38,6 +38,12 @@ void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burs (*md)->tx_metadata_cpp.start_of_burst = is_start_of_burst; } +void uhd_tx_metadata_set_has_time_spec(uhd_tx_metadata_handle *md, bool has_time_spec) +{ + (*md)->tx_metadata_cpp.has_time_spec = has_time_spec; +} + + void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst) { (*md)->tx_metadata_cpp.end_of_burst = is_end_of_burst; diff --git a/lib/src/phy/rf/uhd_c_api.h b/lib/src/phy/rf/uhd_c_api.h index 15bb5f33c..8f6cb2743 100644 --- a/lib/src/phy/rf/uhd_c_api.h +++ b/lib/src/phy/rf/uhd_c_api.h @@ -32,5 +32,6 @@ SRSLTE_API void rf_uhd_register_msg_handler_c(void (*new_handler)(const char*)); SRSLTE_API void uhd_tx_metadata_set_time_spec(uhd_tx_metadata_handle *md, time_t secs, double frac_secs); SRSLTE_API void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burst); +SRSLTE_API void uhd_tx_metadata_set_has_time_spec(uhd_tx_metadata_handle *md, bool has_time_spec); SRSLTE_API void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst); SRSLTE_API void uhd_tx_metadata_add_time_spec(uhd_tx_metadata_handle *md, double frac_secs); diff --git a/lib/src/phy/scrambling/scrambling.c b/lib/src/phy/scrambling/scrambling.c index bb5637814..42f16d1e8 100644 --- a/lib/src/phy/scrambling/scrambling.c +++ b/lib/src/phy/scrambling/scrambling.c @@ -33,29 +33,29 @@ #include "srslte/phy/scrambling/scrambling.h" void srslte_scrambling_f(srslte_sequence_t *s, float *data) { - srslte_scrambling_f_offset(s, data, 0, s->len); + srslte_scrambling_f_offset(s, data, 0, s->cur_len); } void srslte_scrambling_f_offset(srslte_sequence_t *s, float *data, int offset, int len) { - assert (len + offset <= s->len); + assert (len + offset <= s->cur_len); srslte_vec_prod_fff(data, &s->c_float[offset], data, len); } void srslte_scrambling_s(srslte_sequence_t *s, short *data) { - srslte_scrambling_s_offset(s, data, 0, s->len); + srslte_scrambling_s_offset(s, data, 0, s->cur_len); } void srslte_scrambling_s_offset(srslte_sequence_t *s, short *data, int offset, int len) { - assert (len + offset <= s->len); + assert (len + offset <= s->cur_len); srslte_vec_prod_sss(data, &s->c_short[offset], data, len); } void srslte_scrambling_c(srslte_sequence_t *s, cf_t *data) { - srslte_scrambling_c_offset(s, data, 0, s->len); + srslte_scrambling_c_offset(s, data, 0, s->cur_len); } void srslte_scrambling_c_offset(srslte_sequence_t *s, cf_t *data, int offset, int len) { - assert (len + offset <= s->len); + assert (len + offset <= s->cur_len); srslte_vec_prod_cfc(data, &s->c_float[offset], data, len); } @@ -81,7 +81,7 @@ void scrambling_b_word(uint8_t *c, uint8_t *data, int len) { void srslte_scrambling_b(srslte_sequence_t *s, uint8_t *data) { - scrambling_b_word(s->c, data, s->len); + scrambling_b_word(s->c, data, s->cur_len); } void srslte_scrambling_b_offset(srslte_sequence_t *s, uint8_t *data, int offset, int len) { diff --git a/lib/src/phy/scrambling/test/scrambling_test.c b/lib/src/phy/scrambling/test/scrambling_test.c index 9ff47dc85..40722f09b 100644 --- a/lib/src/phy/scrambling/test/scrambling_test.c +++ b/lib/src/phy/scrambling/test/scrambling_test.c @@ -84,8 +84,10 @@ void parse_args(int argc, char **argv) { int init_sequence(srslte_sequence_t *seq, char *name) { if (!strcmp(name, "PBCH")) { + bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_pbch(seq, cp, cell_id); } else if (!strcmp(name, "PDSCH")) { + bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_pdsch(seq, 1234, 0, 0, cell_id, nof_bits); } else { fprintf(stderr, "Unsupported sequence name %s\n", name); @@ -109,18 +111,18 @@ int main(int argc, char **argv) { } if (!do_floats) { - input_b = malloc(sizeof(uint8_t) * seq.len); + input_b = malloc(sizeof(uint8_t) * seq.cur_len); if (!input_b) { perror("malloc"); exit(-1); } - scrambled_b = malloc(sizeof(uint8_t) * seq.len); + scrambled_b = malloc(sizeof(uint8_t) * seq.cur_len); if (!scrambled_b) { perror("malloc"); exit(-1); } - for (i=0;i #include #include +#include #include "srslte/phy/utils/cexptab.h" #include "srslte/phy/sync/cfo.h" @@ -47,6 +48,7 @@ int srslte_cfo_init(srslte_cfo_t *h, uint32_t nsamples) { h->tol = SRSLTE_CFO_TOLERANCE; h->last_freq = 0; h->nsamples = nsamples; + h->max_samples = nsamples; srslte_cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); ret = SRSLTE_SUCCESS; @@ -69,15 +71,15 @@ void srslte_cfo_set_tol(srslte_cfo_t *h, float tol) { h->tol = tol; } -int srslte_cfo_realloc(srslte_cfo_t *h, uint32_t samples) { - h->cur_cexp = realloc(h->cur_cexp, sizeof(cf_t) * samples); - if (!h->cur_cexp) { - perror("realloc"); +int srslte_cfo_resize(srslte_cfo_t *h, uint32_t samples) { + if (samples <= h->max_samples) { + srslte_cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, samples); + h->nsamples = samples; + } else { + fprintf(stderr, "Error in cfo_resize(): nof_samples must be lower than initialized\n"); return SRSLTE_ERROR; } - srslte_cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, samples); - h->nsamples = samples; - + return SRSLTE_SUCCESS; } diff --git a/lib/src/phy/sync/cp.c b/lib/src/phy/sync/cp.c index c745aca85..a282f6dfd 100644 --- a/lib/src/phy/sync/cp.c +++ b/lib/src/phy/sync/cp.c @@ -25,6 +25,7 @@ */ #include +#include #include "srslte/phy/sync/cp.h" #include "srslte/phy/utils/vector.h" @@ -33,7 +34,8 @@ int srslte_cp_synch_init(srslte_cp_synch_t *q, uint32_t symbol_sz) { q->symbol_sz = symbol_sz; - + q->max_symbol_sz = symbol_sz; + q->corr = srslte_vec_malloc(sizeof(cf_t) * q->symbol_sz); if (!q->corr) { perror("malloc"); @@ -49,6 +51,18 @@ void srslte_cp_synch_free(srslte_cp_synch_t *q) } } +int srslte_cp_synch_resize(srslte_cp_synch_t *q, uint32_t symbol_sz) +{ + if (symbol_sz > q->max_symbol_sz) { + fprintf(stderr, "Error in cp_synch_resize(): symbol_sz must be lower than initialized\n"); + return SRSLTE_ERROR; + } + q->symbol_sz = symbol_sz; + + return SRSLTE_SUCCESS; +} + + uint32_t srslte_cp_synch(srslte_cp_synch_t *q, cf_t *input, uint32_t max_offset, uint32_t nof_symbols, uint32_t cp_len) { if (max_offset > q->symbol_sz) { diff --git a/lib/src/phy/sync/pss.c b/lib/src/phy/sync/pss.c index 2ad166bc0..f7b35071d 100644 --- a/lib/src/phy/sync/pss.c +++ b/lib/src/phy/sync/pss.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "srslte/phy/sync/pss.h" #include "srslte/phy/dft/dft.h" @@ -93,9 +94,11 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, * It correlates a signal of frame_size samples with the PSS sequence in the frequency * domain. The PSS sequence is transformed using fft_size samples. */ -int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset, int decimate) { +int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, + uint32_t max_frame_size, uint32_t max_fft_size, + int offset, int decimate) +{ - int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL) { @@ -107,18 +110,20 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, uint32_t frame q->N_id_2 = 10; q->ema_alpha = 0.2; - + + q->max_fft_size = max_fft_size; + q->max_frame_size = max_frame_size; + q->decimate = decimate; - fft_size = fft_size/q->decimate; - frame_size = frame_size/q->decimate; + uint32_t fft_size = max_fft_size/q->decimate; + uint32_t frame_size = max_frame_size/q->decimate; q->fft_size = fft_size; q->frame_size = frame_size; buffer_size = fft_size + frame_size + 1; - - if(q->decimate > 1) - { + + if(q->decimate > 1) { int filter_order = 3; srslte_filt_decim_cc_init(&q->filter,q->decimate,filter_order); q->filter.filter_output = srslte_vec_malloc((buffer_size) * sizeof(cf_t)); @@ -175,21 +180,19 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, uint32_t frame goto clean_and_exit; } bzero(&q->pss_signal_time[N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); - } #ifdef CONVOLUTION_FFT - for(N_id_2 = 0; N_id_2<3; N_id_2++) + for(N_id_2=0; N_id_2<3; N_id_2++) q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { fprintf(stderr, "Error initiating convolution FFT\n"); goto clean_and_exit; } - for(int i =0; i< 3; i++) - { - srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); + for(int i=0; i<3; i++) { + srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); } #endif @@ -208,6 +211,79 @@ clean_and_exit: } +/* Initializes the PSS synchronization object. + * + * It correlates a signal of frame_size samples with the PSS sequence in the frequency + * domain. The PSS sequence is transformed using fft_size samples. + */ +int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { + + + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL) { + + ret = SRSLTE_ERROR; + + if (fft_size > q->max_fft_size || frame_size > q->max_frame_size) { + fprintf(stderr, "Error in pss_synch_config(): fft_size and frame_size must be lower than initialized\n"); + return SRSLTE_ERROR; + } + + uint32_t N_id_2; + uint32_t buffer_size; + + q->N_id_2 = 10; + q->ema_alpha = 0.2; + + fft_size = fft_size/q->decimate; + frame_size = frame_size/q->decimate; + + q->fft_size = fft_size; + q->frame_size = frame_size; + + buffer_size = fft_size + frame_size + 1; + + if (srslte_dft_replan(&q->dftp_input, fft_size)) { + fprintf(stderr, "Error creating DFT plan \n"); + return SRSLTE_ERROR; + } + + bzero(&q->tmp_input[q->frame_size], q->fft_size * sizeof(cf_t)); + bzero(q->conv_output, sizeof(cf_t) * buffer_size); + bzero(q->conv_output_avg, sizeof(float) * buffer_size); + +#ifdef SRSLTE_PSS_ACCUMULATE_ABS + bzero(q->conv_output_abs, sizeof(float) * buffer_size); +#endif + + // Generate PSS sequences for this FFT size + for (N_id_2=0;N_id_2<3;N_id_2++) { + if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { + fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); + return SRSLTE_ERROR; + } + bzero(&q->pss_signal_time[N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); + } +#ifdef CONVOLUTION_FFT + + if (srslte_conv_fft_cc_replan(&q->conv_fft, frame_size, fft_size)) { + fprintf(stderr, "Error initiating convolution FFT\n"); + return SRSLTE_ERROR; + } + for(int i =0; i< 3; i++) { + srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); + } + +#endif + + srslte_pss_synch_reset(q); + + ret = SRSLTE_SUCCESS; + } + return ret; + +} + void srslte_pss_synch_free(srslte_pss_synch_t *q) { uint32_t i; diff --git a/lib/src/phy/sync/sss.c b/lib/src/phy/sync/sss.c index 3586e04de..4ed7b1d6c 100644 --- a/lib/src/phy/sync/sss.c +++ b/lib/src/phy/sync/sss.c @@ -58,7 +58,8 @@ int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { srslte_dft_plan_set_dc(&q->dftp_input, true); q->fft_size = fft_size; - + q->max_fft_size = fft_size; + generate_N_id_1_table(q->N_id_1_table); for (N_id_2=0;N_id_2<3;N_id_2++) { @@ -71,19 +72,18 @@ int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { return SRSLTE_ERROR_INVALID_INPUTS; } -int srslte_sss_synch_realloc(srslte_sss_synch_t *q, uint32_t fft_size) { +int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { if (q != NULL && fft_size <= 2048) { - srslte_dft_plan_free(&q->dftp_input); - if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) { + if (fft_size > q->max_fft_size) { + fprintf(stderr, "Error in sss_synch_resize(): fft_size must be lower than initialized\n"); + return SRSLTE_ERROR; + } + if (srslte_dft_replan(&q->dftp_input, fft_size)) { srslte_sss_synch_free(q); return SRSLTE_ERROR; } - srslte_dft_plan_set_mirror(&q->dftp_input, true); - srslte_dft_plan_set_norm(&q->dftp_input, true); - srslte_dft_plan_set_dc(&q->dftp_input, true); - q->fft_size = fft_size; return SRSLTE_SUCCESS; } diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index fb77e1b25..ee2ba76d1 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "srslte/phy/utils/debug.h" #include "srslte/phy/common/phy_common.h" @@ -39,6 +41,8 @@ #define CFO_EMA_ALPHA 0.1 #define CP_EMA_ALPHA 0.1 +#define DEFAULT_CFO_TOL 50.0 // Hz + static bool fft_size_isvalid(uint32_t fft_size) { if (fft_size >= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) { return true; @@ -77,7 +81,10 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o q->frame_size = frame_size; q->max_offset = max_offset; q->sss_alg = SSS_FULL; - + q->max_frame_size = frame_size; + q->mean_cfo_isunset = true; + q->mean_cfo2_isunset = true; + q->enable_cfo_corr = true; if (srslte_cfo_init(&q->cfocorr, q->frame_size)) { fprintf(stderr, "Error initiating CFO\n"); @@ -89,11 +96,8 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o goto clean_exit; } - // Set a CFO tolerance of approx 50 Hz - srslte_cfo_set_tol(&q->cfocorr, 50.0/(15000.0*q->fft_size)); - - // Set a CFO tolerance of approx 50 Hz - srslte_cfo_set_tol(&q->cfocorr2, 50.0/(15000.0*q->fft_size)); + // Set default CFO tolerance + srslte_sync_set_cfo_tol(q, DEFAULT_CFO_TOL); for (int i=0;i<2;i++) { q->cfo_i_corr[i] = srslte_vec_malloc(sizeof(cf_t)*q->frame_size); @@ -111,11 +115,11 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o srslte_sync_set_cp(q, SRSLTE_CP_NORM); q->decimate = decimate; - if(!decimate) + if(!decimate) { decimate = 1; - - - if (srslte_pss_synch_init_fft_offset_decim(&q->pss, max_offset, fft_size,0,decimate)) { + } + + if (srslte_pss_synch_init_fft_offset_decim(&q->pss, max_offset, fft_size, 0, decimate)) { fprintf(stderr, "Error initializing PSS object\n"); goto clean_exit; } @@ -162,6 +166,80 @@ void srslte_sync_free(srslte_sync_t *q) { } } +int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size) { + + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + frame_size <= 307200 && + fft_size_isvalid(fft_size)) + { + ret = SRSLTE_ERROR; + + if (frame_size > q->max_frame_size) { + fprintf(stderr, "Error in sync_resize(): frame_size must be lower than initialized\n"); + return SRSLTE_ERROR; + } + q->detect_cp = true; + q->sss_en = true; + q->mean_cfo = 0; + q->mean_cfo2 = 0; + q->N_id_2 = 1000; + q->N_id_1 = 1000; + q->cfo_i = 0; + q->find_cfo_i = false; + q->find_cfo_i_initiated = false; + q->cfo_ema_alpha = CFO_EMA_ALPHA; + q->fft_size = fft_size; + q->frame_size = frame_size; + q->max_offset = max_offset; + q->sss_alg = SSS_FULL; + + q->enable_cfo_corr = true; + + if (srslte_pss_synch_resize(&q->pss, max_offset, fft_size, 0)) { + fprintf(stderr, "Error resizing PSS object\n"); + return SRSLTE_ERROR; + } + if (srslte_sss_synch_resize(&q->sss, fft_size)) { + fprintf(stderr, "Error resizing SSS object\n"); + return SRSLTE_ERROR; + } + + if (srslte_cp_synch_resize(&q->cp_synch, fft_size)) { + fprintf(stderr, "Error resizing CFO\n"); + return SRSLTE_ERROR; + } + + if (srslte_cfo_resize(&q->cfocorr, q->frame_size)) { + fprintf(stderr, "Error resizing CFO\n"); + return SRSLTE_ERROR; + } + + if (srslte_cfo_resize(&q->cfocorr2, q->frame_size)) { + fprintf(stderr, "Error resizing CFO\n"); + return SRSLTE_ERROR; + } + + // Update CFO tolerance + srslte_sync_set_cfo_tol(q, q->current_cfo_tol); + + DEBUG("SYNC init with frame_size=%d, max_offset=%d and fft_size=%d\n", frame_size, max_offset, fft_size); + + ret = SRSLTE_SUCCESS; + } else { + fprintf(stderr, "Invalid parameters frame_size: %d, fft_size: %d\n", frame_size, fft_size); + } + + return ret; +} + +void srslte_sync_set_cfo_tol(srslte_sync_t *q, float tol) { + q->current_cfo_tol = tol; + srslte_cfo_set_tol(&q->cfocorr, tol/(15000.0*q->fft_size)); + srslte_cfo_set_tol(&q->cfocorr2, tol/(15000.0*q->fft_size)); +} + void srslte_sync_set_threshold(srslte_sync_t *q, float threshold) { q->threshold = threshold; } @@ -217,7 +295,10 @@ float srslte_sync_get_cfo(srslte_sync_t *q) { } void srslte_sync_set_cfo(srslte_sync_t *q, float cfo) { - q->mean_cfo = cfo; + q->mean_cfo = cfo; + q->mean_cfo2 = cfo; + q->mean_cfo2_isunset = false; + q->mean_cfo_isunset = false; } void srslte_sync_set_cfo_i(srslte_sync_t *q, int cfo_i) { @@ -445,13 +526,18 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t cf_t *input_cfo = input; if (q->enable_cfo_corr) { - float cfo = cfo_estimate(q, input); - - /* compute exponential moving average CFO */ - q->mean_cfo = SRSLTE_VEC_EMA(cfo, q->mean_cfo, q->cfo_ema_alpha); - + float cfo = cfo_estimate(q, input); + + if (q->mean_cfo_isunset) { + q->mean_cfo = cfo; + q->mean_cfo_isunset = false; + } else { + /* compute exponential moving average CFO */ + q->mean_cfo = SRSLTE_VEC_EMA(cfo, q->mean_cfo, q->cfo_ema_alpha); + } + /* Correct CFO with the averaged CFO estimation */ - srslte_cfo_correct(&q->cfocorr2, input, q->temp, -q->mean_cfo / q->fft_size); + srslte_cfo_correct(&q->cfocorr2, input, q->temp, -q->mean_cfo / q->fft_size); input_cfo = q->temp; } @@ -504,8 +590,13 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]); - q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); - + if (q->mean_cfo2_isunset) { + q->mean_cfo2 = cfo2; + q->mean_cfo2_isunset = true; + } else { + q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); + } + ret = SRSLTE_SYNC_FOUND; } else { ret = SRSLTE_SYNC_FOUND_NOSPACE; @@ -526,7 +617,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t } void srslte_sync_reset(srslte_sync_t *q) { - q->M_ext_avg = 0; + q->M_ext_avg = 0; q->M_norm_avg = 0; srslte_pss_synch_reset(&q->pss); } diff --git a/lib/src/phy/ue/ue_cell_search.c b/lib/src/phy/ue/ue_cell_search.c index f7d244387..dc35fb48c 100644 --- a/lib/src/phy/ue/ue_cell_search.c +++ b/lib/src/phy/ue/ue_cell_search.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "srslte/phy/ue/ue_cell_search.h" @@ -51,11 +52,16 @@ int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t * q, uint32_t max_frames, cell.id = SRSLTE_CELL_ID_UNKNOWN; cell.nof_prb = SRSLTE_CS_NOF_PRB; - if (srslte_ue_sync_init(&q->ue_sync, cell, recv_callback, stream_handler)) { + if (srslte_ue_sync_init(&q->ue_sync, cell.nof_prb, true, recv_callback, stream_handler)) { fprintf(stderr, "Error initiating ue_sync\n"); goto clean_exit; } - + + if (srslte_ue_sync_set_cell(&q->ue_sync, cell)) { + fprintf(stderr, "Error initiating ue_sync\n"); + goto clean_exit; + } + q->sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); q->nof_rx_antennas = 1; @@ -105,11 +111,15 @@ int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t * q, uint32_t max_fra cell.id = SRSLTE_CELL_ID_UNKNOWN; cell.nof_prb = SRSLTE_CS_NOF_PRB; - if (srslte_ue_sync_init_multi(&q->ue_sync, cell, recv_callback, nof_rx_antennas, stream_handler)) { + if (srslte_ue_sync_init_multi(&q->ue_sync, cell.nof_prb, true, recv_callback, nof_rx_antennas, stream_handler)) { fprintf(stderr, "Error initiating ue_sync\n"); goto clean_exit; } - + if (srslte_ue_sync_set_cell(&q->ue_sync, cell)) { + fprintf(stderr, "Error initiating ue_sync\n"); + goto clean_exit; + } + for (int i=0;isf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); } @@ -242,7 +252,8 @@ int srslte_ue_cellsearch_scan(srslte_ue_cellsearch_t * q, { int ret = 0; float max_peak_value = -1.0; - uint32_t nof_detected_cells = 0; + uint32_t nof_detected_cells = 0; + for (uint32_t N_id_2=0;N_id_2<3 && ret >= 0;N_id_2++) { ret = srslte_ue_cellsearch_scan_N_id_2(q, N_id_2, &found_cells[N_id_2]); if (ret < 0) { @@ -273,8 +284,12 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q, if (q != NULL) { - ret = SRSLTE_SUCCESS; - + ret = SRSLTE_SUCCESS; + + bzero(q->candidates, sizeof(srslte_ue_cellsearch_result_t)*q->max_frames); + bzero(q->mode_ntimes, sizeof(uint32_t)*q->max_frames); + bzero(q->mode_counted, sizeof(uint8_t)*q->max_frames); + srslte_ue_sync_set_N_id_2(&q->ue_sync, N_id_2); srslte_ue_sync_reset(&q->ue_sync); do { @@ -282,7 +297,7 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q, ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); - break; + return -1; } else if (ret == 1) { /* This means a peak was found and ue_sync is now in tracking state */ ret = srslte_sync_get_cell_id(&q->ue_sync.strack); diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 888b0d9b3..c4e2d3f6c 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -27,6 +27,7 @@ #include "srslte/phy/ue/ue_dl.h" #include +#include #define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb) @@ -35,6 +36,7 @@ #define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) #define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define MAX_SFLEN_RE SRSLTE_SF_LEN_RE(max_prb, q->cell.cp) const static srslte_dci_format_t ue_dci_formats[8][2] = { /* Mode 1 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}, @@ -51,57 +53,64 @@ static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FO const uint32_t nof_common_formats = 2; int srslte_ue_dl_init(srslte_ue_dl_t *q, - srslte_cell_t cell, + uint32_t max_prb, uint32_t nof_rx_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && - nof_rx_antennas <= SRSLTE_MAX_PORTS && - srslte_cell_isvalid(&cell)) + nof_rx_antennas <= SRSLTE_MAX_PORTS) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_ue_dl_t)); - - q->cell = 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; q->sample_offset = 0; - q->nof_rx_antennas = nof_rx_antennas; - - if (srslte_ofdm_rx_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { + q->nof_rx_antennas = nof_rx_antennas; + + if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, max_prb)) { fprintf(stderr, "Error initiating FFT\n"); goto clean_exit; } - if (srslte_chest_dl_init(&q->chest, cell)) { - fprintf(stderr, "Error initiating channel estimator\n"); + + if (srslte_ofdm_rx_init_mbsfn(&q->fft_mbsfn, SRSLTE_CP_EXT, max_prb)) { + fprintf(stderr, "Error initiating FFT for MBSFN subframes \n"); goto clean_exit; } - if (srslte_regs_init(&q->regs, q->cell)) { - fprintf(stderr, "Error initiating REGs\n"); + srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, 2); // Set a default to init + + if (srslte_chest_dl_init(&q->chest, max_prb)) { + fprintf(stderr, "Error initiating channel estimator\n"); goto clean_exit; } - if (srslte_pcfich_init_multi(&q->pcfich, &q->regs, q->cell, nof_rx_antennas)) { + if (srslte_pcfich_init(&q->pcfich, nof_rx_antennas)) { fprintf(stderr, "Error creating PCFICH object\n"); goto clean_exit; } - if (srslte_phich_init(&q->phich, &q->regs, q->cell)) { + if (srslte_phich_init(&q->phich, nof_rx_antennas)) { fprintf(stderr, "Error creating PHICH object\n"); goto clean_exit; } - if (srslte_pdcch_init_multi(&q->pdcch, &q->regs, q->cell, nof_rx_antennas)) { + if (srslte_pdcch_init_ue(&q->pdcch, max_prb, nof_rx_antennas)) { fprintf(stderr, "Error creating PDCCH object\n"); goto clean_exit; } - if (srslte_pdsch_init_rx(&q->pdsch, q->cell, nof_rx_antennas)) { + if (srslte_pdsch_init_ue(&q->pdsch, max_prb, nof_rx_antennas)) { fprintf(stderr, "Error creating PDSCH object\n"); goto clean_exit; } + if (srslte_pmch_init_multi(&q->pmch, max_prb, nof_rx_antennas)) { + fprintf(stderr, "Error creating PMCH object\n"); + goto clean_exit; + } for (int i = 0; i < SRSLTE_MAX_TB; i++) { q->softbuffers[i] = srslte_vec_malloc(sizeof(srslte_softbuffer_rx_t)); if (!q->softbuffers[i]) { @@ -109,41 +118,41 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, goto clean_exit; } - if (srslte_softbuffer_rx_init(q->softbuffers[i], q->cell.nof_prb)) { + if (srslte_softbuffer_rx_init(q->softbuffers[i], max_prb)) { fprintf(stderr, "Error initiating soft buffer\n"); goto clean_exit; } } - if (srslte_cfo_init(&q->sfo_correct, q->cell.nof_prb*SRSLTE_NRE)) { + if (srslte_cfo_init(&q->sfo_correct, max_prb*SRSLTE_NRE)) { fprintf(stderr, "Error initiating SFO correct\n"); goto clean_exit; } srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft.symbol_sz); - for (int j=0;jsf_symbols_m[j] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { + q->sf_symbols_m[j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); if (!q->sf_symbols_m[j]) { perror("malloc"); goto clean_exit; } - for (uint32_t i=0;icell.nof_ports;i++) { - q->ce_m[i][j] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + for (uint32_t i=0;ice_m[i][j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); if (!q->ce_m[i][j]) { perror("malloc"); goto clean_exit; } + bzero(q->ce_m[i][j], MAX_SFLEN_RE * sizeof(cf_t)); } } q->sf_symbols = q->sf_symbols_m[0]; - for (int i=0;icell.nof_ports;i++) { + for (int i=0;ice[i] = q->ce_m[i][0]; } ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", - cell.id, cell.nof_ports, cell.nof_prb); + fprintf(stderr, "Invalid parametres\n"); } clean_exit: @@ -156,12 +165,14 @@ clean_exit: void srslte_ue_dl_free(srslte_ue_dl_t *q) { if (q) { srslte_ofdm_rx_free(&q->fft); + srslte_ofdm_rx_free(&q->fft_mbsfn); srslte_chest_dl_free(&q->chest); srslte_regs_free(&q->regs); 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_cfo_free(&q->sfo_correct); for (int i = 0; i < SRSLTE_MAX_TB; i++) { srslte_softbuffer_rx_free(q->softbuffers[i]); @@ -169,11 +180,11 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) { free(q->softbuffers[i]); } } - for (int j=0;jnof_rx_antennas;j++) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { if (q->sf_symbols_m[j]) { free(q->sf_symbols_m[j]); } - for (uint32_t i=0;icell.nof_ports;i++) { + for (uint32_t i=0;ice_m[i][j]) { free(q->ce_m[i][j]); } @@ -183,11 +194,74 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) { } } +int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + srslte_cell_isvalid(&cell)) + { + q->pkt_errors = 0; + q->pkts_total = 0; + q->pending_ul_dci_rnti = 0; + q->sample_offset = 0; + + if (q->cell.id != cell.id || q->cell.nof_prb == 0) { + if (q->cell.nof_prb != 0) { + srslte_regs_free(&q->regs); + } + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + if (srslte_regs_init(&q->regs, q->cell)) { + fprintf(stderr, "Error resizing REGs\n"); + return SRSLTE_ERROR; + } + if (srslte_cfo_resize(&q->sfo_correct, q->cell.nof_prb*SRSLTE_NRE)) { + fprintf(stderr, "Error resizing SFO correct\n"); + return SRSLTE_ERROR; + } + srslte_cfo_set_tol(&q->sfo_correct, 1e-5/q->fft.symbol_sz); + if (srslte_ofdm_rx_set_prb(&q->fft, q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error resizing 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; + } + if (srslte_pcfich_set_cell(&q->pcfich, &q->regs, q->cell)) { + fprintf(stderr, "Error resizing PCFICH object\n"); + return SRSLTE_ERROR; + } + if (srslte_phich_set_cell(&q->phich, &q->regs, q->cell)) { + fprintf(stderr, "Error resizing PHICH object\n"); + return SRSLTE_ERROR; + } + + if (srslte_pdcch_set_cell(&q->pdcch, &q->regs, q->cell)) { + fprintf(stderr, "Error resizing PDCCH object\n"); + return SRSLTE_ERROR; + } + + if (srslte_pdsch_set_cell(&q->pdsch, q->cell)) { + fprintf(stderr, "Error creating PDSCH object\n"); + return SRSLTE_ERROR; + } + q->current_rnti = 0; + } + ret = SRSLTE_SUCCESS; + } else { + fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + cell.id, cell.nof_ports, cell.nof_prb); + } + return ret; +} + /* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while * to execute, so shall be called once the final C-RNTI has been allocated for the session. * For the connection procedure, use srslte_pusch_encode_rnti() or srslte_pusch_decode_rnti() functions */ void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) { + srslte_pdsch_set_rnti(&q->pdsch, rnti); // Compute UE-specific and Common search space for this RNTI @@ -200,6 +274,34 @@ void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) { q->current_rnti = rnti; } +/* Set the area ID on pmch and chest_dl to generate scrambling sequence and reference + * signals. + */ +int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q, + uint16_t mbsfn_area_id) { + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if(q != NULL) { + ret = SRSLTE_ERROR; + if(srslte_chest_dl_set_mbsfn_area_id(&q->chest, mbsfn_area_id)) { + fprintf(stderr, "Error setting MBSFN area ID \n"); + return ret; + } + if(srslte_pmch_set_area_id(&q->pmch, mbsfn_area_id)) { + fprintf(stderr, "Error setting MBSFN area ID \n"); + return ret; + } + q->current_mbsfn_area_id = mbsfn_area_id; + ret = SRSLTE_SUCCESS; + } + return ret; +} + +void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, + uint8_t non_mbsfn_region_length) { + srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length); +} + + void srslte_ue_dl_reset(srslte_ue_dl_t *q) { for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ @@ -221,20 +323,31 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) { */ int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) { - return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks); + return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks); } -int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi) + +int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi){ + + return srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, cfi, SRSLTE_SF_NORM); +} + +int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) { if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Run FFT for all subframe data */ for (int j=0;jnof_rx_antennas;j++) { - srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]); + if(sf_type == SRSLTE_SF_MBSFN ) { + srslte_ofdm_rx_sf(&q->fft_mbsfn, input[j], q->sf_symbols_m[j]); + }else{ + srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]); + } /* Correct SFO multiplying by complex exponential in the time domain */ if (q->sample_offset) { - for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) { + int nsym = (sf_type == SRSLTE_SF_MBSFN)?SRSLTE_CP_EXT_NSYMB:SRSLTE_CP_NSYMB(q->cell.cp); + for (int i=0;i<2*nsym;i++) { srslte_cfo_correct(&q->sfo_correct, &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], @@ -242,18 +355,28 @@ int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_P } } } - return srslte_ue_dl_decode_estimate(q, sf_idx, cfi); + return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, sf_type); } else { return SRSLTE_ERROR_INVALID_INPUTS; } } - int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) { + + return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); +} + + +int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) { float cfi_corr; if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Get channel estimates for each port */ - srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas); + if(sf_type == SRSLTE_SF_MBSFN){ + srslte_chest_dl_estimate_multi_mbsfn(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas, q->current_mbsfn_area_id); + }else{ + srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas); + } + /* First decode PCFICH and obtain CFI */ if (srslte_pcfich_decode_multi(&q->pcfich, q->sf_symbols_m, q->ce_m, @@ -280,26 +403,31 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type) { uint32_t pmi = 0; + uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant); /* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */ if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - if (grant->nof_tb == 1) { + if (nof_tb == 1) { if (grant->pinfo > 0 && grant->pinfo < 5) { pmi = grant->pinfo - 1; } else { - ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, grant->pinfo); + ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); return SRSLTE_ERROR; } } else { if (grant->pinfo < 2) { pmi = grant->pinfo; } else { - ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, grant->pinfo); + ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); return SRSLTE_ERROR; } } } - return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); + if(SRSLTE_SF_MBSFN == grant->sf_type) { + return srslte_pmch_cfg(&q->pmch_cfg, q->cell, grant, cfi, sf_idx); + } else { + return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); + } } int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], @@ -313,7 +441,7 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t cfi; uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) { return ret; } @@ -336,29 +464,33 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], /* ===== These lines of code are supposed to be MAC functionality === */ - + int rvidx[SRSLTE_MAX_CODEWORDS] = {1}; if (dci_unpacked.rv_idx < 0) { - uint32_t sfn = tti/10; - uint32_t k = (sfn/2)%4; - for (int i = 0; i < grant.nof_tb; i++) { - rvidx[i] = ((uint32_t) ceilf((float) 1.5 * k)) % 4; - srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); + uint32_t sfn = tti / 10; + uint32_t k = (sfn / 2) % 4; + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant.tb_en[i]) { + rvidx[i] = ((uint32_t) ceilf((float) 1.5 * k)) % 4; + srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); + } } } else { - for (int i = 0; i < grant.nof_tb; i++) { - switch(i) { - case 0: - rvidx[i] = (uint32_t) dci_unpacked.rv_idx; - break; - case 1: - rvidx[i] = (uint32_t) dci_unpacked.rv_idx_1; - break; - default: - ERROR("Wrong number of transport blocks"); - return SRSLTE_ERROR; + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant.tb_en[i]) { + switch (i) { + case 0: + rvidx[i] = (uint32_t) dci_unpacked.rv_idx; + break; + case 1: + rvidx[i] = (uint32_t) dci_unpacked.rv_idx_1; + break; + default: + ERROR("Wrong number of transport blocks"); + return SRSLTE_ERROR; + } + srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); } - srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); } } @@ -372,14 +504,14 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], } break; case SRSLTE_DCI_FORMAT2: - if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) { + if (SRSLTE_RA_DL_GRANT_NOF_TB(&grant) == 1 && dci_unpacked.pinfo == 0) { mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; } else { mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; } break; case SRSLTE_DCI_FORMAT2A: - if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) { + if (SRSLTE_RA_DL_GRANT_NOF_TB(&grant) == 1 && dci_unpacked.pinfo == 0) { mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; } else { mimo_type = SRSLTE_MIMO_TYPE_CDD; @@ -413,11 +545,14 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], noise_estimate, rnti, data, acks); - for (int tb = 0; tb < q->pdsch_cfg.grant.nof_tb; tb++) { - if (!acks[tb]) { - q->pkt_errors++; + + for (int tb = 0; tb < SRSLTE_MAX_TB; tb++) { + if (grant.tb_en[tb]) { + if (!acks[tb]) { + q->pdsch_pkt_errors++; + } + q->pdsch_pkts_total++; } - q->pkts_total++; } if (ret == SRSLTE_ERROR) { @@ -445,17 +580,79 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], } } + + +int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, + cf_t *input[SRSLTE_MAX_PORTS], + uint8_t *data, + uint32_t tti) +{ + srslte_ra_dl_grant_t grant; + int ret = SRSLTE_ERROR; + uint32_t cfi; + uint32_t sf_idx = tti%10; + + if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) { + return ret; + } + + float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); + // Uncoment next line to do ZF by default in pdsch_ue example + //float noise_estimate = 0; + + grant.sf_type = SRSLTE_SF_MBSFN; + grant.nof_tb = 1; + grant.mcs[0].idx = 2; + + grant.nof_prb = q->pmch.cell.nof_prb; + srslte_dl_fill_ra_mcs(&grant.mcs[0], grant.nof_prb); + srslte_softbuffer_rx_reset_tbs(q->softbuffers[0], (uint32_t) grant.mcs[0].tbs); + for(int j = 0; j < 2; j++){ + for(int f = 0; f < grant.nof_prb; f++){ + grant.prb_idx[j][f] = true; + } + } + grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod); + + // redundancy version is set to 0 for the PMCH + if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, SRSLTE_PMCH_RV, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA)) { + return SRSLTE_ERROR; + } + + if (q->pmch_cfg.grant.mcs[0].mod > 0 && q->pmch_cfg.grant.mcs[0].tbs >= 0) { + ret = srslte_pmch_decode_multi(&q->pmch, &q->pmch_cfg, q->softbuffers[0], + q->sf_symbols_m, q->ce_m, + noise_estimate, + q->current_mbsfn_area_id, data); + + if (ret == SRSLTE_ERROR) { + q->pmch_pkt_errors++; + } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) { + fprintf(stderr, "Error calling srslte_pmch_decode()\n"); + } + } + + q->pmch_pkts_total++; + + if (ret == SRSLTE_SUCCESS) { + return q->pmch_cfg.grant.mcs[0].tbs; + } else { + return 0; + } +} + + /* Compute the Rank Indicator (RI) and Precoder Matrix Indicator (PMI) by computing the Signal to Interference plus * Noise Ratio (SINR), valid for TM4 */ -int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, float *current_sinr) { +int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, float *current_sinr) { float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); float best_sinr = -INFINITY; - uint32_t best_pmi = 0, best_ri = 0; + uint8_t best_pmi = 0, best_ri = 0; - if (q->cell.nof_ports < 2 || q->nof_rx_antennas < 2) { + if (q->cell.nof_ports < 2) { /* Do nothing */ return SRSLTE_SUCCESS; - } else if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { + } else { if (srslte_pdsch_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), q->pmi, q->sinr)) { ERROR("SINR calculation error"); @@ -463,45 +660,42 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, f } /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ - for (uint32_t nof_layers = 1; nof_layers <= 2; nof_layers++) { - float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers; + for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) { + float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers; if (_sinr > best_sinr + 0.1) { best_sinr = _sinr; - best_pmi = q->pmi[nof_layers - 1]; - best_ri = nof_layers; + best_pmi = (uint8_t) q->pmi[nof_layers - 1]; + best_ri = (uint8_t) (nof_layers - 1); } } + } - /* Set RI */ - if (ri != NULL) { - *ri = best_ri; - } + /* Print Trace */ + if (ri != NULL && pmi != NULL && current_sinr != NULL) { + INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi, + 10*log10(*current_sinr), q->pdsch_cfg.nof_layers, q->pdsch_cfg.codebook_idx); + } - /* Set PMI */ - if (pmi != NULL) { - *pmi = best_pmi; - } + /* Set RI */ + if (ri != NULL) { + *ri = best_ri; + } - /* Set current SINR */ - if (current_sinr != NULL && q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - if (q->pdsch_cfg.nof_layers == 1) { - *current_sinr = q->sinr[0][q->pdsch_cfg.codebook_idx]; - } else if (q->pdsch_cfg.nof_layers == 2) { - *current_sinr = q->sinr[1][q->pdsch_cfg.codebook_idx - 1]; - } else { - ERROR("Not implemented number of layers (%d)", q->pdsch_cfg.nof_layers); - return SRSLTE_ERROR; - } - } + /* Set PMI */ + if (pmi != NULL) { + *pmi = best_pmi; + } - /* Print Trace */ - if (ri != NULL && pmi != NULL && current_sinr != NULL) { - INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi, - 10*log10(*current_sinr), q->pdsch_cfg.nof_layers, q->pdsch_cfg.codebook_idx); + /* Set current SINR */ + if (current_sinr != NULL && q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { + if (q->pdsch_cfg.nof_layers == 1) { + *current_sinr = q->sinr[0][q->pdsch_cfg.codebook_idx]; + } else if (q->pdsch_cfg.nof_layers == 2) { + *current_sinr = q->sinr[1][q->pdsch_cfg.codebook_idx - 1]; + } else { + ERROR("Not implemented number of layers (%d)", q->pdsch_cfg.nof_layers); + return SRSLTE_ERROR; } - } else { - ERROR("Not implemented configuration"); - return SRSLTE_ERROR_INVALID_INPUTS; } return SRSLTE_SUCCESS; @@ -509,7 +703,7 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, f /* Compute the Rank Indicator (RI) by computing the condition number, valid for TM3 */ -int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint32_t *ri, float *cn) { +int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint8_t *ri, float *cn) { float _cn; int ret = srslte_pdsch_cn_compute(&q->pdsch, q->ce_m, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), &_cn); @@ -520,7 +714,7 @@ int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint32_t *ri, float *cn) { /* Set rank indicator */ if (!ret && ri) { - *ri = (_cn > 3.0f)? 1:0; + *ri = (uint8_t)((_cn < 17.0f)? 1:0); } return ret; @@ -712,13 +906,7 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr sf_idx, n_prb_lowest, n_dmrs, ngroup, nseq, srslte_phich_ngroups(&q->phich), srslte_phich_nsf(&q->phich)); - cf_t *ce0[SRSLTE_MAX_PORTS]; - for (int i=0;ice_m[i][0]; - } - - - if (!srslte_phich_decode(&q->phich, q->sf_symbols_m[0], ce0, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { + if (!srslte_phich_decode(&q->phich, q->sf_symbols_m, q->ce_m, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance); } else { fprintf(stderr, "Error decoding PHICH\n"); @@ -732,11 +920,11 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr } void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuffer, uint32_t tti, uint32_t rv_idx, uint16_t rnti, uint32_t cfi) { - srslte_vec_save_file("sf_symbols", q->sf_symbols_m, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("sf_symbols", q->sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); printf("%d samples\n", SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)); - srslte_vec_save_file("ce0", q->ce_m[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("ce0", q->ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); if (q->cell.nof_ports > 1) { - srslte_vec_save_file("ce1", q->ce_m[1], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("ce1", q->ce[1], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); } srslte_vec_save_file("pcfich_ce0", q->pcfich.ce[0], q->pcfich.nof_symbols*sizeof(cf_t)); srslte_vec_save_file("pcfich_ce1", q->pcfich.ce[1], q->pcfich.nof_symbols*sizeof(cf_t)); @@ -749,18 +937,18 @@ void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuf srslte_vec_save_file("pdcch_symbols", q->pdcch.symbols[0], q->pdcch.nof_cce*36*sizeof(cf_t)); srslte_vec_save_file("pdcch_eq_symbols", q->pdcch.d, q->pdcch.nof_cce*36*sizeof(cf_t)); srslte_vec_save_file("pdcch_llr", q->pdcch.llr, q->pdcch.nof_cce*72*sizeof(float)); + - - srslte_vec_save_file("pdsch_symbols", q->pdsch.d, q->pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); - srslte_vec_save_file("llr", q->pdsch.e, q->pdsch_cfg.nbits[0].nof_bits*sizeof(cf_t)); + srslte_vec_save_file("pdsch_symbols", q->pdsch.d[0], q->pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); + srslte_vec_save_file("llr", q->pdsch.e[0], q->pdsch_cfg.nbits[0].nof_bits*sizeof(cf_t)); int cb_len = q->pdsch_cfg.cb_segm[0].K1; for (int i=0;ipdsch_cfg.cb_segm[0].C;i++) { - char tmpstr[64]; + char tmpstr[64]; snprintf(tmpstr,64,"rmout_%d.dat",i); srslte_vec_save_file(tmpstr, softbuffer->buffer_f[i], (3*cb_len+12)*sizeof(int16_t)); } - printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, - q->pdsch_cfg.grant.mcs[0].idx, rv_idx, rnti); + printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, tbs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, + q->pdsch_cfg.grant.mcs[0].idx, q->pdsch_cfg.grant.mcs[0].tbs, rv_idx, rnti); } diff --git a/lib/src/phy/ue/ue_mib.c b/lib/src/phy/ue/ue_mib.c index 34c2bc2e3..46a470ab8 100644 --- a/lib/src/phy/ue/ue_mib.c +++ b/lib/src/phy/ue/ue_mib.c @@ -36,45 +36,40 @@ #include "srslte/phy/utils/vector.h" int srslte_ue_mib_init(srslte_ue_mib_t * q, - srslte_cell_t cell) + uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - cell.nof_ports <= SRSLTE_MAX_PORTS) + if (q != NULL) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_ue_mib_t)); - if (srslte_pbch_init(&q->pbch, cell)) { + if (srslte_pbch_init(&q->pbch)) { fprintf(stderr, "Error initiating PBCH\n"); goto clean_exit; } - if (cell.nof_ports == 0) { - cell.nof_ports = SRSLTE_MAX_PORTS; - } - - q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); + q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); if (!q->sf_symbols) { perror("malloc"); goto clean_exit; } - for (int i=0;ice[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); + for (int i=0;ice[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); if (!q->ce[i]) { perror("malloc"); goto clean_exit; } } - if (srslte_ofdm_rx_init(&q->fft, cell.cp, cell.nof_prb)) { + if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, max_prb)) { fprintf(stderr, "Error initializing FFT\n"); goto clean_exit; } - if (srslte_chest_dl_init(&q->chest, cell)) { + if (srslte_chest_dl_init(&q->chest, max_prb)) { fprintf(stderr, "Error initializing reference signal\n"); goto clean_exit; } @@ -109,6 +104,38 @@ void srslte_ue_mib_free(srslte_ue_mib_t * q) } +int srslte_ue_mib_set_cell(srslte_ue_mib_t * q, + srslte_cell_t cell) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + cell.nof_ports <= SRSLTE_MAX_PORTS) + { + if (srslte_pbch_set_cell(&q->pbch, cell)) { + fprintf(stderr, "Error initiating PBCH\n"); + return SRSLTE_ERROR; + } + if (srslte_ofdm_rx_set_prb(&q->fft, cell.cp, cell.nof_prb)) { + fprintf(stderr, "Error initializing FFT\n"); + return SRSLTE_ERROR; + } + + if (cell.nof_ports == 0) { + cell.nof_ports = SRSLTE_MAX_PORTS; + } + + if (srslte_chest_dl_set_cell(&q->chest, cell)) { + fprintf(stderr, "Error initializing reference signal\n"); + return SRSLTE_ERROR; + } + srslte_ue_mib_reset(q); + + ret = SRSLTE_SUCCESS; + } + return ret; +} + void srslte_ue_mib_reset(srslte_ue_mib_t * q) { @@ -142,7 +169,7 @@ int srslte_ue_mib_decode(srslte_ue_mib_t * q, cf_t *input, /* Decode PBCH */ ret = srslte_pbch_decode(&q->pbch, &q->sf_symbols[SRSLTE_SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)], - ce_slot1, srslte_chest_dl_get_noise_estimate(&q->chest), + ce_slot1, 0, bch_payload, nof_tx_ports, sfn_offset); @@ -161,27 +188,21 @@ int srslte_ue_mib_decode(srslte_ue_mib_t * q, cf_t *input, return ret; } -int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, - uint32_t cell_id, - srslte_cp_t cp, - int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*), - void *stream_handler) +int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler) { - srslte_cell_t cell; - // If the ports are set to 0, ue_mib goes through 1, 2 and 4 ports to blindly detect nof_ports - cell.nof_ports = 0; - cell.id = cell_id; - cell.cp = cp; - cell.nof_prb = SRSLTE_UE_MIB_NOF_PRB; - - q->sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); - q->nof_rx_antennas = 1; + for (int i=0;isf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(SRSLTE_UE_MIB_NOF_PRB)); + } + q->nof_rx_antennas = nof_rx_antennas; - if (srslte_ue_mib_init(&q->ue_mib, cell)) { + if (srslte_ue_mib_init(&q->ue_mib, SRSLTE_UE_MIB_NOF_PRB)) { fprintf(stderr, "Error initiating ue_mib\n"); return SRSLTE_ERROR; } - if (srslte_ue_sync_init(&q->ue_sync, cell, recv_callback, stream_handler)) { + if (srslte_ue_sync_init_multi(&q->ue_sync, SRSLTE_UE_MIB_NOF_PRB, false, recv_callback, nof_rx_antennas, stream_handler)) { fprintf(stderr, "Error initiating ue_sync\n"); srslte_ue_mib_free(&q->ue_mib); return SRSLTE_ERROR; @@ -190,38 +211,30 @@ int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, return SRSLTE_SUCCESS; } -int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, - uint32_t cell_id, - srslte_cp_t cp, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), - uint32_t nof_rx_antennas, - void *stream_handler) +int srslte_ue_mib_sync_set_cell(srslte_ue_mib_sync_t *q, + uint32_t cell_id, + srslte_cp_t cp) { - srslte_cell_t cell; + srslte_cell_t cell; // If the ports are set to 0, ue_mib goes through 1, 2 and 4 ports to blindly detect nof_ports - cell.nof_ports = 0; - cell.id = cell_id; - cell.cp = cp; - cell.nof_prb = SRSLTE_UE_MIB_NOF_PRB; - - for (int i=0;isf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); - } - q->nof_rx_antennas = nof_rx_antennas; - - if (srslte_ue_mib_init(&q->ue_mib, cell)) { + cell.nof_ports = 0; + cell.id = cell_id; + cell.cp = cp; + cell.nof_prb = SRSLTE_UE_MIB_NOF_PRB; + + if (srslte_ue_mib_set_cell(&q->ue_mib, cell)) { fprintf(stderr, "Error initiating ue_mib\n"); return SRSLTE_ERROR; } - if (srslte_ue_sync_init_multi(&q->ue_sync, cell, recv_callback, nof_rx_antennas, stream_handler)) { + if (srslte_ue_sync_set_cell(&q->ue_sync, cell)) { fprintf(stderr, "Error initiating ue_sync\n"); srslte_ue_mib_free(&q->ue_mib); return SRSLTE_ERROR; } - srslte_ue_sync_decode_sss_on_track(&q->ue_sync, true); return SRSLTE_SUCCESS; } + void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q) { for (int i=0;inof_rx_antennas;i++) { if (q->sf_buffer[i]) { @@ -246,17 +259,19 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q, int ret = SRSLTE_ERROR_INVALID_INPUTS; uint32_t nof_frames = 0; - int mib_ret = SRSLTE_UE_MIB_NOTFOUND; + int mib_ret = SRSLTE_UE_MIB_NOTFOUND; - if (q != NULL) + if (q != NULL) { - ret = SRSLTE_SUCCESS; + srslte_ue_mib_sync_reset(q); + + ret = SRSLTE_SUCCESS; do { mib_ret = SRSLTE_UE_MIB_NOTFOUND; ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); - break; + return -1; } else if (srslte_ue_sync_get_sfidx(&q->ue_sync) == 0) { if (ret == 1) { mib_ret = srslte_ue_mib_decode(&q->ue_mib, q->sf_buffer[0], bch_payload, nof_tx_ports, sfn_offset); diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index e011789ca..f121c5bac 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "srslte/phy/ue/ue_sync.h" @@ -128,39 +129,41 @@ int recv_callback_multi_to_single(void *h, cf_t *x[SRSLTE_MAX_PORTS], uint32_t n } int srslte_ue_sync_init(srslte_ue_sync_t *q, - srslte_cell_t cell, - int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), - void *stream_handler) + uint32_t max_prb, + bool search_cell, + int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), + void *stream_handler) { - int ret = srslte_ue_sync_init_multi(q, cell, recv_callback_multi_to_single, 1, (void*) q); + int ret = srslte_ue_sync_init_multi(q, max_prb, search_cell, recv_callback_multi_to_single, 1, (void*) q); q->recv_callback_single = recv_callback; q->stream_single = stream_handler; return ret; } int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, - srslte_cell_t cell, + uint32_t max_prb, + bool search_cell, int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), uint32_t nof_rx_antennas, void *stream_handler) { - return srslte_ue_sync_init_multi_decim(q, cell,recv_callback ,nof_rx_antennas,stream_handler,1); + return srslte_ue_sync_init_multi_decim(q, max_prb,search_cell, recv_callback ,nof_rx_antennas,stream_handler,1); } int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, - srslte_cell_t cell, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), - uint32_t nof_rx_antennas, - void *stream_handler, - int decimate) + uint32_t max_prb, + bool search_cell, + int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void *stream_handler, + int decimate) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && stream_handler != NULL && - srslte_nofprb_isvalid(cell.nof_prb) && nof_rx_antennas <= SRSLTE_MAX_PORTS && recv_callback != NULL) { @@ -171,122 +174,182 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, q->stream = stream_handler; q->recv_callback = recv_callback; q->nof_rx_antennas = nof_rx_antennas; - q->cell = cell; - q->fft_size = srslte_symbol_sz(q->cell.nof_prb); + q->fft_size = srslte_symbol_sz(max_prb); q->sf_len = SRSLTE_SF_LEN(q->fft_size); q->file_mode = false; q->correct_cfo = true; q->agc_period = 0; q->sample_offset_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD; q->sfo_ema = DEFAULT_SFO_EMA_COEFF; - - if (cell.id == 1000) { + + q->max_prb = max_prb; + + if (search_cell) { /* If the cell is unkown, we search PSS/SSS in 5 ms */ q->nof_recv_sf = 5; - q->decode_sss_on_track = true; - } else { /* If the cell is known, we work on a 1ms basis */ q->nof_recv_sf = 1; - q->decode_sss_on_track = true; } q->frame_len = q->nof_recv_sf*q->sf_len; - if(q->fft_size < 700 && q->decimate) - { + if(q->fft_size < 700 && q->decimate) { q->decimate = 1; } - - + if(srslte_sync_init_decim(&q->sfind, q->frame_len, q->frame_len, q->fft_size,q->decimate)) { fprintf(stderr, "Error initiating sync find\n"); goto clean_exit; } - if (cell.id == 1000) { + if (search_cell) { if(srslte_sync_init(&q->strack, q->frame_len, TRACK_FRAME_SIZE, q->fft_size)) { fprintf(stderr, "Error initiating sync track\n"); goto clean_exit; - } + } } else { if(srslte_sync_init(&q->strack, q->frame_len, SRSLTE_CP_LEN_NORM(1,q->fft_size), q->fft_size)) { fprintf(stderr, "Error initiating sync track\n"); goto clean_exit; } } - + + ret = SRSLTE_SUCCESS; + } + +clean_exit: + if (ret == SRSLTE_ERROR) { + srslte_ue_sync_free(q); + } + return ret; +} + +uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t *q) { + return q->frame_len; +} + +void srslte_ue_sync_free(srslte_ue_sync_t *q) { + if (q->do_agc) { + srslte_agc_free(&q->agc); + } + if (!q->file_mode) { + srslte_sync_free(&q->sfind); + srslte_sync_free(&q->strack); + } else { + srslte_filesource_free(&q->file_source); + } + bzero(q, sizeof(srslte_ue_sync_t)); +} + + +int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + srslte_nofprb_isvalid(cell.nof_prb)) + { + ret = SRSLTE_ERROR; + + if (cell.nof_prb > q->max_prb) { + fprintf(stderr, "Error in ue_sync_set_cell(): cell.nof_prb must be lower than initialized\n"); + return SRSLTE_ERROR; + } + + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + q->fft_size = srslte_symbol_sz(q->cell.nof_prb); + q->sf_len = SRSLTE_SF_LEN(q->fft_size); + q->agc_period = 0; + if (cell.id == 1000) { - /* If the cell id is unknown, enable CP detection on find */ + + /* If the cell is unkown, we search PSS/SSS in 5 ms */ + q->nof_recv_sf = 5; + + q->decode_sss_on_track = true; + + } else { + + /* If the cell is known, we work on a 1ms basis */ + q->nof_recv_sf = 1; + + q->decode_sss_on_track = true; + } + + q->frame_len = q->nof_recv_sf*q->sf_len; + + if(q->fft_size < 700 && q->decimate) { + q->decimate = 1; + } + + if(srslte_sync_resize(&q->sfind, q->frame_len, q->frame_len, q->fft_size)) { + fprintf(stderr, "Error initiating sync find\n"); + return SRSLTE_ERROR; + } + if (cell.id == 1000) { + if(srslte_sync_resize(&q->strack, q->frame_len, TRACK_FRAME_SIZE, q->fft_size)) { + fprintf(stderr, "Error initiating sync track\n"); + return SRSLTE_ERROR; + } + } else { + if(srslte_sync_resize(&q->strack, q->frame_len, SRSLTE_CP_LEN_NORM(1,q->fft_size), q->fft_size)) { + fprintf(stderr, "Error initiating sync track\n"); + return SRSLTE_ERROR; + } + } + + if (cell.id == 1000) { + /* If the cell id is unknown, enable CP detection on find */ // FIXME: CP detection not working very well. Not supporting Extended CP right now - srslte_sync_cp_en(&q->sfind, false); - srslte_sync_cp_en(&q->strack, false); + srslte_sync_cp_en(&q->sfind, false); + srslte_sync_cp_en(&q->strack, false); srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.8); srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1); - srslte_sync_cfo_i_detec_en(&q->sfind, false); + srslte_sync_cfo_i_detec_en(&q->sfind, false); - q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES; + q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES; srslte_sync_set_threshold(&q->sfind, 2.0); srslte_sync_set_threshold(&q->strack, 1.2); - + } else { srslte_sync_set_N_id_2(&q->sfind, cell.id%3); srslte_sync_set_N_id_2(&q->strack, cell.id%3); q->sfind.cp = cell.cp; q->strack.cp = cell.cp; - srslte_sync_cp_en(&q->sfind, false); - srslte_sync_cp_en(&q->strack, false); + srslte_sync_cp_en(&q->sfind, false); + srslte_sync_cp_en(&q->strack, false); + + srslte_sync_cfo_i_detec_en(&q->sfind, false); - srslte_sync_cfo_i_detec_en(&q->sfind, false); - srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1); srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1); /* In find phase and if the cell is known, do not average pss correlation - * because we only capture 1 subframe and do not know where the peak is. + * because we only capture 1 subframe and do not know where the peak is. */ - q->nof_avg_find_frames = 1; + q->nof_avg_find_frames = 1; srslte_sync_set_em_alpha(&q->sfind, 1); srslte_sync_set_threshold(&q->sfind, 3.0); - + srslte_sync_set_em_alpha(&q->strack, 0.2); srslte_sync_set_threshold(&q->strack, 1.2); } - + srslte_ue_sync_reset(q); - + ret = SRSLTE_SUCCESS; } - -clean_exit: - if (ret == SRSLTE_ERROR) { - srslte_ue_sync_free(q); - } - return ret; -} -uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t *q) { - return q->frame_len; + return ret; } -void srslte_ue_sync_free(srslte_ue_sync_t *q) { - if (q->do_agc) { - srslte_agc_free(&q->agc); - } - if (!q->file_mode) { - srslte_sync_free(&q->sfind); - srslte_sync_free(&q->strack); - } else { - srslte_filesource_free(&q->file_source); - } - bzero(q, sizeof(srslte_ue_sync_t)); -} void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, srslte_timestamp_t *timestamp) { memcpy(timestamp, &q->last_timestamp, sizeof(srslte_timestamp_t)); @@ -317,6 +380,8 @@ void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo) { srslte_sync_set_cfo(&q->strack, cfo/15000); } +void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, float cfo_tol) {} + float srslte_ue_sync_get_sfo(srslte_ue_sync_t *q) { return q->mean_sfo/5e-3; } @@ -448,7 +513,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { discard the offseted samples to align next frame */ if (q->next_rf_sample_offset > 0 && q->next_rf_sample_offset < MAX_TIME_OFFSET) { DEBUG("Positive time offset %d samples.\n", q->next_rf_sample_offset); - if (q->recv_callback(q->stream, dummy_offset_buffer, (uint32_t) q->next_rf_sample_offset, &q->last_timestamp) < 0) { + if (q->recv_callback(q->stream, dummy_offset_buffer, (uint32_t) q->next_rf_sample_offset, NULL) < 0) { fprintf(stderr, "Error receiving from USRP\n"); return SRSLTE_ERROR; } @@ -611,6 +676,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE /* Track PSS/SSS around the expected PSS position * In tracking phase, the subframe carrying the PSS is always the last one of the frame */ + switch(srslte_sync_find(&q->strack, input_buffer[0], q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, &track_idx)) @@ -649,7 +715,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE } if (q->correct_cfo) { for (int i=0;inof_rx_antennas;i++) { - srslte_cfo_correct(&q->sfind.cfocorr, + srslte_cfo_correct(&q->strack.cfocorr, input_buffer[i], input_buffer[i], -srslte_sync_get_cfo(&q->strack) / q->fft_size); diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index 08edcafe0..37dfecd93 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -36,22 +36,22 @@ #define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) #define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define MAX_SFLEN SRSLTE_SF_LEN(srslte_symbol_sz(max_prb)) -int srslte_ue_ul_init(srslte_ue_ul_t *q, - srslte_cell_t cell) +#define DEFAULT_CFO_TOL 50.0 // Hz + +int srslte_ue_ul_init(srslte_ue_ul_t *q, + uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - srslte_cell_isvalid(&cell)) + if (q != NULL) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_ue_ul_t)); - q->cell = cell; - - if (srslte_ofdm_tx_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { + if (srslte_ofdm_tx_init(&q->fft, SRSLTE_CP_NORM, max_prb)) { fprintf(stderr, "Error initiating FFT\n"); goto clean_exit; } @@ -60,41 +60,41 @@ int srslte_ue_ul_init(srslte_ue_ul_t *q, q->normalize_en = false; - if (srslte_cfo_init(&q->cfo, CURRENT_SFLEN)) { + if (srslte_cfo_init(&q->cfo, MAX_SFLEN)) { fprintf(stderr, "Error creating CFO object\n"); goto clean_exit; } - - srslte_cfo_set_tol(&q->cfo, 0); - - if (srslte_pusch_init(&q->pusch, q->cell)) { + + srslte_ue_ul_set_cfo_tol(q, DEFAULT_CFO_TOL); + + if (srslte_pusch_init_ue(&q->pusch, max_prb)) { fprintf(stderr, "Error creating PUSCH object\n"); goto clean_exit; } - if (srslte_pucch_init(&q->pucch, q->cell)) { + if (srslte_pucch_init(&q->pucch)) { fprintf(stderr, "Error creating PUSCH object\n"); goto clean_exit; } - if (srslte_softbuffer_tx_init(&q->softbuffer, q->cell.nof_prb)) { + if (srslte_softbuffer_tx_init(&q->softbuffer, max_prb)) { fprintf(stderr, "Error initiating soft buffer\n"); goto clean_exit; } - if (srslte_refsignal_ul_init(&q->signals, cell)) { + if (srslte_refsignal_ul_init(&q->signals, max_prb)) { fprintf(stderr, "Error initiating srslte_refsignal_ul\n"); goto clean_exit; } - q->sf_symbols = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_PRB(max_prb) * sizeof(cf_t)); if (!q->sf_symbols) { perror("malloc"); goto clean_exit; } - q->refsignal = srslte_vec_malloc(2 * SRSLTE_NRE * q->cell.nof_prb * sizeof(cf_t)); + q->refsignal = srslte_vec_malloc(2 * SRSLTE_NRE * max_prb * sizeof(cf_t)); if (!q->refsignal) { perror("malloc"); goto clean_exit; } - q->srs_signal = srslte_vec_malloc(SRSLTE_NRE * q->cell.nof_prb * sizeof(cf_t)); + q->srs_signal = srslte_vec_malloc(SRSLTE_NRE * max_prb * sizeof(cf_t)); if (!q->srs_signal) { perror("malloc"); goto clean_exit; @@ -102,8 +102,7 @@ int srslte_ue_ul_init(srslte_ue_ul_t *q, q->signals_pregenerated = false; ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", - cell.id, cell.nof_ports, cell.nof_prb); + fprintf(stderr, "Invalid parameters\n"); } clean_exit: @@ -115,7 +114,7 @@ clean_exit: void srslte_ue_ul_free(srslte_ue_ul_t *q) { if (q) { - srslte_ofdm_rx_free(&q->fft); + srslte_ofdm_tx_free(&q->fft); srslte_pusch_free(&q->pusch); srslte_pucch_free(&q->pucch); srslte_softbuffer_tx_free(&q->softbuffer); @@ -140,6 +139,54 @@ void srslte_ue_ul_free(srslte_ue_ul_t *q) { } } +int srslte_ue_ul_set_cell(srslte_ue_ul_t *q, + srslte_cell_t cell) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && srslte_cell_isvalid(&cell)) + { + if (q->cell.id != cell.id || q->cell.nof_prb == 0) { + memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + + if (srslte_ofdm_tx_set_prb(&q->fft, q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error resizing FFT\n"); + return SRSLTE_ERROR; + } + if (srslte_cfo_resize(&q->cfo, SRSLTE_SF_LEN_PRB(q->cell.nof_prb))) { + fprintf(stderr, "Error resizing CFO object\n"); + return SRSLTE_ERROR; + } + + srslte_ue_ul_set_cfo_tol(q, q->current_cfo_tol); + + if (srslte_pusch_set_cell(&q->pusch, q->cell)) { + fprintf(stderr, "Error resizing PUSCH object\n"); + return SRSLTE_ERROR; + } + if (srslte_pucch_set_cell(&q->pucch, q->cell)) { + fprintf(stderr, "Error resizing PUSCH object\n"); + return SRSLTE_ERROR; + } + if (srslte_refsignal_ul_set_cell(&q->signals, q->cell)) { + fprintf(stderr, "Error resizing srslte_refsignal_ul\n"); + return SRSLTE_ERROR; + } + q->signals_pregenerated = false; + } + ret = SRSLTE_SUCCESS; + } else { + fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + cell.id, cell.nof_ports, cell.nof_prb); + } + return ret; +} + +void srslte_ue_ul_set_cfo_tol(srslte_ue_ul_t *q, float tol) { + q->current_cfo_tol = tol; + srslte_cfo_set_tol(&q->cfo, tol/(15000.0*srslte_symbol_sz(q->cell.nof_prb))); +} + void srslte_ue_ul_set_cfo(srslte_ue_ul_t *q, float cur_cfo) { q->current_cfo = cur_cfo; } @@ -154,7 +201,7 @@ void srslte_ue_ul_set_normalization(srslte_ue_ul_t *q, bool enabled) q->normalize_en = enabled; } -/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while +/* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while * to execute, so shall be called once the final C-RNTI has been allocated for the session. * For the connection procedure, use srslte_pusch_encode_rnti() or srslte_pusch_decode_rnti() functions */ @@ -230,6 +277,14 @@ void pucch_encode_bits(srslte_uci_data_t *uci_data, srslte_pucch_format_t format pucch_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 1a } if (format >= SRSLTE_PUCCH_FORMAT_2) { + /* Append Differential CQI */ + memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); + uci_data->uci_cqi_len += uci_data->uci_dif_cqi_len; + + /* Append PMI */ + memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_pmi, uci_data->uci_pmi_len); + uci_data->uci_cqi_len += uci_data->uci_pmi_len; + srslte_uci_encode_cqi_pucch(uci_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits); if (format > SRSLTE_PUCCH_FORMAT_2) { pucch2_bits[0] = uci_data->uci_ack; @@ -295,7 +350,7 @@ int srslte_ue_ul_pucch_encode(srslte_ue_ul_t *q, srslte_uci_data_t uci_data, srslte_ofdm_tx_sf(&q->fft, q->sf_symbols, output_signal); if (q->cfo_en) { - srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); + srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); } if (q->normalize_en) { @@ -365,7 +420,7 @@ int srslte_ue_ul_srs_encode(srslte_ue_ul_t *q, uint32_t tti, cf_t *output_signal srslte_ofdm_tx_sf(&q->fft, q->sf_symbols, output_signal); if (q->cfo_en) { - srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); + srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); } if (q->normalize_en) { @@ -407,7 +462,7 @@ int srslte_ue_ul_pusch_encode_rnti_softbuffer(srslte_ue_ul_t *q, q->pusch_cfg.grant.n_prb_tilde, q->sf_symbols); } else { - + if (srslte_refsignal_dmrs_pusch_gen(&q->signals, q->pusch_cfg.grant.L_prb, q->pusch_cfg.sf_idx, q->pusch_cfg.grant.ncs_dmrs, @@ -434,7 +489,7 @@ int srslte_ue_ul_pusch_encode_rnti_softbuffer(srslte_ue_ul_t *q, srslte_ofdm_tx_sf(&q->fft, q->sf_symbols, output_signal); if (q->cfo_en) { - srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); + srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); } if (q->normalize_en) { diff --git a/lib/src/phy/utils/cexptab.c b/lib/src/phy/utils/cexptab.c index 47ff8ef96..0f9232e85 100644 --- a/lib/src/phy/utils/cexptab.c +++ b/lib/src/phy/utils/cexptab.c @@ -36,7 +36,7 @@ int srslte_cexptab_init(srslte_cexptab_t *h, uint32_t size) { uint32_t i; h->size = size; - h->tab = malloc(sizeof(cf_t) * size); + h->tab = malloc(sizeof(cf_t) * (1+size)); if (h->tab) { for (i = 0; i < size; i++) { h->tab[i] = cexpf(_Complex_I * 2 * M_PI * (float) i / size); diff --git a/lib/src/phy/utils/convolution.c b/lib/src/phy/utils/convolution.c index d3b852b76..f96bdd4a2 100644 --- a/lib/src/phy/utils/convolution.c +++ b/lib/src/phy/utils/convolution.c @@ -27,6 +27,7 @@ #include #include +#include #include "srslte/phy/dft/dft.h" #include "srslte/phy/utils/vector.h" @@ -34,14 +35,17 @@ int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_t filter_len) { + bzero(q, sizeof(srslte_conv_fft_cc_t)); + q->input_len = input_len; q->filter_len = filter_len; q->output_len = input_len+filter_len; + q->max_filter_len = filter_len; + q->max_input_len = input_len; q->input_fft = srslte_vec_malloc(sizeof(cf_t)*q->output_len); q->filter_fft = srslte_vec_malloc(sizeof(cf_t)*q->output_len); q->output_fft = srslte_vec_malloc(sizeof(cf_t)*q->output_len); - - + if (!q->input_fft || !q->filter_fft || !q->output_fft) { return SRSLTE_ERROR; } @@ -64,6 +68,34 @@ int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_ return SRSLTE_SUCCESS; } +int srslte_conv_fft_cc_replan(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_t filter_len) { + if (input_len > q->max_input_len || filter_len > q->max_filter_len) { + fprintf(stderr, "Error in conv_fft_cc_replan(): input_len and filter_len must be lower than initialized\n"); + return -1; + } + + q->input_len = input_len; + q->filter_len = filter_len; + q->output_len = input_len+filter_len; + + if (!q->input_fft || !q->filter_fft || !q->output_fft) { + return SRSLTE_ERROR; + } + if (srslte_dft_replan(&q->input_plan,q->output_len)) { + fprintf(stderr, "Error initiating input plan\n"); + return SRSLTE_ERROR; + } + if (srslte_dft_replan(&q->filter_plan,q->output_len)) { + fprintf(stderr, "Error initiating filter plan\n"); + return SRSLTE_ERROR; + } + if (srslte_dft_replan(&q->output_plan,q->output_len)) { + fprintf(stderr, "Error initiating output plan\n"); + return SRSLTE_ERROR; + } + return SRSLTE_SUCCESS; +} + void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q) { if (q->input_fft) { free(q->input_fft); diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index 3a5fdf9f1..42d4143f9 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -30,6 +30,7 @@ extern "C" { } #include "srslte/radio/radio.h" #include +#include namespace srslte { @@ -47,7 +48,7 @@ bool radio::init(char *args, char *devname) cur_tx_srate = 0; is_start_of_burst = true; - // Suppress radio stdout + // Suppress radio stdout srslte_rf_suppress_stdout(&rf_device); tx_adv_auto = true; @@ -60,7 +61,14 @@ bool radio::init(char *args, char *devname) } else { printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); } - + + if (args) { + strncpy(saved_args, args, 127); + } + if (devname) { + strncpy(saved_devname, devname, 127); + } + return true; } @@ -69,6 +77,16 @@ void radio::stop() srslte_rf_close(&rf_device); } +void radio::reset() +{ + printf("Resetting Radio...\n"); + srslte_rf_close(&rf_device); + sleep(3); + if (srslte_rf_open_devname(&rf_device, saved_devname, saved_args)) { + fprintf(stderr, "Error opening RF device\n"); + } +} + void radio::set_manual_calibration(rf_cal_t* calibration) { srslte_rf_cal_t tx_cal; @@ -102,11 +120,6 @@ void radio::set_tx_adv_neg(bool tx_adv_is_neg) { tx_adv_negative = tx_adv_is_neg; } -void radio::tx_offset(int offset_) -{ - offset = offset_; -} - bool radio::start_agc(bool tx_gain_same_rx) { if (srslte_rf_start_gain_thread(&rf_device, tx_gain_same_rx)) { @@ -167,6 +180,12 @@ bool radio::has_rssi() return srslte_rf_has_rssi(&rf_device); } +bool radio::is_first_of_burst() { + return is_start_of_burst; +} + +#define BLOCKING_TX true + bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) { void *iq_samples[4] = {(void *) zeros, (void *) zeros, (void *) zeros, (void *) zeros}; @@ -185,7 +204,7 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) save_trace(1, &tx_time_pad); srslte_rf_send_timed_multi(&rf_device, iq_samples, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, true, false); is_start_of_burst = false; - } + } } // Save possible end of burst time @@ -194,9 +213,10 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) save_trace(0, &tx_time); iq_samples[0] = buffer; - int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples+offset, tx_time.full_secs, tx_time.frac_secs, true, is_start_of_burst, false); - offset = 0; - is_start_of_burst = false; + int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples, + tx_time.full_secs, tx_time.frac_secs, + BLOCKING_TX, is_start_of_burst, false); + is_start_of_burst = false; if (ret > 0) { return true; } else { @@ -204,16 +224,6 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) } } -uint32_t radio::get_tti_len() -{ - return sf_len; -} - -void radio::set_tti_len(uint32_t sf_len_) -{ - sf_len = sf_len_; -} - void radio::tx_end() { if (!is_start_of_burst) { @@ -250,9 +260,13 @@ void radio::save_trace(uint32_t is_eob, srslte_timestamp_t *tx_time) { } } -void radio::set_rx_freq(float freq) +void radio::set_freq_offset(double freq) { + freq_offset = freq; +} + +void radio::set_rx_freq(double freq) { - rx_freq = srslte_rf_set_rx_freq(&rf_device, freq); + rx_freq = srslte_rf_set_rx_freq(&rf_device, freq+freq_offset); } void radio::set_rx_gain(float gain) @@ -265,19 +279,19 @@ double radio::set_rx_gain_th(float gain) return srslte_rf_set_rx_gain_th(&rf_device, gain); } -void radio::set_master_clock_rate(float rate) +void radio::set_master_clock_rate(double rate) { srslte_rf_set_master_clock_rate(&rf_device, rate); } -void radio::set_rx_srate(float srate) +void radio::set_rx_srate(double srate) { srslte_rf_set_rx_srate(&rf_device, srate); } -void radio::set_tx_freq(float freq) +void radio::set_tx_freq(double freq) { - tx_freq = srslte_rf_set_tx_freq(&rf_device, freq); + tx_freq = srslte_rf_set_tx_freq(&rf_device, freq+freq_offset); } void radio::set_tx_gain(float gain) @@ -285,12 +299,12 @@ void radio::set_tx_gain(float gain) srslte_rf_set_tx_gain(&rf_device, gain); } -float radio::get_rx_freq() +double radio::get_rx_freq() { return rx_freq; } -float radio::get_tx_freq() +double radio::get_tx_freq() { return tx_freq; } @@ -305,7 +319,7 @@ float radio::get_rx_gain() return srslte_rf_get_rx_gain(&rf_device); } -void radio::set_tx_srate(float srate) +void radio::set_tx_srate(double srate) { cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, srate); burst_preamble_samples = (uint32_t) (cur_tx_srate * burst_preamble_sec); @@ -343,25 +357,9 @@ void radio::set_tx_srate(float srate) nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec); } } else if (!strcmp(srslte_rf_name(&rf_device), "uhd_x300")) { - - double srate_khz = round(cur_tx_srate/1e3); - if (srate_khz == 1.92e3) { - nsamples = 50; - } else if (srate_khz == 3.84e3) { - nsamples = 65; - } else if (srate_khz == 5.76e3) { - nsamples = 75; - } else if (srate_khz == 11.52e3) { - nsamples = 89; - } else if (srate_khz == 15.36e3) { - nsamples = 86; - } else if (srate_khz == 23.04e3) { - nsamples = 110; - } else { - /* Interpolate from known values */ - printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); - nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec); - } + + // In X300 TX/RX offset is independent of sampling rate + nsamples = 45; } else if (!strcmp(srslte_rf_name(&rf_device), "bladerf")) { double srate_khz = round(cur_tx_srate/1e3); @@ -392,8 +390,6 @@ void radio::set_tx_srate(float srate) // Calculate TX advance in seconds from samples and sampling rate tx_adv_sec = nsamples/cur_tx_srate; - - printf("Setting TX/RX offset %d samples, %.2f us\n", nsamples, tx_adv_sec*1e6); } void radio::start_rx() diff --git a/lib/src/radio/radio_multi.cc b/lib/src/radio/radio_multi.cc index c8de57f46..3888a77f3 100644 --- a/lib/src/radio/radio_multi.cc +++ b/lib/src/radio/radio_multi.cc @@ -14,9 +14,11 @@ bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname burst_preamble_samples = 0; burst_preamble_time_rounded = 0; cur_tx_srate = 0; - is_start_of_burst = true; - - + is_start_of_burst = true; + + // Suppress radio stdout + srslte_rf_suppress_stdout(&rf_device); + tx_adv_auto = true; // Set default preamble length each known device // We distinguish by device family, maybe we should calibrate per device @@ -27,7 +29,14 @@ bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname } else { printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); } - + + if (args) { + strncpy(saved_args, args, 127); + } + if (devname) { + strncpy(saved_devname, devname, 127); + } + return true; } diff --git a/lib/src/upper/gw.cc b/lib/src/upper/gw.cc deleted file mode 100644 index 685803a4d..000000000 --- a/lib/src/upper/gw.cc +++ /dev/null @@ -1,289 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - - -#include "srslte/upper/gw.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace srslte { - -gw::gw() - :if_up(false) -{} - -void gw::init(srsue::pdcp_interface_gw *pdcp_, srsue::rrc_interface_gw *rrc_, srsue::ue_interface *ue_, log *gw_log_, uint32_t lcid_) -{ - pool = byte_buffer_pool::get_instance(); - pdcp = pdcp_; - rrc = rrc_; - ue = ue_; - gw_log = gw_log_; - lcid = lcid_; - run_enable = true; - - gettimeofday(&metrics_time[1], NULL); - dl_tput_bytes = 0; - ul_tput_bytes = 0; -} - -void gw::stop() -{ - if(run_enable) - { - run_enable = false; - if(if_up) - { - close(tun_fd); - - // 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(); - } - - // TODO: tear down TUN device? - } -} - -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; - - m.dl_tput_mbps = (dl_tput_bytes*8/(double)1e6)/secs; - m.ul_tput_mbps = (ul_tput_bytes*8/(double)1e6)/secs; - gw_log->info("RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", - m.dl_tput_mbps, m.ul_tput_mbps); - - memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval)); - dl_tput_bytes = 0; - ul_tput_bytes = 0; -} - -/******************************************************************************* - PDCP interface -*******************************************************************************/ -void gw::write_pdu(uint32_t lcid, 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()); - dl_tput_bytes += pdu->N_bytes; - 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"); - } - } - pool->deallocate(pdu); -} - -/******************************************************************************* - NAS interface -*******************************************************************************/ -error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) -{ - if(!if_up) - { - if(init_if(err_str)) - { - gw_log->error("init_if failed\n"); - return(ERROR_CANT_START); - } - } - - // Setup the IP address - sock = socket(AF_INET, SOCK_DGRAM, 0); - ifr.ifr_addr.sa_family = AF_INET; - ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip_addr); - if(0 > ioctl(sock, SIOCSIFADDR, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to set socket address: %s\n", err_str); - close(tun_fd); - return(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(0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to set socket netmask: %s\n", err_str); - close(tun_fd); - return(ERROR_CANT_START); - } - - // Setup a thread to receive packets from the TUN device - start(GW_THREAD_PRIO); - - return(ERROR_NONE); -} - -error_t gw::init_if(char *err_str) -{ - if(if_up) - { - return(ERROR_ALREADY_STARTED); - } - - char dev[IFNAMSIZ] = "tun_srsue"; - - // Construct the TUN device - tun_fd = open("/dev/net/tun", O_RDWR); - gw_log->info("TUN file descriptor = %d\n", tun_fd); - if(0 > tun_fd) - { - err_str = strerror(errno); - gw_log->debug("Failed to open TUN device: %s\n", err_str); - return(ERROR_CANT_START); - } - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ); - if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to set TUN device name: %s\n", err_str); - close(tun_fd); - return(ERROR_CANT_START); - } - - // Bring up the interface - sock = socket(AF_INET, SOCK_DGRAM, 0); - if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to bring up socket: %s\n", err_str); - close(tun_fd); - return(ERROR_CANT_START); - } - ifr.ifr_flags |= IFF_UP | IFF_RUNNING; - if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to set socket flags: %s\n", err_str); - close(tun_fd); - return(ERROR_CANT_START); - } - - if_up = true; - - return(ERROR_NONE); -} - -/********************/ -/* GW Receive */ -/********************/ -void gw::run_thread() -{ - struct iphdr *ip_pkt; - uint32 idx = 0; - int32 N_bytes; - byte_buffer_t *pdu = pool_allocate; - - gw_log->info("GW IP packet receiver thread run_enable\n"); - - running = true; - while(run_enable) - { - if (SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET > idx) { - N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx); - } else { - gw_log->error("GW pdu buffer full - gw receive thread exiting.\n"); - gw_log->console("GW pdu buffer full - gw receive thread exiting.\n"); - break; - } - gw_log->debug("Read %d bytes from TUN fd=%d, idx=%d\n", N_bytes, tun_fd, idx); - if(N_bytes > 0) - { - pdu->N_bytes = idx + N_bytes; - ip_pkt = (struct iphdr*)pdu->msg; - - // Warning: Accept only IPv4 packets - if (ip_pkt->version == 4) { - // Check if entire packet was received - if(ntohs(ip_pkt->tot_len) == pdu->N_bytes) - { - gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU"); - - while(run_enable && (!rrc->rrc_connected() || !rrc->have_drb())) { - rrc->rrc_connect(); - usleep(1000); - } - - if (!run_enable) { - break; - } - - // Send PDU directly to PDCP - pdu->set_timestamp(); - ul_tput_bytes += pdu->N_bytes; - pdcp->write_sdu(lcid, pdu); - - do { - pdu = pool_allocate; - if (!pdu) { - printf("Not enough buffers in pool\n"); - usleep(100000); - } - } while(!pdu); - idx = 0; - }else{ - idx += N_bytes; - } - } - }else{ - gw_log->error("Failed to read from TUN interface - gw receive thread exiting.\n"); - gw_log->console("Failed to read from TUN interface - gw receive thread exiting.\n"); - break; - } - } - running = false; - gw_log->info("GW IP receiver thread exiting.\n"); -} - -} // namespace srsue diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 5f4afbd62..0acc7f6bd 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -65,6 +65,15 @@ void pdcp::reset() /******************************************************************************* RRC/GW interface *******************************************************************************/ +bool pdcp::is_drb_enabled(uint32_t lcid) +{ + 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 false; + } + return pdcp_array[lcid].is_active(); +} + void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { if(valid_lcid(lcid)) diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index 0cc551a1f..f506ebc63 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -65,7 +65,10 @@ void rlc::reset_metrics() void rlc::stop() { - reset(); + for(uint32_t i=0; istop(); + rlc = NULL; +} void rlc_entity::empty_queue() { diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index e3bef0a99..627752494 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -66,6 +66,11 @@ void rlc_tm::reset() empty_queue(); } +void rlc_tm::stop() +{ + reset(); +} + rlc_mode_t rlc_tm::get_mode() { return RLC_MODE_TM; diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index 3d6bb9553..b2697178c 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -62,7 +62,8 @@ void rlc_um::init(srslte::log *log_, pdcp = pdcp_; rrc = rrc_; mac_timers = mac_timers_; - reordering_timeout_id = mac_timers->get_unique_id(); + reordering_timer_id = mac_timers->timer_get_unique_id(); + reordering_timer = mac_timers->timer_get(reordering_timer_id); } void rlc_um::configure(srslte_rlc_config_t cnfg_) @@ -102,6 +103,12 @@ void rlc_um::empty_queue() { } } +void rlc_um::stop() +{ + reset(); + mac_timers->timer_release_id(reordering_timer_id); +} + void rlc_um::reset() { @@ -119,7 +126,7 @@ void rlc_um::reset() if(tx_sdu) tx_sdu->reset(); if(mac_timers) - mac_timers->get(reordering_timeout_id)->stop(); + reordering_timer->stop(); // Drop all messages in RX window std::map::iterator it; @@ -203,7 +210,7 @@ void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes) void rlc_um::timer_expired(uint32_t timeout_id) { - if(reordering_timeout_id == timeout_id) + if(reordering_timer_id == timeout_id) { pthread_mutex_lock(&mutex); @@ -221,11 +228,11 @@ void rlc_um::timer_expired(uint32_t timeout_id) reassemble_rx_sdus(); log->debug("Finished reassemble from timeout id=%d\n", timeout_id); } - mac_timers->get(reordering_timeout_id)->stop(); + reordering_timer->stop(); if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) { - mac_timers->get(reordering_timeout_id)->set(this, cfg.t_reordering); - mac_timers->get(reordering_timeout_id)->run(); + reordering_timer->set(this, cfg.t_reordering); + reordering_timer->run(); vr_ux = vr_uh; } @@ -236,7 +243,7 @@ void rlc_um::timer_expired(uint32_t timeout_id) bool rlc_um::reordering_timeout_running() { - return mac_timers->get(reordering_timeout_id)->is_running(); + return reordering_timer->is_running(); } /**************************************************************************** @@ -398,20 +405,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) log->debug("Finished reassemble from received PDU\n"); // Update reordering variables and timers - if(mac_timers->get(reordering_timeout_id)->is_running()) + if(reordering_timer->is_running()) { if(RX_MOD_BASE(vr_ux) <= RX_MOD_BASE(vr_ur) || (!inside_reordering_window(vr_ux) && vr_ux != vr_uh)) { - mac_timers->get(reordering_timeout_id)->stop(); + reordering_timer->stop(); } } - if(!mac_timers->get(reordering_timeout_id)->is_running()) + if(!reordering_timer->is_running()) { if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) { - mac_timers->get(reordering_timeout_id)->set(this, cfg.t_reordering); - mac_timers->get(reordering_timeout_id)->run(); + reordering_timer->set(this, cfg.t_reordering); + reordering_timer->run(); vr_ux = vr_uh; } } @@ -506,11 +513,20 @@ void rlc_um::reassemble_rx_sdus() } // Handle last segment - memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); - rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; - log->debug("Writting last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n", - vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); - vr_ur_in_rx_sdu = vr_ur; + if (rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES && + rx_window[vr_ur].buf->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES && + rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES) + { + + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); + rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; + log->debug("Writting last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n", + vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); + } else { + log->error("Out of bounds while reassembling SDU buffer in UM: sdu_len=%d, window_buffer_len=%d, vr_ur=%d\n", + rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur); + } + vr_ur_in_rx_sdu = vr_ur; if(rlc_um_end_aligned(rx_window[vr_ur].header.fi)) { if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index c7ab2aa74..7a37d0d5d 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -38,11 +38,12 @@ class mac_dummy_timers :public srslte::mac_interface_timers { public: - srslte::timers::timer* get(uint32_t timer_id) + srslte::timers::timer* timer_get(uint32_t timer_id) { return &t; } - uint32_t get_unique_id(){return 0;} + uint32_t timer_get_unique_id(){return 0;} + void timer_release_id(uint32_t id){} private: srslte::timers::timer t; diff --git a/lib/test/upper/rlc_um_test.cc b/lib/test/upper/rlc_um_test.cc index 739c9ebf8..0894a2a8b 100644 --- a/lib/test/upper/rlc_um_test.cc +++ b/lib/test/upper/rlc_um_test.cc @@ -38,16 +38,16 @@ class mac_dummy_timers :public srslte::mac_interface_timers { public: - srslte::timers::timer* get(uint32_t timer_id) + srslte::timers::timer* timer_get(uint32_t timer_id) { return &t; } - uint32_t get_unique_id(){return 0;} + uint32_t timer_get_unique_id(){return 0;} void step() { t.step(); } - + void timer_release_id(uint32_t timer_id) {} private: srslte::timers::timer t; }; @@ -205,8 +205,8 @@ void loss_test() } // Step the reordering timer until expiry - while(!timers.get(1)->is_expired()) - timers.get(1)->step(); + while(!timers.timer_get(1)->is_expired()) + timers.timer_get(1)->step(); assert(NBUFS-1 == tester.n_sdus); } diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 1c54cfc45..44e546116 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -58,8 +58,8 @@ drb_config = drb.conf ##################################################################### [rf] dl_earfcn = 3400 -tx_gain = 80 -rx_gain = 60 +tx_gain = 70 +rx_gain = 40 #device_name = auto #device_args = auto @@ -98,7 +98,8 @@ filename = /tmp/enb.pcap # Logging layers: phy, mac, rlc, pdcp, rrc, nas, gtpu, usim, all # Logging levels: debug, info, warning, error, none # -# filename: File path to use for log output +# filename: File path to use for log output. Can be set to stdout +# to print logs to standard output ##################################################################### [log] all_level = info @@ -122,8 +123,8 @@ enable = false #pdsch_mcs = -1 #pdsch_max_mcs = -1 #pusch_mcs = -1 -#pusch_max_mcs = -1 -nof_ctrl_symbols = 2 +pusch_max_mcs = 16 +nof_ctrl_symbols = 3 ##################################################################### # Expert configuration options diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index b28d12ab4..7b1681cd6 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -139,41 +139,49 @@ typedef struct { *******************************************************************************/ class enb - :public enb_metrics_interface -{ + :public enb_metrics_interface { public: - static enb* get_instance(void); + static enb *get_instance(void); + static void cleanup(void); bool init(all_args_t *args_); + void stop(); + void start_plot(); - + static void rf_msg(srslte_rf_error_t error); + void handle_rf_msg(srslte_rf_error_t error); // eNodeB metrics interface bool get_metrics(enb_metrics_t &m); void pregenerate_signals(bool enable); - + private: static enb *instance; + enb(); + virtual ~enb(); - srslte::radio radio; - srsenb::phy phy; - srsenb::mac mac; - srslte::mac_pcap mac_pcap; - srsenb::rlc rlc; - srsenb::pdcp pdcp; - srsenb::rrc rrc; - srsenb::gtpu gtpu; - srsenb::s1ap s1ap; - - srslte::logger_file logger; + srslte::radio radio; + srsenb::phy phy; + srsenb::mac mac; + srslte::mac_pcap mac_pcap; + srsenb::rlc rlc; + srsenb::pdcp pdcp; + srsenb::rrc rrc; + srsenb::gtpu gtpu; + srsenb::s1ap s1ap; + + srslte::logger_stdout logger_stdout; + srslte::logger_file logger_file; + srslte::logger *logger; + srslte::log_filter rf_log; std::vector phy_log; srslte::log_filter mac_log; diff --git a/srsenb/hdr/mac/mac.h b/srsenb/hdr/mac/mac.h index 97be1825b..d71245e89 100644 --- a/srsenb/hdr/mac/mac.h +++ b/srsenb/hdr/mac/mac.h @@ -102,34 +102,18 @@ public: int rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue); bool process_pdus(); - - void timer_expired(uint32_t timer_id); - - srslte::timers::timer* get(uint32_t timer_id); - u_int32_t get_unique_id(); - + + // Interface for upper-layer timers + srslte::timers::timer* timer_get(uint32_t timer_id); + void timer_release_id(uint32_t timer_id); + u_int32_t timer_get_unique_id(); + uint32_t get_current_tti(); void get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]); - - enum { - HARQ_RTT, - TIME_ALIGNMENT, - CONTENTION_TIMER, - BSR_TIMER_PERIODIC, - BSR_TIMER_RETX, - PHR_TIMER_PERIODIC, - PHR_TIMER_PROHIBIT, - NOF_MAC_TIMERS - } mac_timers_t; - - static const int MAC_NOF_UPPER_TIMERS = 20; - + private: - void log_step_ul(uint32_t tti); - void log_step_dl(uint32_t tti); - - static const int MAX_LOCATIONS = 20; + static const int MAX_LOCATIONS = 20; static const uint32_t cfi = 3; srslte_dci_location_t locations[MAX_LOCATIONS]; @@ -192,21 +176,18 @@ private: /* Class to run upper-layer timers with normal priority */ - class upper_timers : public thread { - public: - upper_timers() : timers_db(MAC_NOF_UPPER_TIMERS),ttisync(10240) {start();} + class timer_thread : public thread { + public: + timer_thread(srslte::timers *t) : ttisync(10240),timers(t),running(false) {start();} void tti_clock(); void stop(); - void reset(); - srslte::timers::timer* get(uint32_t timer_id); - uint32_t get_unique_id(); private: void run_thread(); - srslte::timers timers_db; srslte::tti_sync_cv ttisync; + srslte::timers *timers; bool running; }; - upper_timers upper_timers_thread; + timer_thread timers_thread; /* Class to process MAC PDUs from DEMUX unit */ class pdu_process : public thread { diff --git a/srsenb/hdr/mac/scheduler.h b/srsenb/hdr/mac/scheduler.h index 66f8998c1..231239285 100644 --- a/srsenb/hdr/mac/scheduler.h +++ b/srsenb/hdr/mac/scheduler.h @@ -68,7 +68,7 @@ public: /* Virtual methods for user metric calculation */ virtual void new_tti(std::map &ue_db, uint32_t nof_rb, uint32_t tti) = 0; virtual ul_harq_proc* get_user_allocation(sched_ue *user) = 0; - virtual void update_allocation(ul_harq_proc::ul_alloc_t alloc) = 0; + virtual void update_allocation(ul_harq_proc::ul_alloc_t alloc) = 0; }; @@ -80,7 +80,8 @@ public: ************************************************************/ sched(); - + ~sched(); + void init(rrc_interface_mac *rrc, srslte::log *log); void set_metric(metric_dl *dl_metric, metric_ul *ul_metric); int cell_cfg(cell_cfg_t *cell_cfg); diff --git a/srsenb/hdr/mac/scheduler_metric.h b/srsenb/hdr/mac/scheduler_metric.h index b9d515ade..eda0b31ed 100644 --- a/srsenb/hdr/mac/scheduler_metric.h +++ b/srsenb/hdr/mac/scheduler_metric.h @@ -65,7 +65,7 @@ class ul_metric_rr : public sched::metric_ul public: void new_tti(std::map &ue_db, uint32_t nof_rb, uint32_t tti); ul_harq_proc* get_user_allocation(sched_ue *user); - void update_allocation(ul_harq_proc::ul_alloc_t alloc); + void update_allocation(ul_harq_proc::ul_alloc_t alloc); private: const static int MAX_PRB = 100; diff --git a/srsenb/hdr/mac/scheduler_ue.h b/srsenb/hdr/mac/scheduler_ue.h index b59461140..3653ff65c 100644 --- a/srsenb/hdr/mac/scheduler_ue.h +++ b/srsenb/hdr/mac/scheduler_ue.h @@ -42,7 +42,6 @@ public: // used by sched_metric uint32_t ue_idx; - bool has_pusch; bool has_pucch; typedef struct { @@ -116,7 +115,7 @@ public: bool needs_cqi(uint32_t tti, bool will_send = false); uint32_t get_max_retx(); - bool get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32_t *L); + bool get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2]); bool pucch_sr_collision(uint32_t current_tti, uint32_t n_cce); uint32_t get_pending_ul_old_data(); diff --git a/srsenb/hdr/mac/ue.h b/srsenb/hdr/mac/ue.h index 5805e5472..b879d040b 100644 --- a/srsenb/hdr/mac/ue.h +++ b/srsenb/hdr/mac/ue.h @@ -38,7 +38,7 @@ namespace srsenb { -class ue : public srslte::read_pdu_interface, +class ue : public srslte::read_pdu_interface, public srslte::pdu_queue::process_callback { public: diff --git a/srsenb/hdr/phy/phch_common.h b/srsenb/hdr/phy/phch_common.h index ae396ae0e..00a59d969 100644 --- a/srsenb/hdr/phy/phch_common.h +++ b/srsenb/hdr/phy/phch_common.h @@ -54,6 +54,7 @@ public: phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) { + nof_mutex = 0; max_mutex = max_mutex_; params.max_prach_offset_us = 20; } diff --git a/srsenb/hdr/phy/phch_worker.h b/srsenb/hdr/phy/phch_worker.h index 2f0f80f41..906e8b9d0 100644 --- a/srsenb/hdr/phy/phch_worker.h +++ b/srsenb/hdr/phy/phch_worker.h @@ -42,7 +42,8 @@ public: phch_worker(); void init(phch_common *phy, srslte::log *log_h); - void reset(); + void stop(); + void reset(); cf_t *get_buffer_rx(); void set_time(uint32_t tti, uint32_t tx_mutex_cnt, srslte_timestamp_t tx_time); @@ -83,7 +84,9 @@ private: /* Common objects */ srslte::log *log_h; phch_common *phy; - bool initiated; + bool initiated; + bool running; + cf_t *signal_buffer_rx; cf_t *signal_buffer_tx; uint32_t tti_rx, tti_tx, tti_sched_ul, sf_rx, sf_tx, sf_sched_ul, tx_mutex_cnt; diff --git a/srsenb/hdr/upper/gtpu.h b/srsenb/hdr/upper/gtpu.h index 9ad9441fa..6ec371655 100644 --- a/srsenb/hdr/upper/gtpu.h +++ b/srsenb/hdr/upper/gtpu.h @@ -75,7 +75,7 @@ public: void stop(); // gtpu_interface_rrc - void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in); + void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in); void rem_bearer(uint16_t rnti, uint32_t lcid); void rem_user(uint16_t rnti); @@ -86,7 +86,7 @@ public: private: static const int THREAD_PRIO = 7; static const int GTPU_PORT = 2152; - srslte::byte_buffer_pool *pool; + srslte::byte_buffer_pool *pool; bool running; bool run_enable; @@ -98,11 +98,13 @@ private: typedef struct{ uint32_t teids_in[SRSENB_N_RADIO_BEARERS]; uint32_t teids_out[SRSENB_N_RADIO_BEARERS]; + uint32_t spgw_addrs[SRSENB_N_RADIO_BEARERS]; }bearer_map; std::map rnti_bearers; - srslte_netsink_t snk; - srslte_netsource_t src; + // Socket file descriptors + int snk_fd; + int src_fd; void run_thread(); diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h index 49a02d0b9..e0b9dd158 100644 --- a/srsenb/hdr/upper/rrc.h +++ b/srsenb/hdr/upper/rrc.h @@ -195,6 +195,9 @@ public: bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e); bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); + void setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos, + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out, + LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu); bool release_erabs(); void notify_s1ap_ue_ctxt_setup_complete(); diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index 1bd7240a2..82b4e8145 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -26,6 +26,7 @@ #include #include +#include #include "enb.h" namespace srsenb { @@ -45,6 +46,7 @@ enb* enb::get_instance(void) void enb::cleanup(void) { srslte_dft_exit(); + srslte::byte_buffer_pool::cleanup(); boost::mutex::scoped_lock lock(enb_instance_mutex); if(NULL != instance) { delete instance; @@ -61,33 +63,38 @@ enb::enb() enb::~enb() { - srslte::byte_buffer_pool::cleanup(); } bool enb::init(all_args_t *args_) { args = args_; - logger.init(args->log.filename); - rf_log.init("RF ", &logger); + if (!args->log.filename.compare("stdout")) { + logger = &logger_stdout; + } else { + logger_file.init(args->log.filename); + logger_file.log("\n\n"); + logger = &logger_file; + } + + rf_log.init("RF ", logger); // Create array of pointers to phy_logs for (int i=0;iexpert.phy.nof_phy_threads;i++) { srslte::log_filter *mylog = new srslte::log_filter; char tmp[16]; sprintf(tmp, "PHY%d",i); - mylog->init(tmp, &logger, true); + mylog->init(tmp, logger, true); phy_log.push_back((void*) mylog); } - mac_log.init("MAC ", &logger, true); - rlc_log.init("RLC ", &logger); - pdcp_log.init("PDCP", &logger); - rrc_log.init("RRC ", &logger); - gtpu_log.init("GTPU", &logger); - s1ap_log.init("S1AP", &logger); + mac_log.init("MAC ", logger, true); + rlc_log.init("RLC ", logger); + pdcp_log.init("PDCP", logger); + rrc_log.init("RRC ", logger); + gtpu_log.init("GTPU", logger); + s1ap_log.init("S1AP", logger); // Init logs - logger.log("\n\n"); rf_log.set_level(srslte::LOG_LEVEL_INFO); for (int i=0;iexpert.phy.nof_phy_threads;i++) { ((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level)); @@ -221,15 +228,15 @@ void enb::stop() { if(started) { - mac.stop(); + gtpu.stop(); phy.stop(); - usleep(1e5); + mac.stop(); + usleep(100000); rlc.stop(); pdcp.stop(); - gtpu.stop(); rrc.stop(); - + usleep(1e5); if(args->pcap.enable) { diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index 63d189c20..6c8458540 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -42,7 +42,8 @@ namespace srsenb { -mac::mac() : timers_db((uint32_t) NOF_MAC_TIMERS), +mac::mac() : timers_db(128), + timers_thread(&timers_db), rar_pdu_msg(sched_interface::MAX_RAR_LIST), pdu_process_thread(this) { @@ -83,19 +84,23 @@ bool mac::init(mac_args_t *args_, srslte_cell_t *cell_, phy_interface_mac *phy, reset(); started = true; - } + } + return started; } void mac::stop() { + for (uint32_t i=0;iadd_rnti(SRSLTE_SIRNTI); - - /* Setup P-RNTI in PHY */ - phy_h->add_rnti(SRSLTE_PRNTI); - - /* Setup RA-RNTI in PHY */ - for (int i=0;i<10;i++) { - phy_h->add_rnti(1+i); - } } -uint32_t mac::get_unique_id() -{ - return upper_timers_thread.get_unique_id(); -} - -/* Front-end to upper-layer timers */ -srslte::timers::timer* mac::get(uint32_t timer_id) -{ - return upper_timers_thread.get(timer_id); -} - - void mac::start_pcap(srslte::mac_pcap* pcap_) { pcap = pcap_; @@ -421,7 +403,7 @@ int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv) int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) { - log_step_dl(tti); + log_h->step(tti); if (!started) { return 0; @@ -459,8 +441,7 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) dl_sched_res->sched_grants[n].data = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu, sched_result.data[i].nof_pdu_elems, sched_result.data[i].tbs); - srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.data[i].tbs); - + if (pcap) { pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, rnti, true, tti); } @@ -480,7 +461,6 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) // Set softbuffer (there are no retx in RAR but a softbuffer is required) dl_sched_res->sched_grants[n].softbuffer = &rar_softbuffer_tx; - srslte_softbuffer_tx_reset_tbs(&rar_softbuffer_tx, sched_result.rar[i].tbs); // TBS is usually 54-bit // Assemble PDU dl_sched_res->sched_grants[n].data = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs); @@ -503,9 +483,6 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) // Set softbuffer if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) { dl_sched_res->sched_grants[n].softbuffer = &bcch_softbuffer_tx[sched_result.bc[i].index]; - if (sched_result.bc[i].dci.rv_idx == 0) { - srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.bc[i].tbs*8); - } dl_sched_res->sched_grants[n].data = assemble_si(sched_result.bc[i].index); #ifdef WRITE_SIB_PCAP if (pcap) { @@ -514,7 +491,6 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) #endif } else { dl_sched_res->sched_grants[n].softbuffer = &pcch_softbuffer_tx; - srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.bc[i].tbs*8); dl_sched_res->sched_grants[n].data = pcch_payload_buffer; rlc_h->read_pdu_pcch(pcch_payload_buffer, pcch_payload_buffer_len); @@ -568,8 +544,8 @@ uint8_t* mac::assemble_si(uint32_t index) int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) { - - log_step_ul(tti); + + log_h->step(tti); if (!started) { return 0; @@ -626,66 +602,61 @@ int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) return SRSLTE_SUCCESS; } -void mac::log_step_ul(uint32_t tti) +void mac::tti_clock() { - int tti_ul = tti-8; - if (tti_ul < 0) { - tti_ul += 10240; - } - log_h->step(tti_ul); + timers_thread.tti_clock(); } -void mac::log_step_dl(uint32_t tti) + + + +/******************************************************** + * + * Interface for upper layer timers + * + *******************************************************/ +uint32_t mac::timer_get_unique_id() { - int tti_dl = tti-4; - if (tti_dl < 0) { - tti_dl += 10240; - } - log_h->step(tti_dl); + return timers_db.get_unique_id(); } -void mac::tti_clock() +void mac::timer_release_id(uint32_t timer_id) +{ + timers_db.release_id(timer_id); +} + +/* Front-end to upper-layer timers */ +srslte::timers::timer* mac::timer_get(uint32_t timer_id) { - upper_timers_thread.tti_clock(); + return timers_db.get(timer_id); } + + /******************************************************** * - * Class to run upper-layer timers with normal priority + * Class to run timers with normal priority * *******************************************************/ -void mac::upper_timers::run_thread() +void mac::timer_thread::run_thread() { running=true; ttisync.set_producer_cntr(0); ttisync.resync(); while(running) { ttisync.wait(); - timers_db.step_all(); + timers->step_all(); } } -srslte::timers::timer* mac::upper_timers::get(uint32_t timer_id) -{ - return timers_db.get(timer_id%MAC_NOF_UPPER_TIMERS); -} - -uint32_t mac::upper_timers::get_unique_id() -{ - return timers_db.get_unique_id(); -} -void mac::upper_timers::stop() +void mac::timer_thread::stop() { running=false; ttisync.increase(); wait_thread_finish(); } -void mac::upper_timers::reset() -{ - timers_db.stop_all(); -} -void mac::upper_timers::tti_clock() +void mac::timer_thread::tti_clock() { ttisync.increase(); } diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index 73dbc2d41..801b68d38 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -20,11 +20,18 @@ namespace srsenb { *******************************************************/ sched::sched() { + current_tti = 0; log_h = NULL; pthread_mutex_init(&mutex, NULL); reset(); } +sched::~sched() +{ + srslte_regs_free(®s); + pthread_mutex_destroy(&mutex); +} + void sched::init(rrc_interface_mac *rrc_, srslte::log* log) { sched_cfg.pdsch_max_mcs = 28; @@ -39,6 +46,7 @@ void sched::init(rrc_interface_mac *rrc_, srslte::log* log) int sched::reset() { + bzero(pending_msg3, sizeof(pending_msg3_t)*10); bzero(pending_rar, sizeof(sched_rar_t)*SCHED_MAX_PENDING_RAR); bzero(pending_sibs, sizeof(sched_sib_t)*MAX_SIBS); ue_db.clear(); @@ -611,6 +619,7 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]) tbs, user->get_pending_dl_new_data(current_tti)); } } else { + h->reset(); Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id()); } } @@ -692,7 +701,6 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched sched_ue *user = (sched_ue*) &iter->second; uint16_t rnti = (uint16_t) iter->first; - user->has_pusch = false; user->has_pucch = false; ul_harq_proc *h = user->get_ul_harq(current_tti); @@ -718,15 +726,12 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched sched_ue *user = (sched_ue*) &iter->second; uint16_t rnti = (uint16_t) iter->first; uint32_t prb_idx[2] = {0, 0}; - uint32_t L = 0; - if (user->get_pucch_sched(current_tti, prb_idx, &L)) { + if (user->get_pucch_sched(current_tti, prb_idx)) { user->has_pucch = true; - // allocate PUCCH if no PUSCH for user - if (!user->has_pusch) { - for (int i=0;i<2;i++) { - ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], L}; - ul_metric->update_allocation(pucch); - } + // allocate PUCCH + for (int i=0;i<2;i++) { + ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], 1}; + ul_metric->update_allocation(pucch); } } } @@ -778,6 +783,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched user->get_locations(current_cfi, sf_idx), aggr_level)) { + h->reset(); log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d\n", rnti, h->get_id(), aggr_level); sched_result->pusch[nof_dci_elems].needs_pdcch = false; @@ -799,22 +805,22 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched user->unset_sr(); } - log_h->info("SCHED: %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=%d,%d, n_rtx=%d, tbs=%d, bsr=%d (%d-%d)\n", + log_h->info("SCHED: %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=(%d,%d), n_rtx=%d, tbs=%d, bsr=%d (%d-%d)\n", is_rar?"RAR":"UL", is_newtx?"tx":"retx", rnti, h->get_id(), sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce, - alloc.RB_start, alloc.L, h->nof_retx(), sched_result->pusch[nof_dci_elems].tbs, + alloc.RB_start, alloc.RB_start+alloc.L, h->nof_retx(), sched_result->pusch[nof_dci_elems].tbs, user->get_pending_ul_new_data(current_tti),pending_data_before, user->get_pending_ul_old_data()); nof_dci_elems++; } else { - log_h->warning("SCHED: Error %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=%d,%d, tbs=%d, bsr=%d\n", + log_h->warning("SCHED: Error %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=(%d,%d), tbs=%d, bsr=%d\n", is_rar?"RAR":"UL", is_newtx?"tx":"retx", rnti, h->get_id(), sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce, - alloc.RB_start, alloc.L, sched_result->pusch[nof_dci_elems].tbs, + alloc.RB_start, alloc.RB_start+alloc.L, sched_result->pusch[nof_dci_elems].tbs, user->get_pending_ul_new_data(current_tti)); } } diff --git a/srsenb/src/mac/scheduler_metric.cc b/srsenb/src/mac/scheduler_metric.cc index 309eed45a..708ab2dd8 100644 --- a/srsenb/src/mac/scheduler_metric.cc +++ b/srsenb/src/mac/scheduler_metric.cc @@ -25,8 +25,7 @@ */ #include - -#include "srslte/srslte.h" +#include "mac/scheduler_harq.h" #include "mac/scheduler_metric.h" #define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) @@ -215,8 +214,7 @@ void ul_metric_rr::new_tti(std::map &ue_db, uint32_t nof_rb_, sched_ue *user = (sched_ue*) &iter->second; if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty()) { user->ue_idx = nof_users_with_data; - user->has_pusch = true; - nof_users_with_data++; + nof_users_with_data++; } } @@ -275,7 +273,7 @@ void ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc) return; } for (uint32_t n=alloc.RB_start;n #include #include +#include +#include #include "srslte/srslte.h" #include "srslte/common/pdu.h" @@ -232,7 +234,7 @@ bool sched_ue::pucch_sr_collision(uint32_t current_tti, uint32_t n_cce) } } -bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32_t *L) +bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2]) { if (!phy_config_dedicated_enabled) { return false; @@ -241,7 +243,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32 pucch_sched.sps_enabled = false; pucch_sched.n_pucch_sr = cfg.sr_N_pucch; pucch_sched.n_pucch_2 = cfg.n_pucch_cqi; - pucch_sched.N_pucch_1 = cfg.pucch_cfg.n1_pucch_an; + pucch_sched.N_pucch_1 = cfg.pucch_cfg.n1_pucch_an; bool has_sr = cfg.sr_enabled && srslte_ue_ul_sr_send_tti(cfg.sr_I, current_tti); @@ -250,15 +252,13 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32 if (((dl_harq[i].get_tti()+4)%10240) == current_tti) { uint32_t n_pucch = srslte_pucch_get_npucch(dl_harq[i].get_n_cce(), SRSLTE_PUCCH_FORMAT_1A, has_sr, &pucch_sched); if (prb_idx) { - for (int i=0;i<2;i++) { - prb_idx[i] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_1A, n_pucch, cell.nof_prb, cell.cp, i); - } - } - if (L) { - *L = 1; + for (int j=0;j<2;j++) { + prb_idx[j] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_1A, n_pucch, cell.nof_prb, cell.cp, j); + } + Debug("SCHED: Reserved Format1A PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, ncce=%d, has_sr=%d, n_pucch_1=%d\n", + rnti, prb_idx[0], prb_idx[1], n_pucch, dl_harq[i].get_n_cce(), has_sr, pucch_sched.N_pucch_1); } - Debug("SCHED: Reserved Format1A PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], n_pucch); - return true; + return true; } } // If there is no Format1A/B, then check if it's expecting Format1 @@ -268,9 +268,6 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32 prb_idx[i] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_1, cfg.sr_N_pucch, cell.nof_prb, cell.cp, i); } } - if (L) { - *L = 1; - } Debug("SCHED: Reserved Format1 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], cfg.sr_N_pucch); return true; } @@ -280,12 +277,9 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32 for (int i=0;i<2;i++) { prb_idx[i] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_2, cfg.cqi_pucch, cell.nof_prb, cell.cp, i); } + Debug("SCHED: Reserved Format2 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, pmi_idx=%d\n", + rnti, prb_idx[0], prb_idx[1], cfg.cqi_pucch, cfg.cqi_idx); } - if(L) { - *L = 2; - } - Debug("SCHED: Reserved Format2 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, pmi_idx=%d\n", - rnti, prb_idx[0], prb_idx[1], cfg.cqi_pucch, cfg.cqi_idx); return true; } @@ -397,7 +391,7 @@ int sched_ue::generate_format1(dl_harq_proc *h, if (fixed_mcs_dl < 0) { tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs); } else { - tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb); + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb)/8; mcs = fixed_mcs_dl; } @@ -468,7 +462,7 @@ int sched_ue::generate_format0(ul_harq_proc *h, if (fixed_mcs_ul < 0) { tbs = alloc_tbs_ul(allocation.L, nof_re, req_bytes, &mcs); } else { - tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_ul), allocation.L); + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_ul), allocation.L)/8; mcs = fixed_mcs_ul; } @@ -607,12 +601,12 @@ uint32_t sched_ue::get_required_prb_dl(uint32_t req_bytes, uint32_t nof_ctrl_sym uint32_t nof_re = 0; int tbs = 0; - for (n=1;n 0) { nbytes = tbs; @@ -641,14 +635,14 @@ uint32_t sched_ue::get_required_prb_ul(uint32_t req_bytes) if (fixed_mcs_ul < 0) { tbs = alloc_tbs_ul(n, nof_re, 0, &mcs); } else { - tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_ul), n); + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_ul), n)/8; } if (tbs > 0) { nbytes = tbs; } } - - while (!srslte_dft_precoding_valid_prb(n)) { + + while (!srslte_dft_precoding_valid_prb(n) && n<=cell.nof_prb) { n++; } @@ -702,10 +696,16 @@ uint32_t sched_ue::get_aggr_level(uint32_t nof_bits) uint32_t l=0; float max_coderate = srslte_cqi_to_coderate(dl_cqi); float coderate = 99; + float factor=1.5; + uint32_t l_max = 3; + if (cell.nof_prb == 6) { + factor = 1.0; + l_max = 2; + } do { coderate = srslte_pdcch_coderate(nof_bits, l); l++; - } while(l<3 && coderate > max_coderate); + } while(l max_coderate); Debug("SCHED: CQI=%d, l=%d, nof_bits=%d, coderate=%.2f, max_coderate=%.2f\n", dl_cqi, l, nof_bits, coderate, max_coderate); return l; } @@ -814,8 +814,8 @@ int sched_ue::alloc_tbs(uint32_t nof_prb, uint32_t max_Qm = is_ul?4:6; // Allow 16-QAM in PUSCH Only // TODO: Compute real spectral efficiency based on PUSCH-UCI configuration - if (has_pucch) { - cqi-=2; + if (has_pucch && is_ul) { + cqi-=3; } int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, max_Qm, &sel_mcs)/8; diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index 6c294b96d..ec55b0dcf 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -130,9 +130,9 @@ void metrics_stdout::print_metrics() cout << float_to_string(0, 2); } if (metrics.mac[i].tx_pkts > 0 && metrics.mac[i].tx_errors) { - cout << float_to_string((float) 100*metrics.mac[i].tx_errors/metrics.mac[i].tx_pkts, 2) << "%"; + cout << float_to_string((float) 100*metrics.mac[i].tx_errors/metrics.mac[i].tx_pkts, 1) << "%"; } else { - cout << float_to_string(0, 2) << "%"; + cout << float_to_string(0, 1) << "%"; } cout << float_to_string(metrics.phy[i].ul.sinr, 2); cout << float_to_string(metrics.mac[i].phr, 2); @@ -143,9 +143,9 @@ void metrics_stdout::print_metrics() cout << float_to_string(0, 2); } if (metrics.mac[i].rx_pkts > 0 && metrics.mac[i].rx_errors > 0) { - cout << float_to_string((float) 100*metrics.mac[i].rx_errors/metrics.mac[i].rx_pkts, 2) << "%"; + cout << float_to_string((float) 100*metrics.mac[i].rx_errors/metrics.mac[i].rx_pkts, 1) << "%"; } else { - cout << float_to_string(0, 2) << "%"; + cout << float_to_string(0, 1) << "%"; } cout << float_to_eng_string(metrics.mac[i].ul_buffer, 2); cout << endl; diff --git a/srsenb/src/phy/phch_common.cc b/srsenb/src/phy/phch_common.cc index bfb0d1b0d..e4d91581e 100644 --- a/srsenb/src/phy/phch_common.cc +++ b/srsenb/src/phy/phch_common.cc @@ -60,7 +60,7 @@ bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interf is_first_of_burst = true; is_first_tx = true; - for (uint32_t i=0;i #include +#include +#include +#include void init_plots(srsenb::phch_worker *worker); pthread_t plot_thread; @@ -95,22 +98,40 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_) fprintf(stderr, "Error allocating memory\n"); return; } - if (srslte_enb_dl_init(&enb_dl, phy->cell)) { + if (srslte_enb_dl_init(&enb_dl, phy->cell.nof_prb)) { fprintf(stderr, "Error initiating ENB DL\n"); return; } - - if (srslte_enb_ul_init(&enb_ul, - phy->cell, - NULL, - &phy->pusch_cfg, - &phy->hopping_cfg, - &phy->pucch_cfg)) - { + if (srslte_enb_dl_set_cell(&enb_dl, phy->cell)) { fprintf(stderr, "Error initiating ENB DL\n"); return; } + if (srslte_enb_ul_init(&enb_ul, phy->cell.nof_prb)) { + fprintf(stderr, "Error initiating ENB UL\n"); + return; + } + if (srslte_enb_ul_set_cell(&enb_ul, + phy->cell, + NULL, + &phy->pusch_cfg, + &phy->hopping_cfg, + &phy->pucch_cfg)) + { + fprintf(stderr, "Error initiating ENB UL\n"); + return; + } + /* Setup SI-RNTI in PHY */ + add_rnti(SRSLTE_SIRNTI); + + /* Setup P-RNTI in PHY */ + add_rnti(SRSLTE_PRNTI); + + /* Setup RA-RNTI in PHY */ + for (int i=0;i<10;i++) { + add_rnti(1+i); + } + 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); @@ -118,12 +139,29 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_) Info("Worker %d configured cell %d PRB\n", get_id(), phy->cell.nof_prb); initiated = true; - + running = true; + #ifdef DEBUG_WRITE_FILE f = fopen("test.dat", "w"); #endif } +void phch_worker::stop() +{ + running = false; + pthread_mutex_lock(&mutex); + + srslte_enb_dl_free(&enb_dl); + srslte_enb_ul_free(&enb_ul); + if (signal_buffer_rx) { + free(signal_buffer_rx); + } + if (signal_buffer_tx) { + free(signal_buffer_tx); + } + pthread_mutex_unlock(&mutex); + pthread_mutex_destroy(&mutex); +} void phch_worker::reset() { initiated = false; @@ -149,14 +187,14 @@ void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timesta int phch_worker::add_rnti(uint16_t rnti) { - + if (srslte_enb_dl_add_rnti(&enb_dl, rnti)) { return -1; } if (srslte_enb_ul_add_rnti(&enb_ul, rnti)) { return -1; } - + // Create user ue_db[rnti].rnti = rnti; @@ -227,9 +265,13 @@ void phch_worker::rem_rnti(uint16_t rnti) void phch_worker::work_imp() { - uint32_t sf_ack; - - pthread_mutex_lock(&mutex); + uint32_t sf_ack; + + if (!running) { + return; + } + + 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; @@ -244,10 +286,10 @@ void phch_worker::work_imp() ue_db[rnti].has_grant_tti = -1; } - // Process UL signal + // Process UL signal srslte_enb_ul_fft(&enb_ul, signal_buffer_rx); - // Decode pending UL grants for the tti they were scheduled + // Decode pending UL grants for the tti they were scheduled decode_pusch(ul_grants[sf_rx].sched_grants, ul_grants[sf_rx].nof_grants, sf_rx); // Decode remaining PUCCH ACKs not associated with PUSCH transmission and SR signals @@ -316,7 +358,7 @@ void phch_worker::work_imp() } #endif -unlock: +unlock: pthread_mutex_unlock(&mutex); } @@ -392,8 +434,6 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch, ue_db[rnti].phich_info.n_prb_lowest = enb_ul.pusch_cfg.grant.n_prb_tilde[0]; ue_db[rnti].phich_info.n_dmrs = phy_grant.ncs_dmrs; - - char cqi_str[64]; if (cqi_enabled) { srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); @@ -647,9 +687,13 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx); } + srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL}; - uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL}; - if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, grants[i].grant.rv_idx, sf_idx, d)) + uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL}; + int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0}; + + + if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_idx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0)) { fprintf(stderr, "Error putting PDSCH %d\n",i); return SRSLTE_ERROR; diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index bc4f3173e..c0d0a73c9 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -134,6 +134,9 @@ void phy::stop() { tx_rx.stop(); workers_common.stop(); + for (uint32_t i=0;i +#include +#include +#include using namespace srslte; @@ -42,16 +45,52 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ pool = byte_buffer_pool::get_instance(); - if(0 != srslte_netsource_init(&src, gtp_bind_addr.c_str(), GTPU_PORT, SRSLTE_NETSOURCE_UDP)) { - gtpu_log->error("Failed to create source socket on %s:%d", gtp_bind_addr.c_str(), GTPU_PORT); + // Set up sink socket + snk_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (snk_fd < 0) { + gtpu_log->error("Failed to create sink socket\n"); return false; } - if(0 != srslte_netsink_init(&snk, mme_addr.c_str(), GTPU_PORT, SRSLTE_NETSINK_UDP)) { - gtpu_log->error("Failed to create sink socket on %s:%d", mme_addr.c_str(), GTPU_PORT); + if (fcntl(snk_fd, F_SETFL, O_NONBLOCK)) { + gtpu_log->error("Failed to set non-blocking sink socket\n"); + return false; + } + int enable = 1; +#if defined (SO_REUSEADDR) + if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n"); +#endif +#if defined (SO_REUSEPORT) + if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n"); +#endif + + + // Set up source socket + src_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (src_fd < 0) { + gtpu_log->error("Failed to create source socket\n"); + return false; + } +#if defined (SO_REUSEADDR) + if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n"); +#endif +#if defined (SO_REUSEPORT) + if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n"); +#endif + + struct sockaddr_in bindaddr; + bzero(&bindaddr, sizeof(struct sockaddr_in)); + bindaddr.sin_family = AF_INET; + bindaddr.sin_addr.s_addr = inet_addr(gtp_bind_addr.c_str()); + bindaddr.sin_port = htons(GTPU_PORT); + + if (bind(src_fd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in))) { + gtpu_log->error("Failed to bind on address %s, port %d\n", gtp_bind_addr.c_str(), GTPU_PORT); return false; } - - srslte_netsink_set_nonblocking(&snk); // Setup a thread to receive packets from the src socket start(THREAD_PRIO); @@ -61,7 +100,7 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ void gtpu::stop() { - if(run_enable) { + if (run_enable) { run_enable = false; // Wait thread to exit gracefully otherwise might leave a mutex locked int cnt=0; @@ -75,8 +114,12 @@ void gtpu::stop() wait_thread_finish(); } - srslte_netsink_free(&snk); - srslte_netsource_free(&src); + if (snk_fd) { + close(snk_fd); + } + if (src_fd) { + close(src_fd); + } } // gtpu_interface_pdcp @@ -89,28 +132,38 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu) 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); + gtpu_write_header(&header, pdu); - srslte_netsink_write(&snk, pdu->msg, pdu->N_bytes); + if (sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))<0) { + perror("sendto"); + } + pool->deallocate(pdu); } // gtpu_interface_rrc -void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) +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, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, teid_out, *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;ireset(); gtpu_log->debug("Waiting for read...\n"); - pdu->N_bytes = srslte_netsource_read(&src, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET); + 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"); + } + pdu->N_bytes = (uint32_t) n; gtpu_header_t header; gtpu_read_header(pdu, &header); diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 03ea65f2c..35abda80a 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -24,8 +24,10 @@ * */ -#include -#include +#include "srslte/interfaces/sched_interface.h" +#include "srslte/asn1/liblte_rrc.h" +#include "upper/rrc.h" +#include "srslte/srslte.h" #include "srslte/asn1/liblte_mme.h" #include "upper/rrc.h" @@ -61,7 +63,8 @@ void rrc::init(rrc_cfg_t *cfg_, pthread_mutex_init(&user_mutex, NULL); pthread_mutex_init(&paging_mutex, NULL); - + + act_monitor.start(RRC_THREAD_PRIO); bzero(&sr_sched, sizeof(sr_sched_t)); start(RRC_THREAD_PRIO); @@ -69,9 +72,8 @@ void rrc::init(rrc_cfg_t *cfg_, rrc::activity_monitor::activity_monitor(rrc* parent_) { - running = true; - parent = parent_; - start(RRC_THREAD_PRIO); + running = true; + parent = parent_; } void rrc::activity_monitor::stop() @@ -149,6 +151,7 @@ uint32_t rrc::generate_sibs() srslte_bit_pack_vector(bitbuffer.msg, sib_buffer[i].msg, bitbuffer.N_bits); sib_buffer[i].N_bytes = (bitbuffer.N_bits-1)/8+1; } + free(msg); return nof_messages; } @@ -220,8 +223,13 @@ void rrc::rem_user(uint16_t rnti) if (users.count(rnti) == 1) { rrc_log->console("Disconnecting rnti=0x%x.\n", rnti); rrc_log->info("Disconnecting rnti=0x%x.\n", rnti); - /* **Caution** order of removal here is imporant: from bottom to top */ - mac->ue_rem(rnti); // MAC handles PHY + /* **Caution** order of removal here is important: from bottom to top */ + mac->ue_rem(rnti); // MAC handles PHY + + pthread_mutex_unlock(&user_mutex); + usleep(50000); + pthread_mutex_lock(&user_mutex); + rlc->rem_user(rnti); pdcp->rem_user(rnti); gtpu->rem_user(rnti); @@ -604,23 +612,32 @@ void rrc::run_thread() if (p.pdu) { rrc_log->info_hex(p.pdu->msg, p.pdu->N_bytes, "Rx %s PDU", rb_id_text[p.lcid]); } - switch(p.lcid) - { - case RB_ID_SRB0: - parse_ul_ccch(p.rnti, p.pdu); - break; - case RB_ID_SRB1: - case RB_ID_SRB2: - parse_ul_dcch(p.rnti, p.lcid, p.pdu); - break; - case LCID_REM_USER: - usleep(10000); - rem_user(p.rnti); - break; - default: - rrc_log->error("Rx PDU with invalid bearer id: %s", p.lcid); - break; + pthread_mutex_lock(&user_mutex); + if (users.count(p.rnti) == 1) { + switch(p.lcid) + { + case RB_ID_SRB0: + parse_ul_ccch(p.rnti, p.pdu); + break; + case RB_ID_SRB1: + case RB_ID_SRB2: + parse_ul_dcch(p.rnti, p.lcid, p.pdu); + break; + case LCID_REM_USER: + pthread_mutex_unlock(&user_mutex); + usleep(10000); + rem_user(p.rnti); + pthread_mutex_lock(&user_mutex); + break; + default: + rrc_log->error("Rx PDU with invalid bearer id: %s", p.lcid); + break; + } + } else { + printf("Discarting rnti=0x%xn", p.rnti); + rrc_log->warning("Discarting PDU for removed rnti=0x%x\n", p.rnti); } + pthread_mutex_unlock(&user_mutex); } } void rrc::activity_monitor::run_thread() @@ -934,20 +951,16 @@ bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e) if(erab->iE_Extensions_present) { parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); } - - uint8_t id = erab->e_RAB_ID.E_RAB_ID; - erabs[id].id = id; - memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); - memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); - uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out); - - uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) - parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in)); - - if(erab->nAS_PDU_present) { - memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets); - parent->erab_info.N_bytes = erab->nAS_PDU.n_octets; + if(erab->transportLayerAddress.n_bits > 32) { + parent->rrc_log->error("IPv6 addresses not currently supported\n"); + return false; } + + uint32_t teid_out; + uint8_to_uint32(erab->gTP_TEID.buffer, &teid_out); + LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu = erab->nAS_PDU_present ? &erab->nAS_PDU : NULL; + setup_erab(erab->e_RAB_ID.E_RAB_ID, &erab->e_RABlevelQoSParameters, + &erab->transportLayerAddress, teid_out, nas_pdu); } return true; } @@ -962,25 +975,43 @@ bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e) if(erab->iE_Extensions_present) { parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); } + if(erab->transportLayerAddress.n_bits > 32) { + parent->rrc_log->error("IPv6 addresses not currently supported\n"); + return false; + } - uint8_t id = erab->e_RAB_ID.E_RAB_ID; - erabs[id].id = id; - memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); - memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); - uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out); - - uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) - parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in)); - - memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets); - parent->erab_info.N_bytes = erab->nAS_PDU.n_octets; + uint32_t teid_out; + uint8_to_uint32(erab->gTP_TEID.buffer, &teid_out); + setup_erab(erab->e_RAB_ID.E_RAB_ID, &erab->e_RABlevelQoSParameters, + &erab->transportLayerAddress, teid_out, &erab->nAS_PDU); } + // Work in progress notify_s1ap_ue_erab_setup_response(e); send_connection_reconf_new_bearer(e); return true; } +void rrc::ue::setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos, + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out, + LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu) +{ + erabs[id].id = id; + memcpy(&erabs[id].qos_params, qos, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); + memcpy(&erabs[id].address, addr, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); + erabs[id].teid_out = teid_out; + + uint8_t* bit_ptr = addr->buffer; + uint32_t addr_ = liblte_bits_2_value(&bit_ptr, addr->n_bits); + uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) + parent->gtpu->add_bearer(rnti, lcid, addr_, erabs[id].teid_out, &(erabs[id].teid_in)); + + if(nas_pdu) { + memcpy(parent->erab_info.msg, nas_pdu->buffer, nas_pdu->n_octets); + parent->erab_info.N_bytes = nas_pdu->n_octets; + } +} + bool rrc::ue::release_erabs() { typedef std::map::iterator it_t; @@ -1151,7 +1182,8 @@ void rrc::ue::send_connection_setup(bool is_setup) sched_cfg.pucch_cfg.delta_pucch_shift = liblte_rrc_delta_pucch_shift_num[parent->sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift%LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS]; 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); diff --git a/srsenb/src/upper/s1ap.cc b/srsenb/src/upper/s1ap.cc index eba9186e7..44a564d09 100644 --- a/srsenb/src/upper/s1ap.cc +++ b/srsenb/src/upper/s1ap.cc @@ -347,6 +347,7 @@ bool s1ap::setup_s1() uint16_t tmp16; srslte::byte_buffer_t msg; LIBLTE_S1AP_S1AP_PDU_STRUCT pdu; + bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT)); pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; diff --git a/srsue/hdr/mac/demux.h b/srsue/hdr/mac/demux.h index 2f38a4dfc..fb38990ec 100644 --- a/srsue/hdr/mac/demux.h +++ b/srsue/hdr/mac/demux.h @@ -41,14 +41,16 @@ namespace srsue { class demux : public srslte::pdu_queue::process_callback { public: - demux(uint8_t nof_harq_proc_); - void init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers* timers_db_); + demux(); + void init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers::timer* time_alignment_timer); bool process_pdus(); - uint8_t* request_buffer(uint32_t pid, uint32_t len); + uint8_t* request_buffer(uint32_t len); + uint8_t* request_buffer_bcch(uint32_t len); void deallocate(uint8_t* payload_buffer_ptr); - void push_pdu(uint32_t pid, uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp); + void push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp); + void push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp); void push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes); void set_uecrid_callback(bool (*callback)(void*, uint64_t), void *arg); @@ -59,7 +61,8 @@ public: 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 - uint8_t bcch_buffer[1024]; // BCCH PID has a dedicated buffer + const static int MAX_BCCH_PDU_LEN = 1024; + uint8_t bcch_buffer[MAX_BCCH_PDU_LEN]; // BCCH PID has a dedicated buffer bool (*uecrid_callback) (void*, uint64_t); void *uecrid_callback_arg; @@ -74,10 +77,9 @@ private: phy_interface_mac_common *phy_h; srslte::log *log_h; - srslte::timers *timers_db; + srslte::timers::timer *time_alignment_timer; rlc_interface_mac *rlc; - uint8_t nof_harq_proc; - + // Buffer of PDUs srslte::pdu_queue pdus; }; diff --git a/srsue/hdr/mac/dl_harq.h b/srsue/hdr/mac/dl_harq.h index 963551150..278dbc6dc 100644 --- a/srsue/hdr/mac/dl_harq.h +++ b/srsue/hdr/mac/dl_harq.h @@ -35,7 +35,6 @@ #include "srslte/common/log.h" #include "srslte/common/timers.h" #include "mac/demux.h" -#include "mac/mac_common.h" #include "mac/dl_sps.h" #include "srslte/common/mac_pcap.h" @@ -58,9 +57,9 @@ public: pcap = NULL; } - bool init(srslte::log *log_h_, srslte::timers *timers_, demux *demux_unit_) + bool init(srslte::log *log_h_, srslte::timers::timer *timer_aligment_timer_, demux *demux_unit_) { - timers_db = timers_; + timer_aligment_timer = timer_aligment_timer_; demux_unit = demux_unit_; si_window_start = 0; log_h = log_h_; @@ -102,7 +101,7 @@ public: } else { if (grant.is_sps_release) { dl_sps_assig.clear(); - if (timers_db->get(TIME_ALIGNMENT)->is_running()) { + if (timer_aligment_timer->is_running()) { //phy_h->send_sps_ack(); Warning("PHY Send SPS ACK not implemented\n"); } @@ -166,8 +165,19 @@ private: } void new_grant_dl(Tgrant grant, Taction *action) { - for (uint32_t tb = 0; tb < grant.phy_grant.dl.nof_tb; tb++) { - subproc[tb].new_grant_dl(grant, action); + /* Fill action structure */ + bzero(action, sizeof(Taction)); + action->generate_ack = true; + action->rnti = grant.rnti; + + /* For each subprocess... */ + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + action->default_ack[tb] = false; + action->decode_enabled[tb] = false; + action->phy_grant.dl.tb_en[tb] = grant.tb_en[tb]; + if (grant.tb_en[tb]) { + subproc[tb].new_grant_dl(grant, action); + } } } @@ -188,6 +198,12 @@ private: bzero(&cur_grant, sizeof(Tgrant)); } + ~dl_tb_process() { + if (is_initiated) { + srslte_softbuffer_rx_free(&softbuffer); + } + } + bool init(uint32_t pid_, dl_harq_entity *parent, uint32_t tb_idx) { tid = tb_idx; if (srslte_softbuffer_rx_init(&softbuffer, 110)) { @@ -195,6 +211,7 @@ private: return false; } else { pid = pid_; + is_first_tb = true; is_initiated = true; harq_entity = parent; log_h = harq_entity->log_h; @@ -203,6 +220,7 @@ private: } void reset(void) { + is_first_tb = true; ack = false; payload_buffer_ptr = NULL; bzero(&cur_grant, sizeof(Tgrant)); @@ -224,7 +242,12 @@ private: } } calc_is_new_transmission(grant); - if (is_new_transmission) { + // If this is a new transmission or the size of the TB has changed + if (is_new_transmission || (cur_grant.n_bytes[tid] != grant.n_bytes[tid])) { + if (!is_new_transmission) { + Warning("DL PID %d: Size of grant changed during a retransmission %d!=%d\n", pid, + cur_grant.n_bytes[tid], grant.n_bytes[tid]); + } ack = false; srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes[tid] * 8); n_retx = 0; @@ -235,36 +258,33 @@ private: grant.last_tti = cur_grant.tti; memcpy(&cur_grant, &grant, sizeof(Tgrant)); - // Fill action structure - bzero(action, sizeof(Taction)); - action->default_ack = ack; - action->generate_ack = true; - action->decode_enabled = false; - // If data has not yet been successfully decoded if (!ack) { // Instruct the PHY To combine the received data and attempt to decode it - payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid * SRSLTE_MAX_TB + tid, - cur_grant.n_bytes[tid]); + if (pid == HARQ_BCCH_PID) { + payload_buffer_ptr = harq_entity->demux_unit->request_buffer_bcch(cur_grant.n_bytes[tid]); + } else { + payload_buffer_ptr = harq_entity->demux_unit->request_buffer(cur_grant.n_bytes[tid]); + } action->payload_ptr[tid] = payload_buffer_ptr; - if (!action->payload_ptr) { - action->decode_enabled = false; + if (!action->payload_ptr[tid]) { + action->decode_enabled[tid] = false; Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]); return; } - action->decode_enabled = true; + action->decode_enabled[tid]= true; action->rv[tid] = cur_grant.rv[tid]; - action->rnti = cur_grant.rnti; action->softbuffers[tid] = &softbuffer; memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant)); n_retx++; } else { + action->default_ack[tid] = true; Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid); } - if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) { + if (pid == HARQ_BCCH_PID || harq_entity->timer_aligment_timer->is_expired()) { // Do not generate ACK Debug("Not generating ACK\n"); action->generate_ack = false; @@ -288,27 +308,23 @@ private: harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes[tid], ack, cur_grant.tti); } Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes[tid]); - harq_entity->demux_unit->push_pdu(pid * SRSLTE_MAX_TB + tid, payload_buffer_ptr, cur_grant.n_bytes[tid], - cur_grant.tti); + harq_entity->demux_unit->push_pdu_bcch(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.tti); } else { if (harq_entity->pcap) { harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.rnti, ack, cur_grant.tti); } - if (ack) { - if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) { - Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", - cur_grant.n_bytes[tid]); - harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid]); - } else { - Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes[tid]); - harq_entity->demux_unit->push_pdu(pid * SRSLTE_MAX_TB + tid, payload_buffer_ptr, cur_grant.n_bytes[tid], - cur_grant.tti); - - // Compute average number of retransmissions per packet - harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, - harq_entity->nof_pkts++); - } + if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) { + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", + cur_grant.n_bytes[tid]); + harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid]); + } else { + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes[tid]); + harq_entity->demux_unit->push_pdu(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.tti); + + // Compute average number of retransmissions per packet + harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, + harq_entity->nof_pkts++); } } } else { @@ -328,17 +344,14 @@ private: int get_current_tbs(void) { return cur_grant.n_bytes[tid] * 8; } private: + // Determine if it's a new transmission 5.3.2.2 bool calc_is_new_transmission(Tgrant grant) { - bool is_new_tb = true; - if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes[tid] == cur_grant.n_bytes[tid])) || - pid == HARQ_BCCH_PID) { - is_new_tb = false; - } - if ((grant.ndi[tid] != cur_grant.ndi[tid] && !is_new_tb) || // NDI toggled for same TB - is_new_tb || // is new TB - (pid == HARQ_BCCH_PID && grant.rv[tid] == 0)) // Broadcast PID and 1st TX (RV=0) + if ((grant.ndi[tid] != cur_grant.ndi[tid]) || // 1st condition (NDI has changed) + (pid == HARQ_BCCH_PID && grant.rv[tid] == 0) || // 2nd condition (Broadcast and 1st transmission) + is_first_tb) // 3rd condition (first TB) { + is_first_tb = false; is_new_transmission = true; Debug("Set HARQ for new transmission\n"); } else { @@ -353,6 +366,7 @@ private: dl_harq_entity *harq_entity; srslte::log *log_h; + bool is_first_tb; bool is_new_transmission; uint32_t pid; /* HARQ Proccess ID */ @@ -383,7 +397,7 @@ private: std::vector proc; - srslte::timers *timers_db; + srslte::timers::timer *timer_aligment_timer; demux *demux_unit; srslte::log *log_h; srslte::mac_pcap *pcap; diff --git a/srsue/hdr/mac/mac.h b/srsue/hdr/mac/mac.h index f2785e288..a306af187 100644 --- a/srsue/hdr/mac/mac.h +++ b/srsue/hdr/mac/mac.h @@ -48,9 +48,9 @@ namespace srsue { class mac :public mac_interface_phy ,public mac_interface_rrc + ,public srslte::timer_callback ,public srslte::mac_interface_timers ,public thread - ,public srslte::timer_callback { public: mac(); @@ -90,17 +90,20 @@ public: void set_contention_id(uint64_t uecri); void get_rntis(ue_rnti_t *rntis); - - void timer_expired(uint32_t timer_id); + void start_pcap(srslte::mac_pcap* pcap); - - srslte::timers::timer* get(uint32_t timer_id); - u_int32_t get_unique_id(); - + + // Timer callback interface + void timer_expired(uint32_t timer_id); + uint32_t get_current_tti(); - - static const int MAC_NOF_UPPER_TIMERS = 20; - + + // Interface for upper-layer timers + srslte::timers::timer* timer_get(uint32_t timer_id); + void timer_release_id(uint32_t timer_id); + uint32_t timer_get_unique_id(); + + private: void run_thread(); @@ -144,37 +147,24 @@ private: /* Buffers for PCH reception (not included in DL HARQ) */ const static uint32_t pch_payload_buffer_sz = 8*1024; srslte_softbuffer_rx_t pch_softbuffer; - uint8_t pch_payload_buffer[pch_payload_buffer_sz]; - + uint8_t pch_payload_buffer[pch_payload_buffer_sz]; + + /* Functions for MAC Timers */ - srslte::timers timers_db; + uint32_t timer_alignment; + uint32_t contention_resolution_timer; void setup_timers(); - void timeAlignmentTimerExpire(); - + void timer_alignment_expire(); + srslte::timers timers; + + // pointer to MAC PCAP object srslte::mac_pcap* pcap; - bool signals_pregenerated; bool is_first_ul_grant; mac_metrics_t metrics; - - /* Class to run upper-layer timers with normal priority */ - class upper_timers : public periodic_thread { - public: - upper_timers(); - void reset(); - srslte::timers::timer* get(uint32_t timer_id); - uint32_t get_unique_id(); - private: - void run_period(); - srslte::timers timers_db; - }; - upper_timers upper_timers_thread; - - - /* Class to process MAC PDUs from DEMUX unit */ class pdu_process : public thread { public: diff --git a/srsue/hdr/mac/mac_common.h b/srsue/hdr/mac/mac_common.h deleted file mode 100644 index d40d179eb..000000000 --- a/srsue/hdr/mac/mac_common.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#ifndef MAC_COMMON_H -#define MAC_COMMON_H - -namespace srsue { - -typedef enum { - HARQ_RTT, - TIME_ALIGNMENT, - CONTENTION_TIMER, - BSR_TIMER_PERIODIC, - BSR_TIMER_RETX, - PHR_TIMER_PERIODIC, - PHR_TIMER_PROHIBIT, - NOF_MAC_TIMERS -} mac_timers_t; - -} // namespace srsue - -#endif // MAC_COMMON_H diff --git a/srsue/hdr/mac/mux.h b/srsue/hdr/mac/mux.h index 1167af752..0d04c99cb 100644 --- a/srsue/hdr/mac/mux.h +++ b/srsue/hdr/mac/mux.h @@ -100,7 +100,7 @@ private: uint8_t nof_harq_proc; /* Msg3 Buffer */ - static const uint32_t MSG3_BUFF_SZ = 128; + static const uint32_t MSG3_BUFF_SZ = 1024; uint8_t msg3_buff[MSG3_BUFF_SZ]; /* PDU Buffer */ diff --git a/srsue/hdr/mac/proc_bsr.h b/srsue/hdr/mac/proc_bsr.h index 21f278e29..656e9a7a3 100644 --- a/srsue/hdr/mac/proc_bsr.h +++ b/srsue/hdr/mac/proc_bsr.h @@ -81,6 +81,9 @@ private: bool generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes); char* bsr_type_tostring(triggered_bsr_type_t type); char* bsr_format_tostring(bsr_format_t format); + + uint32_t timer_periodic_id; + uint32_t timer_retx_id; }; } // namespace srsue diff --git a/srsue/hdr/mac/proc_phr.h b/srsue/hdr/mac/proc_phr.h index 942f30456..240a7bab7 100644 --- a/srsue/hdr/mac/proc_phr.h +++ b/srsue/hdr/mac/proc_phr.h @@ -49,7 +49,9 @@ public: bool generate_phr_on_ul_grant(float *phr); void timer_expired(uint32_t timer_id); - + + void start_timer(); + private: bool pathloss_changed(); @@ -59,11 +61,15 @@ private: phy_interface_mac* phy_h; srslte::timers* timers_db; bool initiated; - int timer_prohibit; - int timer_periodic; + int timer_prohibit_value; + int timer_periodic_value; int dl_pathloss_change; int last_pathloss_db; bool phr_is_triggered; + + uint32_t timer_periodic_id; + uint32_t timer_prohibit_id; + }; } // namespace srsue diff --git a/srsue/hdr/mac/proc_ra.h b/srsue/hdr/mac/proc_ra.h index 6863371c0..2bd2dd807 100644 --- a/srsue/hdr/mac/proc_ra.h +++ b/srsue/hdr/mac/proc_ra.h @@ -59,8 +59,7 @@ class ra_proc : public srslte::timer_callback phy_h = NULL; log_h = NULL; mac_cfg = NULL; - timers_db = NULL; - mux_unit = NULL; + mux_unit = NULL; demux_unit = NULL; rrc = NULL; transmitted_contention_id = 0; @@ -69,14 +68,21 @@ class ra_proc : public srslte::timer_callback started_by_pdcch = false; rar_grant_nbytes = 0; rar_grant_tti = 0; - msg3_flushed = false; + msg3_flushed = false; + + time_alignment_timer = NULL; + contention_resolution_timer = NULL; }; + + ~ra_proc(); + void init(phy_interface_mac *phy_h, rrc_interface_mac *rrc_, srslte::log *log_h, mac_interface_rrc::ue_rnti_t *rntis, - mac_interface_rrc::mac_cfg_t *mac_cfg, - srslte::timers *timers_db, + mac_interface_rrc::mac_cfg_t *mac_cfg, + srslte::timers::timer* time_alignment_timer_, + srslte::timers::timer* contention_resolution_timer_, mux *mux_unit, demux *demux_unit); void reset(); @@ -98,9 +104,9 @@ class ra_proc : public srslte::timer_callback void start_pcap(srslte::mac_pcap* pcap); private: static bool uecrid_callback(void *arg, uint64_t uecri); - + bool contention_resolution_id_received(uint64_t uecri); - void process_timeadv_cmd(uint32_t ta_cmd); + void process_timeadv_cmd(uint32_t ta_cmd); void step_initialization(); void step_resource_selection(); void step_preamble_transmission(); @@ -111,14 +117,14 @@ private: void step_contention_resolution(); void step_completition(); - // Buffer to receive RAR PDU + // Buffer to receive RAR PDU static const uint32_t MAX_RAR_PDU_LEN = 2048; uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; - srslte::rar_pdu rar_pdu_msg; - + srslte::rar_pdu rar_pdu_msg; + // Random Access parameters provided by higher layers defined in 5.1.1 uint32_t configIndex; - uint32_t nof_preambles; + uint32_t nof_preambles; uint32_t nof_groupA_preambles; uint32_t nof_groupB_preambles; uint32_t messagePowerOffsetGroupB; @@ -127,26 +133,25 @@ private: uint32_t powerRampingStep; uint32_t preambleTransMax; uint32_t iniReceivedTargetPower; - int delta_preamble_db; - uint32_t contentionResolutionTimer; - uint32_t maskIndex; - int preambleIndex; - uint32_t new_ra_msg_len; - + int delta_preamble_db; + uint32_t contentionResolutionTimer; + uint32_t maskIndex; + int preambleIndex; + uint32_t new_ra_msg_len; + // Internal variables - uint32_t preambleTransmissionCounter; - uint32_t backoff_param_ms; - uint32_t sel_maskIndex; - uint32_t sel_preamble; + uint32_t preambleTransmissionCounter; + uint32_t backoff_param_ms; + uint32_t sel_maskIndex; + uint32_t sel_preamble; uint32_t backoff_interval_start; uint32_t backoff_inteval; - int received_target_power_dbm; - uint32_t ra_rnti; - uint32_t current_ta; - - srslte_softbuffer_rx_t softbuffer_rar; - - + int received_target_power_dbm; + uint32_t ra_rnti; + uint32_t current_ta; + + srslte_softbuffer_rx_t softbuffer_rar; + enum { IDLE = 0, INITIALIZATION, // Section 5.1.1 @@ -160,36 +165,38 @@ private: COMPLETION, // Section 5.1.6 COMPLETION_DONE, RA_PROBLEM // Section 5.1.5 last part - } state; - + } state; + typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t; - - ra_group_t last_msg3_group; - bool msg3_transmitted; - bool first_rar_received; + + ra_group_t last_msg3_group; + bool msg3_transmitted; + bool first_rar_received; void read_params(); - + phy_interface_mac *phy_h; srslte::log *log_h; - srslte::timers *timers_db; mux *mux_unit; demux *demux_unit; srslte::mac_pcap *pcap; rrc_interface_mac *rrc; + srslte::timers::timer *time_alignment_timer; + srslte::timers::timer *contention_resolution_timer; + mac_interface_rrc::ue_rnti_t *rntis; mac_interface_rrc::mac_cfg_t *mac_cfg; - + uint64_t transmitted_contention_id; - uint16_t transmitted_crnti; - + uint16_t transmitted_crnti; + enum { - PDCCH_CRNTI_NOT_RECEIVED = 0, - PDCCH_CRNTI_UL_GRANT, - PDCCH_CRNTI_DL_GRANT + PDCCH_CRNTI_NOT_RECEIVED = 0, + PDCCH_CRNTI_UL_GRANT, + PDCCH_CRNTI_DL_GRANT } pdcch_to_crnti_received; - bool started_by_pdcch; + bool started_by_pdcch; uint32_t rar_grant_nbytes; uint32_t rar_grant_tti; bool msg3_flushed; diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index 952b9f002..4749971b6 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -35,7 +35,6 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/log.h" #include "mac/mux.h" -#include "mac/mac_common.h" #include "mac/ul_sps.h" #include "srslte/common/mac_pcap.h" #include "srslte/common/timers.h" @@ -55,9 +54,10 @@ public: ul_harq_entity() : proc(N) { - pcap = NULL; - timers_db = NULL; - mux_unit = NULL; + contention_timer = NULL; + + pcap = NULL; + mux_unit = NULL; log_h = NULL; params = NULL; rntis = NULL; @@ -68,14 +68,14 @@ public: bool init(srslte::log *log_h_, mac_interface_rrc_common::ue_rnti_t *rntis_, mac_interface_rrc_common::ul_harq_params_t *params_, - srslte::timers* timers_db_, + srslte::timers::timer* contention_timer_, mux *mux_unit_) { log_h = log_h_; mux_unit = mux_unit_; params = params_; rntis = rntis_; - timers_db = timers_db_; + contention_timer = contention_timer_; for (uint32_t i=0;itimers_db->get(CONTENTION_TIMER)->reset(); + harq_entity->contention_timer->reset(); } harq_entity->mux_unit->pusch_retx(tti_tx, pid); @@ -357,8 +368,10 @@ private: current_tx_nb = 0; current_irv = 0; is_msg3 = is_msg3_; + Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n", - pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes[0], cur_grant.rnti); + pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes[0], + is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti); generate_tx(tti_tx, action); } } @@ -403,7 +416,7 @@ private: ul_sps ul_sps_assig; - srslte::timers *timers_db; + srslte::timers::timer *contention_timer; mux *mux_unit; std::vector proc; srslte::log *log_h; diff --git a/srsue/hdr/metrics_csv.h b/srsue/hdr/metrics_csv.h new file mode 100644 index 000000000..a897265d2 --- /dev/null +++ b/srsue/hdr/metrics_csv.h @@ -0,0 +1,64 @@ +/** + * + * \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/. + * + */ + +/****************************************************************************** + * File: metrics_csv.h + * Description: Metrics class writing to CSV file. + *****************************************************************************/ + +#ifndef METRICS_CSV_H +#define METRICS_CSV_H + +#include +#include +#include +#include +#include + +#include "srslte/common/metrics_hub.h" +#include "ue_metrics_interface.h" + +namespace srsue { + +class metrics_csv : public srslte::metrics_listener +{ +public: + metrics_csv(std::string filename); + + void set_metrics(ue_metrics_t &m, float report_period_secs); + void set_ue_handle(ue_metrics_interface *ue_); + +private: + std::string float_to_string(float f, int digits, bool add_semicolon = true); + + std::ofstream file; + ue_metrics_interface* ue; + uint32_t n_reports; +}; + +} // namespace srsue + +#endif // METRICS_CSV_H diff --git a/srsue/hdr/metrics_stdout.h b/srsue/hdr/metrics_stdout.h index cd3efc1a3..8ae33b24e 100644 --- a/srsue/hdr/metrics_stdout.h +++ b/srsue/hdr/metrics_stdout.h @@ -36,36 +36,28 @@ #include #include +#include "srslte/common/metrics_hub.h" #include "ue_metrics_interface.h" namespace srsue { -class metrics_stdout +class metrics_stdout : public srslte::metrics_listener { public: metrics_stdout(); - bool init(ue_metrics_interface *u, float report_period_secs=1.0); - void stop(); void toggle_print(bool b); - static void* metrics_thread_start(void *m); - void metrics_thread_run(); + void set_metrics(ue_metrics_t &m, float report_period_secs); + void set_ue_handle(ue_metrics_interface *ue_); private: - void print_metrics(); - void print_disconnect(); std::string float_to_string(float f, int digits); std::string float_to_eng_string(float f, int digits); std::string int_to_eng_string(int f, int digits); - - ue_metrics_interface *ue_; - bool started; - bool do_print; - pthread_t metrics_thread; - ue_metrics_t metrics; - float metrics_report_period; // seconds - uint8_t n_reports; + bool do_print; + uint8_t n_reports; + ue_metrics_interface* ue; }; } // namespace srsue diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index 7f0075e33..aa64fe9ea 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -27,6 +27,9 @@ #ifndef UEPHYWORKERCOMMON_H #define UEPHYWORKERCOMMON_H +#define TX_MODE_CONTINUOUS 1 + + #include #include #include @@ -36,8 +39,6 @@ #include "srslte/common/log.h" #include "phy/phy_metrics.h" -//#define CONTINUOUS_TX - namespace srsue { @@ -47,8 +48,8 @@ namespace srsue { /* Common variables used by all phy workers */ phy_interface_rrc::phy_cfg_t *config; - phy_args_t *args; - srslte::log *log_h; + phy_args_t *args; + rrc_interface_phy *rrc; mac_interface_phy *mac; srslte_ue_ul_t ue_ul; @@ -69,7 +70,8 @@ namespace srsue { void init(phy_interface_rrc::phy_cfg_t *config, phy_args_t *args, srslte::log *_log, - srslte::radio *_radio, + srslte::radio *_radio, + rrc_interface_phy *rrc, mac_interface_phy *_mac); /* For RNTI searches, -1 means now or forever */ @@ -116,7 +118,8 @@ namespace srsue { bool is_first_of_burst; srslte::radio *radio_h; float cfo; - + srslte::log *log_h; + bool ul_rnti_active(uint32_t tti); bool dl_rnti_active(uint32_t tti); diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index 838d49d30..044960760 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -45,62 +45,108 @@ class phch_recv : public thread { public: phch_recv(); + ~phch_recv(); void init(srslte::radio_multi* radio_handler, mac_interface_phy *mac,rrc_interface_phy *rrc, prach *prach_buffer, srslte::thread_pool *_workers_pool, phch_common *_worker_com, srslte::log* _log_h, uint32_t nof_rx_antennas, uint32_t prio, int sync_cpu_affinity = -1); void stop(); void set_agc_enable(bool enable); - void resync_sfn(); - + void set_earfcn(std::vector earfcn); + + void reset_sync(); + void cell_search_start(); + void cell_search_stop(); + void cell_search_next(bool reset = false); + bool cell_select(uint32_t earfcn, srslte_cell_t cell); + uint32_t get_current_tti(); - void sync_start(); - void sync_stop(); bool status_is_sync(); void set_time_adv_sec(float time_adv_sec); void get_current_cell(srslte_cell_t *cell); - const static int MUTEX_X_WORKER = 4; + const static int MUTEX_X_WORKER = 4; + + // public variables needed by callback function + uint32_t current_sflen; + srslte::radio_multi *radio_h; + int next_offset; + private: - + + std::vector earfcn; + + void reset(); + void radio_error(); + bool wait_radio_reset(); void set_ue_sync_opts(srslte_ue_sync_t *q); void run_thread(); - int sync_sfn(); - + + void set_sampling_rate(); + bool set_frequency(); + void resync_sfn(bool is_connected = false); + bool stop_sync(); + + void cell_search_inc(); + + bool init_cell(); + void free_cell(); + + void stop_rx(); + void start_rx(); + bool radio_is_rx; + + bool radio_is_resetting; + bool running; - srslte::radio_multi *radio_h; mac_interface_phy *mac; - rrc_interface_phy *rrc; + rrc_interface_phy *rrc; srslte::log *log_h; srslte::thread_pool *workers_pool; phch_common *worker_com; prach *prach_buffer; - + + // Structures for Cell Camp srslte_ue_sync_t ue_sync; srslte_ue_mib_t ue_mib; - + + // Structures for Cell Search + srslte_ue_cellsearch_t cs; + srslte_ue_mib_sync_t ue_mib_sync; + uint32_t nof_rx_antennas; - cf_t *sf_buffer_sfn[SRSLTE_MAX_PORTS]; + cf_t *sf_buffer[SRSLTE_MAX_PORTS]; // Sync metrics sync_metrics_t metrics; enum { - IDLE, CELL_SEARCH, SYNCING, SYNC_DONE - } phy_state; + IDLE = 0, + CELL_SEARCH, + CELL_SELECT, + CELL_RESELECT, + CELL_MEASURE, + CELL_CAMP + } phy_state; + + bool is_in_idle; - srslte_cell_t cell; + enum { + SRATE_NONE=0, SRATE_FIND, SRATE_CAMP + } srate_mode; + float current_srate; + + srslte_cell_t cell; bool cell_is_set; bool is_sfn_synched; bool started; float time_adv_sec; - bool radio_is_streaming; - uint32_t tti; + uint32_t tti; bool do_agc; float last_gain; @@ -108,13 +154,23 @@ private: uint32_t nof_tx_mutex; uint32_t tx_mutex_cnt; + uint32_t current_earfcn; + uint32_t sync_sfn_cnt; - const static uint32_t SYNC_SFN_TIMEOUT = 5000; + const static uint32_t SYNC_SFN_TIMEOUT = 200; float ul_dl_factor; - - bool cell_search(int force_N_id_2 = -1); - bool init_cell(); - void free_cell(); + int cur_earfcn_index; + bool cell_search_in_progress; + uint32_t measure_cnt; + float measure_rsrp; + srslte_ue_dl_t ue_dl_measure; + + const static int RSRP_MEASURE_NOF_FRAMES = 5; + + int cell_sync_sfn(); + int cell_meas_rsrp(); + int cell_search(int force_N_id_2 = -1); + bool set_cell(); }; } // namespace srsue diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 7b196f948..0811723e0 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -42,15 +42,17 @@ class phch_worker : public srslte::thread_pool::worker public: phch_worker(); + ~phch_worker(); void reset(); void set_common(phch_common *phy); - bool init_cell(srslte_cell_t cell); - void free_cell(); - + bool init(uint32_t max_prb, srslte::log *log); + + bool set_cell(srslte_cell_t cell); + /* Functions used by main PHY thread */ cf_t* get_buffer(uint32_t antenna_idx); void set_tti(uint32_t tti, uint32_t tx_tti); - void set_tx_time(srslte_timestamp_t tx_time); + void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset); void set_cfo(float cfo); void set_sample_offset(float sample_offset); @@ -95,7 +97,7 @@ private: void set_uci_sr(); void set_uci_periodic_cqi(); void set_uci_aperiodic_cqi(); - void set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], uint32_t nof_tb); + void set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS]); bool srs_is_ready_to_send(); float set_power(float tx_power); void setup_tx_gain(); @@ -111,15 +113,19 @@ private: /* Common objects */ phch_common *phy; - srslte_cell_t cell; - bool cell_initiated; + srslte::log *log_h; + srslte_cell_t cell; + bool mem_initiated; + bool cell_initiated; cf_t *signal_buffer[SRSLTE_MAX_PORTS]; uint32_t tti; uint32_t tx_tti; bool pregen_enabled; uint32_t last_dl_pdcch_ncce; - bool rnti_is_set; - + bool rnti_is_set; + + uint32_t next_offset; + /* Objects for DL */ srslte_ue_dl_t ue_dl; uint32_t cfi; diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index b478bbcdd..0c77360b2 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -46,17 +46,21 @@ typedef _Complex float cf_t; class phy : public phy_interface_mac , public phy_interface_rrc + , public thread { public: phy(); bool init(srslte::radio_multi *radio_handler, mac_interface_phy *mac, - rrc_interface_phy *rrc, - srslte::log *log_h, + rrc_interface_phy *rrc, + std::vector log_vec, phy_args_t *args = NULL); void stop(); + void wait_initialize(); + bool is_initiated(); + void set_agc_enable(bool enabled); void get_metrics(phy_metrics_t &m); @@ -69,21 +73,25 @@ public: void enable_pregen_signals(bool enable); void start_trace(); - void write_trace(std::string filename); - + void write_trace(std::string filename); + + void set_earfcn(std::vector earfcns); + /********** RRC INTERFACE ********************/ void reset(); - bool status_is_sync(); + void sync_reset(); void configure_ul_params(bool pregen_disabled = false); - void resync_sfn(); - + void cell_search_start(); + void cell_search_stop(); + void cell_search_next(); + bool cell_select(uint32_t earfcn, srslte_cell_t phy_cell); + /********** MAC INTERFACE ********************/ /* Functions to synchronize with a cell */ - void sync_start(); - void sync_stop(); + bool sync_status(); // this is also RRC interface /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ - void set_crnti(uint16_t rnti); + void set_crnti(uint16_t rnti); /* Instructs the PHY to configure using the parameters written by set_param() */ void configure_prach_params(); @@ -127,7 +135,10 @@ public: void start_plot(); private: - + + void run_thread(); + + bool initiated; uint32_t nof_workers; const static int MAX_WORKERS = 4; @@ -136,8 +147,11 @@ private: const static int SF_RECV_THREAD_PRIO = 1; const static int WORKERS_THREAD_PRIO = 0; - srslte::radio_multi *radio_handler; - srslte::log *log_h; + srslte::radio_multi *radio_handler; + std::vector log_vec; + srslte::log *log_h; + srsue::mac_interface_phy *mac; + srsue::rrc_interface_phy *rrc; srslte::thread_pool workers_pool; std::vector workers; diff --git a/srsue/hdr/phy/prach.h b/srsue/hdr/phy/prach.h index 694353926..67ccc0c94 100644 --- a/srsue/hdr/phy/prach.h +++ b/srsue/hdr/phy/prach.h @@ -45,14 +45,15 @@ namespace srsue { args = NULL; config = NULL; - initiated = false; - signal_buffer = NULL; + signal_buffer = NULL; transmitted_tti = 0; - target_power_dbm = 0; + target_power_dbm = 0; + mem_initiated = false; + cell_initiated = false; } - void init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config, phy_args_t *args, srslte::log *log_h); - bool init_cell(srslte_cell_t cell); - void free_cell(); + ~prach(); + void init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config, uint32_t max_prb, phy_args_t *args, srslte::log *log_h); + bool set_cell(srslte_cell_t cell); bool prepare_to_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = -1); bool is_ready_to_send(uint32_t current_tti); int tx_tti(); @@ -70,7 +71,8 @@ namespace srsue { srslte::log *log_h; int preamble_idx; int allowed_subframe; - bool initiated; + bool mem_initiated; + bool cell_initiated; uint32_t len; cf_t *buffer[64]; srslte_prach_t prach_obj; diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index c69dbddeb..4e48f6b6d 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -45,7 +45,7 @@ #include "srslte/upper/pdcp.h" #include "upper/rrc.h" #include "upper/nas.h" -#include "srslte/upper/gw.h" +#include "upper/gw.h" #include "upper/usim.h" #include "srslte/common/buffer_pool.h" @@ -71,7 +71,7 @@ public: void stop(); bool is_attached(); void start_plot(); - + static void rf_msg(srslte_rf_error_t error); void handle_rf_msg(srslte_rf_error_t error); @@ -79,10 +79,7 @@ public: bool get_metrics(ue_metrics_t &m); void pregenerate_signals(bool enable); - - // Testing - void test_con_restablishment(); - + private: virtual ~ue(); @@ -95,12 +92,15 @@ private: srslte::pdcp pdcp; srsue::rrc rrc; srsue::nas nas; - srslte::gw gw; + srsue::gw gw; srsue::usim usim; - srslte::logger_file logger; - srslte::log_filter rf_log; - srslte::log_filter phy_log; + srslte::logger_stdout logger_stdout; + srslte::logger_file logger_file; + srslte::logger *logger; + + // rf_log is on ue_base + std::vector phy_log; srslte::log_filter mac_log; srslte::log_filter rlc_log; srslte::log_filter pdcp_log; @@ -113,8 +113,7 @@ private: all_args_t *args; bool started; - rf_metrics_t rf_metrics; - + bool check_srslte_version(); }; diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index 4720d8062..411896f70 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -52,15 +52,17 @@ namespace srsue { *******************************************************************************/ typedef struct { + uint32_t dl_earfcn; float dl_freq; float ul_freq; + float freq_offset; float rx_gain; float tx_gain; - uint32_t nof_rx_ant; - std::string device_name; - std::string device_args; - std::string time_adv_nsamples; - std::string burst_preamble; + uint32_t nof_rx_ant; + std::string device_name; + std::string device_args; + std::string time_adv_nsamples; + std::string burst_preamble; }rf_args_t; typedef struct { @@ -105,6 +107,8 @@ typedef struct { float metrics_period_secs; bool pregenerate_signals; std::string ue_cateogry; + bool metrics_csv_enable; + std::string metrics_csv_filename; }expert_args_t; typedef struct { diff --git a/srsue/hdr/ue_metrics_interface.h b/srsue/hdr/ue_metrics_interface.h index 70688863e..20ee6f031 100644 --- a/srsue/hdr/ue_metrics_interface.h +++ b/srsue/hdr/ue_metrics_interface.h @@ -29,7 +29,8 @@ #include -#include "srslte/upper/gw_metrics.h" +#include "srslte/common/metrics_hub.h" +#include "upper/gw_metrics.h" #include "srslte/upper/rlc_metrics.h" #include "mac/mac_metrics.h" #include "phy/phy_metrics.h" @@ -48,14 +49,15 @@ typedef struct { phy_metrics_t phy; mac_metrics_t mac; srslte::rlc_metrics_t rlc; - srslte::gw_metrics_t gw; + gw_metrics_t gw; }ue_metrics_t; // UE interface -class ue_metrics_interface +class ue_metrics_interface : public srslte::metrics_interface { public: virtual bool get_metrics(ue_metrics_t &m) = 0; + virtual bool is_attached() = 0; }; } // namespace srsue diff --git a/lib/include/srslte/upper/gw.h b/srsue/hdr/upper/gw.h similarity index 74% rename from lib/include/srslte/upper/gw.h rename to srsue/hdr/upper/gw.h index ce5936b71..800b31624 100644 --- a/lib/include/srslte/upper/gw.h +++ b/srsue/hdr/upper/gw.h @@ -33,40 +33,40 @@ #include "srslte/common/msg_queue.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/threads.h" -#include "srslte/upper/gw_metrics.h" +#include "gw_metrics.h" #include -namespace srslte { +namespace srsue { class gw - :public srsue::gw_interface_pdcp - ,public srsue::gw_interface_nas + :public gw_interface_pdcp + ,public gw_interface_nas ,public thread { public: gw(); - void init(srsue::pdcp_interface_gw *pdcp_, srsue::rrc_interface_gw *rrc_, srsue::ue_interface *ue_, log *gw_log_, uint32_t lcid_); + void init(pdcp_interface_gw *pdcp_, nas_interface_gw *nas_, srslte::log *gw_log_, uint32_t lcid_); void stop(); void get_metrics(gw_metrics_t &m); // PDCP interface - void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu); // NAS interface - error_t setup_if_addr(uint32_t ip_addr, char *err_str); + srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str); private: static const int GW_THREAD_PRIO = 7; - srsue::pdcp_interface_gw *pdcp; - srsue::rrc_interface_gw *rrc; - srsue::ue_interface *ue; + pdcp_interface_gw *pdcp; + nas_interface_gw *nas; - byte_buffer_pool *pool; - log *gw_log; + srslte::byte_buffer_pool *pool; + + srslte::log *gw_log; bool running; bool run_enable; int32 tun_fd; @@ -75,12 +75,14 @@ private: bool if_up; uint32_t lcid; + uint32_t current_ip_addr; + long ul_tput_bytes; long dl_tput_bytes; struct timeval metrics_time[3]; void run_thread(); - error_t init_if(char *err_str); + srslte::error_t init_if(char *err_str); }; } // namespace srsue diff --git a/lib/include/srslte/upper/gw_metrics.h b/srsue/hdr/upper/gw_metrics.h similarity index 98% rename from lib/include/srslte/upper/gw_metrics.h rename to srsue/hdr/upper/gw_metrics.h index b5d8eaf23..e596046c9 100644 --- a/lib/include/srslte/upper/gw_metrics.h +++ b/srsue/hdr/upper/gw_metrics.h @@ -28,7 +28,7 @@ #define UE_GW_METRICS_H -namespace srslte { +namespace srsue { struct gw_metrics_t { diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index 32afd52bb..e743165fb 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -39,16 +39,16 @@ using srslte::byte_buffer_t; namespace srsue { // EMM states (3GPP 24.302 v10.0.0) -typedef enum{ - EMM_STATE_NULL = 0, - EMM_STATE_DEREGISTERED, - EMM_STATE_REGISTERED_INITIATED, - EMM_STATE_REGISTERED, - EMM_STATE_SERVICE_REQUEST_INITIATED, - EMM_STATE_DEREGISTERED_INITIATED, - EMM_STATE_TAU_INITIATED, - EMM_STATE_N_ITEMS, -}emm_state_t; +typedef enum { + EMM_STATE_NULL = 0, + EMM_STATE_DEREGISTERED, + EMM_STATE_REGISTERED_INITIATED, + EMM_STATE_REGISTERED, + EMM_STATE_SERVICE_REQUEST_INITIATED, + EMM_STATE_DEREGISTERED_INITIATED, + EMM_STATE_TAU_INITIATED, + EMM_STATE_N_ITEMS, +} emm_state_t; static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", "DEREGISTERED", "REGISTERED INITIATED", @@ -57,8 +57,15 @@ static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", "DEREGISTERED INITIATED", "TRACKING AREA UPDATE INITIATED"}; +typedef enum { + PLMN_NOT_SELECTED = 0, + PLMN_SELECTED +} plmn_selection_state_t; + class nas - :public nas_interface_rrc + : public nas_interface_rrc, + public nas_interface_ue, + public nas_interface_gw { public: nas(); @@ -72,71 +79,105 @@ public: emm_state_t get_state(); // RRC interface - void notify_connection_setup(); - void write_pdu(uint32_t lcid, byte_buffer_t *pdu); - uint32_t get_ul_count(); - bool is_attached(); - bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); - + void notify_connection_setup(); + + void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + + uint32_t get_ul_count(); + + bool is_attached(); + bool is_attaching(); + + bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); + + void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code); + void plmn_search_end(); + + // UE interface + void attach_request(); + void deattach_request(); + private: srslte::byte_buffer_pool *pool; - srslte::log *nas_log; - rrc_interface_nas *rrc; + srslte::log *nas_log; + rrc_interface_nas *rrc; usim_interface_nas *usim; - gw_interface_nas *gw; + gw_interface_nas *gw; + srslte::srslte_nas_config_t cfg; - emm_state_t state; - + emm_state_t state; + + plmn_selection_state_t plmn_selection; + LIBLTE_RRC_PLMN_IDENTITY_STRUCT current_plmn; + LIBLTE_RRC_PLMN_IDENTITY_STRUCT selecting_plmn; + LIBLTE_RRC_PLMN_IDENTITY_STRUCT home_plmn; + + std::vector known_plmns; + // Save short MAC - + // Identifiers LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti; - bool is_guti_set; + bool is_guti_set; uint32_t ip_addr; - uint8_t eps_bearer_id; + uint8_t eps_bearer_id; - uint8_t transaction_id; + uint8_t transaction_id; // NAS counters - incremented for each security-protected message recvd/sent uint32_t count_ul; uint32_t count_dl; // Security - uint8_t ksi; - uint8_t k_nas_enc[32]; - uint8_t k_nas_int[32]; + uint8_t ksi; + uint8_t k_nas_enc[32]; + uint8_t k_nas_int[32]; srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; - void integrity_generate(uint8_t *key_128, - uint32_t count, - uint8_t rb_id, - uint8_t direction, - uint8_t *msg, - uint32_t msg_len, - uint8_t *mac); + void integrity_generate(uint8_t *key_128, + uint32_t count, + uint8_t rb_id, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac); + void integrity_check(); + void cipher_encrypt(); + void cipher_decrypt(); // Parsers void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu); + void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu); + void parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu); + void parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu); + void parse_identity_request(uint32_t lcid, byte_buffer_t *pdu); + void parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu); + void parse_service_reject(uint32_t lcid, byte_buffer_t *pdu); + void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu); + void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu); // Senders void send_attach_request(); + void send_identity_response(); + void send_service_request(); + void send_esm_information_response(); void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 9cbdd5201..3643f76c3 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -35,6 +35,7 @@ #include "srslte/common/common.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/security.h" +#include "srslte/common/threads.h" #include @@ -47,107 +48,156 @@ static std::string rb_id_str[] = {"SRB0", "SRB1", "SRB2", "DRB4","DRB5","DRB6", "DRB7","DRB8"}; - class rrc :public rrc_interface_nas ,public rrc_interface_phy ,public rrc_interface_mac - ,public rrc_interface_gw ,public rrc_interface_pdcp ,public rrc_interface_rlc ,public srslte::timer_callback + ,public thread { public: rrc(); - void init(phy_interface_rrc *phy_, - mac_interface_rrc *mac_, - rlc_interface_rrc *rlc_, - pdcp_interface_rrc *pdcp_, - nas_interface_rrc *nas_, - usim_interface_rrc *usim_, + + void init(phy_interface_rrc *phy_, + mac_interface_rrc *mac_, + rlc_interface_rrc *rlc_, + pdcp_interface_rrc *pdcp_, + nas_interface_rrc *nas_, + usim_interface_rrc *usim_, srslte::mac_interface_timers *mac_timers_, - srslte::log *rrc_log_); + srslte::log *rrc_log_); + void stop(); rrc_state_t get_state(); - void set_ue_category(int category); + + void set_ue_category(int category); // Timeout callback interface void timer_expired(uint32_t timeout_id); - void test_con_restablishment(); - void liblte_rrc_log(char* str); - + void liblte_rrc_log(char *str); + private: - srslte::byte_buffer_pool *pool; - srslte::log *rrc_log; - phy_interface_rrc *phy; - mac_interface_rrc *mac; - rlc_interface_rrc *rlc; - pdcp_interface_rrc *pdcp; - nas_interface_rrc *nas; - usim_interface_rrc *usim; - - srslte::bit_buffer_t bit_buf; - - pthread_mutex_t mutex; - - rrc_state_t state; - uint8_t transaction_id; - bool drb_up; + srslte::byte_buffer_pool *pool; + srslte::log *rrc_log; + phy_interface_rrc *phy; + mac_interface_rrc *mac; + rlc_interface_rrc *rlc; + pdcp_interface_rrc *pdcp; + nas_interface_rrc *nas; + usim_interface_rrc *usim; - uint8_t k_rrc_enc[32]; - uint8_t k_rrc_int[32]; - uint8_t k_up_enc[32]; - uint8_t k_up_int[32]; // Not used: only for relay nodes (3GPP 33.401 Annex A.7) + srslte::bit_buffer_t bit_buf; - srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; - srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + pthread_mutex_t mutex; - LIBLTE_RRC_MIB_STRUCT mib; - LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; - LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + rrc_state_t state; + uint8_t transaction_id; + bool drb_up; - std::map srbs; - std::map drbs; + // timeouts in ms - LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; - LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + uint32_t connecting_timeout; + static const uint32_t RRC_CONNECTING_TIMEOUT = 1000; - pthread_t sib_search_thread; + uint32_t plmn_select_timeout; + static const uint32_t RRC_PLMN_SELECT_TIMEOUT = 10000; - // RRC constants and timers + uint32_t select_cell_timeout; + static const uint32_t RRC_SELECT_CELL_TIMEOUT = 2000; + + uint8_t k_rrc_enc[32]; + uint8_t k_rrc_int[32]; + uint8_t k_up_enc[32]; + uint8_t k_up_int[32]; // Not used: only for relay nodes (3GPP 33.401 Annex A.7) + + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + + std::map srbs; + std::map drbs; + + LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + + // RRC constants and timers srslte::mac_interface_timers *mac_timers; - uint32_t n310_cnt, N310; - uint32_t n311_cnt, N311; + uint32_t n310_cnt, N310; + uint32_t n311_cnt, N311; uint32_t t301, t310, t311; - uint32_t safe_reset_timer; int ue_category; - - + + typedef struct { + uint32_t earfcn; + srslte_cell_t phy_cell; + float rsrp; + bool has_valid_sib1; + bool has_valid_sib2; + bool in_sync; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + } cell_t; + + std::vector known_cells; + cell_t *current_cell; + + + typedef enum { + SI_ACQUIRE_IDLE = 0, + SI_ACQUIRE_SIB1, + SI_ACQUIRE_SIB2 + } si_acquire_state_t; + + si_acquire_state_t si_acquire_state; + void run_si_acquisition_procedure(); + uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x); + uint32_t nof_sib1_trials; + uint32_t last_win_start; + + void select_next_cell_in_plmn(); + LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id; + int last_selected_cell; + + bool thread_running; + void run_thread(); + // NAS interface void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + uint16_t get_mcc(); + uint16_t get_mnc(); + void enable_capabilities(); + void plmn_search(); + void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); // PHY interface void in_sync(); void out_of_sync(); + void earfcn_end(); + void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); // MAC interface void release_pucch_srs(); - void ra_problem(); + + void ra_problem(); // GW interface - bool rrc_connected(); - void rrc_connect(); + bool is_connected(); + bool have_drb(); // PDCP interface void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + 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); // Radio bearers @@ -175,31 +225,29 @@ private: } // RLC interface - void max_retx_attempted(); + void max_retx_attempted(); // Senders - void send_con_request(); - void send_con_restablish_request(); - void send_con_restablish_complete(); - void send_con_setup_complete(byte_buffer_t *nas_msg); - void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu); - void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu); - void send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu); - void send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu); + void send_con_request(); + void send_con_restablish_request(); + void send_con_restablish_complete(); + void send_con_setup_complete(byte_buffer_t *nas_msg); + void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu); + void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu); + void send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu); + void send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu); // Parsers - void parse_dl_ccch(byte_buffer_t *pdu); - void parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu); - void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu); + void parse_dl_ccch(byte_buffer_t *pdu); + void parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu); + void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu); // Helpers - void reset_ue(); void rrc_connection_release(); void radio_link_failure(); static void* start_sib_thread(void *rrc_); void sib_search(); - uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x); - void apply_sib2_configs(); + void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); 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, byte_buffer_t *pdu); diff --git a/srsue/hdr/upper/rrc_common.h b/srsue/hdr/upper/rrc_common.h index 692a20cb3..95b909620 100644 --- a/srsue/hdr/upper/rrc_common.h +++ b/srsue/hdr/upper/rrc_common.h @@ -29,22 +29,25 @@ namespace srsue { + // RRC states (3GPP 36.331 v10.0.0) -typedef enum{ - RRC_STATE_IDLE = 0, - RRC_STATE_SIB1_SEARCH, - RRC_STATE_SIB2_SEARCH, - RRC_STATE_WAIT_FOR_CON_SETUP, - RRC_STATE_COMPLETING_SETUP, - RRC_STATE_RRC_CONNECTED, - RRC_STATE_N_ITEMS, -}rrc_state_t; +typedef enum { + RRC_STATE_IDLE = 0, + RRC_STATE_PLMN_SELECTION, + RRC_STATE_CELL_SELECTING, + RRC_STATE_CELL_SELECTED, + RRC_STATE_CONNECTING, + RRC_STATE_CONNECTED, + RRC_STATE_LEAVE_CONNECTED, + RRC_STATE_N_ITEMS, +} rrc_state_t; static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE", - "SIB1_SEARCH", - "SIB2_SEARCH", - "WAIT FOR CON SETUP", - "COMPLETING SETUP", - "RRC CONNECTED"}; + "PLMN SELECTION", + "CELL SELECTING", + "CELL SELECTED", + "CONNECTING", + "CONNECTED", + "LEAVE CONNECTED"}; } // namespace srsue diff --git a/srsue/hdr/upper/usim.h b/srsue/hdr/upper/usim.h index bb4e394bd..fea15ba68 100644 --- a/srsue/hdr/upper/usim.h +++ b/srsue/hdr/upper/usim.h @@ -61,6 +61,7 @@ public: // NAS interface void get_imsi_vec(uint8_t* imsi_, uint32_t n); void get_imei_vec(uint8_t* imei_, uint32_t n); + int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id); void generate_authentication_response(uint8_t *rand, uint8_t *autn_enb, @@ -119,6 +120,8 @@ private: uint8_t k_asme[32]; uint8_t k_enb[32]; + bool initiated; + }; } // namespace srsue diff --git a/srsue/src/CMakeLists.txt b/srsue/src/CMakeLists.txt index 5c6000f63..0755a6490 100644 --- a/srsue/src/CMakeLists.txt +++ b/srsue/src/CMakeLists.txt @@ -31,7 +31,7 @@ if (RPATH) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) endif (RPATH) -add_executable(srsue main.cc ue_base.cc ue.cc metrics_stdout.cc) +add_executable(srsue main.cc ue_base.cc ue.cc metrics_stdout.cc metrics_csv.cc) target_link_libraries(srsue srsue_mac srsue_phy srsue_upper diff --git a/srsue/src/mac/demux.cc b/srsue/src/mac/demux.cc index 4fcb402fc..14c524165 100644 --- a/srsue/src/mac/demux.cc +++ b/srsue/src/mac/demux.cc @@ -36,16 +36,16 @@ namespace srsue { -demux::demux(uint8_t nof_harq_proc_) : mac_msg(20), pending_mac_msg(20), nof_harq_proc(nof_harq_proc_) +demux::demux() : mac_msg(20), pending_mac_msg(20) { } -void demux::init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc_, srslte::log* log_h_, srslte::timers* timers_db_) +void demux::init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc_, srslte::log* log_h_, srslte::timers::timer* time_alignment_timer_) { phy_h = phy_h_; log_h = log_h_; - rlc = rlc_; - timers_db = timers_db_; + rlc = rlc_; + time_alignment_timer = time_alignment_timer_; pdus.init(this, log_h); } @@ -64,18 +64,18 @@ void demux::deallocate(uint8_t* payload_buffer_ptr) pdus.deallocate(payload_buffer_ptr); } } - -uint8_t* demux::request_buffer(uint32_t pid, uint32_t len) -{ - uint8_t *buff = NULL; - if (pid < nof_harq_proc) { - return pdus.request(len); - } else if (pid == nof_harq_proc) { - buff = bcch_buffer; +uint8_t* demux::request_buffer_bcch(uint32_t len) +{ + if (len < MAX_BCCH_PDU_LEN) { + return bcch_buffer; } else { - Error("Requested buffer for invalid PID=%d\n", pid); + return NULL; } - return buff; +} + +uint8_t* demux::request_buffer(uint32_t len) +{ + return pdus.request(len); } /* Demultiplexing of MAC PDU associated with a Temporal C-RNTI. The PDU will @@ -117,21 +117,17 @@ void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes) * This function enqueues the packet and returns quicly because ACK * deadline is important here. */ -void demux::push_pdu(uint32_t pid, uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) -{ - if (pid < nof_harq_proc) { - return pdus.push(buff, nof_bytes, tstamp); - } else if (pid == nof_harq_proc) { - /* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through - * the MAC in transparent mode. - * Warning: In this case function sends the message to RLC now, since SI blocks do not - * require ACK feedback to be transmitted quickly. - */ - Debug("Pushed BCCH MAC PDU in transparent mode\n"); - rlc->write_pdu_bcch_dlsch(buff, nof_bytes); - } else { - Error("Pushed buffer for invalid PID=%d\n", pid); - } +void demux::push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) { + return pdus.push(buff, nof_bytes, tstamp); +} + +/* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through +* the MAC in transparent mode. +* Warning: In this case function sends the message to RLC now, since SI blocks do not +* require ACK feedback to be transmitted quickly. +*/ +void demux::push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) { + rlc->write_pdu_bcch_dlsch(buff, nof_bytes); } bool demux::process_pdus() @@ -190,8 +186,8 @@ bool demux::process_ce(srslte::sch_subh *subh) { Info("Received TA=%d\n", subh->get_ta_cmd()); // Start or restart timeAlignmentTimer - timers_db->get(TIME_ALIGNMENT)->reset(); - timers_db->get(TIME_ALIGNMENT)->run(); + time_alignment_timer->reset(); + time_alignment_timer->run(); break; case srslte::sch_subh::PADDING: break; diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index 6028ce7e8..1a2c909ae 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -42,61 +42,63 @@ namespace srsue { mac::mac() : ttisync(10240), - timers_db((uint32_t) NOF_MAC_TIMERS), + timers(64), mux_unit(MAC_NOF_HARQ_PROC), - demux_unit(SRSLTE_MAX_TB*MAC_NOF_HARQ_PROC), pdu_process_thread(&demux_unit) { - started = false; - pcap = NULL; - signals_pregenerated = false; + started = false; + pcap = NULL; bzero(&metrics, sizeof(mac_metrics_t)); } - + bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h_) { - started = false; + started = false; phy_h = phy; - rlc_h = rlc; - rrc_h = rrc; - log_h = log_h_; - tti = 0; - is_synchronized = false; - last_temporal_crnti = 0; - phy_rnti = 0; - + rlc_h = rlc; + rrc_h = rrc; + log_h = log_h_; + tti = 0; + is_synchronized = false; + last_temporal_crnti = 0; + phy_rnti = 0; + srslte_softbuffer_rx_init(&pch_softbuffer, 100); - - bsr_procedure.init( rlc_h, log_h, &config, &timers_db); - phr_procedure.init(phy_h, log_h, &config, &timers_db); + + timer_alignment = timers.get_unique_id(); + contention_resolution_timer = timers.get_unique_id(); + + bsr_procedure.init( rlc_h, log_h, &config, &timers); + phr_procedure.init(phy_h, log_h, &config, &timers); mux_unit.init ( rlc_h, log_h, &bsr_procedure, &phr_procedure); - demux_unit.init (phy_h, rlc_h, log_h, &timers_db); - ra_procedure.init (phy_h, rrc, log_h, &uernti, &config, &timers_db, &mux_unit, &demux_unit); + demux_unit.init (phy_h, rlc_h, log_h, timers.get(timer_alignment)); + ra_procedure.init (phy_h, rrc, log_h, &uernti, &config, timers.get(timer_alignment), timers.get(contention_resolution_timer), &mux_unit, &demux_unit); sr_procedure.init (phy_h, rrc, log_h, &config); - ul_harq.init ( log_h, &uernti, &config.ul_harq_params, &timers_db, &mux_unit); - dl_harq.init ( log_h, &timers_db, &demux_unit); + ul_harq.init ( log_h, &uernti, &config.ul_harq_params, timers.get(contention_resolution_timer), &mux_unit); + dl_harq.init ( log_h, timers.get(timer_alignment), &demux_unit); reset(); - - started = true; + + started = true; start(MAC_MAIN_THREAD_PRIO); - - - return started; + + + return started; } void mac::stop() { - started = false; + srslte_softbuffer_rx_free(&pch_softbuffer); + + started = false; ttisync.increase(); - upper_timers_thread.thread_cancel(); pdu_process_thread.stop(); wait_thread_finish(); } void mac::start_pcap(srslte::mac_pcap* pcap_) { - pcap = pcap_; + pcap = pcap_; dl_harq.start_pcap(pcap); ul_harq.start_pcap(pcap); ra_procedure.start_pcap(pcap); @@ -112,89 +114,72 @@ void mac::reconfiguration() void mac::reset() { bzero(&metrics, sizeof(mac_metrics_t)); - + Info("Resetting MAC\n"); - - timers_db.stop_all(); - upper_timers_thread.reset(); - + + timers.stop_all(); + ul_harq.reset_ndi(); - + mux_unit.msg3_flush(); mux_unit.reset(); - - ra_procedure.reset(); + + ra_procedure.reset(); sr_procedure.reset(); bsr_procedure.reset(); phr_procedure.reset(); - + dl_harq.reset(); phy_h->pdcch_dl_search_reset(); phy_h->pdcch_ul_search_reset(); - - signals_pregenerated = false; - is_first_ul_grant = true; - + + is_first_ul_grant = true; + bzero(&uernti, sizeof(ue_rnti_t)); } void mac::run_thread() { int cnt=0; - - Info("Waiting PHY to synchronize with cell\n"); - phy_h->sync_start(); - while(!phy_h->get_current_tti() && started) { - usleep(50000); + + while (!phy_h->sync_status() && started) { + usleep(5000); + if (phy_h->sync_status()) { + Debug("Setting ttysync to %d\n", phy_h->get_current_tti()); + ttisync.set_producer_cntr(phy_h->get_current_tti()); + } } - Debug("Setting ttysync to %d\n", phy_h->get_current_tti()); - ttisync.set_producer_cntr(phy_h->get_current_tti()); - + while(started) { /* Warning: Here order of invocation of procedures is important!! */ ttisync.wait(); tti = phy_h->get_current_tti(); - - if (started) { - log_h->step(tti); - - timers_db.step_all(); - - // Step all procedures - bsr_procedure.step(tti); - phr_procedure.step(tti); - - // Check if BSR procedure need to start SR - - if (bsr_procedure.need_to_send_sr(tti)) { - Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti); - sr_procedure.start(); - } - if (bsr_procedure.need_to_reset_sr()) { - Debug("Resetting SR procedure by BSR request\n"); - sr_procedure.reset(); - } - sr_procedure.step(tti); - // Check SR if we need to start RA - if (sr_procedure.need_random_access()) { - ra_procedure.start_mac_order(); - } - ra_procedure.step(tti); - - if (ra_procedure.is_successful() && !signals_pregenerated) { - - // Configure PHY to look for UL C-RNTI grants - phy_h->pdcch_ul_search(SRSLTE_RNTI_USER, uernti.crnti); - phy_h->pdcch_dl_search(SRSLTE_RNTI_USER, uernti.crnti); - - // Pregenerate UL signals and C-RNTI scrambling sequences - Debug("Pre-computing C-RNTI scrambling sequences for C-RNTI=0x%x\n", uernti.crnti); - phy_h->set_crnti(uernti.crnti); - signals_pregenerated = true; - } + log_h->step(tti); + timers.step_all(); + + // Step all procedures + bsr_procedure.step(tti); + phr_procedure.step(tti); + + // Check if BSR procedure need to start SR + + if (bsr_procedure.need_to_send_sr(tti)) { + Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti); + sr_procedure.start(); } - } + if (bsr_procedure.need_to_reset_sr()) { + Debug("Resetting SR procedure by BSR request\n"); + sr_procedure.reset(); + } + sr_procedure.step(tti); + + // Check SR if we need to start RA + if (sr_procedure.need_random_access()) { + ra_procedure.start_mac_order(); + } + ra_procedure.step(tti); + } } void mac::bcch_start_rx() @@ -210,7 +195,7 @@ void mac::bcch_start_rx(int si_window_start, int si_window_length) } else { phy_h->pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, si_window_start); } - Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length); + Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length); } void mac::bcch_stop_rx() @@ -221,7 +206,7 @@ void mac::bcch_stop_rx() void mac::pcch_start_rx() { phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI); - Info("SCHED: Searching for DL grant for P-RNTI\n"); + Info("SCHED: Searching for DL grant for P-RNTI\n"); } void mac::pcch_stop_rx() @@ -237,9 +222,9 @@ void mac::tti_clock(uint32_t tti) void mac::bch_decoded_ok(uint8_t* payload, uint32_t len) { - // Send MIB to RLC + // Send MIB to RLC rlc_h->write_pdu_bcch_bch(payload, len); - + if (pcap) { pcap->write_dl_bch(payload, len, true, phy_h->get_current_tti()); } @@ -247,9 +232,9 @@ void mac::bch_decoded_ok(uint8_t* payload, uint32_t len) void mac::pch_decoded_ok(uint32_t len) { - // Send PCH payload to RLC + // Send PCH payload to RLC rlc_h->write_pdu_pcch(pch_payload_buffer, len); - + if (pcap) { pcap->write_dl_pch(pch_payload_buffer, len, true, phy_h->get_current_tti()); } @@ -280,8 +265,8 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: } else if (grant.rnti_type == SRSLTE_RNTI_PCH) { memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); - action->generate_ack = false; - action->decode_enabled = true; + action->generate_ack = false; + action->decode_enabled[0] = true; srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1); action->payload_ptr[0] = pch_payload_buffer; action->softbuffers[0] = &pch_softbuffer; @@ -289,12 +274,12 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: action->rv[0] = grant.rv[0]; if (grant.n_bytes[0] > pch_payload_buffer_sz) { Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes[0], pch_payload_buffer_sz); - action->decode_enabled = false; + action->decode_enabled[0] = false; } } else { // If PDCCH for C-RNTI and RA procedure in Contention Resolution, notify it if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { - ra_procedure.pdcch_to_crnti(false); + ra_procedure.pdcch_to_crnti(false); } dl_harq.new_grant_dl(grant, action); } @@ -309,11 +294,11 @@ void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: { /* Start PHR Periodic timer on first UL grant */ if (is_first_ul_grant) { - is_first_ul_grant = false; - timers_db.get(PHR_TIMER_PERIODIC)->run(); + is_first_ul_grant = false; + phr_procedure.start_timer(); } if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { - ra_procedure.pdcch_to_crnti(true); + ra_procedure.pdcch_to_crnti(true); } ul_harq.new_grant_ul(grant, action); metrics.tx_pkts++; @@ -356,25 +341,23 @@ void mac::setup_timers() { int value = liblte_rrc_time_alignment_timer_num[config.main.time_alignment_timer]; if (value > 0) { - timers_db.get(TIME_ALIGNMENT)->set(this, value); + timers.get(timer_alignment)->set(this, value); } } void mac::timer_expired(uint32_t timer_id) { - switch(timer_id) { - case TIME_ALIGNMENT: - timeAlignmentTimerExpire(); - break; - default: - break; + if(timer_id == timer_alignment) { + timer_alignment_expire(); + } else { + Warning("Received callback from unknown timer_id=%d\n", timer_id); } } /* Function called on expiry of TimeAlignmentTimer */ -void mac::timeAlignmentTimerExpire() +void mac::timer_alignment_expire() { - printf("timeAlignmentTimer has expired value=%d ms\n", timers_db.get(TIME_ALIGNMENT)->get_timeout()); + printf("TimeAlignment timer has expired value=%d ms\n", timers.get(timer_alignment)->get_timeout()); rrc_h->release_pucch_srs(); dl_harq.reset(); ul_harq.reset(); @@ -387,7 +370,7 @@ void mac::get_rntis(ue_rnti_t* rntis) void mac::set_contention_id(uint64_t uecri) { - uernti.contention_id = uecri; + uernti.contention_id = uecri; } void mac::get_config(mac_cfg_t* mac_cfg) @@ -420,32 +403,20 @@ void mac::set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT* sr_cfg) void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) { - Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSd=%d\n", + Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSd=%d\n", lcid, lcg, priority, PBR_x_tti, BSD); mux_unit.set_priority(lcid, priority, PBR_x_tti, BSD); bsr_procedure.setup_lcg(lcid, lcg); bsr_procedure.set_priority(lcid, priority); } -uint32_t mac::get_unique_id() -{ - return upper_timers_thread.get_unique_id(); -} - -/* Front-end to upper-layer timers */ -srslte::timers::timer* mac::get(uint32_t timer_id) -{ - return upper_timers_thread.get(timer_id); -} - - void mac::get_metrics(mac_metrics_t &m) { Info("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f\n", metrics.rx_pkts?((float) 100*metrics.rx_errors/metrics.rx_pkts):0.0, dl_harq.get_average_retx(), metrics.tx_pkts?((float) 100*metrics.tx_errors/metrics.tx_pkts):0.0, - dl_harq.get_average_retx()); + ul_harq.get_average_retx()); metrics.ul_buffer = (int) bsr_procedure.get_buffer_state(); m = metrics; @@ -453,44 +424,33 @@ void mac::get_metrics(mac_metrics_t &m) } + + /******************************************************** * - * Class to run upper-layer timers with normal priority + * Interface for timers used by upper layers * *******************************************************/ - -mac::upper_timers::upper_timers() : timers_db(MAC_NOF_UPPER_TIMERS) +srslte::timers::timer* mac::timer_get(uint32_t timer_id) { - start_periodic(1000, MAC_MAIN_THREAD_PRIO+1); + return timers.get(timer_id); } -void mac::upper_timers::run_period() +void mac::timer_release_id(uint32_t timer_id) { - timers_db.step_all(); -} - -srslte::timers::timer* mac::upper_timers::get(uint32_t timer_id) -{ - return timers_db.get(timer_id%MAC_NOF_UPPER_TIMERS); -} - -uint32_t mac::upper_timers::get_unique_id() -{ - return timers_db.get_unique_id(); + timers.release_id(timer_id); } -void mac::upper_timers::reset() +uint32_t mac::timer_get_unique_id() { - timers_db.stop_all(); + return timers.get_unique_id(); } - - /******************************************************** * * Class that runs a thread to process DL MAC PDUs from - * DEMU unit + * DEMUX unit * *******************************************************/ mac::pdu_process::pdu_process(demux *demux_unit_) diff --git a/srsue/src/mac/mux.cc b/srsue/src/mac/mux.cc index 5ab58fb50..e38300b87 100644 --- a/srsue/src/mac/mux.cc +++ b/srsue/src/mac/mux.cc @@ -349,14 +349,19 @@ bool mux::msg3_is_transmitted() /* Returns a pointer to the Msg3 buffer */ uint8_t* mux::msg3_get(uint8_t *payload, uint32_t pdu_sz) { - uint8_t* msg3_buff_start_pdu = pdu_get(msg3_buff, pdu_sz, 0, 0); - if (!msg3_buff_start_pdu) { - Error("Moving PDU from Mux unit to Msg3 buffer\n"); + if (pdu_sz < MSG3_BUFF_SZ - 32) { + uint8_t* msg3_buff_start_pdu = pdu_get(msg3_buff, pdu_sz, 0, 0); + if (!msg3_buff_start_pdu) { + Error("Moving PDU from Mux unit to Msg3 buffer\n"); + return NULL; + } + memcpy(payload, msg3_buff_start_pdu, sizeof(uint8_t)*pdu_sz); + msg3_has_been_transmitted = true; + return payload; + } else { + Error("Msg3 size (%d) is longer than internal msg3_buff size=%d, (see mux.h)\n", pdu_sz, MSG3_BUFF_SZ-32); return NULL; - } - memcpy(payload, msg3_buff_start_pdu, sizeof(uint8_t)*pdu_sz); - msg3_has_been_transmitted = true; - return payload; + } } diff --git a/srsue/src/mac/proc_bsr.cc b/srsue/src/mac/proc_bsr.cc index 3117eeffc..898943ab9 100644 --- a/srsue/src/mac/proc_bsr.cc +++ b/srsue/src/mac/proc_bsr.cc @@ -50,17 +50,21 @@ void bsr_proc::init(rlc_interface_mac *rlc_, srslte::log* log_h_, mac_interface_ log_h = log_h_; rlc = rlc_; mac_cfg = mac_cfg_; - timers_db = timers_db_; + timers_db = timers_db_; + + timer_periodic_id = timers_db->get_unique_id(); + timer_retx_id = timers_db->get_unique_id(); + reset(); initiated = true; } void bsr_proc::reset() { - timers_db->get(BSR_TIMER_PERIODIC)->stop(); - timers_db->get(BSR_TIMER_PERIODIC)->reset(); - timers_db->get(BSR_TIMER_RETX)->stop(); - timers_db->get(BSR_TIMER_RETX)->reset(); + timers_db->get(timer_periodic_id)->stop(); + timers_db->get(timer_periodic_id)->reset(); + timers_db->get(timer_retx_id)->stop(); + timers_db->get(timer_retx_id)->reset(); reset_sr = false; sr_is_sent = false; @@ -77,23 +81,20 @@ void bsr_proc::reset() /* Process Periodic BSR */ void bsr_proc::timer_expired(uint32_t timer_id) { - switch(timer_id) { - case BSR_TIMER_PERIODIC: - if (triggered_bsr_type == NONE) { - // Check condition 4 in Sec 5.4.5 - triggered_bsr_type = PERIODIC; - Debug("BSR: Triggering Periodic BSR\n"); - } - break; - case BSR_TIMER_RETX: - // Enable reTx of SR only if periodic timer is not infinity - int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer]; - if (periodic >= 0) { - triggered_bsr_type = REGULAR; - Debug("BSR: Triggering BSR reTX\n"); - sr_is_sent = false; - } - break; + if(timer_id == timer_periodic_id) { + if (triggered_bsr_type == NONE) { + // Check condition 4 in Sec 5.4.5 + triggered_bsr_type = PERIODIC; + Debug("BSR: Triggering Periodic BSR\n"); + } + } else if (timer_id == timer_retx_id) { + // Enable reTx of SR only if periodic timer is not infinity + int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer]; + if (periodic >= 0) { + triggered_bsr_type = REGULAR; + Debug("BSR: Triggering BSR reTX\n"); + sr_is_sent = false; + } } } @@ -222,17 +223,17 @@ void bsr_proc::step(uint32_t tti) } int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer]; - if (periodic > 0 && (uint32_t)periodic != timers_db->get(BSR_TIMER_PERIODIC)->get_timeout()) + if (periodic > 0 && (uint32_t)periodic != timers_db->get(timer_periodic_id)->get_timeout()) { - timers_db->get(BSR_TIMER_PERIODIC)->set(this, periodic); - timers_db->get(BSR_TIMER_PERIODIC)->run(); + timers_db->get(timer_periodic_id)->set(this, periodic); + timers_db->get(timer_periodic_id)->run(); Info("BSR: Configured timer periodic %d ms\n", periodic); } int retx = liblte_rrc_retransmission_bsr_timer_num[mac_cfg->main.ulsch_cnfg.retx_bsr_timer]; - if (retx > 0 && (uint32_t)retx != timers_db->get(BSR_TIMER_RETX)->get_timeout()) + if (retx > 0 && (uint32_t)retx != timers_db->get(timer_retx_id)->get_timeout()) { - timers_db->get(BSR_TIMER_RETX)->set(this, retx); - timers_db->get(BSR_TIMER_RETX)->run(); + timers_db->get(timer_retx_id)->set(this, retx); + timers_db->get(timer_retx_id)->run(); Info("BSR: Configured timer reTX %d ms\n", retx); } @@ -309,18 +310,18 @@ bool bsr_proc::need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr) grant_size, total_data, bsr_sz); ret = true; } - if (timers_db->get(BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) { - timers_db->get(BSR_TIMER_PERIODIC)->reset(); - timers_db->get(BSR_TIMER_PERIODIC)->run(); + if (timers_db->get(timer_periodic_id)->get_timeout() && bsr->format != TRUNC_BSR) { + timers_db->get(timer_periodic_id)->reset(); + timers_db->get(timer_periodic_id)->run(); } } // Cancel all triggered BSR and SR triggered_bsr_type = NONE; reset_sr = true; // Restart or Start ReTX timer - if (timers_db->get(BSR_TIMER_RETX)->get_timeout()) { - timers_db->get(BSR_TIMER_RETX)->reset(); - timers_db->get(BSR_TIMER_RETX)->run(); + if (timers_db->get(timer_retx_id)->get_timeout()) { + timers_db->get(timer_retx_id)->reset(); + timers_db->get(timer_retx_id)->run(); } return ret; } @@ -340,9 +341,9 @@ bool bsr_proc::generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr) bsr_type_tostring(triggered_bsr_type), bsr_format_tostring(bsr->format), bsr->buff_size[0], bsr->buff_size[1], bsr->buff_size[2], bsr->buff_size[3]); - if (timers_db->get(BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) { - timers_db->get(BSR_TIMER_PERIODIC)->reset(); - timers_db->get(BSR_TIMER_PERIODIC)->run(); + if (timers_db->get(timer_periodic_id)->get_timeout() && bsr->format != TRUNC_BSR) { + timers_db->get(timer_periodic_id)->reset(); + timers_db->get(timer_periodic_id)->run(); } } diff --git a/srsue/src/mac/proc_phr.cc b/srsue/src/mac/proc_phr.cc index 11828f306..ead0bf153 100644 --- a/srsue/src/mac/proc_phr.cc +++ b/srsue/src/mac/proc_phr.cc @@ -49,14 +49,18 @@ void phr_proc::init(phy_interface_mac* phy_h_, srslte::log* log_h_, mac_interfac mac_cfg = mac_cfg_; timers_db = timers_db_; initiated = true; + + timer_periodic_id = timers_db->get_unique_id(); + timer_prohibit_id = timers_db->get_unique_id(); + reset(); } void phr_proc::reset() { phr_is_triggered = false; - timer_periodic = -2; - timer_prohibit = -2; + timer_periodic_value = -2; + timer_prohibit_value = -2; dl_pathloss_change = -2; } @@ -72,23 +76,26 @@ bool phr_proc::pathloss_changed() { return false; } } + +void phr_proc::start_timer() { + timers_db->get(timer_periodic_id)->run(); +} /* Trigger PHR when timers exire */ void phr_proc::timer_expired(uint32_t timer_id) { - switch(timer_id) { - case PHR_TIMER_PERIODIC: - timers_db->get(PHR_TIMER_PERIODIC)->reset(); - timers_db->get(PHR_TIMER_PERIODIC)->run(); - Debug("PHR: Triggered by timer periodic (timer expired).\n"); - phr_is_triggered = true; - break; - case PHR_TIMER_PROHIBIT: - int pathloss_db = liblte_rrc_dl_pathloss_change_num[mac_cfg->main.phr_cnfg.dl_pathloss_change]; - if (pathloss_changed()) { - Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f (timer expired)\n", last_pathloss_db); - phr_is_triggered = true; - } - break; + if(timer_id == timer_periodic_id) { + timers_db->get(timer_periodic_id)->reset(); + timers_db->get(timer_periodic_id)->run(); + Debug("PHR: Triggered by timer periodic (timer expired).\n"); + phr_is_triggered = true; + } else if (timer_id == timer_prohibit_id) { + int pathloss_db = liblte_rrc_dl_pathloss_change_num[mac_cfg->main.phr_cnfg.dl_pathloss_change]; + if (pathloss_changed()) { + Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f (timer expired)\n", last_pathloss_db); + phr_is_triggered = true; + } + } else { + log_h->warning("Received timer callback from unknown timer_id=%d\n", timer_id); } } @@ -102,28 +109,28 @@ void phr_proc::step(uint32_t tti) int cfg_timer_periodic = liblte_rrc_periodic_phr_timer_num[mac_cfg->main.phr_cnfg.periodic_phr_timer]; // Setup timers and trigger PHR when configuration changed by higher layers - if (timer_periodic != cfg_timer_periodic && cfg_timer_periodic > 0) + if (timer_periodic_value != cfg_timer_periodic && cfg_timer_periodic > 0) { - timer_periodic = cfg_timer_periodic; - timers_db->get(PHR_TIMER_PERIODIC)->set(this, timer_periodic); - timers_db->get(PHR_TIMER_PERIODIC)->run(); + timer_periodic_value = cfg_timer_periodic; + timers_db->get(timer_periodic_id)->set(this, timer_periodic_value); + timers_db->get(timer_periodic_id)->run(); phr_is_triggered = true; - Info("PHR: Configured timer periodic %d ms\n", timer_periodic); + Info("PHR: Configured timer periodic %d ms\n", timer_periodic_value); } } int cfg_timer_prohibit = liblte_rrc_prohibit_phr_timer_num[mac_cfg->main.phr_cnfg.prohibit_phr_timer]; - if (timer_prohibit != cfg_timer_prohibit && cfg_timer_prohibit > 0) + if (timer_prohibit_value != cfg_timer_prohibit && cfg_timer_prohibit > 0) { - timer_prohibit = cfg_timer_prohibit; - timers_db->get(PHR_TIMER_PROHIBIT)->set(this, timer_prohibit); - timers_db->get(PHR_TIMER_PROHIBIT)->run(); - Info("PHR: Configured timer prohibit %d ms\n", timer_prohibit); + timer_prohibit_value = cfg_timer_prohibit; + timers_db->get(timer_prohibit_id)->set(this, timer_prohibit_value); + timers_db->get(timer_prohibit_id)->run(); + Info("PHR: Configured timer prohibit %d ms\n", timer_prohibit_value); phr_is_triggered = true; } - if (pathloss_changed() && timers_db->get(PHR_TIMER_PROHIBIT)->is_expired()) + if (pathloss_changed() && timers_db->get(timer_prohibit_id)->is_expired()) { Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f\n", last_pathloss_db); phr_is_triggered = true; @@ -140,10 +147,10 @@ bool phr_proc::generate_phr_on_ul_grant(float *phr) Debug("PHR: Generating PHR=%f\n", phr?*phr:0.0); - timers_db->get(PHR_TIMER_PERIODIC)->reset(); - timers_db->get(PHR_TIMER_PROHIBIT)->reset(); - timers_db->get(PHR_TIMER_PERIODIC)->run(); - timers_db->get(PHR_TIMER_PROHIBIT)->run(); + timers_db->get(timer_periodic_id)->reset(); + timers_db->get(timer_prohibit_id)->reset(); + timers_db->get(timer_periodic_id)->run(); + timers_db->get(timer_prohibit_id)->run(); phr_is_triggered = false; diff --git a/srsue/src/mac/proc_ra.cc b/srsue/src/mac/proc_ra.cc index 98fed02fc..4bceef2a5 100644 --- a/srsue/src/mac/proc_ra.cc +++ b/srsue/src/mac/proc_ra.cc @@ -53,7 +53,8 @@ void ra_proc::init(phy_interface_mac* phy_h_, srslte::log* log_h_, mac_interface_rrc::ue_rnti_t *rntis_, mac_interface_rrc::mac_cfg_t *mac_cfg_, - srslte::timers* timers_db_, + srslte::timers::timer* time_alignment_timer_, + srslte::timers::timer* contention_resolution_timer_, mux* mux_unit_, demux* demux_unit_) { @@ -61,10 +62,13 @@ void ra_proc::init(phy_interface_mac* phy_h_, log_h = log_h_; mac_cfg = mac_cfg_; rntis = rntis_; - timers_db = timers_db_; mux_unit = mux_unit_; demux_unit= demux_unit_; - rrc = rrc_; + rrc = rrc_; + + time_alignment_timer = time_alignment_timer_; + contention_resolution_timer = contention_resolution_timer_; + srslte_softbuffer_rx_init(&softbuffer_rar, 10); // Tell demux to call us when a UE CRID is received @@ -73,6 +77,10 @@ void ra_proc::init(phy_interface_mac* phy_h_, reset(); } +ra_proc::~ra_proc() { + srslte_softbuffer_rx_free(&softbuffer_rar); +} + void ra_proc::reset() { state = IDLE; msg3_transmitted = false; @@ -115,7 +123,7 @@ void ra_proc::read_params() { delta_preamble_db = delta_preamble_db_table[configIndex%5]; if (contentionResolutionTimer > 0) { - timers_db->get(CONTENTION_TIMER)->set(this, contentionResolutionTimer); + contention_resolution_timer->set(this, contentionResolutionTimer); } } @@ -165,14 +173,14 @@ void ra_proc::process_timeadv_cmd(uint32_t ta) { if (preambleIndex == 0) { // Preamble not selected by UE MAC phy_h->set_timeadv_rar(ta); - timers_db->get(TIME_ALIGNMENT)->reset(); - timers_db->get(TIME_ALIGNMENT)->run(); + time_alignment_timer->reset(); + time_alignment_timer->run(); Debug("Applying RAR TA CMD %d\n", ta); } else { // Preamble selected by UE MAC - if (!timers_db->get(TIME_ALIGNMENT)->is_running()) { + if (!time_alignment_timer->is_running()) { phy_h->set_timeadv_rar(ta); - timers_db->get(TIME_ALIGNMENT)->run(); + time_alignment_timer->run(); Debug("Applying RAR TA CMD %d\n", ta); } else { // Ignore TA CMD @@ -271,8 +279,9 @@ void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_p { if (grant.n_bytes[0] < MAX_RAR_PDU_LEN) { rDebug("DL grant found RA-RNTI=%d\n", ra_rnti); - action->decode_enabled = true; - action->default_ack = false; + action->decode_enabled[0] = true; + action->decode_enabled[1] = false; + action->default_ack[0] = false; action->generate_ack = false; action->payload_ptr[0] = rar_pdu_buffer; action->rnti = grant.rnti; @@ -286,7 +295,8 @@ void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_p } } else { rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes[0], MAX_RAR_PDU_LEN); - action->decode_enabled = false; + action->decode_enabled[0] = false; + action->decode_enabled[1] = false; state = RESPONSE_ERROR; } } @@ -355,8 +365,8 @@ void ra_proc::tb_decoded_ok() { state = CONTENTION_RESOLUTION; // Start contention resolution timer - timers_db->get(CONTENTION_TIMER)->reset(); - timers_db->get(CONTENTION_TIMER)->run(); + contention_resolution_timer->reset(); + contention_resolution_timer->run(); } } else { rDebug("Found RAR for preamble %d\n", rar_pdu_msg.get()->get_rapid()); @@ -417,7 +427,7 @@ bool ra_proc::contention_resolution_id_received(uint64_t rx_contention_id) { rDebug("MAC PDU Contains Contention Resolution ID CE\n"); // MAC PDU successfully decoded and contains MAC CE contention Id - timers_db->get(CONTENTION_TIMER)->stop(); + contention_resolution_timer->stop(); if (transmitted_contention_id == rx_contention_id) { @@ -453,7 +463,7 @@ void ra_proc::step_contention_resolution() { (started_by_pdcch && pdcch_to_crnti_received != PDCCH_CRNTI_NOT_RECEIVED)) { rDebug("PDCCH for C-RNTI received\n"); - timers_db->get(CONTENTION_TIMER)->stop(); + contention_resolution_timer->stop(); rntis->temp_rnti = 0; state = COMPLETION; } @@ -479,6 +489,12 @@ void ra_proc::step_completition() { mux_unit->msg3_flush(); msg3_flushed = true; } + // Configure PHY to look for UL C-RNTI grants + phy_h->pdcch_ul_search(SRSLTE_RNTI_USER, rntis->crnti); + phy_h->pdcch_dl_search(SRSLTE_RNTI_USER, rntis->crnti); + + phy_h->set_crnti(rntis->crnti); + msg3_transmitted = false; state = COMPLETION_DONE; } @@ -559,7 +575,7 @@ void ra_proc::pdcch_to_crnti(bool contains_uplink_grant) { void ra_proc::harq_retx() { - timers_db->get(CONTENTION_TIMER)->reset(); + contention_resolution_timer->reset(); } } diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 16e0cb59f..569083998 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -38,6 +38,8 @@ #include "ue.h" #include "metrics_stdout.h" +#include "metrics_csv.h" +#include "srslte/common/metrics_hub.h" #include "srslte/version.h" using namespace std; @@ -61,8 +63,8 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { // Command line or config file options bpo::options_description common("Configuration options"); common.add_options() - ("rf.dl_freq", bpo::value(&args->rf.dl_freq)->default_value(2680000000), "Downlink centre frequency") - ("rf.ul_freq", bpo::value(&args->rf.ul_freq)->default_value(2560000000), "Uplink centre frequency") + ("rf.dl_earfcn", bpo::value(&args->rf.dl_earfcn)->default_value(3400), "Downlink EARFCN") + ("rf.freq_offset", bpo::value(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset") ("rf.rx_gain", bpo::value(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain") ("rf.tx_gain", bpo::value(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain") ("rf.nof_rx_ant", bpo::value(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas") @@ -103,6 +105,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("log.usim_level", bpo::value(&args->log.usim_level), "USIM log level") ("log.usim_hex_limit", bpo::value(&args->log.usim_hex_limit), "USIM log hex dump limit") + ("log.all_level", bpo::value(&args->log.all_level)->default_value("info"), "ALL log level") ("log.all_hex_limit", bpo::value(&args->log.all_hex_limit)->default_value(32), "ALL log hex dump limit") @@ -133,6 +136,14 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { bpo::value(&args->expert.metrics_period_secs)->default_value(1.0), "Periodicity for metrics in seconds") + ("expert.metrics_csv_enable", + bpo::value(&args->expert.metrics_csv_enable)->default_value(false), + "Write UE metrics to CSV file") + + ("expert.metrics_csv_filename", + bpo::value(&args->expert.metrics_csv_filename)->default_value("/tmp/ue_metrics.csv"), + "Metrics CSV filename") + ("expert.pregenerate_signals", bpo::value(&args->expert.pregenerate_signals)->default_value(false), "Pregenerate uplink signals after attach. Improves CPU performance.") @@ -319,13 +330,13 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { static bool running = true; static bool do_metrics = false; +metrics_stdout metrics_screen; void sig_int_handler(int signo) { running = false; } void *input_loop(void *m) { - metrics_stdout *metrics = (metrics_stdout *) m; char key; while (running) { cin >> key; @@ -336,7 +347,7 @@ void *input_loop(void *m) { } else { cout << "Enter t to restart trace." << endl; } - metrics->toggle_print(do_metrics); + metrics_screen.toggle_print(do_metrics); } } return NULL; @@ -344,11 +355,11 @@ void *input_loop(void *m) { int main(int argc, char *argv[]) { + srslte::metrics_hub metricshub; signal(SIGINT, sig_int_handler); all_args_t args; parse_args(&args, argc, argv); - srsue_instance_type_t type = LTE; ue_base *ue = ue_base::get_instance(type); if (!ue) { @@ -361,11 +372,18 @@ int main(int argc, char *argv[]) exit(1); } - metrics_stdout metrics; - metrics.init(ue, args.expert.metrics_period_secs); + metricshub.init(ue, args.expert.metrics_period_secs); + metricshub.add_listener(&metrics_screen); + metrics_screen.set_ue_handle(ue); + + metrics_csv metrics_file(args.expert.metrics_csv_filename); + if (args.expert.metrics_csv_enable) { + metricshub.add_listener(&metrics_file); + metrics_file.set_ue_handle(ue); + } pthread_t input; - pthread_create(&input, NULL, &input_loop, &metrics); + pthread_create(&input, NULL, &input_loop, &args); bool plot_started = false; bool signals_pregenerated = false; @@ -383,7 +401,7 @@ int main(int argc, char *argv[]) sleep(1); } pthread_cancel(input); - metrics.stop(); + metricshub.stop(); ue->stop(); ue->cleanup(); cout << "--- exiting ---" << endl; diff --git a/srsue/src/metrics_csv.cc b/srsue/src/metrics_csv.cc new file mode 100644 index 000000000..f9bdce213 --- /dev/null +++ b/srsue/src/metrics_csv.cc @@ -0,0 +1,105 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2015 The srsUE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \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 "metrics_csv.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +namespace srsue{ + +metrics_csv::metrics_csv(std::string filename) + :n_reports(0) + ,ue(NULL) +{ + file.open(filename.c_str()); +} + +void metrics_csv::set_ue_handle(ue_metrics_interface *ue_) +{ + ue = ue_; +} + +void metrics_csv::set_metrics(ue_metrics_t &metrics, float metrics_report_period) +{ + if (file.is_open() && ue != NULL) { + if(n_reports == 0) { + file << "time;rsrp;pl;cfo;dl_mcs;dl_snr;dl_turbo;dl_brate;dl_bler;ul_mcs;ul_buff;ul_brate;ul_bler;rf_o;rf_u;rf_l;is_attached" << endl; + } + file << (metrics_report_period*n_reports) << ";"; + file << float_to_string(metrics.phy.dl.rsrp, 2); + file << float_to_string(metrics.phy.dl.pathloss, 2); + file << float_to_string(metrics.phy.sync.cfo, 2); + file << float_to_string(metrics.phy.dl.mcs, 2); + file << float_to_string(metrics.phy.dl.sinr, 2); + file << float_to_string(metrics.phy.dl.turbo_iters, 2); + file << float_to_string((float) metrics.mac.rx_brate/metrics_report_period, 2); + if (metrics.mac.rx_pkts > 0) { + file << float_to_string((float) 100*metrics.mac.rx_errors/metrics.mac.rx_pkts, 1); + } else { + file << float_to_string(0, 2); + } + file << float_to_string(metrics.phy.ul.mcs, 2); + file << float_to_string((float) metrics.mac.ul_buffer, 2); + file << float_to_string((float) metrics.mac.tx_brate/metrics_report_period, 2); + if (metrics.mac.tx_pkts > 0) { + file << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1); + } else { + file << float_to_string(0, 2); + } + file << float_to_string(metrics.rf.rf_o, 2); + file << float_to_string(metrics.rf.rf_u, 2); + file << float_to_string(metrics.rf.rf_l, 2); + file << (ue->is_attached() ? "1.0" : "0.0"); + file << endl; + + n_reports++; + } else { + std::cout << "Error, couldn't write CSV file." << std::endl; + } +} + +std::string metrics_csv::float_to_string(float f, int digits, bool add_semicolon) +{ + std::ostringstream os; + const int precision = (f == 0.0) ? digits-1 : digits - log10(fabs(f))-2*DBL_EPSILON; + os << std::fixed << std::setprecision(precision) << f; + if (add_semicolon) + os << ';'; + return os.str(); +} + +} // namespace srsue diff --git a/srsue/src/metrics_stdout.cc b/srsue/src/metrics_stdout.cc index 0a86683d2..048532c8f 100644 --- a/srsue/src/metrics_stdout.cc +++ b/srsue/src/metrics_stdout.cc @@ -48,29 +48,15 @@ char const * const prefixes[2][9] = }; metrics_stdout::metrics_stdout() - :started(false) - ,do_print(false) + :do_print(false) ,n_reports(10) + ,ue(NULL) { } -bool metrics_stdout::init(ue_metrics_interface *u, float report_period_secs) +void metrics_stdout::set_ue_handle(ue_metrics_interface *ue_) { - ue_ = u; - metrics_report_period = report_period_secs; - - started = true; - pthread_create(&metrics_thread, NULL, &metrics_thread_start, this); - return true; -} - -void metrics_stdout::stop() -{ - if(started) - { - started = false; - pthread_join(metrics_thread, NULL); - } + ue = ue_; } void metrics_stdout::toggle_print(bool b) @@ -78,30 +64,16 @@ void metrics_stdout::toggle_print(bool b) do_print = b; } -void* metrics_stdout::metrics_thread_start(void *m_) -{ - metrics_stdout *m = (metrics_stdout*)m_; - m->metrics_thread_run(); - return NULL; -} -void metrics_stdout::metrics_thread_run() +void metrics_stdout::set_metrics(ue_metrics_t &metrics, float metrics_report_period) { - while(started) - { - usleep(metrics_report_period*1e6); - if(ue_->get_metrics(metrics)) { - print_metrics(); - } else { - print_disconnect(); - } - } -} + if(!do_print || ue == NULL) + return; -void metrics_stdout::print_metrics() -{ - if(!do_print) + if (!ue->is_attached()) { + cout << "--- disconnected ---" << endl; return; + } if(++n_reports > 10) { @@ -120,7 +92,7 @@ void metrics_stdout::print_metrics() if (metrics.mac.rx_pkts > 0) { cout << float_to_string((float) 100*metrics.mac.rx_errors/metrics.mac.rx_pkts, 1) << "%"; } else { - cout << float_to_string(0, 2) << "%"; + cout << float_to_string(0, 1) << "%"; } cout << float_to_string(metrics.phy.ul.mcs, 2); cout << float_to_eng_string((float) metrics.mac.ul_buffer, 2); @@ -128,7 +100,7 @@ void metrics_stdout::print_metrics() if (metrics.mac.tx_pkts > 0) { cout << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1) << "%"; } else { - cout << float_to_string(0, 2) << "%"; + cout << float_to_string(0, 1) << "%"; } cout << endl; @@ -138,13 +110,6 @@ void metrics_stdout::print_metrics() } -void metrics_stdout::print_disconnect() -{ - if(do_print) { - cout << "--- disconnected ---" << endl; - } -} - std::string metrics_stdout::float_to_string(float f, int digits) { std::ostringstream os; diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index 3c3987863..d49b1ced2 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -34,8 +34,6 @@ #define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) #define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define TX_MODE_CONTINUOUS 0 - namespace srsue { cf_t zeros[50000]; @@ -63,6 +61,10 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) cur_pusch_power = 0; bzero(zeros, 50000*sizeof(cf_t)); + // FIXME: This is an ungly fix to avoid the TX filters to empty + for (int i=0;i<50000;i++) { + zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I); + } bzero(&dl_metrics, sizeof(dl_metrics_t)); dl_metrics_read = true; dl_metrics_count = 0; @@ -74,10 +76,11 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) sync_metrics_count = 0; } -void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, mac_interface_phy *_mac) +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) { log_h = _log; - radio_h = _radio; + radio_h = _radio; + rrc = _rrc; mac = _mac; config = _config; args = _args; @@ -186,7 +189,9 @@ void phch_common::set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int dl_rnti_type = type; dl_rnti_start = tti_start; dl_rnti_end = tti_end; - Debug("Set DL rnti: start=%d, end=%d, value=0x%x\n", tti_start, tti_end, rnti_value); + if (log_h) { + Debug("Set DL rnti: start=%d, end=%d, value=0x%x\n", tti_start, tti_end, rnti_value); + } } void phch_common::reset_pending_ack(uint32_t tti) { diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 251bfd144..c14141257 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -25,6 +25,7 @@ */ #include +#include #include "srslte/srslte.h" #include "srslte/common/log.h" #include "phy/phch_worker.h" @@ -37,466 +38,766 @@ #define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) namespace srsue { - -phch_recv::phch_recv() { - running = false; +int radio_recv_wrapper_cs(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { + phch_recv *h = (phch_recv*) obj; + srslte::radio_multi *radio_h = h->radio_h; + + if (radio_h->rx_now(data, nsamples, rx_time)) { + int offset = nsamples - h->current_sflen; + if (abs(offset) < 10 && offset != 0) { + h->next_offset = offset; + } else if (nsamples < 10) { + h->next_offset = nsamples; + } + return nsamples; + } else { + return -1; + } } -void phch_recv::init(srslte::radio_multi* _radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, - prach* _prach_buffer, srslte::thread_pool* _workers_pool, - phch_common* _worker_com, srslte::log* _log_h, uint32_t nof_rx_antennas_, uint32_t prio, int sync_cpu_affinity) -{ - radio_h = _radio_handler; - log_h = _log_h; - mac = _mac; - rrc = _rrc; +double callback_set_rx_gain(void *h, double gain) { + srslte::radio_multi *radio_handler = (srslte::radio_multi *) h; + return radio_handler->set_rx_gain_th(gain); +} + + +phch_recv::phch_recv() { + bzero(&cell, sizeof(srslte_cell_t)); + running = false; +} + +void phch_recv:: init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, + prach *_prach_buffer, srslte::thread_pool *_workers_pool, + phch_common *_worker_com, srslte::log *_log_h, uint32_t nof_rx_antennas_, uint32_t prio, + int sync_cpu_affinity) { + radio_h = _radio_handler; + log_h = _log_h; + mac = _mac; + rrc = _rrc; workers_pool = _workers_pool; - worker_com = _worker_com; - prach_buffer = _prach_buffer; + worker_com = _worker_com; + prach_buffer = _prach_buffer; nof_rx_antennas = nof_rx_antennas_; - tx_mutex_cnt = 0; - running = true; - phy_state = IDLE; - time_adv_sec = 0; - cell_is_set = false; - sync_sfn_cnt = 0; - - for (uint32_t i=0;iget_nof_workers(); + reset(); + + for (uint32_t i = 0; i < nof_rx_antennas; i++) { + sf_buffer[i] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * 3 * SRSLTE_SF_LEN_PRB(100)); + } + + + if (srslte_ue_cellsearch_init_multi(&cs, 5, radio_recv_wrapper_cs, nof_rx_antennas, + this)) { + Error("SYNC: Initiating UE cell search\n"); + return; + } + + srslte_ue_cellsearch_set_nof_valid_frames(&cs, 2); + + // Set options defined in expert section + set_ue_sync_opts(&cs.ue_sync); + + if (do_agc) { + srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain); + } + + if (srslte_ue_dl_init(&ue_dl_measure, SRSLTE_MAX_PRB, nof_rx_antennas)) { + Error("SYNC: Initiating ue_dl_measure\n"); + return; + } + + if (srslte_ue_mib_init(&ue_mib, SRSLTE_MAX_PRB)) { + Error("SYNC: Initiating UE MIB decoder\n"); + return; + } + + if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_wrapper_cs, nof_rx_antennas, this)) { + Error("SYNC: Initiating ue_sync\n"); + return; + } + + if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_wrapper_cs, nof_rx_antennas, this)) { + Error("SYNC: Initiating UE MIB synchronization\n"); + return; + } + + nof_tx_mutex = MUTEX_X_WORKER * workers_pool->get_nof_workers(); worker_com->set_nof_mutex(nof_tx_mutex); - if(sync_cpu_affinity < 0){ + if (sync_cpu_affinity < 0) { start(prio); } else { start_cpu(prio, sync_cpu_affinity); } - - } -void phch_recv::stop() { - running = false; - wait_thread_finish(); - for (uint32_t i=0;irx_now(data, nsamples, rx_time)) { - int offset = nsamples-radio_h->get_tti_len(); - if (abs(offset)<10 && offset != 0) { - radio_h->tx_offset(offset); - } else if (nsamples<10) { - radio_h->tx_offset(nsamples); - } - return nsamples; - } else { - return -1; +void phch_recv::reset() { + tx_mutex_cnt = 0; + running = true; + phy_state = IDLE; + time_adv_sec = 0; + next_offset = 0; + cell_is_set = false; + sync_sfn_cnt = 0; + srate_mode = SRATE_NONE; + cell_search_in_progress = false; + current_earfcn = 0; + radio_is_resetting = false; +} + +void phch_recv::radio_error() { + log_h->error("SYNC: Receiving from radio.\n"); + phy_state = IDLE; + radio_is_resetting=true; + + // Need to find a method to effectively reset radio, reloading the driver does not work + //radio_h->reset(); + radio_h->stop(); + + fprintf(stdout, "Error while receiving samples. Restart srsUE\n"); + exit(-1); + + reset(); + radio_is_resetting=false; +} + +bool phch_recv::wait_radio_reset() { + int cnt=0; + while(cnt < 20 && radio_is_resetting) { + sleep(1); + cnt++; } + return radio_is_resetting; } -double callback_set_rx_gain(void *h, double gain) { - srslte::radio_multi *radio_handler = (srslte::radio_multi*) h; - return radio_handler->set_rx_gain_th(gain); +void phch_recv::set_agc_enable(bool enable) { + do_agc = enable; } void phch_recv::set_time_adv_sec(float _time_adv_sec) { - time_adv_sec = _time_adv_sec; + if (TX_MODE_CONTINUOUS && !radio_h->is_first_of_burst()) { + int nsamples = ceil(current_srate*_time_adv_sec); + next_offset = -nsamples; + } else { + time_adv_sec = _time_adv_sec; + } } void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { if (worker_com->args->cfo_integer_enabled) { - srslte_ue_sync_cfo_i_detec_en(q, true); + srslte_ue_sync_cfo_i_detec_en(q, true); } - - float cfo_tol = worker_com->args->cfo_correct_tol_hz; - srslte_cfo_set_tol(&q->strack.cfocorr, cfo_tol/(15000*q->fft_size)); - srslte_cfo_set_tol(&q->sfind.cfocorr, cfo_tol/(15000*q->fft_size)); - int time_correct_period = worker_com->args->time_correct_period; + srslte_ue_sync_set_cfo_tol(q, worker_com->args->cfo_correct_tol_hz); + + int time_correct_period = worker_com->args->time_correct_period; if (time_correct_period > 0) { - srslte_ue_sync_set_sample_offset_correct_period(q, time_correct_period); + srslte_ue_sync_set_sample_offset_correct_period(q, time_correct_period); } - - sss_alg_t sss_alg = SSS_FULL; + + sss_alg_t sss_alg = SSS_FULL; if (!worker_com->args->sss_algorithm.compare("diff")) { sss_alg = SSS_DIFF; } else if (!worker_com->args->sss_algorithm.compare("partial")) { sss_alg = SSS_PARTIAL_3; - } else if (!worker_com->args->sss_algorithm.compare("full")){ - sss_alg = SSS_FULL; + } else if (!worker_com->args->sss_algorithm.compare("full")) { + sss_alg = SSS_FULL; } else { - Warning("Invalid SSS algorithm %s. Using 'full'\n", worker_com->args->sss_algorithm.c_str()); + Warning("SYNC: Invalid SSS algorithm %s. Using 'full'\n", worker_com->args->sss_algorithm.c_str()); } - srslte_sync_set_sss_algorithm(&q->strack, (sss_alg_t) sss_alg); - srslte_sync_set_sss_algorithm(&q->sfind, (sss_alg_t) sss_alg); + srslte_sync_set_sss_algorithm(&q->strack, (sss_alg_t) sss_alg); + srslte_sync_set_sss_algorithm(&q->sfind, (sss_alg_t) sss_alg); } -bool phch_recv::init_cell() { +bool phch_recv::set_cell() { cell_is_set = false; - if (!srslte_ue_mib_init(&ue_mib, cell)) - { - if (!srslte_ue_sync_init_multi(&ue_sync, cell, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) - { - - // Set options defined in expert section - set_ue_sync_opts(&ue_sync); - - for (uint32_t i=0;iget_nof_workers();i++) { - if (!((phch_worker*) workers_pool->get_worker(i))->init_cell(cell)) { - Error("Error setting cell: initiating PHCH worker\n"); - return false; - } - } - radio_h->set_tti_len(SRSLTE_SF_LEN_PRB(cell.nof_prb)); - if (do_agc) { - srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, last_gain); - } - srslte_ue_sync_set_cfo(&ue_sync, cellsearch_cfo); - cell_is_set = true; - } else { - Error("Error setting cell: initiating ue_sync"); - } - } else { - Error("Error setting cell: initiating ue_mib\n"); - } - return cell_is_set; -} + if (srslte_ue_mib_set_cell(&ue_mib, cell)) { + Error("SYNC: Setting cell: initiating ue_mib\n"); + return false; + } + if (srslte_ue_sync_set_cell(&ue_sync, cell)) { + Error("SYNC: Setting cell: initiating ue_sync"); + return false; + } -void phch_recv::free_cell() -{ - if (cell_is_set) { - for (uint32_t i=0;iget_nof_workers();i++) { - ((phch_worker*) workers_pool->get_worker(i))->free_cell(); + // Set options defined in expert section + set_ue_sync_opts(&ue_sync); + + if (srslte_ue_dl_set_cell(&ue_dl_measure, cell)) { + Error("SYNC: Setting cell: initiating ue_dl_measure\n"); + return false; + } + + worker_com->set_cell(cell); + + for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) { + if (!((phch_worker *) workers_pool->get_worker(i))->set_cell(cell)) { + Error("SYNC: Setting cell: initiating PHCH worker\n"); + return false; } - prach_buffer->free_cell(); } -} + if (do_agc) { + srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, last_gain); + } + cell_is_set = true; + return cell_is_set; +} -bool phch_recv::cell_search(int force_N_id_2) -{ +int phch_recv::cell_search(int force_N_id_2) { uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - uint8_t bch_payload_bits[SRSLTE_BCH_PAYLOAD_LEN/8]; - + srslte_ue_cellsearch_result_t found_cells[3]; - srslte_ue_cellsearch_t cs; - bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t)); + bzero(&cell, sizeof(srslte_cell_t)); + bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t)); - log_h->console("Searching for cell...\n"); - if (srslte_ue_cellsearch_init_multi(&cs, SRSLTE_DEFAULT_MAX_FRAMES_PSS, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) { - Error("Initiating UE cell search\n"); - return false; + if (srate_mode != SRATE_FIND) { + srate_mode = SRATE_FIND; + radio_h->set_rx_srate(1.92e6); } - - srslte_ue_cellsearch_set_nof_valid_frames(&cs, SRSLTE_DEFAULT_NOF_VALID_PSS_FRAMES); - - // Set options defined in expert section - set_ue_sync_opts(&cs.ue_sync); - - if (do_agc) { - srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain); - } - - radio_h->set_rx_srate(1.92e6); - radio_h->start_rx(); - + start_rx(); + /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ uint32_t max_peak_cell = 0; - int ret = SRSLTE_ERROR; - + int ret = SRSLTE_ERROR; + + Info("SYNC: Searching for cell...\n"); + printf("."); fflush(stdout); + if (force_N_id_2 >= 0 && force_N_id_2 < 3) { ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]); max_peak_cell = force_N_id_2; } else { - ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell); + ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell); } last_gain = srslte_agc_get_gain(&cs.ue_sync.agc); - radio_h->stop_rx(); - srslte_ue_cellsearch_free(&cs); - if (ret < 0) { - Error("Error decoding MIB: Error searching PSS\n"); - return false; + Error("SYNC: Error decoding MIB: Error searching PSS\n"); + return -1; } else if (ret == 0) { - Error("Error decoding MIB: Could not find any PSS in this frequency\n"); - return false; + stop_rx(); + Info("SYNC: Could not find any cell in this frequency\n"); + return 0; } - - // Save result - cell.id = found_cells[max_peak_cell].cell_id; - cell.cp = found_cells[max_peak_cell].cp; + // Save result + cell.id = found_cells[max_peak_cell].cell_id; + cell.cp = found_cells[max_peak_cell].cp; cellsearch_cfo = found_cells[max_peak_cell].cfo; - - log_h->console("Found CELL ID: %d CP: %s, CFO: %.1f KHz.\nTrying to decode MIB...\n", - cell.id, srslte_cp_string(cell.cp), cellsearch_cfo/1000); - - srslte_ue_mib_sync_t ue_mib_sync; - if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, cell.id, cell.cp, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) { - Error("Initiating UE MIB synchronization\n"); - return false; + printf("\n"); + Info("SYNC: PSS/SSS detected: PCI=%d, CFO=%.1f KHz, CP=%s\n", + cell.id, cellsearch_cfo/1000, srslte_cp_string(cell.cp)); + + if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, cell.id, cell.cp)) { + Error("SYNC: Setting UE MIB cell\n"); + return false; } - - // Set options defined in expert section - set_ue_sync_opts(&ue_mib_sync.ue_sync); + + // Set options defined in expert section + set_ue_sync_opts(&ue_mib_sync.ue_sync); if (do_agc) { - srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain); + srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain); } + srslte_ue_sync_reset(&ue_mib_sync.ue_sync); srslte_ue_sync_set_cfo(&ue_mib_sync.ue_sync, cellsearch_cfo); /* Find and decode MIB */ - uint32_t sfn; - int sfn_offset; - radio_h->start_rx(); - ret = srslte_ue_mib_sync_decode(&ue_mib_sync, - SRSLTE_DEFAULT_MAX_FRAMES_PBCH, - bch_payload, &cell.nof_ports, &sfn_offset); - radio_h->stop_rx(); + int sfn_offset; + ret = srslte_ue_mib_sync_decode(&ue_mib_sync, + 40, + bch_payload, &cell.nof_ports, &sfn_offset); + stop_rx(); last_gain = srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc); cellsearch_cfo = srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); - srslte_ue_mib_sync_free(&ue_mib_sync); + + srslte_ue_sync_reset(&ue_sync); + srslte_ue_sync_set_cfo(&ue_sync, cellsearch_cfo); if (ret == 1) { srslte_pbch_mib_unpack(bch_payload, &cell, NULL); - worker_com->set_cell(cell); - srslte_cell_fprint(stdout, &cell, 0); - srslte_bit_pack_vector(bch_payload, bch_payload_bits, SRSLTE_BCH_PAYLOAD_LEN); - mac->bch_decoded_ok(bch_payload_bits, SRSLTE_BCH_PAYLOAD_LEN/8); - return true; + fprintf(stdout, "Found Cell: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", + cell.id, cell.nof_prb, cell.nof_ports, cellsearch_cfo/1000); + + Info("SYNC: MIB Decoded: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", + cell.id, cell.nof_prb, cell.nof_ports, cellsearch_cfo/1000); + + return true; + } else if (ret == 0) { + Warning("SYNC: Found PSS but could not decode PBCH\n"); + return 0; } else { - Warning("Error decoding MIB: Error decoding PBCH\n"); - return false; + Error("SYNC: Receiving MIB\n"); + return -1; } } -int phch_recv::sync_sfn(void) { - - int ret = SRSLTE_ERROR; +int phch_recv::cell_sync_sfn(void) { + + int ret = SRSLTE_ERROR; uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; srslte_ue_sync_decode_sss_on_track(&ue_sync, true); - ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer_sfn); + ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); if (ret < 0) { - Error("Error calling ue_sync_get_buffer"); + Error("SYNC: Error calling ue_sync_get_buffer"); return -1; } - + if (ret == 1) { if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) { - int sfn_offset=0; - Info("SYNC: Decoding MIB...\n"); - int n = srslte_ue_mib_decode(&ue_mib, sf_buffer_sfn[0], bch_payload, NULL, &sfn_offset); + int sfn_offset = 0; + Info("SYNC: Trying to decode MIB... SNR=%.1f dB\n", + 10*log10(srslte_chest_dl_get_snr(&ue_mib.chest))); + int n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset); if (n < 0) { - Error("Error decoding MIB while synchronising SFN"); - return -1; - } else if (n == SRSLTE_UE_MIB_FOUND) { - uint32_t sfn; + Error("SYNC: Error decoding MIB while synchronising SFN"); + return -1; + } else if (n == SRSLTE_UE_MIB_FOUND) { + uint32_t sfn; srslte_pbch_mib_unpack(bch_payload, &cell, &sfn); - sfn = (sfn + sfn_offset)%1024; - tti = sfn*10; - + sfn = (sfn+sfn_offset)%1024; + tti = sfn * 10; + srslte_ue_sync_decode_sss_on_track(&ue_sync, true); Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", tti, sfn_offset); srslte_ue_mib_reset(&ue_mib); return 1; } - } + } } else { Debug("SYNC: PSS/SSS not found...\n"); } return 0; } -void phch_recv::resync_sfn() { - sync_sfn_cnt = 0; - phy_state = SYNCING; +int phch_recv::cell_meas_rsrp() { + + uint32_t cfi = 0; + + tti = (tti+1) % 10240; + log_h->step(tti); + + uint32_t sf_idx = tti%10; + + int sync_res = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); + if (sync_res == 1) { + if (srslte_ue_dl_decode_fft_estimate(&ue_dl_measure, sf_buffer, sf_idx, &cfi)) { + log_h->error("SYNC: Measuring RSRP: Estimating channel\n"); + return -1; + } + float rsrp = srslte_chest_dl_get_rsrp(&ue_dl_measure.chest); + float snr = srslte_chest_dl_get_snr(&ue_dl_measure.chest); + measure_rsrp = SRSLTE_VEC_CMA(rsrp, measure_rsrp, measure_cnt); + measure_cnt++; + log_h->info("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", + measure_cnt, RSRP_MEASURE_NOF_FRAMES, sf_idx, 10 * log10(rsrp / 1000), 10*log10(snr)); + if (measure_cnt >= RSRP_MEASURE_NOF_FRAMES) { + return 1; + } + } else { + log_h->error("SYNC: Measuring RSRP: Sync error\n"); + return -1; + } + + return 0; +} + +void phch_recv::resync_sfn(bool is_connected) { + + wait_radio_reset(); + + stop_rx(); + start_rx(); + srslte_ue_mib_reset(&ue_mib); + Info("SYNC: Starting SFN synchronization\n"); + sync_sfn_cnt = 0; + phy_state = is_connected?CELL_RESELECT:CELL_SELECT; +} + +void phch_recv::set_earfcn(std::vector earfcn) { + this->earfcn = earfcn; +} + +bool phch_recv::stop_sync() { + + wait_radio_reset(); + + if (phy_state == IDLE && is_in_idle) { + return true; + } else { + Info("SYNC: Going to IDLE\n"); + phy_state = IDLE; + int cnt = 0; + while (!is_in_idle && cnt < 100) { + usleep(10000); + cnt++; + } + return is_in_idle; + } +} + +void phch_recv::reset_sync() { + + wait_radio_reset(); + + Warning("SYNC: Resetting sync, cell_search_in_progress=%s\n", cell_search_in_progress?"yes":"no"); + srslte_ue_sync_reset(&ue_mib_sync.ue_sync); + srslte_ue_sync_reset(&ue_sync); + resync_sfn(true); +} + +void phch_recv::cell_search_inc() +{ + cur_earfcn_index++; + if (cur_earfcn_index >= 0) { + if (cur_earfcn_index >= (int) earfcn.size() - 1) { + cur_earfcn_index = 0; + rrc->earfcn_end(); + } + } + Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); + if (current_earfcn != earfcn[cur_earfcn_index]) { + current_earfcn = earfcn[cur_earfcn_index]; + set_frequency(); + } +} + +void phch_recv::cell_search_next(bool reset) { + if (cell_search_in_progress || reset) { + cell_search_in_progress = false; + if (!stop_sync()) { + log_h->warning("SYNC: Couldn't stop PHY\n"); + } + if (reset) { + cur_earfcn_index = -1; + } + cell_search_inc(); + phy_state = CELL_SEARCH; + cell_search_in_progress = true; + } +} + +void phch_recv::cell_search_start() { + if (earfcn.size() > 0) { + Info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size()); + cell_search_next(true); + } else { + Info("SYNC: Empty EARFCN list. Stopping cell search...\n"); + log_h->console("Empty EARFCN list. Stopping cell search...\n"); + } +} + +void phch_recv::cell_search_stop() { + Info("SYNC: Stopping Cell Search procedure...\n"); + if (!stop_sync()) { + Error("SYNC: Stopping cell search\n"); + } + cell_search_in_progress = false; +} + +bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { + + // Check if we are already camping in this cell + if (earfcn == current_earfcn && this->cell.id == cell.id) { + log_h->info("Cell Select: Already in cell EARFCN=%d\n", earfcn); + cell_search_in_progress = false; + if (srate_mode != SRATE_CAMP) { + set_sampling_rate(); + } + if (phy_state < CELL_SELECT) { + resync_sfn(); + } + return true; + } else { + + cell_search_in_progress = false; + + if (!stop_sync()) { + log_h->warning("Still not in idle\n"); + } + + current_earfcn = earfcn; + + printf("cell select called set frequency\n"); + + if (set_frequency()) { + this->cell = cell; + log_h->info("Cell Select: Configuring cell...\n"); + + if (set_cell()) { + log_h->info("Cell Select: Synchronizing on cell...\n"); + + resync_sfn(); + + usleep(500000); // Time offset we set start_rx to start receveing samples + return true; + } else { + log_h->error("Cell Select: Configuring cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id); + } + } + return false; + } +} + +bool phch_recv::set_frequency() +{ + double dl_freq = 1e6*srslte_band_fd(current_earfcn); + double ul_freq = 1e6*srslte_band_fu(srslte_band_ul_earfcn(current_earfcn)); + if (dl_freq > 0 && ul_freq > 0) { + log_h->info("SYNC: Set DL EARFCN=%d, f_dl=%.1f MHz, f_ul=%.1f MHz\n", + current_earfcn, dl_freq / 1e6, ul_freq / 1e6); + + log_h->console("Searching cell in DL EARFCN=%d, f_dl=%.1f MHz, f_ul=%.1f MHz\n", + current_earfcn, dl_freq / 1e6, ul_freq / 1e6); + + radio_h->set_rx_freq(dl_freq); + radio_h->set_tx_freq(ul_freq); + ul_dl_factor = radio_h->get_tx_freq()/radio_h->get_rx_freq(); + + srslte_ue_sync_reset(&ue_sync); + + return true; + } else { + log_h->error("SYNC: Cell Search: Invalid EARFCN=%d\n", current_earfcn); + return false; + } } -void phch_recv::run_thread() +void phch_recv::set_sampling_rate() { - int sync_res; + current_srate = (float) srslte_sampling_freq_hz(cell.nof_prb); + current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb); + if (current_srate != -1) { + Info("SYNC: Setting sampling rate %.2f MHz\n", current_srate/1000000); + + if (30720 % ((int) current_srate / 1000) == 0) { + radio_h->set_master_clock_rate(30.72e6); + } else { + radio_h->set_master_clock_rate(23.04e6); + } + srate_mode = SRATE_CAMP; + radio_h->set_rx_srate(current_srate); + radio_h->set_tx_srate(current_srate); + } else { + Error("Error setting sampling rate for cell with %d PRBs\n", cell.nof_prb); + } +} + +void phch_recv::run_thread() { phch_worker *worker = NULL; cf_t *buffer[SRSLTE_MAX_PORTS]; - while(running) { - switch(phy_state) { + phy_state = IDLE; + is_in_idle = true; + + while (running) { + if (phy_state != IDLE) { + is_in_idle = false; + Debug("SYNC: state=%d\n", phy_state); + } + switch (phy_state) { case CELL_SEARCH: - if (cell_search()) { - log_h->console("Initializating cell configuration...\n"); - init_cell(); - float srate = (float) srslte_sampling_freq_hz(cell.nof_prb); - - if (30720%((int) srate/1000) == 0) { - radio_h->set_master_clock_rate(30.72e6); - } else { - radio_h->set_master_clock_rate(23.04e6); + if (cell_search_in_progress) { + switch(cell_search()) { + case 1: + if (!srslte_cell_isvalid(&cell)) { + Error("SYNC: Detected invalid cell\n"); + phy_state = IDLE; + break; + } + if (set_cell()) { + set_sampling_rate(); + resync_sfn(); + } + break; + case 0: + if (cell_search_in_progress) { + cell_search_inc(); + } + break; + default: + radio_error(); + break; } - - log_h->console("Setting Sampling frequency %.2f MHz\n", (float) srate/1000000); - radio_h->set_rx_srate(srate); - radio_h->set_tx_srate(srate); - - ul_dl_factor = radio_h->get_tx_freq()/radio_h->get_rx_freq(); - - Info("SYNC: Cell found. Synchronizing...\n"); - phy_state = SYNCING; - sync_sfn_cnt = 0; - srslte_ue_mib_reset(&ue_mib); } break; - case SYNCING: - + case CELL_RESELECT: + case CELL_SELECT: + srslte_ue_sync_decode_sss_on_track(&ue_sync, true); - - if (!radio_is_streaming) { - // Start streaming - radio_h->start_rx(); - radio_is_streaming = true; - } - - switch(sync_sfn()) { - default: - log_h->console("Going IDLE\n"); - phy_state = IDLE; - break; + + switch (cell_sync_sfn()) { case 1: srslte_ue_sync_set_agc_period(&ue_sync, 20); - phy_state = SYNC_DONE; - break; + if (!cell_search_in_progress) { + phy_state = CELL_CAMP; + log_h->info("Sync OK. Camping on cell PCI=%d...\n", cell.id); + } else { + measure_cnt = 0; + measure_rsrp = 0; + phy_state = CELL_MEASURE; + } + break; case 0: - break; - } + break; + default: + radio_error(); + break; + } sync_sfn_cnt++; if (sync_sfn_cnt >= SYNC_SFN_TIMEOUT) { - sync_sfn_cnt = 0; - radio_h->stop_rx(); - radio_is_streaming = false; - log_h->console("Timeout while synchronizing SFN\n"); - log_h->warning("Timeout while synchronizing SFN\n"); + sync_sfn_cnt = 0; + log_h->warning("SYNC: Timeout while synchronizing SFN\n"); + if (phy_state == CELL_SELECT) { + phy_state = CELL_SEARCH; + } else { + phy_state = IDLE; + } } - break; - case SYNC_DONE: - tti = (tti+1)%10240; - worker = (phch_worker*) workers_pool->wait_worker(tti); - sync_res = 0; - if (worker) { - for (uint32_t i=0;iinfo("SYNC: Measured OK. Camping on cell PCI=%d...\n", cell.id); + phy_state = CELL_CAMP; + rrc->cell_found(earfcn[cur_earfcn_index], cell, 10*log10(measure_rsrp/1000)); + break; + case 0: + break; + default: + radio_error(); + break; + } + break; + case CELL_CAMP: + tti = (tti+1) % 10240; + worker = (phch_worker *) workers_pool->wait_worker(tti); + if (worker) { + for (uint32_t i = 0; i < nof_rx_antennas; i++) { buffer[i] = worker->get_buffer(i); } - sync_res = srslte_ue_sync_zerocopy_multi(&ue_sync, buffer); - if (sync_res == 1) { - - log_h->step(tti); - - Debug("Worker %d synchronized\n", worker->get_id()); - - metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); - metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); - worker->set_cfo(ul_dl_factor*metrics.cfo/15000); - worker_com->set_sync_metrics(metrics); - - float sample_offset = (float) srslte_ue_sync_get_sfo(&ue_sync)/1000; - worker->set_sample_offset(sample_offset); - - /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ - srslte_timestamp_t rx_time, tx_time, tx_time_prach; - srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); - srslte_timestamp_copy(&tx_time, &rx_time); - srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec); - worker->set_tx_time(tx_time); - - Debug("Settting TTI=%d, tx_mutex=%d to worker %d\n", tti, tx_mutex_cnt, worker->get_id()); - worker->set_tti(tti, tx_mutex_cnt); - tx_mutex_cnt = (tx_mutex_cnt+1)%nof_tx_mutex; - - // Check if we need to TX a PRACH - if (prach_buffer->is_ready_to_send(tti)) { - srslte_timestamp_copy(&tx_time_prach, &rx_time); - srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf*1e-3); - prach_buffer->send(radio_h, ul_dl_factor*metrics.cfo/15000, worker_com->pathloss, tx_time_prach); - radio_h->tx_end(); - worker_com->p0_preamble = prach_buffer->get_p0_preamble(); - worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss + worker_com->p0_preamble); - } - workers_pool->start_worker(worker); - // Notify RRC in-sync every 1 frame - if ((tti%10) == 0) { - rrc->in_sync(); - log_h->debug("Sending in-sync to RRC\n"); - } - } else { - log_h->console("Sync error.\n"); - log_h->error("Sync error. Sending out-of-sync to RRC\n"); - // Notify RRC of out-of-sync frame - rrc->out_of_sync(); - worker->release(); - worker_com->reset_ul(); - phy_state = SYNCING; + switch(srslte_ue_sync_zerocopy_multi(&ue_sync, buffer)) { + case 1: + + log_h->step(tti); + + Debug("SYNC: Worker %d synchronized\n", worker->get_id()); + + metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); + metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); + worker->set_cfo(ul_dl_factor * metrics.cfo / 15000); + worker_com->set_sync_metrics(metrics); + + worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000); + + /* Compute TX time: Any transmission happens in TTI4 thus advance 4 ms the reception time */ + srslte_timestamp_t rx_time, tx_time, tx_time_prach; + srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); + srslte_timestamp_copy(&tx_time, &rx_time); + srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec); + worker->set_tx_time(tx_time, next_offset); + next_offset = 0; + + Debug("SYNC: Setting TTI=%d, tx_mutex=%d to worker %d\n", tti, tx_mutex_cnt, worker->get_id()); + worker->set_tti(tti, tx_mutex_cnt); + tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex; + + // Check if we need to TX a PRACH + if (prach_buffer->is_ready_to_send(tti)) { + srslte_timestamp_copy(&tx_time_prach, &rx_time); + srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf * 1e-3); + prach_buffer->send(radio_h, ul_dl_factor * metrics.cfo / 15000, worker_com->pathloss, tx_time_prach); + radio_h->tx_end(); + worker_com->p0_preamble = prach_buffer->get_p0_preamble(); + worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble); + } + workers_pool->start_worker(worker); + break; + case 0: + log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); + // Notify RRC of out-of-sync frame + rrc->out_of_sync(); + worker->release(); + worker_com->reset_ul(); + mac->tti_clock(tti); + break; + default: + radio_error(); + break; } } else { // wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here - running = false; + running = false; } break; case IDLE: + if (!is_in_idle) { + stop_rx(); + } + is_in_idle = true; usleep(1000); + // Keep running MAC timer from system clock + tti = (tti+1) % 10240; + mac->tti_clock(tti); break; } } } -uint32_t phch_recv::get_current_tti() -{ - return tti; -} - -bool phch_recv::status_is_sync() -{ - return phy_state == SYNC_DONE; +void phch_recv::stop_rx() { + if (radio_is_rx) { + Info("SYNC: Stopping RX streaming\n"); + radio_h->stop_rx(); + } + radio_is_rx = false; } -void phch_recv::get_current_cell(srslte_cell_t* cell_) -{ - if (cell_) { - memcpy(cell_, &cell, sizeof(srslte_cell_t)); +void phch_recv::start_rx() { + if (!radio_is_rx) { + Info("SYNC: Starting RX streaming\n"); + radio_h->start_rx(); } + radio_is_rx = true; } -void phch_recv::sync_start() -{ - radio_h->set_master_clock_rate(30.72e6); - phy_state = CELL_SEARCH; +uint32_t phch_recv::get_current_tti() { + return tti; } -void phch_recv::sync_stop() -{ - free_cell(); - radio_h->stop_rx(); - radio_is_streaming = false; - phy_state = IDLE; +bool phch_recv::status_is_sync() { + return phy_state == CELL_CAMP; } +void phch_recv::get_current_cell(srslte_cell_t *cell_) { + if (cell_) { + memcpy(cell_, &cell, sizeof(srslte_cell_t)); + } +} } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 53dc232dc..c0fec2ba2 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -30,18 +30,18 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/asn1/liblte_rrc.h" -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) /* This is to visualize the channel response */ #ifdef ENABLE_GUI #include "srsgui/srsgui.h" #include -#include -#include +#include "srslte/srslte.h" +#include "srslte/interfaces/ue_interfaces.h" void init_plots(srsue::phch_worker *worker); pthread_t plot_thread; @@ -60,15 +60,31 @@ phch_worker::phch_worker() : tr_exec(10240) { phy = NULL; bzero(signal_buffer, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - + + mem_initiated = false; cell_initiated = false; pregen_enabled = false; - trace_enabled = false; - + trace_enabled = false; + reset(); } -void phch_worker::reset() + +phch_worker::~phch_worker() +{ + if (mem_initiated) { + for (uint32_t i=0;iargs->nof_rx_ant;i++) { + if (signal_buffer[i]) { + free(signal_buffer[i]); + } + } + srslte_ue_dl_free(&ue_dl); + srslte_ue_ul_free(&ue_ul); + mem_initiated = false; + } +} + +void phch_worker::reset() { bzero(&dl_metrics, sizeof(dl_metrics_t)); bzero(&ul_metrics, sizeof(ul_metrics_t)); @@ -89,48 +105,57 @@ void phch_worker::set_common(phch_common* phy_) { phy = phy_; } - -bool phch_worker::init_cell(srslte_cell_t cell_) + +bool phch_worker::init(uint32_t max_prb, srslte::log *log_h) { - memcpy(&cell, &cell_, sizeof(srslte_cell_t)); - - // ue_sync in phy.cc requires a buffer for 3 subframes + this->log_h = log_h; + // ue_sync in phy.cc requires a buffer for 3 subframes for (uint32_t i=0;iargs->nof_rx_ant;i++) { - signal_buffer[i] = (cf_t*) srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + signal_buffer[i] = (cf_t*) srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(max_prb)); if (!signal_buffer[i]) { Error("Allocating memory\n"); - return false; + return false; } } - if (srslte_ue_dl_init(&ue_dl, cell, phy->args->nof_rx_ant)) { + if (srslte_ue_dl_init(&ue_dl, max_prb, phy->args->nof_rx_ant)) { Error("Initiating UE DL\n"); - return false; + return false; } - - if (srslte_ue_ul_init(&ue_ul, cell)) { + + if (srslte_ue_ul_init(&ue_ul, max_prb)) { Error("Initiating UE UL\n"); - return false; + return false; } + srslte_ue_ul_set_normalization(&ue_ul, true); srslte_ue_ul_set_cfo_enable(&ue_ul, true); - - cell_initiated = true; - - return true; + + mem_initiated = true; + + return true; } -void phch_worker::free_cell() +bool phch_worker::set_cell(srslte_cell_t cell_) { - if (cell_initiated) { - for (uint32_t i=0;iargs->nof_rx_ant;i++) { - if (signal_buffer[i]) { - free(signal_buffer[i]); - } + if (cell.id != cell_.id || !cell_initiated) { + memcpy(&cell, &cell_, sizeof(srslte_cell_t)); + + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { + Error("Initiating UE DL\n"); + return false; } - srslte_ue_dl_free(&ue_dl); - srslte_ue_ul_free(&ue_ul); + + if (srslte_ue_ul_set_cell(&ue_ul, cell)) { + Error("Initiating UE UL\n"); + return false; + } + srslte_ue_ul_set_normalization(&ue_ul, true); + srslte_ue_ul_set_cfo_enable(&ue_ul, true); + + cell_initiated = true; } + return true; } cf_t* phch_worker::get_buffer(uint32_t antenna_idx) @@ -142,6 +167,7 @@ void phch_worker::set_tti(uint32_t tti_, uint32_t tx_tti_) { tti = tti_; tx_tti = tx_tti_; + log_h->step(tti); } void phch_worker::set_cfo(float cfo_) @@ -193,11 +219,14 @@ void phch_worker::work_imp() bzero(&ul_action, sizeof(mac_interface_phy::tb_action_ul_t)); /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ - if (extract_fft_and_pdcch_llr()) { - - + bool chest_ok = extract_fft_and_pdcch_llr(); + + bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0; + + if (chest_ok && snr_th_ok) { + /***** Downlink Processing *******/ - + /* PDCCH DL + PDSCH */ dl_grant_available = decode_pdcch_dl(&dl_mac_grant); if(dl_grant_available) { @@ -206,33 +235,66 @@ void phch_worker::work_imp() /* Set DL ACKs to default */ for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - dl_ack[tb] = dl_action.default_ack; + dl_ack[tb] = dl_action.default_ack[tb]; } /* Decode PDSCH if instructed to do so */ - if (dl_action.decode_enabled) { + 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 && dl_action.decode_enabled) { - - // NOTE: Currently hard-coded to 1st TB only - for (uint32_t tb = 0; tb < 1; 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 (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.phy_grant.dl.nof_tb); + set_uci_ack(dl_ack, dl_mac_grant.tb_en); + } + + /* Select Rank Indicator by computing Condition Number */ + if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { + if (ue_dl.nof_rx_antennas > 1) { + /* If 2 ort more receiving antennas, select RI */ + float cn = 0.0f; + srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn); + uci_data.uci_ri_len = 1; + } else { + /* If only one receiving antenna, force RI for 1 layer */ + uci_data.uci_ri = 0; + uci_data.uci_ri_len = 1; + Warning("Only one receiving antenna with TM3. Forcing RI=1 layer.\n"); + } + } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4){ + float sinr = 0.0f; + uint8 packed_pmi = 0; + srslte_ue_dl_ri_pmi_select(&ue_dl, &uci_data.uci_ri, &packed_pmi, &sinr); + srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, 2); + uci_data.uci_ri_len = 1; + if (uci_data.uci_ri == 0) { + uci_data.uci_pmi_len = 2; + uci_data.uci_dif_cqi_len = 0; + } else { + uci_data.uci_pmi_len = 1; + uci_data.uci_dif_cqi_len = 3; + } + + /* If only one antenna in TM4 print limitation warning */ + if (ue_dl.nof_rx_antennas < 2) { + Warning("Only one receiving antenna with TM4. Forcing RI=1 layer (PMI=%d).\n", packed_pmi); + } } } } // Decode PHICH - bool ul_ack; + bool ul_ack = false; bool ul_ack_available = decode_phich(&ul_ack); /***** Uplink Processing + Transmission *******/ @@ -285,20 +347,37 @@ void phch_worker::work_imp() } tr_log_end(); - - phy->worker_end(tx_tti, signal_ready, signal_buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb), tx_time); - - if (dl_action.decode_enabled && !dl_action.generate_ack_callback) { - if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH) { + + if (next_offset > 0) { + phy->worker_end(tx_tti, signal_ready, signal_buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time); + } else { + phy->worker_end(tx_tti, signal_ready, &signal_buffer[0][-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]) { phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]); } else { - for (uint32_t tb = 0; tb < dl_mac_grant.phy_grant.dl.nof_tb; tb++) { - phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); + 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); + } } } } update_measurements(); + + if (chest_ok) { + if (snr_th_ok) { + phy->rrc->in_sync(); + log_h->debug("SYNC: Sending in-sync to RRC\n"); + } else { + phy->rrc->out_of_sync(); + log_h->debug("SNR=%.1f dB under threshold. Sending out-of-sync to RRC\n", + 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))); + } + } /* Tell the plotting thread to draw the plots */ #ifdef ENABLE_GUI @@ -392,7 +471,7 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) Error("Converting DCI message to DL grant\n"); return false; } - + /* Fill MAC grant structure */ grant->ndi[0] = dci_unpacked.ndi; grant->ndi[1] = dci_unpacked.ndi_1; @@ -405,12 +484,20 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) grant->rnti = dl_rnti; grant->rnti_type = type; grant->last_tti = 0; - + grant->tb_en[0] = dci_unpacked.tb_en[0]; + grant->tb_en[1] = dci_unpacked.tb_en[1]; + grant->tb_cw_swap = dci_unpacked.tb_cw_swap; // FIXME: tb_cw_swap not supported + + if (grant->tb_cw_swap) { + Info("tb_cw_swap = true\n"); + printf("tb_cw_swap = true\n"); + } + last_dl_pdcch_ncce = srslte_ue_dl_get_ncce(&ue_dl); char hexstr[16]; hexstr[0]='\0'; - if (phy->log_h->get_level() >= srslte::LOG_LEVEL_INFO) { + if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { srslte_vec_sprint_hex(hexstr, dci_msg.data, dci_msg.nof_bits); } Info("PDCCH: DL DCI %s cce_index=%2d, L=%d, n_data_bits=%d, hex=%s\n", srslte_dci_format_string(dci_msg.format), @@ -427,13 +514,15 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL int rv[SRSLTE_MAX_CODEWORDS], uint16_t rnti, uint32_t harq_pid, bool acks[SRSLTE_MAX_CODEWORDS]) { char timestr[64]; + char commonstr[128]; + char tbstr[2][128]; bool valid_config = true; timestr[0]='\0'; srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; int ret = SRSLTE_SUCCESS; - for (uint32_t tb = 0; tb < grant->nof_tb; tb++) { - if (rv[tb] < 0 || rv[tb] > 3) { + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (grant->tb_en[tb] && (rv[tb] < 0 || rv[tb] > 3)) { valid_config = false; Error("Wrong RV (%d) for TB index %d", rv[tb], tb); } @@ -452,22 +541,24 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL } break; case LIBLTE_RRC_TRANSMISSION_MODE_3: - if (grant->nof_tb == 1) { + if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 1) { mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (grant->nof_tb == 2) { + } else if (ue_dl.nof_rx_antennas > 1 && SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { mimo_type = SRSLTE_MIMO_TYPE_CDD; } else { - Error("Wrong number of transport blocks (%d) for TM3\n", grant->nof_tb); + Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, + SRSLTE_RA_DL_GRANT_NOF_TB(grant)); valid_config = false; } break; case LIBLTE_RRC_TRANSMISSION_MODE_4: - if (grant->nof_tb == 1) { + if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 1) { mimo_type = (grant->pinfo == 0) ? SRSLTE_MIMO_TYPE_TX_DIVERSITY : SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } else if (grant->nof_tb == 2) { + } else if (ue_dl.nof_rx_antennas > 1 && SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; } else { - Error("Wrong number of transport blocks (%d) for TM4\n", grant->nof_tb); + Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, + SRSLTE_RA_DL_GRANT_NOF_TB(grant)); valid_config = false; } break; @@ -505,7 +596,7 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL srslte_pdsch_set_max_noi(&ue_dl.pdsch, phy->args->pdsch_max_its); } - + #ifdef LOG_EXECTIME struct timeval t[3]; gettimeofday(&t[1], NULL); @@ -513,7 +604,7 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL ret = srslte_pdsch_decode(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffers, ue_dl.sf_symbols_m, ue_dl.ce_m, noise_estimate, rnti, payload, acks); if (ret) { - Error("Decoding PDSCH"); + Error("ERROR: Decoding PDSCH\n"); } #ifdef LOG_EXECTIME gettimeofday(&t[2], NULL); @@ -521,17 +612,19 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); #endif - Info("PDSCH: l_crb=%2d, harq=%d, nof_tb=%d, tbs={%d, %d}, mcs={%d, %d}, rv={%d, %d}, crc={%s, %s}, snr=%.1f dB, n_iter=%d%s\n", - grant->nof_prb, harq_pid, - grant->nof_tb, grant->mcs[0].tbs / 8, grant->mcs[1].tbs / 8, grant->mcs[0].idx, grant->mcs[1].idx, - rv[0], rv[1], acks[0] ? "OK" : "KO", acks[1] ? "OK" : "KO", - 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)), - srslte_pdsch_last_noi(&ue_dl.pdsch), - timestr); + snprintf(commonstr, 128, "PDSCH: l_crb=%2d, harq=%d, snr=%.1f dB", grant->nof_prb, harq_pid, + 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest))); + + for (int i=0;itb_en[i]) { + snprintf(tbstr[i], 128, ", TB%d: tbs=%d, mcs=%d, rv=%d, crc=%s, it=%d", + i, grant->mcs[i].tbs/8, grant->mcs[i].idx, rv[i], acks[i] ? "OK" : "KO", + srslte_pdsch_last_noi_cw(&ue_dl.pdsch, i)); + } + } + + Info("%s%s%s%s\n", commonstr, grant->tb_en[0]?tbstr[0]:"", grant->tb_en[1]?tbstr[1]:"", 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; } else { @@ -585,7 +678,7 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant) { Error("Converting RAR message to UL grant\n"); return false; - } + } grant->rnti_type = SRSLTE_RNTI_TEMP; grant->is_from_rar = true; grant->has_cqi_request = false; // In contention-based Random Access CQI request bit is reserved @@ -611,7 +704,7 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant) char hexstr[16]; hexstr[0]='\0'; - if (phy->log_h->get_level() >= srslte::LOG_LEVEL_INFO) { + if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { srslte_vec_sprint_hex(hexstr, dci_msg.data, dci_msg.nof_bits); } // Change to last_location_ul @@ -660,22 +753,24 @@ void phch_worker::reset_uci() bzero(&uci_data, sizeof(srslte_uci_data_t)); } - void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], uint32_t nof_tb) { - if (nof_tb > 0) { - uci_data.uci_ack = (uint8_t) ((ack[0]) ? 1 : 0); - } - - if (nof_tb > 1) { - uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0); - } +void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS]) +{ + uint32_t nof_tb = 0; + if (tb_en[0]) { + uci_data.uci_ack = (uint8_t) ((ack[0]) ? 1 : 0); + nof_tb = 1; + } else { + uci_data.uci_ack = 1; + } - if (nof_tb > 2) { - Error("Number of transport blocks is not supported"); - } + if (tb_en[1]) { + uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0); + nof_tb = 2; + } - uci_data.uci_ack_len = nof_tb; + uci_data.uci_ack_len = nof_tb; - } +} void phch_worker::set_uci_sr() { @@ -698,14 +793,23 @@ void phch_worker::set_uci_periodic_cqi() int cqi_max = phy->args->cqi_max; if (period_cqi.configured && rnti_is_set) { - if (srslte_cqi_send(period_cqi.pmi_idx, (tti+4)%10240)) { + if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, (tti+4)%10240)) { + if (uci_data.uci_ri_len) { + uci_data.uci_cqi[0] = uci_data.uci_ri; + uci_data.uci_cqi_len = uci_data.uci_ri_len; + uci_data.uci_ri_len = 0; + uci_data.uci_dif_cqi_len = 0; + uci_data.uci_pmi_len = 0; + Info("PUCCH: Periodic RI=%d\n", uci_data.uci_cqi[0]); + } + } else if (srslte_cqi_send(period_cqi.pmi_idx, (tti+4)%10240)) { srslte_cqi_value_t cqi_report; if (period_cqi.format_is_subband) { // TODO: Implement subband periodic reports cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND; cqi_report.subband.subband_cqi = srslte_cqi_from_snr(phy->avg_snr_db); cqi_report.subband.subband_label = 0; - phy->log_h->console("Warning: Subband CQI periodic reports not implemented\n"); + log_h->console("Warning: Subband CQI periodic reports not implemented\n"); Info("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.subband.subband_cqi, phy->avg_snr_db); } else { cqi_report.type = SRSLTE_CQI_TYPE_WIDEBAND; @@ -773,8 +877,9 @@ bool phch_worker::srs_is_ready_to_send() { return false; } -void phch_worker::set_tx_time(srslte_timestamp_t _tx_time) +void phch_worker::set_tx_time(srslte_timestamp_t _tx_time, uint32_t next_offset) { + this->next_offset = next_offset; memcpy(&tx_time, &_tx_time, sizeof(srslte_timestamp_t)); } @@ -810,15 +915,16 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui #ifdef LOG_EXECTIME gettimeofday(&logtime_start[2], NULL); get_time_interval(logtime_start); - snprintf(timestr, 64, ", total_time=%4d us", (int) logtime_start[0].tv_usec); + snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec); #endif - Info("PUSCH: tti_tx=%d, n_prb=%d, rb_start=%d, tbs=%d, mod=%d, mcs=%d, rv_idx=%d, ack=%s, cfo=%.1f Hz%s\n", + Info("PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n", (tti+4)%10240, - grant->L_prb, grant->n_prb[0], - grant->mcs.tbs/8, grant->mcs.mod, grant->mcs.idx, rv, + grant->n_prb[0], grant->n_prb[0]+grant->L_prb, + grant->mcs.tbs/8, grant->mcs.idx, rv, uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no", - cfo*15000, timestr); + uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no", + cfo*15, timestr); // Store metrics ul_metrics.mcs = grant->mcs.idx; @@ -853,17 +959,22 @@ void phch_worker::encode_pucch() memcpy(&t[2], &logtime_start[2], sizeof(struct timeval)); get_time_interval(logtime_start); get_time_interval(t); - snprintf(timestr, 64, ", enc_time=%d, total_time=%d us", (int) t[0].tv_usec, (int) logtime_start[0].tv_usec); + snprintf(timestr, 64, ", tot_time=%d us", (int) logtime_start[0].tv_usec); #endif float tx_power = srslte_ue_ul_pucch_power(&ue_ul, phy->pathloss, ue_ul.last_pucch_format, uci_data.uci_cqi_len, uci_data.uci_ack_len); float gain = set_power(tx_power); - Info("PUCCH: power=%.2f dBm, tti_tx=%d, n_cce=%3d, n_pucch=%d, n_prb=%d, ack=%s, sr=%s, cfo=%.1f Hz%s\n", - tx_power, (tti+4)%10240, - last_dl_pdcch_ncce, ue_ul.pucch.last_n_pucch, ue_ul.pucch.last_n_prb, - uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no",uci_data.scheduling_request?"yes":"no", - cfo*15000, timestr); + Info("PUCCH: tti_tx=%d, n_pucch=%d, n_prb=%d, ack=%s%s, ri=%s, pmi=%s%s, sr=%s, cfo=%.1f KHz%s\n", + (tti+4)%10240, + ue_ul.pucch.last_n_pucch, ue_ul.pucch.last_n_prb, + uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no", + uci_data.uci_ack_len>1?(uci_data.uci_ack_2?"1":"0"):"", + uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no", + uci_data.uci_pmi_len>0?(uci_data.uci_pmi[1]?"1":"0"):"no", + uci_data.uci_pmi_len>0?(uci_data.uci_pmi[0]?"1":"0"):"", + uci_data.scheduling_request?"yes":"no", + cfo*15, timestr); } if (uci_data.scheduling_request) { @@ -884,7 +995,7 @@ void phch_worker::encode_srs() #ifdef LOG_EXECTIME gettimeofday(&logtime_start[2], NULL); get_time_interval(logtime_start); - snprintf(timestr, 64, ", total_time=%4d us", (int) logtime_start[0].tv_usec); + snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec); #endif float tx_power = srslte_ue_ul_srs_power(&ue_ul, phy->pathloss); @@ -992,12 +1103,19 @@ void phch_worker::set_ul_params(bool pregen_disabled) /* CQI configuration */ bzero(&period_cqi, sizeof(srslte_cqi_periodic_cfg_t)); period_cqi.configured = dedicated->cqi_report_cnfg.report_periodic_setup_present; - period_cqi.pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx; + period_cqi.pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx; period_cqi.simul_cqi_ack = dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi; period_cqi.format_is_subband = dedicated->cqi_report_cnfg.report_periodic.format_ind_periodic == LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_SUBBAND_CQI; period_cqi.subband_size = dedicated->cqi_report_cnfg.report_periodic.format_ind_periodic_subband_k; - + + if (dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present) { + period_cqi.ri_idx = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx; + period_cqi.ri_idx_present = true; + } else { + period_cqi.ri_idx_present = false; + } + /* SR configuration */ I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx; @@ -1027,13 +1145,13 @@ void phch_worker::start_plot() { #ifdef ENABLE_GUI if (plot_worker_id == -1) { plot_worker_id = get_id(); - phy->log_h->console("Starting plot for worker_id=%d\n", plot_worker_id); + log_h->console("Starting plot for worker_id=%d\n", plot_worker_id); init_plots(this); } else { - phy->log_h->console("Trying to start a plot but already started by worker_id=%d\n", plot_worker_id); + log_h->console("Trying to start a plot but already started by worker_id=%d\n", plot_worker_id); } #else - phy->log_h->console("Trying to start a plot but plots are disabled (ENABLE_GUI constant in phch_worker.cc)\n"); + log_h->console("Trying to start a plot but plots are disabled (ENABLE_GUI constant in phch_worker.cc)\n"); #endif } @@ -1043,7 +1161,7 @@ int phch_worker::read_ce_abs(float *ce_abs) { bzero(ce_abs, sizeof(float)*sz); int g = (sz - 12*cell.nof_prb)/2; for (i = 0; i < 12*cell.nof_prb; i++) { - ce_abs[g+i] = 20 * log10(cabs(ue_dl.ce[0][i])); + ce_abs[g+i] = 20 * log10f(cabsf(ue_dl.ce_m[0][0][i])); if (isinf(ce_abs[g+i])) { ce_abs[g+i] = -80; } @@ -1054,7 +1172,7 @@ int phch_worker::read_ce_abs(float *ce_abs) { int phch_worker::read_pdsch_d(cf_t* pdsch_d) { - memcpy(pdsch_d, ue_dl.pdsch.d, ue_dl.pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); + memcpy(pdsch_d, ue_dl.pdsch.d[0], ue_dl.pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); return ue_dl.pdsch_cfg.nbits[0].nof_re; } diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index dea66346b..e74107661 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -95,44 +95,64 @@ bool phy::check_args(phy_args_t *args) return true; } -bool phy::init(srslte::radio_multi* radio_handler_, mac_interface_phy *mac, rrc_interface_phy *rrc, - srslte::log *log_h_, phy_args_t *phy_args) -{ +bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_interface_phy *rrc, + std::vector log_vec, phy_args_t *phy_args) { mlockall(MCL_CURRENT | MCL_FUTURE); - - n_ta = 0; - log_h = log_h_; - radio_handler = radio_handler_; - + + n_ta = 0; + this->log_vec = log_vec; + this->log_h = (srslte::log*) log_vec[0]; + this->radio_handler = radio_handler; + this->mac = mac; + this->rrc = rrc; + if (!phy_args) { - args = &default_args; + args = &default_args; set_default_args(args); } else { args = phy_args; } - + if (!check_args(args)) { - return false; + return false; } - - nof_workers = args->nof_phy_threads; - + + nof_workers = args->nof_phy_threads; + + initiated = false; + start(); + return true; +} + +// Initializes PHY in a thread +void phy::run_thread() { + + prach_buffer.init(&config.common.prach_cnfg, SRSLTE_MAX_PRB, args, log_h); + workers_common.init(&config, args, (srslte::log*) log_vec[0], radio_handler, rrc, mac); + // Add workers to workers pool and start threads for (uint32_t i=0;iworker_cpu_mask); + workers[i].init(SRSLTE_MAX_PRB, (srslte::log*) log_vec[i]); + workers_pool.init_worker(i, &workers[i], WORKERS_THREAD_PRIO, args->worker_cpu_mask); } - prach_buffer.init(&config.common.prach_cnfg, args, log_h); - workers_common.init(&config, args, log_h, radio_handler, mac); - + // Warning this must be initialized after all workers have been added to the pool sf_recv.init(radio_handler, mac, rrc, &prach_buffer, &workers_pool, &workers_common, log_h, args->nof_rx_ant, SF_RECV_THREAD_PRIO, args->sync_cpu_affinity); // Disable UL signal pregeneration until the attachment enable_pregen_signals(false); - return true; + initiated = true; +} + +void phy::wait_initialize() { + wait_thread_finish(); +} + +bool phy::is_initiated() { + return initiated; } void phy::set_agc_enable(bool enabled) @@ -190,7 +210,7 @@ void phy::configure_prach_params() Debug("Configuring PRACH parameters\n"); srslte_cell_t cell; sf_recv.get_current_cell(&cell); - if (!prach_buffer.init_cell(cell)) { + if (!prach_buffer.set_cell(cell)) { Error("Configuring PRACH parameters\n"); } } else { @@ -201,11 +221,37 @@ void phy::configure_prach_params() void phy::configure_ul_params(bool pregen_disabled) { Info("PHY: Configuring UL parameters\n"); - for (uint32_t i=0;iget_max_tx_power() - workers_common.cur_pusch_power; @@ -257,8 +303,8 @@ int phy::prach_tx_tti() void phy::reset() { - // TODO - n_ta = 0; + Info("Resetting PHY\n"); + n_ta = 0; pdcch_dl_search_reset(); for(uint32_t i=0;i earfcns) { - return sf_recv.status_is_sync(); + sf_recv.set_earfcn(earfcns); } -void phy::resync_sfn() { - sf_recv.resync_sfn(); -} - -void phy::sync_start() +bool phy::sync_status() { - sf_recv.sync_start(); -} - -void phy::sync_stop() -{ - sf_recv.sync_stop(); + return sf_recv.status_is_sync(); } void phy::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) diff --git a/srsue/src/phy/prach.cc b/srsue/src/phy/prach.cc index 62980c623..7c693fe7a 100644 --- a/srsue/src/phy/prach.cc +++ b/srsue/src/phy/prach.cc @@ -41,14 +41,13 @@ namespace srsue { - -void prach::free_cell() -{ - if (initiated) { + +prach::~prach() { + if (mem_initiated) { for (int i=0;i<64;i++) { if (buffer[i]) { - free(buffer[i]); - } + free(buffer[i]); + } } if (signal_buffer) { free(signal_buffer); @@ -58,84 +57,103 @@ void prach::free_cell() } } -void prach::init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config_, phy_args_t *args_, srslte::log* log_h_) +void prach::init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config_, uint32_t max_prb, phy_args_t *args_, srslte::log* log_h_) { - log_h = log_h_; - config = config_; - args = args_; + log_h = log_h_; + config = config_; + args = args_; + + for (int i=0;i<64;i++) { + buffer[i] = (cf_t*) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN*sizeof(cf_t)); + if(!buffer[i]) { + perror("malloc"); + return; + } + } + if (srslte_cfo_init(&cfo_h, SRSLTE_PRACH_MAX_LEN)) { + fprintf(stderr, "PRACH: Error initiating CFO\n"); + return; + } + srslte_cfo_set_tol(&cfo_h, 0); + signal_buffer = (cf_t*) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN*sizeof(cf_t)); + if (!signal_buffer) { + perror("malloc"); + return; + } + if (srslte_prach_init(&prach_obj, srslte_symbol_sz(max_prb))) { + Error("Initiating PRACH library\n"); + return; + } + mem_initiated = true; } -bool prach::init_cell(srslte_cell_t cell_) +bool prach::set_cell(srslte_cell_t cell_) { - // TODO: Check if other PRACH parameters changed - if (cell_.id != cell.id || !initiated) { - if (initiated) { - free_cell(); - } - cell = cell_; - preamble_idx = -1; - - uint32_t configIdx = config->prach_cnfg_info.prach_config_index; - uint32_t rootSeq = config->root_sequence_index; - uint32_t zeroCorrConfig = config->prach_cnfg_info.zero_correlation_zone_config; - uint32_t freq_offset = config->prach_cnfg_info.prach_freq_offset; - bool highSpeed = config->prach_cnfg_info.high_speed_flag; - - if (6 + freq_offset > cell.nof_prb) { - log_h->console("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, cell.nof_prb); - log_h->error("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, cell.nof_prb); - return false; - } - - if (srslte_prach_init(&prach_obj, srslte_symbol_sz(cell.nof_prb), - configIdx, rootSeq, highSpeed, zeroCorrConfig)) - { - Error("Initiating PRACH library\n"); - return false; - } - - len = prach_obj.N_seq + prach_obj.N_cp; - for (int i=0;i<64;i++) { - buffer[i] = (cf_t*) srslte_vec_malloc(len*sizeof(cf_t)); - if(!buffer[i]) { - return false; - } - if(srslte_prach_gen(&prach_obj, i, freq_offset, buffer[i])) { - Error("Generating PRACH preamble %d\n", i); + if (mem_initiated) { + // TODO: Check if other PRACH parameters changed + if (cell_.id != cell.id || !cell_initiated) { + memcpy(&cell, &cell_, sizeof(srslte_cell_t)); + preamble_idx = -1; + + uint32_t configIdx = config->prach_cnfg_info.prach_config_index; + uint32_t rootSeq = config->root_sequence_index; + uint32_t zeroCorrConfig = config->prach_cnfg_info.zero_correlation_zone_config; + uint32_t freq_offset = config->prach_cnfg_info.prach_freq_offset; + bool highSpeed = config->prach_cnfg_info.high_speed_flag; + + if (6 + freq_offset > cell.nof_prb) { + log_h->console("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, cell.nof_prb); + log_h->error("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, cell.nof_prb); + return false; + } + + Info("PRACH: configIdx=%d, rootSequence=%d, zeroCorrelationConfig=%d, freqOffset=%d\n", + configIdx, rootSeq, zeroCorrConfig, freq_offset); + + if (srslte_prach_set_cell(&prach_obj, srslte_symbol_sz(cell.nof_prb), + configIdx, rootSeq, highSpeed, zeroCorrConfig)) { + Error("Initiating PRACH library\n"); return false; } + for (int i=0;i<64;i++) { + if(srslte_prach_gen(&prach_obj, i, freq_offset, buffer[i])) { + Error("Generating PRACH preamble %d\n", i); + return false; + } + } + + len = prach_obj.N_seq + prach_obj.N_cp; + transmitted_tti = -1; + cell_initiated = true; } - srslte_cfo_init(&cfo_h, len); - srslte_cfo_set_tol(&cfo_h, 0); - signal_buffer = (cf_t*) srslte_vec_malloc(len*sizeof(cf_t)); - initiated = signal_buffer?true:false; - transmitted_tti = -1; - Debug("PRACH Initiated %s\n", initiated?"OK":"KO"); + return true; + } else { + fprintf(stderr, "PRACH: Error must call init() first\n"); + return false; } - return initiated; } bool prach::prepare_to_send(uint32_t preamble_idx_, int allowed_subframe_, float target_power_dbm_) { - if (initiated && preamble_idx_ < 64) { + if (cell_initiated && preamble_idx_ < 64) { preamble_idx = preamble_idx_; target_power_dbm = target_power_dbm_; allowed_subframe = allowed_subframe_; transmitted_tti = -1; - Debug("PRACH prepare to send preamble %d\n", preamble_idx); + Debug("PRACH: prepare to send preamble %d\n", preamble_idx); return true; } else { - if (!initiated) { - Error("PRACH not initiated\n"); + if (!cell_initiated) { + Error("PRACH: Cell not configured\n"); } else if (preamble_idx_ >= 64) { - Error("Invalid preamble %d\n", preamble_idx_); + Error("PRACH: Invalid preamble %d\n", preamble_idx_); } return false; } } bool prach::is_ready_to_send(uint32_t current_tti_) { - if (initiated && preamble_idx >= 0 && preamble_idx < 64) { + if (cell_initiated && preamble_idx >= 0 && preamble_idx < 64) { // consider the number of subframes the transmission must be anticipated uint32_t current_tti = (current_tti_ + tx_advance_sf)%10240; if (srslte_prach_tti_opportunity(&prach_obj, current_tti, allowed_subframe)) { @@ -195,9 +213,9 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, tx_time=%f\n", preamble_idx, cfo*15, tx_time.frac_secs); - preamble_idx = -1; + preamble_idx = -1; - radio_handler->set_tx_gain(old_gain); + radio_handler->set_tx_gain(old_gain); Debug("Restoring TX gain to %.0f dB\n", old_gain); } diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 0110a1a14..92adaf8dd 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -32,6 +32,7 @@ #include #include #include +#include using namespace srslte; @@ -51,22 +52,38 @@ ue::~ue() bool ue::init(all_args_t *args_) { args = args_; - - logger.init(args->log.filename); - rf_log.init("RF ", &logger); - phy_log.init("PHY ", &logger, true); - mac_log.init("MAC ", &logger, true); - rlc_log.init("RLC ", &logger); - pdcp_log.init("PDCP", &logger); - rrc_log.init("RRC ", &logger); - nas_log.init("NAS ", &logger); - gw_log.init("GW ", &logger); - usim_log.init("USIM", &logger); + + if (!args->log.filename.compare("stdout")) { + logger = &logger_stdout; + } else { + logger_file.init(args->log.filename); + logger_file.log("\n\n"); + logger = &logger_file; + } + + rf_log.init("RF ", logger); + // Create array of pointers to phy_logs + for (int i=0;iexpert.phy.nof_phy_threads;i++) { + srslte::log_filter *mylog = new srslte::log_filter; + char tmp[16]; + sprintf(tmp, "PHY%d",i); + mylog->init(tmp, logger, true); + phy_log.push_back((void*) mylog); + } + + mac_log.init("MAC ", logger, true); + rlc_log.init("RLC ", logger); + pdcp_log.init("PDCP", logger); + rrc_log.init("RRC ", logger); + nas_log.init("NAS ", logger); + gw_log.init("GW ", logger); + usim_log.init("USIM", logger); // Init logs - logger.log("\n\n"); rf_log.set_level(srslte::LOG_LEVEL_INFO); - phy_log.set_level(level(args->log.phy_level)); + for (int i=0;iexpert.phy.nof_phy_threads;i++) { + ((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level)); + } mac_log.set_level(level(args->log.mac_level)); rlc_log.set_level(level(args->log.rlc_level)); pdcp_log.set_level(level(args->log.pdcp_level)); @@ -75,7 +92,9 @@ bool ue::init(all_args_t *args_) gw_log.set_level(level(args->log.gw_level)); usim_log.set_level(level(args->log.usim_level)); - phy_log.set_hex_limit(args->log.phy_hex_limit); + for (int i=0;iexpert.phy.nof_phy_threads;i++) { + ((srslte::log_filter*) phy_log[i])->set_hex_limit(args->log.phy_hex_limit); + } mac_log.set_hex_limit(args->log.mac_hex_limit); rlc_log.set_hex_limit(args->log.rlc_hex_limit); pdcp_log.set_hex_limit(args->log.pdcp_hex_limit); @@ -97,7 +116,11 @@ bool ue::init(all_args_t *args_) } // Init layers - + + // PHY initis in background, start before radio + args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; + phy.init(&radio, &mac, &rrc, phy_log, &args->expert.phy); + /* Start Radio */ char *dev_name = NULL; if (args->rf.device_name.compare("auto")) { @@ -128,15 +151,13 @@ bool ue::init(all_args_t *args_) radio.set_manual_calibration(&args->rf_cal); // Set PHY options - args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; if (args->rf.tx_gain > 0) { args->expert.phy.ul_pwr_ctrl_en = false; } else { args->expert.phy.ul_pwr_ctrl_en = true; } - phy.init(&radio, &mac, &rrc, &phy_log, &args->expert.phy); - + if (args->rf.rx_gain < 0) { radio.start_agc(false); radio.set_tx_rx_gain_offset(10); @@ -154,23 +175,30 @@ bool ue::init(all_args_t *args_) } radio.register_error_handler(rf_msg); - - radio.set_rx_freq(args->rf.dl_freq); - radio.set_tx_freq(args->rf.ul_freq); - - phy_log.console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz\n", args->rf.dl_freq/1e6, args->rf.ul_freq/1e6); + radio.set_freq_offset(args->rf.freq_offset); mac.init(&phy, &rlc, &rrc, &mac_log); rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */); - pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); + usim.init(&args->usim, &usim_log); + nas.init(&usim, &rrc, &gw, &nas_log, 1 /* RB_ID_SRB1 */); + gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */); + rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log); rrc.set_ue_category(atoi(args->expert.ue_cateogry.c_str())); - - nas.init(&usim, &rrc, &gw, &nas_log, 1 /* RB_ID_SRB1 */); - gw.init(&pdcp, &rrc, this, &gw_log, 3 /* RB_ID_DRB1 */); - usim.init(&args->usim, &usim_log); + + // Currently EARFCN list is set to only one frequency as indicated in ue.conf + std::vector earfcn_list; + earfcn_list.push_back(args->rf.dl_earfcn); + phy.set_earfcn(earfcn_list); + + printf("Waiting PHY to initialize...\n"); + phy.wait_initialize(); + phy.configure_ul_params(); + + printf("...\n"); + nas.attach_request(); started = true; return true; @@ -181,10 +209,6 @@ void ue::pregenerate_signals(bool enable) phy.enable_pregen_signals(enable); } -void ue::test_con_restablishment() { - rrc.test_con_restablishment(); -} - void ue::stop() { if(started) @@ -222,7 +246,7 @@ void ue::stop() bool ue::is_attached() { - return (EMM_STATE_REGISTERED == nas.get_state()); + return (RRC_STATE_CONNECTED == rrc.get_state()); } void ue::start_plot() { @@ -236,7 +260,7 @@ bool ue::get_metrics(ue_metrics_t &m) rf_metrics.rf_error = false; // Reset error flag if(EMM_STATE_REGISTERED == nas.get_state()) { - if(RRC_STATE_RRC_CONNECTED == rrc.get_state()) { + if(RRC_STATE_CONNECTED == rrc.get_state()) { phy.get_metrics(m.phy); mac.get_metrics(m.mac); rlc.get_metrics(m.rlc); diff --git a/srsue/src/ue_base.cc b/srsue/src/ue_base.cc index c84393ae4..94b9b5155 100644 --- a/srsue/src/ue_base.cc +++ b/srsue/src/ue_base.cc @@ -88,7 +88,7 @@ void ue_base::handle_rf_msg(srslte_rf_error_t error) } else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) { rf_metrics.rf_l++; rf_metrics.rf_error = true; - rf_log.warning("Late\n"); + rf_log.warning("Late (detected in %s)\n", error.opt?"rx call":"asynchronous thread"); } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) { std::string str(error.msg); str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); diff --git a/srsue/src/upper/gw.cc b/srsue/src/upper/gw.cc new file mode 100644 index 000000000..07ac36989 --- /dev/null +++ b/srsue/src/upper/gw.cc @@ -0,0 +1,318 @@ +/** + * + * \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 "../../hdr/upper/gw.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace srsue { + +gw::gw() + :if_up(false) +{ + current_ip_addr = 0; +} + +void gw::init(pdcp_interface_gw *pdcp_, nas_interface_gw *nas_, srslte::log *gw_log_, uint32_t lcid_) +{ + pool = srslte::byte_buffer_pool::get_instance(); + pdcp = pdcp_; + nas = nas_; + gw_log = gw_log_; + lcid = lcid_; + run_enable = true; + + gettimeofday(&metrics_time[1], NULL); + dl_tput_bytes = 0; + ul_tput_bytes = 0; +} + +void gw::stop() +{ + if(run_enable) + { + run_enable = false; + if(if_up) + { + close(tun_fd); + + // 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(); + + current_ip_addr = 0; + } + + // TODO: tear down TUN device? + } +} + +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; + + m.dl_tput_mbps = (dl_tput_bytes*8/(double)1e6)/secs; + m.ul_tput_mbps = (ul_tput_bytes*8/(double)1e6)/secs; + gw_log->info("RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", + m.dl_tput_mbps, m.ul_tput_mbps); + + memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval)); + dl_tput_bytes = 0; + ul_tput_bytes = 0; +} + +/******************************************************************************* + PDCP interface +*******************************************************************************/ +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()); + dl_tput_bytes += pdu->N_bytes; + 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"); + } + } + pool->deallocate(pdu); +} + +/******************************************************************************* + NAS interface +*******************************************************************************/ +srslte::error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) +{ + if (ip_addr != current_ip_addr) { + if(!if_up) + { + if(init_if(err_str)) + { + gw_log->error("init_if failed\n"); + return(srslte::ERROR_CANT_START); + } + } + + // Setup the IP address + sock = socket(AF_INET, SOCK_DGRAM, 0); + ifr.ifr_addr.sa_family = AF_INET; + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip_addr); + if(0 > ioctl(sock, SIOCSIFADDR, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to set socket address: %s\n", err_str); + close(tun_fd); + 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(0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to set socket netmask: %s\n", err_str); + close(tun_fd); + return(srslte::ERROR_CANT_START); + } + + current_ip_addr = ip_addr; + + // Setup a thread to receive packets from the TUN device + start(GW_THREAD_PRIO); + } + + return(srslte::ERROR_NONE); +} + +srslte::error_t gw::init_if(char *err_str) +{ + if(if_up) + { + return(srslte::ERROR_ALREADY_STARTED); + } + + char dev[IFNAMSIZ] = "tun_srsue"; + + // Construct the TUN device + tun_fd = open("/dev/net/tun", O_RDWR); + gw_log->info("TUN file descriptor = %d\n", tun_fd); + if(0 > tun_fd) + { + err_str = strerror(errno); + gw_log->debug("Failed to open TUN device: %s\n", err_str); + 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); + if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to set TUN device name: %s\n", err_str); + close(tun_fd); + return(srslte::ERROR_CANT_START); + } + + // Bring up the interface + sock = socket(AF_INET, SOCK_DGRAM, 0); + if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to bring up socket: %s\n", err_str); + close(tun_fd); + return(srslte::ERROR_CANT_START); + } + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to set socket flags: %s\n", err_str); + close(tun_fd); + return(srslte::ERROR_CANT_START); + } + + if_up = true; + + return(srslte::ERROR_NONE); +} + +/********************/ +/* GW Receive */ +/********************/ +void gw::run_thread() +{ + struct iphdr *ip_pkt; + uint32 idx = 0; + int32 N_bytes; + srslte::byte_buffer_t *pdu = pool_allocate; + + const static uint32_t ATTACH_TIMEOUT_MS = 10000; + const static uint32_t ATTACH_MAX_ATTEMPTS = 3; + uint32_t attach_cnt = 0; + uint32_t attach_attempts = 0; + + gw_log->info("GW IP packet receiver thread run_enable\n"); + + running = true; + while(run_enable) + { + if (SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET > idx) { + N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx); + } else { + gw_log->error("GW pdu buffer full - gw receive thread exiting.\n"); + gw_log->console("GW pdu buffer full - gw receive thread exiting.\n"); + break; + } + gw_log->debug("Read %d bytes from TUN fd=%d, idx=%d\n", N_bytes, tun_fd, idx); + if(N_bytes > 0) + { + pdu->N_bytes = idx + N_bytes; + ip_pkt = (struct iphdr*)pdu->msg; + + // Warning: Accept only IPv4 packets + if (ip_pkt->version == 4) { + // Check if entire packet was received + if(ntohs(ip_pkt->tot_len) == pdu->N_bytes) + { + gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU"); + + while(run_enable && !pdcp->is_drb_enabled(lcid) && attach_attempts < ATTACH_MAX_ATTEMPTS) { + if (attach_cnt == 0) { + gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", lcid, attach_attempts, ATTACH_MAX_ATTEMPTS); + nas->attach_request(); + attach_attempts++; + } + attach_cnt++; + if (attach_cnt == ATTACH_TIMEOUT_MS) { + attach_cnt = 0; + } + usleep(1000); + } + + if (attach_attempts == ATTACH_MAX_ATTEMPTS) { + gw_log->warning("LCID=%d was not active after %d attempts\n", lcid, ATTACH_MAX_ATTEMPTS); + } + + attach_attempts = 0; + attach_cnt = 0; + + if (!run_enable) { + break; + } + + // Send PDU directly to PDCP + if (pdcp->is_drb_enabled(lcid)) { + pdu->set_timestamp(); + ul_tput_bytes += pdu->N_bytes; + pdcp->write_sdu(lcid, pdu); + + do { + pdu = pool_allocate; + if (!pdu) { + printf("Not enough buffers in pool\n"); + usleep(100000); + } + } while(!pdu); + idx = 0; + } + }else{ + idx += N_bytes; + } + } + }else{ + gw_log->error("Failed to read from TUN interface - gw receive thread exiting.\n"); + gw_log->console("Failed to read from TUN interface - gw receive thread exiting.\n"); + break; + } + } + running = false; + gw_log->info("GW IP receiver thread exiting.\n"); +} + +} // namespace srsue diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 1595a2cec..f0fd8cf54 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -25,116 +25,193 @@ */ +#include "srslte/asn1/liblte_rrc.h" #include "upper/nas.h" +#include "srslte/common/bcd_helpers.h" using namespace srslte; -namespace srsue{ +namespace srsue { nas::nas() - :state(EMM_STATE_DEREGISTERED) - ,is_guti_set(false) - ,ip_addr(0) - ,eps_bearer_id(0) - ,count_ul(0) - ,count_dl(0) -{} + : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), is_guti_set(false), ip_addr(0), eps_bearer_id(0), + count_ul(0), count_dl(0) {} void nas::init(usim_interface_nas *usim_, - rrc_interface_nas *rrc_, - gw_interface_nas *gw_, - srslte::log *nas_log_, + rrc_interface_nas *rrc_, + gw_interface_nas *gw_, + srslte::log *nas_log_, srslte::srslte_nas_config_t cfg_) { - pool = byte_buffer_pool::get_instance(); - usim = usim_; - rrc = rrc_; - gw = gw_; + pool = byte_buffer_pool::get_instance(); + usim = usim_; + rrc = rrc_; + gw = gw_; nas_log = nas_log_; + state = EMM_STATE_DEREGISTERED; + plmn_selection = PLMN_NOT_SELECTED; + + if (usim->get_home_plmn_id(&home_plmn)) { + nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n"); + home_plmn.mcc = 61441; // This is 001 + home_plmn.mnc = 65281; // This is 01 + } cfg = cfg_; } -void nas::stop() -{} +void nas::stop() {} -emm_state_t nas::get_state() -{ +emm_state_t nas::get_state() { return state; } +/******************************************************************************* +UE interface +*******************************************************************************/ + +void nas::attach_request() { + nas_log->info("Attach Request\n"); + if (state == EMM_STATE_DEREGISTERED) { + state = EMM_STATE_REGISTERED_INITIATED; + if (plmn_selection == PLMN_NOT_SELECTED) { + nas_log->info("Starting PLMN Search...\n"); + rrc->plmn_search(); + } else if (plmn_selection == PLMN_SELECTED) { + nas_log->info("Selecting PLMN %s\n", plmn_id_to_string(current_plmn).c_str()); + rrc->plmn_select(current_plmn); + selecting_plmn = current_plmn; + } + } else if (state == EMM_STATE_REGISTERED) { + nas_log->info("NAS state is registered, connecting to same PLMN\n"); + rrc->plmn_select(current_plmn); + selecting_plmn = current_plmn; + } else { + nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]); + } +} + +void nas::deattach_request() { + state = EMM_STATE_DEREGISTERED_INITIATED; + nas_log->info("Dettach request not supported\n"); +} /******************************************************************************* - RRC interface +RRC interface *******************************************************************************/ -bool nas::is_attached() -{ +void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) { + + // Check if already registered + for (uint32_t i=0;iinfo("Found known PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str()); + if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { + nas_log->info("Connecting Home PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str()); + rrc->plmn_select(plmn_id); + selecting_plmn = plmn_id; + } + return; + } + } + + // Save if new PLMN + known_plmns.push_back(plmn_id); + + nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(plmn_id).c_str(), + tracking_area_code); + nas_log->console("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(plmn_id).c_str(), + tracking_area_code); + + if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { + rrc->plmn_select(plmn_id); + selecting_plmn = plmn_id; + } + +} + +// RRC indicates that the UE has gone through all EARFCN and finished PLMN selection +void nas::plmn_search_end() { + if (known_plmns.size() > 0) { + nas_log->info("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n", + plmn_id_to_string(home_plmn).c_str(), + plmn_id_to_string(known_plmns[0]).c_str()); + + nas_log->console("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n", + plmn_id_to_string(home_plmn).c_str(), + plmn_id_to_string(known_plmns[0]).c_str()); + + rrc->plmn_select(known_plmns[0]); + } else { + nas_log->debug("Finished searching PLMN in current EARFCN set but no networks were found.\n"); + } +} + +bool nas::is_attached() { return state == EMM_STATE_REGISTERED; } -void nas::notify_connection_setup() -{ +bool nas::is_attaching() { + return state == EMM_STATE_REGISTERED_INITIATED; +} + +void nas::notify_connection_setup() { nas_log->debug("State = %s\n", emm_state_text[state]); - if(EMM_STATE_DEREGISTERED == state) { + if (EMM_STATE_REGISTERED_INITIATED == state) { send_attach_request(); } else { send_service_request(); } } -void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) -{ +void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { uint8 pd; uint8 msg_type; nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", rrc->get_rb_name(lcid).c_str()); // Parse the message - liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT*)pdu, &pd, &msg_type); - switch(msg_type) - { - case LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT: + liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) pdu, &pd, &msg_type); + switch (msg_type) { + case LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT: parse_attach_accept(lcid, pdu); break; - case LIBLTE_MME_MSG_TYPE_ATTACH_REJECT: + case LIBLTE_MME_MSG_TYPE_ATTACH_REJECT: parse_attach_reject(lcid, pdu); break; - case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REQUEST: + case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REQUEST: parse_authentication_request(lcid, pdu); break; - case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REJECT: + case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REJECT: parse_authentication_reject(lcid, pdu); break; - case LIBLTE_MME_MSG_TYPE_IDENTITY_REQUEST: + case LIBLTE_MME_MSG_TYPE_IDENTITY_REQUEST: parse_identity_request(lcid, pdu); break; - case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMMAND: + case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMMAND: parse_security_mode_command(lcid, pdu); break; - case LIBLTE_MME_MSG_TYPE_SERVICE_REJECT: + case LIBLTE_MME_MSG_TYPE_SERVICE_REJECT: parse_service_reject(lcid, pdu); break; - case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST: + case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST: parse_esm_information_request(lcid, pdu); break; - case LIBLTE_MME_MSG_TYPE_EMM_INFORMATION: + case LIBLTE_MME_MSG_TYPE_EMM_INFORMATION: parse_emm_information(lcid, pdu); break; - default: - nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n",msg_type); + default: + nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n", msg_type); pool->deallocate(pdu); break; } } -uint32_t nas::get_ul_count() -{ +uint32_t nas::get_ul_count() { return count_ul; } -bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) -{ - if(is_guti_set) { +bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) { + if (is_guti_set) { s_tmsi->mmec = guti.mme_code; s_tmsi->m_tmsi = guti.m_tmsi; return true; @@ -144,113 +221,94 @@ bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) } /******************************************************************************* - Security +Security *******************************************************************************/ -void nas::integrity_generate(uint8_t *key_128, - uint32_t count, - uint8_t rb_id, - uint8_t direction, - uint8_t *msg, - uint32_t msg_len, - uint8_t *mac) -{ - switch(integ_algo) - { - case INTEGRITY_ALGORITHM_ID_EIA0: - break; - case INTEGRITY_ALGORITHM_ID_128_EIA1: - security_128_eia1(key_128, - count, - rb_id, - direction, - msg, - msg_len, - mac); - break; - case INTEGRITY_ALGORITHM_ID_128_EIA2: - security_128_eia2(key_128, - count, - rb_id, - direction, - msg, - msg_len, - mac); - break; - default: - break; +void nas::integrity_generate(uint8_t *key_128, + uint32_t count, + uint8_t rb_id, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *mac) { + switch (integ_algo) { + case INTEGRITY_ALGORITHM_ID_EIA0: + break; + case INTEGRITY_ALGORITHM_ID_128_EIA1: + security_128_eia1(key_128, + count, + rb_id, + direction, + msg, + msg_len, + mac); + break; + case INTEGRITY_ALGORITHM_ID_128_EIA2: + security_128_eia2(key_128, + count, + rb_id, + direction, + msg, + msg_len, + mac); + break; + default: + break; } } -void nas::integrity_check() -{ +void nas::integrity_check() { } -void nas::cipher_encrypt() -{ +void nas::cipher_encrypt() { } -void nas::cipher_decrypt() -{ +void nas::cipher_decrypt() { } - /******************************************************************************* - Parsers +Parsers *******************************************************************************/ -void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) -{ - LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept; - LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req; - LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete; - LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_def_eps_bearer_context_accept; +void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { + LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept; + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req; + LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete; + LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_def_eps_bearer_context_accept; nas_log->info("Received Attach Accept\n"); count_dl++; - liblte_mme_unpack_attach_accept_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &attach_accept); + liblte_mme_unpack_attach_accept_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &attach_accept); - if(attach_accept.eps_attach_result == LIBLTE_MME_EPS_ATTACH_RESULT_EPS_ONLY) - { + if (attach_accept.eps_attach_result == LIBLTE_MME_EPS_ATTACH_RESULT_EPS_ONLY) { //FIXME: Handle t3412.unit //FIXME: Handle tai_list - if(attach_accept.guti_present) - { + if (attach_accept.guti_present) { memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); is_guti_set = true; // TODO: log message to console } - if(attach_accept.lai_present) - { + if (attach_accept.lai_present) { } - if(attach_accept.ms_id_present) - {} - if(attach_accept.emm_cause_present) - {} - if(attach_accept.t3402_present) - {} - if(attach_accept.t3423_present) - {} - if(attach_accept.equivalent_plmns_present) - {} - if(attach_accept.emerg_num_list_present) - {} - if(attach_accept.eps_network_feature_support_present) - {} - if(attach_accept.additional_update_result_present) - {} - if(attach_accept.t3412_ext_present) - {} - - liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, &act_def_eps_bearer_context_req); - - if(LIBLTE_MME_PDN_TYPE_IPV4 == act_def_eps_bearer_context_req.pdn_addr.pdn_type) - { + if (attach_accept.ms_id_present) {} + if (attach_accept.emm_cause_present) {} + if (attach_accept.t3402_present) {} + if (attach_accept.t3423_present) {} + if (attach_accept.equivalent_plmns_present) {} + if (attach_accept.emerg_num_list_present) {} + if (attach_accept.eps_network_feature_support_present) {} + if (attach_accept.additional_update_result_present) {} + if (attach_accept.t3412_ext_present) {} + + liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, + &act_def_eps_bearer_context_req); + + if (LIBLTE_MME_PDN_TYPE_IPV4 == act_def_eps_bearer_context_req.pdn_addr.pdn_type) { ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[0] << 24; ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[1] << 16; ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[2] << 8; @@ -263,28 +321,24 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) act_def_eps_bearer_context_req.pdn_addr.addr[3]); nas_log->console("Network attach successful. IP: %u.%u.%u.%u\n", - act_def_eps_bearer_context_req.pdn_addr.addr[0], - act_def_eps_bearer_context_req.pdn_addr.addr[1], - act_def_eps_bearer_context_req.pdn_addr.addr[2], - act_def_eps_bearer_context_req.pdn_addr.addr[3]); - + act_def_eps_bearer_context_req.pdn_addr.addr[0], + act_def_eps_bearer_context_req.pdn_addr.addr[1], + act_def_eps_bearer_context_req.pdn_addr.addr[2], + act_def_eps_bearer_context_req.pdn_addr.addr[3]); + // Setup GW char *err_str = NULL; - if(gw->setup_if_addr(ip_addr, err_str)) - { + if (gw->setup_if_addr(ip_addr, err_str)) { nas_log->error("Failed to set gateway address - %s\n", err_str); } - } - else - { + } else { nas_log->error("Not handling IPV6 or IPV4V6\n"); pool->deallocate(pdu); return; } eps_bearer_id = act_def_eps_bearer_context_req.eps_bearer_id; - if(act_def_eps_bearer_context_req.transaction_id_present) - { - transaction_id = act_def_eps_bearer_context_req.proc_transaction_id; + if (act_def_eps_bearer_context_req.transaction_id_present) { + transaction_id = act_def_eps_bearer_context_req.proc_transaction_id; } //FIXME: Handle the following parameters @@ -303,23 +357,25 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) // FIXME: Setup the default EPS bearer context state = EMM_STATE_REGISTERED; + current_plmn = selecting_plmn; // Send EPS bearer context accept and attach complete count_ul++; - act_def_eps_bearer_context_accept.eps_bearer_id = eps_bearer_id; - act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id; - act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false; - liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(&act_def_eps_bearer_context_accept, &attach_complete.esm_msg); + act_def_eps_bearer_context_accept.eps_bearer_id = eps_bearer_id; + act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id; + act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false; + liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(&act_def_eps_bearer_context_accept, + &attach_complete.esm_msg); liblte_mme_pack_attach_complete_msg(&attach_complete, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, count_ul, - (LIBLTE_BYTE_MSG_STRUCT*)pdu); + (LIBLTE_BYTE_MSG_STRUCT *) pdu); integrity_generate(&k_nas_int[16], count_ul, - lcid-1, + lcid - 1, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], - pdu->N_bytes-5, + pdu->N_bytes - 5, &pdu->msg[1]); // Instruct RRC to enable capabilities @@ -327,21 +383,18 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) nas_log->info("Sending Attach Complete\n"); rrc->write_sdu(lcid, pdu); - - } - else - { + + } else { nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result); state = EMM_STATE_DEREGISTERED; pool->deallocate(pdu); } } -void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) -{ +void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) { LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT attach_rej; - liblte_mme_unpack_attach_reject_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &attach_rej); + liblte_mme_unpack_attach_reject_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &attach_rej); nas_log->warning("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause); nas_log->console("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause); state = EMM_STATE_DEREGISTERED; @@ -349,13 +402,12 @@ void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) // FIXME: Command RRC to release? } -void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) -{ - LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req; +void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { + LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req; LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res; nas_log->info("Received Authentication Request\n");; - liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &auth_req); + liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req); // Reuse the pdu for the response message pdu->reset(); @@ -367,56 +419,49 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) nas_log->info("MCC=%d, MNC=%d\n", mcc, mnc); - bool net_valid; + bool net_valid; uint8_t res[16]; usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, &net_valid, res); - if(net_valid) - { + if (net_valid) { nas_log->info("Network authentication successful\n"); - for(int i=0; i<8; i++) - { + for (int i = 0; i < 8; i++) { auth_res.res[i] = res[i]; } - liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT*)pdu); + liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT *) pdu); nas_log->info("Sending Authentication Response\n"); rrc->write_sdu(lcid, pdu); - } - else - { + } else { nas_log->warning("Network authentication failure\n"); nas_log->console("Warning: Network authentication failure\n"); pool->deallocate(pdu); } } -void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) -{ +void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) { nas_log->warning("Received Authentication Reject\n"); pool->deallocate(pdu); state = EMM_STATE_DEREGISTERED; // FIXME: Command RRC to release? } -void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) -{ +void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) { nas_log->error("TODO:parse_identity_request\n"); } -void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) -{ - bool success; - LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd; - LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp; - LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej; +void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) { + bool success; + LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd; + LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp; + LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej; nas_log->info("Received Security Mode Command\n"); - liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT*)pdu, &sec_mode_cmd); + liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &sec_mode_cmd); ksi = sec_mode_cmd.nas_ksi.nas_ksi; - cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM)sec_mode_cmd.selected_nas_sec_algs.type_of_eea; - integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM)sec_mode_cmd.selected_nas_sec_algs.type_of_eia; + cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea; + integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia; // FIXME: Handle nonce_ue, nonce_mme // FIXME: Currently only handling ciphering EEA0 (null) and integrity EIA1,EIA2 // FIXME: Use selected_nas_sec_algs to choose correct algos @@ -425,17 +470,14 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) ksi, ciphering_algorithm_id_text[cipher_algo], integrity_algorithm_id_text[integ_algo]); - if(CIPHERING_ALGORITHM_ID_EEA0 != cipher_algo || - (INTEGRITY_ALGORITHM_ID_128_EIA2 != integ_algo && - INTEGRITY_ALGORITHM_ID_128_EIA1 != integ_algo) || - sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) - { + if (CIPHERING_ALGORITHM_ID_EEA0 != cipher_algo || + (INTEGRITY_ALGORITHM_ID_128_EIA2 != integ_algo && + INTEGRITY_ALGORITHM_ID_128_EIA1 != integ_algo) || + sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) { sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH; nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n"); success = false; - } - else - { + } else { // Generate NAS encryption key and integrity protection key usim->generate_nas_keys(k_nas_enc, k_nas_int, cipher_algo, integ_algo); nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); @@ -446,38 +488,35 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) uint8_t genMAC[4]; integrity_generate(&k_nas_int[16], count_dl, - lcid-1, + lcid - 1, SECURITY_DIRECTION_DOWNLINK, &pdu->msg[5], - pdu->N_bytes-5, + pdu->N_bytes - 5, genMAC); nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:"); nas_log->info_hex(genMAC, 4, "Generated PDU MAC:"); - bool match=true; - for(int i=0;i<4;i++) { - if(inMAC[i] != genMAC[i]) { + bool match = true; + for (int i = 0; i < 4; i++) { + if (inMAC[i] != genMAC[i]) { match = false; } } - if(!match) { + if (!match) { sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED; nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); success = false; } else { - if(sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) - { - sec_mode_comp.imeisv_present = true; - sec_mode_comp.imeisv.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV; - usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15); - sec_mode_comp.imeisv.imeisv[14] = 5; - sec_mode_comp.imeisv.imeisv[15] = 3; - } - else - { - sec_mode_comp.imeisv_present = false; + if (sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) { + sec_mode_comp.imeisv_present = true; + sec_mode_comp.imeisv.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV; + usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15); + sec_mode_comp.imeisv.imeisv[14] = 5; + sec_mode_comp.imeisv.imeisv[15] = 3; + } else { + sec_mode_comp.imeisv_present = false; } // Reuse pdu for response @@ -485,13 +524,13 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, count_ul, - (LIBLTE_BYTE_MSG_STRUCT*)pdu); + (LIBLTE_BYTE_MSG_STRUCT *) pdu); integrity_generate(&k_nas_int[16], count_ul, - lcid-1, + lcid - 1, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], - pdu->N_bytes-5, + pdu->N_bytes - 5, &pdu->msg[1]); nas_log->info("Sending Security Mode Complete nas_count_ul=%d, RB=%s\n", count_ul, @@ -500,44 +539,41 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) } } - if(!success) { + if (!success) { // Reuse pdu for response pdu->reset(); - liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT*)pdu); + liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) pdu); } rrc->write_sdu(lcid, pdu); } -void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) -{ +void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) { nas_log->error("TODO:parse_service_reject\n"); } -void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) -{ + +void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) { nas_log->error("TODO:parse_esm_information_request\n"); } -void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) -{ + +void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) { nas_log->error("TODO:parse_emm_information\n"); } /******************************************************************************* - Senders +Senders *******************************************************************************/ -void nas::send_attach_request() -{ - LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req; - byte_buffer_t *msg = pool_allocate; - u_int32_t i; +void nas::send_attach_request() { + LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req; + byte_buffer_t *msg = pool_allocate; + u_int32_t i; attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH; - for(i=0; i<8; i++) - { - attach_req.ue_network_cap.eea[i] = false; - attach_req.ue_network_cap.eia[i] = false; + for (i = 0; i < 8; i++) { + attach_req.ue_network_cap.eea[i] = false; + attach_req.ue_network_cap.eia[i] = false; } attach_req.ue_network_cap.eea[0] = true; // EEA0 supported attach_req.ue_network_cap.eia[0] = true; // EIA0 supported @@ -571,45 +607,43 @@ void nas::send_attach_request() attach_req.old_guti_type_present = false; // Pack the message - liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT*)msg); + liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); nas_log->info("Sending attach request\n"); rrc->write_sdu(cfg.lcid, msg); } -void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) -{ - LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req; +void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { + LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req; - nas_log->info("Generating PDN Connectivity Request\n"); + nas_log->info("Generating PDN Connectivity Request\n"); - // Set the PDN con req parameters - pdn_con_req.eps_bearer_id = 0x00; // Unassigned bearer ID - pdn_con_req.proc_transaction_id = 0x01; // First transaction ID - pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4; - pdn_con_req.request_type = LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST; + // Set the PDN con req parameters + pdn_con_req.eps_bearer_id = 0x00; // Unassigned bearer ID + pdn_con_req.proc_transaction_id = 0x01; // First transaction ID + pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4; + pdn_con_req.request_type = LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST; - // Set the optional flags - pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed - pdn_con_req.apn_present = false; - pdn_con_req.protocol_cnfg_opts_present = false; - pdn_con_req.device_properties_present = false; + // Set the optional flags + pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed + pdn_con_req.apn_present = false; + pdn_con_req.protocol_cnfg_opts_present = false; + pdn_con_req.device_properties_present = false; - // Pack the message - liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg); + // Pack the message + liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg); } -void nas::send_identity_response(){} +void nas::send_identity_response() {} -void nas::send_service_request() -{ +void nas::send_service_request() { byte_buffer_t *msg = pool_allocate; count_ul++; // Pack the service request message directly - msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg->N_bytes++; - msg->msg[1] = (ksi & 0x07) << 5; + msg->msg[1] = (ksi & 0x07) << 5; msg->msg[1] |= count_ul & 0x1F; msg->N_bytes++; @@ -630,6 +664,6 @@ void nas::send_service_request() rrc->write_sdu(cfg.lcid, msg); } -void nas::send_esm_information_response(){} +void nas::send_esm_information_response() {} } // namespace srsue diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 8b417f40d..94c2e449a 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -27,19 +27,24 @@ #include #include -#include - +#include "srslte/asn1/liblte_rrc.h" #include "upper/rrc.h" -#include "srslte/phy/utils/bit.h" +#include +#include +#include #include "srslte/common/security.h" #include "srslte/common/bcd_helpers.h" -#include "boost/assign.hpp" #define TIMEOUT_RESYNC_REESTABLISH 100 using namespace srslte; -namespace srsue{ +namespace srsue { + + +/******************************************************************************* + Base functions +*******************************************************************************/ rrc::rrc() :state(RRC_STATE_IDLE) @@ -48,12 +53,11 @@ rrc::rrc() } static void liblte_rrc_handler(void *ctx, char *str) { - rrc *r = (rrc*) ctx; + rrc *r = (rrc *) ctx; r->liblte_rrc_log(str); } -void rrc::liblte_rrc_log(char* str) -{ +void rrc::liblte_rrc_log(char *str) { if (rrc_log) { rrc_log->warning("[ASN]: %s\n", str); } else { @@ -61,339 +65,528 @@ void rrc::liblte_rrc_log(char* str) } } -void rrc::init(phy_interface_rrc *phy_, - mac_interface_rrc *mac_, - rlc_interface_rrc *rlc_, - pdcp_interface_rrc *pdcp_, - nas_interface_rrc *nas_, - usim_interface_rrc *usim_, - mac_interface_timers *mac_timers_, - srslte::log *rrc_log_) -{ - pool = byte_buffer_pool::get_instance(); - phy = phy_; - mac = mac_; - rlc = rlc_; - pdcp = pdcp_; - nas = nas_; - usim = usim_; +void rrc::init(phy_interface_rrc *phy_, + mac_interface_rrc *mac_, + rlc_interface_rrc *rlc_, + pdcp_interface_rrc *pdcp_, + nas_interface_rrc *nas_, + usim_interface_rrc *usim_, + mac_interface_timers *mac_timers_, + srslte::log *rrc_log_) { + pool = byte_buffer_pool::get_instance(); + phy = phy_; + mac = mac_; + rlc = rlc_; + pdcp = pdcp_; + nas = nas_; + usim = usim_; rrc_log = rrc_log_; // Use MAC timers mac_timers = mac_timers_; - t301 = mac_timers->get_unique_id(); - t310 = mac_timers->get_unique_id(); - t311 = mac_timers->get_unique_id(); - safe_reset_timer = mac_timers->get_unique_id(); + state = RRC_STATE_IDLE; + si_acquire_state = SI_ACQUIRE_IDLE; + + thread_running = true; + start(); + + pthread_mutex_init(&mutex, NULL); + ue_category = SRSLTE_UE_CATEGORY; + t301 = mac_timers->timer_get_unique_id(); + t310 = mac_timers->timer_get_unique_id(); + t311 = mac_timers->timer_get_unique_id(); - pthread_mutex_init(&mutex, NULL); - - ue_category = SRSLTE_UE_CATEGORY; - transaction_id = 0; - + // Register logging handler with liblte_rrc liblte_rrc_log_register_handler(this, liblte_rrc_handler); - - // Set default values for all layers + + nof_sib1_trials = 0; + last_win_start = 0; + + // Set default values for all layers set_rrc_default(); set_phy_default(); set_mac_default(); } -void rrc::stop() -{} +void rrc::stop() { + thread_running = false; + wait_thread_finish(); +} -rrc_state_t rrc::get_state() -{ +rrc_state_t rrc::get_state() { return state; } -void rrc::set_ue_category(int category) -{ - if(category >= 1 && category <= 5) { - ue_category = category; +bool rrc::is_connected() { + return (RRC_STATE_CONNECTED == state); +} + +bool rrc::have_drb() { + return drb_up; +} + +void rrc::set_ue_category(int category) { + if (category >= 1 && category <= 5) { + ue_category = category; } else { rrc_log->error("Unsupported UE category %d\n", category); } } +/* + * + * RRC State Machine + * + */ +void rrc::run_thread() { -/******************************************************************************* - NAS interface -*******************************************************************************/ + while (thread_running) { -void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) -{ - rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", rb_id_str[lcid].c_str()); - - switch(state) - { - case RRC_STATE_COMPLETING_SETUP: - send_con_setup_complete(sdu); - break; - case RRC_STATE_RRC_CONNECTED: - send_ul_info_transfer(lcid, sdu); - break; - default: - rrc_log->error("SDU received from NAS while RRC state = %s", rrc_state_text[state]); - break; + if (state >= RRC_STATE_IDLE && state < RRC_STATE_CONNECTING) { + run_si_acquisition_procedure(); + } + + switch(state) { + /* Procedures in IDLE state 36.304 Sec 4 */ + case RRC_STATE_IDLE: + // If camping on the cell, it will receive SI and paging from PLMN + if (phy->sync_status()) { + // If attempting to attach, reselect cell + if (nas->is_attaching()) { + sleep(1); + rrc_log->info("RRC IDLE: NAS is attaching and camping on cell, reselecting...\n"); + plmn_select(selected_plmn_id); + } + // If not camping on a cell + } else { + // If NAS is attached, perform cell reselection on current PLMN + if (nas->is_attached()) { + rrc_log->info("RRC IDLE: NAS is attached, PHY not synchronized. Re-selecting cell...\n"); + plmn_select(selected_plmn_id); + } else if (nas->is_attaching()) { + sleep(1); + rrc_log->info("RRC IDLE: NAS is attaching, searching again PLMN\n"); + plmn_search(); + } + // If not attached, PLMN selection will be triggered from higher layers + } + break; + case RRC_STATE_PLMN_SELECTION: + plmn_select_timeout++; + if (plmn_select_timeout >= RRC_PLMN_SELECT_TIMEOUT) { + rrc_log->info("RRC PLMN Search: timeout expired\n"); + phy->cell_search_stop(); + sleep(1); + rrc_log->console("\nRRC PLMN Search: timeout expired. Searching again\n"); + plmn_select_timeout = 0; + phy->cell_search_start(); + } + break; + case RRC_STATE_CELL_SELECTING: + if (phy->sync_status()) { + if (!current_cell->has_valid_sib1) { + si_acquire_state = SI_ACQUIRE_SIB1; + } else if (!current_cell->has_valid_sib2) { + si_acquire_state = SI_ACQUIRE_SIB2; + } else { + apply_sib2_configs(¤t_cell->sib2); + si_acquire_state = SI_ACQUIRE_IDLE; + state = RRC_STATE_CELL_SELECTED; + } + } + select_cell_timeout++; + if (select_cell_timeout >= RRC_SELECT_CELL_TIMEOUT) { + rrc_log->info("RRC Cell Selecting: timeout expired. Starting Cell Search...\n"); + state = RRC_STATE_PLMN_SELECTION; + plmn_select_timeout = 0; + phy->cell_search_start(); + } + break; + case RRC_STATE_CELL_SELECTED: + rrc_log->info("RRC Cell Selected: Sending connection request...\n"); + send_con_request(); + state = RRC_STATE_CONNECTING; + connecting_timeout = 0; + break; + case RRC_STATE_CONNECTING: + connecting_timeout++; + if (connecting_timeout >= RRC_CONNECTING_TIMEOUT) { + // Select another cell + rrc_log->info("RRC Connecting: timeout expired. Selecting next cell\n"); + state = RRC_STATE_CELL_SELECTING; + } + break; + case RRC_STATE_CONNECTED: + // Take measurements, cell reselection, etc + break; + case RRC_STATE_LEAVE_CONNECTED: + usleep(60000); + rrc_log->info("Leaving RRC_CONNECTED state\n"); + drb_up = false; + pdcp->reset(); + rlc->reset(); + phy->reset(); + mac->reset(); + set_phy_default(); + set_mac_default(); + mac->pcch_start_rx(); + mac_timers->timer_get(t310)->stop(); + mac_timers->timer_get(t311)->stop(); + state = RRC_STATE_IDLE; + break; + default: + break; + } + usleep(1000); } } -uint16_t rrc::get_mcc() -{ - if(sib1.N_plmn_ids > 0) - return sib1.plmn_id[0].id.mcc; - else - return 0; -} -uint16_t rrc::get_mnc() -{ - if(sib1.N_plmn_ids > 0) - return sib1.plmn_id[0].id.mnc; - else - return 0; -} + + + + /******************************************************************************* - MAC interface +* +* +* +* System Information Acquisition procedure +* +* +* *******************************************************************************/ -/* Reception of PUCCH/SRS release procedure (Section 5.3.13) */ -void rrc::release_pucch_srs() -{ - // Apply default configuration for PUCCH (CQI and SR) and SRS (release) - set_phy_default_pucch_srs(); - - // Configure RX signals without pregeneration because default option is release - phy->configure_ul_params(true); - + + +// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message +uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { + return (period * 10 * (1 + tti / (period * 10)) + x) % 10240; // the 1 means next opportunity } -void rrc::ra_problem() { - radio_link_failure(); +void rrc::run_si_acquisition_procedure() +{ + uint32_t tti; + uint32_t si_win_start=0, si_win_len=0; + uint16_t period; + const int SIB1_SEARCH_TIMEOUT = 30; + + switch (si_acquire_state) { + case SI_ACQUIRE_SIB1: + // Instruct MAC to look for SIB1 + tti = mac->get_current_tti(); + si_win_start = sib_start_tti(tti, 2, 5); + if (tti > last_win_start + 10) { + last_win_start = si_win_start; + mac->bcch_start_rx(si_win_start, 1); + rrc_log->debug("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n", + si_win_start, 1); + nof_sib1_trials++; + if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) { + if (state == RRC_STATE_CELL_SELECTING) { + select_next_cell_in_plmn(); + si_acquire_state = SI_ACQUIRE_IDLE; + } else if (state == RRC_STATE_PLMN_SELECTION) { + phy->cell_search_next(); + } + nof_sib1_trials = 0; + } + } + break; + case SI_ACQUIRE_SIB2: + // Instruct MAC to look for SIB2 only when selecting a cell + tti = mac->get_current_tti(); + period = liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]; + si_win_start = sib_start_tti(tti, period, 0); + if (tti > last_win_start + 10) { + last_win_start = si_win_start; + si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + + mac->bcch_start_rx(si_win_start, si_win_len); + rrc_log->debug("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n", + si_win_start, si_win_len); + } + break; + default: + break; + } } + + + + + + + + + + /******************************************************************************* - PHY interface +* +* +* +* PLMN selection, cell selection/reselection and acquisition of SI procedures +* +* +* *******************************************************************************/ -// Detection of physical layer problems (5.3.11.1) -void rrc::out_of_sync() -{ - if (!mac_timers->get(t311)->is_running() && !mac_timers->get(t310)->is_running()) { - n310_cnt++; - if (n310_cnt == N310) { - mac_timers->get(t310)->reset(); - mac_timers->get(t310)->run(); - n310_cnt = 0; - rrc_log->info("Detected %d out-of-sync from PHY. Starting T310 timer\n", N310); +uint16_t rrc::get_mcc() { + if (current_cell) { + if (current_cell->sib1.N_plmn_ids > 0) { + return current_cell->sib1.plmn_id[0].id.mcc; } } + return 0; } -// Recovery of physical layer problems (5.3.11.2) -void rrc::in_sync() -{ - if (mac_timers->get(t310)->is_running()) { - n311_cnt++; - if (n311_cnt == N311) { - mac_timers->get(t310)->stop(); - n311_cnt = 0; - rrc_log->info("Detected %d in-sync from PHY. Stopping T310 timer\n", N311); +uint16_t rrc::get_mnc() { + if (current_cell) { + if (current_cell->sib1.N_plmn_ids > 0) { + return current_cell->sib1.plmn_id[0].id.mnc; } } + return 0; } -/******************************************************************************* - GW interface -*******************************************************************************/ - -bool rrc::rrc_connected() -{ - return (RRC_STATE_RRC_CONNECTED == state); +void rrc::plmn_search() { + rrc_log->info("Starting PLMN search procedure\n"); + state = RRC_STATE_PLMN_SELECTION; + phy->cell_search_start(); + plmn_select_timeout = 0; } -void rrc::rrc_connect() { - pthread_mutex_lock(&mutex); - if(RRC_STATE_IDLE == state) { - rrc_log->info("RRC in IDLE state - sending connection request.\n"); - state = RRC_STATE_WAIT_FOR_CON_SETUP; - send_con_request(); +void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { + + // If already camping on the selected PLMN, select this cell + if (state == RRC_STATE_IDLE || state == RRC_STATE_CONNECTED || state == RRC_STATE_PLMN_SELECTION) { + if (phy->sync_status() && selected_plmn_id.mcc == plmn_id.mcc && selected_plmn_id.mnc == plmn_id.mnc) { + rrc_log->info("Already camping on selected PLMN, connecting...\n"); + state = RRC_STATE_CELL_SELECTING; + select_cell_timeout = 0; + } else { + rrc_log->info("PLMN Id=%s selected\n", plmn_id_to_string(plmn_id).c_str()); + // Sort cells according to RSRP + + selected_plmn_id = plmn_id; + last_selected_cell = -1; + select_cell_timeout = 0; + + state = RRC_STATE_CELL_SELECTING; + select_next_cell_in_plmn(); + } + } else { + rrc_log->warning("Requested PLMN select in incorrect state %s\n", rrc_state_text[state]); } - pthread_mutex_unlock(&mutex); } -bool rrc::have_drb() -{ - return drb_up; +void rrc::select_next_cell_in_plmn() { + for (uint32_t i = last_selected_cell + 1; i < known_cells.size(); i++) { + for (uint32_t j = 0; j < known_cells[i].sib1.N_plmn_ids; j++) { + if (known_cells[i].sib1.plmn_id[j].id.mcc == selected_plmn_id.mcc || + known_cells[i].sib1.plmn_id[j].id.mnc == selected_plmn_id.mnc) { + rrc_log->info("Selecting cell PCI=%d, EARFCN=%d, Cell ID=0x%x\n", + known_cells[i].phy_cell.id, known_cells[i].earfcn, + known_cells[i].sib1.cell_id); + rrc_log->console("Select cell: PCI=%d, EARFCN=%d, Cell ID=0x%x\n", + known_cells[i].phy_cell.id, known_cells[i].earfcn, + known_cells[i].sib1.cell_id); + // Check that cell satisfies S criteria + if (known_cells[i].in_sync) { // %% rsrp > S dbm + // Try to select Cell + if (phy->cell_select(known_cells[i].earfcn, known_cells[i].phy_cell)) + { + last_selected_cell = i; + current_cell = &known_cells[i]; + return; + } else { + rrc_log->warning("Selecting cell EARFCN=%d, Cell ID=0x%x.\n", + known_cells[i].earfcn, known_cells[i].sib1.cell_id); + } + } + } + } + } + rrc_log->info("No more known cells...\n"); } -/******************************************************************************* - PDCP interface -*******************************************************************************/ +void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { + + // find if cell_id-earfcn combination already exists + for (uint32_t i = 0; i < known_cells.size(); i++) { + if (earfcn == known_cells[i].earfcn && phy_cell.id == known_cells[i].phy_cell.id) { + known_cells[i].rsrp = rsrp; + known_cells[i].in_sync = true; + current_cell = &known_cells[i]; + rrc_log->info("Updating cell EARFCN=%d, PCI=%d, RSRP=%.1f dBm\n", known_cells[i].earfcn, + known_cells[i].phy_cell.id, known_cells[i].rsrp); + + if (!known_cells[i].has_valid_sib1) { + si_acquire_state = SI_ACQUIRE_SIB1; + } else if (state == RRC_STATE_PLMN_SELECTION) { + for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { + nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); + } + usleep(5000); + phy->cell_search_next(); + } + return; + } + } + // add to list of known cells + cell_t cell; + cell.phy_cell = phy_cell; + cell.rsrp = rsrp; + cell.earfcn = earfcn; + cell.has_valid_sib1 = false; + cell.has_valid_sib2 = false; + known_cells.push_back(cell); + + // save current cell + current_cell = &known_cells.back(); + + si_acquire_state = SI_ACQUIRE_SIB1; + + rrc_log->info("New Cell: PCI=%d, PRB=%d, Ports=%d, EARFCN=%d, RSRP=%.1f dBm\n", + cell.phy_cell.id, cell.phy_cell.nof_prb, cell.phy_cell.nof_ports, + cell.earfcn, cell.rsrp); +} -void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) -{ - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", rb_id_str[lcid].c_str()); - rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); +// PHY indicates that has gone through all known EARFCN +void rrc::earfcn_end() { + rrc_log->debug("Finished searching cells in EARFCN set while in state %s\n", rrc_state_text[state]); - switch(lcid) - { - case RB_ID_SRB0: - parse_dl_ccch(pdu); - break; - case RB_ID_SRB1: - case RB_ID_SRB2: - parse_dl_dcch(lcid, pdu); - break; - default: - rrc_log->error("TX PDU with invalid bearer id: %s", lcid); - break; + // If searching for PLMN, indicate NAS we scanned all frequencies + if (state == RRC_STATE_PLMN_SELECTION) { + nas->plmn_search_end(); } - } -void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu) -{ - // Unpack the MIB - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH BCH message received."); - rrc_log->info("BCCH BCH message Stack latency: %ld us\n", pdu->get_latency_us()); - srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); - bit_buf.N_bits = pdu->N_bytes*8; - pool->deallocate(pdu); - liblte_rrc_unpack_bcch_bch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &mib); - rrc_log->info("MIB received BW=%s MHz\n", liblte_rrc_dl_bandwidth_text[mib.dl_bw]); - rrc_log->console("MIB received BW=%s MHz\n", liblte_rrc_dl_bandwidth_text[mib.dl_bw]); - // Start the SIB search state machine - state = RRC_STATE_SIB1_SEARCH; - pthread_create(&sib_search_thread, NULL, &rrc::start_sib_thread, this); -} -void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) -{ - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); - rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us()); - LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; - srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); - bit_buf.N_bits = pdu->N_bytes*8; - pool->deallocate(pdu); - liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dlsch_msg); - if (dlsch_msg.N_sibs > 0) { - if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && RRC_STATE_SIB1_SEARCH == state) { - // Handle SIB1 - memcpy(&sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); - rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", - sib1.cell_id&0xfff, - liblte_rrc_si_window_length_num[sib1.si_window_length], - liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity]); - std::stringstream ss; - for(uint32_t i=0;iset_config_tdd(&dlsch_msg.sibs[0].sib.sib1.tdd_cnfg); - } - - rrc_log->console("SIB1 received, CellID=%d, %s\n", - sib1.cell_id&0xfff, - ss.str().c_str()); - - state = RRC_STATE_SIB2_SEARCH; - mac->bcch_stop_rx(); - //TODO: Use all SIB1 info - } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && RRC_STATE_SIB2_SEARCH == state) { - // Handle SIB2 - memcpy(&sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); - rrc_log->console("SIB2 received\n"); - rrc_log->info("SIB2 received\n"); - state = RRC_STATE_WAIT_FOR_CON_SETUP; - mac->bcch_stop_rx(); - apply_sib2_configs(); - send_con_request(); + + + +/******************************************************************************* +* +* +* +* Detection of Radio-Link Failures +* +* +* +*******************************************************************************/ + +// Detection of physical layer problems (5.3.11.1) +void rrc::out_of_sync() { + current_cell->in_sync = false; + if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) { + n310_cnt++; + if (n310_cnt == N310) { + // attempt resync + phy->sync_reset(); + + mac_timers->timer_get(t310)->reset(); + mac_timers->timer_get(t310)->run(); + n310_cnt = 0; + rrc_log->info("Detected %d out-of-sync from PHY. Starting T310 timer\n", N310); } } } -void rrc::write_pdu_pcch(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, "PCCH message received %d bytes\n", pdu->N_bytes); - rrc_log->info("PCCH message Stack latency: %ld us\n", pdu->get_latency_us()); - rrc_log->console("PCCH message received %d bytes\n", pdu->N_bytes); - - LIBLTE_RRC_PCCH_MSG_STRUCT pcch_msg; - srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); - bit_buf.N_bits = pdu->N_bytes*8; - pool->deallocate(pdu); - liblte_rrc_unpack_pcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &pcch_msg); - - if (pcch_msg.paging_record_list_size > LIBLTE_RRC_MAX_PAGE_REC) { - pcch_msg.paging_record_list_size = LIBLTE_RRC_MAX_PAGE_REC; +// Recovery of physical layer problems (5.3.11.2) +void rrc::in_sync() { + current_cell->in_sync = true; + if (mac_timers->timer_get(t310)->is_running()) { + n311_cnt++; + if (n311_cnt == N311) { + mac_timers->timer_get(t310)->stop(); + n311_cnt = 0; + rrc_log->info("Detected %d in-sync from PHY. Stopping T310 timer\n", N311); } + } +} - LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; - if(!nas->get_s_tmsi(&s_tmsi)) { - rrc_log->info("No S-TMSI present in NAS\n"); - return; - } - - LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged; - for (uint32_t i=0;iinfo("Received paging (%d/%d) for UE 0x%x\n", i+1, pcch_msg.paging_record_list_size, - pcch_msg.paging_record_list[i].ue_identity.s_tmsi); - rrc_log->console("Received paging (%d/%d) for UE 0x%x\n", i+1, pcch_msg.paging_record_list_size, - pcch_msg.paging_record_list[i].ue_identity.s_tmsi); - if(s_tmsi.mmec == s_tmsi_paged->mmec && s_tmsi.m_tmsi == s_tmsi_paged->m_tmsi) { - rrc_log->info("S-TMSI match in paging message\n"); - rrc_log->console("S-TMSI match in paging message\n"); - mac->pcch_stop_rx(); - if(RRC_STATE_IDLE == state) { - rrc_log->info("RRC in IDLE state - sending connection request.\n"); - state = RRC_STATE_WAIT_FOR_CON_SETUP; - send_con_request(); - } - } - } +/* Detection of radio link failure (5.3.11.3) + * Upon T310 expiry, RA problem or RLC max retx + */ +void rrc::radio_link_failure() { + // TODO: Generate and store failure report + + phy->sync_reset(); + rrc_log->warning("Detected Radio-Link Failure\n"); + rrc_log->console("Warning: Detected Radio-Link Failure\n"); + if (state != RRC_STATE_CONNECTED) { + state = RRC_STATE_LEAVE_CONNECTED; + } else { + send_con_restablish_request(); } } -/******************************************************************************* - RLC interface -*******************************************************************************/ +/* Reception of PUCCH/SRS release procedure (Section 5.3.13) */ +void rrc::release_pucch_srs() { + // Apply default configuration for PUCCH (CQI and SR) and SRS (release) + set_phy_default_pucch_srs(); -void rrc::max_retx_attempted() -{ + // Configure RX signals without pregeneration because default option is release + phy->configure_ul_params(true); +} + +void rrc::ra_problem() { + radio_link_failure(); +} + +void rrc::max_retx_attempted() { //TODO: Handle the radio link failure rrc_log->warning("Max RLC reTx attempted\n"); - //radio_link_failure(); + radio_link_failure(); } +void rrc::timer_expired(uint32_t timeout_id) { + if (timeout_id == t310) { + rrc_log->info("Timer T310 expired: Radio Link Failure\n"); + radio_link_failure(); + } else if (timeout_id == t311) { + rrc_log->info("Timer T311 expired: Going to RRC IDLE\n"); + state = RRC_STATE_LEAVE_CONNECTED; + } else if (timeout_id == t301) { + rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); + state = RRC_STATE_LEAVE_CONNECTED; + } else { + rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); + } +} + + + + + + + + /******************************************************************************* - Senders +* +* +* +* Connection Control: Establishment, Reconfiguration, Reestablishment and Release +* +* +* *******************************************************************************/ -void rrc::send_con_request() -{ +void rrc::send_con_request() { rrc_log->debug("Preparing RRC Connection Request\n"); LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; - LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; // Prepare ConnectionRequest packet ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ; - if(nas->get_s_tmsi(&s_tmsi)) { + if (nas->get_s_tmsi(&s_tmsi)) { ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI; ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi; } else { @@ -401,276 +594,607 @@ void rrc::send_con_request() ul_ccch_msg.msg.rrc_con_req.ue_id.random = 1000; } ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; - liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); // Byte align and pack the message bits for PDCP - if((bit_buf.N_bits % 8) != 0) - { - for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) bit_buf.msg[bit_buf.N_bits + i] = 0; bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); } - byte_buffer_t *pdcp_buf = pool_allocate; + byte_buffer_t *pdcp_buf = pool_allocate;; srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits/8; + pdcp_buf->N_bytes = bit_buf.N_bits / 8; pdcp_buf->set_timestamp(); // Set UE contention resolution ID in MAC - uint64_t uecri=0; - uint8_t *ue_cri_ptr = (uint8_t*) &uecri; + uint64_t uecri = 0; + uint8_t *ue_cri_ptr = (uint8_t *) &uecri; uint32_t nbytes = 6; - for (uint32_t i=0;imsg[i]; + for (uint32_t i = 0; i < nbytes; i++) { + ue_cri_ptr[nbytes - i - 1] = pdcp_buf->msg[i]; } rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); - + mac->set_contention_id(uecri); rrc_log->info("Sending RRC Connection Request on SRB0\n"); - state = RRC_STATE_WAIT_FOR_CON_SETUP; pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); } - /* RRC connection re-establishment procedure (5.3.7) */ -void rrc::send_con_restablish_request() -{ - - srslte_cell_t cell; +void rrc::send_con_restablish_request() { + + srslte_cell_t cell; phy->get_current_cell(&cell); LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; - LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; // Compute shortMAC-I uint8_t varShortMAC[128], varShortMAC_packed[16]; bzero(varShortMAC, 128); bzero(varShortMAC_packed, 16); - uint8_t *msg_ptr = varShortMAC; + uint8_t *msg_ptr = varShortMAC; liblte_rrc_pack_cell_identity_ie(0x1a2d0, &msg_ptr); liblte_rrc_pack_phys_cell_id_ie(cell.id, &msg_ptr); - mac_interface_rrc::ue_rnti_t ue_rnti; + mac_interface_rrc::ue_rnti_t ue_rnti; mac->get_rntis(&ue_rnti); liblte_rrc_pack_c_rnti_ie(ue_rnti.crnti, &msg_ptr); srslte_bit_pack_vector(varShortMAC, varShortMAC_packed, msg_ptr - varShortMAC); - + uint8_t mac_key[4]; security_128_eia2(&k_rrc_int[16], - 1, - 1, - 1, - varShortMAC_packed, - 7, - mac_key); - - mac_interface_rrc::ue_rnti_t uernti; + 1, + 1, + 1, + varShortMAC_packed, + 7, + mac_key); + + mac_interface_rrc::ue_rnti_t uernti; mac->get_rntis(&uernti); - + // Prepare ConnectionRestalishmentRequest packet - ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REEST_REQ; + ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REEST_REQ; ul_ccch_msg.msg.rrc_con_reest_req.ue_id.c_rnti = uernti.crnti; ul_ccch_msg.msg.rrc_con_reest_req.ue_id.phys_cell_id = cell.id; - ul_ccch_msg.msg.rrc_con_reest_req.ue_id.short_mac_i = mac_key[2]<<8 | mac_key[3]; + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.short_mac_i = mac_key[2] << 8 | mac_key[3]; ul_ccch_msg.msg.rrc_con_reest_req.cause = LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE; - liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); rrc_log->info("Initiating RRC Connection Reestablishment Procedure\n"); rrc_log->console("RRC Connection Reestablishment\n"); - mac_timers->get(t310)->stop(); - mac_timers->get(t311)->reset(); - mac_timers->get(t311)->run(); - + mac_timers->timer_get(t310)->stop(); + mac_timers->timer_get(t311)->reset(); + mac_timers->timer_get(t311)->run(); + + phy->reset(); set_phy_default(); mac->reset(); - + set_mac_default(); + // FIXME: Cell selection should be different?? - phy->resync_sfn(); - - // Wait for cell re-synchronization - uint32_t timeout_cnt = 0; - while(!phy->status_is_sync() && timeout_cnt < TIMEOUT_RESYNC_REESTABLISH){ + + // Wait for cell re-synchronization + uint32_t timeout_cnt = 0; + while (!phy->sync_status() && timeout_cnt < TIMEOUT_RESYNC_REESTABLISH) { usleep(10000); - timeout_cnt++; + timeout_cnt++; } - mac_timers->get(t301)->reset(); - mac_timers->get(t301)->run(); - mac_timers->get(t311)->stop(); + mac_timers->timer_get(t301)->reset(); + mac_timers->timer_get(t301)->run(); + mac_timers->timer_get(t311)->stop(); rrc_log->info("Cell Selection finished. Initiating transmission of RRC Connection Reestablishment Request\n"); - + // Byte align and pack the message bits for PDCP - if((bit_buf.N_bits % 8) != 0) - { - for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) bit_buf.msg[bit_buf.N_bits + i] = 0; bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); } - byte_buffer_t *pdcp_buf = pool_allocate; + byte_buffer_t *pdcp_buf = pool_allocate;; srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits/8; + pdcp_buf->N_bytes = bit_buf.N_bits / 8; // Set UE contention resolution ID in MAC - uint64_t uecri=0; - uint8_t *ue_cri_ptr = (uint8_t*) &uecri; + uint64_t uecri = 0; + uint8_t *ue_cri_ptr = (uint8_t *) &uecri; uint32_t nbytes = 6; - for (uint32_t i=0;imsg[i]; + for (uint32_t i = 0; i < nbytes; i++) { + ue_cri_ptr[nbytes - i - 1] = pdcp_buf->msg[i]; } rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); mac->set_contention_id(uecri); - rrc_log->info("Sending RRC Connection Resetablishment Request on SRB0\n"); - state = RRC_STATE_WAIT_FOR_CON_SETUP; + rrc_log->info("Sending RRC Connection Reestablishment Request on SRB0\n"); pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); } - -void rrc::send_con_restablish_complete() -{ +void rrc::send_con_restablish_complete() { rrc_log->debug("Preparing RRC Connection Reestablishment Complete\n"); LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; // Prepare ConnectionSetupComplete packet ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_REEST_COMPLETE; ul_dcch_msg.msg.rrc_con_reest_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + + // Byte align and pack the message bits for PDCP + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + byte_buffer_t *pdcp_buf = pool_allocate;; + srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); + pdcp_buf->N_bytes = bit_buf.N_bits / 8; + + state = RRC_STATE_CONNECTED; + rrc_log->console("RRC Connected\n"); + rrc_log->info("Sending RRC Connection Reestablishment Complete\n"); + pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); +} + +void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) { + rrc_log->debug("Preparing RRC Connection Setup Complete\n"); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + // Prepare ConnectionSetupComplete packet + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE; + ul_dcch_msg.msg.rrc_con_setup_complete.registered_mme_present = false; + ul_dcch_msg.msg.rrc_con_setup_complete.rrc_transaction_id = transaction_id; + ul_dcch_msg.msg.rrc_con_setup_complete.selected_plmn_id = 1; + memcpy(ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.msg, nas_msg->msg, nas_msg->N_bytes); + ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.N_bytes = nas_msg->N_bytes; + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); // Byte align and pack the message bits for PDCP - if((bit_buf.N_bits % 8) != 0) - { - for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) bit_buf.msg[bit_buf.N_bits + i] = 0; bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); } - byte_buffer_t *pdcp_buf = pool_allocate; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits/8; + byte_buffer_t *pdcp_buf = pool_allocate;; + srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); + pdcp_buf->N_bytes = bit_buf.N_bits / 8; + pdcp_buf->set_timestamp(); + + state = RRC_STATE_CONNECTED; + rrc_log->console("RRC Connected\n"); + rrc_log->info("Sending RRC Connection Setup Complete\n"); + pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); +} + +void rrc::send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu) { + rrc_log->debug("Preparing RX Info Transfer\n"); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + // Prepare RX INFO packet + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER; + ul_dcch_msg.msg.ul_info_transfer.dedicated_info_type = LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_NAS; + memcpy(ul_dcch_msg.msg.ul_info_transfer.dedicated_info.msg, sdu->msg, sdu->N_bytes); + ul_dcch_msg.msg.ul_info_transfer.dedicated_info.N_bytes = sdu->N_bytes; + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + + // Reset and reuse sdu buffer + byte_buffer_t *pdu = sdu; + pdu->reset(); + + // Byte align and pack the message bits for PDCP + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); + pdu->N_bytes = bit_buf.N_bits / 8; + pdu->set_timestamp(); + pdu->set_timestamp(); + + rrc_log->info("Sending RX Info Transfer\n"); + pdcp->write_sdu(lcid, pdu); +} + +void rrc::send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu) { + rrc_log->debug("Preparing Security Mode Complete\n"); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_COMPLETE; + ul_dcch_msg.msg.security_mode_complete.rrc_transaction_id = transaction_id; + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + + // Byte align and pack the message bits for PDCP + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); + pdu->N_bytes = bit_buf.N_bits / 8; + pdu->set_timestamp(); + + rrc_log->info("Sending Security Mode Complete\n"); + pdcp->write_sdu(lcid, pdu); +} + +void rrc::send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu) { + rrc_log->debug("Preparing RRC Connection Reconfig Complete\n"); + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE; + ul_dcch_msg.msg.rrc_con_reconfig_complete.rrc_transaction_id = transaction_id; + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + + // Byte align and pack the message bits for PDCP + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); + pdu->N_bytes = bit_buf.N_bits / 8; + pdu->set_timestamp(); + + rrc_log->info("Sending RRC Connection Reconfig Complete\n"); + pdcp->write_sdu(lcid, pdu); +} + + +void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, + byte_buffer_t *pdu) { + uint32_t i; + + if (reconfig->rr_cnfg_ded_present) { + apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); + } else { + printf("received con reconfig no rr confg present\n"); + } + if (reconfig->meas_cnfg_present) { + //TODO: handle meas_cnfg + } + if (reconfig->mob_ctrl_info_present) { + //TODO: handle mob_ctrl_info + } + + send_rrc_con_reconfig_complete(lcid, pdu); + + byte_buffer_t *nas_sdu; + for (i = 0; i < reconfig->N_ded_info_nas; i++) { + nas_sdu = pool_allocate;; + memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); + nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; + nas->write_pdu(lcid, nas_sdu); + } +} + + /* Actions upon reception of RRCConnectionRelease 5.3.8.3 */ +void rrc::rrc_connection_release() { + // Save idleModeMobilityControlInfo, etc. + state = RRC_STATE_LEAVE_CONNECTED; + rrc_log->console("Received RRC Connection Release\n"); +} + + + + + + + + +/******************************************************************************* +* +* +* +* Reception of Broadcast messages (MIB and SIBs) +* +* +* +*******************************************************************************/ +void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu) { + pool->deallocate(pdu); + if (state == RRC_STATE_PLMN_SELECTION) { + // Do we need to do something with BCH? + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH BCH message received."); + } else { + rrc_log->warning("Received BCCH BCH in incorrect state\n"); + } +} + +void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); + rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us()); + LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); + bit_buf.N_bits = pdu->N_bytes * 8; + pool->deallocate(pdu); + liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dlsch_msg); + + if (dlsch_msg.N_sibs > 0) { + if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state) { + mac->bcch_stop_rx(); + + // Handle SIB1 + memcpy(¤t_cell->sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); + + rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", + current_cell->sib1.cell_id & 0xfff, + liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length], + liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]); + + + // Set TDD Config + if (current_cell->sib1.tdd) { + phy->set_config_tdd(¤t_cell->sib1.tdd_cnfg); + } + + current_cell->has_valid_sib1 = true; + + // Send PLMN and TAC to NAS + std::stringstream ss; + for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { + nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); + } + + // Jump to next state + switch(state) { + case RRC_STATE_CELL_SELECTING: + si_acquire_state = SI_ACQUIRE_SIB2; + break; + case RRC_STATE_PLMN_SELECTION: + si_acquire_state = SI_ACQUIRE_IDLE; + rrc_log->info("SI Acquisition done. Searching next cell...\n"); + usleep(5000); + phy->cell_search_next(); + break; + default: + si_acquire_state = SI_ACQUIRE_IDLE; + } + + } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && + SI_ACQUIRE_SIB2 == si_acquire_state) { + mac->bcch_stop_rx(); + + // Handle SIB2 + memcpy(¤t_cell->sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); + rrc_log->info("SIB2 received\n"); + + apply_sib2_configs(¤t_cell->sib2); + + current_cell->has_valid_sib2 = true; + + // Jump to next state + switch(state) { + case RRC_STATE_CELL_SELECTING: + si_acquire_state = SI_ACQUIRE_IDLE; + state = RRC_STATE_CELL_SELECTED; + break; + default: + si_acquire_state = SI_ACQUIRE_IDLE; + } + } + } +} + + + +/******************************************************************************* +* +* +* +* Reception of Paging messages +* +* +* +*******************************************************************************/ +void rrc::write_pdu_pcch(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, "PCCH message received %d bytes\n", pdu->N_bytes); + rrc_log->info("PCCH message Stack latency: %ld us\n", pdu->get_latency_us()); + rrc_log->console("PCCH message received %d bytes\n", pdu->N_bytes); + + LIBLTE_RRC_PCCH_MSG_STRUCT pcch_msg; + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); + bit_buf.N_bits = pdu->N_bytes * 8; + pool->deallocate(pdu); + liblte_rrc_unpack_pcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &pcch_msg); + + if (pcch_msg.paging_record_list_size > LIBLTE_RRC_MAX_PAGE_REC) { + pcch_msg.paging_record_list_size = LIBLTE_RRC_MAX_PAGE_REC; + } + + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + if (!nas->get_s_tmsi(&s_tmsi)) { + rrc_log->info("No S-TMSI present in NAS\n"); + return; + } + + LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged; + for (uint32_t i = 0; i < pcch_msg.paging_record_list_size; i++) { + s_tmsi_paged = &pcch_msg.paging_record_list[i].ue_identity.s_tmsi; + rrc_log->info("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi); + rrc_log->console("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi); + if (s_tmsi.mmec == s_tmsi_paged->mmec && s_tmsi.m_tmsi == s_tmsi_paged->m_tmsi) { + rrc_log->info("S-TMSI match in paging message\n"); + rrc_log->console("S-TMSI match in paging message\n"); + mac->pcch_stop_rx(); + if (RRC_STATE_IDLE == state) { + rrc_log->info("RRC in IDLE state - sending connection request.\n"); + state = RRC_STATE_CELL_SELECTING; + } + } + } + } +} + + + + + + + + + + + +/******************************************************************************* +* +* +* +* Packet processing +* +* +* +*******************************************************************************/ +void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { + rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", get_rb_name(lcid).c_str()); + switch (state) { + case RRC_STATE_CONNECTING: + send_con_setup_complete(sdu); + break; + case RRC_STATE_CONNECTED: + send_ul_info_transfer(lcid, sdu); + break; + default: + rrc_log->error("SDU received from NAS while RRC state = %s", rrc_state_text[state]); + break; + } +} - state = RRC_STATE_RRC_CONNECTED; - rrc_log->console("RRC Connected\n"); - rrc_log->info("Sending RRC Connection Reestablishment Complete\n"); - pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); +void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", get_rb_name(lcid).c_str()); + rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); + + switch (lcid) { + case RB_ID_SRB0: + parse_dl_ccch(pdu); + break; + case RB_ID_SRB1: + case RB_ID_SRB2: + parse_dl_dcch(lcid, pdu); + break; + default: + rrc_log->error("TX PDU with invalid bearer id: %s", lcid); + break; + } } -void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) -{ - rrc_log->debug("Preparing RRC Connection Setup Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; +void rrc::parse_dl_ccch(byte_buffer_t *pdu) { + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); + bit_buf.N_bits = pdu->N_bytes * 8; + pool->deallocate(pdu); + bzero(&dl_ccch_msg, sizeof(LIBLTE_RRC_DL_CCCH_MSG_STRUCT)); + liblte_rrc_unpack_dl_ccch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dl_ccch_msg); - // Prepare ConnectionSetupComplete packet - ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE; - ul_dcch_msg.msg.rrc_con_setup_complete.registered_mme_present = false; - ul_dcch_msg.msg.rrc_con_setup_complete.rrc_transaction_id = transaction_id; - ul_dcch_msg.msg.rrc_con_setup_complete.selected_plmn_id = 1; - memcpy(ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.msg, nas_msg->msg, nas_msg->N_bytes); - ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.N_bytes = nas_msg->N_bytes; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + rrc_log->info("SRB0 - Received %s\n", + liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg.msg_type]); - // Byte align and pack the message bits for PDCP - if((bit_buf.N_bits % 8) != 0) - { - for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + switch (dl_ccch_msg.msg_type) { + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ: + rrc_log->info("Connection Reject received. Wait time: %d\n", + dl_ccch_msg.msg.rrc_con_rej.wait_time); + state = RRC_STATE_IDLE; + break; + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP: + rrc_log->info("Connection Setup received\n"); + transaction_id = dl_ccch_msg.msg.rrc_con_setup.rrc_transaction_id; + handle_con_setup(&dl_ccch_msg.msg.rrc_con_setup); + rrc_log->info("Notifying NAS of connection setup\n"); + nas->notify_connection_setup(); + break; + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST: + rrc_log->info("Connection Reestablishment received\n"); + rrc_log->console("Reestablishment OK\n"); + transaction_id = dl_ccch_msg.msg.rrc_con_reest.rrc_transaction_id; + handle_con_reest(&dl_ccch_msg.msg.rrc_con_reest); + break; + /* Reception of RRCConnectionReestablishmentReject 5.3.7.8 */ + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ: + rrc_log->info("Connection Reestablishment Reject received\n"); + rrc_log->console("Reestablishment Reject\n"); + state = RRC_STATE_LEAVE_CONNECTED; + break; + default: + break; } - byte_buffer_t *pdcp_buf = pool_allocate; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits/8; - pdcp_buf->set_timestamp(); - - state = RRC_STATE_RRC_CONNECTED; - rrc_log->console("RRC Connected\n"); - rrc_log->info("Sending RRC Connection Setup Complete\n"); - pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); } -void rrc::send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu) -{ - rrc_log->debug("Preparing RX Info Transfer\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; +void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); + bit_buf.N_bits = pdu->N_bytes * 8; + liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dl_dcch_msg); - // Prepare RX INFO packet - ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER; - ul_dcch_msg.msg.ul_info_transfer.dedicated_info_type = LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_NAS; - memcpy(ul_dcch_msg.msg.ul_info_transfer.dedicated_info.msg, sdu->msg, sdu->N_bytes); - ul_dcch_msg.msg.ul_info_transfer.dedicated_info.N_bytes = sdu->N_bytes; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + rrc_log->info("%s - Received %s\n", + get_rb_name(lcid).c_str(), + liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]); - // Reset and reuse sdu buffer - byte_buffer_t *pdu = sdu; + // Reset and reuse pdu buffer if possible pdu->reset(); - // Byte align and pack the message bits for PDCP - if((bit_buf.N_bits % 8) != 0) - { - for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits/8; - pdu->set_timestamp(); - pdu->set_timestamp(); + switch (dl_dcch_msg.msg_type) { + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER: + memcpy(pdu->msg, dl_dcch_msg.msg.dl_info_transfer.dedicated_info.msg, + dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes); + pdu->N_bytes = dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes; + nas->write_pdu(lcid, pdu); + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_SECURITY_MODE_COMMAND: + transaction_id = dl_dcch_msg.msg.security_mode_cmd.rrc_transaction_id; - rrc_log->info("Sending RX Info Transfer\n"); - pdcp->write_sdu(lcid, pdu); + cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.cipher_alg; + integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg; + + // Configure PDCP for security + usim->generate_as_keys(nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); + pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + send_security_mode_complete(lcid, pdu); + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG: + transaction_id = dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id; + handle_rrc_con_reconfig(lcid, &dl_dcch_msg.msg.rrc_con_reconfig, pdu); + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_CAPABILITY_ENQUIRY: + transaction_id = dl_dcch_msg.msg.ue_cap_enquiry.rrc_transaction_id; + for (uint32_t i = 0; i < dl_dcch_msg.msg.ue_cap_enquiry.N_ue_cap_reqs; i++) { + if (LIBLTE_RRC_RAT_TYPE_EUTRA == dl_dcch_msg.msg.ue_cap_enquiry.ue_capability_request[i]) { + send_rrc_ue_cap_info(lcid, pdu); + break; + } + } + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RELEASE: + rrc_connection_release(); + break; + default: + break; + } } -void rrc::send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu) -{ - rrc_log->debug("Preparing Security Mode Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; - ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_COMPLETE; - ul_dcch_msg.msg.security_mode_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); - // Byte align and pack the message bits for PDCP - if((bit_buf.N_bits % 8) != 0) - { - for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits/8; - pdu->set_timestamp(); - rrc_log->info("Sending Security Mode Complete\n"); - pdcp->write_sdu(lcid, pdu); -} -void rrc::send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu) -{ - rrc_log->debug("Preparing RRC Connection Reconfig Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; - ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE; - ul_dcch_msg.msg.rrc_con_reconfig_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); - // Byte align and pack the message bits for PDCP - if((bit_buf.N_bits % 8) != 0) - { - for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits/8; - pdu->set_timestamp(); - rrc_log->info("Sending RRC Connection Reconfig Complete\n"); - pdcp->write_sdu(lcid, pdu); -} -void rrc::enable_capabilities() -{ - bool enable_ul_64 = ue_category>=5 && sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam; - rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64?"Enabling":"Disabling"); - phy->set_config_64qam_en(enable_ul_64); + +/******************************************************************************* +* +* +* +* Capabilities Message +* +* +* +*******************************************************************************/ +void rrc::enable_capabilities() { + bool enable_ul_64 = ue_category >= 5 && current_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam; + rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64 ? "Enabling" : "Disabling"); + phy->set_config_64qam_en(enable_ul_64); } -void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) -{ +void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { rrc_log->debug("Preparing UE Capability Info\n"); LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; @@ -722,371 +1246,150 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[1] = true; cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[2] = true; - cap->feature_group_indicator_present = true; - cap->feature_group_indicator = 0x62001000; - cap->inter_rat_params.utra_fdd_present = false; - cap->inter_rat_params.utra_tdd128_present = false; - cap->inter_rat_params.utra_tdd384_present = false; - cap->inter_rat_params.utra_tdd768_present = false; - cap->inter_rat_params.geran_present = false; - cap->inter_rat_params.cdma2000_hrpd_present = false; + cap->feature_group_indicator_present = true; + cap->feature_group_indicator = 0x62001000; + cap->inter_rat_params.utra_fdd_present = false; + cap->inter_rat_params.utra_tdd128_present = false; + cap->inter_rat_params.utra_tdd384_present = false; + cap->inter_rat_params.utra_tdd768_present = false; + cap->inter_rat_params.geran_present = false; + cap->inter_rat_params.cdma2000_hrpd_present = false; cap->inter_rat_params.cdma2000_1xrtt_present = false; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf); + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); // Byte align and pack the message bits for PDCP - if((bit_buf.N_bits % 8) != 0) - { - for(uint32_t i=0; i<8-(bit_buf.N_bits % 8); i++) + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) bit_buf.msg[bit_buf.N_bits + i] = 0; bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); } srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits/8; + pdu->N_bytes = bit_buf.N_bits / 8; pdu->set_timestamp(); rrc_log->info("Sending UE Capability Info\n"); pdcp->write_sdu(lcid, pdu); } -/******************************************************************************* - Parsers -*******************************************************************************/ - -void rrc::parse_dl_ccch(byte_buffer_t *pdu) -{ - srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); - bit_buf.N_bits = pdu->N_bytes*8; - pool->deallocate(pdu); - bzero(&dl_ccch_msg, sizeof(LIBLTE_RRC_DL_CCCH_MSG_STRUCT)); - liblte_rrc_unpack_dl_ccch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dl_ccch_msg); - rrc_log->info("SRB0 - Received %s\n", - liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg.msg_type]); - switch(dl_ccch_msg.msg_type) - { - case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ: - rrc_log->info("Connection Reject received. Wait time: %d\n", - dl_ccch_msg.msg.rrc_con_rej.wait_time); - state = RRC_STATE_IDLE; - break; - case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP: - rrc_log->info("Connection Setup received\n"); - transaction_id = dl_ccch_msg.msg.rrc_con_setup.rrc_transaction_id; - handle_con_setup(&dl_ccch_msg.msg.rrc_con_setup); - rrc_log->info("Notifying NAS of connection setup\n"); - state = RRC_STATE_COMPLETING_SETUP; - nas->notify_connection_setup(); - break; - case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST: - rrc_log->info("Connection Reestablishment received\n"); - rrc_log->console("Reestablishment OK\n"); - transaction_id = dl_ccch_msg.msg.rrc_con_reest.rrc_transaction_id; - handle_con_reest(&dl_ccch_msg.msg.rrc_con_reest); - break; - case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ: - rrc_log->info("Connection Reestablishment Reject received\n"); - rrc_log->console("Reestablishment Reject\n"); - usleep(50000); - rrc_connection_release(); - break; - default: - break; - } -} -void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) -{ - srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); - bit_buf.N_bits = pdu->N_bytes*8; - liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dl_dcch_msg); - rrc_log->info("%s - Received %s\n", - rb_id_str[lcid].c_str(), - liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]); - // Reset and reuse pdu buffer if possible - pdu->reset(); - switch(dl_dcch_msg.msg_type) - { - case LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER: - memcpy(pdu->msg, dl_dcch_msg.msg.dl_info_transfer.dedicated_info.msg, dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes); - pdu->N_bytes = dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes; - nas->write_pdu(lcid, pdu); - break; - case LIBLTE_RRC_DL_DCCH_MSG_TYPE_SECURITY_MODE_COMMAND: - transaction_id = dl_dcch_msg.msg.security_mode_cmd.rrc_transaction_id; - - cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM)dl_dcch_msg.msg.security_mode_cmd.sec_algs.cipher_alg; - integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM)dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg; - - // Configure PDCP for security - usim->generate_as_keys(nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); - pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); - send_security_mode_complete(lcid, pdu); - break; - case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG: - transaction_id = dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id; - handle_rrc_con_reconfig(lcid, &dl_dcch_msg.msg.rrc_con_reconfig, pdu); - break; - case LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_CAPABILITY_ENQUIRY: - transaction_id = dl_dcch_msg.msg.ue_cap_enquiry.rrc_transaction_id; - for(uint32_t i=0; iinfo("Timer T310 expired: Radio Link Failure\n"); - radio_link_failure(); - } else if (timeout_id == t311) { - rrc_log->info("Timer T311 expired: Going to RRC IDLE\n"); - rrc_connection_release(); - } else if (timeout_id == t301) { - rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); - rrc_connection_release(); - } else if (timeout_id == safe_reset_timer) { - reset_ue(); - } else { - rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); - } -} /******************************************************************************* - Helpers +* +* +* +* PHY and MAC Radio Resource configuration +* +* +* *******************************************************************************/ -void rrc::reset_ue() { - phy->reset(); - mac->reset(); - pdcp->reset(); - rlc->reset(); - mac->pcch_start_rx(); - mac_timers->get(safe_reset_timer)->stop(); - mac_timers->get(safe_reset_timer)->reset(); - rrc_log->console("RRC Connection released.\n"); -} - -void rrc::rrc_connection_release() { - pthread_mutex_lock(&mutex); - drb_up = false; - state = RRC_STATE_IDLE; - set_phy_default(); - set_mac_default(); - mac_timers->get(t311)->run(); - mac_timers->get(t310)->stop(); - mac_timers->get(t311)->stop(); - mac_timers->get(safe_reset_timer)->stop(); - mac_timers->get(safe_reset_timer)->reset(); - mac_timers->get(safe_reset_timer)->run(); - pthread_mutex_unlock(&mutex); -} - -void rrc::test_con_restablishment() -{ - printf("Testing connection Reestablishment\n"); - send_con_restablish_request(); -} - -/* Detection of radio link failure (5.3.11.3) */ -void rrc::radio_link_failure() { - // TODO: Generate and store failure report - - rrc_log->warning("Detected Radio-Link Failure\n"); - rrc_log->console("Warning: Detected Radio-Link Failure\n"); - if (state != RRC_STATE_RRC_CONNECTED) { - rrc_connection_release(); - } else { - send_con_restablish_request(); - } -} - -void* rrc::start_sib_thread(void *rrc_) -{ - rrc *r = (rrc*)rrc_; - r->sib_search(); - return NULL; -} - -void rrc::sib_search() -{ - bool searching = true; - uint32_t tti ; - uint32_t si_win_start, si_win_len; - uint16_t period; - uint32_t nof_sib1_trials = 0; - const int SIB1_SEARCH_TIMEOUT = 30; - - while(searching) - { - switch(state) - { - case RRC_STATE_SIB1_SEARCH: - // Instruct MAC to look for SIB1 - while(!phy->status_is_sync()){ - usleep(50000); - } - usleep(10000); - tti = mac->get_current_tti(); - si_win_start = sib_start_tti(tti, 2, 5); - mac->bcch_start_rx(si_win_start, 1); - rrc_log->debug("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n", - si_win_start, 1); - nof_sib1_trials++; - if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) { - rrc_log->info("Timeout while searching for SIB1. Resynchronizing SFN...\n"); - rrc_log->console("Timeout while searching for SIB1. Resynchronizing SFN...\n"); - phy->resync_sfn(); - nof_sib1_trials = 0; - } - break; - case RRC_STATE_SIB2_SEARCH: - // Instruct MAC to look for SIB2 - usleep(10000); - tti = mac->get_current_tti(); - period = liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity]; - si_win_start = sib_start_tti(tti, period, 0); - si_win_len = liblte_rrc_si_window_length_num[sib1.si_window_length]; - - mac->bcch_start_rx(si_win_start, si_win_len); - rrc_log->debug("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n", - si_win_start, si_win_len); - - break; - default: - searching = false; - break; - } - usleep(100000); - } -} - -// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message -uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { - return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity -} +void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) { -void rrc::apply_sib2_configs() -{ - if(RRC_STATE_WAIT_FOR_CON_SETUP != state){ - rrc_log->error("State must be RRC_STATE_WAIT_FOR_CON_SETUP to handle SIB2. Actual state: %s\n", - rrc_state_text[state]); - return; - } - - // Apply RACH timeAlginmentTimer configuration - mac_interface_rrc::mac_cfg_t cfg; + // Apply RACH timeAlginmentTimer configuration + mac_interface_rrc::mac_cfg_t cfg; mac->get_config(&cfg); - cfg.main.time_alignment_timer = sib2.time_alignment_timer; - memcpy(&cfg.rach, &sib2.rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); - cfg.prach_config_index = sib2.rr_config_common_sib.prach_cnfg.root_sequence_index; + + cfg.main.time_alignment_timer = sib2->time_alignment_timer; + memcpy(&cfg.rach, &sib2->rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); + cfg.prach_config_index = sib2->rr_config_common_sib.prach_cnfg.root_sequence_index; cfg.ul_harq_params.max_harq_msg3_tx = cfg.rach.max_harq_msg3_tx; + mac->set_config(&cfg); - + rrc_log->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n", - liblte_rrc_number_of_ra_preambles_num[sib2.rr_config_common_sib.rach_cnfg.num_ra_preambles], - liblte_rrc_ra_response_window_size_num[sib2.rr_config_common_sib.rach_cnfg.ra_resp_win_size], - liblte_rrc_mac_contention_resolution_timer_num[sib2.rr_config_common_sib.rach_cnfg.mac_con_res_timer]); + liblte_rrc_number_of_ra_preambles_num[sib2->rr_config_common_sib.rach_cnfg.num_ra_preambles], + liblte_rrc_ra_response_window_size_num[sib2->rr_config_common_sib.rach_cnfg.ra_resp_win_size], + liblte_rrc_mac_contention_resolution_timer_num[sib2->rr_config_common_sib.rach_cnfg.mac_con_res_timer]); // Apply PHY RR Config Common - phy_interface_rrc::phy_cfg_common_t common; - memcpy(&common.pdsch_cnfg, &sib2.rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); - memcpy(&common.pusch_cnfg, &sib2.rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); - memcpy(&common.pucch_cnfg, &sib2.rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); - memcpy(&common.ul_pwr_ctrl, &sib2.rr_config_common_sib.ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT)); - memcpy(&common.prach_cnfg, &sib2.rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT)); - if (sib2.rr_config_common_sib.srs_ul_cnfg.present) { - memcpy(&common.srs_ul_cnfg, &sib2.rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); + phy_interface_rrc::phy_cfg_common_t common; + memcpy(&common.pdsch_cnfg, &sib2->rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.pusch_cnfg, &sib2->rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.pucch_cnfg, &sib2->rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); + memcpy(&common.ul_pwr_ctrl, &sib2->rr_config_common_sib.ul_pwr_ctrl, + sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT)); + memcpy(&common.prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT)); + if (sib2->rr_config_common_sib.srs_ul_cnfg.present) { + memcpy(&common.srs_ul_cnfg, &sib2->rr_config_common_sib.srs_ul_cnfg, + sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); } else { // default is release - common.srs_ul_cnfg.present = false; + common.srs_ul_cnfg.present = false; } phy->set_config_common(&common); phy->configure_ul_params(); rrc_log->info("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n", - sib2.rr_config_common_sib.pusch_cnfg.pusch_hopping_offset, - sib2.rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch, - sib2.rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift, - sib2.rr_config_common_sib.pusch_cnfg.n_sb); + sib2->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset, + sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch, + sib2->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift, + sib2->rr_config_common_sib.pusch_cnfg.n_sb); rrc_log->info("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n", - liblte_rrc_delta_pucch_shift_num[sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift], - sib2.rr_config_common_sib.pucch_cnfg.n_cs_an, - sib2.rr_config_common_sib.pucch_cnfg.n1_pucch_an, - sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi); - + liblte_rrc_delta_pucch_shift_num[sib2->rr_config_common_sib.pucch_cnfg.delta_pucch_shift], + sib2->rr_config_common_sib.pucch_cnfg.n_cs_an, + sib2->rr_config_common_sib.pucch_cnfg.n1_pucch_an, + sib2->rr_config_common_sib.pucch_cnfg.n_rb_cqi); + rrc_log->info("Set PRACH ConfigCommon: SeqIdx=%d, HS=%s, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n", - sib2.rr_config_common_sib.prach_cnfg.root_sequence_index, - sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?"yes":"no", - sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset, - sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config, - sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index); + sib2->rr_config_common_sib.prach_cnfg.root_sequence_index, + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag ? "yes" : "no", + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset, + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config, + sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index); rrc_log->info("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%s\n", - liblte_rrc_srs_bw_config_num[sib2.rr_config_common_sib.srs_ul_cnfg.bw_cnfg], - liblte_rrc_srs_subfr_config_num[sib2.rr_config_common_sib.srs_ul_cnfg.subfr_cnfg], - sib2.rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx?"yes":"no"); - - mac_timers->get(t301)->set(this, liblte_rrc_t301_num[sib2.ue_timers_and_constants.t301]); - mac_timers->get(t310)->set(this, liblte_rrc_t310_num[sib2.ue_timers_and_constants.t310]); - mac_timers->get(t311)->set(this, liblte_rrc_t311_num[sib2.ue_timers_and_constants.t311]); - N310 = liblte_rrc_n310_num[sib2.ue_timers_and_constants.n310]; - N311 = liblte_rrc_n311_num[sib2.ue_timers_and_constants.n311]; - - rrc_log->info("Set Constants and Timers: N310=%d, N311=%d, t301=%d, t310=%d, t311=%d\n", - N310, N311, mac_timers->get(t301)->get_timeout(), - mac_timers->get(t310)->get_timeout(), mac_timers->get(t311)->get_timeout()); - + liblte_rrc_srs_bw_config_num[sib2->rr_config_common_sib.srs_ul_cnfg.bw_cnfg], + liblte_rrc_srs_subfr_config_num[sib2->rr_config_common_sib.srs_ul_cnfg.subfr_cnfg], + sib2->rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx ? "yes" : "no"); + + mac_timers->timer_get(t301)->set(this, liblte_rrc_t301_num[sib2->ue_timers_and_constants.t301]); + mac_timers->timer_get(t310)->set(this, liblte_rrc_t310_num[sib2->ue_timers_and_constants.t310]); + mac_timers->timer_get(t311)->set(this, liblte_rrc_t311_num[sib2->ue_timers_and_constants.t311]); + N310 = liblte_rrc_n310_num[sib2->ue_timers_and_constants.n310]; + N311 = liblte_rrc_n311_num[sib2->ue_timers_and_constants.n311]; + + rrc_log->info("Set Constants and Timers: N310=%d, N311=%d, t301=%d, t310=%d, t311=%d\n", + N310, N311, mac_timers->timer_get(t301)->get_timeout(), + mac_timers->timer_get(t310)->get_timeout(), mac_timers->timer_get(t311)->get_timeout()); + } - // 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 - LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *current_cfg; - phy_interface_rrc::phy_cfg_t c; +// 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 + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *current_cfg; + phy_interface_rrc::phy_cfg_t c; phy->get_config(&c); current_cfg = &c.dedicated; - - if(phy_cnfg->pucch_cnfg_ded_present) { + + if (phy_cnfg->pucch_cnfg_ded_present) { memcpy(¤t_cfg->pucch_cnfg_ded, &phy_cnfg->pucch_cnfg_ded, sizeof(LIBLTE_RRC_PUCCH_CONFIG_DEDICATED_STRUCT)); } else if (apply_defaults) { - current_cfg->pucch_cnfg_ded.tdd_ack_nack_feedback_mode = LIBLTE_RRC_TDD_ACK_NACK_FEEDBACK_MODE_BUNDLING; - current_cfg->pucch_cnfg_ded.ack_nack_repetition_setup_present = false; + current_cfg->pucch_cnfg_ded.tdd_ack_nack_feedback_mode = LIBLTE_RRC_TDD_ACK_NACK_FEEDBACK_MODE_BUNDLING; + current_cfg->pucch_cnfg_ded.ack_nack_repetition_setup_present = false; } - if(phy_cnfg->pusch_cnfg_ded_present) { - memcpy(¤t_cfg->pusch_cnfg_ded, &phy_cnfg->pusch_cnfg_ded, sizeof(LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT)); + if (phy_cnfg->pusch_cnfg_ded_present) { + memcpy(¤t_cfg->pusch_cnfg_ded, &phy_cnfg->pusch_cnfg_ded, sizeof(LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT)); } else if (apply_defaults) { - current_cfg->pusch_cnfg_ded.beta_offset_ack_idx = 10; - current_cfg->pusch_cnfg_ded.beta_offset_ri_idx = 12; + current_cfg->pusch_cnfg_ded.beta_offset_ack_idx = 10; + current_cfg->pusch_cnfg_ded.beta_offset_ri_idx = 12; current_cfg->pusch_cnfg_ded.beta_offset_cqi_idx = 15; } - if(phy_cnfg->ul_pwr_ctrl_ded_present) { - memcpy(¤t_cfg->ul_pwr_ctrl_ded, &phy_cnfg->ul_pwr_ctrl_ded, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT)); + if (phy_cnfg->ul_pwr_ctrl_ded_present) { + memcpy(¤t_cfg->ul_pwr_ctrl_ded, &phy_cnfg->ul_pwr_ctrl_ded, + sizeof(LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT)); } else if (apply_defaults) { - current_cfg->ul_pwr_ctrl_ded.p0_ue_pusch = 0; + current_cfg->ul_pwr_ctrl_ded.p0_ue_pusch = 0; current_cfg->ul_pwr_ctrl_ded.delta_mcs_en = LIBLTE_RRC_DELTA_MCS_ENABLED_EN0; current_cfg->ul_pwr_ctrl_ded.accumulation_en = true; current_cfg->ul_pwr_ctrl_ded.p0_ue_pucch = 0; @@ -1097,140 +1400,144 @@ void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT } else { current_cfg->ul_pwr_ctrl_ded.filter_coeff = LIBLTE_RRC_FILTER_COEFFICIENT_FC4; } - if(phy_cnfg->tpc_pdcch_cnfg_pucch_present) { - memcpy(¤t_cfg->tpc_pdcch_cnfg_pucch, &phy_cnfg->tpc_pdcch_cnfg_pucch, sizeof(LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT)); + if (phy_cnfg->tpc_pdcch_cnfg_pucch_present) { + memcpy(¤t_cfg->tpc_pdcch_cnfg_pucch, &phy_cnfg->tpc_pdcch_cnfg_pucch, + sizeof(LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT)); } else if (apply_defaults) { - current_cfg->tpc_pdcch_cnfg_pucch.setup_present = false; + current_cfg->tpc_pdcch_cnfg_pucch.setup_present = false; } - if(phy_cnfg->tpc_pdcch_cnfg_pusch_present) { - memcpy(¤t_cfg->tpc_pdcch_cnfg_pusch, &phy_cnfg->tpc_pdcch_cnfg_pusch, sizeof(LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT)); + if (phy_cnfg->tpc_pdcch_cnfg_pusch_present) { + memcpy(¤t_cfg->tpc_pdcch_cnfg_pusch, &phy_cnfg->tpc_pdcch_cnfg_pusch, + sizeof(LIBLTE_RRC_TPC_PDCCH_CONFIG_STRUCT)); } else { - current_cfg->tpc_pdcch_cnfg_pusch.setup_present = false; + current_cfg->tpc_pdcch_cnfg_pusch.setup_present = false; } - if(phy_cnfg->cqi_report_cnfg_present) { + if (phy_cnfg->cqi_report_cnfg_present) { if (phy_cnfg->cqi_report_cnfg.report_periodic_present) { - memcpy(¤t_cfg->cqi_report_cnfg.report_periodic, &phy_cnfg->cqi_report_cnfg.report_periodic, sizeof(LIBLTE_RRC_CQI_REPORT_PERIODIC_STRUCT)); - current_cfg->cqi_report_cnfg.report_periodic_setup_present = phy_cnfg->cqi_report_cnfg.report_periodic_setup_present; + memcpy(¤t_cfg->cqi_report_cnfg.report_periodic, &phy_cnfg->cqi_report_cnfg.report_periodic, + sizeof(LIBLTE_RRC_CQI_REPORT_PERIODIC_STRUCT)); + current_cfg->cqi_report_cnfg.report_periodic_setup_present = phy_cnfg->cqi_report_cnfg.report_periodic_setup_present; } else if (apply_defaults) { - current_cfg->cqi_report_cnfg.report_periodic_setup_present = false; + current_cfg->cqi_report_cnfg.report_periodic_setup_present = false; } if (phy_cnfg->cqi_report_cnfg.report_mode_aperiodic_present) { - current_cfg->cqi_report_cnfg.report_mode_aperiodic = phy_cnfg->cqi_report_cnfg.report_mode_aperiodic; + current_cfg->cqi_report_cnfg.report_mode_aperiodic = phy_cnfg->cqi_report_cnfg.report_mode_aperiodic; current_cfg->cqi_report_cnfg.report_mode_aperiodic_present = phy_cnfg->cqi_report_cnfg.report_mode_aperiodic_present; } else if (apply_defaults) { - current_cfg->cqi_report_cnfg.report_mode_aperiodic_present = false; + current_cfg->cqi_report_cnfg.report_mode_aperiodic_present = false; } current_cfg->cqi_report_cnfg.nom_pdsch_rs_epre_offset = phy_cnfg->cqi_report_cnfg.nom_pdsch_rs_epre_offset; } - if(phy_cnfg->srs_ul_cnfg_ded_present && phy_cnfg->srs_ul_cnfg_ded.setup_present) { - memcpy(¤t_cfg->srs_ul_cnfg_ded, &phy_cnfg->srs_ul_cnfg_ded, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_DEDICATED_STRUCT)); + if (phy_cnfg->srs_ul_cnfg_ded_present && phy_cnfg->srs_ul_cnfg_ded.setup_present) { + memcpy(¤t_cfg->srs_ul_cnfg_ded, &phy_cnfg->srs_ul_cnfg_ded, + sizeof(LIBLTE_RRC_SRS_UL_CONFIG_DEDICATED_STRUCT)); } else if (apply_defaults) { - current_cfg->srs_ul_cnfg_ded.setup_present = false; + current_cfg->srs_ul_cnfg_ded.setup_present = false; } - if(phy_cnfg->antenna_info_present) { + if (phy_cnfg->antenna_info_present) { if (!phy_cnfg->antenna_info_default_value) { - if(phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_1 && - phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_2) { - rrc_log->error("Transmission mode TM%s not currently supported by srsUE\n", liblte_rrc_transmission_mode_text[phy_cnfg->antenna_info_explicit_value.tx_mode]); + if (phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_1 && + phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_2) { + rrc_log->error("Transmission mode TM%s not currently supported by srsUE\n", + liblte_rrc_transmission_mode_text[phy_cnfg->antenna_info_explicit_value.tx_mode]); } - memcpy(¤t_cfg->antenna_info_explicit_value, &phy_cnfg->antenna_info_explicit_value, sizeof(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT)); + memcpy(¤t_cfg->antenna_info_explicit_value, &phy_cnfg->antenna_info_explicit_value, + sizeof(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT)); } else if (apply_defaults) { current_cfg->antenna_info_explicit_value.tx_mode = LIBLTE_RRC_TRANSMISSION_MODE_2; - current_cfg->antenna_info_explicit_value.codebook_subset_restriction_present = false; - current_cfg->antenna_info_explicit_value.ue_tx_antenna_selection_setup_present = false; + current_cfg->antenna_info_explicit_value.codebook_subset_restriction_present = false; + current_cfg->antenna_info_explicit_value.ue_tx_antenna_selection_setup_present = false; } } else if (apply_defaults) { current_cfg->antenna_info_explicit_value.tx_mode = LIBLTE_RRC_TRANSMISSION_MODE_2; - current_cfg->antenna_info_explicit_value.codebook_subset_restriction_present = false; - current_cfg->antenna_info_explicit_value.ue_tx_antenna_selection_setup_present = false; + current_cfg->antenna_info_explicit_value.codebook_subset_restriction_present = false; + current_cfg->antenna_info_explicit_value.ue_tx_antenna_selection_setup_present = false; } - if(phy_cnfg->sched_request_cnfg_present) { - memcpy(¤t_cfg->sched_request_cnfg, &phy_cnfg->sched_request_cnfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); + if (phy_cnfg->sched_request_cnfg_present) { + memcpy(¤t_cfg->sched_request_cnfg, &phy_cnfg->sched_request_cnfg, + sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); } else if (apply_defaults) { - current_cfg->sched_request_cnfg.setup_present = false; + current_cfg->sched_request_cnfg.setup_present = false; } - if(phy_cnfg->pdsch_cnfg_ded_present) { - current_cfg->pdsch_cnfg_ded = phy_cnfg->pdsch_cnfg_ded; + if (phy_cnfg->pdsch_cnfg_ded_present) { + current_cfg->pdsch_cnfg_ded = phy_cnfg->pdsch_cnfg_ded; } else if (apply_defaults) { - current_cfg->pdsch_cnfg_ded = LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_0; + current_cfg->pdsch_cnfg_ded = LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_0; } if (phy_cnfg->cqi_report_cnfg_present) { if (phy_cnfg->cqi_report_cnfg.report_periodic_present) { - rrc_log->info("Set cqi-PUCCH-ResourceIndex=%d, cqi-pmi-ConfigIndex=%d, cqi-FormatIndicatorPeriodic=%s\n", - current_cfg->cqi_report_cnfg.report_periodic.pucch_resource_idx, - current_cfg->cqi_report_cnfg.report_periodic.pmi_cnfg_idx, - liblte_rrc_cqi_format_indicator_periodic_text[current_cfg->cqi_report_cnfg.report_periodic.format_ind_periodic]); - } + rrc_log->info("Set cqi-PUCCH-ResourceIndex=%d, cqi-pmi-ConfigIndex=%d, cqi-FormatIndicatorPeriodic=%s\n", + current_cfg->cqi_report_cnfg.report_periodic.pucch_resource_idx, + current_cfg->cqi_report_cnfg.report_periodic.pmi_cnfg_idx, + liblte_rrc_cqi_format_indicator_periodic_text[current_cfg->cqi_report_cnfg.report_periodic.format_ind_periodic]); + } if (phy_cnfg->cqi_report_cnfg.report_mode_aperiodic_present) { - rrc_log->info("Set cqi-ReportModeAperiodic=%s\n", - liblte_rrc_cqi_report_mode_aperiodic_text[current_cfg->cqi_report_cnfg.report_mode_aperiodic]); - } - + rrc_log->info("Set cqi-ReportModeAperiodic=%s\n", + liblte_rrc_cqi_report_mode_aperiodic_text[current_cfg->cqi_report_cnfg.report_mode_aperiodic]); + } + } - + if (phy_cnfg->sched_request_cnfg_present) { rrc_log->info("Set PHY config ded: SR-n_pucch=%d, SR-ConfigIndex=%d, SR-TransMax=%d\n", - current_cfg->sched_request_cnfg.sr_pucch_resource_idx, - current_cfg->sched_request_cnfg.sr_cnfg_idx, - liblte_rrc_dsr_trans_max_num[current_cfg->sched_request_cnfg.dsr_trans_max]); + current_cfg->sched_request_cnfg.sr_pucch_resource_idx, + current_cfg->sched_request_cnfg.sr_cnfg_idx, + liblte_rrc_dsr_trans_max_num[current_cfg->sched_request_cnfg.dsr_trans_max]); } - + if (current_cfg->srs_ul_cnfg_ded_present) { rrc_log->info("Set PHY config ded: SRS-ConfigIndex=%d, SRS-bw=%s, SRS-Nrcc=%d, SRS-hop=%s, SRS-Ncs=%s\n", - current_cfg->srs_ul_cnfg_ded.srs_cnfg_idx, - liblte_rrc_srs_bandwidth_text[current_cfg->srs_ul_cnfg_ded.srs_bandwidth], - current_cfg->srs_ul_cnfg_ded.freq_domain_pos, - liblte_rrc_srs_hopping_bandwidth_text[current_cfg->srs_ul_cnfg_ded.srs_hopping_bandwidth], - liblte_rrc_cyclic_shift_text[current_cfg->srs_ul_cnfg_ded.cyclic_shift]); + current_cfg->srs_ul_cnfg_ded.srs_cnfg_idx, + liblte_rrc_srs_bandwidth_text[current_cfg->srs_ul_cnfg_ded.srs_bandwidth], + current_cfg->srs_ul_cnfg_ded.freq_domain_pos, + liblte_rrc_srs_hopping_bandwidth_text[current_cfg->srs_ul_cnfg_ded.srs_hopping_bandwidth], + liblte_rrc_cyclic_shift_text[current_cfg->srs_ul_cnfg_ded.cyclic_shift]); } - + phy->set_config_dedicated(current_cfg); // Apply changes to PHY phy->configure_ul_params(); - } -void rrc::apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cnfg, bool apply_defaults) -{ +void rrc::apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cnfg, bool apply_defaults) { // Set Default MAC main configuration (9.2.2) LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT default_cfg; bzero(&default_cfg, sizeof(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT)); - default_cfg.ulsch_cnfg.max_harq_tx = LIBLTE_RRC_MAX_HARQ_TX_N5; + default_cfg.ulsch_cnfg.max_harq_tx = LIBLTE_RRC_MAX_HARQ_TX_N5; default_cfg.ulsch_cnfg.periodic_bsr_timer = LIBLTE_RRC_PERIODIC_BSR_TIMER_INFINITY; - default_cfg.ulsch_cnfg.retx_bsr_timer = LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF2560; - default_cfg.ulsch_cnfg.tti_bundling = false; - default_cfg.drx_cnfg.setup_present = false; - default_cfg.phr_cnfg.setup_present = false; - default_cfg.time_alignment_timer = LIBLTE_RRC_TIME_ALIGNMENT_TIMER_INFINITY; + default_cfg.ulsch_cnfg.retx_bsr_timer = LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF2560; + default_cfg.ulsch_cnfg.tti_bundling = false; + default_cfg.drx_cnfg.setup_present = false; + default_cfg.phr_cnfg.setup_present = false; + default_cfg.time_alignment_timer = LIBLTE_RRC_TIME_ALIGNMENT_TIMER_INFINITY; if (!apply_defaults) { - if(mac_cnfg->ulsch_cnfg_present) - { - if(mac_cnfg->ulsch_cnfg.max_harq_tx_present) { + if (mac_cnfg->ulsch_cnfg_present) { + if (mac_cnfg->ulsch_cnfg.max_harq_tx_present) { default_cfg.ulsch_cnfg.max_harq_tx = mac_cnfg->ulsch_cnfg.max_harq_tx; - default_cfg.ulsch_cnfg.max_harq_tx_present = true; + default_cfg.ulsch_cnfg.max_harq_tx_present = true; } - if(mac_cnfg->ulsch_cnfg.periodic_bsr_timer_present) { + if (mac_cnfg->ulsch_cnfg.periodic_bsr_timer_present) { default_cfg.ulsch_cnfg.periodic_bsr_timer = mac_cnfg->ulsch_cnfg.periodic_bsr_timer; - default_cfg.ulsch_cnfg.periodic_bsr_timer_present = true; + default_cfg.ulsch_cnfg.periodic_bsr_timer_present = true; } default_cfg.ulsch_cnfg.retx_bsr_timer = mac_cnfg->ulsch_cnfg.retx_bsr_timer; - default_cfg.ulsch_cnfg.tti_bundling = mac_cnfg->ulsch_cnfg.tti_bundling; + default_cfg.ulsch_cnfg.tti_bundling = mac_cnfg->ulsch_cnfg.tti_bundling; } - if(mac_cnfg->drx_cnfg_present) { + if (mac_cnfg->drx_cnfg_present) { memcpy(&default_cfg.drx_cnfg, &mac_cnfg->drx_cnfg, sizeof(LIBLTE_RRC_DRX_CONFIG_STRUCT)); - default_cfg.drx_cnfg_present = true; + default_cfg.drx_cnfg_present = true; } - if(mac_cnfg->phr_cnfg_present) { - memcpy(&default_cfg.phr_cnfg, &mac_cnfg->phr_cnfg, sizeof(LIBLTE_RRC_PHR_CONFIG_STRUCT)); - default_cfg.phr_cnfg_present = true; + if (mac_cnfg->phr_cnfg_present) { + memcpy(&default_cfg.phr_cnfg, &mac_cnfg->phr_cnfg, sizeof(LIBLTE_RRC_PHR_CONFIG_STRUCT)); + default_cfg.phr_cnfg_present = true; } default_cfg.time_alignment_timer = mac_cnfg->time_alignment_timer; } - + // Setup MAC configuration mac->set_config_main(&default_cfg); @@ -1246,98 +1553,65 @@ void rrc::apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cnfg liblte_rrc_periodic_bsr_timer_num[default_cfg.ulsch_cnfg.periodic_bsr_timer]); if (default_cfg.phr_cnfg_present) { rrc_log->info("Set MAC PHR config: periodicPHR-Timer=%d, prohibitPHR-Timer=%d, dl-PathlossChange=%d\n", - liblte_rrc_periodic_phr_timer_num[default_cfg.phr_cnfg.periodic_phr_timer], - liblte_rrc_prohibit_phr_timer_num[default_cfg.phr_cnfg.prohibit_phr_timer], - liblte_rrc_dl_pathloss_change_num[default_cfg.phr_cnfg.dl_pathloss_change]); + liblte_rrc_periodic_phr_timer_num[default_cfg.phr_cnfg.periodic_phr_timer], + liblte_rrc_prohibit_phr_timer_num[default_cfg.phr_cnfg.prohibit_phr_timer], + liblte_rrc_dl_pathloss_change_num[default_cfg.phr_cnfg.dl_pathloss_change]); } } -void rrc::apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg) { - if(cnfg->phy_cnfg_ded_present) { - apply_phy_config_dedicated(&cnfg->phy_cnfg_ded, false); - // Apply SR configuration to MAC - if (cnfg->phy_cnfg_ded.sched_request_cnfg_present) { - mac->set_config_sr(&cnfg->phy_cnfg_ded.sched_request_cnfg); - } +void rrc::apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg) { + if (cnfg->phy_cnfg_ded_present) { + apply_phy_config_dedicated(&cnfg->phy_cnfg_ded, false); + // Apply SR configuration to MAC + if (cnfg->phy_cnfg_ded.sched_request_cnfg_present) { + mac->set_config_sr(&cnfg->phy_cnfg_ded.sched_request_cnfg); + } } - - if(cnfg->mac_main_cnfg_present) { + + if (cnfg->mac_main_cnfg_present) { apply_mac_config_dedicated(&cnfg->mac_main_cnfg.explicit_value, cnfg->mac_main_cnfg.default_value); } - - if(cnfg->sps_cnfg_present) { + + if (cnfg->sps_cnfg_present) { //TODO } - if(cnfg->rlf_timers_and_constants_present) { + if (cnfg->rlf_timers_and_constants_present) { //TODO } - for(uint32_t i=0; isrb_to_add_mod_list_size; i++) { + for (uint32_t i = 0; i < cnfg->srb_to_add_mod_list_size; i++) { // TODO: handle SRB modification add_srb(&cnfg->srb_to_add_mod_list[i]); } - for(uint32_t i=0; idrb_to_release_list_size; i++) { + for (uint32_t i = 0; i < cnfg->drb_to_release_list_size; i++) { release_drb(cnfg->drb_to_release_list[i]); } - for(uint32_t i=0; idrb_to_add_mod_list_size; i++) { + for (uint32_t i = 0; i < cnfg->drb_to_add_mod_list_size; i++) { // TODO: handle DRB modification add_drb(&cnfg->drb_to_add_mod_list[i]); } } -void rrc::handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup) -{ +void rrc::handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup) { // Apply the Radio Resource configuration - apply_rr_config_dedicated(&setup->rr_cnfg); + apply_rr_config_dedicated(&setup->rr_cnfg); } /* Reception of RRCConnectionReestablishment by the UE 5.3.7.5 */ -void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) -{ - mac_timers->get(t301)->stop(); - +void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) { + mac_timers->timer_get(t301)->stop(); + // TODO: Restablish DRB1. Not done because never was suspended // Apply the Radio Resource configuration apply_rr_config_dedicated(&setup->rr_cnfg); // TODO: Some security stuff here... is it necessary? - + send_con_restablish_complete(); } -void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu) -{ - uint32_t i; - - if (reconfig->rr_cnfg_ded_present) { - apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); - } else { - printf("received con reconfig no rr confg present\n"); - } - if(reconfig->meas_cnfg_present) - { - //TODO: handle meas_cnfg - } - if(reconfig->mob_ctrl_info_present) - { - //TODO: handle mob_ctrl_info - } - - send_rrc_con_reconfig_complete(lcid, pdu); - - byte_buffer_t *nas_sdu; - for(i=0;iN_ded_info_nas;i++) - { - nas_sdu = pool_allocate; - memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); - nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; - nas->write_pdu(lcid, nas_sdu); - } -} - -void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) -{ +void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) { // Setup PDCP pdcp->add_bearer(srb_cnfg->srb_id, srslte_pdcp_config_t(true)); // Set PDCP config control flag if(RB_ID_SRB2 == srb_cnfg->srb_id) { @@ -1345,10 +1619,8 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) } // Setup RLC - if(srb_cnfg->rlc_cnfg_present) - { - if(srb_cnfg->rlc_default_cnfg_present) - { + if (srb_cnfg->rlc_cnfg_present) { + if (srb_cnfg->rlc_default_cnfg_present) { rlc->add_bearer(srb_cnfg->srb_id); }else{ rlc->add_bearer(srb_cnfg->srb_id, srslte_rlc_config_t(&srb_cnfg->rlc_explicit_cnfg)); @@ -1356,57 +1628,51 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) } // Setup MAC - uint8_t log_chan_group = 0; - uint8_t priority = 1; - int prioritized_bit_rate = -1; - int bucket_size_duration = -1; - - if(srb_cnfg->lc_cnfg_present) - { - if(srb_cnfg->lc_default_cnfg_present) - { - if(RB_ID_SRB2 == srb_cnfg->srb_id) + uint8_t log_chan_group = 0; + uint8_t priority = 1; + int prioritized_bit_rate = -1; + int bucket_size_duration = -1; + + if (srb_cnfg->lc_cnfg_present) { + if (srb_cnfg->lc_default_cnfg_present) { + if (RB_ID_SRB2 == srb_cnfg->srb_id) priority = 3; - }else{ - if(srb_cnfg->lc_explicit_cnfg.log_chan_sr_mask_present) - { + } else { + if (srb_cnfg->lc_explicit_cnfg.log_chan_sr_mask_present) { //TODO } - if(srb_cnfg->lc_explicit_cnfg.ul_specific_params_present) - { - if(srb_cnfg->lc_explicit_cnfg.ul_specific_params.log_chan_group_present) - log_chan_group = srb_cnfg->lc_explicit_cnfg.ul_specific_params.log_chan_group; - - priority = srb_cnfg->lc_explicit_cnfg.ul_specific_params.priority; - prioritized_bit_rate = liblte_rrc_prioritized_bit_rate_num[srb_cnfg->lc_explicit_cnfg.ul_specific_params.prioritized_bit_rate]; - bucket_size_duration = liblte_rrc_bucket_size_duration_num[srb_cnfg->lc_explicit_cnfg.ul_specific_params.bucket_size_duration]; + if (srb_cnfg->lc_explicit_cnfg.ul_specific_params_present) { + if (srb_cnfg->lc_explicit_cnfg.ul_specific_params.log_chan_group_present) + log_chan_group = srb_cnfg->lc_explicit_cnfg.ul_specific_params.log_chan_group; + + priority = srb_cnfg->lc_explicit_cnfg.ul_specific_params.priority; + prioritized_bit_rate = liblte_rrc_prioritized_bit_rate_num[srb_cnfg->lc_explicit_cnfg.ul_specific_params.prioritized_bit_rate]; + bucket_size_duration = liblte_rrc_bucket_size_duration_num[srb_cnfg->lc_explicit_cnfg.ul_specific_params.bucket_size_duration]; } } mac->setup_lcid(srb_cnfg->srb_id, log_chan_group, priority, prioritized_bit_rate, bucket_size_duration); } srbs[srb_cnfg->srb_id] = *srb_cnfg; - rrc_log->info("Added radio bearer %s\n", rb_id_str[srb_cnfg->srb_id].c_str()); + rrc_log->info("Added radio bearer %s\n", get_rb_name(srb_cnfg->srb_id).c_str()); } -void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) -{ +void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { - if(!drb_cnfg->pdcp_cnfg_present || - !drb_cnfg->rlc_cnfg_present || - !drb_cnfg->lc_cnfg_present) - { + if (!drb_cnfg->pdcp_cnfg_present || + !drb_cnfg->rlc_cnfg_present || + !drb_cnfg->lc_cnfg_present) { rrc_log->error("Cannot add DRB - incomplete configuration\n"); return; } - uint32_t lcid = 0; + uint32_t lcid = 0; if (drb_cnfg->lc_id_present) { lcid = drb_cnfg->lc_id; } else { lcid = RB_ID_SRB2 + drb_cnfg->drb_id; rrc_log->warning("LCID not present, using %d\n", lcid); } - + // Setup PDCP srslte_pdcp_config_t pdcp_cfg; pdcp_cfg.is_data = true; @@ -1422,85 +1688,76 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) rlc->add_bearer(lcid, srslte_rlc_config_t(&drb_cnfg->rlc_cnfg)); // Setup MAC - uint8_t log_chan_group = 0; - uint8_t priority = 1; - int prioritized_bit_rate = -1; - int bucket_size_duration = -1; - if(drb_cnfg->lc_cnfg.ul_specific_params_present) - { - if(drb_cnfg->lc_cnfg.ul_specific_params.log_chan_group_present) { - log_chan_group = drb_cnfg->lc_cnfg.ul_specific_params.log_chan_group; + uint8_t log_chan_group = 0; + uint8_t priority = 1; + int prioritized_bit_rate = -1; + int bucket_size_duration = -1; + if (drb_cnfg->lc_cnfg.ul_specific_params_present) { + if (drb_cnfg->lc_cnfg.ul_specific_params.log_chan_group_present) { + log_chan_group = drb_cnfg->lc_cnfg.ul_specific_params.log_chan_group; } else { rrc_log->warning("LCG not present, setting to 0\n"); } - priority = drb_cnfg->lc_cnfg.ul_specific_params.priority; - prioritized_bit_rate = liblte_rrc_prioritized_bit_rate_num[drb_cnfg->lc_cnfg.ul_specific_params.prioritized_bit_rate]; - + priority = drb_cnfg->lc_cnfg.ul_specific_params.priority; + prioritized_bit_rate = liblte_rrc_prioritized_bit_rate_num[drb_cnfg->lc_cnfg.ul_specific_params.prioritized_bit_rate]; + if (prioritized_bit_rate > 0) { rrc_log->warning("PBR>0 currently not supported. Setting it to Inifinty\n"); - prioritized_bit_rate = -1; + prioritized_bit_rate = -1; } - - bucket_size_duration = liblte_rrc_bucket_size_duration_num[drb_cnfg->lc_cnfg.ul_specific_params.bucket_size_duration]; - } + + bucket_size_duration = liblte_rrc_bucket_size_duration_num[drb_cnfg->lc_cnfg.ul_specific_params.bucket_size_duration]; + } mac->setup_lcid(lcid, log_chan_group, priority, prioritized_bit_rate, bucket_size_duration); - + drbs[lcid] = *drb_cnfg; drb_up = true; - rrc_log->info("Added radio bearer %s\n", rb_id_str[lcid].c_str()); + rrc_log->info("Added radio bearer %s\n", get_rb_name(lcid).c_str()); } -void rrc::release_drb(uint8_t lcid) -{ +void rrc::release_drb(uint8_t lcid) { // TODO } -/************************** - * DEFAULT VALUES Section 9 -****************************/ - // PHY CONFIG DEDICATED Defaults (3GPP 36.331 v10 9.2.4) -void rrc::set_phy_default_pucch_srs() -{ - +void rrc::set_phy_default_pucch_srs() { + phy_interface_rrc::phy_cfg_t current_cfg; phy->get_config(¤t_cfg); - + // Set defaults to CQI, SRS and SR - current_cfg.dedicated.cqi_report_cnfg_present = false; - current_cfg.dedicated.srs_ul_cnfg_ded_present = false; - current_cfg.dedicated.sched_request_cnfg_present = false; + current_cfg.dedicated.cqi_report_cnfg_present = false; + current_cfg.dedicated.srs_ul_cnfg_ded_present = false; + current_cfg.dedicated.sched_request_cnfg_present = false; apply_phy_config_dedicated(¤t_cfg.dedicated, true); - - // Release SR configuration from MAC - LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT cfg; + + // Release SR configuration from MAC + LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT cfg; bzero(&cfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); mac->set_config_sr(&cfg); } -void rrc::set_phy_default() -{ - LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT defaults; +void rrc::set_phy_default() { + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT defaults; bzero(&defaults, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); apply_phy_config_dedicated(&defaults, true); } -void rrc::set_mac_default() -{ +void rrc::set_mac_default() { apply_mac_config_dedicated(NULL, true); - LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sr_cfg; + LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sr_cfg; bzero(&sr_cfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); - sr_cfg.setup_present = false; + sr_cfg.setup_present = false; mac->set_config_sr(&sr_cfg); } void rrc::set_rrc_default() { N310 = 1; - N311 = 1; - mac_timers->get(t310)->set(this, 1000); - mac_timers->get(t311)->set(this, 1000); - mac_timers->get(safe_reset_timer)->set(this, 10); + N311 = 1; + mac_timers->timer_get(t310)->set(this, 1000); + mac_timers->timer_get(t311)->set(this, 1000); } + } // namespace srsue diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index 7b1f92896..e1d2c204f 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -25,13 +25,15 @@ */ +#include #include "upper/usim.h" +#include "srslte/common/bcd_helpers.h" using namespace srslte; namespace srsue{ -usim::usim() +usim::usim() : initiated(false) {} void usim::init(usim_args_t *args, srslte::log *usim_log_) @@ -91,6 +93,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_) if("xor" == args->algo) { auth_algo = auth_algo_xor; } + initiated = true; } void usim::stop() @@ -102,24 +105,31 @@ void usim::stop() void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) { - if(NULL == imsi_ || n < 15) - { + if (!initiated) { + fprintf(stderr, "USIM not initiated!\n"); + return; + } + + if(NULL == imsi_ || n < 15) { usim_log->error("Invalid parameters to get_imsi_vec"); return; } uint64_t temp = imsi; - for(int i=14;i>=0;i--) - { - imsi_[i] = temp % 10; - temp /= 10; + for(int i=14;i>=0;i--) { + imsi_[i] = temp % 10; + temp /= 10; } } void usim::get_imei_vec(uint8_t* imei_, uint32_t n) { - if(NULL == imei_ || n < 15) - { + if (!initiated) { + fprintf(stderr, "USIM not initiated!\n"); + return; + } + + if(NULL == imei_ || n < 15) { usim_log->error("Invalid parameters to get_imei_vec"); return; } @@ -127,9 +137,50 @@ void usim::get_imei_vec(uint8_t* imei_, uint32_t n) uint64 temp = imei; for(int i=14;i>=0;i--) { - imei_[i] = temp % 10; - temp /= 10; + imei_[i] = temp % 10; + temp /= 10; + } +} + +int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) +{ + if (!initiated) { + fprintf(stderr, "USIM not initiated!\n"); + return -1; + } + + int mcc_len = 3; + int mnc_len = 2; + + uint8_t imsi_vec[15]; + get_imsi_vec(imsi_vec, 15); + + std::ostringstream mcc_str, mnc_str; + + for (int i=0;imcc); + string_to_mnc(mnc_str.str(), &home_plmn_id->mnc); + + usim_log->info("Read Home PLMN Id=%s\n", + plmn_id_to_string(*home_plmn_id).c_str()); + + return 0; } void usim::generate_authentication_response(uint8_t *rand, diff --git a/srsue/test/CMakeLists.txt b/srsue/test/CMakeLists.txt index c9949a7e2..217c369ee 100644 --- a/srsue/test/CMakeLists.txt +++ b/srsue/test/CMakeLists.txt @@ -21,3 +21,7 @@ add_subdirectory(phy) add_subdirectory(mac) add_subdirectory(upper) + +add_executable(metrics_test metrics_test.cc ../src/metrics_stdout.cc ../src/metrics_csv.cc) +target_link_libraries(metrics_test srslte_phy srslte_common) +add_test(metrics_test metrics_test -o ${CMAKE_CURRENT_BINARY_DIR}/ue_metrics.csv) diff --git a/srsue/test/mac/mac_test.cc b/srsue/test/mac/mac_test.cc index 368a7f35e..4cb47e9f8 100644 --- a/srsue/test/mac/mac_test.cc +++ b/srsue/test/mac/mac_test.cc @@ -427,22 +427,11 @@ private: int main(int argc, char *argv[]) { - srslte::log_filter mac_log("MAC"), phy_log("PHY"); + srslte::log_filter mac_log("MAC"); rlctest my_rlc; parse_args(&prog_args, argc, argv); - switch (prog_args.verbose) { - case 1: - mac_log.set_level(srslte::LOG_LEVEL_INFO); - phy_log.set_level(srslte::LOG_LEVEL_INFO); - break; - case 2: - mac_log.set_level(srslte::LOG_LEVEL_DEBUG); - phy_log.set_level(srslte::LOG_LEVEL_DEBUG); - break; - } - - // Capture SIGINT to write traces + // Capture SIGINT to write traces if (prog_args.do_trace) { signal(SIGINT, sig_int_handler); //radio.start_trace(); @@ -461,7 +450,26 @@ int main(int argc, char *argv[]) if (!radio.init()) { exit(1); } - phy.init(&radio, &mac, NULL, &phy_log); + + std::vector phy_log; + + srslte::log_filter *mylog = new srslte::log_filter("PHY"); + char tmp[16]; + sprintf(tmp, "PHY%d",0); + phy_log.push_back((void*) mylog); + + switch (prog_args.verbose) { + case 1: + mac_log.set_level(srslte::LOG_LEVEL_INFO); + mylog->set_level(srslte::LOG_LEVEL_INFO); + break; + case 2: + mac_log.set_level(srslte::LOG_LEVEL_DEBUG); + mylog->set_level(srslte::LOG_LEVEL_DEBUG); + break; + } + + phy.init(&radio, &mac, NULL, phy_log); if (prog_args.rf_rx_gain > 0 && prog_args.rf_tx_gain > 0) { radio.set_rx_gain(prog_args.rf_rx_gain); radio.set_tx_gain(prog_args.rf_tx_gain); diff --git a/srsue/test/metrics_test.cc b/srsue/test/metrics_test.cc new file mode 100644 index 000000000..52a5f98f9 --- /dev/null +++ b/srsue/test/metrics_test.cc @@ -0,0 +1,122 @@ +/** + * + * \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 +#include +#include +#include +#include +#include "ue_metrics_interface.h" +#include "srslte/common/metrics_hub.h" +#include "metrics_stdout.h" +#include "metrics_csv.h" + +using namespace srsue; + +namespace srsue { + +char *csv_file_name = NULL; + +// fake classes +class ue_dummy : public ue_metrics_interface +{ +public: + bool get_metrics(ue_metrics_t &m) + { + // fill dummy values + bzero(&m, sizeof(ue_metrics_t)); + m.rf.rf_o = 10; + m.phy.dl.rsrp = -10.0; + m.phy.dl.pathloss = 74; + return true; + } + + bool is_attached() + { + return (rand() % 2 == 0); + } +}; +} + +void usage(char *prog) { + printf("Usage: %s -o csv_output_file\n", prog); +} + +void parse_args(int argc, char **argv) { + int opt; + + while ((opt = getopt(argc, argv, "o")) != -1) { + switch(opt) { + case 'o': + csv_file_name = argv[optind]; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!csv_file_name) { + usage(argv[0]); + exit(-1); + } +} + + +int main(int argc, char **argv) +{ + float period = 1.0; + ue_dummy ue; + + if (argc < 3) { + usage(argv[0]); + exit(-1); + } + + parse_args(argc,argv); + + // the default metrics type for stdout output + metrics_stdout metrics_screen; + metrics_screen.set_ue_handle(&ue); + + // the CSV file writer + metrics_csv metrics_file(csv_file_name); + metrics_file.set_ue_handle(&ue); + + // create metrics hub and register metrics for stdout + srslte::metrics_hub metricshub; + metricshub.init(&ue, period); + metricshub.add_listener(&metrics_screen); + metricshub.add_listener(&metrics_file); + + // enable printing + metrics_screen.toggle_print(true); + + std::cout << "Running for 2 seconds .." << std::endl; + usleep(2e6); + + metricshub.stop(); + return 0; +} diff --git a/srsue/test/phy/CMakeLists.txt b/srsue/test/phy/CMakeLists.txt index bb463efb0..a0570f0e7 100644 --- a/srsue/test/phy/CMakeLists.txt +++ b/srsue/test/phy/CMakeLists.txt @@ -18,8 +18,8 @@ # and at http://www.gnu.org/licenses/. # -add_executable(ue_itf_test_sib1 ue_itf_test_sib1.cc) -target_link_libraries(ue_itf_test_sib1 srsue_phy srslte_common srslte_phy srslte_radio ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +#add_executable(ue_itf_test_sib1 ue_itf_test_sib1.cc) +#target_link_libraries(ue_itf_test_sib1 srsue_phy srslte_common srslte_phy srslte_radio ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -add_executable(ue_itf_test_prach ue_itf_test_prach.cc) -target_link_libraries(ue_itf_test_prach srsue_phy srslte_common srslte_phy srslte_radio ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +#add_executable(ue_itf_test_prach ue_itf_test_prach.cc) +#target_link_libraries(ue_itf_test_prach srsue_phy srslte_common srslte_phy srslte_radio ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) diff --git a/srsue/test/phy/ue_itf_test_prach.cc b/srsue/test/phy/ue_itf_test_prach.cc index c2d78470d..810278c7c 100644 --- a/srsue/test/phy/ue_itf_test_prach.cc +++ b/srsue/test/phy/ue_itf_test_prach.cc @@ -277,8 +277,8 @@ public: } void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) { - action->decode_enabled = true; - action->default_ack = false; + action->decode_enabled[0] = true; + action->default_ack[0] = false; if (grant.rnti == 2) { action->generate_ack = false; } else { @@ -380,9 +380,7 @@ int main(int argc, char *argv[]) radio.set_tx_freq(prog_args.rf_tx_freq); // Instruct the PHY to configure PRACH parameters and sync to current cell - my_phy.sync_start(); - - while(!my_phy.status_is_sync()) { + while(!my_phy.sync_status()) { usleep(20000); } diff --git a/srsue/test/phy/ue_itf_test_sib1.cc b/srsue/test/phy/ue_itf_test_sib1.cc index be3cb18e8..23f8566be 100644 --- a/srsue/test/phy/ue_itf_test_sib1.cc +++ b/srsue/test/phy/ue_itf_test_sib1.cc @@ -116,8 +116,8 @@ public: total_dci++; - action->decode_enabled = true; - action->default_ack = false; + action->decode_enabled[0] = true; + action->default_ack[0] = false; action->generate_ack = false; for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { action->payload_ptr[tb] = payload[tb]; @@ -194,11 +194,9 @@ int main(int argc, char *argv[]) // Set RX freq and gain radio.set_rx_freq(prog_args.rf_freq); - my_phy.sync_start(); - - bool running = true; + bool running = true; while(running) { - if (bch_decoded && my_phy.status_is_sync()) { + if (bch_decoded && my_phy.sync_status()) { uint32_t tti = my_phy.get_current_tti(); // SIB1 is scheduled in subframe #5 of even frames, try to decode next frame SIB1 @@ -208,7 +206,7 @@ int main(int argc, char *argv[]) total_pkts++; } usleep(30000); - if (bch_decoded && my_phy.status_is_sync() && total_pkts > 0) { + if (bch_decoded && my_phy.sync_status() && total_pkts > 0) { if (srslte_verbose == SRSLTE_VERBOSE_NONE && srsapps_verbose == 0) { float gain = prog_args.rf_gain; if (gain < 0) { diff --git a/srsue/test/upper/CMakeLists.txt b/srsue/test/upper/CMakeLists.txt index 324ae4913..cbffe1cc8 100644 --- a/srsue/test/upper/CMakeLists.txt +++ b/srsue/test/upper/CMakeLists.txt @@ -18,17 +18,6 @@ # and at http://www.gnu.org/licenses/. # -# IP traffic over RLC test -add_executable(ip_test ip_test.cc) -target_link_libraries(ip_test srsue_mac - srsue_phy - srslte_common - srslte_phy - srslte_radio - srslte_upper - ${CMAKE_THREAD_LIBS_INIT} - ${Boost_LIBRARIES}) - add_executable(usim_test usim_test.cc) target_link_libraries(usim_test srsue_upper srslte_upper srslte_phy) add_test(usim_test usim_test) diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 8c9ba7d3d..30c05069a 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -3,8 +3,8 @@ ##################################################################### # RF configuration # -# dl_freq: Downlink centre frequency (Hz). -# ul_freq: Uplink centre frequency (Hz). +# dl_earfcn: Downlink EARFCN code. +# freq_offset: Uplink and Downlink optional frequency offset (in Hz) # tx_gain: Transmit gain (dB). # rx_gain: Optional receive gain (dB). If disabled, AGC if enabled # @@ -21,10 +21,10 @@ # Default "auto". B210 USRP: 400 us, bladeRF: 0 us. ##################################################################### [rf] -dl_freq = 2685000000 -ul_freq = 2565000000 -tx_gain = 80 -rx_gain = 60 +dl_earfcn = 3400 +freq_offset = 0 +tx_gain = 70 +rx_gain = 40 #nof_rx_ant = 1 #device_name = auto @@ -64,7 +64,8 @@ filename = /tmp/ue.pcap # Logging layers: phy, mac, rlc, pdcp, rrc, nas, gw, usim, all # Logging levels: debug, info, warning, error, none # -# filename: File path to use for log output +# filename: File path to use for log output. Can be set to stdout +# to print logs to standard output ##################################################################### [log] all_level = info @@ -129,6 +130,10 @@ enable = false # # pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance. # +# metrics_csv_enable: Write UE metrics to CSV file. +# +# metrics_csv_filename: File path to use for CSV metrics. +# ##################################################################### [expert] #ue_category = 4 @@ -148,6 +153,8 @@ enable = false #sss_algorithm = full #estimator_fil_w = 0.1 #pregenerate_signals = false +#metrics_csv_enable = false +#metrics_csv_filename = /tmp/ue_metrics.csv ##################################################################### # Manual RF calibration