Merge branch 'next' of github.com:softwareradiosystems/srsLTE into next

master
Ismael Gomez 7 years ago
commit 38019dd77c

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

@ -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;
int 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 %s]\n", args->mbsfn_area_id);
printf("\t-N Non-MBSFN region [Default %s]\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);
} }

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

@ -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_ */

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

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

@ -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]) {

@ -0,0 +1,486 @@
/**
*
* \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;
}
float srslte_pmch_average_noi(srslte_pmch_t *q)
{
return q->dl_sch.average_nof_iterations;
}
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,10 +32,10 @@
#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/pusch.h"
#include "srslte/phy/phch/sch.h" #include "srslte/phy/phch/sch.h"
#include "srslte/phy/phch/pmch.h"
#include "srslte/phy/phch/uci.h" #include "srslte/phy/phch/uci.h"
#include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/phy_common.h"
#include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/bit.h"

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

@ -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]) {
@ -151,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]);
@ -258,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++){
@ -282,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],
@ -300,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,
@ -358,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,
@ -372,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;
} }
@ -476,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++;
} }
} }
@ -510,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) {

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

Loading…
Cancel
Save