Merge branch 'next' into next_testers

master
Ismael Gomez 7 years ago
commit a7cd65e307

@ -1,6 +1,11 @@
Change Log for Releases 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 ## 002.000.000
* Added fully functional srsENB to srsLTE code * Added fully functional srsENB to srsLTE code
* Merged srsUE code into srsLTE and reestructured PHY code * Merged srsUE code into srsLTE and reestructured PHY code

@ -120,7 +120,7 @@ else(POLARSSL_FOUND)
endif(BUILD_STATIC) endif(BUILD_STATIC)
add_definitions(-DHAVE_MBEDTLS) add_definitions(-DHAVE_MBEDTLS)
else(MBEDTLS_FOUND) 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 (MBEDTLS_FOUND)
endif(POLARSSL_FOUND) endif(POLARSSL_FOUND)

@ -15,12 +15,13 @@ srsLTE is released under the AGPLv3 license and uses software from the OpenLTE p
Common Features Common Features
--------------- ---------------
* LTE Release 8 compliant * LTE Release 8 compliant (with selected features of Release 9)
* FDD configuration * FDD configuration
* Tested bandwidths: 1.4, 3, 5, 10, 15 and 20 MHz * 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 * 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 * MAC, RLC, PDCP, RRC, NAS, S1AP and GW layers
* Detailed log system with per-layer log levels and hex dumps * Detailed log system with per-layer log levels and hex dumps
* MAC layer wireshark packet capture * MAC layer wireshark packet capture
@ -33,6 +34,7 @@ srsUE Features
* Cell search and synchronization procedure for the UE * Cell search and synchronization procedure for the UE
* Soft USIM supporting Milenage and XOR authentication * Soft USIM supporting Milenage and XOR authentication
* Virtual network interface *tun_srsue* created upon network attach * 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. * 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. * 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 5
* LG Nexus 4 * LG Nexus 4
* Motorola Moto G4 plus * Motorola Moto G4 plus
* Huawei P9/P9lite
* Huawei dongles: E3276 and E398
Hardware Hardware
-------- --------
@ -65,13 +69,14 @@ We have tested the following hardware:
* USRP B210 * USRP B210
* USRP X300 * USRP X300
* bladeRF * bladeRF
* limeSDR * limeSDR (currently, only the PHY-layer examples, i.e., pdsch_enodeb/ue are supported)
Build Instructions Build Instructions
------------------ ------------------
* Mandatory requirements: * Mandatory requirements:
* Common: * Common:
* cmake https://cmake.org/
* libfftw http://www.fftw.org/ * libfftw http://www.fftw.org/
* PolarSSL/mbedTLS https://tls.mbed.org * PolarSSL/mbedTLS https://tls.mbed.org
* srsUE: * srsUE:
@ -83,7 +88,7 @@ Build Instructions
For example, on Ubuntu 17.04, one can install the required libraries with: 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. Note that depending on your flavor and version of Linux, the actual package names may be different.

@ -16,6 +16,7 @@ FIND_LIBRARY(
HINTS $ENV{UHD_DIR}/lib HINTS $ENV{UHD_DIR}/lib
PATHS /usr/local/lib PATHS /usr/local/lib
/usr/lib /usr/lib
/usr/lib/x86_64-linux-gnu
/usr/local/lib64 /usr/local/lib64
/usr/local/lib32 /usr/local/lib32
) )

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/. # and at http://www.gnu.org/licenses/.
# #
SET(SRSLTE_VERSION_MAJOR 002) SET(SRSLTE_VERSION_MAJOR 17)
SET(SRSLTE_VERSION_MINOR 000) SET(SRSLTE_VERSION_MINOR 9)
SET(SRSLTE_VERSION_PATCH 000) SET(SRSLTE_VERSION_PATCH 0)
SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}") SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}")

@ -241,19 +241,31 @@ int main(int argc, char **argv) {
srslte_rf_stop_rx_stream(&rf); srslte_rf_stop_rx_stream(&rf);
srslte_rf_flush_buffer(&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"); fprintf(stderr, "Error initiating ue_sync\n");
return -1; 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"); fprintf(stderr, "Error initiating UE downlink processing module\n");
return -1; 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"); fprintf(stderr, "Error initaiting UE MIB decoder\n");
return -1; 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 */ /* 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); 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"); fprintf(stderr, "Error initiating FFT\n");
return -1; 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"); fprintf(stderr, "Error initiating channel estimator\n");
return -1; 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); int sf_re = SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);
cf_t *sf_symbols = srslte_vec_malloc(sf_re * sizeof(cf_t)); 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); fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
return -1; return -1;
} else if (n == 0) { } 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_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++; nof_trials++;
} else { } else {
printf("Decoded SIB1. Payload: "); printf("Decoded SIB1. Payload: ");

@ -188,6 +188,18 @@ int main(int argc, char **argv) {
sigprocmask(SIG_UNBLOCK, &sigset, NULL); sigprocmask(SIG_UNBLOCK, &sigset, NULL);
signal(SIGINT, sig_int_handler); 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<nof_freqs && !go_exit;freq++) { for (freq=0;freq<nof_freqs && !go_exit;freq++) {
/* set rf_freq */ /* set rf_freq */
@ -203,18 +215,6 @@ int main(int argc, char **argv) {
} }
bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t)); bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t));
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);
}
INFO("Setting sampling frequency %.2f MHz for PSS search\n", SRSLTE_CS_SAMP_FREQ/1000000); INFO("Setting sampling frequency %.2f MHz for PSS search\n", SRSLTE_CS_SAMP_FREQ/1000000);
srslte_rf_set_rx_srate(&rf, SRSLTE_CS_SAMP_FREQ); srslte_rf_set_rx_srate(&rf, SRSLTE_CS_SAMP_FREQ);
@ -222,7 +222,6 @@ int main(int argc, char **argv) {
srslte_rf_start_rx_stream(&rf); srslte_rf_start_rx_stream(&rf);
n = srslte_ue_cellsearch_scan(&cs, found_cells, NULL); n = srslte_ue_cellsearch_scan(&cs, found_cells, NULL);
srslte_ue_cellsearch_free(&cs);
if (n < 0) { if (n < 0) {
fprintf(stderr, "Error searching cell\n"); fprintf(stderr, "Error searching cell\n");
exit(-1); exit(-1);
@ -254,7 +253,7 @@ int main(int argc, char **argv) {
} }
} }
} }
printf("\n\nFound %d cells\n", n_found_cells); printf("\n\nFound %d cells\n", n_found_cells);
for (int i=0;i<n_found_cells;i++) { for (int i=0;i<n_found_cells;i++) {
printf("Found CELL %.1f MHz, EARFCN=%d, PHYID=%d, %d PRB, %d ports, PSS power=%.1f dBm\n", printf("Found CELL %.1f MHz, EARFCN=%d, PHYID=%d, %d PRB, %d ports, PSS power=%.1f dBm\n",
@ -268,7 +267,8 @@ int main(int argc, char **argv) {
} }
printf("\nBye\n"); printf("\nBye\n");
srslte_ue_cellsearch_free(&cs);
srslte_rf_close(&rf); srslte_rf_close(&rf);
exit(0); exit(0);
} }

@ -27,7 +27,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <unistd.h> #include <unistd.h>
#include <sys/select.h>
#include <pthread.h> #include <pthread.h>
#include <semaphore.h> #include <semaphore.h>
#include <signal.h> #include <signal.h>
@ -38,10 +40,11 @@
#define UE_CRNTI 0x1234 #define UE_CRNTI 0x1234
#define M_CRNTI 0xFFFD
#ifndef DISABLE_RF #ifndef DISABLE_RF
#include "srslte/phy/rf/rf.h" #include "srslte/phy/rf/rf.h"
#include "srslte/phy/common/phy_common.h"
srslte_rf_t rf; srslte_rf_t rf;
#else #else
#warning Compiling pdsch_ue with no RF support #warning Compiling pdsch_ue with no RF support
@ -55,52 +58,67 @@ char *output_file_name = NULL;
#define DOWN_KEY 66 #define DOWN_KEY 66
srslte_cell_t cell = { srslte_cell_t cell = {
25, // nof_prb 25, // nof_prb
1, // nof_ports 1, // nof_ports
0, // cell_id 0, // cell_id
SRSLTE_CP_NORM, // cyclic prefix SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_NORM, // PHICH length SRSLTE_PHICH_NORM, // PHICH length
SRSLTE_PHICH_R_1 // PHICH resources 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 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; uint32_t mcs_idx = 1, last_mcs_idx = 1;
int nof_frames = -1; int nof_frames = -1;
char mimo_type_str[32] = "single"; char mimo_type_str[32] = "single";
uint32_t nof_tb = 1; uint32_t nof_tb = 1;
uint32_t multiplex_pmi = 0; uint32_t multiplex_pmi = 0;
uint32_t multiplex_nof_layers = 1; uint32_t multiplex_nof_layers = 1;
int mbsfn_area_id = -1;
char *rf_args = ""; char *rf_args = "";
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000; float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
bool null_file_sink=false; bool null_file_sink=false;
srslte_filesink_t fsink; srslte_filesink_t fsink;
srslte_ofdm_t ifft; srslte_ofdm_t ifft;
srslte_ofdm_t ifft_mbsfn;
srslte_pbch_t pbch; srslte_pbch_t pbch;
srslte_pcfich_t pcfich; srslte_pcfich_t pcfich;
srslte_pdcch_t pdcch; srslte_pdcch_t pdcch;
srslte_pdsch_t pdsch; 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_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
srslte_regs_t regs; 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}; int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0};
cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL}; cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL};
int sf_n_re, sf_n_samples; int sf_n_re, sf_n_samples;
pthread_t net_thread; pthread_t net_thread;
void *net_thread_fnc(void *arg); void *net_thread_fnc(void *arg);
sem_t net_sem; sem_t net_sem;
bool net_packet_ready = false; bool net_packet_ready = false;
srslte_netsource_t net_source; srslte_netsource_t net_source;
srslte_netsink_t net_sink; srslte_netsink_t net_sink;
int prbset_num = 1, last_prbset_num = 1; int prbset_num = 1, last_prbset_num = 1;
int prbset_orig = 0; 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 #define DATA_BUFF_SZ 1024*1024
uint8_t *data[2], data2[DATA_BUFF_SZ]; 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-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); 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-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-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi);
printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers); printf("\t-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) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "aglfmoncpvutxbw")) != -1) { while ((opt = getopt(argc, argv, "aglfmoncpvutxbwM")) != -1) {
switch (opt) { switch (opt) {
case 'a': case 'a':
rf_args = argv[optind]; rf_args = argv[optind];
@ -173,6 +193,9 @@ void parse_args(int argc, char **argv) {
case 'w': case 'w':
multiplex_nof_layers = (uint32_t) atoi(argv[optind]); multiplex_nof_layers = (uint32_t) atoi(argv[optind]);
break; break;
case 'M':
mbsfn_area_id = atoi(argv[optind]);
break;
case 'v': case 'v':
srslte_verbose++; srslte_verbose++;
break; break;
@ -188,7 +211,7 @@ void parse_args(int argc, char **argv) {
} }
#endif #endif
} }
void base_init() { void base_init() {
int i; int i;
@ -245,6 +268,7 @@ void base_init() {
bzero(output_buffer[i], sizeof(cf_t) * sf_n_samples); bzero(output_buffer[i], sizeof(cf_t) * sf_n_samples);
} }
/* open file or USRP */ /* open file or USRP */
if (output_file_name) { if (output_file_name) {
if (strcmp(output_file_name, "NULL")) { if (strcmp(output_file_name, "NULL")) {
@ -291,18 +315,36 @@ void base_init() {
fprintf(stderr, "Error creating iFFT object\n"); fprintf(stderr, "Error creating iFFT object\n");
exit(-1); 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); srslte_ofdm_set_normalize(&ifft, true);
if (srslte_pbch_init(&pbch, cell)) {
if (srslte_pbch_init(&pbch)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
exit(-1); exit(-1);
} }
if (srslte_pbch_set_cell(&pbch, cell)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
if (srslte_regs_init(&regs, cell)) { if (srslte_regs_init(&regs, cell)) {
fprintf(stderr, "Error initiating regs\n"); fprintf(stderr, "Error initiating regs\n");
exit(-1); exit(-1);
} }
if (srslte_pcfich_init(&pcfich, 1)) {
if (srslte_pcfich_init(&pcfich, &regs, cell)) { fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
if (srslte_pcfich_set_cell(&pcfich, &regs, cell)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
exit(-1); exit(-1);
} }
@ -312,19 +354,34 @@ void base_init() {
exit(-1); exit(-1);
} }
if (srslte_pdcch_init_tx(&pdcch, &regs, 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, &regs, cell)) {
fprintf(stderr, "Error creating PDCCH object\n"); fprintf(stderr, "Error creating PDCCH object\n");
exit(-1); exit(-1);
} }
bzero(&pdsch, sizeof(srslte_pdsch_t)); if (srslte_pdsch_init_enb(&pdsch, cell.nof_prb)) {
if (srslte_pdsch_init_tx(&pdsch, cell)) { fprintf(stderr, "Error creating PDSCH object\n");
exit(-1);
}
if (srslte_pdsch_set_cell(&pdsch, cell)) {
fprintf(stderr, "Error creating PDSCH object\n"); fprintf(stderr, "Error creating PDSCH object\n");
exit(-1); exit(-1);
} }
srslte_pdsch_set_rnti(&pdsch, UE_CRNTI); 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++) { for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
softbuffers[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1); softbuffers[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1);
if (!softbuffers[i]) { if (!softbuffers[i]) {
@ -339,6 +396,7 @@ void base_init() {
} }
} }
void base_free() { void base_free() {
int i; int i;
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
@ -351,8 +409,12 @@ void base_free() {
srslte_pdcch_free(&pdcch); srslte_pdcch_free(&pdcch);
srslte_regs_free(&regs); srslte_regs_free(&regs);
srslte_pbch_free(&pbch); srslte_pbch_free(&pbch);
if(mbsfn_area_id > -1){
srslte_pmch_free(&pmch);
}
srslte_ofdm_tx_free(&ifft_mbsfn);
srslte_ofdm_tx_free(&ifft); srslte_ofdm_tx_free(&ifft);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (data[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_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_to_nbits(&dummy_grant, cfi, cell, 0, &dummy_nbits);
srslte_ra_dl_grant_fprint(stdout, &dummy_grant); 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) { if (pdsch_cfg.mimo_type != SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) {
printf("\nTransmission mode key table:\n"); printf("\nTransmission mode key table:\n");
printf(" Mode | 1TB | 2TB |\n"); printf(" Mode | 1TB | 2TB |\n");
@ -581,6 +643,7 @@ int update_control() {
} }
} }
/** Function run in a separate thread to receive UDP data */ /** Function run in a separate thread to receive UDP data */
void *net_thread_fnc(void *arg) { void *net_thread_fnc(void *arg) {
int n; int n;
@ -618,6 +681,7 @@ void *net_thread_fnc(void *arg) {
return NULL; return NULL;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int nf=0, sf_idx=0, N_id_2=0; int nf=0, sf_idx=0, N_id_2=0;
cf_t pss_signal[SRSLTE_PSS_LEN]; 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_msg_t dci_msg;
srslte_dci_location_t locations[SRSLTE_NSUBFRAMES_X_FRAME][30]; srslte_dci_location_t locations[SRSLTE_NSUBFRAMES_X_FRAME][30];
uint32_t sfn; uint32_t sfn;
srslte_chest_dl_t est; srslte_refsignal_t csr_refs;
srslte_refsignal_t mbsfn_refs;
#ifdef DISABLE_RF #ifdef DISABLE_RF
if (argc < 3) { if (argc < 3) {
@ -659,17 +724,31 @@ int main(int argc, char **argv) {
srslte_pss_generate(pss_signal, N_id_2); srslte_pss_generate(pss_signal, N_id_2);
srslte_sss_generate(sss_signal0, sss_signal5, cell.id); 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"); fprintf(stderr, "Error initializing equalizer\n");
exit(-1); 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++) { for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
sf_symbols[i] = sf_buffer[i%cell.nof_ports]; 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)]; slot1_symbols[i] = &sf_buffer[i%cell.nof_ports][SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)];
} }
#ifndef DISABLE_RF #ifndef DISABLE_RF
@ -718,48 +797,51 @@ int main(int argc, char **argv) {
/* Initiate valid DCI locations */ /* Initiate valid DCI locations */
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) { for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
srslte_pdcch_ue_locations(&pdcch, locations[i], 30, i, cfi, UE_CRNTI); srslte_pdcch_ue_locations(&pdcch, locations[i], 30, i, cfi, UE_CRNTI);
} }
nf = 0; nf = 0;
bool send_data = false; bool send_data = false;
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
srslte_softbuffer_tx_reset(softbuffers[i]); srslte_softbuffer_tx_reset(softbuffers[i]);
} }
#ifndef DISABLE_RF #ifndef DISABLE_RF
bool start_of_burst = true; bool start_of_burst = true;
#endif #endif
while ((nf < nof_frames || nof_frames == -1) && !go_exit) { while ((nf < nof_frames || nof_frames == -1) && !go_exit) {
for (sf_idx = 0; sf_idx < SRSLTE_NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) { for (sf_idx = 0; sf_idx < SRSLTE_NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) {
/* Set Antenna port resource elements to zero */ /* Set Antenna port resource elements to zero */
bzero(sf_symbols[0], sizeof(cf_t) * sf_n_re); bzero(sf_symbols[0], sizeof(cf_t) * sf_n_re);
/* Populate Synchronization signals if required */
if (sf_idx == 0 || sf_idx == 5) { if (sf_idx == 0 || sf_idx == 5) {
srslte_pss_put_slot(pss_signal, sf_symbols[0], cell.nof_prb, SRSLTE_CP_NORM); srslte_pss_put_slot(pss_signal, sf_symbols[0], cell.nof_prb, SRSLTE_CP_NORM);
srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb, srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb,
SRSLTE_CP_NORM); SRSLTE_CP_NORM);
} }
/* Copy zeros, SSS, PSS into the rest of antenna ports */ /* Copy zeros, SSS, PSS into the rest of antenna ports */
for (i = 1; i < cell.nof_ports; i++) { for (i = 1; i < cell.nof_ports; i++) {
memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re); memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re);
} }
/* Put reference signals */ if(sf_idx == 1 && mbsfn_area_id > -1){
for (i = 0; i < cell.nof_ports; i++) { srslte_refsignal_mbsfn_put_sf(cell, 0,csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]);
srslte_refsignal_cs_put_sf(cell, (uint32_t) i, est.csr_signal.pilots[i / 2][sf_idx], sf_symbols[i]); } 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); srslte_pbch_mib_pack(&cell, sfn, bch_payload);
if (sf_idx == 0) { if (sf_idx == 0) {
srslte_pbch_encode(&pbch, bch_payload, slot1_symbols, nf%4); 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 */ /* Update DL resource allocation from control port */
if (update_control(sf_idx)) { if (update_control(sf_idx)) {
@ -774,9 +856,11 @@ int main(int argc, char **argv) {
} }
} else { } else {
INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs); 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 (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
for (i = 0; i < pdsch_cfg.grant.mcs[tb].tbs / 8; i++) { if (pdsch_cfg.grant.tb_en[tb]) {
data[tb][i] = (uint8_t) rand(); 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 */ /* Uncomment this to transmit on sf 0 and 5 only */
@ -785,84 +869,134 @@ int main(int argc, char **argv) {
} else { } else {
send_data = false; send_data = false;
} }
} }
if (send_data) { if (send_data) {
srslte_dci_format_t dci_format; if(sf_idx != 1 || mbsfn_area_id < 0) { // PDCCH + PDSCH
switch(pdsch_cfg.mimo_type) { srslte_dci_format_t dci_format;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: switch(pdsch_cfg.mimo_type) {
dci_format = SRSLTE_DCI_FORMAT1; case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
break; dci_format = SRSLTE_DCI_FORMAT1;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY: break;
case SRSLTE_MIMO_TYPE_CDD: case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
dci_format = SRSLTE_DCI_FORMAT2A; case SRSLTE_MIMO_TYPE_CDD:
break; dci_format = SRSLTE_DCI_FORMAT2A;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: break;
dci_format = SRSLTE_DCI_FORMAT2; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
if (multiplex_nof_layers == 1) { dci_format = SRSLTE_DCI_FORMAT2;
ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1); if (multiplex_nof_layers == 1) {
} else { ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1);
ra_dl.pinfo = (uint8_t) multiplex_pmi; } 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; net_packet_ready = false;
default: sem_post(&net_sem);
fprintf(stderr, "Wrong MIMO configuration\n"); }
exit(SRSLTE_ERROR); }else{ // We're sending MCH on subframe 1 - PDCCH + PMCH
}
/* Encode PDCCH */ /* Encode PDCCH */
INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); 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); 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], UE_CRNTI, sf_symbols, sf_idx, cfi)) { 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"); fprintf(stderr, "Error encoding DCI message\n");
exit(-1); 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 */ if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, sf_idx)) {
srslte_ra_dl_grant_t grant; fprintf(stderr, "Error configuring PMCH\n");
srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant); exit(-1);
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"); /* Encode PMCH */
exit(-1); if (srslte_pmch_encode(&pmch, &pmch_cfg, softbuffers[0], data[0], mbsfn_area_id, sf_symbols)) {
} fprintf(stderr, "Error encoding PDSCH\n");
exit(-1);
/* Encode PDSCH */ }
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, sf_symbols)) { if (net_port > 0 && net_packet_ready) {
fprintf(stderr, "Error encoding PDSCH\n"); if (null_file_sink) {
exit(-1); 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) {
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) {
fprintf(stderr, "Error sending data through UDP socket\n"); 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 */ /* Transform to OFDM symbols */
for (i = 0; i < cell.nof_ports; i++) { if(sf_idx != 1 || mbsfn_area_id < 0){
srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]); 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 */ /* send to file or usrp */
if (output_file_name) { if (output_file_name) {
if (!null_file_sink) { 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); usleep(1000);
} else { } else {
#ifndef DISABLE_RF #ifndef DISABLE_RF
float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb); float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb);
for (i = 0; i < cell.nof_ports; i++) { for (i = 0; i < cell.nof_ports; i++) {
srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb)); srslte_vec_sc_prod_cfc(output_buffer[i], 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); srslte_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false);
start_of_burst=false; start_of_burst=false;
#endif #endif
} }
} }

@ -36,10 +36,8 @@
#include <signal.h> #include <signal.h>
#include <pthread.h> #include <pthread.h>
#include <semaphore.h> #include <semaphore.h>
#include <srslte/srslte.h> #include <srslte/phy/common/phy_common.h>
#include <srslte/phy/phch/pdsch_cfg.h> #include "srslte/phy/io/filesink.h"
#include <srslte/phy/phch/ra.h>
#include "srslte/srslte.h" #include "srslte/srslte.h"
#define ENABLE_AGC_DEFAULT #define ENABLE_AGC_DEFAULT
@ -69,7 +67,7 @@ sem_t plot_sem;
uint32_t plot_sf_idx=0; uint32_t plot_sf_idx=0;
bool plot_track = true; bool plot_track = true;
#endif #endif
char *output_file_name;
#define PRINT_CHANGE_SCHEDULIGN #define PRINT_CHANGE_SCHEDULIGN
//#define CORRECT_SAMPLE_OFFSET //#define CORRECT_SAMPLE_OFFSET
@ -101,6 +99,8 @@ typedef struct {
int net_port_signal; int net_port_signal;
char *net_address_signal; char *net_address_signal;
int decimate; int decimate;
int32_t mbsfn_area_id;
uint8_t non_mbsfn_region;
int verbose; int verbose;
}prog_args_t; }prog_args_t;
@ -132,10 +132,12 @@ void args_default(prog_args_t *args) {
args->net_address_signal = "127.0.0.1"; args->net_address_signal = "127.0.0.1";
args->decimate = 0; args->decimate = 0;
args->cpu_affinity = -1; args->cpu_affinity = -1;
args->mbsfn_area_id = -1;
args->non_mbsfn_region = 2;
} }
void usage(prog_args_t *args, char *prog) { 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 #ifndef DISABLE_RF
printf("\t-a RF args [Default %s]\n", args->rf_args); 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); 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-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 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-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"); printf("\t-v [set srslte_verbose to debug, default none]\n");
} }
void parse_args(prog_args_t *args, int argc, char **argv) { void parse_args(prog_args_t *args, int argc, char **argv) {
int opt; int opt;
args_default(args); args_default(args);
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZy")) != -1) { while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZyWMN")) != -1) {
switch (opt) { switch (opt) {
case 'i': case 'i':
args->input_file_name = argv[optind]; args->input_file_name = argv[optind];
@ -250,6 +254,15 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
case 'y': case 'y':
args->cpu_affinity = atoi(argv[optind]); args->cpu_affinity = atoi(argv[optind]);
break; 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: default:
usage(args, argv[0]); usage(args, argv[0]);
exit(-1); exit(-1);
@ -278,6 +291,7 @@ void sig_int_handler(int signo)
cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}; cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL};
#ifndef DISABLE_RF #ifndef DISABLE_RF
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { 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); DEBUG(" ---- Receive %d samples ---- \n", nsamples);
@ -303,9 +317,9 @@ srslte_ue_sync_t ue_sync;
prog_args_t prog_args; prog_args_t prog_args;
uint32_t sfn = 0; // system frame number 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 */ /* 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_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(_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 #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; srslte_cell_t cell;
int64_t sf_cnt; int64_t sf_cnt;
srslte_ue_mib_t ue_mib; srslte_ue_mib_t ue_mib;
#ifndef DISABLE_RF #ifndef DISABLE_RF
srslte_rf_t rf; srslte_rf_t rf;
#endif #endif
@ -324,7 +339,7 @@ int main(int argc, char **argv) {
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
int sfn_offset; int sfn_offset;
float cfo = 0; float cfo = 0;
parse_args(&prog_args, argc, argv); parse_args(&prog_args, argc, argv);
for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) { 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) { if(prog_args.cpu_affinity > -1) {
cpu_set_t cpuset; 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_set_rx_freq(&rf, prog_args.rf_freq + prog_args.file_offset_freq);
srslte_rf_rx_wait_lo_locked(&rf); srslte_rf_rx_wait_lo_locked(&rf);
uint32_t ntrial=0; uint32_t ntrial=0;
do { 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); 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_ports = prog_args.file_nof_ports;
cell.nof_prb = prog_args.file_nof_prb; 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)) { 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"); fprintf(stderr, "Error initiating ue_sync\n");
exit(-1); exit(-1);
@ -475,23 +492,42 @@ int main(int argc, char **argv) {
//ue_sync.decimate = prog_args.decimate; //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"); fprintf(stderr, "Error initiating ue_sync\n");
exit(-1); exit(-1);
} }
if (srslte_ue_sync_set_cell(&ue_sync, cell))
{
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);
}
#endif #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"); fprintf(stderr, "Error initaiting UE MIB decoder\n");
exit(-1); 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"); fprintf(stderr, "Error initiating UE downlink processing module\n");
exit(-1); 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<prog_args.rf_nof_rx_ant;i++) { for (int i=0;i<prog_args.rf_nof_rx_ant;i++) {
sf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); sf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb));
} }
@ -499,6 +535,11 @@ int main(int argc, char **argv) {
/* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */
srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti); srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti);
/* Configure MBSFN area id and non-MBSFN Region */
if (prog_args.mbsfn_area_id > -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 */ /* Initialize subframe counter */
sf_cnt = 0; sf_cnt = 0;
@ -518,7 +559,7 @@ int main(int argc, char **argv) {
// Variables for measurements // Variables for measurements
uint32_t nframes=0; 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, 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; sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS], cn = 0.0;
bool decode_pdsch = false; 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 a new line is detected set verbose level to Debug */
if (fgets(input, sizeof(input), stdin)) { if (fgets(input, sizeof(input), stdin)) {
srslte_verbose = SRSLTE_VERBOSE_DEBUG; 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); ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); 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 */ /* srslte_ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */
if (ret == 1) { if (ret == 1) {
uint32_t sfidx = srslte_ue_sync_get_sfidx(&ue_sync);
switch (state) { switch (state) {
case DECODE_MIB: 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); n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset);
if (n < 0) { if (n < 0) {
fprintf(stderr, "Error decoding UE MIB\n"); fprintf(stderr, "Error decoding UE MIB\n");
@ -603,50 +650,64 @@ int main(int argc, char **argv) {
decode_pdsch = true; decode_pdsch = true;
} else { } else {
/* We are looking for SIB1 Blocks, search only in appropiate places */ /* 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; decode_pdsch = true;
} else { } else {
decode_pdsch = false; decode_pdsch = false;
} }
} }
INFO("Attempting DL decode SFN=%d\n", sfn);
if (decode_pdsch) { if (decode_pdsch) {
if (cell.nof_ports == 1) { if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe
/* Transmission mode 1 */ if (cell.nof_ports == 1) {
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); /* Transmission mode 1 */
} else { n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
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 { } else {
/* Transmission mode 3 */ if (prog_args.rf_nof_rx_ant == 1) {
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), /* Transmission mode 2 */
acks); n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
if (n < 1) { acks);
/* Transmission mode 4 */ } else {
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), /* Transmission mode 3 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
acks); 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) { if (n < 0) {
// fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
} else if (n > 0) { } else if (n > 0) {
/* Send data if socket active */ /* Send data if socket active */
if (prog_args.net_port > 0) { 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 // FIXME: UDP Data transmission does not work
for (uint32_t tb = 0; tb < ue_dl.pdsch_cfg.grant.nof_tb; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8); 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 #ifdef PRINT_CHANGE_SCHEDULIGN
if (ue_dl.dl_dci.mcs_idx != old_dl_dci.mcs_idx || 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)) || 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++; nof_trials++;
rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f); 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); 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); 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); 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); 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++; nframes++;
if (isnan(rsrq)) { if (isnan(rsrq)) {
rsrq = 0; rsrq = 0;
@ -680,20 +743,20 @@ int main(int argc, char **argv) {
noise = 0; noise = 0;
} }
if (isnan(rsrp0)) { if (isnan(rsrp0)) {
rsrp1 = 0; rsrp0 = 0;
} }
if (isnan(rsrp0)) { if (isnan(rsrp1)) {
rsrp1 = 0; rsrp1 = 0;
} }
} }
// Plot and Printf // Plot and Printf
if (srslte_ue_sync_get_sfidx(&ue_sync) == 5 && sfn % 20 == 0) { if (sfidx == 5) {
float gain = prog_args.rf_gain; float gain = prog_args.rf_gain;
if (gain < 0) { if (gain < 0) {
gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc)); gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc));
} }
/* Print transmission scheme */ /* Print transmission scheme */
if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { 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), 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 basic Parameters */
PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers); 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(" 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(" 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(" 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(" 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, PRINT_LINE(" TB 0: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[0].idx,
ue_dl.pdsch_cfg.grant.mcs[0].tbs); ue_dl.pdsch_cfg.grant.mcs[0].tbs);
PRINT_LINE(" TB 1: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[1].idx, 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("Press enter maximum printing debug log of 1 subframe.");
PRINT_LINE(""); PRINT_LINE("");
PRINT_LINE_RESET_CURSOR(); PRINT_LINE_RESET_CURSOR();
} }
break; break;
} }
if (srslte_ue_sync_get_sfidx(&ue_sync) == 9) { if (sfidx == 9) {
sfn++; sfn++;
if (sfn == 1024) { if (sfn == 1024) {
sfn = 0; sfn = 0;
PRINT_LINE_ADVANCE_CURSOR(); PRINT_LINE_ADVANCE_CURSOR();
ue_dl.pdsch_pkt_errors = 0;
ue_dl.pdsch_pkts_total = 0;
/*
ue_dl.pkt_errors = 0; ue_dl.pkt_errors = 0;
ue_dl.pkts_total = 0; ue_dl.pkts_total = 0;
ue_dl.nof_detected = 0; ue_dl.nof_detected = 0;
nof_trials = 0; nof_trials = 0;
*/
} }
} }
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) { 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_sf_idx = srslte_ue_sync_get_sfidx(&ue_sync);
plot_track = true; plot_track = true;
sem_post(&plot_sem); sem_post(&plot_sem);
@ -790,8 +861,7 @@ int main(int argc, char **argv) {
sf_cnt++; sf_cnt++;
} // Main loop } // Main loop
printf("\033[30B\n");
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) { if (!prog_args.disable_plots) {
if (!pthread_kill(plot_thread, 0)) { if (!pthread_kill(plot_thread, 0)) {
@ -812,13 +882,14 @@ int main(int argc, char **argv) {
free(sf_buffer[i]); free(sf_buffer[i]);
} }
} }
#ifndef DISABLE_RF #ifndef DISABLE_RF
if (!prog_args.input_file_name) { if (!prog_args.input_file_name) {
srslte_ue_mib_free(&ue_mib); srslte_ue_mib_free(&ue_mib);
srslte_rf_close(&rf); srslte_rf_close(&rf);
} }
#endif #endif
printf("\nBye\n"); printf("\nBye\n");
exit(0); exit(0);
} }

@ -165,11 +165,15 @@ int main(int argc, char **argv) {
cell.nof_prb = nof_prb; cell.nof_prb = nof_prb;
cell.nof_ports = 1; 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"); fprintf(stderr, "Error initiating ue_sync\n");
exit(-1); 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; uint32_t subframe_count = 0;
bool start_capture = false; bool start_capture = false;
bool stop_capture = false; bool stop_capture = false;

@ -30,6 +30,7 @@
#include <ctype.h> #include <ctype.h>
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include <srslte/asn1/liblte_rrc.h>
namespace srslte { namespace srslte {
@ -112,6 +113,12 @@ inline bool mnc_to_string(uint16_t mnc, std::string *str)
*str += (mnc & 0x000F) + '0'; *str += (mnc & 0x000F) + '0';
return true; 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 } // namespace srslte

@ -93,7 +93,7 @@ public:
available.pop(); available.pop();
if (available.size() < capacity/20) { 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 #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
if (debug_name) { if (debug_name) {

@ -50,7 +50,7 @@
#define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756 #define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756
#define SRSLTE_BUFFER_HEADER_OFFSET 1024 #define SRSLTE_BUFFER_HEADER_OFFSET 1024
#define SRSLTE_BUFFER_POOL_LOG_ENABLED //#define SRSLTE_BUFFER_POOL_LOG_ENABLED
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
#define pool_allocate (pool->allocate(__FUNCTION__)) #define pool_allocate (pool->allocate(__FUNCTION__))

@ -71,8 +71,9 @@ public:
/* Timer services with ms resolution. /* Timer services with ms resolution.
* timer_id must be lower than MAC_NOF_UPPER_TIMERS * timer_id must be lower than MAC_NOF_UPPER_TIMERS
*/ */
virtual timers::timer* get(uint32_t timer_id) = 0; virtual timers::timer* timer_get(uint32_t timer_id) = 0;
virtual uint32_t get_unique_id() = 0; virtual void timer_release_id(uint32_t timer_id) = 0;
virtual uint32_t timer_get_unique_id() = 0;
}; };
class read_pdu_interface class read_pdu_interface

@ -24,20 +24,26 @@ template<typename metrics_t>
class metrics_listener class metrics_listener
{ {
public: public:
virtual void set_metrics(metrics_t &m) = 0; virtual void set_metrics(metrics_t &m, float report_period_secs=1.0) = 0;
}; };
template<typename metrics_t> template<typename metrics_t>
class metrics_hub : public periodic_thread class metrics_hub : public periodic_thread
{ {
public: public:
bool init(metrics_interface<metrics_t> *m_, float report_period_secs=1.0) { metrics_hub()
m = m_; :m(NULL)
,report_period_secs(1)
{}
bool init(metrics_interface<metrics_t> *m_, float report_period_secs_=1.0) {
m = m_;
report_period_secs = report_period_secs_;
start_periodic(report_period_secs*1e6); start_periodic(report_period_secs*1e6);
return true; return true;
} }
void stop() { void stop() {
thread_cancel(); thread_cancel();
wait_thread_finish();
} }
void add_listener(metrics_listener<metrics_t> *listener) { void add_listener(metrics_listener<metrics_t> *listener) {
@ -46,15 +52,18 @@ public:
private: private:
void run_period() { void run_period() {
metrics_t metric; if (m) {
m->get_metrics(metric); metrics_t metric;
for (uint32_t i=0;i<listeners.size();i++) { bzero(&metric, sizeof(metrics_t));
listeners[i]->set_metrics(metric); m->get_metrics(metric);
for (uint32_t i=0;i<listeners.size();i++) {
listeners[i]->set_metrics(metric, report_period_secs);
}
} }
} }
metrics_interface<metrics_t> *m; metrics_interface<metrics_t> *m;
std::vector<metrics_listener<metrics_t>*> listeners; std::vector<metrics_listener<metrics_t>*> listeners;
float report_period_secs;
}; };
} // namespace srslte } // namespace srslte

@ -74,7 +74,7 @@ public:
} }
void step() { void step() {
if (running) { if (running) {
counter++; counter++;
if (is_expired()) { if (is_expired()) {
running = false; running = false;
if (callback) { if (callback) {
@ -145,7 +145,7 @@ public:
} }
uint32_t get_unique_id() { uint32_t get_unique_id() {
if (nof_used_timers >= nof_timers) { 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; return 0;
} else { } else {
while(used_timers[next_timer]) { while(used_timers[next_timer]) {

@ -244,7 +244,7 @@ public:
class gtpu_interface_rrc class gtpu_interface_rrc
{ {
public: 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_bearer(uint16_t rnti, uint32_t lcid) = 0;
virtual void rem_user(uint16_t rnti) = 0; virtual void rem_user(uint16_t rnti) = 0;
}; };

@ -32,7 +32,7 @@
#include "upper/common_enb.h" #include "upper/common_enb.h"
#include "upper/s1ap_metrics.h" #include "upper/s1ap_metrics.h"
#include "upper/rrc_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 "srslte/upper/rlc_metrics.h"
#include "mac/mac_metrics.h" #include "mac/mac_metrics.h"
#include "phy/phy_metrics.h" #include "phy/phy_metrics.h"

@ -54,6 +54,7 @@ class usim_interface_nas
public: public:
virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; 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 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, virtual void generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
@ -98,10 +99,28 @@ class nas_interface_rrc
{ {
public: public:
virtual bool is_attached() = 0; virtual bool is_attached() = 0;
virtual bool is_attaching() = 0;
virtual void notify_connection_setup() = 0; virtual void notify_connection_setup() = 0;
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
virtual uint32_t get_ul_count() = 0; virtual uint32_t get_ul_count() = 0;
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 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 // RRC interface for MAC
@ -123,6 +142,8 @@ class rrc_interface_phy
public: public:
virtual void in_sync() = 0; virtual void in_sync() = 0;
virtual void out_of_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 // RRC interface for NAS
@ -133,18 +154,11 @@ public:
virtual uint16_t get_mcc() = 0; virtual uint16_t get_mcc() = 0;
virtual uint16_t get_mnc() = 0; virtual uint16_t get_mnc() = 0;
virtual void enable_capabilities() = 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; 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 // RRC interface for PDCP
class rrc_interface_pdcp class rrc_interface_pdcp
{ {
@ -169,6 +183,7 @@ class pdcp_interface_gw
{ {
public: public:
virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; 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 // PDCP interface for RRC
@ -281,6 +296,8 @@ public:
bool last_ndi[SRSLTE_MAX_CODEWORDS]; bool last_ndi[SRSLTE_MAX_CODEWORDS];
uint32_t n_bytes[SRSLTE_MAX_CODEWORDS]; uint32_t n_bytes[SRSLTE_MAX_CODEWORDS];
int rv[SRSLTE_MAX_CODEWORDS]; int rv[SRSLTE_MAX_CODEWORDS];
bool tb_en[SRSLTE_MAX_CODEWORDS];
bool tb_cw_swap;
uint16_t rnti; uint16_t rnti;
bool is_from_rar; bool is_from_rar;
bool is_sps_release; bool is_sps_release;
@ -290,11 +307,11 @@ public:
} mac_grant_t; } mac_grant_t;
typedef struct { typedef struct {
bool decode_enabled; bool decode_enabled[SRSLTE_MAX_TB];
int rv[SRSLTE_MAX_TB]; int rv[SRSLTE_MAX_TB];
uint16_t rnti; uint16_t rnti;
bool generate_ack; 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 // If non-null, called after tb_decoded_ok to determine if ack needs to be sent
bool (*generate_ack_callback)(void*); bool (*generate_ack_callback)(void*);
void *generate_ack_callback_arg; void *generate_ack_callback_arg;
@ -421,8 +438,8 @@ typedef struct {
int worker_cpu_mask; int worker_cpu_mask;
int sync_cpu_affinity; int sync_cpu_affinity;
uint32_t nof_rx_ant; uint32_t nof_rx_ant;
std::string equalizer_mode; std::string equalizer_mode;
int cqi_max; int cqi_max;
int cqi_fixed; int cqi_fixed;
float snr_ema_coeff; float snr_ema_coeff;
@ -442,9 +459,8 @@ class phy_interface_mac_common
{ {
public: public:
/* Start synchronization with strongest cell in the current carrier frequency */ /* Start synchronization with strongest cell in the current carrier frequency */
virtual void sync_start() = 0; virtual bool sync_status() = 0;
virtual void sync_stop() = 0;
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
virtual void set_crnti(uint16_t rnti) = 0; 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_common(phy_cfg_common_t *common) = 0;
virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0; virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0;
virtual void set_config_64qam_en(bool enable) = 0; virtual void set_config_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? */ /* 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() */ /* Configure UL using parameters written with set_param() */
virtual void configure_ul_params(bool pregen_disabled = false) = 0; virtual void configure_ul_params(bool pregen_disabled = false) = 0;
virtual void reset() = 0; virtual void reset() = 0;
virtual void resync_sfn() = 0;
}; };

@ -60,7 +60,10 @@ typedef enum {
typedef struct { typedef struct {
srslte_cell_t cell; 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;
cf_t *pilot_estimates_average; cf_t *pilot_estimates_average;
cf_t *pilot_recv_signal; cf_t *pilot_recv_signal;
@ -75,7 +78,7 @@ typedef struct {
srslte_interp_linsrslte_vec_t srslte_interp_linvec; srslte_interp_linsrslte_vec_t srslte_interp_linvec;
srslte_interp_lin_t srslte_interp_lin; srslte_interp_lin_t srslte_interp_lin;
srslte_interp_lin_t srslte_interp_lin_mbsfn;
float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float noise_estimate[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_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, SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q,
float *filter, 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_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q,
srslte_chest_dl_noise_alg_t noise_estimation_alg); srslte_chest_dl_noise_alg_t noise_estimation_alg);
SRSLTE_API int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, SRSLTE_API int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS], cf_t *input[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][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], cf_t *ce[SRSLTE_MAX_PORTS],
uint32_t sf_idx); 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, SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q,
cf_t *input, cf_t *input,
cf_t *ce, cf_t *ce,

@ -77,9 +77,13 @@ typedef struct {
SRSLTE_API int srslte_chest_ul_init(srslte_chest_ul_t *q, 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_API void srslte_chest_ul_set_cfg(srslte_chest_ul_t *q,
srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg,

@ -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 // 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(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(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(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 */ /** Cell-Specific Reference Signal */
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_cell_t cell; 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 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; 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_API int srslte_refsignal_cs_init(srslte_refsignal_t *q,
srslte_cell_t cell); 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, SRSLTE_API int srslte_refsignal_cs_put_sf(srslte_cell_t cell,
uint32_t port_id, 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 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 #endif

@ -94,7 +94,10 @@ typedef struct {
} srslte_refsignal_srs_pregen_t; } srslte_refsignal_srs_pregen_t;
SRSLTE_API int srslte_refsignal_ul_init(srslte_refsignal_ul_t *q, 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); 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_API bool srslte_refsignal_dmrs_pusch_cfg_isvalid(srslte_refsignal_ul_t *q,
srslte_refsignal_dmrs_pusch_cfg_t *cfg, 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_refsignal_ul_dmrs_pregen_t *pregen);
SRSLTE_API void srslte_refsignal_dmrs_pusch_pregen_free(srslte_refsignal_ul_t *q, SRSLTE_API void srslte_refsignal_dmrs_pusch_pregen_free(srslte_refsignal_ul_t *q,

@ -63,7 +63,11 @@
#define SRSLTE_LTE_CRC16 0x11021 #define SRSLTE_LTE_CRC16 0x11021
#define SRSLTE_LTE_CRC8 0x19B #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_CP_NORM, SRSLTE_CP_EXT} srslte_cp_t;
typedef enum {SRSLTE_SF_NORM, SRSLTE_SF_MBSFN} srslte_sf_t;
#define SRSLTE_CRNTI_START 0x000B #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) || 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_NOF_LTE_BANDS 38
#define SRSLTE_DEFAULT_MAX_FRAMES_PBCH 500 #define SRSLTE_DEFAULT_MAX_FRAMES_PBCH 500
@ -157,6 +168,7 @@ typedef enum {
SRSLTE_RNTI_TEMP, /* Temporary C-RNTI */ SRSLTE_RNTI_TEMP, /* Temporary C-RNTI */
SRSLTE_RNTI_SPS, /* Semi-Persistent Scheduling C-RNTI */ SRSLTE_RNTI_SPS, /* Semi-Persistent Scheduling C-RNTI */
SRSLTE_RNTI_PCH, /* Paging RNTI */ SRSLTE_RNTI_PCH, /* Paging RNTI */
SRSLTE_RNTI_MBSFN,
SRSLTE_RNTI_NOF_TYPES SRSLTE_RNTI_NOF_TYPES
} srslte_rnti_type_t; } srslte_rnti_type_t;

@ -44,7 +44,8 @@ typedef struct SRSLTE_API {
uint8_t *c_bytes; uint8_t *c_bytes;
float *c_float; float *c_float;
short *c_short; short *c_short;
uint32_t len; uint32_t cur_len;
uint32_t max_len;
} srslte_sequence_t; } srslte_sequence_t;
SRSLTE_API int srslte_sequence_init(srslte_sequence_t *q, uint32_t len); 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 len,
uint32_t seed); uint32_t seed);
SRSLTE_API void srslte_sequence_set_LTE_pr(srslte_sequence_t *q, SRSLTE_API int srslte_sequence_set_LTE_pr(srslte_sequence_t *q,
uint32_t seed); uint32_t len,
uint32_t seed);
SRSLTE_API int srslte_sequence_pbch(srslte_sequence_t *seq, SRSLTE_API int srslte_sequence_pbch(srslte_sequence_t *seq,
srslte_cp_t cp, srslte_cp_t cp,
@ -92,4 +94,10 @@ SRSLTE_API int srslte_sequence_pucch(srslte_sequence_t *seq,
uint16_t rnti, uint16_t rnti,
uint32_t nslot, uint32_t nslot,
uint32_t cell_id); 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 #endif

@ -58,6 +58,7 @@ typedef enum {
}srslte_dft_dir_t; }srslte_dft_dir_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
int init_size; // DFT length used in the first initialization
int size; // DFT length int size; // DFT length
void *in; // Input buffer void *in; // Input buffer
void *out; // Output 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_dir_t dir,
srslte_dft_mode_t type); 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, int dft_points,
srslte_dft_dir_t dir); srslte_dft_dir_t dir);
@ -88,6 +89,16 @@ SRSLTE_API int srslte_dft_plan_r(srslte_dft_plan_t *plan,
int dft_points, int dft_points,
srslte_dft_dir_t dir); 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); SRSLTE_API void srslte_dft_plan_free(srslte_dft_plan_t *plan);
/* Set options */ /* Set options */

@ -45,12 +45,18 @@ typedef struct SRSLTE_API {
uint32_t max_prb; uint32_t max_prb;
srslte_dft_plan_t dft_plan[SRSLTE_MAX_PRB+1]; 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_dft_precoding_t;
SRSLTE_API int srslte_dft_precoding_init(srslte_dft_precoding_t *q, SRSLTE_API int srslte_dft_precoding_init(srslte_dft_precoding_t *q,
uint32_t max_prb); 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); 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_prb,
uint32_t nof_symbols); 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 #endif

@ -47,6 +47,7 @@
/* This is common for both directions */ /* This is common for both directions */
typedef struct SRSLTE_API{ typedef struct SRSLTE_API{
srslte_dft_plan_t fft_plan; srslte_dft_plan_t fft_plan;
uint32_t max_prb;
uint32_t nof_symbols; uint32_t nof_symbols;
uint32_t symbol_sz; uint32_t symbol_sz;
uint32_t nof_guards; uint32_t nof_guards;
@ -55,7 +56,14 @@ typedef struct SRSLTE_API{
srslte_cp_t cp; srslte_cp_t cp;
cf_t *tmp; // for removing zero padding 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; bool freq_shift;
float freq_shift_f;
cf_t *shift_buffer; cf_t *shift_buffer;
}srslte_ofdm_t; }srslte_ofdm_t;
@ -63,11 +71,32 @@ SRSLTE_API int srslte_ofdm_init_(srslte_ofdm_t *q,
srslte_cp_t cp, srslte_cp_t cp,
int symbol_sz, int symbol_sz,
int nof_prb, 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_API int srslte_ofdm_rx_init(srslte_ofdm_t *q,
srslte_cp_t cp_type, 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); 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, srslte_cp_t cp_type,
uint32_t nof_prb); 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_free(srslte_ofdm_t *q);
SRSLTE_API void srslte_ofdm_tx_slot(srslte_ofdm_t *q, SRSLTE_API void srslte_ofdm_tx_slot(srslte_ofdm_t *q,
cf_t *input, cf_t *input,
cf_t *output); 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, SRSLTE_API void srslte_ofdm_tx_sf(srslte_ofdm_t *q,
cf_t *input, cf_t *input,
cf_t *output); 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, SRSLTE_API void srslte_ofdm_set_normalize(srslte_ofdm_t *q,
bool normalize_enable); bool normalize_enable);
#endif SRSLTE_API void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t *q,
uint8_t non_mbsfn_region);
#endif

@ -76,7 +76,7 @@ typedef struct SRSLTE_API {
srslte_pdsch_t pdsch; srslte_pdsch_t pdsch;
srslte_phich_t phich; srslte_phich_t phich;
srslte_refsignal_cs_t csr_signal; srslte_refsignal_t csr_signal;
srslte_pdsch_cfg_t pdsch_cfg; srslte_pdsch_cfg_t pdsch_cfg;
srslte_ra_dl_dci_t dl_dci; srslte_ra_dl_dci_t dl_dci;
@ -88,6 +88,8 @@ typedef struct SRSLTE_API {
float sss_signal5[SRSLTE_SSS_LEN]; float sss_signal5[SRSLTE_SSS_LEN];
float tx_amp; float tx_amp;
uint8_t tmp[1024*128];
} srslte_enb_dl_t; } srslte_enb_dl_t;
@ -108,11 +110,14 @@ typedef struct {
/* This function shall be called just after the initial synchronization */ /* This function shall be called just after the initial synchronization */
SRSLTE_API int srslte_enb_dl_init(srslte_enb_dl_t *q, 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_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); uint32_t cfi);
SRSLTE_API void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, 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_ra_dl_grant_t *grant,
srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS], srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS],
uint16_t rnti, uint16_t rnti,
uint32_t rv_idx, int rv_idx[SRSLTE_MAX_CODEWORDS],
uint32_t sf_idx, 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_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q,
srslte_ra_dl_dci_t *grant, srslte_ra_dl_dci_t *grant,
srslte_dci_format_t format, srslte_dci_format_t format,
srslte_dci_location_t location, srslte_dci_location_t location,
uint16_t rnti, 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_API int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q,
srslte_ra_ul_dci_t *grant, 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, uint16_t rnti,
uint32_t sf_idx); 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 #endif

@ -100,15 +100,18 @@ typedef struct {
} srslte_enb_ul_pusch_t; } srslte_enb_ul_pusch_t;
/* This function shall be called just after the initial synchronization */ /* This function shall be called just after the initial synchronization */
SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t *q, SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t *q,
srslte_cell_t cell, uint32_t max_prb);
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 void srslte_enb_ul_free(srslte_enb_ul_t *q); 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, SRSLTE_API int srslte_enb_ul_add_rnti(srslte_enb_ul_t *q,
uint16_t rnti); uint16_t rnti);

@ -50,20 +50,14 @@
#define SRSLTE_TCOD_MAX_LEN_CODED (SRSLTE_TCOD_RATE*SRSLTE_TCOD_MAX_LEN_CB+SRSLTE_TCOD_TOTALTAIL) #define SRSLTE_TCOD_MAX_LEN_CODED (SRSLTE_TCOD_RATE*SRSLTE_TCOD_MAX_LEN_CB+SRSLTE_TCOD_TOTALTAIL)
#include "srslte/phy/fec/turbodecoder_gen.h" #include "srslte/phy/fec/turbodecoder_gen.h"
#ifdef LV_HAVE_SSE
#include "srslte/phy/fec/turbodecoder_simd.h" #include "srslte/phy/fec/turbodecoder_simd.h"
#else
#define SRSLTE_TDEC_NPAR 1
#endif
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
#ifdef LV_HAVE_SSE float *input_conv;
srslte_tdec_simd_t tdec_simd; union {
#else srslte_tdec_simd_t tdec_simd;
float *input_conv; srslte_tdec_gen_t tdec_gen;
srslte_tdec_gen_t tdec_gen; };
#endif
} srslte_tdec_t; } srslte_tdec_t;
SRSLTE_API int srslte_tdec_init(srslte_tdec_t * h, 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, SRSLTE_API int srslte_tdec_get_nof_iterations_cb(srslte_tdec_t * h,
uint32_t cb_idx); 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, SRSLTE_API void srslte_tdec_iteration(srslte_tdec_t * h,
int16_t* input, int16_t* input,
@ -101,15 +95,15 @@ SRSLTE_API int srslte_tdec_run_all(srslte_tdec_t * h,
uint32_t long_cb); uint32_t long_cb);
SRSLTE_API void srslte_tdec_iteration_par(srslte_tdec_t * h, 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); uint32_t long_cb);
SRSLTE_API void srslte_tdec_decision_par(srslte_tdec_t * h, 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); uint32_t long_cb);
SRSLTE_API void srslte_tdec_decision_byte_par(srslte_tdec_t * h, 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); uint32_t long_cb);
SRSLTE_API void srslte_tdec_decision_byte_par_cb(srslte_tdec_t * h, 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); uint32_t long_cb);
SRSLTE_API int srslte_tdec_run_all_par(srslte_tdec_t * h, SRSLTE_API int srslte_tdec_run_all_par(srslte_tdec_t * h,
int16_t * input[SRSLTE_TDEC_NPAR], int16_t * input[SRSLTE_TDEC_MAX_NPAR],
uint8_t *output[SRSLTE_TDEC_NPAR], uint8_t *output[SRSLTE_TDEC_MAX_NPAR],
uint32_t nof_iterations, uint32_t nof_iterations,
uint32_t long_cb); uint32_t long_cb);

@ -43,23 +43,8 @@
#include "srslte/phy/fec/tc_interl.h" #include "srslte/phy/fec/tc_interl.h"
#include "srslte/phy/fec/cbsegm.h" #include "srslte/phy/fec/cbsegm.h"
//#define ENABLE_SIMD_INTER // Define maximum number of CB decoded in parallel (2 for AVX2)
#define SRSLTE_TDEC_MAX_NPAR 2
// 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 SRSLTE_TCOD_RATE 3 #define SRSLTE_TCOD_RATE 3
#define SRSLTE_TCOD_TOTALTAIL 12 #define SRSLTE_TCOD_TOTALTAIL 12
@ -80,18 +65,18 @@ typedef struct SRSLTE_API {
map_gen_t dec; map_gen_t dec;
int16_t *app1[SRSLTE_TDEC_NPAR]; int16_t *app1[SRSLTE_TDEC_MAX_NPAR];
int16_t *app2[SRSLTE_TDEC_NPAR]; int16_t *app2[SRSLTE_TDEC_MAX_NPAR];
int16_t *ext1[SRSLTE_TDEC_NPAR]; int16_t *ext1[SRSLTE_TDEC_MAX_NPAR];
int16_t *ext2[SRSLTE_TDEC_NPAR]; int16_t *ext2[SRSLTE_TDEC_MAX_NPAR];
int16_t *syst[SRSLTE_TDEC_NPAR]; int16_t *syst[SRSLTE_TDEC_MAX_NPAR];
int16_t *parity0[SRSLTE_TDEC_NPAR]; int16_t *parity0[SRSLTE_TDEC_MAX_NPAR];
int16_t *parity1[SRSLTE_TDEC_NPAR]; int16_t *parity1[SRSLTE_TDEC_MAX_NPAR];
int cb_mask; int cb_mask;
int current_cbidx; int current_cbidx;
srslte_tc_interl_t interleaver[SRSLTE_NOF_TC_CB_SIZES]; 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_tdec_simd_t;
SRSLTE_API int srslte_tdec_simd_init(srslte_tdec_simd_t * h, 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, SRSLTE_API int srslte_tdec_simd_reset(srslte_tdec_simd_t * h,
uint32_t long_cb); uint32_t long_cb);
SRSLTE_API
SRSLTE_API int srslte_tdec_simd_get_nof_iterations_cb(srslte_tdec_simd_t * h, SRSLTE_API int srslte_tdec_simd_get_nof_iterations_cb(srslte_tdec_simd_t * h,
uint32_t cb_idx); 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); uint32_t cb_idx);
SRSLTE_API void srslte_tdec_simd_iteration(srslte_tdec_simd_t * h, 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); uint32_t long_cb);
SRSLTE_API void srslte_tdec_simd_decision(srslte_tdec_simd_t * h, 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); uint32_t long_cb);
SRSLTE_API void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, 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); uint32_t long_cb);
SRSLTE_API void srslte_tdec_simd_decision_byte_cb(srslte_tdec_simd_t * h, 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); uint32_t long_cb);
SRSLTE_API int srslte_tdec_simd_run_all(srslte_tdec_simd_t * h, SRSLTE_API int srslte_tdec_simd_run_all(srslte_tdec_simd_t * h,
int16_t * input[SRSLTE_TDEC_NPAR], int16_t * input[SRSLTE_TDEC_MAX_NPAR],
uint8_t *output[SRSLTE_TDEC_NPAR], uint8_t *output[SRSLTE_TDEC_MAX_NPAR],
uint32_t nof_iterations, uint32_t nof_iterations,
uint32_t long_cb); uint32_t long_cb);

@ -49,9 +49,9 @@
#include "srslte/phy/fec/cbsegm.h" #include "srslte/phy/fec/cbsegm.h"
#if LV_HAVE_AVX2 #if LV_HAVE_AVX2
#define SRSLTE_TDEC_NPAR 16 #define SRSLTE_TDEC_MAX_NPAR 16
#else #else
#define SRSLTE_TDEC_NPAR 8 #define SRSLTE_TDEC_MAX_NPAR 8
#endif #endif
@ -71,7 +71,7 @@ typedef struct SRSLTE_API {
int current_cbidx; int current_cbidx;
uint32_t current_long_cb; uint32_t current_long_cb;
srslte_tc_interl_t interleaver[SRSLTE_NOF_TC_CB_SIZES]; 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_tdec_simd_inter_t;
SRSLTE_API int srslte_tdec_simd_inter_init(srslte_tdec_simd_inter_t * h, 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); uint32_t cb_idx);
SRSLTE_API void srslte_tdec_simd_inter_iteration(srslte_tdec_simd_inter_t * h, 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 nof_cb,
uint32_t long_cb); uint32_t long_cb);
SRSLTE_API void srslte_tdec_simd_inter_decision(srslte_tdec_simd_inter_t * h, 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 nof_cb,
uint32_t long_cb); uint32_t long_cb);
SRSLTE_API void srslte_tdec_simd_inter_decision_byte(srslte_tdec_simd_inter_t * h, 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 nof_cb,
uint32_t long_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); uint32_t long_cb);
SRSLTE_API int srslte_tdec_simd_inter_run_all(srslte_tdec_simd_inter_t * h, SRSLTE_API int srslte_tdec_simd_inter_run_all(srslte_tdec_simd_inter_t * h,
int16_t *input[SRSLTE_TDEC_NPAR], int16_t *input[SRSLTE_TDEC_MAX_NPAR],
uint8_t *output[SRSLTE_TDEC_NPAR], uint8_t *output[SRSLTE_TDEC_MAX_NPAR],
uint32_t nof_iterations, uint32_t nof_iterations,
uint32_t nof_cb, uint32_t nof_cb,
uint32_t long_cb); uint32_t long_cb);

@ -41,11 +41,14 @@
#include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/phy_common.h"
#define SRSLTE_CQI_MAX_BITS 64 #define SRSLTE_CQI_MAX_BITS 64
#define SRSLTE_DIF_CQI_MAX_BITS 3
#define SRSLTE_PMI_MAX_BITS 4
typedef struct { typedef struct {
bool configured; bool configured;
uint32_t pmi_idx; uint32_t pmi_idx;
uint32_t ri_idx; uint32_t ri_idx;
bool ri_idx_present;
bool simul_cqi_ack; bool simul_cqi_ack;
bool format_is_subband; bool format_is_subband;
uint32_t subband_size; uint32_t subband_size;

@ -53,6 +53,8 @@
#define SRSLTE_BCH_PAYLOADCRC_LEN (SRSLTE_BCH_PAYLOAD_LEN+16) #define SRSLTE_BCH_PAYLOADCRC_LEN (SRSLTE_BCH_PAYLOAD_LEN+16)
#define SRSLTE_BCH_ENCODED_LEN 3*(SRSLTE_BCH_PAYLOADCRC_LEN) #define SRSLTE_BCH_ENCODED_LEN 3*(SRSLTE_BCH_PAYLOADCRC_LEN)
#define SRSLTE_PBCH_MAX_RE 256 // make it avx2-aligned
/* PBCH object */ /* PBCH object */
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_cell_t cell; srslte_cell_t cell;
@ -83,12 +85,14 @@ typedef struct SRSLTE_API {
} srslte_pbch_t; } srslte_pbch_t;
SRSLTE_API int srslte_pbch_init(srslte_pbch_t *q, SRSLTE_API int srslte_pbch_init(srslte_pbch_t *q);
srslte_cell_t cell);
SRSLTE_API void srslte_pbch_free(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 *slot1_symbols,
cf_t *ce_slot1[SRSLTE_MAX_PORTS], cf_t *ce_slot1[SRSLTE_MAX_PORTS],
float noise_estimate, float noise_estimate,

@ -78,14 +78,12 @@ typedef struct SRSLTE_API {
} srslte_pcfich_t; } srslte_pcfich_t;
SRSLTE_API int srslte_pcfich_init(srslte_pcfich_t *q, SRSLTE_API int srslte_pcfich_init(srslte_pcfich_t *q,
srslte_regs_t *regs, uint32_t nof_rx_antennas);
srslte_cell_t cell);
SRSLTE_API int srslte_pcfich_set_cell(srslte_pcfich_t *q,
SRSLTE_API int srslte_pcfich_init_multi(srslte_pcfich_t *q, srslte_regs_t *regs,
srslte_regs_t *regs, srslte_cell_t cell);
srslte_cell_t cell,
uint32_t nof_rx_antennas);
SRSLTE_API void srslte_pcfich_free(srslte_pcfich_t *q); SRSLTE_API void srslte_pcfich_free(srslte_pcfich_t *q);

@ -64,6 +64,7 @@ typedef struct SRSLTE_API {
uint32_t nof_cce; uint32_t nof_cce;
uint32_t max_bits; uint32_t max_bits;
uint32_t nof_rx_antennas; uint32_t nof_rx_antennas;
bool is_ue;
srslte_regs_t *regs; srslte_regs_t *regs;
@ -84,29 +85,16 @@ typedef struct SRSLTE_API {
} srslte_pdcch_t; } srslte_pdcch_t;
SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q, SRSLTE_API int srslte_pdcch_init_ue(srslte_pdcch_t *q,
srslte_regs_t *regs, uint32_t max_prb,
srslte_cell_t cell); uint32_t nof_rx_antennas);
SRSLTE_API int srslte_pdcch_init_tx(srslte_pdcch_t *q, SRSLTE_API int srslte_pdcch_init_enb(srslte_pdcch_t *q,
srslte_regs_t *regs, uint32_t max_prb);
srslte_cell_t cell);
SRSLTE_API int srslte_pdcch_set_cell(srslte_pdcch_t *q,
SRSLTE_API int srslte_pdcch_init_rx(srslte_pdcch_t *q, srslte_regs_t *regs,
srslte_regs_t *regs, srslte_cell_t cell);
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 void srslte_pdcch_free(srslte_pdcch_t *q); SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q);

@ -49,6 +49,7 @@
typedef struct { typedef struct {
srslte_sequence_t seq[SRSLTE_MAX_CODEWORDS][SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq[SRSLTE_MAX_CODEWORDS][SRSLTE_NSUBFRAMES_X_FRAME];
uint32_t cell_id;
bool sequence_generated; bool sequence_generated;
} srslte_pdsch_user_t; } srslte_pdsch_user_t;
@ -57,9 +58,13 @@ typedef struct SRSLTE_API {
srslte_cell_t cell; srslte_cell_t cell;
uint32_t nof_rx_antennas; uint32_t nof_rx_antennas;
uint32_t last_nof_iterations[SRSLTE_MAX_CODEWORDS];
uint32_t max_re; uint32_t max_re;
uint16_t ue_rnti;
bool is_ue;
/* buffers */ /* buffers */
// void buffers are shared for tx and rx // void buffers are shared for tx and rx
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */ 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 // This is to generate the scrambling seq for multiple CRNTIs
srslte_pdsch_user_t **users; srslte_pdsch_user_t **users;
srslte_sequence_t tmp_seq;
srslte_sch_t dl_sch; srslte_sch_t dl_sch;
} srslte_pdsch_t; } 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_API int srslte_pdsch_init_ue(srslte_pdsch_t *q,
srslte_cell_t cell, uint32_t max_prb,
uint32_t nof_antennas); 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 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); uint16_t rnti);
SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q, 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, uint32_t nof_ce,
float *cn); 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 #endif

@ -85,26 +85,24 @@ typedef struct SRSLTE_API {
} srslte_phich_t; } srslte_phich_t;
SRSLTE_API int srslte_phich_init(srslte_phich_t *q, SRSLTE_API int srslte_phich_init(srslte_phich_t *q,
srslte_regs_t *regs, uint32_t nof_rx_antennas);
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 void srslte_phich_free(srslte_phich_t *q); 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_prb_lowest,
uint32_t n_dmrs, uint32_t n_dmrs,
uint32_t *ngroup, uint32_t *ngroup,
uint32_t *nseq); uint32_t *nseq);
SRSLTE_API int srslte_phich_decode(srslte_phich_t *q, SRSLTE_API int srslte_phich_decode(srslte_phich_t *q,
cf_t *slot_symbols, cf_t *slot_symbols[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate, float noise_estimate,
uint32_t ngroup, uint32_t ngroup,
uint32_t nseq, uint32_t nseq,
@ -112,16 +110,6 @@ SRSLTE_API int srslte_phich_decode(srslte_phich_t *q,
uint8_t *ack, uint8_t *ack,
float *distance); 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, SRSLTE_API int srslte_phich_encode(srslte_phich_t *q,
uint8_t ack, uint8_t ack,
uint32_t ngroup, uint32_t ngroup,

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

@ -44,6 +44,8 @@
#include "srslte/phy/common/phy_common.h" #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. /** Generation and detection of RACH signals for uplink.
* Currently only supports preamble formats 0-3. * Currently only supports preamble formats 0-3.
* Does not currently support high speed flag. * 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_ul; // IFFT size for uplink
uint32_t N_ifft_prach; // IFFT size for PRACH generation uint32_t N_ifft_prach; // IFFT size for PRACH generation
uint32_t max_N_ifft_ul;
// Working parameters // Working parameters
uint32_t N_zc; // PRACH sequence length uint32_t N_zc; // PRACH sequence length
uint32_t N_cs; // Cyclic shift size uint32_t N_cs; // Cyclic shift size
@ -82,12 +86,12 @@ typedef struct SRSLTE_API {
float *corr; float *corr;
// PRACH IFFT // PRACH IFFT
srslte_dft_plan_t *fft; srslte_dft_plan_t fft;
srslte_dft_plan_t *ifft; srslte_dft_plan_t ifft;
// ZC-sequence FFT and IFFT // ZC-sequence FFT and IFFT
srslte_dft_plan_t *zc_fft; srslte_dft_plan_t zc_fft;
srslte_dft_plan_t *zc_ifft; srslte_dft_plan_t zc_ifft;
cf_t *signal_fft; cf_t *signal_fft;
float detect_factor; 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_prach_sf_config_t *sf_config);
SRSLTE_API int srslte_prach_init(srslte_prach_t *p, SRSLTE_API int srslte_prach_init(srslte_prach_t *p,
uint32_t N_ifft_ul, uint32_t max_N_ifft_ul);
uint32_t config_idx,
uint32_t root_seq_index, SRSLTE_API int srslte_prach_set_cell(srslte_prach_t *p,
bool high_speed_flag, uint32_t N_ifft_ul,
uint32_t zero_corr_zone_config); 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_API int srslte_prach_init_cfg(srslte_prach_t* p,
srslte_prach_cfg_t* cfg, srslte_prach_cfg_t* cfg,

@ -45,7 +45,7 @@
#define SRSLTE_PUCCH_N_SEQ 12 #define SRSLTE_PUCCH_N_SEQ 12
#define SRSLTE_PUCCH2_NOF_BITS SRSLTE_UCI_CQI_CODED_PUCCH_B #define SRSLTE_PUCCH2_NOF_BITS SRSLTE_UCI_CQI_CODED_PUCCH_B
#define SRSLTE_PUCCH_MAX_BITS SRSLTE_CQI_MAX_BITS #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 { typedef enum SRSLTE_API {
SRSLTE_PUCCH_FORMAT_1 = 0, SRSLTE_PUCCH_FORMAT_1 = 0,
@ -115,12 +115,14 @@ typedef struct SRSLTE_API {
}srslte_pucch_t; }srslte_pucch_t;
SRSLTE_API int srslte_pucch_init(srslte_pucch_t *q, SRSLTE_API int srslte_pucch_init(srslte_pucch_t *q);
srslte_cell_t cell);
SRSLTE_API void srslte_pucch_free(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, srslte_pucch_cfg_t* cfg,
bool group_hopping_en); bool group_hopping_en);

@ -62,13 +62,16 @@ typedef struct {
typedef struct { typedef struct {
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
bool sequences_generated; uint32_t cell_id;
} srslte_pusch_user_t; bool sequence_generated;
} srslte_pusch_user_t;
/* PUSCH object */ /* PUSCH object */
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_cell_t cell; srslte_cell_t cell;
bool is_ue;
uint16_t ue_rnti;
uint32_t max_re; uint32_t max_re;
srslte_dft_precoding_t dft_precoding; srslte_dft_precoding_t dft_precoding;
@ -96,12 +99,18 @@ typedef struct SRSLTE_API {
}srslte_pusch_t; }srslte_pusch_t;
SRSLTE_API int srslte_pusch_init(srslte_pusch_t *q, SRSLTE_API int srslte_pusch_init_ue(srslte_pusch_t *q,
srslte_cell_t cell); 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 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_pusch_cfg_t *cfg,
srslte_ra_ul_grant_t *grant, srslte_ra_ul_grant_t *grant,
srslte_uci_cfg_t *uci_cfg, 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, SRSLTE_API int srslte_pusch_set_rnti(srslte_pusch_t *q,
uint16_t rnti); 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); uint16_t rnti);
SRSLTE_API int srslte_pusch_encode(srslte_pusch_t *q, SRSLTE_API int srslte_pusch_encode(srslte_pusch_t *q,

@ -103,11 +103,17 @@ typedef struct SRSLTE_API {
bool prb_idx[2][SRSLTE_MAX_PRB]; bool prb_idx[2][SRSLTE_MAX_PRB];
uint32_t nof_prb; uint32_t nof_prb;
uint32_t Qm[SRSLTE_MAX_CODEWORDS]; uint32_t Qm[SRSLTE_MAX_CODEWORDS];
uint32_t Qm2[SRSLTE_MAX_CODEWORDS];
srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS]; srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS];
srslte_ra_mcs_t mcs2[SRSLTE_MAX_CODEWORDS];
uint32_t nof_tb; uint32_t nof_tb;
srslte_sf_t sf_type;
bool tb_en[SRSLTE_MAX_CODEWORDS];
uint32_t pinfo; uint32_t pinfo;
} srslte_ra_dl_grant_t; } 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 */ /** Unpacked DCI message for DL grant */
typedef struct SRSLTE_API { 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_API void srslte_ra_ul_grant_fprint(FILE *f,
srslte_ra_ul_grant_t *grant); 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_ */ #endif /* RB_ALLOC_H_ */

@ -56,10 +56,9 @@
/* DL-SCH AND UL-SCH common functions */ /* DL-SCH AND UL-SCH common functions */
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
uint32_t max_iterations; uint32_t max_iterations;
uint32_t nof_iterations; uint32_t nof_iterations;
float average_nof_iterations;
/* buffers */ /* buffers */
uint8_t *cb_in; uint8_t *cb_in;
uint8_t *parity_bits; uint8_t *parity_bits;
@ -77,6 +76,7 @@ typedef struct SRSLTE_API {
srslte_uci_cqi_pusch_t uci_cqi; srslte_uci_cqi_pusch_t uci_cqi;
} srslte_sch_t; } srslte_sch_t;
#include "srslte/phy/phch/pmch.h"
SRSLTE_API int srslte_sch_init(srslte_sch_t *q); 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, SRSLTE_API void srslte_sch_set_max_noi(srslte_sch_t *q,
uint32_t max_iterations); 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 uint32_t srslte_sch_last_noi(srslte_sch_t *q);
SRSLTE_API int srslte_dlsch_encode(srslte_sch_t *q, SRSLTE_API int srslte_dlsch_encode(srslte_sch_t *q,

@ -64,6 +64,10 @@ typedef struct SRSLTE_API {
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
uint8_t uci_cqi[SRSLTE_CQI_MAX_BITS]; uint8_t uci_cqi[SRSLTE_CQI_MAX_BITS];
uint32_t uci_cqi_len; 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 uint8_t uci_ri; // Only 1-bit supported for RI
uint32_t uci_ri_len; uint32_t uci_ri_len;
uint8_t uci_ack; // 1st codeword bit for HARQ-ACK 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); bool *cqi_ack);
SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg,
uint8_t data, uint8_t acks[2],
uint32_t O_cqi, uint32_t nof_acks,
uint32_t O_cqi,
float beta, float beta,
uint32_t H_prime_total, uint32_t H_prime_total,
srslte_uci_bit_t *ri_bits); 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 H_prime_total,
uint32_t O_cqi, uint32_t O_cqi,
srslte_uci_bit_t *ack_bits, 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, SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg,
uint8_t data, uint8_t data,

@ -67,7 +67,8 @@ SRSLTE_API void srslte_interp_linear_f(float *input,
typedef struct { typedef struct {
cf_t *diff_vec; cf_t *diff_vec;
uint32_t vector_len; uint32_t vector_len;
uint32_t max_vector_len;
} srslte_interp_linsrslte_vec_t; } srslte_interp_linsrslte_vec_t;
SRSLTE_API int srslte_interp_linear_vector_init(srslte_interp_linsrslte_vec_t *q, 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 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, SRSLTE_API void srslte_interp_linear_vector(srslte_interp_linsrslte_vec_t *q,
cf_t *in0, cf_t *in0,
cf_t *in1, cf_t *in1,
@ -107,7 +111,9 @@ typedef struct {
cf_t *diff_vec2; cf_t *diff_vec2;
float *ramp; float *ramp;
uint32_t vector_len; uint32_t vector_len;
uint32_t M; uint32_t M;
uint32_t max_vector_len;
uint32_t max_M;
} srslte_interp_lin_t; } srslte_interp_lin_t;
SRSLTE_API int srslte_interp_linear_init(srslte_interp_lin_t *q, 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 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, SRSLTE_API void srslte_interp_linear_offset(srslte_interp_lin_t *q,
cf_t *input, cf_t *input,
cf_t *output, cf_t *output,

@ -49,6 +49,7 @@ typedef struct SRSLTE_API {
float last_freq; float last_freq;
float tol; float tol;
int nsamples; int nsamples;
int max_samples;
srslte_cexptab_t tab; srslte_cexptab_t tab;
cf_t *cur_cexp; cf_t *cur_cexp;
}srslte_cfo_t; }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 void srslte_cfo_free(srslte_cfo_t *h);
SRSLTE_API int srslte_cfo_realloc(srslte_cfo_t *h, SRSLTE_API int srslte_cfo_resize(srslte_cfo_t *h,
uint32_t samples); uint32_t samples);
SRSLTE_API void srslte_cfo_set_tol(srslte_cfo_t *h, SRSLTE_API void srslte_cfo_set_tol(srslte_cfo_t *h,
float tol); float tol);

@ -35,6 +35,7 @@
typedef struct { typedef struct {
cf_t *corr; cf_t *corr;
uint32_t symbol_sz; uint32_t symbol_sz;
uint32_t max_symbol_sz;
} srslte_cp_synch_t; } srslte_cp_synch_t;
SRSLTE_API int srslte_cp_synch_init(srslte_cp_synch_t *q, 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 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, SRSLTE_API uint32_t srslte_cp_synch(srslte_cp_synch_t *q,
cf_t *input, cf_t *input,
uint32_t max_offset, uint32_t max_offset,

@ -79,6 +79,10 @@ typedef struct SRSLTE_API {
#endif #endif
int decimate; int decimate;
uint32_t max_frame_size;
uint32_t max_fft_size;
uint32_t frame_size; uint32_t frame_size;
uint32_t N_id_2; uint32_t N_id_2;
uint32_t fft_size; 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 cfo_i,
int decimate); 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, SRSLTE_API int srslte_pss_synch_init(srslte_pss_synch_t *q,
uint32_t frame_size); uint32_t frame_size);

@ -70,6 +70,7 @@ typedef struct SRSLTE_API {
srslte_dft_plan_t dftp_input; srslte_dft_plan_t dftp_input;
uint32_t fft_size; uint32_t fft_size;
uint32_t max_fft_size;
float corr_peak_threshold; float corr_peak_threshold;
uint32_t symbol_sz; uint32_t symbol_sz;
@ -89,7 +90,7 @@ typedef struct SRSLTE_API {
SRSLTE_API int srslte_sss_synch_init(srslte_sss_synch_t *q, SRSLTE_API int srslte_sss_synch_init(srslte_sss_synch_t *q,
uint32_t fft_size); 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); uint32_t fft_size);
SRSLTE_API void srslte_sss_synch_free(srslte_sss_synch_t *q); SRSLTE_API void srslte_sss_synch_free(srslte_sss_synch_t *q);

@ -75,6 +75,8 @@ typedef struct SRSLTE_API {
uint32_t frame_size; uint32_t frame_size;
uint32_t max_offset; uint32_t max_offset;
bool enable_cfo_corr; bool enable_cfo_corr;
bool mean_cfo2_isunset;
bool mean_cfo_isunset;
float mean_cfo; float mean_cfo;
float mean_cfo2; float mean_cfo2;
int cfo_i; int cfo_i;
@ -85,6 +87,7 @@ typedef struct SRSLTE_API {
uint32_t cp_len; uint32_t cp_len;
srslte_cfo_t cfocorr; srslte_cfo_t cfocorr;
srslte_cfo_t cfocorr2; srslte_cfo_t cfocorr2;
float current_cfo_tol;
sss_alg_t sss_alg; sss_alg_t sss_alg;
bool detect_cp; bool detect_cp;
bool sss_en; bool sss_en;
@ -97,6 +100,8 @@ typedef struct SRSLTE_API {
float M_ext_avg; float M_ext_avg;
cf_t *temp; cf_t *temp;
uint32_t max_frame_size;
}srslte_sync_t; }srslte_sync_t;
typedef enum { 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 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); SRSLTE_API void srslte_sync_reset(srslte_sync_t *q);
/* Finds a correlation peak in the input signal around position find_offset */ /* 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, SRSLTE_API void srslte_sync_set_threshold(srslte_sync_t *q,
float threshold); float threshold);
SRSLTE_API void srslte_sync_set_cfo_tol(srslte_sync_t *q,
float tol);
/* Gets the subframe idx (0 or 5) */ /* Gets the subframe idx (0 or 5) */
SRSLTE_API uint32_t srslte_sync_get_sf_idx(srslte_sync_t *q); SRSLTE_API uint32_t srslte_sync_get_sf_idx(srslte_sync_t *q);

@ -48,6 +48,7 @@
#include "srslte/phy/phch/pcfich.h" #include "srslte/phy/phch/pcfich.h"
#include "srslte/phy/phch/pdcch.h" #include "srslte/phy/phch/pdcch.h"
#include "srslte/phy/phch/pdsch.h" #include "srslte/phy/phch/pdsch.h"
#include "srslte/phy/phch/pmch.h"
#include "srslte/phy/phch/pdsch_cfg.h" #include "srslte/phy/phch/pdsch_cfg.h"
#include "srslte/phy/phch/phich.h" #include "srslte/phy/phch/phich.h"
#include "srslte/phy/phch/ra.h" #include "srslte/phy/phch/ra.h"
@ -76,14 +77,17 @@ typedef struct SRSLTE_API {
srslte_pcfich_t pcfich; srslte_pcfich_t pcfich;
srslte_pdcch_t pdcch; srslte_pdcch_t pdcch;
srslte_pdsch_t pdsch; srslte_pdsch_t pdsch;
srslte_pmch_t pmch;
srslte_phich_t phich; srslte_phich_t phich;
srslte_regs_t regs; srslte_regs_t regs;
srslte_ofdm_t fft; srslte_ofdm_t fft;
srslte_ofdm_t fft_mbsfn;
srslte_chest_dl_t chest; srslte_chest_dl_t chest;
srslte_cfo_t sfo_correct; 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_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
srslte_ra_dl_dci_t dl_dci; srslte_ra_dl_dci_t dl_dci;
srslte_cell_t cell; srslte_cell_t cell;
@ -103,9 +107,14 @@ typedef struct SRSLTE_API {
srslte_dci_format_t dci_format; srslte_dci_format_t dci_format;
uint64_t pkt_errors; uint64_t pkt_errors;
uint64_t pkts_total; 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; uint64_t nof_detected;
uint16_t current_rnti; 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_ue[3][10];
dci_blind_search_t current_ss_common[3]; dci_blind_search_t current_ss_common[3];
srslte_dci_location_t last_location; srslte_dci_location_t last_location;
@ -119,19 +128,34 @@ typedef struct SRSLTE_API {
/* This function shall be called just after the initial synchronization */ /* This function shall be called just after the initial synchronization */
SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q, 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); uint32_t nof_rx_antennas);
SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q); 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, SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS], 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 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 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_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q,
srslte_ra_dl_grant_t *grant, 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, uint16_t rnti,
bool acks[SRSLTE_MAX_CODEWORDS]); 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, SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q,
uint32_t *ri, uint8_t *ri,
uint32_t *pmi, uint8_t *pmi,
float *current_sinr); float *current_sinr);
SRSLTE_API int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, SRSLTE_API int srslte_ue_dl_ri_select(srslte_ue_dl_t *q,
uint32_t *ri, uint8_t *ri,
float *cn); float *cn);
SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, 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, SRSLTE_API void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q,
uint16_t rnti); 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_API void srslte_ue_dl_save_signal(srslte_ue_dl_t *q,
srslte_softbuffer_rx_t *softbuffer, srslte_softbuffer_rx_t *softbuffer,
uint32_t tti, uint32_t tti,

@ -79,10 +79,13 @@ typedef struct SRSLTE_API {
} srslte_ue_mib_t; } srslte_ue_mib_t;
SRSLTE_API int srslte_ue_mib_init(srslte_ue_mib_t *q, 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 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 void srslte_ue_mib_reset(srslte_ue_mib_t * q);
SRSLTE_API int srslte_ue_mib_decode(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; uint32_t nof_rx_antennas;
} srslte_ue_mib_sync_t; } srslte_ue_mib_sync_t;
SRSLTE_API int srslte_ue_mib_sync_init(srslte_ue_mib_sync_t *q, SRSLTE_API int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q,
uint32_t cell_id, int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t *),
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 *),
uint32_t nof_rx_antennas, uint32_t nof_rx_antennas,
void *stream_handler); void *stream_handler);
SRSLTE_API void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q); 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 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, SRSLTE_API int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q,

@ -69,6 +69,8 @@ typedef enum SRSLTE_API { SF_FIND, SF_TRACK} srslte_ue_sync_state_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_sync_t sfind; srslte_sync_t sfind;
srslte_sync_t strack; srslte_sync_t strack;
uint32_t max_prb;
srslte_agc_t agc; srslte_agc_t agc;
bool do_agc; bool do_agc;
@ -125,22 +127,25 @@ typedef struct SRSLTE_API {
} srslte_ue_sync_t; } srslte_ue_sync_t;
SRSLTE_API int srslte_ue_sync_init(srslte_ue_sync_t *q, 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*), int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*),
void *stream_handler); void *stream_handler);
SRSLTE_API int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, SRSLTE_API 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*), int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
uint32_t nof_rx_antennas, uint32_t nof_rx_antennas,
void *stream_handler); void *stream_handler);
SRSLTE_API int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, SRSLTE_API int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q,
srslte_cell_t cell, uint32_t max_prb,
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), bool search_cell,
uint32_t nof_rx_antennas, int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
void *stream_handler, uint32_t nof_rx_antennas,
int decimate); void *stream_handler,
int decimate);
SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q, SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q,
uint32_t nof_prb, 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 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, SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q,
double (set_gain_callback)(void*, double), double (set_gain_callback)(void*, double),
float init_gain_value); 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, SRSLTE_API int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q,
cf_t *input_buffer[SRSLTE_MAX_PORTS]); 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, SRSLTE_API void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q,
float cfo); float cfo);

@ -75,7 +75,8 @@ typedef struct SRSLTE_API {
bool normalize_en; bool normalize_en;
bool cfo_en; bool cfo_en;
float current_cfo_tol;
float current_cfo; float current_cfo;
srslte_pucch_format_t last_pucch_format; 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 */ /* This function shall be called just after the initial synchronization */
SRSLTE_API int srslte_ue_ul_init(srslte_ue_ul_t *q, SRSLTE_API int srslte_ue_ul_init(srslte_ue_ul_t *q,
srslte_cell_t cell); uint32_t max_prb);
SRSLTE_API void srslte_ue_ul_free(srslte_ue_ul_t *q); 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); 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); bool enabled);
SRSLTE_API void srslte_ue_ul_set_normalization(srslte_ue_ul_t *q, SRSLTE_API void srslte_ue_ul_set_normalization(srslte_ue_ul_t *q,

@ -46,6 +46,8 @@ typedef struct SRSLTE_API {
uint32_t input_len; uint32_t input_len;
uint32_t filter_len; uint32_t filter_len;
uint32_t output_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 input_plan;
srslte_dft_plan_t filter_plan; srslte_dft_plan_t filter_plan;
srslte_dft_plan_t output_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 input_len,
uint32_t filter_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); SRSLTE_API void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q);

@ -57,8 +57,7 @@ namespace srslte {
bzero(&end_of_burst_time, sizeof(srslte_timestamp_t)); bzero(&end_of_burst_time, sizeof(srslte_timestamp_t));
bzero(zeros, burst_preamble_max_samples*sizeof(cf_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; is_start_of_burst = false;
burst_preamble_samples = 0; burst_preamble_samples = 0;
burst_preamble_time_rounded = 0; burst_preamble_time_rounded = 0;
@ -72,13 +71,12 @@ namespace srslte {
rx_freq = 0; rx_freq = 0;
trace_enabled = false; trace_enabled = false;
tti = 0; tti = 0;
agc_enabled = false; agc_enabled = false;
offset = 0;
}; };
bool init(char *args = NULL, char *devname = NULL); bool init(char *args = NULL, char *devname = NULL);
void stop(); void stop();
void reset();
bool start_agc(bool tx_gain_same_rx); bool start_agc(bool tx_gain_same_rx);
void set_burst_preamble(double preamble_us); void set_burst_preamble(double preamble_us);
@ -98,15 +96,16 @@ namespace srslte {
void set_tx_rx_gain_offset(float offset); void set_tx_rx_gain_offset(float offset);
double set_rx_gain_th(float gain); double set_rx_gain_th(float gain);
void set_tx_freq(float freq); void set_freq_offset(double freq);
void set_rx_freq(float freq); void set_tx_freq(double freq);
void set_rx_freq(double freq);
float get_tx_freq(); double get_tx_freq();
float get_rx_freq(); double get_rx_freq();
void set_master_clock_rate(float rate); void set_master_clock_rate(double rate);
void set_tx_srate(float srate); void set_tx_srate(double srate);
void set_rx_srate(float srate); void set_rx_srate(double srate);
float get_tx_gain(); float get_tx_gain();
float get_rx_gain(); float get_rx_gain();
@ -122,9 +121,8 @@ namespace srslte {
void stop_rx(); void stop_rx();
void set_tti(uint32_t tti); void set_tti(uint32_t tti);
void tx_offset(int offset);
void set_tti_len(uint32_t sf_len); bool is_first_of_burst();
uint32_t get_tti_len();
void register_error_handler(srslte_rf_error_handler_t h); 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_burst_preamble_sec = 0.0;
const static double blade_default_tx_adv_samples = 27; const static double blade_default_tx_adv_samples = 27;
const static double blade_default_tx_adv_offset_sec = 1e-6; const static double blade_default_tx_adv_offset_sec = 1e-6;
float tx_freq, rx_freq; double tx_freq, rx_freq, freq_offset;
trace<uint32_t> tr_local_time; trace<uint32_t> tr_local_time;
trace<uint32_t> tr_usrp_time; trace<uint32_t> tr_usrp_time;
@ -167,8 +165,10 @@ namespace srslte {
bool trace_enabled; bool trace_enabled;
uint32_t tti; uint32_t tti;
bool agc_enabled; bool agc_enabled;
int offset;
uint32_t sf_len; char saved_args[128];
char saved_devname[128];
}; };
} }

@ -50,6 +50,9 @@ public:
uint8_t direction_); uint8_t direction_);
void stop(); void stop();
// GW interface
bool is_drb_enabled(uint32_t lcid);
// RRC interface // RRC interface
void reset(); void reset();
void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void write_sdu(uint32_t lcid, byte_buffer_t *sdu);

@ -78,6 +78,7 @@ public:
mac_interface_timers *mac_timers); mac_interface_timers *mac_timers);
void configure(srslte_rlc_config_t cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void stop();
void empty_queue(); void empty_queue();
rlc_mode_t get_mode(); rlc_mode_t get_mode();

@ -158,6 +158,7 @@ public:
srslte::mac_interface_timers *mac_timers_) = 0; srslte::mac_interface_timers *mac_timers_) = 0;
virtual void configure(srslte_rlc_config_t cnfg) = 0; virtual void configure(srslte_rlc_config_t cnfg) = 0;
virtual void reset() = 0; virtual void reset() = 0;
virtual void stop() = 0;
virtual void empty_queue() = 0; virtual void empty_queue() = 0;
virtual rlc_mode_t get_mode() = 0; virtual rlc_mode_t get_mode() = 0;

