mirror of https://github.com/pvnis/srsRAN_4G.git
Merge pull request #37 from ismagom/master
Changed data types and introduced lte_cell_t structure. Fixed some bugs with PDSCH.master
commit
0f53f877ed
@ -0,0 +1,167 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#include "liblte/phy/io/filesource.h"
|
||||
#include "liblte/phy/phch/ue_sync.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
#endif
|
||||
|
||||
|
||||
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
|
||||
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
|
||||
return cuhd_recv(h, data, nsamples, 1);
|
||||
}
|
||||
|
||||
/* Setup USRP or input file */
|
||||
int iodev_init(iodev_t *q, iodev_cfg_t *config) {
|
||||
|
||||
if (config->input_file_name) {
|
||||
if (filesource_init(&q->fsrc, config->input_file_name, COMPLEX_FLOAT_BIN)) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
q->input_buffer_file = vec_malloc(SF_LEN_MAX * sizeof(cf_t));
|
||||
if (!q->input_buffer_file) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
q->mode = FILESOURCE;
|
||||
q->sf_len = 1920;
|
||||
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(config->uhd_args, &q->uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* set uhd_freq */
|
||||
cuhd_set_rx_gain(q->uhd, config->uhd_gain);
|
||||
cuhd_set_rx_freq(q->uhd, (double) config->uhd_freq);
|
||||
|
||||
cuhd_rx_wait_lo_locked(q->uhd);
|
||||
DEBUG("Set uhd_freq to %.3f MHz\n", (double ) config->uhd_freq);
|
||||
|
||||
DEBUG("Starting receiver...\n", 0);
|
||||
cuhd_start_rx_stream(q->uhd);
|
||||
|
||||
if (config->find_threshold > 0.0) {
|
||||
ue_sync_set_threshold(&q->sframe, config->find_threshold);
|
||||
}
|
||||
|
||||
ue_sync_init(&q->sframe, cuhd_set_rx_srate, cuhd_recv_wrapper, q->uhd);
|
||||
|
||||
// Here, the subframe length and input buffer is managed by ue_sync
|
||||
q->mode = UHD;
|
||||
|
||||
#else
|
||||
printf("Error UHD not available. Select an input file\n");
|
||||
return LIBLTE_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
memcpy(&q->config, config, sizeof(iodev_cfg_t));
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void iodev_free(iodev_t *q) {
|
||||
|
||||
if (q->mode == FILESOURCE) {
|
||||
filesource_free(&q->fsrc);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_close(q->uhd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Receive samples from the USRP or read from file */
|
||||
int iodev_receive(iodev_t *q, cf_t **buffer) {
|
||||
int n;
|
||||
if (q->mode == FILESOURCE) {
|
||||
DEBUG(" ----- READING %d SAMPLES ---- \n", q->sf_len);
|
||||
n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len);
|
||||
*buffer = q->input_buffer_file;
|
||||
if (n == -1) {
|
||||
fprintf(stderr, "Error reading file\n");
|
||||
/* wrap file if arrive to end */
|
||||
} else if (n < q->sf_len) {
|
||||
DEBUG("Read %d from file. Seeking to 0\n",n);
|
||||
filesource_seek(&q->fsrc, 0);
|
||||
n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len);
|
||||
if (n == -1) {
|
||||
fprintf(stderr, "Error reading file\n");
|
||||
/* wrap file if arrive to end */
|
||||
} else {
|
||||
n = 1;
|
||||
}
|
||||
} else {
|
||||
n = 1;
|
||||
}
|
||||
} else {
|
||||
/* Use ue_sync_work which returns a synchronized buffer of subframe samples */
|
||||
#ifndef DISABLE_UHD
|
||||
n = ue_sync_get_buffer(&q->sframe, buffer);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error calling ue_sync_work()\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void* iodev_get_cuhd(iodev_t *q) {
|
||||
if (q->mode == UHD) {
|
||||
return q->uhd;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool iodev_isfile(iodev_t *q) {
|
||||
return q->mode == FILESOURCE;
|
||||
}
|
||||
|
||||
bool iodev_isUSRP(iodev_t *q) {
|
||||
return q->mode == UHD;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef IODEF_H
|
||||
#define IODEF_H
|
||||
|
||||
#include "liblte/config.h"
|
||||
|
||||
#include "liblte/phy/phch/ue_sync.h"
|
||||
#include "liblte/phy/io/filesource.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
#endif
|
||||
|
||||
/*********
|
||||
*
|
||||
* This component is a wrapper to the cuhd or filesource modules. It uses
|
||||
* sync_frame_t to read aligned subframes from the USRP or filesource to read
|
||||
* subframes from a file.
|
||||
*
|
||||
* When created, it starts receiving/reading at 1.92 MHz. The sampling frequency
|
||||
* can then be changed using iodev_set_srate()
|
||||
*/
|
||||
|
||||
|
||||
typedef enum LIBLTE_API {FILESOURCE, UHD} iodev_mode_t;
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
char *input_file_name;
|
||||
float uhd_freq;
|
||||
float uhd_gain;
|
||||
char *uhd_args;
|
||||
float find_threshold;
|
||||
} iodev_cfg_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
#ifndef DISABLE_UHD
|
||||
void *uhd;
|
||||
ue_sync_t sframe;
|
||||
#endif
|
||||
uint32_t sf_len;
|
||||
cf_t *input_buffer_file; // for UHD mode, the input buffer is managed by sync_frame_t
|
||||
filesource_t fsrc;
|
||||
iodev_cfg_t config;
|
||||
iodev_mode_t mode;
|
||||
} iodev_t;
|
||||
|
||||
|
||||
LIBLTE_API int iodev_init(iodev_t *q,
|
||||
iodev_cfg_t *config);
|
||||
|
||||
LIBLTE_API void iodev_free(iodev_t *q);
|
||||
|
||||
LIBLTE_API int iodev_receive(iodev_t *q,
|
||||
cf_t **buffer);
|
||||
|
||||
LIBLTE_API void* iodev_get_cuhd(iodev_t *q);
|
||||
|
||||
LIBLTE_API bool iodev_isfile(iodev_t *q);
|
||||
|
||||
LIBLTE_API bool iodev_isUSRP(iodev_t *q);
|
||||
|
||||
#endif
|
@ -1,283 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
void *uhd;
|
||||
#endif
|
||||
|
||||
char *output_file_name = NULL;
|
||||
int nof_frames=-1;
|
||||
int cell_id = 1;
|
||||
int nof_prb = 6;
|
||||
char *uhd_args = "";
|
||||
|
||||
float uhd_amp=0.25, uhd_gain=10.0, uhd_freq=2400000000;
|
||||
|
||||
filesink_t fsink;
|
||||
lte_fft_t ifft;
|
||||
pbch_t pbch;
|
||||
|
||||
cf_t *slot_buffer = NULL, *output_buffer = NULL;
|
||||
int slot_n_re, slot_n_samples;
|
||||
|
||||
#define UHD_SAMP_FREQ 1920000
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [agmfoncvp]\n", prog);
|
||||
#ifndef DISABLE_UHD
|
||||
printf("\t-a UHD args [Default %s]\n", uhd_args);
|
||||
printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain);
|
||||
printf("\t-m UHD signal amplitude [Default %.2f]\n", uhd_amp);
|
||||
printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq/1000000);
|
||||
#else
|
||||
printf("\t UHD is disabled. CUHD library not available\n");
|
||||
#endif
|
||||
printf("\t-o output_file [Default USRP]\n");
|
||||
printf("\t-n number of frames [Default %d]\n", nof_frames);
|
||||
printf("\t-c cell id [Default %d]\n", cell_id);
|
||||
printf("\t-p nof_prb [Default %d]\n", nof_prb);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) {
|
||||
switch(opt) {
|
||||
case 'a':
|
||||
uhd_args = argv[optind];
|
||||
break;
|
||||
case 'g':
|
||||
uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'm':
|
||||
uhd_amp = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
uhd_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 'o':
|
||||
output_file_name = argv[optind];
|
||||
break;
|
||||
case 'n':
|
||||
nof_frames = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 'c':
|
||||
cell_id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
#ifdef DISABLE_UHD
|
||||
if (!output_file_name) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void base_init() {
|
||||
/* init memory */
|
||||
slot_buffer = malloc(sizeof(cf_t) * slot_n_re);
|
||||
if (!slot_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
output_buffer = malloc(sizeof(cf_t) * slot_n_samples);
|
||||
if (!output_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
/* open file or USRP */
|
||||
if (output_file_name) {
|
||||
if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) {
|
||||
fprintf(stderr, "Error opening file %s\n", output_file_name);
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(uhd_args,&uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
#else
|
||||
printf("Error UHD not available. Select an output file\n");
|
||||
exit(-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* create ifft object */
|
||||
if (lte_ifft_init(&ifft, CPNORM, nof_prb)) {
|
||||
fprintf(stderr, "Error creating iFFT object\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
|
||||
fprintf(stderr, "Error creating PBCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
|
||||
pbch_free(&pbch);
|
||||
|
||||
lte_ifft_free(&ifft);
|
||||
|
||||
if (slot_buffer) {
|
||||
free(slot_buffer);
|
||||
}
|
||||
if (output_buffer) {
|
||||
free(output_buffer);
|
||||
}
|
||||
if (output_file_name) {
|
||||
filesink_free(&fsink);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_close(&uhd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int nf, ns, N_id_2;
|
||||
cf_t pss_signal[PSS_LEN];
|
||||
float sss_signal0[SSS_LEN]; // for subframe 0
|
||||
float sss_signal5[SSS_LEN]; // for subframe 5
|
||||
pbch_mib_t mib;
|
||||
refsignal_t refs[NSLOTS_X_FRAME];
|
||||
int i;
|
||||
cf_t *slot1_symbols[MAX_PORTS_CTRL];
|
||||
|
||||
|
||||
#ifdef DISABLE_UHD
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
N_id_2 = cell_id%3;
|
||||
slot_n_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
|
||||
slot_n_samples = SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb));
|
||||
|
||||
/* this *must* be called after setting slot_len_* */
|
||||
base_init();
|
||||
|
||||
/* Generate PSS/SSS signals */
|
||||
pss_generate(pss_signal, N_id_2);
|
||||
sss_generate(sss_signal0, sss_signal5, cell_id);
|
||||
|
||||
/* Generate CRS signals */
|
||||
for (i=0;i<NSLOTS_X_FRAME;i++) {
|
||||
if (refsignal_init_LTEDL(&refs[i], 0, i, cell_id, CPNORM, nof_prb)) {
|
||||
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
mib.nof_ports = 1;
|
||||
mib.nof_prb = 6;
|
||||
mib.phich_length = PHICH_NORM;
|
||||
mib.phich_resources = R_1;
|
||||
mib.sfn = 0;
|
||||
|
||||
for (i=0;i<MAX_PORTS_CTRL;i++) { // now there's only 1 port
|
||||
slot1_symbols[i] = slot_buffer;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
if (!output_file_name) {
|
||||
printf("Set TX rate: %.2f MHz\n", cuhd_set_tx_srate(uhd, UHD_SAMP_FREQ)/1000000);
|
||||
printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain));
|
||||
printf("Set TX freq: %.2f MHz\n", cuhd_set_tx_freq(uhd, uhd_freq)/1000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
nf = 0;
|
||||
|
||||
while(nf<nof_frames || nof_frames == -1) {
|
||||
for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
|
||||
bzero(slot_buffer, sizeof(cf_t) * slot_n_re);
|
||||
|
||||
switch(ns) {
|
||||
case 0: // tx pss/sss
|
||||
case 10: // tx pss/sss
|
||||
pss_put_slot(pss_signal, slot_buffer, nof_prb, CPNORM);
|
||||
sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM);
|
||||
break;
|
||||
case 1: // tx pbch
|
||||
pbch_encode(&pbch, &mib, slot1_symbols, 1);
|
||||
break;
|
||||
default: // transmit zeros
|
||||
break;
|
||||
}
|
||||
|
||||
refsignal_put(&refs[ns], slot_buffer);
|
||||
|
||||
/* Transform to OFDM symbols */
|
||||
lte_ifft_run(&ifft, slot_buffer, output_buffer);
|
||||
|
||||
/* send to file or usrp */
|
||||
if (output_file_name) {
|
||||
filesink_write(&fsink, output_buffer, slot_n_samples);
|
||||
usleep(5000);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, slot_n_samples);
|
||||
cuhd_send(uhd, output_buffer, slot_n_samples, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
mib.sfn=(mib.sfn+1)%1024;
|
||||
printf("SFN: %4d\r", mib.sfn);fflush(stdout);
|
||||
nf++;
|
||||
}
|
||||
|
||||
base_free();
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
@ -1,501 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
void *uhd;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
#include "liblte/graphics/plot.h"
|
||||
plot_real_t poutfft;
|
||||
plot_complex_t pce;
|
||||
plot_scatter_t pscatrecv, pscatequal;
|
||||
#endif
|
||||
|
||||
#define MHZ 1000000
|
||||
#define SAMP_FREQ 1920000
|
||||
#define FLEN 9600
|
||||
#define FLEN_PERIOD 0.005
|
||||
|
||||
#define NOF_PORTS 2
|
||||
|
||||
float find_threshold = 20.0, track_threshold = 10.0;
|
||||
int max_track_lost = 20, nof_frames = -1;
|
||||
int track_len=300;
|
||||
char *input_file_name = NULL;
|
||||
int disable_plots = 0;
|
||||
|
||||
int go_exit=0;
|
||||
|
||||
float uhd_freq = 2600000000.0, uhd_gain = 20.0;
|
||||
char *uhd_args = "";
|
||||
|
||||
filesource_t fsrc;
|
||||
cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL];
|
||||
pbch_t pbch;
|
||||
lte_fft_t fft;
|
||||
chest_t chest;
|
||||
sync_t sfind, strack;
|
||||
cfo_t cfocorr;
|
||||
|
||||
|
||||
enum sync_state {FIND, TRACK};
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [iagfndvp]\n", prog);
|
||||
printf("\t-i input_file [Default use USRP]\n");
|
||||
#ifndef DISABLE_UHD
|
||||
printf("\t-a UHD args [Default %s]\n", uhd_args);
|
||||
printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain);
|
||||
printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq/1000000);
|
||||
#else
|
||||
printf("\t UHD is disabled. CUHD library not available\n");
|
||||
#endif
|
||||
printf("\t-n nof_frames [Default %d]\n", nof_frames);
|
||||
printf("\t-p PSS threshold [Default %f]\n", find_threshold);
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
printf("\t-d disable plots [Default enabled]\n");
|
||||
#else
|
||||
printf("\t plots are disabled. Graphics library not available\n");
|
||||
#endif
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "iagfndvp")) != -1) {
|
||||
switch(opt) {
|
||||
case 'i':
|
||||
input_file_name = argv[optind];
|
||||
break;
|
||||
case 'a':
|
||||
uhd_args = argv[optind];
|
||||
break;
|
||||
case 'g':
|
||||
uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
uhd_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
find_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_frames = atoi(argv[optind]);
|
||||
break;
|
||||
case 'd':
|
||||
disable_plots = 1;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
|
||||
void init_plots() {
|
||||
plot_init();
|
||||
plot_real_init(&poutfft);
|
||||
plot_real_setTitle(&poutfft, "Output FFT - Magnitude");
|
||||
plot_real_setLabels(&poutfft, "Index", "dB");
|
||||
plot_real_setYAxisScale(&poutfft, -60, 0);
|
||||
plot_real_setXAxisScale(&poutfft, 1, 504);
|
||||
|
||||
plot_complex_init(&pce);
|
||||
plot_complex_setTitle(&pce, "Channel Estimates");
|
||||
plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01);
|
||||
plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01);
|
||||
plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01);
|
||||
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
|
||||
|
||||
plot_scatter_init(&pscatrecv);
|
||||
plot_scatter_setTitle(&pscatrecv, "Received Symbols");
|
||||
plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01);
|
||||
plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01);
|
||||
|
||||
plot_scatter_init(&pscatequal);
|
||||
plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
|
||||
plot_scatter_setXAxisScale(&pscatequal, -1, 1);
|
||||
plot_scatter_setYAxisScale(&pscatequal, -1, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int base_init(int frame_length) {
|
||||
int i;
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
if (!disable_plots) {
|
||||
init_plots();
|
||||
}
|
||||
#else
|
||||
printf("-- PLOTS are disabled. Graphics library not available --\n\n");
|
||||
#endif
|
||||
|
||||
if (input_file_name) {
|
||||
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* open UHD device */
|
||||
#ifndef DISABLE_UHD
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(uhd_args,&uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
printf("Error UHD not available. Select an input file\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
input_buffer = (cf_t*) malloc(frame_length * sizeof(cf_t));
|
||||
if (!input_buffer) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fft_buffer = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
|
||||
if (!fft_buffer) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0;i<MAX_PORTS_CTRL;i++) {
|
||||
ce[i] = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
|
||||
if (!ce[i]) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (sync_init(&sfind, FLEN)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
return -1;
|
||||
}
|
||||
if (sync_init(&strack, track_len)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
return -1;
|
||||
}
|
||||
if (chest_init(&chest, LINEAR, CPNORM, 6, NOF_PORTS)) {
|
||||
fprintf(stderr, "Error initializing equalizer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cfo_init(&cfocorr, FLEN)) {
|
||||
fprintf(stderr, "Error initiating CFO\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lte_fft_init(&fft, CPNORM, 6)) {
|
||||
fprintf(stderr, "Error initializing FFT\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
int i;
|
||||
|
||||
if (input_file_name) {
|
||||
filesource_free(&fsrc);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_close(uhd);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
plot_exit();
|
||||
#endif
|
||||
|
||||
sync_free(&sfind);
|
||||
sync_free(&strack);
|
||||
lte_fft_free(&fft);
|
||||
chest_free(&chest);
|
||||
cfo_free(&cfocorr);
|
||||
|
||||
free(input_buffer);
|
||||
free(fft_buffer);
|
||||
for (i=0;i<MAX_PORTS_CTRL;i++) {
|
||||
free(ce[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mib_decoder_init(int cell_id) {
|
||||
|
||||
if (chest_ref_LTEDL(&chest, cell_id)) {
|
||||
fprintf(stderr, "Error initializing reference signal\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
|
||||
fprintf(stderr, "Error initiating PBCH\n");
|
||||
return -1;
|
||||
}
|
||||
DEBUG("PBCH initiated cell_id=%d\n", cell_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
|
||||
int i, n;
|
||||
lte_fft_run(&fft, input, fft_buffer);
|
||||
|
||||
/* Get channel estimates for each port */
|
||||
for (i=0;i<NOF_PORTS;i++) {
|
||||
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
|
||||
}
|
||||
|
||||
DEBUG("Decoding PBCH\n", 0);
|
||||
n = pbch_decode(&pbch, fft_buffer, ce, 1, mib);
|
||||
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
float tmp[72*7];
|
||||
if (!disable_plots) {
|
||||
for (i=0;i<72*7;i++) {
|
||||
tmp[i] = 10*log10f(cabsf(fft_buffer[i]));
|
||||
}
|
||||
plot_real_setNewData(&poutfft, tmp, 72*7);
|
||||
plot_complex_setNewData(&pce, ce[0], 72*7);
|
||||
plot_scatter_setNewData(&pscatrecv, pbch.pbch_symbols[0], pbch.nof_symbols);
|
||||
if (n) {
|
||||
plot_scatter_setNewData(&pscatequal, pbch.pbch_d, pbch.nof_symbols);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void sigintHandler(int sig_num)
|
||||
{
|
||||
go_exit=1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt;
|
||||
int cell_id;
|
||||
int find_idx, track_idx, last_found;
|
||||
enum sync_state state;
|
||||
int nslot;
|
||||
pbch_mib_t mib;
|
||||
float cfo;
|
||||
int n;
|
||||
int nof_found_mib = 0;
|
||||
float timeoffset = 0;
|
||||
|
||||
#ifdef DISABLE_UHD
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (base_init(FLEN)) {
|
||||
fprintf(stderr, "Error initializing memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
sync_pss_det_peak_to_avg(&sfind);
|
||||
sync_pss_det_peak_to_avg(&strack);
|
||||
|
||||
if (!input_file_name) {
|
||||
#ifndef DISABLE_UHD
|
||||
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
|
||||
cuhd_set_rx_srate(uhd, SAMP_FREQ);
|
||||
cuhd_set_rx_gain(uhd, uhd_gain);
|
||||
/* set uhd_freq */
|
||||
cuhd_set_rx_freq(uhd, (double) uhd_freq);
|
||||
cuhd_rx_wait_lo_locked(uhd);
|
||||
DEBUG("Set uhd_freq to %.3f MHz\n", (double) uhd_freq);
|
||||
|
||||
DEBUG("Starting receiver...\n",0);
|
||||
cuhd_start_rx_stream(uhd);
|
||||
#endif
|
||||
}
|
||||
|
||||
printf("\n --- Press Ctrl+C to exit --- \n");
|
||||
signal(SIGINT, sigintHandler);
|
||||
|
||||
state = FIND;
|
||||
nslot = 0;
|
||||
find_idx = 0;
|
||||
cfo = 0;
|
||||
mib.sfn = -1;
|
||||
frame_cnt = 0;
|
||||
last_found = 0;
|
||||
sync_set_threshold(&sfind, find_threshold);
|
||||
sync_force_N_id_2(&sfind, -1);
|
||||
|
||||
while(!go_exit && (frame_cnt < nof_frames || nof_frames==-1)) {
|
||||
INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
|
||||
if (input_file_name) {
|
||||
n = filesource_read(&fsrc, input_buffer, FLEN);
|
||||
if (n == -1) {
|
||||
fprintf(stderr, "Error reading file\n");
|
||||
exit(-1);
|
||||
} else if (n < FLEN) {
|
||||
filesource_seek(&fsrc, 0);
|
||||
filesource_read(&fsrc, input_buffer, FLEN);
|
||||
}
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_recv(uhd, input_buffer, FLEN, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
switch(state) {
|
||||
case FIND:
|
||||
/* find peak in all frame */
|
||||
find_idx = sync_run(&sfind, input_buffer);
|
||||
INFO("FIND %3d:\tPAR=%.2f\n", frame_cnt, sync_get_peak_to_avg(&sfind));
|
||||
if (find_idx != -1) {
|
||||
/* if found peak, go to track and set track threshold */
|
||||
cell_id = sync_get_cell_id(&sfind);
|
||||
if (cell_id != -1) {
|
||||
frame_cnt = -1;
|
||||
last_found = 0;
|
||||
sync_set_threshold(&strack, track_threshold);
|
||||
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
|
||||
sync_force_cp(&strack, sync_get_cp(&sfind));
|
||||
mib_decoder_init(cell_id);
|
||||
nof_found_mib = 0;
|
||||
nslot = sync_get_slot_id(&sfind);
|
||||
nslot=(nslot+10)%20;
|
||||
cfo = 0;
|
||||
timeoffset = 0;
|
||||
printf("\n");
|
||||
state = TRACK;
|
||||
} else {
|
||||
printf("cellid=-1\n");
|
||||
}
|
||||
}
|
||||
if (verbose == VERBOSE_NONE) {
|
||||
printf("Finding PSS... PAR=%.2f\r", sync_get_peak_to_avg(&sfind));
|
||||
}
|
||||
break;
|
||||
case TRACK:
|
||||
/* Find peak around known position find_idx */
|
||||
INFO("TRACK %3d: PSS find_idx %d offset %d\n", frame_cnt, find_idx, find_idx - track_len);
|
||||
track_idx = sync_run(&strack, &input_buffer[find_idx - track_len]);
|
||||
|
||||
if (track_idx != -1) {
|
||||
/* compute cumulative moving average CFO */
|
||||
cfo = (sync_get_cfo(&strack) + frame_cnt * cfo) / (frame_cnt + 1);
|
||||
/* compute cumulative moving average time offset */
|
||||
timeoffset = (float) (track_idx-track_len + timeoffset * frame_cnt) / (frame_cnt + 1);
|
||||
last_found = frame_cnt;
|
||||
find_idx = (find_idx + track_idx - track_len)%FLEN;
|
||||
if (nslot != sync_get_slot_id(&strack)) {
|
||||
INFO("Expected slot %d but got %d\n", nslot, sync_get_slot_id(&strack));
|
||||
printf("\r\n");
|
||||
fflush(stdout);
|
||||
printf("\r\n");
|
||||
state = FIND;
|
||||
}
|
||||
} else {
|
||||
/* if sync not found, adjust time offset with the averaged value */
|
||||
find_idx = (find_idx + (int) timeoffset)%FLEN;
|
||||
}
|
||||
|
||||
/* if we missed too many PSS go back to FIND */
|
||||
if (frame_cnt - last_found > max_track_lost) {
|
||||
INFO("%d frames lost. Going back to FIND", frame_cnt - last_found);
|
||||
printf("\r\n");
|
||||
fflush(stdout);
|
||||
printf("\r\n");
|
||||
state = FIND;
|
||||
}
|
||||
|
||||
// Correct CFO
|
||||
INFO("Correcting CFO=%.4f\n", cfo);
|
||||
|
||||
cfo_correct(&cfocorr, input_buffer, -cfo/128);
|
||||
|
||||
if (nslot == 0 && find_idx + 960 < FLEN) {
|
||||
INFO("Finding MIB at idx %d\n", find_idx);
|
||||
if (mib_decoder_run(&input_buffer[find_idx], &mib)) {
|
||||
INFO("MIB detected attempt=%d\n", frame_cnt);
|
||||
if (verbose == VERBOSE_NONE) {
|
||||
if (!nof_found_mib) {
|
||||
printf("\r\n");
|
||||
fflush(stdout);
|
||||
printf("\r\n");
|
||||
printf(" - Phy. CellId:\t%d\n", cell_id);
|
||||
pbch_mib_fprint(stdout, &mib);
|
||||
}
|
||||
}
|
||||
nof_found_mib++;
|
||||
} else {
|
||||
INFO("MIB not found attempt %d\n",frame_cnt);
|
||||
}
|
||||
if (frame_cnt) {
|
||||
printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, ErrorRate: %.1e\r", mib.sfn,
|
||||
cfo*15, timeoffset/5, find_idx, frame_cnt-2*(nof_found_mib-1), frame_cnt,
|
||||
(float) (frame_cnt-2*(nof_found_mib-1))/frame_cnt);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
if (input_file_name) {
|
||||
usleep(5000);
|
||||
}
|
||||
nslot = (nslot+10)%20;
|
||||
break;
|
||||
}
|
||||
frame_cnt++;
|
||||
}
|
||||
|
||||
base_free();
|
||||
|
||||
printf("\nBye\n");
|
||||
exit(0);
|
||||
}
|
||||
|
@ -0,0 +1,386 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
void *uhd;
|
||||
#endif
|
||||
|
||||
char *output_file_name = NULL;
|
||||
|
||||
lte_cell_t cell = {
|
||||
6, // nof_prb
|
||||
1, // nof_ports
|
||||
1, // cell_id
|
||||
CPNORM // cyclic prefix
|
||||
};
|
||||
|
||||
uint32_t cfi=1;
|
||||
uint32_t mcs_idx = 12;
|
||||
int nof_frames = -1;
|
||||
|
||||
char *uhd_args = "";
|
||||
float uhd_amp = 0.25, uhd_gain = 10.0, uhd_freq = 2400000000;
|
||||
|
||||
filesink_t fsink;
|
||||
lte_fft_t ifft;
|
||||
pbch_t pbch;
|
||||
pcfich_t pcfich;
|
||||
pdcch_t pdcch;
|
||||
pdsch_t pdsch;
|
||||
pdsch_harq_t harq_process;
|
||||
regs_t regs;
|
||||
|
||||
cf_t *sf_buffer = NULL, *output_buffer = NULL;
|
||||
int sf_n_re, sf_n_samples;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [agmfoncvp]\n", prog);
|
||||
#ifndef DISABLE_UHD
|
||||
printf("\t-a UHD args [Default %s]\n", uhd_args);
|
||||
printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain);
|
||||
printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq / 1000000);
|
||||
#else
|
||||
printf("\t UHD is disabled. CUHD library not available\n");
|
||||
#endif
|
||||
printf("\t-o output_file [Default USRP]\n");
|
||||
printf("\t-m MCS index [Default %d]\n", mcs_idx);
|
||||
printf("\t-n number of frames [Default %d]\n", nof_frames);
|
||||
printf("\t-c cell id [Default %d]\n", cell.id);
|
||||
printf("\t-p nof_prb [Default %d]\n", cell.nof_prb);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
uhd_args = argv[optind];
|
||||
break;
|
||||
case 'g':
|
||||
uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
uhd_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 'o':
|
||||
output_file_name = argv[optind];
|
||||
break;
|
||||
case 'm':
|
||||
mcs_idx = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_frames = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
cell.nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 'c':
|
||||
cell.id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
#ifdef DISABLE_UHD
|
||||
if (!output_file_name) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void base_init() {
|
||||
|
||||
/* init memory */
|
||||
sf_buffer = malloc(sizeof(cf_t) * sf_n_re);
|
||||
if (!sf_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
output_buffer = malloc(sizeof(cf_t) * sf_n_samples);
|
||||
if (!output_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
/* open file or USRP */
|
||||
if (output_file_name) {
|
||||
if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) {
|
||||
fprintf(stderr, "Error opening file %s\n", output_file_name);
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(uhd_args, &uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
#else
|
||||
printf("Error UHD not available. Select an output file\n");
|
||||
exit(-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* create ifft object */
|
||||
if (lte_ifft_init(&ifft, CPNORM, cell.nof_prb)) {
|
||||
fprintf(stderr, "Error creating iFFT object\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (pbch_init(&pbch, cell)) {
|
||||
fprintf(stderr, "Error creating PBCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (regs_init(®s, R_1, PHICH_NORM, cell)) {
|
||||
fprintf(stderr, "Error initiating regs\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pcfich_init(&pcfich, ®s, cell)) {
|
||||
fprintf(stderr, "Error creating PBCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (regs_set_cfi(®s, cfi)) {
|
||||
fprintf(stderr, "Error setting CFI\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pdcch_init(&pdcch, ®s, cell)) {
|
||||
fprintf(stderr, "Error creating PDCCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pdsch_init(&pdsch, cell)) {
|
||||
fprintf(stderr, "Error creating PDSCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
pdsch_set_rnti(&pdsch, 1234);
|
||||
|
||||
if (pdsch_harq_init(&harq_process, &pdsch)) {
|
||||
fprintf(stderr, "Error initiating HARQ process\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
|
||||
pdsch_harq_free(&harq_process);
|
||||
pdsch_free(&pdsch);
|
||||
pdcch_free(&pdcch);
|
||||
regs_free(®s);
|
||||
pbch_free(&pbch);
|
||||
|
||||
lte_ifft_free(&ifft);
|
||||
|
||||
if (sf_buffer) {
|
||||
free(sf_buffer);
|
||||
}
|
||||
if (output_buffer) {
|
||||
free(output_buffer);
|
||||
}
|
||||
if (output_file_name) {
|
||||
filesink_free(&fsink);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_close(&uhd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int nf, sf_idx, N_id_2;
|
||||
cf_t pss_signal[PSS_LEN];
|
||||
float sss_signal0[SSS_LEN]; // for subframe 0
|
||||
float sss_signal5[SSS_LEN]; // for subframe 5
|
||||
pbch_mib_t mib;
|
||||
ra_pdsch_t ra_dl;
|
||||
ra_prb_t prb_alloc;
|
||||
refsignal_t refs[NSLOTS_X_FRAME];
|
||||
int i, n;
|
||||
char *data;
|
||||
cf_t *sf_symbols[MAX_PORTS];
|
||||
dci_msg_t dci_msg;
|
||||
dci_location_t locations[NSUBFRAMES_X_FRAME][10];
|
||||
|
||||
#ifdef DISABLE_UHD
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
N_id_2 = cell.id % 3;
|
||||
sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB;
|
||||
sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(cell.nof_prb));
|
||||
|
||||
/* this *must* be called after setting slot_len_* */
|
||||
base_init();
|
||||
|
||||
/* Generate PSS/SSS signals */
|
||||
pss_generate(pss_signal, N_id_2);
|
||||
sss_generate(sss_signal0, sss_signal5, cell.id);
|
||||
|
||||
/* Generate CRS signals */
|
||||
for (i = 0; i < NSLOTS_X_FRAME; i++) {
|
||||
if (refsignal_init_LTEDL(&refs[i], 0, i, cell)) {
|
||||
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
mib.nof_ports = cell.nof_ports;
|
||||
mib.nof_prb = cell.nof_prb;
|
||||
mib.phich_length = PHICH_NORM;
|
||||
mib.phich_resources = R_1;
|
||||
mib.sfn = 0;
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) { // now there's only 1 port
|
||||
sf_symbols[i] = sf_buffer;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
if (!output_file_name) {
|
||||
printf("Set TX rate: %.2f MHz\n",
|
||||
cuhd_set_tx_srate(uhd, lte_sampling_freq_hz(cell.nof_prb)) / 1000000);
|
||||
printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain));
|
||||
printf("Set TX freq: %.2f MHz\n",
|
||||
cuhd_set_tx_freq(uhd, uhd_freq) / 1000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
bzero(&ra_dl, sizeof(ra_pdsch_t));
|
||||
ra_dl.harq_process = 0;
|
||||
ra_dl.mcs_idx = mcs_idx;
|
||||
ra_dl.ndi = 0;
|
||||
ra_dl.rv_idx = 0;
|
||||
ra_dl.alloc_type = alloc_type0;
|
||||
ra_dl.type0_alloc.rbg_bitmask = 0xffffffff;
|
||||
|
||||
dci_msg_pack_pdsch(&ra_dl, &dci_msg, Format1, cell.nof_prb, false);
|
||||
|
||||
ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb);
|
||||
ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, 1, cell.nof_prb<10?(cfi+1):cfi, CPNORM);
|
||||
ra_mcs_from_idx_dl(mcs_idx, cell.nof_prb, &ra_dl.mcs);
|
||||
|
||||
ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb);
|
||||
|
||||
/* Initiate valid DCI locations */
|
||||
for (i=0;i<NSUBFRAMES_X_FRAME;i++) {
|
||||
pdcch_ue_locations(&pdcch, locations[i], 10, i, cfi, 1234);
|
||||
}
|
||||
|
||||
data = malloc(sizeof(char) * ra_dl.mcs.tbs);
|
||||
if (!data) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
nf = 0;
|
||||
|
||||
if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) {
|
||||
fprintf(stderr, "Error configuring HARQ process\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
while (nf < nof_frames || nof_frames == -1) {
|
||||
for (sf_idx = 0; sf_idx < NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) {
|
||||
bzero(sf_buffer, sizeof(cf_t) * sf_n_re);
|
||||
|
||||
if (sf_idx == 0 || sf_idx == 5) {
|
||||
pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, CPNORM);
|
||||
sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb,
|
||||
CPNORM);
|
||||
}
|
||||
|
||||
if (sf_idx == 0) {
|
||||
pbch_encode(&pbch, &mib, sf_symbols);
|
||||
}
|
||||
|
||||
for (n=0;n<2;n++) {
|
||||
refsignal_put(&refs[2*sf_idx+n], &sf_buffer[n*sf_n_re/2]);
|
||||
}
|
||||
|
||||
pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx);
|
||||
|
||||
INFO("SF: %d, Generating %d random bits\n", sf_idx, ra_dl.mcs.tbs);
|
||||
for (i=0;i<ra_dl.mcs.tbs;i++) {
|
||||
data[i] = rand()%2;
|
||||
}
|
||||
|
||||
INFO("Puttting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
|
||||
if (pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], 1234, sf_symbols, sf_idx, cfi)) {
|
||||
fprintf(stderr, "Error encoding DCI message\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
pdsch_encode(&pdsch, data, sf_symbols, sf_idx, &harq_process, ra_dl.rv_idx);
|
||||
|
||||
/* Transform to OFDM symbols */
|
||||
lte_ifft_run_sf(&ifft, sf_buffer, output_buffer);
|
||||
|
||||
/* send to file or usrp */
|
||||
if (output_file_name) {
|
||||
filesink_write(&fsink, output_buffer, sf_n_samples);
|
||||
usleep(5000);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, sf_n_samples);
|
||||
cuhd_send(uhd, output_buffer, sf_n_samples, true);
|
||||
#endif
|
||||
}
|
||||
nf++;
|
||||
}
|
||||
mib.sfn = (mib.sfn + 1) % 1024;
|
||||
printf("SFN: %4d\r", mib.sfn);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
base_free();
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,323 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
#include "iodev.h"
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
void init_plots();
|
||||
void do_plots(ue_dl_t *q, uint32_t sf_idx);
|
||||
#endif
|
||||
|
||||
int go_exit = 0;
|
||||
|
||||
/* Local function definitions */
|
||||
void init_plots();
|
||||
|
||||
/**********************************************************************
|
||||
* Program arguments processing
|
||||
***********************************************************************/
|
||||
typedef struct {
|
||||
uint32_t cell_id_file;
|
||||
uint32_t nof_prb_file;
|
||||
uint16_t rnti;
|
||||
int nof_subframes;
|
||||
bool disable_plots;
|
||||
iodev_cfg_t io_config;
|
||||
}prog_args_t;
|
||||
|
||||
void args_default(prog_args_t *args) {
|
||||
args->cell_id_file = 1;
|
||||
args->nof_prb_file = 6;
|
||||
args->rnti = SIRNTI;
|
||||
args->nof_subframes = -1;
|
||||
args->disable_plots = false;
|
||||
args->io_config.find_threshold = -1.0;
|
||||
args->io_config.input_file_name = NULL;
|
||||
args->io_config.uhd_args = "";
|
||||
args->io_config.uhd_freq = -1.0;
|
||||
args->io_config.uhd_gain = 20.0;
|
||||
}
|
||||
|
||||
void usage(prog_args_t *args, char *prog) {
|
||||
printf("Usage: %s [cargfndvtb] [-i input_file | -f rx_frequency (in Hz)]\n", prog);
|
||||
printf("\t-c cell_id if reading from file [Default %d]\n", args->cell_id_file);
|
||||
printf("\t-p nof_prb if reading from file [Default %d]\n", args->nof_prb_file);
|
||||
printf("\t-r RNTI to look for [Default 0x%x]\n", args->rnti);
|
||||
#ifndef DISABLE_UHD
|
||||
printf("\t-a UHD args [Default %s]\n", args->io_config.uhd_args);
|
||||
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->io_config.uhd_gain);
|
||||
#else
|
||||
printf("\t UHD is disabled. CUHD library not available\n");
|
||||
#endif
|
||||
printf("\t-b Decode PBCH only [Default All channels]\n");
|
||||
printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes);
|
||||
printf("\t-t PSS threshold [Default %f]\n", args->io_config.find_threshold);
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
printf("\t-d disable plots [Default enabled]\n");
|
||||
#else
|
||||
printf("\t plots are disabled. Graphics library not available\n");
|
||||
#endif
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(prog_args_t *args, int argc, char **argv) {
|
||||
int opt;
|
||||
args_default(args);
|
||||
while ((opt = getopt(argc, argv, "icagfndvtbp")) != -1) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
args->io_config.input_file_name = argv[optind];
|
||||
break;
|
||||
case 'c':
|
||||
args->cell_id_file = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
args->nof_prb_file = atoi(argv[optind]);
|
||||
break;
|
||||
case 'a':
|
||||
args->io_config.uhd_args = argv[optind];
|
||||
break;
|
||||
case 'g':
|
||||
args->io_config.uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
args->io_config.uhd_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
args->io_config.find_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
args->nof_subframes = atoi(argv[optind]);
|
||||
break;
|
||||
case 'd':
|
||||
args->disable_plots = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(args, argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (args->io_config.uhd_freq < 0 && args->io_config.input_file_name == NULL) {
|
||||
usage(args, argv[0]);
|
||||
}
|
||||
}
|
||||
/**********************************************************************/
|
||||
|
||||
void sigintHandler(int x) {
|
||||
go_exit = 1;
|
||||
}
|
||||
|
||||
/* TODO: Do something with the output data */
|
||||
char data[10000];
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ret;
|
||||
cf_t *sf_buffer;
|
||||
iodev_t iodev;
|
||||
prog_args_t prog_args;
|
||||
lte_cell_t cell;
|
||||
ue_dl_t ue_dl;
|
||||
bool ue_dl_initiated = false;
|
||||
int64_t sf_cnt;
|
||||
uint32_t sf_idx;
|
||||
pbch_mib_t mib;
|
||||
bool printed_sib = false;
|
||||
uint32_t rlen;
|
||||
|
||||
parse_args(&prog_args, argc, argv);
|
||||
|
||||
if (iodev_init(&iodev, &prog_args.io_config)) {
|
||||
fprintf(stderr, "Error initiating input device\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (!prog_args.disable_plots) {
|
||||
init_plots();
|
||||
}
|
||||
|
||||
/* Setup SIGINT handler */
|
||||
printf("\n --- Press Ctrl+C to exit --- \n");
|
||||
signal(SIGINT, sigintHandler);
|
||||
|
||||
/* Initialize frame and subframe counters */
|
||||
sf_cnt = 0;
|
||||
sf_idx = 0;
|
||||
|
||||
/* Main loop */
|
||||
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
|
||||
|
||||
ret = iodev_receive(&iodev, &sf_buffer);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error reading from input device (%d)\n", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
/* iodev_receive returns 1 if successfully read 1 aligned subframe */
|
||||
if (ret == 1) {
|
||||
if (!ue_dl_initiated) {
|
||||
if (iodev_isUSRP(&iodev)) {
|
||||
cell = ue_sync_get_cell(&iodev.sframe);
|
||||
mib = ue_sync_get_mib(&iodev.sframe);
|
||||
} else {
|
||||
cell.id = prog_args.cell_id_file;
|
||||
cell.cp = CPNORM;
|
||||
cell.nof_ports = 1; // TODO: Use prog_args
|
||||
cell.nof_prb = prog_args.nof_prb_file;
|
||||
mib.phich_resources = R_1;
|
||||
mib.phich_length = PHICH_NORM;
|
||||
}
|
||||
if (ue_dl_init(&ue_dl, cell, mib.phich_resources, mib.phich_length, 1234)) {
|
||||
fprintf(stderr, "Error initiating UE downlink processing module\n");
|
||||
exit(-1);
|
||||
}
|
||||
pdsch_set_rnti(&ue_dl.pdsch, prog_args.rnti);
|
||||
ue_dl_initiated = true;
|
||||
} else {
|
||||
if (iodev_isUSRP(&iodev)) {
|
||||
sf_idx = ue_sync_get_sfidx(&iodev.sframe);
|
||||
}
|
||||
rlen = ue_dl_receive(&ue_dl, sf_buffer, data, sf_idx, ue_sync_get_mib(&iodev.sframe).sfn, prog_args.rnti);
|
||||
if (rlen < 0) {
|
||||
fprintf(stderr, "\nError running receiver\n");fflush(stdout);
|
||||
exit(-1);
|
||||
}
|
||||
if (prog_args.rnti == SIRNTI && !printed_sib && rlen > 0) {
|
||||
printf("\n\nDecoded SIB1 Message: ");
|
||||
vec_fprint_hex(stdout, data, rlen);
|
||||
printf("\n");fflush(stdout);
|
||||
printed_sib = true;
|
||||
}
|
||||
if (!(sf_cnt % 10)) {
|
||||
printf("Cell ID: %3d, RSSI: %+.2f dBm, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r",
|
||||
cell.id, 20*log10f(agc_get_rssi(&iodev.sframe.agc)), iodev.sframe.cur_cfo * 15, iodev.sframe.mean_time_offset / 5, iodev.sframe.peak_idx,
|
||||
(int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (float) ue_dl.pkt_errors / ue_dl.pkts_total);
|
||||
fflush(stdout);
|
||||
if (VERBOSE_ISINFO()) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (!prog_args.disable_plots && sf_idx == 5) {
|
||||
do_plots(&ue_dl, sf_idx);
|
||||
}
|
||||
}
|
||||
if (iodev_isfile(&iodev)) {
|
||||
sf_idx++;
|
||||
if (sf_idx == NSUBFRAMES_X_FRAME) {
|
||||
sf_idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prog_args.nof_subframes > 0) {
|
||||
sf_cnt++;
|
||||
}
|
||||
if (iodev_isfile(&iodev)) {
|
||||
usleep(5000);
|
||||
}
|
||||
}
|
||||
|
||||
if (ue_dl_initiated) {
|
||||
ue_dl_free(&ue_dl);
|
||||
}
|
||||
iodev_free(&iodev);
|
||||
|
||||
printf("\nBye\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* Plotting Functions
|
||||
***********************************************************************/
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
|
||||
|
||||
#include "liblte/graphics/plot.h"
|
||||
plot_real_t poutfft;
|
||||
plot_complex_t pce;
|
||||
plot_scatter_t pscatrecv, pscatequal;
|
||||
|
||||
float tmp_plot[SLOT_LEN_RE(MAX_PRB, CPNORM)];
|
||||
|
||||
void init_plots() {
|
||||
plot_init();
|
||||
plot_real_init(&poutfft);
|
||||
plot_real_setTitle(&poutfft, "Output FFT - Magnitude");
|
||||
plot_real_setLabels(&poutfft, "Index", "dB");
|
||||
plot_real_setYAxisScale(&poutfft, -30, 20);
|
||||
|
||||
plot_complex_init(&pce);
|
||||
plot_complex_setTitle(&pce, "Channel Estimates");
|
||||
plot_complex_setYAxisScale(&pce, Ip, -3, 3);
|
||||
plot_complex_setYAxisScale(&pce, Q, -3, 3);
|
||||
plot_complex_setYAxisScale(&pce, Magnitude, 0, 4);
|
||||
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
|
||||
|
||||
plot_scatter_init(&pscatrecv);
|
||||
plot_scatter_setTitle(&pscatrecv, "Received Symbols");
|
||||
plot_scatter_setXAxisScale(&pscatrecv, -4, 4);
|
||||
plot_scatter_setYAxisScale(&pscatrecv, -4, 4);
|
||||
|
||||
plot_scatter_init(&pscatequal);
|
||||
plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
|
||||
plot_scatter_setXAxisScale(&pscatequal, -2, 2);
|
||||
plot_scatter_setYAxisScale(&pscatequal, -2, 2);
|
||||
}
|
||||
|
||||
void do_plots(ue_dl_t *q, uint32_t sf_idx) {
|
||||
int i;
|
||||
uint32_t nof_re = SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp);
|
||||
uint32_t nof_symbols = q->harq_process[0].prb_alloc.re_sf[sf_idx];
|
||||
for (i = 0; i < nof_re; i++) {
|
||||
tmp_plot[i] = 10 * log10f(cabsf(q->sf_symbols[i]));
|
||||
if (isinf(tmp_plot[i])) {
|
||||
tmp_plot[i] = -80;
|
||||
}
|
||||
}
|
||||
plot_real_setNewData(&poutfft, tmp_plot, nof_re);
|
||||
plot_complex_setNewData(&pce, q->ce[0], nof_re);
|
||||
plot_scatter_setNewData(&pscatrecv, q->pdsch.pdsch_symbols[0], nof_symbols);
|
||||
plot_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols);
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,69 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef AGC_
|
||||
#define AGC_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <complex.h>
|
||||
|
||||
#include "liblte/config.h"
|
||||
|
||||
/* Automatic Gain Control
|
||||
*
|
||||
*/
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
#define AGC_DEFAULT_BW (1e-2f)
|
||||
|
||||
typedef struct LIBLTE_API{
|
||||
float bandwidth;
|
||||
float gain;
|
||||
float y_out;
|
||||
bool lock;
|
||||
} agc_t;
|
||||
|
||||
LIBLTE_API int agc_init (agc_t *q);
|
||||
|
||||
LIBLTE_API void agc_free(agc_t *q);
|
||||
|
||||
LIBLTE_API void agc_set_bandwidth(agc_t *q,
|
||||
float bandwidth);
|
||||
|
||||
LIBLTE_API float agc_get_rssi(agc_t *q);
|
||||
|
||||
LIBLTE_API void agc_lock(agc_t *q, bool enable);
|
||||
|
||||
LIBLTE_API void agc_push(agc_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output,
|
||||
uint32_t len);
|
||||
|
||||
#endif // AGC_
|
@ -0,0 +1,96 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UEDL_H
|
||||
#define UEDL_H
|
||||
|
||||
/*******************************************************
|
||||
*
|
||||
* This module is a frontend to all the data and control channels processing
|
||||
* modules.
|
||||
********************************************************/
|
||||
|
||||
|
||||
|
||||
#include "liblte/phy/ch_estimation/chest.h"
|
||||
#include "liblte/phy/common/fft.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
|
||||
#include "liblte/phy/phch/dci.h"
|
||||
#include "liblte/phy/phch/pbch.h"
|
||||
#include "liblte/phy/phch/pcfich.h"
|
||||
#include "liblte/phy/phch/pdcch.h"
|
||||
#include "liblte/phy/phch/pdsch.h"
|
||||
#include "liblte/phy/phch/phich.h"
|
||||
#include "liblte/phy/phch/ra.h"
|
||||
#include "liblte/phy/phch/regs.h"
|
||||
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
#include "liblte/config.h"
|
||||
|
||||
#define NOF_HARQ_PROCESSES 8
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
pcfich_t pcfich;
|
||||
pdcch_t pdcch;
|
||||
pdsch_t pdsch;
|
||||
pdsch_harq_t harq_process[NOF_HARQ_PROCESSES];
|
||||
regs_t regs;
|
||||
lte_fft_t fft;
|
||||
chest_t chest;
|
||||
|
||||
lte_cell_t cell;
|
||||
|
||||
cf_t *sf_symbols;
|
||||
cf_t *ce[MAX_PORTS];
|
||||
|
||||
uint64_t pkt_errors;
|
||||
uint64_t pkts_total;
|
||||
uint64_t nof_trials;
|
||||
|
||||
uint16_t user_rnti;
|
||||
}ue_dl_t;
|
||||
|
||||
/* This function shall be called just after the initial synchronization */
|
||||
LIBLTE_API int ue_dl_init(ue_dl_t *q,
|
||||
lte_cell_t cell,
|
||||
phich_resources_t phich_resources,
|
||||
phich_length_t phich_length,
|
||||
uint16_t user_rnti);
|
||||
|
||||
LIBLTE_API void ue_dl_free(ue_dl_t *q);
|
||||
|
||||
LIBLTE_API int ue_dl_receive(ue_dl_t *q,
|
||||
cf_t *sf_buffer,
|
||||
char *data,
|
||||
uint32_t sf_idx,
|
||||
uint32_t sfn,
|
||||
uint16_t rnti);
|
||||
|
||||
#endif
|
@ -0,0 +1,171 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UE_SYNC_
|
||||
#define UE_SYNC_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/sync/sync.h"
|
||||
#include "liblte/phy/sync/cfo.h"
|
||||
#include "liblte/phy/ch_estimation/chest.h"
|
||||
#include "liblte/phy/phch/pbch.h"
|
||||
#include "liblte/phy/common/fft.h"
|
||||
#include "liblte/phy/agc/agc.h"
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* This object automatically manages the cell association and
|
||||
* synchronization procedure. By default, it associates with the
|
||||
* CELL whose correlation peak to average ratio is the highest.
|
||||
*
|
||||
* TODO: Associate with arbitrary CELL ID
|
||||
*
|
||||
* The main function is ue_sync_get_buffer(), which returns a pointer
|
||||
* to the aligned subframe of samples (before FFT). This function
|
||||
* should be called regularly, returning every 1 ms. It reads from the
|
||||
* USRP, aligns the samples to the subframe and performs time/freq synch.
|
||||
*
|
||||
* The function returns 0 during the cell association procedure, which includes
|
||||
* PSS/SSS synchronization, MIB decoding from the PBCH and sampling frequency
|
||||
* adjustment (according to signal bandwidth) and resynchronization.
|
||||
*
|
||||
* The function returns 1 when the signal is correctly acquired and the
|
||||
* returned buffer is aligned with the subframe.
|
||||
*
|
||||
*
|
||||
*************************************************************/
|
||||
|
||||
typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t;
|
||||
|
||||
#define SYNC_PBCH_NOF_PRB 6
|
||||
#define SYNC_PBCH_NOF_PORTS 2
|
||||
|
||||
#define TRACK_MAX_LOST 10
|
||||
#define PSS_THRESHOLD 1
|
||||
|
||||
#define NOF_MIB_DECODES 10
|
||||
|
||||
#define MEASURE_EXEC_TIME
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
sync_t s;
|
||||
|
||||
void *stream;
|
||||
double (*set_rate_callback)(void*, double);
|
||||
int (*recv_callback)(void*, void*, uint32_t);
|
||||
|
||||
ue_sync_state_t state;
|
||||
|
||||
cf_t *input_buffer;
|
||||
cf_t *receive_buffer;
|
||||
cf_t *sf_symbols;
|
||||
cf_t *ce[SYNC_PBCH_NOF_PORTS];
|
||||
|
||||
/* These count half frames (5ms) */
|
||||
uint64_t frame_ok_cnt;
|
||||
uint32_t frame_no_cnt;
|
||||
uint32_t frame_total_cnt;
|
||||
|
||||
/* this is the system frame number (SFN) */
|
||||
uint32_t frame_number;
|
||||
|
||||
lte_cell_t cell;
|
||||
uint32_t sf_idx;
|
||||
|
||||
cfo_t cfocorr;
|
||||
float cur_cfo;
|
||||
|
||||
/* Variables for PBCH decoding */
|
||||
agc_t agc;
|
||||
pbch_mib_t mib;
|
||||
lte_fft_t fft;
|
||||
chest_t chest;
|
||||
pbch_t pbch;
|
||||
bool pbch_initialized;
|
||||
uint32_t pbch_decoded;
|
||||
bool pbch_decode_always;
|
||||
bool pbch_decoder_enabled;
|
||||
uint32_t pbch_last_trial;
|
||||
|
||||
bool decode_sss_on_track;
|
||||
|
||||
uint32_t peak_idx;
|
||||
int time_offset;
|
||||
float mean_time_offset;
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
float mean_exec_time;
|
||||
#endif
|
||||
} ue_sync_t;
|
||||
|
||||
|
||||
LIBLTE_API int ue_sync_init(ue_sync_t *q,
|
||||
double (set_rate_callback)(void*, double),
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler);
|
||||
|
||||
LIBLTE_API void ue_sync_free(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API int ue_sync_get_buffer(ue_sync_t *q,
|
||||
cf_t **sf_symbols);
|
||||
|
||||
|
||||
LIBLTE_API void ue_sync_reset(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled);
|
||||
|
||||
LIBLTE_API void ue_sync_pbch_enable(ue_sync_t *q, bool enabled);
|
||||
|
||||
LIBLTE_API void ue_sync_pbch_always(ue_sync_t *q, bool enabled);
|
||||
|
||||
LIBLTE_API void ue_sync_set_threshold(ue_sync_t *q,
|
||||
float threshold);
|
||||
|
||||
LIBLTE_API ue_sync_state_t ue_sync_get_state(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API uint32_t ue_sync_get_sfidx(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API uint32_t ue_sync_get_peak_idx(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API lte_cell_t ue_sync_get_cell(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API pbch_mib_t ue_sync_get_mib(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API bool ue_sync_is_mib_decoded(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API float ue_sync_get_cfo(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API float ue_sync_get_sfo(ue_sync_t *q);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // SYNC_FRAME_
|
||||
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DECIM_H
|
||||
#define DECIM_H_
|
||||
|
||||
#include "liblte/config.h"
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
|
||||
LIBLTE_API void decim_c(cf_t *input, cf_t *output, int M, int len);
|
||||
LIBLTE_API void decim_f(float *input, float *output, int M, int len);
|
||||
|
||||
#endif // DECIM_H
|
@ -0,0 +1,79 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser 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 <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <complex.h>
|
||||
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
#include "liblte/phy/agc/agc.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
|
||||
int agc_init (agc_t *q) {
|
||||
bzero(q, sizeof(agc_t));
|
||||
q->bandwidth = AGC_DEFAULT_BW;
|
||||
q->lock = false;
|
||||
q->gain = 1.0;
|
||||
q->y_out = 1.0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void agc_free(agc_t *q) {
|
||||
bzero(q, sizeof(agc_t));
|
||||
}
|
||||
|
||||
void agc_set_bandwidth(agc_t *q, float bandwidth) {
|
||||
q->bandwidth = bandwidth;
|
||||
}
|
||||
|
||||
float agc_get_rssi(agc_t *q) {
|
||||
return 1.0/q->gain;
|
||||
}
|
||||
|
||||
void agc_lock(agc_t *q, bool enable) {
|
||||
q->lock = enable;
|
||||
}
|
||||
|
||||
void agc_push(agc_t *q, cf_t *input, cf_t *output, uint32_t len) {
|
||||
|
||||
// Apply current gain to input signal
|
||||
vec_sc_prod_cfc(input, q->gain, output, len);
|
||||
|
||||
// compute output energy estimate
|
||||
float y = sqrtf(crealf(vec_dot_prod_conj_ccc(output, output, len))/len);
|
||||
|
||||
q->y_out = (1-q->bandwidth) * q->y_out + q->bandwidth * y;
|
||||
if (!q->lock) {
|
||||
q->gain *= expf(-0.5*q->bandwidth*logf(q->y_out));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue