Merge branch 'next' into next_novolk

master
Ismael Gomez 7 years ago
commit 4375113efc

@ -72,6 +72,7 @@ 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 +84,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.

@ -335,9 +335,8 @@ 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 {

@ -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
@ -63,33 +66,43 @@ srslte_cell_t cell = {
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;
@ -99,8 +112,13 @@ 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;
@ -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,7 +315,15 @@ 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, true); srslte_ofdm_set_normalize(&ifft, true);
srslte_ofdm_set_normalize(&ifft_mbsfn, true);
if (srslte_pbch_init(&pbch)) { if (srslte_pbch_init(&pbch)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
exit(-1); exit(-1);
@ -301,11 +333,13 @@ void base_init() {
exit(-1); 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, 1)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
exit(-1); exit(-1);
@ -340,6 +374,14 @@ void base_init() {
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]) {
@ -354,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++) {
@ -366,9 +409,13 @@ 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]) {
free(data[i]); free(data[i]);
@ -481,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");
@ -596,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;
@ -633,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];
@ -645,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) {
@ -674,21 +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.nof_prb)) { /* 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 (srslte_chest_dl_set_cell(&est, cell)) { if(mbsfn_area_id > -1) {
if(srslte_refsignal_mbsfn_init(&mbsfn_refs, cell, mbsfn_area_id)) {
fprintf(stderr, "Error initializing equalizer\n"); fprintf(stderr, "Error initializing equalizer\n");
exit(-1); 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
@ -737,7 +797,6 @@ 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;
@ -747,6 +806,7 @@ int main(int argc, char **argv) {
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
@ -756,7 +816,7 @@ int main(int argc, char **argv) {
/* 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,
@ -768,9 +828,12 @@ int main(int argc, char **argv) {
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){
srslte_refsignal_mbsfn_put_sf(cell, 0,csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]);
} else {
for (i = 0; i < cell.nof_ports; i++) { for (i = 0; i < cell.nof_ports; i++) {
srslte_refsignal_cs_put_sf(cell, (uint32_t) i, est.csr_signal.pilots[i / 2][sf_idx], sf_symbols[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);
@ -809,6 +872,7 @@ int main(int argc, char **argv) {
} }
if (send_data) { if (send_data) {
if(sf_idx != 1 || mbsfn_area_id < 0) { // PDCCH + PDSCH
srslte_dci_format_t dci_format; srslte_dci_format_t dci_format;
switch(pdsch_cfg.mimo_type) { switch(pdsch_cfg.mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
@ -854,23 +918,70 @@ int main(int argc, char **argv) {
if (net_port > 0 && net_packet_ready) { if (net_port > 0 && net_packet_ready) {
if (null_file_sink) { if (null_file_sink) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (pdsch_cfg.grant.tb_en[tb]) {
srslte_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.mcs[tb].tbs); srslte_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.mcs[tb].tbs);
if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.mcs[tb].tbs - 1) / 8) < 0) { if (srslte_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);
}
}else{ // We're sending MCH on subframe 1 - PDCCH + PMCH
/* Encode PDCCH */
INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_msg, cell.nof_prb, cell.nof_ports, false);
if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], M_CRNTI, sf_symbols, sf_idx, cfi)) {
fprintf(stderr, "Error encoding DCI message\n");
exit(-1);
}
/* Configure pmch_cfg parameters */
srslte_ra_dl_grant_t grant;
grant.nof_tb = 1;
grant.mcs[0].idx = 2;
grant.mcs[0].mod = SRSLTE_MOD_QPSK;
grant.nof_prb = cell.nof_prb;
grant.sf_type = SRSLTE_SF_MBSFN;
grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod);
srslte_dl_fill_ra_mcs(&grant.mcs[0], cell.nof_prb);
for(int i = 0; i < 2; i++){
for(int j = 0; j < grant.nof_prb; j++){
grant.prb_idx[i][j] = true;
}
}
if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, sf_idx)) {
fprintf(stderr, "Error configuring PMCH\n");
exit(-1);
}
/* Encode PMCH */
if (srslte_pmch_encode(&pmch, &pmch_cfg, softbuffers[0], data[0], mbsfn_area_id, sf_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n");
exit(-1);
}
if (net_port > 0 && net_packet_ready) {
if (null_file_sink) {
srslte_bit_pack_vector(data[0], data_tmp, pmch_cfg.grant.mcs[0].tbs);
if (srslte_netsink_write(&net_sink, data_tmp, 1+(pmch_cfg.grant.mcs[0].tbs-1)/8) < 0) {
fprintf(stderr, "Error sending data through UDP socket\n");
}
} }
net_packet_ready = false; net_packet_ready = false;
sem_post(&net_sem); sem_post(&net_sem);
} }
} }
}
/* Transform to OFDM symbols */ /* Transform to OFDM symbols */
if(sf_idx != 1 || mbsfn_area_id < 0){
for (i = 0; i < cell.nof_ports; i++) { for (i = 0; i < cell.nof_ports; i++) {
srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[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) {

@ -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);
@ -304,8 +318,8 @@ 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
@ -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);
@ -518,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;
@ -592,7 +614,6 @@ int main(int argc, char **argv) {
} }
} }
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");
@ -605,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");
@ -626,15 +650,14 @@ 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(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe
if (cell.nof_ports == 1) { if (cell.nof_ports == 1) {
/* Transmission mode 1 */ /* Transmission mode 1 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
@ -654,15 +677,29 @@ int main(int argc, char **argv) {
} }
} }
} }
}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 < SRSLTE_MAX_CODEWORDS; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (ue_dl.pdsch_cfg.grant.tb_en[tb]) { if (ue_dl.pdsch_cfg.grant.tb_en[tb]) {
@ -670,7 +707,7 @@ int main(int argc, char **argv) {
} }
} }
} }
}
#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)) ||
@ -689,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);
@ -696,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;
@ -704,15 +743,15 @@ 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));
@ -733,7 +772,10 @@ int main(int argc, char **argv) {
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,
@ -775,14 +817,17 @@ 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;
@ -794,7 +839,7 @@ int main(int argc, char **argv) {
#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);
@ -816,7 +861,6 @@ 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) {
@ -845,6 +889,7 @@ int main(int argc, char **argv) {
srslte_rf_close(&rf); srslte_rf_close(&rf);
} }
#endif #endif
printf("\nBye\n"); printf("\nBye\n");
exit(0); exit(0);
} }

@ -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,7 +24,7 @@ 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>
@ -38,6 +38,7 @@ public:
} }
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) {
@ -47,6 +48,7 @@ public:
private: private:
void run_period() { void run_period() {
metrics_t metric; metrics_t metric;
bzero(&metric, sizeof(metrics_t));
m->get_metrics(metric); m->get_metrics(metric);
for (uint32_t i=0;i<listeners.size();i++) { for (uint32_t i=0;i<listeners.size();i++) {
listeners[i]->set_metrics(metric); listeners[i]->set_metrics(metric);

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

@ -98,6 +98,7 @@ 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;
@ -113,6 +114,13 @@ public:
virtual void deattach_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
class rrc_interface_mac_common class rrc_interface_mac_common
{ {
@ -172,6 +180,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
@ -295,11 +304,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;
@ -518,20 +527,19 @@ public:
/* Cell search and selection procedures */ /* Cell search and selection procedures */
virtual void cell_search_start() = 0; virtual void cell_search_start() = 0;
virtual void cell_search_stop() = 0;
virtual void cell_search_next() = 0; virtual void cell_search_next() = 0;
virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0; virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0;
virtual bool sync_stop() = 0;
/* Is the PHY downlink synchronized? */ /* Is the PHY downlink synchronized? */
virtual bool sync_status() = 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];
@ -96,9 +99,13 @@ SRSLTE_API int srslte_chest_dl_init(srslte_chest_dl_t *q,
SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t *q); 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_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q,
srslte_cell_t cell); srslte_cell_t cell);
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,
uint32_t filter_len); uint32_t filter_len);
@ -109,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],
@ -120,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,

@ -40,25 +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,
uint32_t max_prb); uint32_t max_prb);
SRSLTE_API int srslte_refsignal_cs_set_cell(srslte_refsignal_cs_t * q, SRSLTE_API int srslte_refsignal_cs_set_cell(srslte_refsignal_t * q,
srslte_cell_t cell); srslte_cell_t cell);
SRSLTE_API void srslte_refsignal_cs_free(srslte_refsignal_cs_t *q); 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,
@ -84,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

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

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

@ -56,6 +56,12 @@ 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; float freq_shift_f;
cf_t *shift_buffer; cf_t *shift_buffer;
@ -64,9 +70,22 @@ typedef struct SRSLTE_API{
SRSLTE_API int srslte_ofdm_init_(srslte_ofdm_t *q, 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 max_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 max_prb); uint32_t max_prb);
@ -95,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);
@ -111,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);
SRSLTE_API void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t *q,
uint8_t non_mbsfn_region);
#endif #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;
@ -89,6 +89,8 @@ typedef struct SRSLTE_API {
float tx_amp; float tx_amp;
uint8_t tmp[1024*128];
} srslte_enb_dl_t; } srslte_enb_dl_t;
typedef struct { typedef struct {
@ -176,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

@ -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
srslte_tdec_simd_t tdec_simd;
#else
float *input_conv; float *input_conv;
union {
srslte_tdec_simd_t tdec_simd;
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);

@ -58,6 +58,7 @@ 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;
@ -149,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

@ -101,16 +101,6 @@ SRSLTE_API void srslte_phich_calc(srslte_phich_t *q,
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 *ce[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_decode_multi(srslte_phich_t *q,
cf_t *slot_symbols[SRSLTE_MAX_PORTS], cf_t *slot_symbols[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate, float noise_estimate,

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

@ -103,7 +103,11 @@ 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;
srslte_sf_t sf_type;
bool tb_en[SRSLTE_MAX_CODEWORDS]; bool tb_en[SRSLTE_MAX_CODEWORDS];
uint32_t pinfo; uint32_t pinfo;
} srslte_ra_dl_grant_t; } srslte_ra_dl_grant_t;
@ -290,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_ */

@ -58,7 +58,6 @@ 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;
@ -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,

@ -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;
@ -127,15 +136,27 @@ SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q);
SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q,
srslte_cell_t cell); srslte_cell_t cell);
SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS], cf_t *input[SRSLTE_MAX_PORTS],
uint32_t sf_idx, uint32_t sf_idx,
uint32_t *cfi); uint32_t *cfi);
SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint32_t sf_idx,
uint32_t *cfi,
srslte_sf_t sf_type);
int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q,
uint32_t sf_idx, uint32_t sf_idx,
uint32_t *cfi); uint32_t *cfi);
SRSLTE_API int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q,
uint32_t sf_idx,
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,
uint32_t cfi, uint32_t cfi,
@ -184,6 +205,18 @@ 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,
uint8_t *ri, uint8_t *ri,
uint8_t *pmi, uint8_t *pmi,
@ -203,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,

@ -57,7 +57,6 @@ 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;
@ -73,12 +72,11 @@ namespace srslte {
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);
@ -123,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);
@ -168,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;

@ -81,29 +81,46 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
{ {
bzero(q, sizeof(srslte_chest_dl_t)); bzero(q, sizeof(srslte_chest_dl_t));
ret = srslte_refsignal_cs_init(&q->csr_signal, max_prb);
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(max_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) * pilot_vec_size);
q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb));
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(max_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(max_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;
@ -119,6 +136,11 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
goto clean_exit; goto clean_exit;
} }
if (srslte_interp_linear_init(&q->srslte_interp_lin_mbsfn, 6*max_prb, SRSLTE_NRE/6)) {
fprintf(stderr, "Error initializing interpolator\n");
goto clean_exit;
}
q->noise_alg = SRSLTE_NOISE_ALG_REFS; q->noise_alg = SRSLTE_NOISE_ALG_REFS;
q->smooth_filter_len = 3; q->smooth_filter_len = 3;
@ -137,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);
} }
@ -157,6 +190,19 @@ 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 srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -165,7 +211,7 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
{ {
if (q->cell.id != cell.id || q->cell.nof_prb == 0) { if (q->cell.id != cell.id || q->cell.nof_prb == 0) {
memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); memcpy(&q->cell, &cell, sizeof(srslte_cell_t));
ret = srslte_refsignal_cs_set_cell(&q->csr_signal, cell); ret = srslte_refsignal_cs_set_cell(&q->csr_refs, 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);
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -187,7 +233,6 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
} }
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
return ret; return ret;
} }
@ -253,21 +298,43 @@ 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
for (l=0;l<(nsymbols);l++) {
if (ch_mode == SRSLTE_SF_MBSFN) {
if (l == 0) {
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l],
&ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE],
fidx_offset, SRSLTE_NRE/2-fidx_offset);
} else {
fidx_offset = srslte_refsignal_mbsfn_fidx(l - 1);
srslte_interp_linear_offset(&q->srslte_interp_lin_mbsfn, &pilot_estimates[(2*q->cell.nof_prb) + 6*q->cell.nof_prb*(l - 1)],
&ce[srslte_refsignal_mbsfn_nsymbol(l - 1) * q->cell.nof_prb * SRSLTE_NRE],
fidx_offset, SRSLTE_NRE/6-fidx_offset);
}
} else {
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l], 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], &ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE],
fidx_offset, SRSLTE_NRE/2-fidx_offset); fidx_offset, SRSLTE_NRE/2-fidx_offset);
} }
}
/* Now interpolate in the time domain between symbols */ /* Now interpolate in the time domain between symbols */
if (ch_mode == SRSLTE_SF_MBSFN) {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1);
} else {
if (SRSLTE_CP_ISNORM(q->cell.cp)) { if (SRSLTE_CP_ISNORM(q->cell.cp)) {
if (nsymbols == 4) { if (nsymbols == 4) {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3);
@ -292,6 +359,8 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
} }
} }
} }
}
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) {
@ -319,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++) {
@ -341,23 +410,14 @@ 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){
{
/* 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) { 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 */
@ -372,7 +432,6 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u
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 */
@ -381,10 +440,42 @@ 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++) {
@ -411,6 +502,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++) {

@ -75,17 +75,44 @@ 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()
{
if(false){
return 3;
}else{
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,11 +124,104 @@ 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)
{
uint32_t ret = 0;
if(l == 0){
ret = 2;
} else if (l == 1) {
ret = 6;
} else if (l == 2){
ret = 10;
}
return ret;
}
int srslte_refsignal_mbsfn_gen_seq(srslte_refsignal_t * q, srslte_cell_t cell, uint32_t N_mbsfn_id)
{
uint32_t c_init;
uint32_t i, ns, l, p;
uint32_t mp;
int ret = SRSLTE_ERROR;
srslte_sequence_t seq_mbsfn;
bzero(&seq_mbsfn, sizeof(srslte_sequence_t));
if (srslte_sequence_init(&seq_mbsfn, 20* SRSLTE_MAX_PRB)) {
goto free_and_exit;
}
for(ns=0; ns<SRSLTE_NSUBFRAMES_X_FRAME;ns++){
for(p=0;p<2;p++) {
uint32_t nsymbols = 3; // replace with function
for(l=0;l<nsymbols;l++) {
uint32_t lp = (srslte_refsignal_mbsfn_nsymbol(l))%6;
uint32_t slot =(l)?(ns*2+1):(ns*2);
c_init = 512*(7*(slot+1)+lp+1)*(2*N_mbsfn_id + 1) + N_mbsfn_id;
srslte_sequence_set_LTE_pr(&seq_mbsfn,SRSLTE_MAX_PRB*20 ,c_init);
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;
free_and_exit:
if (ret == SRSLTE_ERROR) {
srslte_sequence_free(&seq_mbsfn);
srslte_refsignal_free(q);
}
return ret;
}
int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, srslte_cell_t cell, uint16_t mbsfn_area_id)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
uint32_t i, p;
if (q != NULL &&
srslte_cell_isvalid(&cell))
{
ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_refsignal_t));
q->cell = cell;
q->type = SRSLTE_SF_MBSFN;
q->mbsfn_area_id = mbsfn_area_id;
for (p=0;p<2;p++) {
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * q->cell.nof_prb * 18);
if (!q->pilots[p][i]) {
perror("malloc");
goto free_and_exit;
}
}
}
if(srslte_refsignal_mbsfn_gen_seq(q, q->cell, q->mbsfn_area_id)) {
goto free_and_exit;
}
ret = SRSLTE_SUCCESS;
}
free_and_exit:
if (ret == SRSLTE_ERROR) {
srslte_refsignal_free(q);
}
return ret;
}
/** Allocates memory for the 20 slots in a subframe /** Allocates memory for the 20 slots in a subframe
*/ */
int srslte_refsignal_cs_init(srslte_refsignal_cs_t * q, uint32_t max_prb) int srslte_refsignal_cs_init(srslte_refsignal_t * q, uint32_t max_prb)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -109,7 +229,6 @@ int srslte_refsignal_cs_init(srslte_refsignal_cs_t * q, uint32_t max_prb)
if (q != NULL) if (q != NULL)
{ {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
for (int p=0;p<2;p++) { for (int p=0;p<2;p++) {
for (int i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) { 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)); q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(max_prb, 2*p));
@ -123,7 +242,7 @@ int srslte_refsignal_cs_init(srslte_refsignal_cs_t * q, uint32_t max_prb)
} }
free_and_exit: free_and_exit:
if (ret == SRSLTE_ERROR) { if (ret == SRSLTE_ERROR) {
srslte_refsignal_cs_free(q); srslte_refsignal_free(q);
} }
return ret; return ret;
} }
@ -131,7 +250,7 @@ free_and_exit:
/** Allocates and precomputes the Cell-Specific Reference (CSR) signal for /** Allocates and precomputes the Cell-Specific Reference (CSR) signal for
* the 20 slots in a subframe * the 20 slots in a subframe
*/ */
int srslte_refsignal_cs_set_cell(srslte_refsignal_cs_t * q, srslte_cell_t cell) int srslte_refsignal_cs_set_cell(srslte_refsignal_t * q, srslte_cell_t cell)
{ {
uint32_t c_init; uint32_t c_init;
@ -188,7 +307,7 @@ int srslte_refsignal_cs_set_cell(srslte_refsignal_cs_t * q, srslte_cell_t cell)
} }
/** 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)
{ {
for (int p=0;p<2;p++) { for (int p=0;p<2;p++) {
for (int i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) { for (int i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
@ -197,10 +316,12 @@ void srslte_refsignal_cs_free(srslte_refsignal_cs_t * q)
} }
} }
} }
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)
{ {
@ -228,6 +349,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)
{ {
@ -254,4 +414,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;
}
}

@ -152,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++) {

@ -37,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");
@ -60,6 +66,7 @@ int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_p
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->nof_re = nof_prb * SRSLTE_NRE; q->nof_re = nof_prb * SRSLTE_NRE;
@ -70,9 +77,19 @@ int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_p
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; 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) { int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb) {
@ -120,6 +137,17 @@ int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) {
return srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_FORWARD); return srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_FORWARD);
} }
int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb)
{
int symbol_sz = srslte_symbol_sz(nof_prb);
if (symbol_sz < 0) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1;
}
return srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN);
}
int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) { int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) {
uint32_t i; uint32_t i;
int ret; int ret;
@ -130,9 +158,34 @@ int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) {
return -1; return -1;
} }
q->max_prb = max_prb; q->max_prb = max_prb;
ret = srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_BACKWARD); 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_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb)
{
uint32_t i;
int ret;
int symbol_sz = srslte_symbol_sz(nof_prb);
if (symbol_sz < 0) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1;
}
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);
@ -190,7 +243,6 @@ int srslte_ofdm_tx_set_prb(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) {
void srslte_ofdm_rx_free(srslte_ofdm_t *q) { void srslte_ofdm_rx_free(srslte_ofdm_t *q) {
srslte_ofdm_free_(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
@ -233,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++) {
@ -250,10 +319,16 @@ 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);
} }
if(!q->mbsfn_subframe){
for (n=0;n<2;n++) { for (n=0;n<2;n++) {
srslte_ofdm_rx_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); 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]);
}
}
/* Transforms input OFDM symbols into output samples. /* Transforms input OFDM symbols into output samples.
* Performs FFT on a each symbol and adds CP. * Performs FFT on a each symbol and adds CP.
@ -271,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;
if(!q->mbsfn_subframe){
for (n=0;n<2;n++) { for (n=0;n<2;n++) {
srslte_ofdm_tx_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]); 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);
} }
} }

@ -122,7 +122,7 @@ void srslte_enb_dl_free(srslte_enb_dl_t *q)
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]) {
@ -336,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);
}

@ -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,13 +36,16 @@
#include "srslte/phy/utils/mat.h" #include "srslte/phy/utils/mat.h"
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
#include <immintrin.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>
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;
@ -1364,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:
@ -1404,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;
} }

@ -29,15 +29,11 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <srslte/phy/phch/pdsch_cfg.h>
#include <srslte/phy/common/sequence.h>
#include <srslte/phy/phch/pdsch.h>
#include "prb_dl.h" #include "prb_dl.h"
#include "srslte/phy/phch/pdsch.h" #include "srslte/phy/phch/pdsch.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"
#include "srslte/phy/utils/bit.h"
#define MAX_PDSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) #define MAX_PDSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12)
@ -246,7 +242,7 @@ static int pdsch_init(srslte_pdsch_t *q, uint32_t max_prb, bool is_ue, uint32_t
goto clean; goto clean;
} }
if (q->is_ue) { 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;
@ -309,7 +305,7 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
free(q->symbols[i]); free(q->symbols[i]);
} }
if (q->is_ue) { if (q->is_ue) {
for (int j=0;j<q->nof_rx_antennas;j++) { for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
if (q->ce[i][j]) { if (q->ce[i][j]) {
free(q->ce[i][j]); free(q->ce[i][j]);
} }
@ -606,6 +602,9 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c
/* Return */ /* Return */
ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, codeword_idx); 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) { if (ret == SRSLTE_SUCCESS) {
*ack = true; *ack = true;
} else if (ret == SRSLTE_ERROR) { } else if (ret == SRSLTE_ERROR) {
@ -613,7 +612,7 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
} else { } else {
ERROR("Detected NULL pointer"); ERROR("Detected NULL pointer in TB%d &softbuffer=%p &data=%p &ack=%p", codeword_idx, softbuffer, (void*)data, ack);
} }
return ret; return ret;
@ -686,10 +685,10 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
srslte_layerdemap_type(x, q->d, cfg->nof_layers, 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 < SRSLTE_MAX_CODEWORDS; tb ++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) {
if (cfg->grant.tb_en[tb]) { /* Decode only if transport block is enabled and the default ACK is not true */
if (cfg->grant.tb_en[tb] && !acks[tb]) {
int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb, &acks[tb]); int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb, &acks[tb]);
/* Check if there has been any execution error */ /* Check if there has been any execution error */
@ -712,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) {
@ -722,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;
@ -816,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];
} }

@ -173,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,481 @@
/**
*
* \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",0);
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",0);
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",0);
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",0);
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;
}

@ -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,7 +89,8 @@ 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) {
if(sf_type == SRSLTE_SF_NORM){
switch (nof_ports) { switch (nof_ports) {
case 1: case 1:
case 2: case 2:
@ -103,6 +108,10 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_
break; break;
} }
} }
if(sf_type == SRSLTE_SF_MBSFN){
re -= 6*(slot + 1);
}
}
return re; return re;
} }
@ -281,20 +290,20 @@ uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t ce
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) {
@ -466,6 +475,52 @@ int dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) {
return tbs; return tbs;
} }
int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb) {
uint32_t i_tbs = 0;
int tbs = -1;
if (mcs->idx < 5) {
mcs->mod = SRSLTE_MOD_QPSK;
i_tbs = mcs->idx*2;
}else if (mcs->idx < 6) {
mcs->mod = SRSLTE_MOD_16QAM;
i_tbs = mcs->idx*2;
}else if (mcs->idx < 11) {
mcs->mod = SRSLTE_MOD_16QAM;
i_tbs = mcs->idx + 5;
}else if (mcs->idx < 20) {
mcs->mod = SRSLTE_MOD_64QAM;
i_tbs = mcs->idx + 5;
}else if (mcs->idx < 28) {
//mcs->mod = SRSLTE_MOD_256QAM;
i_tbs = mcs->idx + 5;
}else if (mcs->idx == 28) {
mcs->mod = SRSLTE_MOD_QPSK;
tbs = 0;
i_tbs = 0;
}else if (mcs->idx == 29) {
mcs->mod = SRSLTE_MOD_16QAM;
tbs = 0;
i_tbs = 0;
}else if (mcs->idx == 30) {
mcs->mod = SRSLTE_MOD_64QAM;
tbs = 0;
i_tbs = 0;
}else if (mcs->idx == 31) {
mcs->mod = SRSLTE_MOD_64QAM;
tbs = 0;
i_tbs = 0;
}
if (tbs == -1) {
tbs = srslte_ra_tbs_from_idx(i_tbs, nprb);
if (tbs >= 0) {
mcs->tbs = tbs;
}
}
return tbs;
}
/* Modulation order and transport block size determination 7.1.7 in 36.213 /* Modulation order and transport block size determination 7.1.7 in 36.213
* This looks at DCI type, type of RNTI and reads fields dci->type?_alloc, dci->mcs_idx, * This looks at DCI type, type of RNTI and reads fields dci->type?_alloc, dci->mcs_idx,
* dci->dci_is_1a and dci->dci_is_1c * dci->dci_is_1a and dci->dci_is_1c
@ -496,21 +551,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 {
@ -545,7 +602,11 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl
/* Compute number of RE for first transport block */ /* Compute number of RE for first transport block */
nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi); nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi);
nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi; nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi;
if (SRSLTE_SF_NORM == grant->sf_type) {
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; 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]; nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i];
} }
} }
@ -555,6 +616,7 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl
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;
@ -845,5 +907,3 @@ 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++) {
@ -351,10 +341,12 @@ bool decode_tb_cb(srslte_sch_t *q,
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
@ -384,13 +376,11 @@ bool decode_tb_cb(srslte_sch_t *q,
} }
} }
// 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);
@ -410,6 +400,8 @@ bool decode_tb_cb(srslte_sch_t *q,
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--;
@ -421,12 +413,16 @@ bool decode_tb_cb(srslte_sch_t *q,
} 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);
q->nof_iterations += q->max_iterations;
q->nof_iterations /= (nof_cb-remaining_cb+1);
return false; 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);
} }

@ -78,3 +78,9 @@ int srslte_sequence_pusch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot,
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) {
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));
}

@ -460,6 +460,10 @@ int main(int argc, char **argv) {
srslte_softbuffer_rx_reset_tbs(softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs); srslte_softbuffer_rx_reset_tbs(softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs);
} }
} }
/* Set ACKs to zero, otherwise will not decode if there are positive ACKs*/
bzero(acks, sizeof(acks));
r = srslte_pdsch_decode(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data_rx, acks); r = srslte_pdsch_decode(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data_rx, acks);
} }
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);

@ -263,7 +263,7 @@ int main(int argc, char **argv) {
for (ngroup=0;ngroup<srslte_phich_ngroups(&phich);ngroup++) { for (ngroup=0;ngroup<srslte_phich_ngroups(&phich);ngroup++) {
for (nseq=0;nseq<max_nseq;nseq++) { for (nseq=0;nseq<max_nseq;nseq++) {
if (srslte_phich_decode(&phich, fft_buffer, ce, srslte_chest_dl_get_noise_estimate(&chest), ngroup, nseq, numsubframe, &ack_rx, &distance)<0) { if (srslte_phich_decode(&phich, &fft_buffer, &ce, srslte_chest_dl_get_noise_estimate(&chest), ngroup, nseq, numsubframe, &ack_rx, &distance)<0) {
printf("Error decoding ACK\n"); printf("Error decoding ACK\n");
exit(-1); exit(-1);
} }

@ -103,7 +103,7 @@ int main(int argc, char **argv) {
srslte_phich_t phich; srslte_phich_t phich;
srslte_regs_t regs; srslte_regs_t regs;
int i, j; int i, j;
cf_t *ce[SRSLTE_MAX_PORTS]; cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
int nof_re; int nof_re;
cf_t *slot_symbols[SRSLTE_MAX_PORTS]; cf_t *slot_symbols[SRSLTE_MAX_PORTS];
uint8_t ack[50][SRSLTE_PHICH_NORM_NSEQUENCES], ack_rx; uint8_t ack[50][SRSLTE_PHICH_NORM_NSEQUENCES], ack_rx;
@ -120,13 +120,15 @@ int main(int argc, char **argv) {
/* init memory */ /* init memory */
for (i=0;i<SRSLTE_MAX_PORTS;i++) { for (i=0;i<SRSLTE_MAX_PORTS;i++) {
ce[i] = malloc(sizeof(cf_t) * nof_re); for (int k=0;k<SRSLTE_MAX_PORTS;k++) {
if (!ce[i]) { ce[k][i] = malloc(sizeof(cf_t) * nof_re);
if (!ce[k][i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
for (j = 0; j < nof_re; j++) { for (j = 0; j < nof_re; j++) {
ce[i][j] = 1; ce[k][i][j] = 1;
}
} }
slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); slot_symbols[i] = malloc(sizeof(cf_t) * nof_re);
if (!slot_symbols[i]) { if (!slot_symbols[i]) {
@ -185,7 +187,7 @@ int main(int argc, char **argv) {
for (ngroup=0;ngroup<srslte_phich_ngroups(&phich);ngroup++) { for (ngroup=0;ngroup<srslte_phich_ngroups(&phich);ngroup++) {
for (nseq=0;nseq<max_nseq;nseq++) { for (nseq=0;nseq<max_nseq;nseq++) {
if (srslte_phich_decode(&phich, slot_symbols[0], ce, 0, ngroup, nseq, nsf, &ack_rx, &distance)<0) { if (srslte_phich_decode(&phich, slot_symbols, ce, 0, ngroup, nseq, nsf, &ack_rx, &distance)<0) {
printf("Error decoding ACK\n"); printf("Error decoding ACK\n");
exit(-1); exit(-1);
} }
@ -208,7 +210,9 @@ int main(int argc, char **argv) {
srslte_phich_free(&phich); srslte_phich_free(&phich);
for (i=0;i<SRSLTE_MAX_PORTS;i++) { for (i=0;i<SRSLTE_MAX_PORTS;i++) {
free(ce[i]); for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
free(ce[i][j]);
}
free(slot_symbols[i]); free(slot_symbols[i]);
} }
printf("OK\n"); printf("OK\n");

@ -190,7 +190,7 @@ int main(int argc, char **argv) {
bzero(&uci_data_tx, sizeof(srslte_uci_data_t)); bzero(&uci_data_tx, sizeof(srslte_uci_data_t));
uci_data_tx.uci_cqi_len = 4; uci_data_tx.uci_cqi_len = 4;
uci_data_tx.uci_ri_len = 0; uci_data_tx.uci_ri_len = 0;
uci_data_tx.uci_ack_len = 2; uci_data_tx.uci_ack_len = 1;
memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t)); memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t));
for (uint32_t i=0;i<20;i++) { for (uint32_t i=0;i<20;i++) {

@ -582,6 +582,48 @@ static uint32_t encode_ri_ack(uint8_t data[2], uint32_t data_len, srslte_uci_bit
return i; return i;
} }
/* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit HARQ
*/
#ifndef MIMO_ENB
static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos)
{
uint32_t p0 = pos[0].position;
uint32_t p1 = pos[1].position;
uint32_t q0 = c_seq[p0]?q_bits[p0]:-q_bits[p0];
uint32_t q1 = c_seq[p0]?q_bits[p1]:-q_bits[p1];
return -(q0+q1);
}
int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq,
float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks)
{
int32_t rx_ack = 0;
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
}
uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta);
// Use the same interleaver function to get the HARQ bit position
for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]);
rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, &ack_bits[cfg->grant.Qm*i]);
}
if (acks) {
acks[0] = rx_ack>0;
}
return (int) Qprime;
}
#else
static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3]) static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3])
{ {
uint32_t p0 = pos[Qm * 0 + 0].position; uint32_t p0 = pos[Qm * 0 + 0].position;
@ -603,10 +645,6 @@ static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos
data[2] -= q2 + q5; data[2] -= q2 + q5;
} }
/* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit HARQ
*/
int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq,
float beta, uint32_t H_prime_total, float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks) uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks)
@ -635,6 +673,7 @@ int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_s
} }
return (int) Qprime; return (int) Qprime;
} }
#endif
/* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 /* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit HARQ * Currently only supporting 1-bit HARQ
@ -681,7 +720,7 @@ int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_se
for (uint32_t i=0;i<Qprime;i++) { for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ri_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); uci_ulsch_interleave_ri_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]);
if ((i % 3 == 0) && i > 0) { if ((i % 3 == 0) && i > 0) {
decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum); //decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum);
} }
} }

@ -76,9 +76,10 @@ static void log_overflow(rf_uhd_handler_t *h) {
} }
} }
static void log_late(rf_uhd_handler_t *h) { static void log_late(rf_uhd_handler_t *h, bool is_rx) {
if (h->uhd_error_handler) { if (h->uhd_error_handler) {
srslte_rf_error_t error; srslte_rf_error_t error;
error.opt = is_rx?1:0;
bzero(&error, sizeof(srslte_rf_error_t)); bzero(&error, sizeof(srslte_rf_error_t));
error.type = SRSLTE_RF_ERROR_LATE; error.type = SRSLTE_RF_ERROR_LATE;
h->uhd_error_handler(error); h->uhd_error_handler(error);
@ -109,7 +110,7 @@ static void* async_thread(void *h) {
event_code == UHD_ASYNC_METADATA_EVENT_CODE_UNDERFLOW_IN_PACKET) { event_code == UHD_ASYNC_METADATA_EVENT_CODE_UNDERFLOW_IN_PACKET) {
log_underflow(handler); log_underflow(handler);
} else if (event_code == UHD_ASYNC_METADATA_EVENT_CODE_TIME_ERROR) { } else if (event_code == UHD_ASYNC_METADATA_EVENT_CODE_TIME_ERROR) {
log_late(handler); log_late(handler, false);
} }
} }
} else { } else {
@ -290,6 +291,13 @@ int rf_uhd_open(char *args, void **h)
return rf_uhd_open_multi(args, h, 1); return rf_uhd_open_multi(args, h, 1);
} }
static void remove_substring(char *s,const char *toremove)
{
while((s=strstr(s,toremove))) {
memmove(s,s+strlen(toremove),1+strlen(s+strlen(toremove)));
}
}
int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
{ {
if (h) { if (h) {
@ -325,6 +333,30 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
bzero(zero_mem, sizeof(cf_t)*64*1024); bzero(zero_mem, sizeof(cf_t)*64*1024);
// Check external clock argument
enum {DEFAULT, EXTERNAL, GPSDO} clock_src;
if (strstr(args, "clock=external")) {
remove_substring(args, "clock=external");
clock_src = EXTERNAL;
} else if (strstr(args, "clock=gpsdo")) {
printf("Using GPSDO clock\n");
remove_substring(args, "clock=gpsdo");
clock_src = GPSDO;
} else {
clock_src = DEFAULT;
}
// Set over the wire format
char *otw_format = "sc16";
if (strstr(args, "otw_format=sc12")) {
otw_format = "sc12";
} else if (strstr(args, "otw_format=sc16")) {
/* Do nothing */
} else if (strstr(args, "otw_format=")) {
fprintf(stderr, "Wrong over the wire format. Valid formats: sc12, sc16\n");
return -1;
}
/* If device type or name not given in args, choose a B200 */ /* If device type or name not given in args, choose a B200 */
if (args[0]=='\0') { if (args[0]=='\0') {
if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) { if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) {
@ -379,14 +411,12 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
} }
// Set external clock reference // Set external clock reference
if (strstr(args, "clock=external")) { if (clock_src == EXTERNAL) {
uhd_usrp_set_clock_source(handler->usrp, "external", 0); uhd_usrp_set_clock_source(handler->usrp, "external", 0);
} else if (strstr(args, "clock=gpsdo")) { } else if (clock_src == GPSDO) {
printf("Using GPSDO clock\n");
uhd_usrp_set_clock_source(handler->usrp, "gpsdo", 0); uhd_usrp_set_clock_source(handler->usrp, "gpsdo", 0);
} }
handler->has_rssi = get_has_rssi(handler); handler->has_rssi = get_has_rssi(handler);
if (handler->has_rssi) { if (handler->has_rssi) {
uhd_sensor_value_make_from_realnum(&handler->rssi_value, "rssi", 0, "dBm", "%f"); uhd_sensor_value_make_from_realnum(&handler->rssi_value, "rssi", 0, "dBm", "%f");
@ -395,7 +425,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
size_t channel[4] = {0, 1, 2, 3}; size_t channel[4] = {0, 1, 2, 3};
uhd_stream_args_t stream_args = { uhd_stream_args_t stream_args = {
.cpu_format = "fc32", .cpu_format = "fc32",
.otw_format = "sc16", .otw_format = otw_format,
.args = "", .args = "",
.channel_list = channel, .channel_list = channel,
.n_channels = nof_channels, .n_channels = nof_channels,
@ -405,8 +435,10 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
handler->nof_tx_channels = nof_channels; handler->nof_tx_channels = nof_channels;
/* Set default rate to avoid decimation warnings */ /* Set default rate to avoid decimation warnings */
uhd_usrp_set_rx_rate(handler->usrp, 1.92e6, 0); for (int i=0;i<nof_channels;i++) {
uhd_usrp_set_tx_rate(handler->usrp, 1.92e6, 0); uhd_usrp_set_rx_rate(handler->usrp, 1.92e6, i);
uhd_usrp_set_tx_rate(handler->usrp, 1.92e6, i);
}
/* Initialize rx and tx stremers */ /* Initialize rx and tx stremers */
uhd_rx_streamer_make(&handler->rx_stream); uhd_rx_streamer_make(&handler->rx_stream);
@ -626,9 +658,10 @@ int rf_uhd_recv_with_time_multi(void *h,
if (error_code == UHD_RX_METADATA_ERROR_CODE_OVERFLOW) { if (error_code == UHD_RX_METADATA_ERROR_CODE_OVERFLOW) {
log_overflow(handler); log_overflow(handler);
} else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) { } else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) {
log_late(handler); log_late(handler, true);
} else if (error_code == UHD_RX_METADATA_ERROR_CODE_TIMEOUT) { } else if (error_code == UHD_RX_METADATA_ERROR_CODE_TIMEOUT) {
fprintf(stderr, "Error timed out while receiving asynchronoous messages from UHD.\n"); fprintf(stderr, "Error timed out while receiving samples from UHD.\n");
return -1;
} else if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE ) { } else if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE ) {
fprintf(stderr, "Error code 0x%x was returned during streaming. Aborting.\n", error_code); fprintf(stderr, "Error code 0x%x was returned during streaming. Aborting.\n", error_code);
} }
@ -677,11 +710,11 @@ int rf_uhd_send_timed_multi(void *h,
} }
size_t txd_samples; size_t txd_samples;
int trials = 0;
if (blocking) {
if (has_time_spec) { if (has_time_spec) {
uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs); uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs);
} }
int trials = 0;
if (blocking) {
int n = 0; int n = 0;
cf_t *data_c[4]; cf_t *data_c[4];
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -727,9 +760,15 @@ int rf_uhd_send_timed_multi(void *h,
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
buffs_ptr[i] = data[i]; buffs_ptr[i] = data[i];
} }
uhd_tx_metadata_set_has_time_spec(&handler->tx_md, is_start_of_burst);
uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst); uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst);
uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst);
return uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples); uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 3.0, &txd_samples);
if (error) {
fprintf(stderr, "Error sending to UHD: %d\n", error);
return -1;
}
return txd_samples;
} }
} }

@ -38,6 +38,12 @@ void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burs
(*md)->tx_metadata_cpp.start_of_burst = is_start_of_burst; (*md)->tx_metadata_cpp.start_of_burst = is_start_of_burst;
} }
void uhd_tx_metadata_set_has_time_spec(uhd_tx_metadata_handle *md, bool has_time_spec)
{
(*md)->tx_metadata_cpp.has_time_spec = has_time_spec;
}
void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst) void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst)
{ {
(*md)->tx_metadata_cpp.end_of_burst = is_end_of_burst; (*md)->tx_metadata_cpp.end_of_burst = is_end_of_burst;

@ -32,5 +32,6 @@
SRSLTE_API void rf_uhd_register_msg_handler_c(void (*new_handler)(const char*)); SRSLTE_API void rf_uhd_register_msg_handler_c(void (*new_handler)(const char*));
SRSLTE_API void uhd_tx_metadata_set_time_spec(uhd_tx_metadata_handle *md, time_t secs, double frac_secs); SRSLTE_API void uhd_tx_metadata_set_time_spec(uhd_tx_metadata_handle *md, time_t secs, double frac_secs);
SRSLTE_API void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burst); SRSLTE_API void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burst);
SRSLTE_API void uhd_tx_metadata_set_has_time_spec(uhd_tx_metadata_handle *md, bool has_time_spec);
SRSLTE_API void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst); SRSLTE_API void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst);
SRSLTE_API void uhd_tx_metadata_add_time_spec(uhd_tx_metadata_handle *md, double frac_secs); SRSLTE_API void uhd_tx_metadata_add_time_spec(uhd_tx_metadata_handle *md, double frac_secs);

@ -297,7 +297,7 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q,
ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->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");
break; return -1;
} else if (ret == 1) { } else if (ret == 1) {
/* This means a peak was found and ue_sync is now in tracking state */ /* This means a peak was found and ue_sync is now in tracking state */
ret = srslte_sync_get_cell_id(&q->ue_sync.strack); ret = srslte_sync_get_cell_id(&q->ue_sync.strack);

@ -65,8 +65,10 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
bzero(q, sizeof(srslte_ue_dl_t)); bzero(q, sizeof(srslte_ue_dl_t));
q->pkt_errors = 0; q->pdsch_pkt_errors = 0;
q->pkts_total = 0; q->pdsch_pkts_total = 0;
q->pmch_pkt_errors = 0;
q->pmch_pkts_total = 0;
q->pending_ul_dci_rnti = 0; q->pending_ul_dci_rnti = 0;
q->sample_offset = 0; q->sample_offset = 0;
q->nof_rx_antennas = nof_rx_antennas; q->nof_rx_antennas = nof_rx_antennas;
@ -75,6 +77,13 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
fprintf(stderr, "Error initiating FFT\n"); fprintf(stderr, "Error initiating FFT\n");
goto clean_exit; goto clean_exit;
} }
if (srslte_ofdm_rx_init_mbsfn(&q->fft_mbsfn, SRSLTE_CP_EXT, max_prb)) {
fprintf(stderr, "Error initiating FFT for MBSFN subframes \n");
goto clean_exit;
}
srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, 2); // Set a default to init
if (srslte_chest_dl_init(&q->chest, max_prb)) { if (srslte_chest_dl_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;
@ -97,6 +106,11 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
fprintf(stderr, "Error creating PDSCH object\n"); fprintf(stderr, "Error creating PDSCH object\n");
goto clean_exit; goto clean_exit;
} }
if (srslte_pmch_init_multi(&q->pmch, max_prb, nof_rx_antennas)) {
fprintf(stderr, "Error creating PMCH object\n");
goto clean_exit;
}
for (int i = 0; i < SRSLTE_MAX_TB; i++) { for (int i = 0; i < SRSLTE_MAX_TB; i++) {
q->softbuffers[i] = srslte_vec_malloc(sizeof(srslte_softbuffer_rx_t)); q->softbuffers[i] = srslte_vec_malloc(sizeof(srslte_softbuffer_rx_t));
if (!q->softbuffers[i]) { if (!q->softbuffers[i]) {
@ -115,7 +129,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
} }
srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft.symbol_sz); srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft.symbol_sz);
for (int j=0;j<nof_rx_antennas;j++) { for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
q->sf_symbols_m[j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); q->sf_symbols_m[j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t));
if (!q->sf_symbols_m[j]) { if (!q->sf_symbols_m[j]) {
perror("malloc"); perror("malloc");
@ -127,6 +141,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
} }
bzero(q->ce_m[i][j], MAX_SFLEN_RE * sizeof(cf_t));
} }
} }
@ -150,12 +165,14 @@ clean_exit:
void srslte_ue_dl_free(srslte_ue_dl_t *q) { void srslte_ue_dl_free(srslte_ue_dl_t *q) {
if (q) { if (q) {
srslte_ofdm_rx_free(&q->fft); srslte_ofdm_rx_free(&q->fft);
srslte_ofdm_rx_free(&q->fft_mbsfn);
srslte_chest_dl_free(&q->chest); srslte_chest_dl_free(&q->chest);
srslte_regs_free(&q->regs); srslte_regs_free(&q->regs);
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_pmch_free(&q->pmch);
srslte_cfo_free(&q->sfo_correct); srslte_cfo_free(&q->sfo_correct);
for (int i = 0; i < SRSLTE_MAX_TB; i++) { for (int i = 0; i < SRSLTE_MAX_TB; i++) {
srslte_softbuffer_rx_free(q->softbuffers[i]); srslte_softbuffer_rx_free(q->softbuffers[i]);
@ -163,7 +180,7 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) {
free(q->softbuffers[i]); free(q->softbuffers[i]);
} }
} }
for (int j=0;j<q->nof_rx_antennas;j++) { for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
if (q->sf_symbols_m[j]) { if (q->sf_symbols_m[j]) {
free(q->sf_symbols_m[j]); free(q->sf_symbols_m[j]);
} }
@ -257,6 +274,34 @@ void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) {
q->current_rnti = rnti; q->current_rnti = rnti;
} }
/* Set the area ID on pmch and chest_dl to generate scrambling sequence and reference
* signals.
*/
int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q,
uint16_t mbsfn_area_id) {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if(q != NULL) {
ret = SRSLTE_ERROR;
if(srslte_chest_dl_set_mbsfn_area_id(&q->chest, mbsfn_area_id)) {
fprintf(stderr, "Error setting MBSFN area ID \n");
return ret;
}
if(srslte_pmch_set_area_id(&q->pmch, mbsfn_area_id)) {
fprintf(stderr, "Error setting MBSFN area ID \n");
return ret;
}
q->current_mbsfn_area_id = mbsfn_area_id;
ret = SRSLTE_SUCCESS;
}
return ret;
}
void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q,
uint8_t non_mbsfn_region_length) {
srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length);
}
void srslte_ue_dl_reset(srslte_ue_dl_t *q) { void srslte_ue_dl_reset(srslte_ue_dl_t *q) {
for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){
@ -281,17 +326,28 @@ int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_
return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks); return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks);
} }
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi)
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi){
return srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, cfi, SRSLTE_SF_NORM);
}
int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type)
{ {
if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
/* Run FFT for all subframe data */ /* Run FFT for all subframe data */
for (int j=0;j<q->nof_rx_antennas;j++) { for (int j=0;j<q->nof_rx_antennas;j++) {
if(sf_type == SRSLTE_SF_MBSFN ) {
srslte_ofdm_rx_sf(&q->fft_mbsfn, input[j], q->sf_symbols_m[j]);
}else{
srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]); srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]);
}
/* Correct SFO multiplying by complex exponential in the time domain */ /* Correct SFO multiplying by complex exponential in the time domain */
if (q->sample_offset) { if (q->sample_offset) {
for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) { int nsym = (sf_type == SRSLTE_SF_MBSFN)?SRSLTE_CP_EXT_NSYMB:SRSLTE_CP_NSYMB(q->cell.cp);
for (int i=0;i<2*nsym;i++) {
srslte_cfo_correct(&q->sfo_correct, srslte_cfo_correct(&q->sfo_correct,
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
@ -299,18 +355,28 @@ int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_P
} }
} }
} }
return srslte_ue_dl_decode_estimate(q, sf_idx, cfi); return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, sf_type);
} else { } else {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
} }
int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) { int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) {
return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM);
}
int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) {
float cfi_corr; float cfi_corr;
if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
/* Get channel estimates for each port */ /* Get channel estimates for each port */
if(sf_type == SRSLTE_SF_MBSFN){
srslte_chest_dl_estimate_multi_mbsfn(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas, q->current_mbsfn_area_id);
}else{
srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas); srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas);
}
/* First decode PCFICH and obtain CFI */ /* First decode PCFICH and obtain CFI */
if (srslte_pcfich_decode_multi(&q->pcfich, q->sf_symbols_m, q->ce_m, if (srslte_pcfich_decode_multi(&q->pcfich, q->sf_symbols_m, q->ce_m,
@ -357,8 +423,12 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3
} }
} }
} }
if(SRSLTE_SF_MBSFN == grant->sf_type) {
return srslte_pmch_cfg(&q->pmch_cfg, q->cell, grant, cfi, sf_idx);
} else {
return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi);
} }
}
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti, uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti,
@ -371,7 +441,7 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
uint32_t cfi; uint32_t cfi;
uint32_t sf_idx = tti%10; uint32_t sf_idx = tti%10;
if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) { if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) {
return ret; return ret;
} }
@ -475,12 +545,13 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
noise_estimate, noise_estimate,
rnti, data, acks); rnti, data, acks);
for (int tb = 0; tb < SRSLTE_MAX_TB; tb++) { for (int tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (grant.tb_en[tb]) { if (grant.tb_en[tb]) {
if (!acks[tb]) { if (!acks[tb]) {
q->pkt_errors++; q->pdsch_pkt_errors++;
} }
q->pkts_total++; q->pdsch_pkts_total++;
} }
} }
@ -509,6 +580,69 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
} }
} }
int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data,
uint32_t tti)
{
srslte_ra_dl_grant_t grant;
int ret = SRSLTE_ERROR;
uint32_t cfi;
uint32_t sf_idx = tti%10;
if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) {
return ret;
}
float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest);
// Uncoment next line to do ZF by default in pdsch_ue example
//float noise_estimate = 0;
grant.sf_type = SRSLTE_SF_MBSFN;
grant.nof_tb = 1;
grant.mcs[0].idx = 2;
grant.nof_prb = q->pmch.cell.nof_prb;
srslte_dl_fill_ra_mcs(&grant.mcs[0], grant.nof_prb);
srslte_softbuffer_rx_reset_tbs(q->softbuffers[0], (uint32_t) grant.mcs[0].tbs);
for(int j = 0; j < 2; j++){
for(int f = 0; f < grant.nof_prb; f++){
grant.prb_idx[j][f] = true;
}
}
grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod);
// redundancy version is set to 0 for the PMCH
if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, SRSLTE_PMCH_RV, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA)) {
return SRSLTE_ERROR;
}
if (q->pmch_cfg.grant.mcs[0].mod > 0 && q->pmch_cfg.grant.mcs[0].tbs >= 0) {
ret = srslte_pmch_decode_multi(&q->pmch, &q->pmch_cfg, q->softbuffers[0],
q->sf_symbols_m, q->ce_m,
noise_estimate,
q->current_mbsfn_area_id, data);
if (ret == SRSLTE_ERROR) {
q->pmch_pkt_errors++;
} else if (ret == SRSLTE_ERROR_INVALID_INPUTS) {
fprintf(stderr, "Error calling srslte_pmch_decode()\n");
}
}
printf("q->pmch_pkts_total %d \n", q->pmch_pkts_total);
printf("qq->pmch_pkt_errors %d \n", q->pmch_pkt_errors);
q->pmch_pkts_total++;
if (ret == SRSLTE_SUCCESS) {
return q->pmch_cfg.grant.mcs[0].tbs;
} else {
return 0;
}
}
/* Compute the Rank Indicator (RI) and Precoder Matrix Indicator (PMI) by computing the Signal to Interference plus /* Compute the Rank Indicator (RI) and Precoder Matrix Indicator (PMI) by computing the Signal to Interference plus
* Noise Ratio (SINR), valid for TM4 */ * Noise Ratio (SINR), valid for TM4 */
int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, float *current_sinr) { int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, float *current_sinr) {
@ -516,10 +650,10 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo
float best_sinr = -INFINITY; float best_sinr = -INFINITY;
uint8_t best_pmi = 0, best_ri = 0; uint8_t best_pmi = 0, best_ri = 0;
if (q->cell.nof_ports < 2 || q->nof_rx_antennas < 2) { if (q->cell.nof_ports < 2) {
/* Do nothing */ /* Do nothing */
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} else if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { } else {
if (srslte_pdsch_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate, if (srslte_pdsch_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate,
SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), q->pmi, q->sinr)) { SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), q->pmi, q->sinr)) {
ERROR("SINR calculation error"); ERROR("SINR calculation error");
@ -527,7 +661,7 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo
} }
/* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */
for (uint32_t nof_layers = 1; nof_layers <= 2; nof_layers++) { for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) {
float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers; float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers;
if (_sinr > best_sinr + 0.1) { if (_sinr > best_sinr + 0.1) {
best_sinr = _sinr; best_sinr = _sinr;
@ -535,6 +669,13 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo
best_ri = (uint8_t) (nof_layers - 1); best_ri = (uint8_t) (nof_layers - 1);
} }
} }
}
/* Print Trace */
if (ri != NULL && pmi != NULL && current_sinr != NULL) {
INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi,
10*log10(*current_sinr), q->pdsch_cfg.nof_layers, q->pdsch_cfg.codebook_idx);
}
/* Set RI */ /* Set RI */
if (ri != NULL) { if (ri != NULL) {
@ -558,16 +699,6 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo
} }
} }
/* Print Trace */
if (ri != NULL && pmi != NULL && current_sinr != NULL) {
INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi,
10*log10(*current_sinr), q->pdsch_cfg.nof_layers, q->pdsch_cfg.codebook_idx);
}
} else {
ERROR("Not implemented configuration");
return SRSLTE_ERROR_INVALID_INPUTS;
}
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -776,13 +907,7 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr
sf_idx, n_prb_lowest, n_dmrs, ngroup, nseq, sf_idx, n_prb_lowest, n_dmrs, ngroup, nseq,
srslte_phich_ngroups(&q->phich), srslte_phich_nsf(&q->phich)); srslte_phich_ngroups(&q->phich), srslte_phich_nsf(&q->phich));
cf_t *ce0[SRSLTE_MAX_PORTS]; if (!srslte_phich_decode(&q->phich, q->sf_symbols_m, q->ce_m, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) {
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ce0[i] = q->ce_m[i][0];
}
if (!srslte_phich_decode(&q->phich, q->sf_symbols_m[0], ce0, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) {
INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance); INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance);
} else { } else {
fprintf(stderr, "Error decoding PHICH\n"); fprintf(stderr, "Error decoding PHICH\n");
@ -815,16 +940,16 @@ void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuf
srslte_vec_save_file("pdcch_llr", q->pdcch.llr, q->pdcch.nof_cce*72*sizeof(float)); srslte_vec_save_file("pdcch_llr", q->pdcch.llr, q->pdcch.nof_cce*72*sizeof(float));
srslte_vec_save_file("pdsch_symbols", q->pdsch.d, q->pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); srslte_vec_save_file("pdsch_symbols", q->pdsch.d[0], q->pdsch_cfg.nbits[0].nof_re*sizeof(cf_t));
srslte_vec_save_file("llr", q->pdsch.e, q->pdsch_cfg.nbits[0].nof_bits*sizeof(cf_t)); srslte_vec_save_file("llr", q->pdsch.e[0], q->pdsch_cfg.nbits[0].nof_bits*sizeof(cf_t));
int cb_len = q->pdsch_cfg.cb_segm[0].K1; int cb_len = q->pdsch_cfg.cb_segm[0].K1;
for (int i=0;i<q->pdsch_cfg.cb_segm[0].C;i++) { for (int i=0;i<q->pdsch_cfg.cb_segm[0].C;i++) {
char tmpstr[64]; char tmpstr[64];
snprintf(tmpstr,64,"rmout_%d.dat",i); snprintf(tmpstr,64,"rmout_%d.dat",i);
srslte_vec_save_file(tmpstr, softbuffer->buffer_f[i], (3*cb_len+12)*sizeof(int16_t)); srslte_vec_save_file(tmpstr, softbuffer->buffer_f[i], (3*cb_len+12)*sizeof(int16_t));
} }
printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, 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, rv_idx, rnti); q->pdsch_cfg.grant.mcs[0].idx, q->pdsch_cfg.grant.mcs[0].tbs, rv_idx, rnti);
} }

@ -271,7 +271,7 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q,
ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->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");
break; return -1;
} else if (srslte_ue_sync_get_sfidx(&q->ue_sync) == 0) { } else if (srslte_ue_sync_get_sfidx(&q->ue_sync) == 0) {
if (ret == 1) { if (ret == 1) {
mib_ret = srslte_ue_mib_decode(&q->ue_mib, q->sf_buffer[0], bch_payload, nof_tx_ports, sfn_offset); mib_ret = srslte_ue_mib_decode(&q->ue_mib, q->sf_buffer[0], bch_payload, nof_tx_ports, sfn_offset);

@ -513,7 +513,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) {
discard the offseted samples to align next frame */ discard the offseted samples to align next frame */
if (q->next_rf_sample_offset > 0 && q->next_rf_sample_offset < MAX_TIME_OFFSET) { if (q->next_rf_sample_offset > 0 && q->next_rf_sample_offset < MAX_TIME_OFFSET) {
DEBUG("Positive time offset %d samples.\n", q->next_rf_sample_offset); DEBUG("Positive time offset %d samples.\n", q->next_rf_sample_offset);
if (q->recv_callback(q->stream, dummy_offset_buffer, (uint32_t) q->next_rf_sample_offset, &q->last_timestamp) < 0) { if (q->recv_callback(q->stream, dummy_offset_buffer, (uint32_t) q->next_rf_sample_offset, NULL) < 0) {
fprintf(stderr, "Error receiving from USRP\n"); fprintf(stderr, "Error receiving from USRP\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -676,6 +676,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
/* Track PSS/SSS around the expected PSS position /* Track PSS/SSS around the expected PSS position
* In tracking phase, the subframe carrying the PSS is always the last one of the frame * In tracking phase, the subframe carrying the PSS is always the last one of the frame
*/ */
switch(srslte_sync_find(&q->strack, input_buffer[0], switch(srslte_sync_find(&q->strack, input_buffer[0],
q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2,
&track_idx)) &track_idx))

@ -30,6 +30,7 @@ extern "C" {
} }
#include "srslte/radio/radio.h" #include "srslte/radio/radio.h"
#include <string.h> #include <string.h>
#include <unistd.h>
namespace srslte { namespace srslte {
@ -61,6 +62,13 @@ bool radio::init(char *args, char *devname)
printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device));
} }
if (args) {
strncpy(saved_args, args, 128);
}
if (devname) {
strncpy(saved_devname, devname, 128);
}
return true; return true;
} }
@ -69,6 +77,16 @@ void radio::stop()
srslte_rf_close(&rf_device); srslte_rf_close(&rf_device);
} }
void radio::reset()
{
printf("Resetting Radio...\n");
srslte_rf_close(&rf_device);
sleep(3);
if (srslte_rf_open_devname(&rf_device, saved_devname, saved_args)) {
fprintf(stderr, "Error opening RF device\n");
}
}
void radio::set_manual_calibration(rf_cal_t* calibration) void radio::set_manual_calibration(rf_cal_t* calibration)
{ {
srslte_rf_cal_t tx_cal; srslte_rf_cal_t tx_cal;
@ -102,11 +120,6 @@ void radio::set_tx_adv_neg(bool tx_adv_is_neg) {
tx_adv_negative = tx_adv_is_neg; tx_adv_negative = tx_adv_is_neg;
} }
void radio::tx_offset(int offset_)
{
offset = offset_;
}
bool radio::start_agc(bool tx_gain_same_rx) bool radio::start_agc(bool tx_gain_same_rx)
{ {
if (srslte_rf_start_gain_thread(&rf_device, tx_gain_same_rx)) { if (srslte_rf_start_gain_thread(&rf_device, tx_gain_same_rx)) {
@ -167,6 +180,12 @@ bool radio::has_rssi()
return srslte_rf_has_rssi(&rf_device); return srslte_rf_has_rssi(&rf_device);
} }
bool radio::is_first_of_burst() {
return is_start_of_burst;
}
#define BLOCKING_TX true
bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
{ {
void *iq_samples[4] = {(void *) zeros, (void *) zeros, (void *) zeros, (void *) zeros}; void *iq_samples[4] = {(void *) zeros, (void *) zeros, (void *) zeros, (void *) zeros};
@ -194,8 +213,9 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
save_trace(0, &tx_time); save_trace(0, &tx_time);
iq_samples[0] = buffer; iq_samples[0] = buffer;
int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples+offset, tx_time.full_secs, tx_time.frac_secs, true, is_start_of_burst, false); int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples,
offset = 0; tx_time.full_secs, tx_time.frac_secs,
BLOCKING_TX, is_start_of_burst, false);
is_start_of_burst = false; is_start_of_burst = false;
if (ret > 0) { if (ret > 0) {
return true; return true;
@ -204,16 +224,6 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
} }
} }
uint32_t radio::get_tti_len()
{
return sf_len;
}
void radio::set_tti_len(uint32_t sf_len_)
{
sf_len = sf_len_;
}
void radio::tx_end() void radio::tx_end()
{ {
if (!is_start_of_burst) { if (!is_start_of_burst) {

@ -30,6 +30,13 @@ bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname
printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device));
} }
if (args) {
strncpy(saved_args, args, 128);
}
if (devname) {
strncpy(saved_devname, devname, 128);
}
return true; return true;
} }

@ -65,6 +65,15 @@ void pdcp::reset()
/******************************************************************************* /*******************************************************************************
RRC/GW interface RRC/GW interface
*******************************************************************************/ *******************************************************************************/
bool pdcp::is_drb_enabled(uint32_t lcid)
{
if(lcid >= SRSLTE_N_RADIO_BEARERS) {
pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid);
return false;
}
return pdcp_array[lcid].is_active();
}
void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu) void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
{ {
if(valid_lcid(lcid)) if(valid_lcid(lcid))

@ -65,7 +65,10 @@ void rlc::reset_metrics()
void rlc::stop() void rlc::stop()
{ {
reset(); for(uint32_t i=0; i<SRSLTE_N_RADIO_BEARERS; i++) {
if(rlc_array[i].active())
rlc_array[i].stop();
}
} }
void rlc::get_metrics(rlc_metrics_t &m) void rlc::get_metrics(rlc_metrics_t &m)

@ -93,6 +93,12 @@ void rlc_am::empty_queue() {
} }
} }
void rlc_am::stop()
{
reset();
pthread_mutex_destroy(&mutex);
}
void rlc_am::reset() void rlc_am::reset()
{ {
// Empty tx_sdu_queue before locking the mutex // Empty tx_sdu_queue before locking the mutex

@ -76,6 +76,11 @@ void rlc_entity::reset()
rlc = NULL; rlc = NULL;
} }
void rlc_entity::stop()
{
rlc->stop();
rlc = NULL;
}
void rlc_entity::empty_queue() void rlc_entity::empty_queue()
{ {

@ -66,6 +66,11 @@ void rlc_tm::reset()
empty_queue(); empty_queue();
} }
void rlc_tm::stop()
{
reset();
}
rlc_mode_t rlc_tm::get_mode() rlc_mode_t rlc_tm::get_mode()
{ {
return RLC_MODE_TM; return RLC_MODE_TM;

@ -62,7 +62,8 @@ void rlc_um::init(srslte::log *log_,
pdcp = pdcp_; pdcp = pdcp_;
rrc = rrc_; rrc = rrc_;
mac_timers = mac_timers_; mac_timers = mac_timers_;
reordering_timeout_id = mac_timers->get_unique_id(); reordering_timer_id = mac_timers->timer_get_unique_id();
reordering_timer = mac_timers->timer_get(reordering_timer_id);
} }
void rlc_um::configure(srslte_rlc_config_t cnfg_) void rlc_um::configure(srslte_rlc_config_t cnfg_)
@ -102,6 +103,12 @@ void rlc_um::empty_queue() {
} }
} }
void rlc_um::stop()
{
reset();
mac_timers->timer_release_id(reordering_timer_id);
}
void rlc_um::reset() void rlc_um::reset()
{ {
@ -119,7 +126,7 @@ void rlc_um::reset()
if(tx_sdu) if(tx_sdu)
tx_sdu->reset(); tx_sdu->reset();
if(mac_timers) if(mac_timers)
mac_timers->get(reordering_timeout_id)->stop(); reordering_timer->stop();
// Drop all messages in RX window // Drop all messages in RX window
std::map<uint32_t, rlc_umd_pdu_t>::iterator it; std::map<uint32_t, rlc_umd_pdu_t>::iterator it;
@ -203,7 +210,7 @@ void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes)
void rlc_um::timer_expired(uint32_t timeout_id) void rlc_um::timer_expired(uint32_t timeout_id)
{ {
if(reordering_timeout_id == timeout_id) if(reordering_timer_id == timeout_id)
{ {
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
@ -221,11 +228,11 @@ void rlc_um::timer_expired(uint32_t timeout_id)
reassemble_rx_sdus(); reassemble_rx_sdus();
log->debug("Finished reassemble from timeout id=%d\n", timeout_id); log->debug("Finished reassemble from timeout id=%d\n", timeout_id);
} }
mac_timers->get(reordering_timeout_id)->stop(); reordering_timer->stop();
if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur))
{ {
mac_timers->get(reordering_timeout_id)->set(this, cfg.t_reordering); reordering_timer->set(this, cfg.t_reordering);
mac_timers->get(reordering_timeout_id)->run(); reordering_timer->run();
vr_ux = vr_uh; vr_ux = vr_uh;
} }
@ -236,7 +243,7 @@ void rlc_um::timer_expired(uint32_t timeout_id)
bool rlc_um::reordering_timeout_running() bool rlc_um::reordering_timeout_running()
{ {
return mac_timers->get(reordering_timeout_id)->is_running(); return reordering_timer->is_running();
} }
/**************************************************************************** /****************************************************************************
@ -398,20 +405,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
log->debug("Finished reassemble from received PDU\n"); log->debug("Finished reassemble from received PDU\n");
// Update reordering variables and timers // Update reordering variables and timers
if(mac_timers->get(reordering_timeout_id)->is_running()) if(reordering_timer->is_running())
{ {
if(RX_MOD_BASE(vr_ux) <= RX_MOD_BASE(vr_ur) || if(RX_MOD_BASE(vr_ux) <= RX_MOD_BASE(vr_ur) ||
(!inside_reordering_window(vr_ux) && vr_ux != vr_uh)) (!inside_reordering_window(vr_ux) && vr_ux != vr_uh))
{ {
mac_timers->get(reordering_timeout_id)->stop(); reordering_timer->stop();
} }
} }
if(!mac_timers->get(reordering_timeout_id)->is_running()) if(!reordering_timer->is_running())
{ {
if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur))
{ {
mac_timers->get(reordering_timeout_id)->set(this, cfg.t_reordering); reordering_timer->set(this, cfg.t_reordering);
mac_timers->get(reordering_timeout_id)->run(); reordering_timer->run();
vr_ux = vr_uh; vr_ux = vr_uh;
} }
} }
@ -506,10 +513,19 @@ void rlc_um::reassemble_rx_sdus()
} }
// Handle last segment // Handle last segment
// Handle last segment
if (rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES ||
rx_window[vr_ur].buf->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES ||
rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES) {
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes);
rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes;
log->debug("Writting last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n", log->debug("Writting last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n",
vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes);
} else {
log->error("Out of bounds while reassembling SDU buffer in UM: sdu_len=%d, window_buffer_len=%d, vr_ur=%d\n",
rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur);
}
vr_ur_in_rx_sdu = vr_ur; vr_ur_in_rx_sdu = vr_ur;
if(rlc_um_end_aligned(rx_window[vr_ur].header.fi)) if(rlc_um_end_aligned(rx_window[vr_ur].header.fi))
{ {

@ -38,11 +38,12 @@ class mac_dummy_timers
:public srslte::mac_interface_timers :public srslte::mac_interface_timers
{ {
public: public:
srslte::timers::timer* get(uint32_t timer_id) srslte::timers::timer* timer_get(uint32_t timer_id)
{ {
return &t; return &t;
} }
uint32_t get_unique_id(){return 0;} uint32_t timer_get_unique_id(){return 0;}
void timer_release_id(uint32_t id){}
private: private:
srslte::timers::timer t; srslte::timers::timer t;

@ -38,16 +38,16 @@ class mac_dummy_timers
:public srslte::mac_interface_timers :public srslte::mac_interface_timers
{ {
public: public:
srslte::timers::timer* get(uint32_t timer_id) srslte::timers::timer* timer_get(uint32_t timer_id)
{ {
return &t; return &t;
} }
uint32_t get_unique_id(){return 0;} uint32_t timer_get_unique_id(){return 0;}
void step() void step()
{ {
t.step(); t.step();
} }
void timer_release_id(uint32_t timer_id) {}
private: private:
srslte::timers::timer t; srslte::timers::timer t;
}; };
@ -205,8 +205,8 @@ void loss_test()
} }
// Step the reordering timer until expiry // Step the reordering timer until expiry
while(!timers.get(1)->is_expired()) while(!timers.timer_get(1)->is_expired())
timers.get(1)->step(); timers.timer_get(1)->step();
assert(NBUFS-1 == tester.n_sdus); assert(NBUFS-1 == tester.n_sdus);
} }

@ -58,8 +58,8 @@ drb_config = drb.conf
##################################################################### #####################################################################
[rf] [rf]
dl_earfcn = 3400 dl_earfcn = 3400
tx_gain = 80 tx_gain = 70
rx_gain = 50 rx_gain = 40
#device_name = auto #device_name = auto
#device_args = auto #device_args = auto
@ -98,8 +98,9 @@ filename = /tmp/enb.pcap
# Logging layers: phy, mac, rlc, pdcp, rrc, nas, gtpu, usim, all # Logging layers: phy, mac, rlc, pdcp, rrc, nas, gtpu, usim, all
# Logging levels: debug, info, warning, error, none # Logging levels: debug, info, warning, error, none
# #
# filename: File path to use for log output # filename: File path to use for log output. Can be set to stdout
##################################################################### # to print logs to standard output
git c#####################################################################
[log] [log]
all_level = info all_level = info
all_hex_limit = 32 all_hex_limit = 32

@ -138,8 +138,6 @@ typedef struct {
Main UE class Main UE class
*******************************************************************************/ *******************************************************************************/
//#define LOG_STDOUT
class enb class enb
:public enb_metrics_interface { :public enb_metrics_interface {
public: public:
@ -180,11 +178,10 @@ private:
srsenb::gtpu gtpu; srsenb::gtpu gtpu;
srsenb::s1ap s1ap; srsenb::s1ap s1ap;
#ifdef LOG_STDOUT srslte::logger_stdout logger_stdout;
srslte::logger_stdout logger; srslte::logger_file logger_file;
#else srslte::logger *logger;
srslte::logger_file logger;
#endif
srslte::log_filter rf_log; srslte::log_filter rf_log;
std::vector<void*> phy_log; std::vector<void*> phy_log;
srslte::log_filter mac_log; srslte::log_filter mac_log;

@ -103,27 +103,14 @@ public:
bool process_pdus(); bool process_pdus();
void timer_expired(uint32_t timer_id); // Interface for upper-layer timers
srslte::timers::timer* timer_get(uint32_t timer_id);
srslte::timers::timer* get(uint32_t timer_id); void timer_release_id(uint32_t timer_id);
u_int32_t get_unique_id(); u_int32_t timer_get_unique_id();
uint32_t get_current_tti(); uint32_t get_current_tti();
void get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]); void get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]);
enum {
HARQ_RTT,
TIME_ALIGNMENT,
CONTENTION_TIMER,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
PHR_TIMER_PERIODIC,
PHR_TIMER_PROHIBIT,
NOF_MAC_TIMERS
} mac_timers_t;
static const int MAC_NOF_UPPER_TIMERS = 20;
private: private:
void log_step_ul(uint32_t tti); void log_step_ul(uint32_t tti);
@ -192,21 +179,18 @@ private:
/* Class to run upper-layer timers with normal priority */ /* Class to run upper-layer timers with normal priority */
class upper_timers : public thread { class timer_thread : public thread {
public: public:
upper_timers() : timers_db(MAC_NOF_UPPER_TIMERS),ttisync(10240) {start();} timer_thread(srslte::timers *t) : ttisync(10240),timers(t),running(false) {start();}
void tti_clock(); void tti_clock();
void stop(); void stop();
void reset();
srslte::timers::timer* get(uint32_t timer_id);
uint32_t get_unique_id();
private: private:
void run_thread(); void run_thread();
srslte::timers timers_db;
srslte::tti_sync_cv ttisync; srslte::tti_sync_cv ttisync;
srslte::timers *timers;
bool running; bool running;
}; };
upper_timers upper_timers_thread; timer_thread timers_thread;
/* Class to process MAC PDUs from DEMUX unit */ /* Class to process MAC PDUs from DEMUX unit */
class pdu_process : public thread { class pdu_process : public thread {

@ -75,7 +75,7 @@ public:
void stop(); void stop();
// gtpu_interface_rrc // gtpu_interface_rrc
void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in); void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in);
void rem_bearer(uint16_t rnti, uint32_t lcid); void rem_bearer(uint16_t rnti, uint32_t lcid);
void rem_user(uint16_t rnti); void rem_user(uint16_t rnti);
@ -98,11 +98,13 @@ private:
typedef struct{ typedef struct{
uint32_t teids_in[SRSENB_N_RADIO_BEARERS]; uint32_t teids_in[SRSENB_N_RADIO_BEARERS];
uint32_t teids_out[SRSENB_N_RADIO_BEARERS]; uint32_t teids_out[SRSENB_N_RADIO_BEARERS];
uint32_t spgw_addrs[SRSENB_N_RADIO_BEARERS];
}bearer_map; }bearer_map;
std::map<uint16_t, bearer_map> rnti_bearers; std::map<uint16_t, bearer_map> rnti_bearers;
srslte_netsink_t snk; // Socket file descriptors
srslte_netsource_t src; int snk_fd;
int src_fd;
void run_thread(); void run_thread();

@ -195,6 +195,9 @@ public:
bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e); bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e);
bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e);
void setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos,
LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out,
LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu);
bool release_erabs(); bool release_erabs();
void notify_s1ap_ue_ctxt_setup_complete(); void notify_s1ap_ue_ctxt_setup_complete();

@ -26,6 +26,7 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <enb.h>
#include "enb.h" #include "enb.h"
namespace srsenb { namespace srsenb {
@ -68,30 +69,32 @@ bool enb::init(all_args_t *args_)
{ {
args = args_; args = args_;
#ifndef LOG_STDOUT if (!args->log.filename.compare("stdout")) {
logger.init(args->log.filename); logger = &logger_stdout;
#endif } else {
rf_log.init("RF ", &logger); logger_file.init(args->log.filename);
logger_file.log("\n\n");
logger = &logger_file;
}
rf_log.init("RF ", logger);
// Create array of pointers to phy_logs // Create array of pointers to phy_logs
for (int i=0;i<args->expert.phy.nof_phy_threads;i++) { for (int i=0;i<args->expert.phy.nof_phy_threads;i++) {
srslte::log_filter *mylog = new srslte::log_filter; srslte::log_filter *mylog = new srslte::log_filter;
char tmp[16]; char tmp[16];
sprintf(tmp, "PHY%d",i); sprintf(tmp, "PHY%d",i);
mylog->init(tmp, &logger, true); mylog->init(tmp, logger, true);
phy_log.push_back((void*) mylog); phy_log.push_back((void*) mylog);
} }
mac_log.init("MAC ", &logger, true); mac_log.init("MAC ", logger, true);
rlc_log.init("RLC ", &logger); rlc_log.init("RLC ", logger);
pdcp_log.init("PDCP", &logger); pdcp_log.init("PDCP", logger);
rrc_log.init("RRC ", &logger); rrc_log.init("RRC ", logger);
gtpu_log.init("GTPU", &logger); gtpu_log.init("GTPU", logger);
s1ap_log.init("S1AP", &logger); s1ap_log.init("S1AP", logger);
// Init logs // Init logs
#ifndef LOG_STDOUT
logger.log("\n\n");
#endif
rf_log.set_level(srslte::LOG_LEVEL_INFO); rf_log.set_level(srslte::LOG_LEVEL_INFO);
for (int i=0;i<args->expert.phy.nof_phy_threads;i++) { for (int i=0;i<args->expert.phy.nof_phy_threads;i++) {
((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level)); ((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level));
@ -225,13 +228,13 @@ void enb::stop()
{ {
if(started) if(started)
{ {
mac.stop(); gtpu.stop();
phy.stop(); phy.stop();
usleep(1e5); mac.stop();
usleep(100000);
rlc.stop(); rlc.stop();
pdcp.stop(); pdcp.stop();
gtpu.stop();
rrc.stop(); rrc.stop();
usleep(1e5); usleep(1e5);

@ -42,7 +42,8 @@
namespace srsenb { namespace srsenb {
mac::mac() : timers_db((uint32_t) NOF_MAC_TIMERS), mac::mac() : timers_db(128),
timers_thread(&timers_db),
rar_pdu_msg(sched_interface::MAX_RAR_LIST), rar_pdu_msg(sched_interface::MAX_RAR_LIST),
pdu_process_thread(this) pdu_process_thread(this)
{ {
@ -99,7 +100,7 @@ void mac::stop()
srslte_softbuffer_tx_free(&pcch_softbuffer_tx); srslte_softbuffer_tx_free(&pcch_softbuffer_tx);
srslte_softbuffer_tx_free(&rar_softbuffer_tx); srslte_softbuffer_tx_free(&rar_softbuffer_tx);
started = false; started = false;
upper_timers_thread.stop(); timers_thread.stop();
pdu_process_thread.stop(); pdu_process_thread.stop();
} }
@ -109,7 +110,6 @@ void mac::reset()
Info("Resetting MAC\n"); Info("Resetting MAC\n");
timers_db.stop_all(); timers_db.stop_all();
upper_timers_thread.reset();
tti = 0; tti = 0;
last_rnti = 70; last_rnti = 70;
@ -119,18 +119,6 @@ void mac::reset()
} }
uint32_t mac::get_unique_id()
{
return upper_timers_thread.get_unique_id();
}
/* Front-end to upper-layer timers */
srslte::timers::timer* mac::get(uint32_t timer_id)
{
return upper_timers_thread.get(timer_id);
}
void mac::start_pcap(srslte::mac_pcap* pcap_) void mac::start_pcap(srslte::mac_pcap* pcap_)
{ {
pcap = pcap_; pcap = pcap_;
@ -453,7 +441,6 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
dl_sched_res->sched_grants[n].data = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu, dl_sched_res->sched_grants[n].data = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu,
sched_result.data[i].nof_pdu_elems, sched_result.data[i].nof_pdu_elems,
sched_result.data[i].tbs); sched_result.data[i].tbs);
srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.data[i].tbs);
if (pcap) { if (pcap) {
pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, rnti, true, tti); pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, rnti, true, tti);
@ -474,7 +461,6 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
// Set softbuffer (there are no retx in RAR but a softbuffer is required) // Set softbuffer (there are no retx in RAR but a softbuffer is required)
dl_sched_res->sched_grants[n].softbuffer = &rar_softbuffer_tx; dl_sched_res->sched_grants[n].softbuffer = &rar_softbuffer_tx;
srslte_softbuffer_tx_reset_tbs(&rar_softbuffer_tx, sched_result.rar[i].tbs); // TBS is usually 54-bit
// Assemble PDU // Assemble PDU
dl_sched_res->sched_grants[n].data = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs); dl_sched_res->sched_grants[n].data = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs);
@ -497,9 +483,6 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
// Set softbuffer // Set softbuffer
if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) { if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) {
dl_sched_res->sched_grants[n].softbuffer = &bcch_softbuffer_tx[sched_result.bc[i].index]; dl_sched_res->sched_grants[n].softbuffer = &bcch_softbuffer_tx[sched_result.bc[i].index];
if (sched_result.bc[i].dci.rv_idx == 0) {
srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.bc[i].tbs*8);
}
dl_sched_res->sched_grants[n].data = assemble_si(sched_result.bc[i].index); dl_sched_res->sched_grants[n].data = assemble_si(sched_result.bc[i].index);
#ifdef WRITE_SIB_PCAP #ifdef WRITE_SIB_PCAP
if (pcap) { if (pcap) {
@ -508,7 +491,6 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
#endif #endif
} else { } else {
dl_sched_res->sched_grants[n].softbuffer = &pcch_softbuffer_tx; dl_sched_res->sched_grants[n].softbuffer = &pcch_softbuffer_tx;
srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.bc[i].tbs*8);
dl_sched_res->sched_grants[n].data = pcch_payload_buffer; dl_sched_res->sched_grants[n].data = pcch_payload_buffer;
rlc_h->read_pdu_pcch(pcch_payload_buffer, pcch_payload_buffer_len); rlc_h->read_pdu_pcch(pcch_payload_buffer, pcch_payload_buffer_len);
@ -640,46 +622,59 @@ void mac::log_step_dl(uint32_t tti)
void mac::tti_clock() void mac::tti_clock()
{ {
upper_timers_thread.tti_clock(); timers_thread.tti_clock();
} }
/******************************************************** /********************************************************
* *
* Class to run upper-layer timers with normal priority * Interface for upper layer timers
* *
*******************************************************/ *******************************************************/
void mac::upper_timers::run_thread() uint32_t mac::timer_get_unique_id()
{ {
running=true; return timers_db.get_unique_id();
ttisync.set_producer_cntr(0);
ttisync.resync();
while(running) {
ttisync.wait();
timers_db.step_all();
} }
void mac::timer_release_id(uint32_t timer_id)
{
timers_db.release_id(timer_id);
} }
srslte::timers::timer* mac::upper_timers::get(uint32_t timer_id)
/* Front-end to upper-layer timers */
srslte::timers::timer* mac::timer_get(uint32_t timer_id)
{ {
return timers_db.get(timer_id%MAC_NOF_UPPER_TIMERS); return timers_db.get(timer_id);
} }
uint32_t mac::upper_timers::get_unique_id()
/********************************************************
*
* Class to run timers with normal priority
*
*******************************************************/
void mac::timer_thread::run_thread()
{ {
return timers_db.get_unique_id(); running=true;
ttisync.set_producer_cntr(0);
ttisync.resync();
while(running) {
ttisync.wait();
timers->step_all();
}
} }
void mac::upper_timers::stop() void mac::timer_thread::stop()
{ {
running=false; running=false;
ttisync.increase(); ttisync.increase();
wait_thread_finish(); wait_thread_finish();
} }
void mac::upper_timers::reset()
{
timers_db.stop_all();
}
void mac::upper_timers::tti_clock() void mac::timer_thread::tti_clock()
{ {
ttisync.increase(); ttisync.increase();
} }

@ -635,7 +635,7 @@ uint32_t sched_ue::get_required_prb_ul(uint32_t req_bytes)
return 0; return 0;
} }
for (n=1;n<=cell.nof_prb && nbytes < req_bytes + 4;n++) { for (n=1;n<cell.nof_prb && nbytes < req_bytes + 4;n++) {
uint32_t nof_re = (2*(SRSLTE_CP_NSYMB(cell.cp)-1) - N_srs)*n*SRSLTE_NRE; uint32_t nof_re = (2*(SRSLTE_CP_NSYMB(cell.cp)-1) - N_srs)*n*SRSLTE_NRE;
int tbs = 0; int tbs = 0;
if (fixed_mcs_ul < 0) { if (fixed_mcs_ul < 0) {
@ -648,7 +648,7 @@ uint32_t sched_ue::get_required_prb_ul(uint32_t req_bytes)
} }
} }
while (!srslte_dft_precoding_valid_prb(n)) { while (!srslte_dft_precoding_valid_prb(n) && n<=cell.nof_prb) {
n++; n++;
} }
@ -705,7 +705,7 @@ uint32_t sched_ue::get_aggr_level(uint32_t nof_bits)
do { do {
coderate = srslte_pdcch_coderate(nof_bits, l); coderate = srslte_pdcch_coderate(nof_bits, l);
l++; l++;
} while(l<3 && coderate > max_coderate); } while(l<3 && 1.5*coderate > max_coderate);
Debug("SCHED: CQI=%d, l=%d, nof_bits=%d, coderate=%.2f, max_coderate=%.2f\n", dl_cqi, l, nof_bits, coderate, max_coderate); Debug("SCHED: CQI=%d, l=%d, nof_bits=%d, coderate=%.2f, max_coderate=%.2f\n", dl_cqi, l, nof_bits, coderate, max_coderate);
return l; return l;
} }
@ -815,7 +815,7 @@ int sched_ue::alloc_tbs(uint32_t nof_prb,
// TODO: Compute real spectral efficiency based on PUSCH-UCI configuration // TODO: Compute real spectral efficiency based on PUSCH-UCI configuration
if (has_pucch && is_ul) { if (has_pucch && is_ul) {
cqi-=2; cqi-=3;
} }
int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, max_Qm, &sel_mcs)/8; int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, max_Qm, &sel_mcs)/8;

@ -434,8 +434,6 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch,
ue_db[rnti].phich_info.n_prb_lowest = enb_ul.pusch_cfg.grant.n_prb_tilde[0]; ue_db[rnti].phich_info.n_prb_lowest = enb_ul.pusch_cfg.grant.n_prb_tilde[0];
ue_db[rnti].phich_info.n_dmrs = phy_grant.ncs_dmrs; ue_db[rnti].phich_info.n_dmrs = phy_grant.ncs_dmrs;
char cqi_str[64]; char cqi_str[64];
if (cqi_enabled) { if (cqi_enabled) {
srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value);
@ -689,10 +687,12 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process,
phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx); phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx);
} }
srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL}; srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL};
uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL}; uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL};
int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0}; int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0};
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_idx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0)) if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_idx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0))
{ {
fprintf(stderr, "Error putting PDSCH %d\n",i); fprintf(stderr, "Error putting PDSCH %d\n",i);

@ -26,6 +26,9 @@
#include "upper/gtpu.h" #include "upper/gtpu.h"
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
using namespace srslte; using namespace srslte;
@ -42,16 +45,51 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
pool = byte_buffer_pool::get_instance(); pool = byte_buffer_pool::get_instance();
if(0 != srslte_netsource_init(&src, gtp_bind_addr.c_str(), GTPU_PORT, SRSLTE_NETSOURCE_UDP)) { // Set up sink socket
gtpu_log->error("Failed to create source socket on %s:%d", gtp_bind_addr.c_str(), GTPU_PORT); snk_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (snk_fd < 0) {
gtpu_log->error("Failed to create sink socket\n");
return false; return false;
} }
if(0 != srslte_netsink_init(&snk, mme_addr.c_str(), GTPU_PORT, SRSLTE_NETSINK_UDP)) { if (fcntl(snk_fd, F_SETFL, O_NONBLOCK)) {
gtpu_log->error("Failed to create sink socket on %s:%d", mme_addr.c_str(), GTPU_PORT); gtpu_log->error("Failed to set non-blocking sink socket\n");
return false;
}
int enable = 1;
#if defined (SO_REUSEADDR)
if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n");
#endif
#if defined (SO_REUSEPORT)
if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0)
gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n");
#endif
// Set up source socket
src_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (src_fd < 0) {
gtpu_log->error("Failed to create source socket\n");
return false;
}
#if defined (SO_REUSEADDR)
if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n");
#endif
#if defined (SO_REUSEPORT)
if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0)
gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n");
#endif
struct sockaddr_in bindaddr;
bindaddr.sin_family = AF_INET;
bindaddr.sin_addr.s_addr = inet_addr(gtp_bind_addr.c_str());
bindaddr.sin_port = htons(GTPU_PORT);
if (bind(src_fd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in))) {
gtpu_log->error("Failed to bind on address %s, port %d\n", gtp_bind_addr, GTPU_PORT);
return false; return false;
} }
srslte_netsink_set_nonblocking(&snk);
// Setup a thread to receive packets from the src socket // Setup a thread to receive packets from the src socket
start(THREAD_PRIO); start(THREAD_PRIO);
@ -75,8 +113,12 @@ void gtpu::stop()
wait_thread_finish(); wait_thread_finish();
} }
srslte_netsink_free(&snk); if (snk_fd) {
srslte_netsource_free(&src); close(snk_fd);
}
if (src_fd) {
close(src_fd);
}
} }
// gtpu_interface_pdcp // gtpu_interface_pdcp
@ -89,28 +131,35 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu)
header.length = pdu->N_bytes; header.length = pdu->N_bytes;
header.teid = rnti_bearers[rnti].teids_out[lcid]; header.teid = rnti_bearers[rnti].teids_out[lcid];
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]);
servaddr.sin_port = htons(GTPU_PORT);
gtpu_write_header(&header, pdu); gtpu_write_header(&header, pdu);
srslte_netsink_write(&snk, pdu->msg, pdu->N_bytes); sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in));
pool->deallocate(pdu); pool->deallocate(pdu);
} }
// gtpu_interface_rrc // gtpu_interface_rrc
void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in)
{ {
// Allocate a TEID for the incoming tunnel // Allocate a TEID for the incoming tunnel
rntilcid_to_teidin(rnti, lcid, teid_in); rntilcid_to_teidin(rnti, lcid, teid_in);
gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, teid_out, *teid_in); gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, addr, teid_out, *teid_in);
// Initialize maps if it's a new RNTI // Initialize maps if it's a new RNTI
if(rnti_bearers.count(rnti) == 0) { if(rnti_bearers.count(rnti) == 0) {
for(int i=0;i<SRSENB_N_RADIO_BEARERS;i++) { for(int i=0;i<SRSENB_N_RADIO_BEARERS;i++) {
rnti_bearers[rnti].teids_in[i] = 0; rnti_bearers[rnti].teids_in[i] = 0;
rnti_bearers[rnti].teids_out[i] = 0; rnti_bearers[rnti].teids_out[i] = 0;
rnti_bearers[rnti].spgw_addrs[i] = 0;
} }
} }
rnti_bearers[rnti].teids_in[lcid] = *teid_in; rnti_bearers[rnti].teids_in[lcid] = *teid_in;
rnti_bearers[rnti].teids_out[lcid] = teid_out; rnti_bearers[rnti].teids_out[lcid] = teid_out;
rnti_bearers[rnti].spgw_addrs[lcid] = addr;
} }
void gtpu::rem_bearer(uint16_t rnti, uint32_t lcid) void gtpu::rem_bearer(uint16_t rnti, uint32_t lcid)
@ -146,10 +195,16 @@ void gtpu::run_thread()
running=true; running=true;
while(run_enable) { while(run_enable) {
pdu->reset(); pdu->reset();
gtpu_log->debug("Waiting for read...\n"); gtpu_log->debug("Waiting for read...\n");
pdu->N_bytes = srslte_netsource_read(&src, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET); do{
pdu->N_bytes = recv(src_fd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0);
}while (pdu->N_bytes == -1 && errno == EAGAIN);
if (pdu->N_bytes == -1) {
gtpu_log->error("Failed to read from socket\n");
}
gtpu_header_t header; gtpu_header_t header;
gtpu_read_header(pdu, &header); gtpu_read_header(pdu, &header);

@ -224,6 +224,7 @@ void rrc::rem_user(uint16_t rnti)
rrc_log->info("Disconnecting rnti=0x%x.\n", rnti); rrc_log->info("Disconnecting rnti=0x%x.\n", rnti);
/* **Caution** order of removal here is imporant: from bottom to top */ /* **Caution** order of removal here is imporant: from bottom to top */
mac->ue_rem(rnti); // MAC handles PHY mac->ue_rem(rnti); // MAC handles PHY
usleep(50000);
rlc->rem_user(rnti); rlc->rem_user(rnti);
pdcp->rem_user(rnti); pdcp->rem_user(rnti);
gtpu->rem_user(rnti); gtpu->rem_user(rnti);
@ -945,20 +946,16 @@ bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e)
if(erab->iE_Extensions_present) { if(erab->iE_Extensions_present) {
parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n");
} }
if(erab->transportLayerAddress.n_bits > 32) {
uint8_t id = erab->e_RAB_ID.E_RAB_ID; parent->rrc_log->error("IPv6 addresses not currently supported\n");
erabs[id].id = id; return false;
memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT));
memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT));
uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out);
uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1)
parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in));
if(erab->nAS_PDU_present) {
memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets);
parent->erab_info.N_bytes = erab->nAS_PDU.n_octets;
} }
uint32_t teid_out;
uint8_to_uint32(erab->gTP_TEID.buffer, &teid_out);
LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu = erab->nAS_PDU_present ? &erab->nAS_PDU : NULL;
setup_erab(erab->e_RAB_ID.E_RAB_ID, &erab->e_RABlevelQoSParameters,
&erab->transportLayerAddress, teid_out, nas_pdu);
} }
return true; return true;
} }
@ -973,25 +970,43 @@ bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e)
if(erab->iE_Extensions_present) { if(erab->iE_Extensions_present) {
parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n");
} }
if(erab->transportLayerAddress.n_bits > 32) {
parent->rrc_log->error("IPv6 addresses not currently supported\n");
return false;
}
uint8_t id = erab->e_RAB_ID.E_RAB_ID; uint32_t teid_out;
erabs[id].id = id; uint8_to_uint32(erab->gTP_TEID.buffer, &teid_out);
memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); setup_erab(erab->e_RAB_ID.E_RAB_ID, &erab->e_RABlevelQoSParameters,
memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); &erab->transportLayerAddress, teid_out, &erab->nAS_PDU);
uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out);
uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1)
parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in));
memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets);
parent->erab_info.N_bytes = erab->nAS_PDU.n_octets;
} }
// Work in progress // Work in progress
notify_s1ap_ue_erab_setup_response(e); notify_s1ap_ue_erab_setup_response(e);
send_connection_reconf_new_bearer(e); send_connection_reconf_new_bearer(e);
return true; return true;
} }
void rrc::ue::setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos,
LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out,
LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu)
{
erabs[id].id = id;
memcpy(&erabs[id].qos_params, qos, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT));
memcpy(&erabs[id].address, addr, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT));
erabs[id].teid_out = teid_out;
uint8_t* bit_ptr = addr->buffer;
uint32_t addr_ = liblte_bits_2_value(&bit_ptr, addr->n_bits);
uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1)
parent->gtpu->add_bearer(rnti, lcid, addr_, erabs[id].teid_out, &(erabs[id].teid_in));
if(nas_pdu) {
memcpy(parent->erab_info.msg, nas_pdu->buffer, nas_pdu->n_octets);
parent->erab_info.N_bytes = nas_pdu->n_octets;
}
}
bool rrc::ue::release_erabs() bool rrc::ue::release_erabs()
{ {
typedef std::map<uint8_t, erab_t>::iterator it_t; typedef std::map<uint8_t, erab_t>::iterator it_t;

@ -42,7 +42,7 @@ class demux : public srslte::pdu_queue::process_callback
{ {
public: public:
demux(uint8_t nof_harq_proc_); demux(uint8_t nof_harq_proc_);
void init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers* timers_db_); void init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers::timer* time_alignment_timer);
bool process_pdus(); bool process_pdus();
uint8_t* request_buffer(uint32_t pid, uint32_t len); uint8_t* request_buffer(uint32_t pid, uint32_t len);
@ -74,7 +74,7 @@ private:
phy_interface_mac_common *phy_h; phy_interface_mac_common *phy_h;
srslte::log *log_h; srslte::log *log_h;
srslte::timers *timers_db; srslte::timers::timer *time_alignment_timer;
rlc_interface_mac *rlc; rlc_interface_mac *rlc;
uint8_t nof_harq_proc; uint8_t nof_harq_proc;

@ -35,7 +35,6 @@
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/timers.h" #include "srslte/common/timers.h"
#include "mac/demux.h" #include "mac/demux.h"
#include "mac/mac_common.h"
#include "mac/dl_sps.h" #include "mac/dl_sps.h"
#include "srslte/common/mac_pcap.h" #include "srslte/common/mac_pcap.h"
@ -58,9 +57,9 @@ public:
pcap = NULL; pcap = NULL;
} }
bool init(srslte::log *log_h_, srslte::timers *timers_, demux *demux_unit_) bool init(srslte::log *log_h_, srslte::timers::timer *timer_aligment_timer_, demux *demux_unit_)
{ {
timers_db = timers_; timer_aligment_timer = timer_aligment_timer_;
demux_unit = demux_unit_; demux_unit = demux_unit_;
si_window_start = 0; si_window_start = 0;
log_h = log_h_; log_h = log_h_;
@ -102,7 +101,7 @@ public:
} else { } else {
if (grant.is_sps_release) { if (grant.is_sps_release) {
dl_sps_assig.clear(); dl_sps_assig.clear();
if (timers_db->get(TIME_ALIGNMENT)->is_running()) { if (timer_aligment_timer->is_running()) {
//phy_h->send_sps_ack(); //phy_h->send_sps_ack();
Warning("PHY Send SPS ACK not implemented\n"); Warning("PHY Send SPS ACK not implemented\n");
} }
@ -168,12 +167,14 @@ private:
void new_grant_dl(Tgrant grant, Taction *action) { void new_grant_dl(Tgrant grant, Taction *action) {
/* Fill action structure */ /* Fill action structure */
bzero(action, sizeof(Taction)); bzero(action, sizeof(Taction));
action->default_ack = false;
action->generate_ack = true; action->generate_ack = true;
action->decode_enabled = false; action->rnti = grant.rnti;
/* For each subprocess... */ /* For each subprocess... */
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
action->default_ack[tb] = false;
action->decode_enabled[tb] = false;
action->phy_grant.dl.tb_en[tb] = grant.tb_en[tb];
if (grant.tb_en[tb]) { if (grant.tb_en[tb]) {
subproc[tb].new_grant_dl(grant, action); subproc[tb].new_grant_dl(grant, action);
} }
@ -210,6 +211,7 @@ private:
return false; return false;
} else { } else {
pid = pid_; pid = pid_;
is_first_tb = true;
is_initiated = true; is_initiated = true;
harq_entity = parent; harq_entity = parent;
log_h = harq_entity->log_h; log_h = harq_entity->log_h;
@ -218,6 +220,7 @@ private:
} }
void reset(void) { void reset(void) {
is_first_tb = true;
ack = false; ack = false;
payload_buffer_ptr = NULL; payload_buffer_ptr = NULL;
bzero(&cur_grant, sizeof(Tgrant)); bzero(&cur_grant, sizeof(Tgrant));
@ -239,7 +242,12 @@ private:
} }
} }
calc_is_new_transmission(grant); calc_is_new_transmission(grant);
if (is_new_transmission) { // If this is a new transmission or the size of the TB has changed
if (is_new_transmission || (cur_grant.n_bytes[tid] != grant.n_bytes[tid])) {
if (!is_new_transmission) {
Warning("DL PID %d: Size of grant changed during a retransmission %d!=%d\n", pid,
cur_grant.n_bytes[tid], grant.n_bytes[tid]);
}
ack = false; ack = false;
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes[tid] * 8); srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes[tid] * 8);
n_retx = 0; n_retx = 0;
@ -258,23 +266,22 @@ private:
cur_grant.n_bytes[tid]); cur_grant.n_bytes[tid]);
action->payload_ptr[tid] = payload_buffer_ptr; action->payload_ptr[tid] = payload_buffer_ptr;
if (!action->payload_ptr) { if (!action->payload_ptr) {
action->decode_enabled = false; action->decode_enabled[tid] = false;
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]); Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]);
return; return;
} }
action->decode_enabled = true; action->decode_enabled[tid]= true;
action->rv[tid] = cur_grant.rv[tid]; action->rv[tid] = cur_grant.rv[tid];
action->rnti = cur_grant.rnti;
action->softbuffers[tid] = &softbuffer; action->softbuffers[tid] = &softbuffer;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant)); memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant));
n_retx++; n_retx++;
} else { } else {
action->default_ack[tid] = true;
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid); Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
action->phy_grant.dl.tb_en[tid] = false;
} }
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) { if (pid == HARQ_BCCH_PID || harq_entity->timer_aligment_timer->is_expired()) {
// Do not generate ACK // Do not generate ACK
Debug("Not generating ACK\n"); Debug("Not generating ACK\n");
action->generate_ack = false; action->generate_ack = false;
@ -336,17 +343,14 @@ private:
int get_current_tbs(void) { return cur_grant.n_bytes[tid] * 8; } int get_current_tbs(void) { return cur_grant.n_bytes[tid] * 8; }
private: private:
// Determine if it's a new transmission 5.3.2.2
bool calc_is_new_transmission(Tgrant grant) { bool calc_is_new_transmission(Tgrant grant) {
bool is_new_tb = true;
if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes[tid] == cur_grant.n_bytes[tid])) ||
pid == HARQ_BCCH_PID) {
is_new_tb = false;
}
if ((grant.ndi[tid] != cur_grant.ndi[tid] && !is_new_tb) || // NDI toggled for same TB if ((grant.ndi[tid] != cur_grant.ndi[tid]) || // 1st condition (NDI has changed)
is_new_tb || // is new TB (pid == HARQ_BCCH_PID && grant.rv[tid] == 0) || // 2nd condition (Broadcast and 1st transmission)
(pid == HARQ_BCCH_PID && grant.rv[tid] == 0)) // Broadcast PID and 1st TX (RV=0) is_first_tb) // 3rd condition (first TB)
{ {
is_first_tb = false;
is_new_transmission = true; is_new_transmission = true;
Debug("Set HARQ for new transmission\n"); Debug("Set HARQ for new transmission\n");
} else { } else {
@ -361,6 +365,7 @@ private:
dl_harq_entity *harq_entity; dl_harq_entity *harq_entity;
srslte::log *log_h; srslte::log *log_h;
bool is_first_tb;
bool is_new_transmission; bool is_new_transmission;
uint32_t pid; /* HARQ Proccess ID */ uint32_t pid; /* HARQ Proccess ID */
@ -391,7 +396,7 @@ private:
std::vector<dl_harq_process> proc; std::vector<dl_harq_process> proc;
srslte::timers *timers_db; srslte::timers::timer *timer_aligment_timer;
demux *demux_unit; demux *demux_unit;
srslte::log *log_h; srslte::log *log_h;
srslte::mac_pcap *pcap; srslte::mac_pcap *pcap;

@ -48,9 +48,9 @@ namespace srsue {
class mac class mac
:public mac_interface_phy :public mac_interface_phy
,public mac_interface_rrc ,public mac_interface_rrc
,public srslte::timer_callback
,public srslte::mac_interface_timers ,public srslte::mac_interface_timers
,public thread ,public thread
,public srslte::timer_callback
{ {
public: public:
mac(); mac();
@ -91,15 +91,18 @@ public:
void get_rntis(ue_rnti_t *rntis); void get_rntis(ue_rnti_t *rntis);
void timer_expired(uint32_t timer_id);
void start_pcap(srslte::mac_pcap* pcap); void start_pcap(srslte::mac_pcap* pcap);
srslte::timers::timer* get(uint32_t timer_id); // Timer callback interface
u_int32_t get_unique_id(); void timer_expired(uint32_t timer_id);
uint32_t get_current_tti(); uint32_t get_current_tti();
static const int MAC_NOF_UPPER_TIMERS = 20; // Interface for upper-layer timers
srslte::timers::timer* timer_get(uint32_t timer_id);
void timer_release_id(uint32_t timer_id);
uint32_t timer_get_unique_id();
private: private:
void run_thread(); void run_thread();
@ -146,10 +149,14 @@ private:
srslte_softbuffer_rx_t pch_softbuffer; srslte_softbuffer_rx_t pch_softbuffer;
uint8_t pch_payload_buffer[pch_payload_buffer_sz]; uint8_t pch_payload_buffer[pch_payload_buffer_sz];
/* Functions for MAC Timers */ /* Functions for MAC Timers */
srslte::timers timers_db; uint32_t timer_alignment;
uint32_t contention_resolution_timer;
void setup_timers(); void setup_timers();
void timeAlignmentTimerExpire(); void timer_alignment_expire();
srslte::timers timers;
// pointer to MAC PCAP object // pointer to MAC PCAP object
srslte::mac_pcap* pcap; srslte::mac_pcap* pcap;
@ -158,22 +165,6 @@ private:
mac_metrics_t metrics; mac_metrics_t metrics;
/* Class to run upper-layer timers with normal priority */
class upper_timers : public periodic_thread {
public:
upper_timers();
void reset();
srslte::timers::timer* get(uint32_t timer_id);
uint32_t get_unique_id();
private:
void run_period();
srslte::timers timers_db;
};
upper_timers upper_timers_thread;
/* Class to process MAC PDUs from DEMUX unit */ /* Class to process MAC PDUs from DEMUX unit */
class pdu_process : public thread { class pdu_process : public thread {
public: public:

@ -1,45 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef MAC_COMMON_H
#define MAC_COMMON_H
namespace srsue {
typedef enum {
HARQ_RTT,
TIME_ALIGNMENT,
CONTENTION_TIMER,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
PHR_TIMER_PERIODIC,
PHR_TIMER_PROHIBIT,
NOF_MAC_TIMERS
} mac_timers_t;
} // namespace srsue
#endif // MAC_COMMON_H

@ -81,6 +81,9 @@ private:
bool generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes); bool generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes);
char* bsr_type_tostring(triggered_bsr_type_t type); char* bsr_type_tostring(triggered_bsr_type_t type);
char* bsr_format_tostring(bsr_format_t format); char* bsr_format_tostring(bsr_format_t format);
uint32_t timer_periodic_id;
uint32_t timer_retx_id;
}; };
} // namespace srsue } // namespace srsue

@ -50,6 +50,8 @@ public:
bool generate_phr_on_ul_grant(float *phr); bool generate_phr_on_ul_grant(float *phr);
void timer_expired(uint32_t timer_id); void timer_expired(uint32_t timer_id);
void start_timer();
private: private:
bool pathloss_changed(); bool pathloss_changed();
@ -59,11 +61,15 @@ private:
phy_interface_mac* phy_h; phy_interface_mac* phy_h;
srslte::timers* timers_db; srslte::timers* timers_db;
bool initiated; bool initiated;
int timer_prohibit; int timer_prohibit_value;
int timer_periodic; int timer_periodic_value;
int dl_pathloss_change; int dl_pathloss_change;
int last_pathloss_db; int last_pathloss_db;
bool phr_is_triggered; bool phr_is_triggered;
uint32_t timer_periodic_id;
uint32_t timer_prohibit_id;
}; };
} // namespace srsue } // namespace srsue