@ -56,6 +56,7 @@ public:
void configure(srslte_rlc_config_t cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void stop();
void empty_queue(); void empty_queue();
bool active(); bool active();

@ -48,6 +48,7 @@ public:
mac_interface_timers *mac_timers); mac_interface_timers *mac_timers);
void configure(srslte_rlc_config_t cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void stop();
void empty_queue(); void empty_queue();
rlc_mode_t get_mode(); rlc_mode_t get_mode();

@ -58,6 +58,7 @@ public:
mac_interface_timers *mac_timers_); mac_interface_timers *mac_timers_);
void configure(srslte_rlc_config_t cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void stop();
void empty_queue(); void empty_queue();
rlc_mode_t get_mode(); rlc_mode_t get_mode();
@ -124,7 +125,8 @@ private:
* Timers * Timers
* Ref: 3GPP TS 36.322 v10.0.0 Section 7 * 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; bool pdu_lost;

@ -55,7 +55,7 @@ void logger_file::init(std::string file) {
filename = file; filename = file;
logfile = fopen(filename.c_str(), "w"); logfile = fopen(filename.c_str(), "w");
if(logfile==NULL) { 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(); start();
inited = true; inited = true;

@ -66,7 +66,7 @@ uint8_t* pdu_queue::request(uint32_t len)
void pdu_queue::deallocate(uint8_t* pdu) void pdu_queue::deallocate(uint8_t* pdu)
{ {
if (!pool.deallocate((pdu_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); callback->process_pdu(pdu->ptr, pdu->len, pdu->tstamp);
} }
if (!pool.deallocate(pdu)) { 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++; cnt++;
have_data = true; have_data = true;

@ -32,6 +32,8 @@
#include <string.h> #include <string.h>
#include <complex.h> #include <complex.h>
#include <math.h> #include <math.h>
#include <srslte/phy/common/phy_common.h>
#include <srslte/srslte.h>
#include "srslte/config.h" #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. * 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, uint32_t max_prb)
int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL)
srslte_cell_isvalid(&cell))
{ {
bzero(q, sizeof(srslte_chest_dl_t)); 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) { if (ret != SRSLTE_SUCCESS) {
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
goto clean_exit; 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) { if (!q->tmp_noise) {
perror("malloc"); perror("malloc");
goto clean_exit; 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) { if (!q->pilot_estimates) {
perror("malloc"); perror("malloc");
goto clean_exit; 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) { if (!q->pilot_estimates_average) {
perror("malloc"); perror("malloc");
goto clean_exit; 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) { if (!q->pilot_recv_signal) {
perror("malloc"); perror("malloc");
goto clean_exit; 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"); fprintf(stderr, "Error initializing vector interpolator\n");
goto clean_exit; 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"); fprintf(stderr, "Error initializing interpolator\n");
goto clean_exit; goto clean_exit;
} }
if (srslte_pss_generate(q->pss_signal, cell.id%3)) { if (srslte_interp_linear_init(&q->srslte_interp_lin_mbsfn, 6*max_prb, SRSLTE_NRE/6)) {
fprintf(stderr, "Error initializing PSS signal for noise estimation\n"); fprintf(stderr, "Error initializing interpolator\n");
goto clean_exit; 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; q->smooth_filter_len = 3;
srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1); srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1);
q->cell = cell;
} }
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
@ -142,14 +159,25 @@ clean_exit:
void srslte_chest_dl_free(srslte_chest_dl_t *q) 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; i<SRSLTE_MAX_MBSFN_AREA_IDS; i++) {
if (q->mbsfn_refs[i]) {
srslte_refsignal_free(q->mbsfn_refs[i]);
}
}
free(q->mbsfn_refs);
}
if (q->tmp_noise) { if (q->tmp_noise) {
free(q->tmp_noise); free(q->tmp_noise);
} }
srslte_interp_linear_vector_free(&q->srslte_interp_linvec); 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);
srslte_interp_linear_free(&q->srslte_interp_lin_mbsfn);
if (q->pilot_estimates) { if (q->pilot_estimates) {
free(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)); 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 */ /* 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) 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); int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
/* Substract noisy pilot estimates */ /* Substract noisy pilot estimates */
srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref); 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)] #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 */ /* interpolate the symbols with references in the freq domain */
uint32_t l; 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 */ /* Interpolate in the frequency domain */
for (l=0;l<nsymbols;l++) {
uint32_t fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0); // we add one to nsymbols to allow for inclusion of the non-mbms references in the channel estimation
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l], for (l=0;l<(nsymbols);l++) {
&ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE], if (ch_mode == SRSLTE_SF_MBSFN) {
fidx_offset, SRSLTE_NRE/2-fidx_offset); 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 */ /* Now interpolate in the time domain between symbols */
if (SRSLTE_CP_ISNORM(q->cell.cp)) { if (ch_mode == SRSLTE_SF_MBSFN) {
if (nsymbols == 4) { 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(0), &cesymb(4), &cesymb(1), 4, 3); 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(4), &cesymb(7), &cesymb(5), 3, 2); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3);
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(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); } else {
} else { if (SRSLTE_CP_ISNORM(q->cell.cp)) {
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1); if (nsymbols == 4) {
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(0), &cesymb(4), &cesymb(1), 4, 3);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5); 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);
} else { srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2);
if (nsymbols == 4) { } else {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2); 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(3), &cesymb(6), &cesymb(4), 3, 2); 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(6), &cesymb(9), &cesymb(7), 3, 2); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2); }
} else { } else {
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1); if (nsymbols == 4) {
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(0), &cesymb(3), &cesymb(1), 3, 2);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4); 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) { 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_len < SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN) {
if (filter) { 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; 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) { 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 = srslte_refsignal_cs_nof_symbols(port_id); 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 = 2*q->cell.nof_prb; uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
// Average in the frequency domain // Average in the frequency domain
for (int l=0;l<nsymbols;l++) { for (int l=0;l<nsymbols;l++) {
@ -311,24 +410,16 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id)
return rssi/nsymbols; return rssi/nsymbols;
} }
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) 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) {
/* 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_signal.pilots[port_id/2][sf_idx],
q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
if (ce != NULL) {
/* Smooth estimates (if applicable) and interpolate */ /* Smooth estimates (if applicable) and interpolate */
if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) { 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 { } else {
average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, 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); interpolate_pilots(q, q->pilot_estimates_average, ce, port_id, ch_mode);
} }
/* Estimate noise power */ /* Estimate noise power */
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) { 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); 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) { if (sf_idx == 0 || sf_idx == 5) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input);
} }
} }
} }
/* Compute RSRP for the channel estimates in this port */ /* 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 */ /* compute rssi only for port 0 */
q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); 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; 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) 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_id<nof_rx_antennas;rxant_id++) { for (uint32_t rxant_id=0;rxant_id<nof_rx_antennas;rxant_id++) {
@ -370,7 +494,7 @@ int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_
int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, cf_t *ce[SRSLTE_MAX_PORTS], uint32_t sf_idx) int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, cf_t *ce[SRSLTE_MAX_PORTS], uint32_t sf_idx)
{ {
uint32_t port_id; uint32_t port_id;
for (port_id=0;port_id<q->cell.nof_ports;port_id++) { for (port_id=0;port_id<q->cell.nof_ports;port_id++) {
if (srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id, 0)) { if (srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id, 0)) {
return SRSLTE_ERROR; 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; 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_id<nof_rx_antennas;rxant_id++) {
for (uint32_t port_id=0;port_id<q->cell.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 srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) {
float n = 0; float n = 0;
for (int i=0;i<q->last_nof_antennas;i++) { for (int i=0;i<q->last_nof_antennas;i++) {

@ -32,6 +32,8 @@
#include <string.h> #include <string.h>
#include <complex.h> #include <complex.h>
#include <math.h> #include <math.h>
#include <srslte/srslte.h>
#include <srslte/phy/common/phy_common.h>
#include "srslte/config.h" #include "srslte/config.h"
@ -43,6 +45,9 @@
#define NOF_REFS_SYM (q->cell.nof_prb*SRSLTE_NRE) #define NOF_REFS_SYM (q->cell.nof_prb*SRSLTE_NRE)
#define NOF_REFS_SF (NOF_REFS_SYM*2) // 2 reference symbols per subframe #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. /** 3GPP LTE Downlink channel estimator and equalizer.
* Estimates the channel in the resource elements transmitting references and interpolates for the rest * Estimates the channel in the resource elements transmitting references and interpolates for the rest
* of the resource grid. * of the resource grid.
@ -52,52 +57,49 @@
* This object depends on the srslte_refsignal_t object for creating the LTE CSR signal. * 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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL)
srslte_cell_isvalid(&cell))
{ {
bzero(q, sizeof(srslte_chest_ul_t)); bzero(q, sizeof(srslte_chest_ul_t));
q->cell = cell; ret = srslte_refsignal_ul_init(&q->dmrs_signal, max_prb);
ret = srslte_refsignal_ul_init(&q->dmrs_signal, cell);
if (ret != SRSLTE_SUCCESS) { if (ret != SRSLTE_SUCCESS) {
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
goto clean_exit; 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) { if (!q->tmp_noise) {
perror("malloc"); perror("malloc");
goto clean_exit; 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) { if (!q->pilot_estimates) {
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
} }
for (int i=0;i<4;i++) { 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]) { if (!q->pilot_estimates_tmp[i]) {
perror("malloc"); perror("malloc");
goto clean_exit; 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) { if (!q->pilot_recv_signal) {
perror("malloc"); perror("malloc");
goto clean_exit; 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) { if (!q->pilot_known_signal) {
perror("malloc"); perror("malloc");
goto clean_exit; 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"); fprintf(stderr, "Error initializing vector interpolator\n");
goto clean_exit; 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; q->smooth_filter_len = 3;
srslte_chest_ul_set_smooth_filter3_coeff(q, 0.3333); 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; ret = SRSLTE_SUCCESS;
clean_exit: clean_exit:
if (ret != SRSLTE_SUCCESS) { if (ret != SRSLTE_SUCCESS) {
srslte_chest_ul_free(q); srslte_chest_ul_free(q);
@ -120,9 +127,8 @@ clean_exit:
void srslte_chest_ul_free(srslte_chest_ul_t *q) 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); srslte_refsignal_ul_free(&q->dmrs_signal);
if (q->tmp_noise) { if (q->tmp_noise) {
free(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)); 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, void srslte_chest_ul_set_cfg(srslte_chest_ul_t *q,
srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg,
srslte_pucch_cfg_t *pucch_cfg, srslte_pucch_cfg_t *pucch_cfg,

@ -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 srslte_refsignal_cs_nof_symbols(uint32_t port_id)
{ {
uint32_t ret;
if (port_id < 2) { if (port_id < 2) {
return 4; ret = 4;
} else { } 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) { 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); 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) { inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t port_id) {
if (port_id < 2) { if (port_id < 2) {
if (l % 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); return 1+l*SRSLTE_CP_NSYMB(cp);
} }
} }
inline uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l)
/** 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)
{ {
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 c_init;
uint32_t i, ns, l, p; uint32_t i, ns, l, p;
uint32_t N_cp, mp; uint32_t mp;
srslte_sequence_t seq; int ret = SRSLTE_ERROR;
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && srslte_sequence_t seq_mbsfn;
srslte_cell_isvalid(&cell)) bzero(&seq_mbsfn, sizeof(srslte_sequence_t));
{ if (srslte_sequence_init(&seq_mbsfn, 20* SRSLTE_MAX_PRB)) {
ret = SRSLTE_ERROR; goto free_and_exit;
}
bzero(q, sizeof(srslte_refsignal_cs_t));
bzero(&seq, sizeof(srslte_sequence_t)); for(ns=0; ns<SRSLTE_NSUBFRAMES_X_FRAME;ns++){
if (srslte_sequence_init(&seq, 2 * 2 * SRSLTE_MAX_PRB)) { for(p=0;p<2;p++) {
goto free_and_exit; uint32_t nsymbols = 3; // replace with function
} for(l=0;l<nsymbols;l++) {
uint32_t lp = (srslte_refsignal_mbsfn_nsymbol(l))%6;
if (SRSLTE_CP_ISNORM(cell.cp)) { uint32_t slot =(l)?(ns*2+1):(ns*2);
N_cp = 1; c_init = 512*(7*(slot+1)+lp+1)*(2*N_mbsfn_id + 1) + N_mbsfn_id;
} else { srslte_sequence_set_LTE_pr(&seq_mbsfn,SRSLTE_MAX_PRB*20 ,c_init);
N_cp = 0; for(i=0;i< 6*q->cell.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 (p=0;p<2;p++) {
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) { for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
q->pilots[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]) { if (!q->pilots[p][i]) {
perror("malloc"); perror("malloc");
goto free_and_exit; goto free_and_exit;
} }
} }
} }
for (ns=0;ns<SRSLTE_NSLOTS_X_FRAME;ns++) { if(srslte_refsignal_mbsfn_gen_seq(q, q->cell, q->mbsfn_area_id)) {
for (p=0;p<2;p++) { goto free_and_exit;
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(2*p)/2; }
for (l = 0; l < nsymbols; l++) { ret = SRSLTE_SUCCESS;
/* Compute sequence init value */ }
uint32_t lp = srslte_refsignal_cs_nsymbol(l, cell.cp, 2*p);
c_init = 1024 * (7 * (ns + 1) + lp + 1) * (2 * cell.id + 1) free_and_exit:
+ 2 * cell.id + N_cp; if (ret == SRSLTE_ERROR) {
srslte_refsignal_free(q);
/* generate sequence for this symbol and slot */ }
srslte_sequence_set_LTE_pr(&seq, c_init); return ret;
}
/* Compute signal */
for (i = 0; i < 2*q->cell.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)] = /** Allocates memory for the 20 slots in a subframe
(1 - 2 * (float) seq.c[2 * mp]) / sqrt(2) + */
_Complex_I * (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); 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;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
q->pilots[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; ret = SRSLTE_SUCCESS;
} }
free_and_exit: free_and_exit:
if (ret == SRSLTE_ERROR) { if (ret == SRSLTE_ERROR) {
srslte_sequence_free(&seq); srslte_refsignal_free(q);
srslte_refsignal_cs_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;ns<SRSLTE_NSLOTS_X_FRAME;ns++) {
for (p=0;p<2;p++) {
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(2*p)/2;
for (l = 0; l < nsymbols; l++) {
/* Compute sequence init value */
uint32_t lp = srslte_refsignal_cs_nsymbol(l, cell.cp, 2*p);
c_init = 1024 * (7 * (ns + 1) + lp + 1) * (2 * cell.id + 1)
+ 2 * cell.id + N_cp;
/* generate sequence for this symbol and slot */
srslte_sequence_set_LTE_pr(&seq, 2*2*SRSLTE_MAX_PRB, c_init);
/* Compute signal */
for (i = 0; i < 2*q->cell.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; return ret;
} }
/** Deallocates a srslte_refsignal_cs_t object allocated with srslte_refsignal_cs_init */ /** 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 (int p=0;p<2;p++) {
for (int i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
for (p=0;p<2;p++) {
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
if (q->pilots[p][i]) { if (q->pilots[p][i]) {
free(q->pilots[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 */ /* 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) 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<srslte_refsignal_mbsfn_nof_symbols(); l++) {
uint32_t nsymbol = srslte_refsignal_mbsfn_nsymbol(l);
fidx = srslte_refsignal_mbsfn_fidx(l);
for (i = 0; i < 6*cell.nof_prb; i++) {
sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, nsymbol, fidx)] = mbsfn_pilots[SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i,l,cell)];
fidx += SRSLTE_NRE/6;
}
}
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
/** Copies the RE containing references from an array of subframe symbols to the pilots array. */ /** Copies the RE containing references from an array of subframe symbols to the pilots array. */
int srslte_refsignal_cs_get_sf(srslte_cell_t cell, uint32_t port_id, cf_t *sf_symbols, cf_t *pilots) int srslte_refsignal_cs_get_sf(srslte_cell_t cell, uint32_t port_id, cf_t *sf_symbols, cf_t *pilots)
{ {
@ -244,4 +411,39 @@ int srslte_refsignal_cs_get_sf(srslte_cell_t cell, uint32_t port_id, cf_t *sf_sy
} }
} }
int srslte_refsignal_mbsfn_get_sf(srslte_cell_t cell, uint32_t port_id, cf_t *sf_symbols, cf_t *pilots)
{
uint32_t i, l;
uint32_t fidx;
uint32_t nsymbol;
if (srslte_cell_isvalid(&cell) &&
srslte_portid_isvalid(port_id) &&
pilots != NULL &&
sf_symbols != NULL)
{
// getting refs from non mbsfn section of subframe
nsymbol = srslte_refsignal_cs_nsymbol(0, cell.cp, port_id);
fidx = ((srslte_refsignal_cs_v(port_id, 0) + (cell.id % 6)) % 6);
for (i = 0; i < 2*cell.nof_prb; i++) {
pilots[SRSLTE_REFSIGNAL_PILOT_IDX(i,0,cell)] = sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, nsymbol, fidx)];
fidx += SRSLTE_NRE/2; // 2 references per PRB
}
for (l = 0; l< srslte_refsignal_mbsfn_nof_symbols() ;l++){
nsymbol = srslte_refsignal_mbsfn_nsymbol(l);
fidx = srslte_refsignal_mbsfn_fidx(l);
for (i = 0; i < 6*cell.nof_prb; i++) {
pilots[SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i,l,cell) + (2*cell.nof_prb)] = sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, nsymbol, fidx)];
fidx += SRSLTE_NRE/6;
}
}
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}

@ -29,6 +29,7 @@
#include <strings.h> #include <strings.h>
#include <stdlib.h> #include <stdlib.h>
#include <complex.h> #include <complex.h>
#include <srslte/phy/common/phy_common.h>
#include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/phy_common.h"
#include "srslte/phy/ch_estimation/refsignal_ul.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; q->n_prs_pusch[delta_ss][ns] = n_prs;
} }
srslte_sequence_free(&seq);
} }
srslte_sequence_free(&seq);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -160,9 +161,9 @@ static int generate_srslte_sequence_hopping_v(srslte_refsignal_ul_t *q) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
q->v_pusch[ns][delta_ss] = seq.c[ns]; q->v_pusch[ns][delta_ss] = seq.c[ns];
srslte_sequence_free(&seq);
} }
} }
srslte_sequence_free(&seq);
return SRSLTE_SUCCESS; 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 /** 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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && srslte_cell_isvalid(&cell)) { if (q != NULL) {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_refsignal_ul_t)); bzero(q, sizeof(srslte_refsignal_ul_t));
q->cell = cell;
// Allocate temporal buffer for computing signal argument // 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) { if (!q->tmp_arg) {
perror("malloc"); perror("malloc");
goto free_and_exit; 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; ret = SRSLTE_SUCCESS;
} }
free_and_exit: free_and_exit:
@ -226,6 +205,45 @@ void srslte_refsignal_ul_free(srslte_refsignal_ul_t * q) {
bzero(q, sizeof(srslte_refsignal_ul_t)); 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, void srslte_refsignal_ul_set_cfg(srslte_refsignal_ul_t *q,
srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg,
srslte_pucch_cfg_t *pucch_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_idx<SRSLTE_NSUBFRAMES_X_FRAME;sf_idx++) {
for (uint32_t cs=0;cs<SRSLTE_NOF_CSHIFT;cs++) {
pregen->r[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) 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_idx<SRSLTE_NSUBFRAMES_X_FRAME;sf_idx++) { for (uint32_t sf_idx=0;sf_idx<SRSLTE_NSUBFRAMES_X_FRAME;sf_idx++) {
for (uint32_t cs=0;cs<SRSLTE_NOF_CSHIFT;cs++) { for (uint32_t cs=0;cs<SRSLTE_NOF_CSHIFT;cs++) {
pregen->r[cs][sf_idx] = (cf_t**) calloc(sizeof(cf_t*), q->cell.nof_prb + 1);
if (pregen->r[cs][sf_idx]) { if (pregen->r[cs][sf_idx]) {
for (uint32_t n=0;n<=q->cell.nof_prb;n++) { for (uint32_t n=0;n<=q->cell.nof_prb;n++) {
if (srslte_dft_precoding_valid_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 (pregen->r[cs][sf_idx][n]) {
if (srslte_refsignal_dmrs_pusch_gen(q, n, sf_idx, cs, 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; return SRSLTE_ERROR;

@ -29,6 +29,7 @@
#include <strings.h> #include <strings.h>
#include <unistd.h> #include <unistd.h>
#include <complex.h> #include <complex.h>
#include <srslte/phy/common/phy_common.h>
#include "srslte/srslte.h" #include "srslte/srslte.h"
@ -128,10 +129,13 @@ int main(int argc, char **argv) {
cid = cell.id; cid = cell.id;
max_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) { while(cid <= max_cid) {
cell.id = 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"); fprintf(stderr, "Error initializing equalizer\n");
goto do_exit; goto do_exit;
} }
@ -148,7 +152,7 @@ int main(int argc, char **argv) {
bzero(h, sizeof(cf_t) * num_re); bzero(h, sizeof(cf_t) * num_re);
srslte_refsignal_cs_put_sf(cell, n_port, 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 (i=0;i<2*SRSLTE_CP_NSYMB(cell.cp);i++) {
for (j=0;j<cell.nof_prb * SRSLTE_NRE;j++) { for (j=0;j<cell.nof_prb * SRSLTE_NRE;j++) {
@ -214,10 +218,10 @@ int main(int argc, char **argv) {
} }
} }
} }
srslte_chest_dl_free(&est);
cid+=10; cid+=10;
INFO("cid=%d\n", cid); INFO("cid=%d\n", cid);
} }
srslte_chest_dl_free(&est);
ret = 0; ret = 0;

@ -125,13 +125,17 @@ int main(int argc, char **argv) {
max_cid = cell.id; max_cid = cell.id;
} }
printf("max_cid=%d, cid=%d, cell.id=%d\n", max_cid, cid, cell.id); printf("max_cid=%d, cid=%d, cell.id=%d\n", max_cid, cid, cell.id);
if (srslte_chest_ul_init(&est, cell.nof_prb)) {
fprintf(stderr, "Error initializing equalizer\n");
goto do_exit;
}
while(cid <= max_cid) { while(cid <= max_cid) {
cell.id = cid; cell.id = cid;
if (srslte_chest_ul_init(&est, cell)) { if (srslte_chest_ul_set_cell(&est, cell)) {
fprintf(stderr, "Error initializing equalizer\n"); fprintf(stderr, "Error initializing equalizer\n");
goto do_exit; goto do_exit;
} }
for (int n=6;n<=cell.nof_prb;n+=5) { for (int n=6;n<=cell.nof_prb;n+=5) {
if (srslte_dft_precoding_valid_prb(n)) { if (srslte_dft_precoding_valid_prb(n)) {
for (int delta_ss=29;delta_ss<SRSLTE_NOF_DELTA_SS;delta_ss++) { for (int delta_ss=29;delta_ss<SRSLTE_NOF_DELTA_SS;delta_ss++) {
@ -213,9 +217,9 @@ int main(int argc, char **argv) {
} }
cid+=10; cid+=10;
printf("cid=%d\n", cid); printf("cid=%d\n", cid);
srslte_chest_ul_free(&est);
} }
srslte_chest_ul_free(&est);
if (fmatlab) { if (fmatlab) {
fprintf(fmatlab, "input="); fprintf(fmatlab, "input=");

@ -81,7 +81,12 @@ int main(int argc, char **argv) {
parse_args(argc,argv); parse_args(argc,argv);
if (srslte_refsignal_ul_init(&refs, cell)) { if (srslte_refsignal_ul_init(&refs, cell.nof_prb)) {
fprintf(stderr, "Error initializing UL reference signal\n");
goto do_exit;
}
if (srslte_refsignal_ul_set_cell(&refs, cell)) {
fprintf(stderr, "Error initializing UL reference signal\n"); fprintf(stderr, "Error initializing UL reference signal\n");
goto do_exit; goto do_exit;
} }

@ -235,7 +235,7 @@ int srslte_symbol_sz_power2(uint32_t nof_prb) {
return 1024; return 1024;
} else if (nof_prb<=75) { } else if (nof_prb<=75) {
return 1536; return 1536;
} else if (nof_prb<=100) { } else if (nof_prb<=110) {
return 2048; return 2048;
} else { } else {
return -1; return -1;
@ -257,7 +257,7 @@ int srslte_symbol_sz(uint32_t nof_prb) {
return 768; return 768;
} else if (nof_prb<=75) { } else if (nof_prb<=75) {
return 1024; return 1024;
} else if (nof_prb<=100) { } else if (nof_prb<=110) {
return 1536; return 1536;
} else { } else {
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -605,7 +605,7 @@ int srslte_band_get_fd_region(enum band_geographical_area region, srslte_earfcn_
/* Returns the interval tti1-tti2 mod 10240 */ /* Returns the interval tti1-tti2 mod 10240 */
uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2) { uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2) {
if (tti1 > tti2) { if (tti1 >= tti2) {
return tti1-tti2; return tti1-tti2;
} else { } else {
return 10240-tti2+tti1; return 10240-tti2+tti1;

@ -27,7 +27,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <strings.h> #include <strings.h>
#include <assert.h> #include <pthread.h>
#include <srslte/phy/common/sequence.h>
#include "srslte/phy/common/sequence.h" #include "srslte/phy/common/sequence.h"
#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/vector.h"
@ -35,26 +36,75 @@
#define Nc 1600 #define Nc 1600
#define MAX_SEQ_LEN (128*1024)
#define static_memory
/* /*
* Pseudo Random Sequence generation. * Pseudo Random Sequence generation.
* It follows the 3GPP Release 8 (LTE) 36.211 * It follows the 3GPP Release 8 (LTE) 36.211
* Section 7.2 * 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; int n;
uint32_t *x1, *x2; 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) { if (!x1) {
perror("calloc"); perror("calloc");
return; return -1;
} }
x2 = calloc(Nc + q->len + 31, sizeof(uint32_t)); x2 = calloc(Nc + len + 31, sizeof(uint32_t));
if (!x2) { if (!x2) {
free(x1); free(x1);
perror("calloc"); perror("calloc");
return; return -1;
} }
for (n = 0; n < 31; n++) { 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; 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; x1[n + 31] = (x1[n + 3] + x1[n]) & 0x1;
x2[n + 31] = (x2[n + 3] + x2[n + 2] + +x2[n+1] + x2[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; q->c[n] = (x1[n + Nc] + x2[n + Nc]) & 0x1;
} }
free(x1); free(x1);
free(x2); free(x2);
return 0;
} }
#endif
int srslte_sequence_LTE_pr(srslte_sequence_t *q, uint32_t len, uint32_t seed) { int srslte_sequence_LTE_pr(srslte_sequence_t *q, uint32_t len, uint32_t seed) {
if (srslte_sequence_init(q, len)) { if (srslte_sequence_init(q, len)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
q->len = len; q->cur_len = len;
srslte_sequence_set_LTE_pr(q, seed); srslte_sequence_set_LTE_pr(q, len, seed);
srslte_bit_pack_vector(q->c, q->c_bytes, len); srslte_bit_pack_vector(q->c, q->c_bytes, len);
for (int i=0;i<len;i++) { for (int i=0;i<len;i++) {
q->c_float[i] = (1-2*q->c[i]); q->c_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) { int srslte_sequence_init(srslte_sequence_t *q, uint32_t len) {
if (q->c && (q->len != len)) { if (q->c && len > q->max_len) {
free(q->c); srslte_sequence_free(q);
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) { if (!q->c) {
q->c = srslte_vec_malloc(len * sizeof(uint8_t)); 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) { if (!q->c_short) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
q->len = len; q->max_len = len;
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }

@ -29,6 +29,7 @@
#include <complex.h> #include <complex.h>
#include <fftw3.h> #include <fftw3.h>
#include <string.h> #include <string.h>
#include <srslte/srslte.h>
#include "srslte/phy/dft/dft.h" #include "srslte/phy/dft/dft.h"
#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/vector.h"
@ -38,14 +39,27 @@
#define FFTW_WISDOM_FILE ".fftw_wisdom" #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() { void srslte_dft_load() {
#ifdef FFTW_WISDOM_FILE
fftwf_import_wisdom_from_filename(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() { void srslte_dft_exit() {
#ifdef FFTW_WISDOM_FILE
if (!fftwf_export_wisdom_to_filename(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); 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, 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; 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) { static void allocate(srslte_dft_plan_t *plan, int size_in, int size_out, int len) {
plan->in = fftwf_malloc(size_in*len); plan->in = fftwf_malloc(size_in*len);
plan->out = fftwf_malloc(size_out*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) { 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); allocate(plan,sizeof(fftwf_complex),sizeof(fftwf_complex), dft_points);
int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD; 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) { if (!plan->p) {
return -1; return -1;
} }
plan->size = dft_points; plan->size = dft_points;
plan->init_size = plan->size;
plan->mode = SRSLTE_DFT_COMPLEX; plan->mode = SRSLTE_DFT_COMPLEX;
plan->dir = dir; plan->dir = dir;
plan->forward = (dir==SRSLTE_DFT_FORWARD)?true:false; 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; 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) { 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); allocate(plan,sizeof(float),sizeof(float), dft_points);
int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R; 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) { if (!plan->p) {
return -1; return -1;
} }
plan->size = dft_points; plan->size = dft_points;
plan->init_size = plan->size;
plan->mode = SRSLTE_REAL; plan->mode = SRSLTE_REAL;
plan->dir = dir; plan->dir = dir;
plan->forward = (dir==SRSLTE_DFT_FORWARD)?true:false; plan->forward = (dir==SRSLTE_DFT_FORWARD)?true:false;

@ -40,37 +40,42 @@
#include "srslte/phy/dft/dft_precoding.h" #include "srslte/phy/dft/dft_precoding.h"
/* Create DFT plans for transform precoding */ /* 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)); bzero(q, sizeof(srslte_dft_precoding_t));
if (max_prb <= SRSLTE_MAX_PRB) { if (max_prb <= SRSLTE_MAX_PRB) {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
for (uint32_t i=1;i<=max_prb;i++) { 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); 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); fprintf(stderr, "Error: Creating DFT plan %d\n",i);
goto clean_exit; goto clean_exit;
} }
srslte_dft_plan_set_norm(&q->dft_plan[i], true); 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; q->max_prb = max_prb;
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
clean_exit: clean_exit:
if (ret == SRSLTE_ERROR) { if (ret == SRSLTE_ERROR) {
srslte_dft_precoding_free(q); 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 */ /* 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++) { for (uint32_t i=1;i<=q->max_prb;i++) {
if(srslte_dft_precoding_valid_prb(i)) { if(srslte_dft_precoding_valid_prb(i)) {
srslte_dft_plan_free(&q->dft_plan[i]); srslte_dft_plan_free(&q->dft_plan[i]);
srslte_dft_plan_free(&q->idft_plan[i]);
} }
} }
bzero(q, sizeof(srslte_dft_precoding_t)); 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, 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) { 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; 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;i<nof_symbols;i++) {
srslte_dft_run_c(&q->idft_plan[nof_prb], &input[i*SRSLTE_NRE*nof_prb], &output[i*SRSLTE_NRE*nof_prb]);
}
return SRSLTE_SUCCESS;
}

@ -29,6 +29,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <complex.h> #include <complex.h>
#include <math.h> #include <math.h>
#include <srslte/srslte.h>
#include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/phy_common.h"
#include "srslte/phy/dft/dft.h" #include "srslte/phy/dft/dft.h"
@ -36,7 +37,13 @@
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.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) { 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)) { if (srslte_dft_plan_c(&q->fft_plan, symbol_sz, dir)) {
fprintf(stderr, "Error: Creating DFT plan\n"); 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; 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_mirror(&q->fft_plan, true);
srslte_dft_plan_set_dc(&q->fft_plan, true); srslte_dft_plan_set_dc(&q->fft_plan, true);
q->symbol_sz = (uint32_t) symbol_sz; q->symbol_sz = (uint32_t) symbol_sz;
q->nof_symbols = SRSLTE_CP_NSYMB(cp); q->nof_symbols = SRSLTE_CP_NSYMB(cp);
q->nof_symbols_mbsfn = SRSLTE_CP_NSYMB(SRSLTE_CP_EXT);
q->cp = cp; q->cp = cp;
q->freq_shift = false; q->freq_shift = false;
q->shift_buffer = NULL;
q->nof_re = nof_prb * SRSLTE_NRE; q->nof_re = nof_prb * SRSLTE_NRE;
q->nof_guards = ((symbol_sz - q->nof_re) / 2); q->nof_guards = ((symbol_sz - q->nof_re) / 2);
q->slot_sz = SRSLTE_SLOT_LEN(symbol_sz); 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", 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, 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); 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; return SRSLTE_SUCCESS;
} }
@ -78,30 +127,64 @@ void srslte_ofdm_free_(srslte_ofdm_t *q) {
bzero(q, sizeof(srslte_ofdm_t)); 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); 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); fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1; 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;i<q->nof_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; uint32_t i;
int ret; int ret;
int symbol_sz = srslte_symbol_sz(nof_prb); 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); fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1; 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) { if (ret == SRSLTE_SUCCESS) {
srslte_dft_plan_set_norm(&q->fft_plan, false); 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; 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;i<q->nof_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. /* Shifts the signal after the iFFT or before the FFT.
* Freq_shift is relative to inter-carrier spacing. * Freq_shift is relative to inter-carrier spacing.
* Caution: This function shall not be called during run-time * Caution: This function shall not be called during run-time
*/ */
int srslte_ofdm_set_freq_shift(srslte_ofdm_t *q, float freq_shift) { 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; cf_t *ptr = q->shift_buffer;
for (uint32_t n=0;n<2;n++) { for (uint32_t n=0;n<2;n++) {
for (uint32_t i=0;i<q->nof_symbols;i++) { for (uint32_t i=0;i<q->nof_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); srslte_dft_plan_set_dc(&q->fft_plan, false);
q->freq_shift = true; q->freq_shift = true;
q->freq_shift_f = freq_shift;
return SRSLTE_SUCCESS; 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) { void srslte_ofdm_rx_slot_zerocopy(srslte_ofdm_t *q, cf_t *input, cf_t *output) {
uint32_t i; uint32_t i;
for (i=0;i<q->nof_symbols;i++) { for (i=0;i<q->nof_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) { if (q->freq_shift) {
srslte_vec_prod_ccc(input, q->shift_buffer, input, 2*q->slot_sz); srslte_vec_prod_ccc(input, q->shift_buffer, input, 2*q->slot_sz);
} }
for (n=0;n<2;n++) { if(!q->mbsfn_subframe){
srslte_ofdm_rx_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); 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;i<q->nof_symbols_mbsfn;i++) {
cp_len = ( i>(q->non_mbsfn_region-1) )?SRSLTE_CP_LEN_EXT(q->symbol_sz):SRSLTE_CP_LEN_NORM(i, q->symbol_sz);
memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t));
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) { void srslte_ofdm_set_normalize(srslte_ofdm_t *q, bool normalize_enable) {
srslte_dft_plan_set_norm(&q->fft_plan, 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; uint32_t n;
for (n=0;n<2;n++) { if(!q->mbsfn_subframe){
srslte_ofdm_tx_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]); 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) { if (q->freq_shift) {
srslte_vec_prod_ccc(output, q->shift_buffer, output, 2*q->slot_sz); srslte_vec_prod_ccc(output, q->shift_buffer, output, 2*q->slot_sz);
} }
} }

@ -29,6 +29,8 @@
#include <complex.h> #include <complex.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <srslte/phy/common/phy_common.h>
#include <srslte/srslte.h>
#define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb) #define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb)
@ -39,78 +41,67 @@
#define SRSLTE_ENB_RF_AMP 0.1 #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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL)
srslte_cell_isvalid(&cell))
{ {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_enb_dl_t)); bzero(q, sizeof(srslte_enb_dl_t));
q->cell = cell; q->cfi = 3;
q->cfi = 3;
q->tx_amp = SRSLTE_ENB_RF_AMP; 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"); fprintf(stderr, "Error initiating FFT\n");
goto clean_exit; goto clean_exit;
} }
srslte_ofdm_set_normalize(&q->ifft, true); srslte_ofdm_set_normalize(&q->ifft, true);
if (srslte_regs_init(&q->regs, q->cell)) { if (srslte_pbch_init(&q->pbch)) {
fprintf(stderr, "Error initiating REGs\n");
goto clean_exit;
}
if (srslte_pbch_init(&q->pbch, q->cell)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
goto clean_exit; 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"); fprintf(stderr, "Error creating PCFICH object\n");
goto clean_exit; 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"); fprintf(stderr, "Error creating PHICH object\n");
goto clean_exit; 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"); fprintf(stderr, "Error creating PDCCH object\n");
goto clean_exit; 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"); fprintf(stderr, "Error creating PDSCH object\n");
goto clean_exit; 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); fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
goto clean_exit; goto clean_exit;
} }
for (int i=0;i<q->cell.nof_ports;i++) { for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
q->sf_symbols[i] = srslte_vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); q->sf_symbols[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t));
if (!q->sf_symbols[i]) { if (!q->sf_symbols[i]) {
perror("malloc"); perror("malloc");
goto clean_exit; 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; ret = SRSLTE_SUCCESS;
} else { } else {
fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", fprintf(stderr, "Invalid parameters\n");
cell.id, cell.nof_ports, cell.nof_prb);
} }
clean_exit: clean_exit:
@ -125,12 +116,13 @@ void srslte_enb_dl_free(srslte_enb_dl_t *q)
if (q) { if (q) {
srslte_ofdm_tx_free(&q->ifft); srslte_ofdm_tx_free(&q->ifft);
srslte_regs_free(&q->regs); srslte_regs_free(&q->regs);
srslte_pbch_free(&q->pbch);
srslte_pcfich_free(&q->pcfich); srslte_pcfich_free(&q->pcfich);
srslte_phich_free(&q->phich); srslte_phich_free(&q->phich);
srslte_pdcch_free(&q->pdcch); srslte_pdcch_free(&q->pdcch);
srslte_pdsch_free(&q->pdsch); srslte_pdsch_free(&q->pdsch);
srslte_refsignal_cs_free(&q->csr_signal); srslte_refsignal_free(&q->csr_signal);
for (int i=0;i<SRSLTE_MAX_PORTS;i++) { for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
if (q->sf_symbols[i]) { if (q->sf_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) void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, float amp)
{ {
q->tx_amp = 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], 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, uint16_t rnti, 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)
{ {
/* Configure pdsch_cfg parameters */ /* 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"); fprintf(stderr, "Error configuring PDSCH\n");
return SRSLTE_ERROR; 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; 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;i<q->pdsch_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);
}

@ -39,78 +39,54 @@
#define MAX_CANDIDATES 16 #define MAX_CANDIDATES 16
int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell, int srslte_enb_ul_init(srslte_enb_ul_t *q,
srslte_prach_cfg_t *prach_cfg, uint32_t max_prb)
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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL)
srslte_cell_isvalid(&cell))
{ {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_enb_ul_t)); bzero(q, sizeof(srslte_enb_ul_t));
q->cell = cell; q->users = calloc(sizeof(srslte_enb_ul_user_t*), (1+SRSLTE_SIRNTI));
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);
if (!q->users) { if (!q->users) {
perror("malloc"); perror("malloc");
goto clean_exit; 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"); fprintf(stderr, "Error initiating FFT\n");
goto clean_exit; goto clean_exit;
} }
srslte_ofdm_set_normalize(&q->fft, false); srslte_ofdm_set_normalize(&q->fft, false);
srslte_ofdm_set_freq_shift(&q->fft, -0.5); 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"); fprintf(stderr, "Error creating PUCCH object\n");
goto clean_exit; 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"); fprintf(stderr, "Error creating PUSCH object\n");
goto clean_exit; 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); 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"); fprintf(stderr, "Error initiating channel estimator\n");
goto clean_exit; goto clean_exit;
} }
// Configure common PUCCH configuration q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t));
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));
if (!q->sf_symbols) { if (!q->sf_symbols) {
perror("malloc"); perror("malloc");
goto clean_exit; 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) { if (!q->ce) {
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
@ -119,8 +95,7 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, srslte_cell_t cell,
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} else { } else {
fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", fprintf(stderr, "Invalid parameters\n");
cell.id, cell.nof_ports, cell.nof_prb);
} }
clean_exit: clean_exit:
@ -135,7 +110,7 @@ void srslte_enb_ul_free(srslte_enb_ul_t *q)
if (q) { if (q) {
if (q->users) { if (q->users) {
for (int i=0;i<SRSLTE_SIRNTI;i++) { for (int i=0;i<=SRSLTE_SIRNTI;i++) {
if (q->users[i]) { if (q->users[i]) {
free(q->users[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) int srslte_enb_ul_add_rnti(srslte_enb_ul_t *q, uint16_t rnti)
{ {
if (!q->users[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)) { if (srslte_pucch_set_crnti(&q->pucch, rnti)) {
fprintf(stderr, "Error setting PUCCH rnti\n"); fprintf(stderr, "Error setting PUCCH rnti\n");
return -1; return -1;
@ -183,7 +220,7 @@ void srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint16_t rnti)
if (q->users[rnti]) { if (q->users[rnti]) {
free(q->users[rnti]); free(q->users[rnti]);
q->users[rnti] = NULL; q->users[rnti] = NULL;
srslte_pusch_clear_rnti(&q->pusch, rnti); srslte_pusch_free_rnti(&q->pusch, rnti);
} }
} }

@ -117,7 +117,7 @@ int main(int argc, char **argv) {
float *llr; float *llr;
short *llr_s; short *llr_s;
uint8_t *llr_c; 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; uint32_t i, j;
float var[SNR_POINTS]; float var[SNR_POINTS];
uint32_t snr_points; uint32_t snr_points;
@ -159,7 +159,7 @@ int main(int argc, char **argv) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
for (int cb=0;cb<SRSLTE_TDEC_NPAR;cb++) { for (int cb=0;cb<SRSLTE_TDEC_MAX_NPAR;cb++) {
data_rx_bytes[cb] = srslte_vec_malloc(frame_length * sizeof(uint8_t)); data_rx_bytes[cb] = srslte_vec_malloc(frame_length * sizeof(uint8_t));
if (!data_rx_bytes[cb]) { if (!data_rx_bytes[cb]) {
perror("malloc"); perror("malloc");
@ -254,10 +254,10 @@ int main(int argc, char **argv) {
t = nof_iterations; t = nof_iterations;
} }
int16_t *input[SRSLTE_TDEC_NPAR]; int16_t *input[SRSLTE_TDEC_MAX_NPAR];
uint8_t *output[SRSLTE_TDEC_NPAR]; uint8_t *output[SRSLTE_TDEC_MAX_NPAR];
for (int n=0;n<SRSLTE_TDEC_NPAR;n++) { for (int n=0;n<SRSLTE_TDEC_MAX_NPAR;n++) {
if (n < nof_cb) { if (n < nof_cb) {
input[n] = llr_s; input[n] = llr_s;
} else { } else {

@ -43,7 +43,7 @@
int srslte_tdec_init(srslte_tdec_t * h, uint32_t max_long_cb) { int srslte_tdec_init(srslte_tdec_t * h, uint32_t max_long_cb) {
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_tdec_simd_init(&h->tdec_simd, SRSLTE_TDEC_NPAR, max_long_cb); return srslte_tdec_simd_init(&h->tdec_simd, SRSLTE_TDEC_MAX_NPAR, max_long_cb);
#else #else
h->input_conv = srslte_vec_malloc(sizeof(float) * (3*max_long_cb+12)); h->input_conv = srslte_vec_malloc(sizeof(float) * (3*max_long_cb+12));
if (!h->input_conv) { if (!h->input_conv) {
@ -91,7 +91,7 @@ int srslte_tdec_get_nof_iterations_cb(srslte_tdec_t * h, uint32_t cb_idx)
#endif #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 #ifdef LV_HAVE_SSE
srslte_tdec_simd_iteration(&h->tdec_simd, input, long_cb); srslte_tdec_simd_iteration(&h->tdec_simd, input, long_cb);
#else #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) { 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; input_par[0] = input;
return srslte_tdec_iteration_par(h, input_par, long_cb); 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 #ifdef LV_HAVE_SSE
return srslte_tdec_simd_decision(&h->tdec_simd, output, long_cb); return srslte_tdec_simd_decision(&h->tdec_simd, output, long_cb);
#else #else
@ -114,13 +114,21 @@ void srslte_tdec_decision_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_NPA
#endif #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) { 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; output_par[0] = output;
srslte_tdec_decision_par(h, output_par, long_cb); 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 #ifdef LV_HAVE_SSE
srslte_tdec_simd_decision_byte(&h->tdec_simd, output, long_cb); srslte_tdec_simd_decision_byte(&h->tdec_simd, output, long_cb);
#else #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) { 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; output_par[0] = output;
srslte_tdec_decision_byte_par(h, output_par, long_cb); 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], int srslte_tdec_run_all_par(srslte_tdec_t * h, int16_t * input[SRSLTE_TDEC_MAX_NPAR],
uint8_t *output[SRSLTE_TDEC_NPAR], uint8_t *output[SRSLTE_TDEC_MAX_NPAR],
uint32_t nof_iterations, uint32_t long_cb) { uint32_t nof_iterations, uint32_t long_cb) {
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_tdec_simd_run_all(&h->tdec_simd, input, output, nof_iterations, long_cb); 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) 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; output_par[0] = output;
int16_t *input_par[SRSLTE_TDEC_NPAR]; int16_t *input_par[SRSLTE_TDEC_MAX_NPAR];
input_par[0] = input; input_par[0] = input;
return srslte_tdec_run_all_par(h, input_par, output_par, nof_iterations, long_cb); return srslte_tdec_run_all_par(h, input_par, output_par, nof_iterations, long_cb);

@ -81,7 +81,7 @@ static inline int16_t hMax1(__m256i masked_value)
} }
/* Computes beta values */ /* 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; int k;
uint32_t end = long_cb + 3; uint32_t end = long_cb + 3;

@ -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); 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 #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_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); 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 #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) { if (nof_cb == 1) {
map_sse_beta(s, output[0], long_cb); 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 */ /* 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], 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_NPAR], uint32_t cb_mask, uint32_t long_cb) int16_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t cb_mask, uint32_t long_cb)
{ {
uint32_t nof_cb = 1; uint32_t nof_cb = 1;
int16_t *outptr[SRSLTE_TDEC_NPAR]; int16_t *outptr[SRSLTE_TDEC_MAX_NPAR];
// Compute branch metrics // Compute branch metrics
switch(cb_mask) { 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 */ /* 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) { if (h->current_cbidx >= 0) {
uint16_t *inter = h->interleaver[h->current_cbidx].forward; uint16_t *inter = h->interleaver[h->current_cbidx].forward;
uint16_t *deinter = h->interleaver[h->current_cbidx].reverse; uint16_t *deinter = h->interleaver[h->current_cbidx].reverse;
#if SRSLTE_TDEC_NPAR == 2 #ifndef LV_HAVE_AVX2
h->cb_mask = (input[0]?1:0) | (input[1]?2:0); input[1] = NULL;
#else
h->cb_mask = input[0]?1:0;
#endif #endif
h->cb_mask = (input[0]?1:0) | (input[1]?2:0);
for (int i=0;i<h->max_par_cb;i++) { for (int i=0;i<h->max_par_cb;i++) {
if (h->n_iter[i] == 0 && input[i]) { if (h->n_iter[i] == 0 && input[i]) {
//printf("deinterleaveing %d\n",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;i<h->max_par_cb;i++) { for (int i=0;i<h->max_par_cb;i++) {
tdec_simd_decision(h, output[i], i, long_cb); 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;i<h->max_par_cb;i++) { for (int i=0;i<h->max_par_cb;i++) {
srslte_tdec_simd_decision_byte_cb(h, output[i], i, long_cb); 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 */ /* 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) uint32_t nof_iterations, uint32_t long_cb)
{ {
if (srslte_tdec_simd_reset(h, long_cb)) { if (srslte_tdec_simd_reset(h, long_cb)) {

@ -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) { 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<nof_cb;i++) { for (int i=0;i<nof_cb;i++) {
srslte_tdec_simd_inter_decision_cb(h, output[i], i, long_cb); srslte_tdec_simd_inter_decision_cb(h, output[i], i, long_cb);
@ -269,7 +269,7 @@ void srslte_tdec_simd_inter_decision_byte_cb(srslte_tdec_simd_inter_t * h, uint8
} }
} }
void srslte_tdec_simd_inter_decision_byte(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_byte(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<nof_cb;i++) { for (int i=0;i<nof_cb;i++) {
srslte_tdec_simd_inter_decision_byte_cb(h, output[i], i, long_cb); srslte_tdec_simd_inter_decision_byte_cb(h, output[i], i, long_cb);
@ -277,7 +277,7 @@ void srslte_tdec_simd_inter_decision_byte(srslte_tdec_simd_inter_t * h, uint8_t
} }
int srslte_tdec_simd_inter_run_all(srslte_tdec_simd_inter_t * h, 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) uint32_t nof_iterations, uint32_t nof_cb, uint32_t long_cb)
{ {
uint32_t iter = 0; uint32_t iter = 0;

@ -36,16 +36,15 @@
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
#include <immintrin.h> #include <immintrin.h>
#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_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); 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 #endif
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
#include <immintrin.h> #include <immintrin.h>
#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); 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 #endif
#include "srslte/phy/utils/mat.h"
static srslte_mimo_decoder_t mimo_decoder = SRSLTE_MIMO_DECODER_MMSE; 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, int nof_rxant, int nof_ports, int nof_layers, int codebook_idx, int nof_symbols,
float noise_estimate) float noise_estimate)
{ {
if (nof_ports == 2 && nof_rxant == 2) { if (nof_ports == 2 && nof_rxant <= 2) {
if (nof_layers == 2) { if (nof_layers == 2) {
switch (mimo_decoder) { switch (mimo_decoder) {
case SRSLTE_MIMO_DECODER_ZF: 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) { } else if (nof_ports == 4) {
ERROR("Error predecoding multiplex: not implemented for %d Tx ports", nof_ports); ERROR("Error predecoding multiplex: not implemented for %d Tx ports", nof_ports);
} else { } 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; return SRSLTE_ERROR;
} }

@ -32,6 +32,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <srslte/srslte.h>
#include <srslte/phy/common/phy_common.h>
#include "prb_dl.h" #include "prb_dl.h"
#include "srslte/phy/phch/pbch.h" #include "srslte/phy/phch/pbch.h"
@ -43,7 +45,6 @@
#define PBCH_RE_CP_NORM 240 #define PBCH_RE_CP_NORM 240
#define PBCH_RE_CP_EXT 216 #define PBCH_RE_CP_EXT 216
const uint8_t srslte_crc_mask[4][16] = { const uint8_t srslte_crc_mask[4][16] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 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 }, { 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 * At the receiver, the field nof_ports in the cell structure indicates the
* maximum number of BS transmitter ports to look for. * 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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL)
srslte_cell_isvalid(&cell))
{ {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_pbch_t)); 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)) { if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
goto clean; goto clean;
} }
if (srslte_sequence_pbch(&q->seq, q->cell.cp, q->cell.id)) {
goto clean;
}
int poly[3] = { 0x6D, 0x4F, 0x57 }; int poly[3] = { 0x6D, 0x4F, 0x57 };
if (srslte_viterbi_init(&q->decoder, SRSLTE_VITERBI_37, poly, 40, true)) { if (srslte_viterbi_init(&q->decoder, SRSLTE_VITERBI_37, poly, 40, true)) {
goto clean; goto clean;
@ -178,12 +164,14 @@ int srslte_pbch_init(srslte_pbch_t *q, srslte_cell_t cell) {
q->encoder.tail_biting = true; q->encoder.tail_biting = true;
memcpy(q->encoder.poly, poly, 3 * sizeof(int)); 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); q->d = srslte_vec_malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->d) { if (!q->d) {
goto clean; goto clean;
} }
int i; 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); q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->ce[i]) { if (!q->ce[i]) {
goto clean; goto clean;
@ -209,6 +197,7 @@ int srslte_pbch_init(srslte_pbch_t *q, srslte_cell_t cell) {
if (!q->rm_b) { if (!q->rm_b) {
goto clean; goto clean;
} }
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
clean: clean:
@ -219,11 +208,11 @@ clean:
} }
void srslte_pbch_free(srslte_pbch_t *q) { void srslte_pbch_free(srslte_pbch_t *q) {
if (q->d) { srslte_sequence_free(&q->seq);
free(q->d); srslte_modem_table_free(&q->mod);
} srslte_viterbi_free(&q->decoder);
int i; int i;
for (i = 0; i < q->cell.nof_ports; i++) { for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
if (q->ce[i]) { if (q->ce[i]) {
free(q->ce[i]); free(q->ce[i]);
} }
@ -243,12 +232,36 @@ void srslte_pbch_free(srslte_pbch_t *q) {
if (q->rm_b) { if (q->rm_b) {
free(q->rm_b); free(q->rm_b);
} }
srslte_sequence_free(&q->seq); if (q->d) {
srslte_modem_table_free(&q->mod); free(q->d);
srslte_viterbi_free(&q->decoder); }
bzero(q, sizeof(srslte_pbch_t)); 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 { } else {
nant = q->cell.nof_ports; nant = q->cell.nof_ports;
} }
do { do {
if (nant != 3) { if (nant != 3) {
DEBUG("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); 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); srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate);
} else { } else {
srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant, 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); 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) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols);
srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, 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 { } else {
memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t));
} }

@ -57,38 +57,24 @@ bool srslte_pcfich_exists(int nframe, int nslot) {
return true; 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. /** Initializes the pcfich channel receiver.
* On error, returns -1 and frees the structrure * 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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL)
regs != NULL &&
srslte_cell_isvalid(&cell))
{ {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_pcfich_t)); bzero(q, sizeof(srslte_pcfich_t));
q->cell = cell; q->nof_rx_antennas = nof_rx_antennas;
q->regs = regs;
q->nof_symbols = PCFICH_RE; q->nof_symbols = PCFICH_RE;
q->nof_rx_antennas = nof_rx_antennas;
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
goto clean; 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 */ /* convert cfi bit tables to floats for demodulation */
for (int i=0;i<3;i++) { for (int i=0;i<3;i++) {
for (int j=0;j<PCFICH_CFI_LEN;j++) { for (int j=0;j<PCFICH_CFI_LEN;j++) {
@ -115,6 +101,28 @@ void srslte_pcfich_free(srslte_pcfich_t *q) {
bzero(q, sizeof(srslte_pcfich_t)); bzero(q, sizeof(srslte_pcfich_t));
} }
int srslte_pcfich_set_cell(srslte_pcfich_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_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. /** 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. * 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]; q_symbols[j] = q->symbols[j];
/* extract channel estimates */ /* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) { 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])) { if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, ce[i][j], q->ce[i][j])) {

@ -61,41 +61,20 @@ float srslte_pdcch_coderate(uint32_t nof_bits, uint32_t l) {
} }
/** Initializes the PDCCH transmitter and receiver */ /** Initializes the PDCCH transmitter and receiver */
int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) { static int pdcch_init(srslte_pdcch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas, bool is_ue)
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)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL)
regs != NULL &&
srslte_cell_isvalid(&cell))
{ {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_pdcch_t)); bzero(q, sizeof(srslte_pdcch_t));
q->cell = cell; q->nof_rx_antennas = nof_rx_antennas;
q->regs = regs; q->is_ue = is_ue;
q->nof_rx_antennas = nof_rx_antennas;
/* Allocate memory for the maximum number of PDCCH bits (CFI=3) */ /* 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", INFO("Init PDCCH: Max bits: %d\n", q->max_bits);
q->max_bits, q->cell.nof_ports);
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
goto clean; goto clean;
@ -104,14 +83,6 @@ int srslte_pdcch_init_txrx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t
goto clean; 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 }; int poly[3] = { 0x6D, 0x4F, 0x57 };
if (srslte_viterbi_init(&q->decoder, SRSLTE_VITERBI_37, poly, SRSLTE_DCI_MAX_BITS + 16, true)) { if (srslte_viterbi_init(&q->decoder, SRSLTE_VITERBI_37, poly, SRSLTE_DCI_MAX_BITS + 16, true)) {
goto clean; goto clean;
@ -134,29 +105,23 @@ int srslte_pdcch_init_txrx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t
goto clean; 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++) { for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->x[i]) { if (!q->x[i]) {
goto clean; goto clean;
} }
} q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->symbols[i]) {
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]) {
goto clean; 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; 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; 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) { void srslte_pdcch_free(srslte_pdcch_t *q) {
if (q->e) { if (q->e) {
@ -180,18 +153,18 @@ void srslte_pdcch_free(srslte_pdcch_t *q) {
free(q->d); free(q->d);
} }
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->ce[i][j]) {
free(q->ce[i][j]);
}
}
if (q->x[i]) { if (q->x[i]) {
free(q->x[i]); free(q->x[i]);
} }
} if (q->symbols[i]) {
for (int j=0;j<q->nof_rx_antennas;j++) { free(q->symbols[i]);
if (q->symbols[j]) { }
free(q->symbols[j]); if (q->is_ue) {
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->ce[i][j]) {
free(q->ce[i][j]);
}
}
} }
} }
for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { 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 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) 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 */ /* descramble */
srslte_scrambling_f_offset(&q->seq[nsubframe], q->llr, 0, e_bits); srslte_scrambling_f_offset(&q->seq[nsubframe], q->llr, 0, e_bits);
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
return ret; return ret;

@ -27,17 +27,11 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <assert.h>
#include <math.h>
#include "prb_dl.h" #include "prb_dl.h"
#include "srslte/phy/phch/pdsch.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/debug.h"
#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/vector.h"
@ -45,7 +39,6 @@
#define MAX_PDSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) #define MAX_PDSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12)
const static srslte_mod_t modulations[4] = const static srslte_mod_t modulations[4] =
{ SRSLTE_MOD_BPSK, SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, SRSLTE_MOD_64QAM }; { 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); return srslte_pdsch_cp(q, sf_symbols, symbols, grant, lstart, subframe, false);
} }
/** Initializes the PDCCH transmitter or receiver */ /** Initializes the PDSCH transmitter and receiver */
int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas, bool is_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 ret = SRSLTE_ERROR_INVALID_INPUTS;
int i;
if (q != NULL && if (q != NULL)
srslte_cell_isvalid(&cell) && {
nof_antennas <= SRSLTE_MAX_PORTS)
{
bzero(q, sizeof(srslte_pdsch_t)); bzero(q, sizeof(srslte_pdsch_t));
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
q->cell = cell; q->max_re = max_prb * MAX_PDSCH_RE(q->cell.cp);
q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); q->is_ue = is_ue;
if (is_receiver) { q->nof_rx_antennas = nof_antennas;
q->nof_rx_antennas = nof_antennas;
}
INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, INFO("Init PDSCH: %d PRBs, max_symbols: %d\n", max_prb, q->max_re);
q->cell.nof_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])) { if (srslte_modem_table_lte(&q->mod[i], modulations[i])) {
goto clean; goto clean;
} }
@ -232,7 +219,7 @@ int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antenn
goto clean; 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) // 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)); q->e[i] = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
if (!q->e[i]) { 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 (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (i = 0; i < q->cell.nof_ports; i++) {
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->x[i]) { if (!q->x[i]) {
goto clean; goto clean;
} }
} q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->symbols[i]) {
/* If it is the receiver side, allocate estimated channel */ goto clean;
if (is_receiver) { }
for (i = 0; i < q->cell.nof_ports; i++) { if (q->is_ue) {
for (int j = 0; j < q->nof_rx_antennas; j++) { for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->ce[i][j]) { if (!q->ce[i][j]) {
goto clean; 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;j<SRSLTE_MAX(q->nof_rx_antennas, q->cell.nof_ports);j++) {
q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); q->users = calloc(sizeof(srslte_pdsch_user_t*), q->is_ue?1:(1+SRSLTE_SIRNTI));
if (!q->symbols[j]) {
goto clean;
}
}
/* Allocate User memory (all zeros) */
q->users = calloc(sizeof(srslte_pdsch_user_t*), 1+SRSLTE_SIRNTI);
if (!q->users) { if (!q->users) {
perror("malloc"); perror("malloc");
goto clean; 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) { if (ret == SRSLTE_ERROR) {
srslte_pdsch_free(q); srslte_pdsch_free(q);
} }
return ret; return ret;
} }
int srslte_pdsch_init_tx(srslte_pdsch_t *q, srslte_cell_t cell) { int srslte_pdsch_init_ue(srslte_pdsch_t *q, uint32_t max_prb, uint32_t nof_antennas)
return srslte_pdsch_init(q, cell, 0, false); {
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) { int srslte_pdsch_init_enb(srslte_pdsch_t *q, uint32_t max_prb)
return srslte_pdsch_init(q, cell, nof_antennas, true); {
return pdsch_init(q, max_prb, false, 0);
} }
void srslte_pdsch_free(srslte_pdsch_t *q) { 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]) { if (q->e[i]) {
free(q->e[i]); free(q->e[i]);
@ -313,69 +297,107 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
/* Free sch objects */ /* Free sch objects */
srslte_sch_free(&q->dl_sch); 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]) { if (q->x[i]) {
free(q->x[i]); free(q->x[i]);
} }
for (int j=0;j<q->nof_rx_antennas;j++) { if (q->symbols[i]) {
if (q->ce[i][j]) { free(q->symbols[i]);
free(q->ce[i][j]); }
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;j<SRSLTE_MAX_PORTS;j++) {
if (q->symbols[j]) {
free(q->symbols[j]);
}
}
if (q->users) { if (q->users) {
for (uint16_t u=0;u<SRSLTE_SIRNTI;u++) { if (q->is_ue) {
if (q->users[u]) { srslte_pdsch_free_rnti(q, 0);
srslte_pdsch_free_rnti(q, u); } else {
for (int u=0;u<=SRSLTE_SIRNTI;u++) {
if (q->users[u]) {
srslte_pdsch_free_rnti(q, u);
}
} }
} }
free(q->users); 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]); srslte_modem_table_free(&q->mod[i]);
} }
bzero(q, sizeof(srslte_pdsch_t)); 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. * 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) { int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) {
uint32_t i, j; uint32_t rnti_idx = q->is_ue?0:rnti;
if (!q->users[rnti]) {
q->users[rnti] = calloc(1, sizeof(srslte_pdsch_user_t)); if (!q->users[rnti_idx] || q->is_ue) {
if (q->users[rnti]) { if (!q->users[rnti_idx]) {
for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { q->users[rnti_idx] = calloc(1, sizeof(srslte_pdsch_user_t));
for (j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { if(!q->users[rnti_idx]) {
if (srslte_sequence_pdsch(&q->users[rnti]->seq[j][i], rnti, j, 2 * i, q->cell.id, perror("calloc");
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { return -1;
ERROR("Generating scrambling sequence"); }
return SRSLTE_ERROR; }
} 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; return SRSLTE_SUCCESS;
} }
void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) 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 i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { 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]); free(q->users[rnti_idx]);
q->users[rnti] = NULL; 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; break;
} }
DEBUG("SAVED FILE %s: received subframe symbols\n", filename); 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++) { for (int i = 0; i < q->cell.nof_ports; i++) {
if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) { 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)); 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); for (int i=0;i<cfg->nof_layers;i++) {
srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits[0].nof_re*sizeof(cf_t)); 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); if (snprintf(filename, FILENAME_MAX, "llr_%d.dat", i) < 0) {
srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); 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, 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 sf_idx, int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type,
uint32_t pmi) { uint32_t pmi) {
if (cfg) { if (cfg && grant) {
if (grant) { uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant);
memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t)); 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)) { for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) {
fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs[i].tbs); if (grant->tb_en[cw]) {
return SRSLTE_ERROR; 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); 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 */ /* Check and configure PDSCH transmission modes */
switch(mimo_type) { switch(mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (grant->nof_tb != 1) { if (nof_tb != 1) {
ERROR("Number of transport blocks is not supported for single transmission mode."); ERROR("Wrong number of transport blocks (%d) for single antenna.", nof_tb);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
cfg->nof_layers = 1; cfg->nof_layers = 1;
break; break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY: case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (grant->nof_tb != 1) { if (nof_tb != 1) {
ERROR("Number of transport blocks is not supported for transmit diversity mode."); ERROR("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
cfg->nof_layers = 2; cfg->nof_layers = 2;
break; break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
if (grant->nof_tb == 1) { if (nof_tb == 1) {
cfg->codebook_idx = pmi; cfg->codebook_idx = pmi;
cfg->nof_layers = 1; cfg->nof_layers = 1;
} else { } else if (nof_tb == 2) {
cfg->codebook_idx = pmi + 1; cfg->codebook_idx = pmi + 1;
cfg->nof_layers = 2; 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", 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; break;
case SRSLTE_MIMO_TYPE_CDD: case SRSLTE_MIMO_TYPE_CDD:
if (grant->nof_tb != 2) { if (nof_tb != 2) {
ERROR("Number of transport blocks (%d) is not supported for CDD transmission mode.", grant->nof_tb); ERROR("Wrong number of transport blocks (%d) for CDD.", nof_tb);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
cfg->nof_layers = 2; 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, srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data,
uint32_t codeword_idx) { uint32_t codeword_idx) {
srslte_ra_nbits_t *nbits = &cfg->nbits[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); nbits->nof_re, nbits->nof_bits, rv);
/* Channel coding */ /* 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); ERROR("Error encoding TB %d", codeword_idx);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
/* Bit scrambling */ /* Select scrambling sequence */
if (!pdsch->users[rnti]) { srslte_sequence_t *seq = get_user_sequence(q, rnti, codeword_idx, cfg->sf_idx, nbits->nof_bits);
srslte_sequence_t seq;
if (srslte_sequence_pdsch(&seq, rnti, codeword_idx, 2 * cfg->sf_idx, pdsch->cell.id, nbits->nof_bits)) { /* Bit scrambling */
ERROR("Initialising scrambling sequence"); srslte_scrambling_bytes(seq, (uint8_t *) q->e[codeword_idx], nbits->nof_bits);
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 mapping */ /* Bit mapping */
srslte_mod_modulate_bytes(&pdsch->mod[mcs->mod], srslte_mod_modulate_bytes(&q->mod[mcs->mod],
(uint8_t *) pdsch->e[codeword_idx], (uint8_t *) q->e[codeword_idx],
pdsch->d[codeword_idx], nbits->nof_bits); q->d[codeword_idx], nbits->nof_bits);
} }
return SRSLTE_SUCCESS; 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, 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_nbits_t *nbits = &cfg->nbits[codeword_idx];
srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx];
uint32_t rv = cfg->rv[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", 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, cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs,
nbits->nof_re, nbits->nof_bits, rv); 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, * 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 * 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) { /* Select scrambling sequence */
srslte_scrambling_s_offset(&pdsch->users[rnti]->seq[codeword_idx][cfg->sf_idx], pdsch->e[codeword_idx], srslte_sequence_t *seq = get_user_sequence(q, rnti, codeword_idx, cfg->sf_idx, nbits->nof_bits);
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);
}
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 /** Decodes the PDSCH from the received symbols
@ -585,9 +636,10 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
data != NULL && data != NULL &&
cfg != 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", 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 // Extract Symbols and Channel Estimates
for (int j=0;j<q->nof_rx_antennas;j++) { for (int j=0;j<q->nof_rx_antennas;j++) {
@ -608,10 +660,10 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
// Prepare layers // Prepare layers
int nof_symbols [SRSLTE_MAX_CODEWORDS]; int nof_symbols [SRSLTE_MAX_CODEWORDS];
nof_symbols[0] = cfg->nbits[0].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 * cfg->grant.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 */ /* Skip layer demap */
for (i = 0; i < cfg->nof_layers; i++) { for (i = 0; i < cfg->nof_layers; i++) {
x[i] = q->d[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); cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate);
// Layer demapping only if necessary // Layer demapping only if necessary
if (cfg->nof_layers != cfg->grant.nof_tb) { if (cfg->nof_layers != nof_tb) {
srslte_layerdemap_type(x, q->d, cfg->nof_layers, cfg->grant.nof_tb, srslte_layerdemap_type(x, q->d, cfg->nof_layers, nof_tb,
nof_symbols[0], nof_symbols, cfg->mimo_type); nof_symbols[0], nof_symbols, cfg->mimo_type);
} }
// Codeword decoding // Codeword decoding
for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) {
int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb); /* Decode only if transport block is enabled and the default ACK is not true */
acks[tb] = (ret == SRSLTE_SUCCESS); 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); pdsch_decode_debug(q, cfg, sf_symbols, ce);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} else { } else {
return SRSLTE_ERROR_INVALID_INPUTS; 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, 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]) { 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) { if (q->cell.nof_ports == 2 && q->nof_rx_antennas <= 2) {
for (int nof_layers = 1; nof_layers <= 2; nof_layers++ ) { int nof_layers = 1;
for (; nof_layers <= q->nof_rx_antennas; nof_layers++ ) {
if (sinr[nof_layers - 1] && pmi) { if (sinr[nof_layers - 1] && pmi) {
if (srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, nof_layers, &pmi[nof_layers - 1], if (srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, nof_layers, &pmi[nof_layers - 1],
sinr[nof_layers - 1]) < 0) { 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 { } else {
ERROR("Not implemented configuration"); ERROR("Not implemented configuration");
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
@ -689,6 +757,8 @@ int srslte_pdsch_encode(srslte_pdsch_t *q,
if (q != NULL && if (q != NULL &&
cfg != NULL) { cfg != NULL) {
uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant);
for (i = 0; i < q->cell.nof_ports; i++) { for (i = 0; i < q->cell.nof_ports; i++) {
if (sf_symbols[i] == NULL) { if (sf_symbols[i] == NULL) {
@ -708,15 +778,17 @@ int srslte_pdsch_encode(srslte_pdsch_t *q,
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) {
ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb], rnti, data[tb], 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 // Layer mapping & precode if necessary
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
int nof_symbols; int nof_symbols;
/* If number of layers is equal to transport blocks (codewords) skip layer mapping */ /* 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++) { for (i = 0; i < cfg->nof_layers; i++) {
x[i] = q->d[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)); 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}, (int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits[0].nof_re, cfg->nbits[1].nof_re},
cfg->mimo_type); 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); srslte_sch_set_max_noi(&q->dl_sch, max_iter);
} }
float srslte_pdsch_average_noi(srslte_pdsch_t *q) { float srslte_pdsch_last_noi(srslte_pdsch_t *q) {
return q->dl_sch.average_nof_iterations; return srslte_pdsch_last_noi_cw(q, 0);
} }
uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q) { uint32_t srslte_pdsch_last_noi_cw(srslte_pdsch_t *q, uint32_t cw_idx) {
return q->dl_sch.nof_iterations; return q->last_nof_iterations[cw_idx];
} }

@ -32,6 +32,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <srslte/phy/common/phy_common.h>
#include "srslte/phy/phch/regs.h" #include "srslte/phy/phch/regs.h"
#include "srslte/phy/phch/phich.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 */ /** 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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL)
regs != NULL &&
srslte_cell_isvalid(&cell))
{ {
bzero(q, sizeof(srslte_phich_t)); bzero(q, sizeof(srslte_phich_t));
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
q->cell = cell; q->nof_rx_antennas = nof_rx_antennas;
q->regs = regs;
q->nof_rx_antennas = nof_rx_antennas;
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_BPSK)) { if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_BPSK)) {
goto clean; 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; ret = SRSLTE_SUCCESS;
} }
clean: clean:
@ -114,9 +100,34 @@ void srslte_phich_free(srslte_phich_t *q) {
srslte_modem_table_free(&q->mod); srslte_modem_table_free(&q->mod);
bzero(q, sizeof(srslte_phich_t)); 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 */ /* 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, void srslte_phich_calc(srslte_phich_t *q, uint32_t n_prb_lowest, uint32_t n_dmrs,
uint32_t *ngroup, uint32_t *nseq) 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)); 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, int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS],
uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) 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) {
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;i<q->cell.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)
{
/* Set pointers for layermapping & precoding */ /* Set pointers for layermapping & precoding */
int i, j; int i, j;

@ -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 <stdint.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <math.h>
#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;j<q->nof_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;j<q->nof_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;j<q->nof_rx_antennas;j++) {
if (q->ce[i][j]) {
free(q->ce[i][j]);
}
}
}
for (i=0;i<q->nof_rx_antennas;i++) {
if (q->symbols[i]) {
free(q->symbols[i]);
}
}
if (q->seqs) {
for (i=0; i<SRSLTE_MAX_MBSFN_AREA_IDS; i++) {
if (q->seqs[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;i<q->cell.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;j<q->nof_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;i<q->cell.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;
}

@ -26,6 +26,7 @@
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <srslte/srslte.h>
#include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/phy_common.h"
#include "srslte/phy/phch/prach.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 // 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}; 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 // 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}; 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) 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), srslte_symbol_sz(nof_prb),
cfg->config_idx, cfg->config_idx,
cfg->root_seq_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); cfg->zero_corr_zone);
} }
int srslte_prach_init(srslte_prach_t *p, int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul)
uint32_t N_ifft_ul, {
uint32_t config_idx, int ret = SRSLTE_ERROR;
uint32_t root_seq_index, if(p != NULL &&
bool high_speed_flag, max_N_ifft_ul < 2049)
uint32_t zero_corr_zone_config) {
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; int ret = SRSLTE_ERROR;
if(p != NULL && if(p != NULL &&
N_ifft_ul < 2049 && N_ifft_ul < 2049 &&
config_idx < 64 && config_idx < 64 &&
root_seq_index < MAX_ROOTS) 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); 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->f = preamble_format;
p->rsi = root_seq_index; p->rsi = root_seq_index;
p->hs = high_speed_flag; p->hs = high_speed_flag;
p->zczc = zero_corr_zone_config; p->zczc = zero_corr_zone_config;
p->detect_factor = PRACH_DETECT_FACTOR; p->detect_factor = PRACH_DETECT_FACTOR;
// Determine N_zc and N_cs // Determine N_zc and N_cs
if(4 == preamble_format){ if(4 == preamble_format){
if (p->zczc < 7) { if (p->zczc < 7) {
@ -368,43 +441,33 @@ int srslte_prach_init(srslte_prach_t *p,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
}else{ }else{
p->N_zc = 839; p->N_zc = MAX_N_zc;
if(p->hs){ if(p->hs){
if (p->zczc < 15) { if (p->zczc < 15) {
p->N_cs = prach_Ncs_restricted[p->zczc]; p->N_cs = prach_Ncs_restricted[p->zczc];
} else { } else {
fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d for restricted set\n", p->zczc); fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d for restricted set\n", p->zczc);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
}else{ }else{
if (p->zczc < 16) { if (p->zczc < 16) {
p->N_cs = prach_Ncs_unrestricted[p->zczc]; p->N_cs = prach_Ncs_unrestricted[p->zczc];
} else { } else {
fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d\n", p->zczc); fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d\n", p->zczc);
return SRSLTE_ERROR; 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 // Set up ZC FFTS
p->zc_fft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); if (p->N_zc != MAX_N_zc) {
if(srslte_dft_plan(p->zc_fft, p->N_zc, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)){ if(srslte_dft_replan(&p->zc_fft, p->N_zc)){
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
srslte_dft_plan_set_mirror(p->zc_fft, false); if(srslte_dft_replan(&p->zc_ifft, p->N_zc)){
srslte_dft_plan_set_norm(p->zc_fft, true); return SRSLTE_ERROR;
}
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;
} }
srslte_dft_plan_set_mirror(p->zc_ifft, false);
srslte_dft_plan_set_norm(p->zc_ifft, false);
// Generate our 64 sequences // Generate our 64 sequences
p->N_roots = 0; p->N_roots = 0;
@ -412,9 +475,9 @@ int srslte_prach_init(srslte_prach_t *p,
// Generate sequence FFTs // Generate sequence FFTs
for(int i=0;i<N_SEQS;i++){ for(int i=0;i<N_SEQS;i++){
srslte_dft_run(p->zc_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 // Create our FFT objects and buffers
p->N_ifft_ul = N_ifft_ul; p->N_ifft_ul = N_ifft_ul;
if(4 == preamble_format){ if(4 == preamble_format){
@ -422,47 +485,31 @@ int srslte_prach_init(srslte_prach_t *p,
}else{ }else{
p->N_ifft_prach = p->N_ifft_ul * DELTA_F/DELTA_F_RA; 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 /* The deadzone specifies the number of samples at the end of the correlation window
* that will be considered as belonging to the next preamble * that will be considered as belonging to the next preamble
*/ */
p->deadzone = 0; p->deadzone = 0;
/* /*
if(p->N_cs != 0) { if(p->N_cs != 0) {
float samp_rate=15000*p->N_ifft_ul; float samp_rate=15000*p->N_ifft_ul;
p->deadzone = (uint32_t) ceil((float) samp_rate/((float) p->N_zc*subcarrier_spacing)); 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)); if(srslte_dft_replan(&p->ifft, p->N_ifft_prach)) {
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)) {
fprintf(stderr, "Error creating DFT plan\n"); fprintf(stderr, "Error creating DFT plan\n");
return -1; return -1;
} }
srslte_dft_plan_set_mirror(p->ifft, true); if(srslte_dft_replan(&p->fft, p->N_ifft_prach)){
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)){
fprintf(stderr, "Error creating DFT plan\n"); fprintf(stderr, "Error creating DFT plan\n");
return -1; 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_seq = prach_Tseq[p->f]*p->N_ifft_ul/2048;
p->N_cp = prach_Tcp[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_seq = prach_Tseq[p->f]*SRSLTE_LTE_TS;
p->T_tot = (prach_Tseq[p->f]+prach_Tcp[p->f])*SRSLTE_LTE_TS; p->T_tot = (prach_Tseq[p->f]+prach_Tcp[p->f])*SRSLTE_LTE_TS;
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} else { } else {
fprintf(stderr, "Invalid parameters\n"); 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)); 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)); 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 // Copy CP into buffer
memcpy(signal, &p->ifft_out[p->N_ifft_prach-p->N_cp], p->N_cp*sizeof(cf_t)); 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 // FFT incoming signal
srslte_dft_run(p->fft, signal, p->signal_fft); srslte_dft_run(&p->fft, signal, p->signal_fft);
*n_indices = 0; *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_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); 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->prach_bins);
free(p->corr_spec); free(p->corr_spec);
free(p->corr); free(p->corr);
srslte_dft_plan_free(p->ifft); srslte_dft_plan_free(&p->ifft);
free(p->ifft);
free(p->ifft_in); free(p->ifft_in);
free(p->ifft_out); free(p->ifft_out);
srslte_dft_plan_free(p->fft); srslte_dft_plan_free(&p->fft);
free(p->fft); srslte_dft_plan_free(&p->zc_fft);
srslte_dft_plan_free(p->zc_fft); srslte_dft_plan_free(&p->zc_ifft);
free(p->zc_fft);
srslte_dft_plan_free(p->zc_ifft);
free(p->zc_ifft);
if (p->signal_fft) { if (p->signal_fft) {
free(p->signal_fft); free(p->signal_fft);

@ -416,37 +416,24 @@ void srslte_pucch_set_threshold(srslte_pucch_t *q, float format1_threshold) {
} }
/** Initializes the PDCCH transmitter and receiver */ /** 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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && srslte_cell_isvalid(&cell)) { if (q != NULL) {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_pucch_t)); 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)) { if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
return SRSLTE_ERROR; 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); q->users = calloc(sizeof(srslte_pucch_user_t*), 1+SRSLTE_SIRNTI);
if (!q->users) { if (!q->users) {
perror("malloc"); perror("malloc");
return SRSLTE_ERROR; goto clean_exit;
} }
srslte_uci_cqi_pucch_init(&q->cqi); srslte_uci_cqi_pucch_init(&q->cqi);
q->z = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS); 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->z_tmp = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS);
q->ce = 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; ret = SRSLTE_SUCCESS;
} }
clean_exit:
if (ret == SRSLTE_ERROR) {
srslte_pucch_free(q);
}
return ret; return ret;
} }
void srslte_pucch_free(srslte_pucch_t *q) { void srslte_pucch_free(srslte_pucch_t *q) {
if (q->users) { if (q->users) {
for (int rnti=0;rnti<SRSLTE_SIRNTI;rnti++) { for (int rnti=0;rnti<=SRSLTE_SIRNTI;rnti++) {
srslte_pucch_clear_rnti(q, rnti); srslte_pucch_clear_rnti(q, rnti);
} }
free(q->users); free(q->users);
@ -480,6 +471,31 @@ void srslte_pucch_free(srslte_pucch_t *q) {
bzero(q, sizeof(srslte_pucch_t)); 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) { void srslte_pucch_clear_rnti(srslte_pucch_t *q, uint16_t rnti) {
if (q->users[rnti]) { if (q->users[rnti]) {
for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { 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 // 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)) { 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"); fprintf(stderr, "Error computing PUCCH Format 2 scrambling sequence\n");
srslte_pucch_clear_rnti(q, rnti);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }

@ -32,6 +32,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <srslte/srslte.h>
#include <srslte/phy/phch/pusch.h>
#include "srslte/phy/ch_estimation/refsignal_ul.h" #include "srslte/phy/ch_estimation/refsignal_ul.h"
#include "srslte/phy/phch/pusch.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 */ /** 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 ret = SRSLTE_ERROR_INVALID_INPUTS;
int i; int i;
if (q != NULL && if (q != NULL)
srslte_cell_isvalid(&cell))
{ {
bzero(q, sizeof(srslte_pusch_t)); bzero(q, sizeof(srslte_pusch_t));
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
q->max_re = max_prb * MAX_PUSCH_RE(SRSLTE_CP_NORM);
q->cell = cell;
q->max_re = q->cell.nof_prb * MAX_PUSCH_RE(q->cell.cp);
INFO("Init PUSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, INFO("Init PUSCH: %d PRBs\n", max_prb);
q->cell.nof_prb, q->max_re);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (srslte_modem_table_lte(&q->mod[i], modulations[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]); 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) { if (!q->users) {
perror("malloc"); perror("malloc");
goto clean; goto clean;
} }
/* Precompute sequence for type2 frequency hopping */ if (srslte_sequence_init(&q->tmp_seq, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) {
if (srslte_sequence_LTE_pr(&q->seq_type2_fo, 210, q->cell.id)) { goto clean;
fprintf(stderr, "Error initiating type2 frequency hopping sequence\n");
goto clean;
} }
srslte_sch_init(&q->ul_sch); 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"); fprintf(stderr, "Error initiating DFT transform precoding\n");
goto clean; goto clean;
} }
// Allocate int16 for reception (LLRs). Buffer casted to uint8_t for transmission // 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)); q->q = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
if (!q->q) { if (!q->q) {
@ -244,9 +242,11 @@ int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) {
goto clean; goto clean;
} }
q->ce = srslte_vec_malloc(sizeof(cf_t) * q->max_re); if (!q->is_ue) {
if (!q->ce) { q->ce = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
goto clean; if (!q->ce) {
goto clean;
}
} }
q->z = srslte_vec_malloc(sizeof(cf_t) * q->max_re); q->z = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->z) { if (!q->z) {
@ -262,6 +262,14 @@ int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) {
return ret; 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) { void srslte_pusch_free(srslte_pusch_t *q) {
int i; int i;
@ -284,13 +292,20 @@ void srslte_pusch_free(srslte_pusch_t *q) {
srslte_dft_precoding_free(&q->dft_precoding); srslte_dft_precoding_free(&q->dft_precoding);
if (q->users) { if (q->users) {
for (int rnti=0;rnti<SRSLTE_SIRNTI;rnti++) { if (q->is_ue) {
srslte_pusch_clear_rnti(q, rnti); srslte_pusch_free_rnti(q, 0);
} else {
for (int rnti=0;rnti<=SRSLTE_SIRNTI;rnti++) {
srslte_pusch_free_rnti(q, rnti);
}
} }
free(q->users); free(q->users);
} }
srslte_sequence_free(&q->seq_type2_fo); srslte_sequence_free(&q->seq_type2_fo);
srslte_sequence_free(&q->tmp_seq);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
srslte_modem_table_free(&q->mod[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. /* 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 * 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 */ * For the connection procedure, use srslte_pusch_encode() functions */
int srslte_pusch_set_rnti(srslte_pusch_t *q, uint16_t rnti) { int srslte_pusch_set_rnti(srslte_pusch_t *q, uint16_t rnti) {
uint32_t i; uint32_t i;
if (!q->users[rnti]) { uint32_t rnti_idx = q->is_ue?0:rnti;
q->users[rnti] = calloc(1, sizeof(srslte_pusch_user_t));
if (q->users[rnti]) { if (!q->users[rnti_idx] || q->is_ue) {
for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { if (!q->users[rnti_idx]) {
if (srslte_sequence_pusch(&q->users[rnti]->seq[i], rnti, 2 * i, q->cell.id, q->users[rnti_idx] = calloc(1, sizeof(srslte_pusch_user_t));
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { if (!q->users[rnti_idx]) {
return SRSLTE_ERROR; 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; return SRSLTE_SUCCESS;
} }
void srslte_pusch_clear_rnti(srslte_pusch_t *q, uint16_t rnti) { void srslte_pusch_free_rnti(srslte_pusch_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 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]); free(q->users[rnti_idx]);
q->users[rnti] = NULL; 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; return SRSLTE_ERROR;
} }
if (q->users[rnti] && q->users[rnti]->sequences_generated) { // Generate scrambling sequence if not pre-generated
srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t*) q->q, cfg->nbits.nof_bits); srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits);
} else {
srslte_sequence_t seq; // Run scrambling
if (srslte_sequence_pusch(&seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { srslte_scrambling_bytes(seq, (uint8_t*) q->q, cfg->nbits.nof_bits);
return SRSLTE_ERROR;
} // Correct UCI placeholder/repetition bits
srslte_scrambling_bytes(&seq, (uint8_t*) q->q, cfg->nbits.nof_bits);
srslte_sequence_free(&seq);
}
// Correct UCI placeholder/repetition bits
uint8_t *d = q->q; uint8_t *d = q->q;
for (int i = 0; i < q->ul_sch.nof_ri_ack_bits; i++) { 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) { 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); srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, noise_estimate);
// DFT predecoding // 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 // Soft demodulation
srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->q, cfg->nbits.nof_re); 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 // Decode RI/HARQ bits before descrambling
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
if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) { 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"); fprintf(stderr, "Error decoding RI/HARQ bits\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -554,11 +616,7 @@ int srslte_pusch_decode(srslte_pusch_t *q,
// Descrambling // Descrambling
srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits);
if (!(q->users[rnti] && q->users[rnti]->sequences_generated)) { return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data);
srslte_sequence_free(seq);
}
return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data);
} else { } else {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }

@ -41,15 +41,19 @@
/* Returns the number of RE in a PRB in a slot and subframe */ /* 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 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; 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) { if (slot == 0) {
re = (SRSLTE_CP_NSYMB(cp) - nof_ctrl_symbols) * SRSLTE_NRE; re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols) * SRSLTE_NRE;
} else { } 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 */ /* 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))) { && (prb_idx >= nof_prb / 2 - 3 && prb_idx < nof_prb / 2 + 3 + (nof_prb%2))) {
if (subframe == 0) { if (subframe == 0) {
if (slot == 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 { } else {
if (SRSLTE_CP_ISEXT(cp)) { if (SRSLTE_CP_ISEXT(cp_)) {
re = (SRSLTE_CP_NSYMB(cp) - 4) * SRSLTE_NRE; re = (SRSLTE_CP_NSYMB(cp_) - 4) * SRSLTE_NRE;
skip_refs = true; skip_refs = false;
} else { } 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) { } else if (subframe == 5) {
if (slot == 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;
} }
} }
if ((nof_prb % 2) 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; re += 2 * SRSLTE_NRE / 2;
} else if (subframe == 0) { } else if (subframe == 0) {
re += 4 * SRSLTE_NRE / 2 - nof_ports; re += 4 * SRSLTE_NRE / 2 - nof_ports;
if (SRSLTE_CP_ISEXT(cp)) { if (SRSLTE_CP_ISEXT(cp_)) {
re -= nof_ports > 2 ? 2 : nof_ports; 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 // remove references
if (!skip_refs) { if (skip_refs) {
switch (nof_ports) { if(sf_type == SRSLTE_SF_NORM){
case 1: switch (nof_ports) {
case 2: case 1:
re -= 2 * (slot + 1) * nof_ports; case 2:
break; re -= 2 * (slot + 1) * nof_ports;
case 4: break;
if (slot == 1) { case 4:
re -= 12; if (slot == 1) {
} else { re -= 12;
re -= 4; } else {
if (nof_ctrl_symbols == 1) {
re -= 4; re -= 4;
if (nof_ctrl_symbols == 1) {
re -= 4;
}
} }
break;
} }
break; }
if(sf_type == SRSLTE_SF_MBSFN){
re -= 6*(slot + 1);
} }
} }
return re; 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 */ /* 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 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; uint32_t j, s;
// Compute number of RE per PRB // Compute number of RE per PRB
uint32_t nof_re = 0; uint32_t nof_re = 0;
for (s = 0; s < 2; s++) { for (s = 0; s < 2; s++) {
for (j = 0; j < cell.nof_prb; j++) { for (j = 0; j < cell.nof_prb; j++) {
if (grant->prb_idx[s][j]) { if (grant->prb_idx[s][j]) {
nof_re += ra_re_x_prb(sf_idx, s, j, nof_re += ra_re_x_prb(sf_idx, s, j, cell.nof_prb, cell.nof_ports,
cell.nof_prb, cell.nof_ports, nof_ctrl_symbols, cell.cp); nof_ctrl_symbols, cell.cp, grant->sf_type);
} }
} }
} }
return nof_re; return nof_re;
} }
/** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 /** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213
* Decode dci->type?_alloc to grant * Decode dci->type?_alloc to grant
* This function only reads dci->type?_alloc and dci->alloc_type fields. * 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; 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; uint32_t i_tbs = 0;
int tbs = -1; int tbs = -1;
if (mcs->idx < 10) { if (mcs->idx < 10) {
@ -457,6 +466,53 @@ int dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) {
tbs = 0; tbs = 0;
i_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) { if (tbs == -1) {
tbs = srslte_ra_tbs_from_idx(i_tbs, nprb); tbs = srslte_ra_tbs_from_idx(i_tbs, nprb);
if (tbs >= 0) { 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; grant->mcs[0].tbs = (uint32_t) tbs;
} else { } else {
n_prb = grant->nof_prb; n_prb = grant->nof_prb;
grant->nof_tb = 0;
if (dci->tb_en[0]) { if (dci->tb_en[0]) {
grant->mcs[0].idx = dci->mcs_idx; 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) { if (tbs) {
last_dl_tbs[dci->harq_process%8] = tbs; last_dl_tbs[dci->harq_process%8] = tbs;
} else { } else {
// For mcs>=29, set last TBS received for this PID // For mcs>=29, set last TBS received for this PID
grant->mcs[0].tbs = last_dl_tbs[dci->harq_process%8]; grant->mcs[0].tbs = last_dl_tbs[dci->harq_process%8];
} }
grant->nof_tb++;
} else { } else {
grant->mcs[0].tbs = 0; grant->mcs[0].tbs = 0;
} }
if (dci->tb_en[1]) { if (dci->tb_en[1]) {
grant->mcs[1].idx = dci->mcs_idx_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) { if (tbs) {
last_dl_tbs2[dci->harq_process%8] = tbs; last_dl_tbs2[dci->harq_process%8] = tbs;
} else { } 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->mcs[1].tbs = 0;
} }
} }
grant->nof_tb = 0;
for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
grant->tb_en[tb] = dci->tb_en[tb];
if (dci->tb_en[tb]) { if (dci->tb_en[tb]) {
grant->Qm[tb] = srslte_mod_bits_x_symbol(grant->mcs[tb].mod); grant->Qm[tb] = srslte_mod_bits_x_symbol(grant->mcs[tb].mod);
grant->nof_tb++;
} }
} }
grant->pinfo = dci->pinfo; 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]) srslte_ra_nbits_t nbits [SRSLTE_MAX_CODEWORDS])
{ {
// Compute number of RE // Compute number of RE
for (int i = 0; i < grant->nof_tb; i++) { for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
/* Compute number of RE for first transport block */ if (grant->tb_en[i]) {
nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi); /* Compute number of RE for first transport block */
nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi; nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi);
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi;
nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i]; 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 */ /** Obtains a DL grant from a DCI grant for PDSCH */
int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci, 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) 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; bool crc_is_crnti = false;
if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) { if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) {
crc_is_crnti = true; 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) { void srslte_ra_dl_grant_fprint(FILE *f, srslte_ra_dl_grant_t *grant) {
srslte_ra_prb_fprint(f, grant); srslte_ra_prb_fprint(f, grant);
fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->nof_prb); 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); fprintf(f, " - Number of TBs:\t\t\t%d\n", SRSLTE_RA_DL_GRANT_NOF_TB(grant));
for (int i = 0; i < grant->nof_tb; i++) { for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
fprintf(f, " - Transport block:\t\t\t%d\n", i); if (grant->tb_en[i]) {
fprintf(f, " -> Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs[i].mod)); fprintf(f, " - Transport block:\t\t\t%d\n", i);
fprintf(f, " -> Transport block size:\t\t%d\n", grant->mcs[i].tbs); 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) {
} }
} }
} }

@ -32,12 +32,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include "srslte/phy/phch/pdsch.h" #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/bit.h"
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.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; 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) { uint32_t srslte_sch_last_noi(srslte_sch_t *q) {
return q->nof_iterations; return q->nof_iterations;
} }
/* Encode a transport block according to 36.212 5.3.2 /* 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]; bool cb_map[SRSLTE_MAX_CODEBLOCKS];
uint32_t cb_idx[SRSLTE_TDEC_NPAR]; uint32_t cb_idx[SRSLTE_TDEC_MAX_NPAR];
int16_t *decoder_input[SRSLTE_TDEC_NPAR]; int16_t *decoder_input[SRSLTE_TDEC_MAX_NPAR];
uint32_t nof_cb = cb_size_group?cb_segm->C2:cb_segm->C1; uint32_t nof_cb = cb_size_group?cb_segm->C2:cb_segm->C1;
uint32_t first_cb = cb_size_group?cb_segm->C1:0; 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; return false;
} }
for (int i=0;i<SRSLTE_TDEC_NPAR;i++) { for (int i=0;i<srslte_tdec_get_nof_parallel(&q->decoder);i++) {
cb_idx[i] = i+first_cb; cb_idx[i] = i+first_cb;
decoder_input[i] = false; decoder_input[i] = NULL;
} }
for (int i=0;i<nof_cb;i++) { for (int i=0;i<nof_cb;i++) {
@ -349,12 +339,14 @@ bool decode_tb_cb(srslte_sch_t *q,
srslte_tdec_reset(&q->decoder, cb_len); srslte_tdec_reset(&q->decoder, cb_len);
uint32_t remaining_cb = nof_cb; uint32_t remaining_cb = nof_cb;
q->nof_iterations = 0;
while(remaining_cb>0) { while(remaining_cb>0) {
// Unratematch the codeblocks left to decode // Unratematch the codeblocks left to decode
for (int i=0;i<SRSLTE_TDEC_NPAR;i++) { for (int i=0;i<srslte_tdec_get_nof_parallel(&q->decoder);i++) {
if (!decoder_input[i] && remaining_cb > 0) { if (!decoder_input[i] && remaining_cb > 0) {
// Find an unprocessed CB // Find an unprocessed CB
@ -372,25 +364,23 @@ bool decode_tb_cb(srslte_sch_t *q,
n_e2 = n_e+Qm; n_e2 = n_e+Qm;
rp = (cb_segm->C - gamma)*n_e + (cb_idx[i]-(cb_segm->C - gamma))*n_e2; 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); 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)) { 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"); fprintf(stderr, "Error in rate matching\n");
return SRSLTE_ERROR; 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); 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 // Decide output bits and compute CRC
for (int i=0;i<SRSLTE_TDEC_NPAR;i++) { for (int i=0;i<srslte_tdec_get_nof_parallel(&q->decoder);i++) {
if (decoder_input[i]) { if (decoder_input[i]) {
srslte_tdec_decision_byte_par_cb(&q->decoder, q->cb_in, i, cb_len); 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)) { 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)); 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 // Reset number of iterations for that CB in the decoder
srslte_tdec_reset_cb(&q->decoder, i); srslte_tdec_reset_cb(&q->decoder, i);
remaining_cb--; remaining_cb--;
decoder_input[i] = NULL; decoder_input[i] = NULL;
cb_idx[i] = 0; 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. // Early stop the whole transport block.
} else if (srslte_tdec_get_nof_iterations_cb(&q->decoder, i) >= q->max_iterations) { } 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", 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); cb_idx[i], remaining_cb, i, first_cb, nof_cb);
return false;
q->nof_iterations += q->max_iterations;
q->nof_iterations /= (nof_cb-remaining_cb+1);
return false;
} }
} }
} }
} }
q->nof_iterations /= nof_cb;
return true; 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+1] = 0;
data[cb_segm->tbs/8+2] = 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;i<nof_cb_groups && crc_ok;i++) { for (uint32_t i=0;i<nof_cb_groups && crc_ok;i++) {
crc_ok = decode_tb_cb(q, softbuffer, cb_segm, Qm, rv, nof_e_bits, e_bits, data, i); crc_ok = decode_tb_cb(q, softbuffer, cb_segm, Qm, rv, nof_e_bits, e_bits, data, i);
} }
@ -524,7 +520,7 @@ int srslte_dlsch_decode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbu
int16_t *e_bits, uint8_t *data, int codeword_idx) { int16_t *e_bits, uint8_t *data, int codeword_idx) {
uint32_t Nl = 1; 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; 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) { uint8_t *data, uint8_t *e_bits, int codeword_idx) {
uint32_t Nl = 1; 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; 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 // Deinterleave and decode HARQ bits
if (uci_data->uci_ack_len > 0) { if (uci_data->uci_ack_len > 0) {
uint8_t acks[2] = {0, 0};
float beta = beta_harq_offset[cfg->uci_cfg.I_offset_ack]; float beta = beta_harq_offset[cfg->uci_cfg.I_offset_ack];
if (cfg->cb_segm.tbs == 0) { if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; 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) { if (ret < 0) {
return ret; return ret;
} }
uci_data->uci_ack = acks[0];
uci_data->uci_ack_2 = acks[1];
Q_prime_ack = (uint32_t) ret; Q_prime_ack = (uint32_t) ret;
// Set zeros to HARQ bits // Set zeros to HARQ bits
@ -805,11 +804,13 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q,
// Encode (and interleave) ACK // Encode (and interleave) ACK
if (uci_data.uci_ack_len > 0) { 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]; float beta = beta_harq_offset[cfg->uci_cfg.I_offset_ack];
if (cfg->cb_segm.tbs == 0) { if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; 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) { if (ret < 0) {
return ret; return ret;
} }

@ -33,7 +33,6 @@
* 36.211 6.6.1 * 36.211 6.6.1
*/ */
int srslte_sequence_pbch(srslte_sequence_t *seq, srslte_cp_t cp, uint32_t cell_id) { 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); 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 * 36.211 6.7.1
*/ */
int srslte_sequence_pcfich(srslte_sequence_t *seq, uint32_t nslot, uint32_t cell_id) { 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); 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 * 36.211 6.9.1
*/ */
int srslte_sequence_phich(srslte_sequence_t *seq, uint32_t nslot, uint32_t cell_id) { 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); 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 * 36.211 6.8.2
*/ */
int srslte_sequence_pdcch(srslte_sequence_t *seq, uint32_t nslot, uint32_t cell_id, uint32_t len) { 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); 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 * 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) { 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); 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 * 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) { 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); 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 * 36.211 5.4.2
*/ */
int srslte_sequence_pucch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id) { 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); 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));
}

@ -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_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) 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 # 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) add_executable(pdsch_pdcch_file_test pdsch_pdcch_file_test.c)
target_link_libraries(pdsch_pdcch_file_test srslte_phy) 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(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(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(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(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 # PUSCH TEST

@ -131,7 +131,11 @@ int base_init() {
return -1; 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"); fprintf(stderr, "Error initializing equalizer\n");
return -1; return -1;
} }
@ -141,7 +145,11 @@ int base_init() {
return -1; 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"); fprintf(stderr, "Error initiating PBCH\n");
return -1; return -1;
} }

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

Loading…
Cancel
Save