mirror of https://github.com/PentHertz/srsLTE.git
Merge branch 'next' of github.com:softwareradiosystems/srsLTE into next
This commit is contained in:
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
|
||||||
|
@ -55,41 +58,51 @@ char *output_file_name = NULL;
|
||||||
#define DOWN_KEY 66
|
#define DOWN_KEY 66
|
||||||
|
|
||||||
srslte_cell_t cell = {
|
srslte_cell_t cell = {
|
||||||
25, // nof_prb
|
25, // nof_prb
|
||||||
1, // nof_ports
|
1, // nof_ports
|
||||||
0, // cell_id
|
0, // cell_id
|
||||||
SRSLTE_CP_NORM, // cyclic prefix
|
SRSLTE_CP_NORM, // cyclic prefix
|
||||||
SRSLTE_PHICH_NORM, // PHICH length
|
SRSLTE_PHICH_NORM, // PHICH length
|
||||||
SRSLTE_PHICH_R_1 // PHICH resources
|
SRSLTE_PHICH_R_1 // PHICH resources
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint16_t c = -1;
|
||||||
|
|
||||||
int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device
|
int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device
|
||||||
|
|
||||||
uint32_t cfi = 1;
|
uint32_t cfi = 2;
|
||||||
uint32_t mcs_idx = 1, last_mcs_idx = 1;
|
uint32_t mcs_idx = 1, last_mcs_idx = 1;
|
||||||
int nof_frames = -1;
|
int nof_frames = -1;
|
||||||
|
|
||||||
|
|
||||||
char mimo_type_str[32] = "single";
|
char mimo_type_str[32] = "single";
|
||||||
uint32_t nof_tb = 1;
|
uint32_t nof_tb = 1;
|
||||||
uint32_t multiplex_pmi = 0;
|
uint32_t multiplex_pmi = 0;
|
||||||
uint32_t multiplex_nof_layers = 1;
|
uint32_t multiplex_nof_layers = 1;
|
||||||
|
|
||||||
|
int mbsfn_area_id = -1;
|
||||||
char *rf_args = "";
|
char *rf_args = "";
|
||||||
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
|
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
|
||||||
|
|
||||||
bool null_file_sink=false;
|
bool null_file_sink=false;
|
||||||
srslte_filesink_t fsink;
|
srslte_filesink_t fsink;
|
||||||
srslte_ofdm_t ifft;
|
srslte_ofdm_t ifft;
|
||||||
|
srslte_ofdm_t ifft_mbsfn;
|
||||||
srslte_pbch_t pbch;
|
srslte_pbch_t pbch;
|
||||||
srslte_pcfich_t pcfich;
|
srslte_pcfich_t pcfich;
|
||||||
srslte_pdcch_t pdcch;
|
srslte_pdcch_t pdcch;
|
||||||
srslte_pdsch_t pdsch;
|
srslte_pdsch_t pdsch;
|
||||||
srslte_pdsch_cfg_t pdsch_cfg;
|
srslte_pdsch_cfg_t pdsch_cfg;
|
||||||
|
srslte_pmch_t pmch;
|
||||||
|
srslte_pdsch_cfg_t pmch_cfg;
|
||||||
srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
|
srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
|
||||||
srslte_regs_t regs;
|
srslte_regs_t regs;
|
||||||
srslte_ra_dl_dci_t ra_dl;
|
srslte_ra_dl_dci_t ra_dl;
|
||||||
int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0};
|
int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0};
|
||||||
|
|
||||||
cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL};
|
cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL};
|
||||||
|
|
||||||
|
|
||||||
int sf_n_re, sf_n_samples;
|
int sf_n_re, sf_n_samples;
|
||||||
|
|
||||||
pthread_t net_thread;
|
pthread_t net_thread;
|
||||||
|
@ -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(®s, cell)) {
|
if (srslte_regs_init(®s, 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(®s);
|
srslte_regs_free(®s);
|
||||||
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) {
|
||||||
fprintf(stderr, "Error initializing equalizer\n");
|
if(srslte_refsignal_mbsfn_init(&mbsfn_refs, cell, mbsfn_area_id)) {
|
||||||
|
fprintf(stderr, "Error initializing equalizer\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(srslte_refsignal_cs_set_cell(&csr_refs, cell)){
|
||||||
|
fprintf(stderr, "Error setting cell\n");
|
||||||
exit(-1);
|
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,16 +797,16 @@ int main(int argc, char **argv) {
|
||||||
/* Initiate valid DCI locations */
|
/* Initiate valid DCI locations */
|
||||||
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
|
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
|
||||||
srslte_pdcch_ue_locations(&pdcch, locations[i], 30, i, cfi, UE_CRNTI);
|
srslte_pdcch_ue_locations(&pdcch, locations[i], 30, i, cfi, UE_CRNTI);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nf = 0;
|
nf = 0;
|
||||||
|
|
||||||
bool send_data = false;
|
bool send_data = false;
|
||||||
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||||
srslte_softbuffer_tx_reset(softbuffers[i]);
|
srslte_softbuffer_tx_reset(softbuffers[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef DISABLE_RF
|
#ifndef DISABLE_RF
|
||||||
bool start_of_burst = true;
|
bool start_of_burst = true;
|
||||||
#endif
|
#endif
|
||||||
|
@ -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){
|
||||||
for (i = 0; i < cell.nof_ports; i++) {
|
srslte_refsignal_mbsfn_put_sf(cell, 0,csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]);
|
||||||
srslte_refsignal_cs_put_sf(cell, (uint32_t) i, est.csr_signal.pilots[i / 2][sf_idx], sf_symbols[i]);
|
} else {
|
||||||
|
for (i = 0; i < cell.nof_ports; i++) {
|
||||||
|
srslte_refsignal_cs_put_sf(cell, (uint32_t) i, csr_refs.pilots[i / 2][sf_idx], sf_symbols[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
srslte_pbch_mib_pack(&cell, sfn, bch_payload);
|
srslte_pbch_mib_pack(&cell, sfn, bch_payload);
|
||||||
|
@ -809,83 +872,131 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (send_data) {
|
if (send_data) {
|
||||||
srslte_dci_format_t dci_format;
|
if(sf_idx != 1 || mbsfn_area_id < 0) { // PDCCH + PDSCH
|
||||||
switch(pdsch_cfg.mimo_type) {
|
srslte_dci_format_t dci_format;
|
||||||
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
|
switch(pdsch_cfg.mimo_type) {
|
||||||
dci_format = SRSLTE_DCI_FORMAT1;
|
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
|
||||||
break;
|
dci_format = SRSLTE_DCI_FORMAT1;
|
||||||
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
break;
|
||||||
case SRSLTE_MIMO_TYPE_CDD:
|
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
|
||||||
dci_format = SRSLTE_DCI_FORMAT2A;
|
case SRSLTE_MIMO_TYPE_CDD:
|
||||||
break;
|
dci_format = SRSLTE_DCI_FORMAT2A;
|
||||||
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
break;
|
||||||
dci_format = SRSLTE_DCI_FORMAT2;
|
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
|
||||||
if (multiplex_nof_layers == 1) {
|
dci_format = SRSLTE_DCI_FORMAT2;
|
||||||
ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1);
|
if (multiplex_nof_layers == 1) {
|
||||||
} else {
|
ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1);
|
||||||
ra_dl.pinfo = (uint8_t) multiplex_pmi;
|
} else {
|
||||||
}
|
ra_dl.pinfo = (uint8_t) multiplex_pmi;
|
||||||
break;
|
}
|
||||||
default:
|
break;
|
||||||
fprintf(stderr, "Wrong MIMO configuration\n");
|
default:
|
||||||
exit(SRSLTE_ERROR);
|
fprintf(stderr, "Wrong MIMO configuration\n");
|
||||||
}
|
exit(SRSLTE_ERROR);
|
||||||
/* Encode PDCCH */
|
}
|
||||||
INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
|
/* Encode PDCCH */
|
||||||
srslte_dci_msg_pack_pdsch(&ra_dl, dci_format, &dci_msg, cell.nof_prb, cell.nof_ports, false);
|
INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
|
||||||
if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], UE_CRNTI, sf_symbols, sf_idx, cfi)) {
|
srslte_dci_msg_pack_pdsch(&ra_dl, dci_format, &dci_msg, cell.nof_prb, cell.nof_ports, false);
|
||||||
fprintf(stderr, "Error encoding DCI message\n");
|
if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], UE_CRNTI, sf_symbols, sf_idx, cfi)) {
|
||||||
exit(-1);
|
fprintf(stderr, "Error encoding DCI message\n");
|
||||||
}
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Configure pdsch_cfg parameters */
|
/* Configure pdsch_cfg parameters */
|
||||||
srslte_ra_dl_grant_t grant;
|
srslte_ra_dl_grant_t grant;
|
||||||
srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant);
|
srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant);
|
||||||
if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) {
|
if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) {
|
||||||
fprintf(stderr, "Error configuring PDSCH\n");
|
fprintf(stderr, "Error configuring PDSCH\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encode PDSCH */
|
/* Encode PDSCH */
|
||||||
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, sf_symbols)) {
|
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, sf_symbols)) {
|
||||||
fprintf(stderr, "Error encoding PDSCH\n");
|
fprintf(stderr, "Error encoding PDSCH\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
sem_post(&net_sem);
|
||||||
}
|
}
|
||||||
net_packet_ready = false;
|
|
||||||
sem_post(&net_sem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transform to OFDM symbols */
|
/* Transform to OFDM symbols */
|
||||||
for (i = 0; i < cell.nof_ports; i++) {
|
if(sf_idx != 1 || mbsfn_area_id < 0){
|
||||||
srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]);
|
for (i = 0; i < cell.nof_ports; i++) {
|
||||||
|
srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
srslte_ofdm_tx_sf(&ifft_mbsfn, sf_buffer[0], output_buffer[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send to file or usrp */
|
/* send to file or usrp */
|
||||||
if (output_file_name) {
|
if (output_file_name) {
|
||||||
if (!null_file_sink) {
|
if (!null_file_sink) {
|
||||||
srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports);
|
srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports);
|
||||||
}
|
}
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
} else {
|
} else {
|
||||||
#ifndef DISABLE_RF
|
#ifndef DISABLE_RF
|
||||||
float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb);
|
float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb);
|
||||||
for (i = 0; i < cell.nof_ports; i++) {
|
for (i = 0; i < cell.nof_ports; i++) {
|
||||||
srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||||
}
|
}
|
||||||
srslte_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false);
|
srslte_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false);
|
||||||
start_of_burst=false;
|
start_of_burst=false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,8 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <srslte/srslte.h>
|
#include <srslte/phy/common/phy_common.h>
|
||||||
#include <srslte/phy/phch/pdsch_cfg.h>
|
#include "srslte/phy/io/filesink.h"
|
||||||
#include <srslte/phy/phch/ra.h>
|
|
||||||
|
|
||||||
#include "srslte/srslte.h"
|
#include "srslte/srslte.h"
|
||||||
|
|
||||||
#define ENABLE_AGC_DEFAULT
|
#define ENABLE_AGC_DEFAULT
|
||||||
|
@ -69,7 +67,7 @@ sem_t plot_sem;
|
||||||
uint32_t plot_sf_idx=0;
|
uint32_t plot_sf_idx=0;
|
||||||
bool plot_track = true;
|
bool plot_track = true;
|
||||||
#endif
|
#endif
|
||||||
|
char *output_file_name;
|
||||||
#define PRINT_CHANGE_SCHEDULIGN
|
#define PRINT_CHANGE_SCHEDULIGN
|
||||||
|
|
||||||
//#define CORRECT_SAMPLE_OFFSET
|
//#define CORRECT_SAMPLE_OFFSET
|
||||||
|
@ -101,6 +99,8 @@ typedef struct {
|
||||||
int net_port_signal;
|
int net_port_signal;
|
||||||
char *net_address_signal;
|
char *net_address_signal;
|
||||||
int decimate;
|
int decimate;
|
||||||
|
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,51 +650,64 @@ int main(int argc, char **argv) {
|
||||||
decode_pdsch = true;
|
decode_pdsch = true;
|
||||||
} else {
|
} else {
|
||||||
/* We are looking for SIB1 Blocks, search only in appropiate places */
|
/* We are looking for SIB1 Blocks, search only in appropiate places */
|
||||||
if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
|
if ((sfidx == 5 && (sfn%2)==0) || sfidx == 1) {
|
||||||
decode_pdsch = true;
|
decode_pdsch = true;
|
||||||
} else {
|
} else {
|
||||||
decode_pdsch = false;
|
decode_pdsch = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INFO("Attempting DL decode SFN=%d\n", sfn);
|
|
||||||
if (decode_pdsch) {
|
if (decode_pdsch) {
|
||||||
if (cell.nof_ports == 1) {
|
if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe
|
||||||
/* Transmission mode 1 */
|
if (cell.nof_ports == 1) {
|
||||||
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
|
/* Transmission mode 1 */
|
||||||
} else {
|
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
|
||||||
if (prog_args.rf_nof_rx_ant == 1) {
|
|
||||||
/* Transmission mode 2 */
|
|
||||||
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
|
|
||||||
acks);
|
|
||||||
} else {
|
} else {
|
||||||
/* Transmission mode 3 */
|
if (prog_args.rf_nof_rx_ant == 1) {
|
||||||
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
|
/* Transmission mode 2 */
|
||||||
acks);
|
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
|
||||||
if (n < 1) {
|
|
||||||
/* Transmission mode 4 */
|
|
||||||
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
|
|
||||||
acks);
|
acks);
|
||||||
|
} else {
|
||||||
|
/* Transmission mode 3 */
|
||||||
|
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
|
||||||
|
acks);
|
||||||
|
if (n < 1) {
|
||||||
|
/* Transmission mode 4 */
|
||||||
|
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
|
||||||
|
acks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}else{ // MBSFN subframe
|
||||||
|
n = srslte_ue_dl_decode_mbsfn(&ue_dl,
|
||||||
|
sf_buffer,
|
||||||
|
data[0],
|
||||||
|
sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
|
||||||
|
if(n>0){
|
||||||
|
if(output_file_name){
|
||||||
|
//srslte_filesink_init(&sink, output_file_name, SRSLTE_BYTE_BIN);
|
||||||
|
// srslte_filesink_write(&sink, data, n);
|
||||||
|
//srslte_filesink_free(&sink);
|
||||||
|
}
|
||||||
|
INFO("mbsfn PDU size is %d\n", n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (n < 0) {
|
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]) {
|
||||||
srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8);
|
srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PRINT_CHANGE_SCHEDULIGN
|
#ifdef PRINT_CHANGE_SCHEDULIGN
|
||||||
if (ue_dl.dl_dci.mcs_idx != old_dl_dci.mcs_idx ||
|
if (ue_dl.dl_dci.mcs_idx != old_dl_dci.mcs_idx ||
|
||||||
memcmp(&ue_dl.dl_dci.type0_alloc, &old_dl_dci.type0_alloc, sizeof(srslte_ra_type0_t)) ||
|
memcmp(&ue_dl.dl_dci.type0_alloc, &old_dl_dci.type0_alloc, sizeof(srslte_ra_type0_t)) ||
|
||||||
|
@ -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,14 +136,26 @@ 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],
|
||||||
|
uint32_t sf_idx,
|
||||||
|
uint32_t *cfi);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q,
|
||||||
cf_t *input[SRSLTE_MAX_PORTS],
|
cf_t *input[SRSLTE_MAX_PORTS],
|
||||||
uint32_t sf_idx,
|
uint32_t sf_idx,
|
||||||
uint32_t *cfi);
|
uint32_t *cfi,
|
||||||
|
srslte_sf_t sf_type);
|
||||||
|
|
||||||
SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q,
|
|
||||||
|
int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q,
|
||||||
|
uint32_t sf_idx,
|
||||||
|
uint32_t *cfi);
|
||||||
|
|
||||||
|
SRSLTE_API int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q,
|
||||||
uint32_t sf_idx,
|
uint32_t sf_idx,
|
||||||
uint32_t *cfi);
|
uint32_t *cfi,
|
||||||
|
srslte_sf_t sf_type);
|
||||||
|
|
||||||
SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q,
|
SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q,
|
||||||
srslte_ra_dl_grant_t *grant,
|
srslte_ra_dl_grant_t *grant,
|
||||||
|
@ -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,46 +298,70 @@ static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) {
|
||||||
|
|
||||||
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)]
|
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)]
|
||||||
|
|
||||||
static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id)
|
static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id, srslte_sf_t ch_mode)
|
||||||
{
|
{
|
||||||
/* interpolate the symbols with references in the freq domain */
|
/* interpolate the symbols with references in the freq domain */
|
||||||
uint32_t l;
|
uint32_t l;
|
||||||
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id);
|
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN ) ? srslte_refsignal_mbsfn_nof_symbols() + 1 : srslte_refsignal_cs_nof_symbols(port_id);
|
||||||
|
uint32_t fidx_offset = 0;
|
||||||
/* Interpolate in the frequency domain */
|
/* Interpolate in the frequency domain */
|
||||||
for (l=0;l<nsymbols;l++) {
|
|
||||||
uint32_t fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
|
// we add one to nsymbols to allow for inclusion of the non-mbms references in the channel estimation
|
||||||
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l],
|
for (l=0;l<(nsymbols);l++) {
|
||||||
&ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE],
|
if (ch_mode == SRSLTE_SF_MBSFN) {
|
||||||
fidx_offset, SRSLTE_NRE/2-fidx_offset);
|
if (l == 0) {
|
||||||
|
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
|
||||||
|
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l],
|
||||||
|
&ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE],
|
||||||
|
fidx_offset, SRSLTE_NRE/2-fidx_offset);
|
||||||
|
} else {
|
||||||
|
fidx_offset = srslte_refsignal_mbsfn_fidx(l - 1);
|
||||||
|
srslte_interp_linear_offset(&q->srslte_interp_lin_mbsfn, &pilot_estimates[(2*q->cell.nof_prb) + 6*q->cell.nof_prb*(l - 1)],
|
||||||
|
&ce[srslte_refsignal_mbsfn_nsymbol(l - 1) * q->cell.nof_prb * SRSLTE_NRE],
|
||||||
|
fidx_offset, SRSLTE_NRE/6-fidx_offset);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
|
||||||
|
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l],
|
||||||
|
&ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE],
|
||||||
|
fidx_offset, SRSLTE_NRE/2-fidx_offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now interpolate in the time domain between symbols */
|
/* Now interpolate in the time domain between symbols */
|
||||||
if (SRSLTE_CP_ISNORM(q->cell.cp)) {
|
if (ch_mode == SRSLTE_SF_MBSFN) {
|
||||||
if (nsymbols == 4) {
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1);
|
||||||
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3);
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3);
|
||||||
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2);
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3);
|
||||||
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3);
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1);
|
||||||
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2);
|
} else {
|
||||||
|
if (SRSLTE_CP_ISNORM(q->cell.cp)) {
|
||||||
|
if (nsymbols == 4) {
|
||||||
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3);
|
||||||
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2);
|
||||||
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3);
|
||||||
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2);
|
||||||
|
} else {
|
||||||
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1);
|
||||||
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6);
|
||||||
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1);
|
if (nsymbols == 4) {
|
||||||
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6);
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2);
|
||||||
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5);
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2);
|
||||||
}
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2);
|
||||||
} else {
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2);
|
||||||
if (nsymbols == 4) {
|
} else {
|
||||||
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2);
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1);
|
||||||
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2);
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5);
|
||||||
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2);
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4);
|
||||||
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2);
|
}
|
||||||
} else {
|
|
||||||
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1);
|
|
||||||
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5);
|
|
||||||
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) {
|
void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) {
|
||||||
if (filter_len < SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN) {
|
if (filter_len < SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN) {
|
||||||
if (filter) {
|
if (filter) {
|
||||||
|
@ -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){
|
||||||
{
|
if (ce != NULL) {
|
||||||
/* Get references from the input signal */
|
|
||||||
srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal);
|
|
||||||
|
|
||||||
/* Use the known CSR signal to compute Least-squares estimates */
|
|
||||||
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_signal.pilots[port_id/2][sf_idx],
|
|
||||||
q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
|
||||||
|
|
||||||
if (ce != NULL) {
|
|
||||||
|
|
||||||
/* Smooth estimates (if applicable) and interpolate */
|
/* Smooth estimates (if applicable) and interpolate */
|
||||||
if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) {
|
if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) {
|
||||||
interpolate_pilots(q, q->pilot_estimates, ce, port_id);
|
interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode);
|
||||||
} else {
|
} else {
|
||||||
average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id);
|
average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id, ch_mode);
|
||||||
interpolate_pilots(q, q->pilot_estimates_average, ce, port_id);
|
interpolate_pilots(q, q->pilot_estimates_average, ce, port_id, ch_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Estimate noise power */
|
/* Estimate noise power */
|
||||||
|
@ -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,9 +440,41 @@ 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, uint16_t mbsfn_area_id)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Use the known CSR signal to compute Least-squares estimates */
|
||||||
|
srslte_refsignal_mbsfn_get_sf(q->cell, port_id, input, q->pilot_recv_signal);
|
||||||
|
// estimate for non-mbsfn section of subframe
|
||||||
|
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx],
|
||||||
|
q->pilot_estimates, (2*q->cell.nof_prb));
|
||||||
|
|
||||||
|
srslte_vec_prod_conj_ccc(q->pilot_recv_signal+(2*q->cell.nof_prb), q->mbsfn_refs[mbsfn_area_id]->pilots[port_id/2][sf_idx],
|
||||||
|
q->pilot_estimates+(2*q->cell.nof_prb), SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id)-(2*q->cell.nof_prb));
|
||||||
|
|
||||||
|
chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_MBSFN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas)
|
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)
|
||||||
{
|
{
|
||||||
|
@ -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,8 +319,14 @@ void srslte_ofdm_rx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) {
|
||||||
if (q->freq_shift) {
|
if (q->freq_shift) {
|
||||||
srslte_vec_prod_ccc(input, q->shift_buffer, input, 2*q->slot_sz);
|
srslte_vec_prod_ccc(input, q->shift_buffer, input, 2*q->slot_sz);
|
||||||
}
|
}
|
||||||
for (n=0;n<2;n++) {
|
if(!q->mbsfn_subframe){
|
||||||
srslte_ofdm_rx_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]);
|
for (n=0;n<2;n++) {
|
||||||
|
srslte_ofdm_rx_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
srslte_ofdm_rx_slot_mbsfn(q, &input[0*q->slot_sz], &output[0*q->nof_re*q->nof_symbols]);
|
||||||
|
srslte_ofdm_rx_slot(q, &input[1*q->slot_sz], &output[1*q->nof_re*q->nof_symbols]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
for (n=0;n<2;n++) {
|
if(!q->mbsfn_subframe){
|
||||||
srslte_ofdm_tx_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]);
|
for (n=0;n<2;n++) {
|
||||||
|
srslte_ofdm_tx_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
srslte_ofdm_tx_slot_mbsfn(q, &input[0*q->nof_re*q->nof_symbols], &output[0*q->slot_sz]);
|
||||||
|
srslte_ofdm_tx_slot(q, &input[1*q->nof_re*q->nof_symbols], &output[1*q->slot_sz]);
|
||||||
}
|
}
|
||||||
if (q->freq_shift) {
|
if (q->freq_shift) {
|
||||||
srslte_vec_prod_ccc(output, q->shift_buffer, output, 2*q->slot_sz);
|
srslte_vec_prod_ccc(output, q->shift_buffer, output, 2*q->slot_sz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,22 +89,27 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove references
|
// remove references
|
||||||
if (!skip_refs) {
|
if (skip_refs) {
|
||||||
switch (nof_ports) {
|
if(sf_type == SRSLTE_SF_NORM){
|
||||||
case 1:
|
switch (nof_ports) {
|
||||||
case 2:
|
case 1:
|
||||||
re -= 2 * (slot + 1) * nof_ports;
|
case 2:
|
||||||
break;
|
re -= 2 * (slot + 1) * nof_ports;
|
||||||
case 4:
|
break;
|
||||||
if (slot == 1) {
|
case 4:
|
||||||
re -= 12;
|
if (slot == 1) {
|
||||||
} else {
|
re -= 12;
|
||||||
re -= 4;
|
} else {
|
||||||
if (nof_ctrl_symbols == 1) {
|
|
||||||
re -= 4;
|
re -= 4;
|
||||||
|
if (nof_ctrl_symbols == 1) {
|
||||||
|
re -= 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
if(sf_type == SRSLTE_SF_MBSFN){
|
||||||
|
re -= 6*(slot + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return re;
|
return re;
|
||||||
|
@ -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;
|
||||||
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart;
|
if (SRSLTE_SF_NORM == grant->sf_type) {
|
||||||
|
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart;
|
||||||
|
} else if (SRSLTE_SF_MBSFN == grant->sf_type) {
|
||||||
|
nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart;
|
||||||
|
}
|
||||||
nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i];
|
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++){
|
||||||
|
@ -279,20 +323,31 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) {
|
||||||
*/
|
*/
|
||||||
int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS],
|
int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS],
|
||||||
uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) {
|
uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) {
|
||||||
return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks);
|
return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks);
|
||||||
}
|
}
|
||||||
|
|
||||||
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi)
|
|
||||||
|
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi){
|
||||||
|
|
||||||
|
return srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, cfi, SRSLTE_SF_NORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type)
|
||||||
{
|
{
|
||||||
if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
|
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++) {
|
||||||
srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]);
|
if(sf_type == SRSLTE_SF_MBSFN ) {
|
||||||
|
srslte_ofdm_rx_sf(&q->fft_mbsfn, input[j], q->sf_symbols_m[j]);
|
||||||
|
}else{
|
||||||
|
srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Correct SFO multiplying by complex exponential in the time domain */
|
/* 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 */
|
||||||
srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas);
|
if(sf_type == SRSLTE_SF_MBSFN){
|
||||||
|
srslte_chest_dl_estimate_multi_mbsfn(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas, q->current_mbsfn_area_id);
|
||||||
|
}else{
|
||||||
|
srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* First decode PCFICH and obtain CFI */
|
/* 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,7 +423,11 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi);
|
if(SRSLTE_SF_MBSFN == grant->sf_type) {
|
||||||
|
return srslte_pmch_cfg(&q->pmch_cfg, q->cell, grant, cfi, sf_idx);
|
||||||
|
} else {
|
||||||
|
return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
|
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
|
||||||
|
@ -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…
Reference in New Issue