@ -59,7 +59,6 @@ class ra_proc : public srslte::timer_callback
phy_h = NULL; phy_h = NULL;
log_h = NULL; log_h = NULL;
mac_cfg = NULL; mac_cfg = NULL;
timers_db = NULL;
mux_unit = NULL; mux_unit = NULL;
demux_unit = NULL; demux_unit = NULL;
rrc = NULL; rrc = NULL;
@ -70,6 +69,9 @@ class ra_proc : public srslte::timer_callback
rar_grant_nbytes = 0; rar_grant_nbytes = 0;
rar_grant_tti = 0; rar_grant_tti = 0;
msg3_flushed = false; msg3_flushed = false;
time_alignment_timer = NULL;
contention_resolution_timer = NULL;
}; };
~ra_proc(); ~ra_proc();
@ -79,7 +81,8 @@ class ra_proc : public srslte::timer_callback
srslte::log *log_h, srslte::log *log_h,
mac_interface_rrc::ue_rnti_t *rntis, mac_interface_rrc::ue_rnti_t *rntis,
mac_interface_rrc::mac_cfg_t *mac_cfg, mac_interface_rrc::mac_cfg_t *mac_cfg,
srslte::timers *timers_db, srslte::timers::timer* time_alignment_timer_,
srslte::timers::timer* contention_resolution_timer_,
mux *mux_unit, mux *mux_unit,
demux *demux_unit); demux *demux_unit);
void reset(); void reset();
@ -149,7 +152,6 @@ private:
srslte_softbuffer_rx_t softbuffer_rar; srslte_softbuffer_rx_t softbuffer_rar;
enum { enum {
IDLE = 0, IDLE = 0,
INITIALIZATION, // Section 5.1.1 INITIALIZATION, // Section 5.1.1
@ -174,12 +176,14 @@ private:
phy_interface_mac *phy_h; phy_interface_mac *phy_h;
srslte::log *log_h; srslte::log *log_h;
srslte::timers *timers_db;
mux *mux_unit; mux *mux_unit;
demux *demux_unit; demux *demux_unit;
srslte::mac_pcap *pcap; srslte::mac_pcap *pcap;
rrc_interface_mac *rrc; rrc_interface_mac *rrc;
srslte::timers::timer *time_alignment_timer;
srslte::timers::timer *contention_resolution_timer;
mac_interface_rrc::ue_rnti_t *rntis; mac_interface_rrc::ue_rnti_t *rntis;
mac_interface_rrc::mac_cfg_t *mac_cfg; mac_interface_rrc::mac_cfg_t *mac_cfg;

@ -35,7 +35,6 @@
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "mac/mux.h" #include "mac/mux.h"
#include "mac/mac_common.h"
#include "mac/ul_sps.h" #include "mac/ul_sps.h"
#include "srslte/common/mac_pcap.h" #include "srslte/common/mac_pcap.h"
#include "srslte/common/timers.h" #include "srslte/common/timers.h"
@ -55,8 +54,9 @@ public:
ul_harq_entity() : proc(N) ul_harq_entity() : proc(N)
{ {
contention_timer = NULL;
pcap = NULL; pcap = NULL;
timers_db = NULL;
mux_unit = NULL; mux_unit = NULL;
log_h = NULL; log_h = NULL;
params = NULL; params = NULL;
@ -68,14 +68,14 @@ public:
bool init(srslte::log *log_h_, bool init(srslte::log *log_h_,
mac_interface_rrc_common::ue_rnti_t *rntis_, mac_interface_rrc_common::ue_rnti_t *rntis_,
mac_interface_rrc_common::ul_harq_params_t *params_, mac_interface_rrc_common::ul_harq_params_t *params_,
srslte::timers* timers_db_, srslte::timers::timer* contention_timer_,
mux *mux_unit_) mux *mux_unit_)
{ {
log_h = log_h_; log_h = log_h_;
mux_unit = mux_unit_; mux_unit = mux_unit_;
params = params_; params = params_;
rntis = rntis_; rntis = rntis_;
timers_db = timers_db_; contention_timer = contention_timer_;
for (uint32_t i=0;i<N;i++) { for (uint32_t i=0;i<N;i++) {
if (!proc[i].init(i, this)) { if (!proc[i].init(i, this)) {
return false; return false;
@ -350,7 +350,7 @@ private:
// On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5 // On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5
if (is_msg3) { if (is_msg3) {
harq_entity->timers_db->get(CONTENTION_TIMER)->reset(); harq_entity->contention_timer->reset();
} }
harq_entity->mux_unit->pusch_retx(tti_tx, pid); harq_entity->mux_unit->pusch_retx(tti_tx, pid);
@ -368,6 +368,7 @@ private:
current_tx_nb = 0; current_tx_nb = 0;
current_irv = 0; current_irv = 0;
is_msg3 = is_msg3_; is_msg3 = is_msg3_;
Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n", Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n",
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes[0], pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes[0],
is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti); is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti);
@ -415,7 +416,7 @@ private:
ul_sps ul_sps_assig; ul_sps ul_sps_assig;
srslte::timers *timers_db; srslte::timers::timer *contention_timer;
mux *mux_unit; mux *mux_unit;
std::vector<ul_harq_process> proc; std::vector<ul_harq_process> proc;
srslte::log *log_h; srslte::log *log_h;

@ -0,0 +1,64 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: metrics_csv.h
* Description: Metrics class writing to CSV file.
*****************************************************************************/
#ifndef METRICS_CSV_H
#define METRICS_CSV_H
#include <pthread.h>
#include <stdint.h>
#include <string>
#include <iostream>
#include <fstream>
#include "srslte/common/metrics_hub.h"
#include "ue_metrics_interface.h"
namespace srsue {
class metrics_csv : public srslte::metrics_listener<ue_metrics_t>
{
public:
metrics_csv(std::string filename);
void set_metrics(ue_metrics_t &m, float report_period_secs);
void set_ue_handle(ue_metrics_interface *ue_);
private:
std::string float_to_string(float f, int digits, bool add_semicolon = true);
std::ofstream file;
ue_metrics_interface* ue;
uint32_t n_reports;
};
} // namespace srsue
#endif // METRICS_CSV_H

@ -36,36 +36,28 @@
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include "srslte/common/metrics_hub.h"
#include "ue_metrics_interface.h" #include "ue_metrics_interface.h"
namespace srsue { namespace srsue {
class metrics_stdout class metrics_stdout : public srslte::metrics_listener<ue_metrics_t>
{ {
public: public:
metrics_stdout(); metrics_stdout();
bool init(ue_metrics_interface *u, float report_period_secs=1.0);
void stop();
void toggle_print(bool b); void toggle_print(bool b);
static void* metrics_thread_start(void *m); void set_metrics(ue_metrics_t &m, float report_period_secs);
void metrics_thread_run(); void set_ue_handle(ue_metrics_interface *ue_);
private: private:
void print_metrics();
void print_disconnect();
std::string float_to_string(float f, int digits); std::string float_to_string(float f, int digits);
std::string float_to_eng_string(float f, int digits); std::string float_to_eng_string(float f, int digits);
std::string int_to_eng_string(int f, int digits); std::string int_to_eng_string(int f, int digits);
ue_metrics_interface *ue_;
bool started;
bool do_print; bool do_print;
pthread_t metrics_thread;
ue_metrics_t metrics;
float metrics_report_period; // seconds
uint8_t n_reports; uint8_t n_reports;
ue_metrics_interface* ue;
}; };
} // namespace srsue } // namespace srsue

@ -27,6 +27,9 @@
#ifndef UEPHYWORKERCOMMON_H #ifndef UEPHYWORKERCOMMON_H
#define UEPHYWORKERCOMMON_H #define UEPHYWORKERCOMMON_H
#define TX_MODE_CONTINUOUS 1
#include <pthread.h> #include <pthread.h>
#include <string.h> #include <string.h>
#include <vector> #include <vector>
@ -36,8 +39,6 @@
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "phy/phy_metrics.h" #include "phy/phy_metrics.h"
//#define CONTINUOUS_TX
namespace srsue { namespace srsue {
@ -48,7 +49,7 @@ namespace srsue {
/* Common variables used by all phy workers */ /* Common variables used by all phy workers */
phy_interface_rrc::phy_cfg_t *config; phy_interface_rrc::phy_cfg_t *config;
phy_args_t *args; phy_args_t *args;
srslte::log *log_h; rrc_interface_phy *rrc;
mac_interface_phy *mac; mac_interface_phy *mac;
srslte_ue_ul_t ue_ul; srslte_ue_ul_t ue_ul;
@ -70,6 +71,7 @@ namespace srsue {
phy_args_t *args, phy_args_t *args,
srslte::log *_log, srslte::log *_log,
srslte::radio *_radio, srslte::radio *_radio,
rrc_interface_phy *rrc,
mac_interface_phy *_mac); mac_interface_phy *_mac);
/* For RNTI searches, -1 means now or forever */ /* For RNTI searches, -1 means now or forever */
@ -116,6 +118,7 @@ namespace srsue {
bool is_first_of_burst; bool is_first_of_burst;
srslte::radio *radio_h; srslte::radio *radio_h;
float cfo; float cfo;
srslte::log *log_h;
bool ul_rnti_active(uint32_t tti); bool ul_rnti_active(uint32_t tti);

@ -52,13 +52,12 @@ public:
void stop(); void stop();
void set_agc_enable(bool enable); void set_agc_enable(bool enable);
void resync_sfn();
void set_earfcn(std::vector<uint32_t> earfcn); void set_earfcn(std::vector<uint32_t> earfcn);
bool stop_sync(); void reset_sync();
void cell_search_start(); void cell_search_start();
void cell_search_next(); void cell_search_stop();
void cell_search_next(bool reset = false);
bool cell_select(uint32_t earfcn, srslte_cell_t cell); bool cell_select(uint32_t earfcn, srslte_cell_t cell);
uint32_t get_current_tti(); uint32_t get_current_tti();
@ -70,24 +69,40 @@ public:
const static int MUTEX_X_WORKER = 4; const static int MUTEX_X_WORKER = 4;
// public variables needed by callback function
uint32_t current_sflen;
srslte::radio_multi *radio_h;
int next_offset;
private: private:
std::vector<uint32_t> earfcn; std::vector<uint32_t> earfcn;
void reset();
void radio_error();
bool wait_radio_reset();
void set_ue_sync_opts(srslte_ue_sync_t *q); void set_ue_sync_opts(srslte_ue_sync_t *q);
void run_thread(); void run_thread();
void set_sampling_rate(); void set_sampling_rate();
bool set_frequency(); bool set_frequency();
void resync_sfn(bool is_connected = false);
bool stop_sync();
void cell_search_inc(); void cell_search_inc();
bool init_cell(); bool init_cell();
void free_cell(); void free_cell();
void stop_rx();
void start_rx();
bool radio_is_rx;
bool radio_is_resetting;
bool running; bool running;
srslte::radio_multi *radio_h;
mac_interface_phy *mac; mac_interface_phy *mac;
rrc_interface_phy *rrc; rrc_interface_phy *rrc;
srslte::log *log_h; srslte::log *log_h;
@ -114,6 +129,7 @@ private:
IDLE = 0, IDLE = 0,
CELL_SEARCH, CELL_SEARCH,
CELL_SELECT, CELL_SELECT,
CELL_RESELECT,
CELL_MEASURE, CELL_MEASURE,
CELL_CAMP CELL_CAMP
} phy_state; } phy_state;
@ -123,6 +139,7 @@ private:
enum { enum {
SRATE_NONE=0, SRATE_FIND, SRATE_CAMP SRATE_NONE=0, SRATE_FIND, SRATE_CAMP
} srate_mode; } srate_mode;
float current_srate;
srslte_cell_t cell; srslte_cell_t cell;
bool cell_is_set; bool cell_is_set;
@ -148,12 +165,11 @@ private:
float measure_rsrp; float measure_rsrp;
srslte_ue_dl_t ue_dl_measure; srslte_ue_dl_t ue_dl_measure;
const static int RSRP_MEASURE_NOF_FRAMES = 5; const static int RSRP_MEASURE_NOF_FRAMES = 5;
int cell_sync_sfn(); int cell_sync_sfn();
int cell_meas_rsrp(); int cell_meas_rsrp();
bool cell_search(int force_N_id_2 = -1); int cell_search(int force_N_id_2 = -1);
bool set_cell(); bool set_cell();
}; };

@ -45,14 +45,14 @@ public:
~phch_worker(); ~phch_worker();
void reset(); void reset();
void set_common(phch_common *phy); void set_common(phch_common *phy);
bool init(uint32_t max_prb); bool init(uint32_t max_prb, srslte::log *log);
bool set_cell(srslte_cell_t cell); bool set_cell(srslte_cell_t cell);
/* Functions used by main PHY thread */ /* Functions used by main PHY thread */
cf_t* get_buffer(uint32_t antenna_idx); cf_t* get_buffer(uint32_t antenna_idx);
void set_tti(uint32_t tti, uint32_t tx_tti); void set_tti(uint32_t tti, uint32_t tx_tti);
void set_tx_time(srslte_timestamp_t tx_time); void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset);
void set_cfo(float cfo); void set_cfo(float cfo);
void set_sample_offset(float sample_offset); void set_sample_offset(float sample_offset);
@ -113,6 +113,7 @@ private:
/* Common objects */ /* Common objects */
phch_common *phy; phch_common *phy;
srslte::log *log_h;
srslte_cell_t cell; srslte_cell_t cell;
bool mem_initiated; bool mem_initiated;
bool cell_initiated; bool cell_initiated;
@ -123,6 +124,8 @@ private:
uint32_t last_dl_pdcch_ncce; uint32_t last_dl_pdcch_ncce;
bool rnti_is_set; bool rnti_is_set;
uint32_t next_offset;
/* Objects for DL */ /* Objects for DL */
srslte_ue_dl_t ue_dl; srslte_ue_dl_t ue_dl;
uint32_t cfi; uint32_t cfi;

@ -53,7 +53,7 @@ public:
bool init(srslte::radio_multi *radio_handler, bool init(srslte::radio_multi *radio_handler,
mac_interface_phy *mac, mac_interface_phy *mac,
rrc_interface_phy *rrc, rrc_interface_phy *rrc,
srslte::log *log_h, std::vector<void*> log_vec,
phy_args_t *args = NULL); phy_args_t *args = NULL);
void stop(); void stop();
@ -79,16 +79,16 @@ public:
/********** RRC INTERFACE ********************/ /********** RRC INTERFACE ********************/
void reset(); void reset();
void sync_reset();
void configure_ul_params(bool pregen_disabled = false); void configure_ul_params(bool pregen_disabled = false);
void resync_sfn();
void cell_search_start(); void cell_search_start();
void cell_search_stop();
void cell_search_next(); void cell_search_next();
bool cell_select(uint32_t earfcn, srslte_cell_t phy_cell); bool cell_select(uint32_t earfcn, srslte_cell_t phy_cell);
/********** MAC INTERFACE ********************/ /********** MAC INTERFACE ********************/
/* Functions to synchronize with a cell */ /* Functions to synchronize with a cell */
bool sync_status(); // this is also RRC interface bool sync_status(); // this is also RRC interface
bool sync_stop();
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
void set_crnti(uint16_t rnti); void set_crnti(uint16_t rnti);
@ -148,6 +148,7 @@ private:
const static int WORKERS_THREAD_PRIO = 0; const static int WORKERS_THREAD_PRIO = 0;
srslte::radio_multi *radio_handler; srslte::radio_multi *radio_handler;
std::vector<void*> log_vec;
srslte::log *log_h; srslte::log *log_h;
srsue::mac_interface_phy *mac; srsue::mac_interface_phy *mac;
srsue::rrc_interface_phy *rrc; srsue::rrc_interface_phy *rrc;

@ -45,7 +45,7 @@
#include "srslte/upper/pdcp.h" #include "srslte/upper/pdcp.h"
#include "upper/rrc.h" #include "upper/rrc.h"
#include "upper/nas.h" #include "upper/nas.h"
#include "srslte/upper/gw.h" #include "upper/gw.h"
#include "upper/usim.h" #include "upper/usim.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
@ -57,8 +57,6 @@
namespace srsue { namespace srsue {
//#define LOG_STDOUT
/******************************************************************************* /*******************************************************************************
Main UE class Main UE class
*******************************************************************************/ *******************************************************************************/
@ -82,9 +80,6 @@ public:
void pregenerate_signals(bool enable); void pregenerate_signals(bool enable);
// Testing
void test_con_restablishment();
private: private:
virtual ~ue(); virtual ~ue();
@ -97,16 +92,15 @@ private:
srslte::pdcp pdcp; srslte::pdcp pdcp;
srsue::rrc rrc; srsue::rrc rrc;
srsue::nas nas; srsue::nas nas;
srslte::gw gw; srsue::gw gw;
srsue::usim usim; srsue::usim usim;
#ifdef LOG_STDOUT srslte::logger_stdout logger_stdout;
srslte::logger_stdout logger; srslte::logger_file logger_file;
#else srslte::logger *logger;
srslte::logger_file logger;
#endif // rf_log is on ue_base
srslte::log_filter rf_log; std::vector<void*> phy_log;
srslte::log_filter phy_log;
srslte::log_filter mac_log; srslte::log_filter mac_log;
srslte::log_filter rlc_log; srslte::log_filter rlc_log;
srslte::log_filter pdcp_log; srslte::log_filter pdcp_log;
@ -119,7 +113,6 @@ private:
all_args_t *args; all_args_t *args;
bool started; bool started;
rf_metrics_t rf_metrics;
bool check_srslte_version(); bool check_srslte_version();
}; };

@ -107,6 +107,8 @@ typedef struct {
float metrics_period_secs; float metrics_period_secs;
bool pregenerate_signals; bool pregenerate_signals;
std::string ue_cateogry; std::string ue_cateogry;
bool metrics_csv_enable;
std::string metrics_csv_filename;
}expert_args_t; }expert_args_t;
typedef struct { typedef struct {

@ -29,7 +29,8 @@
#include <stdint.h> #include <stdint.h>
#include "srslte/upper/gw_metrics.h" #include "srslte/common/metrics_hub.h"
#include "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"
@ -48,14 +49,15 @@ typedef struct {
phy_metrics_t phy; phy_metrics_t phy;
mac_metrics_t mac; mac_metrics_t mac;
srslte::rlc_metrics_t rlc; srslte::rlc_metrics_t rlc;
srslte::gw_metrics_t gw; gw_metrics_t gw;
}ue_metrics_t; }ue_metrics_t;
// UE interface // UE interface
class ue_metrics_interface class ue_metrics_interface : public srslte::metrics_interface<ue_metrics_t>
{ {
public: public:
virtual bool get_metrics(ue_metrics_t &m) = 0; virtual bool get_metrics(ue_metrics_t &m) = 0;
virtual bool is_attached() = 0;
}; };
} // namespace srsue } // namespace srsue

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

Loading…
Cancel
Save