mirror of https://github.com/PentHertz/srsLTE.git
Improved synch. Fixed some bugs. Added ue_ul
This commit is contained in:
parent
99df252279
commit
6fe535f8a4
|
@ -65,27 +65,10 @@ LIBLTE_API double cuhd_set_rx_freq_offset(void *h,
|
||||||
double freq,
|
double freq,
|
||||||
double off);
|
double off);
|
||||||
|
|
||||||
LIBLTE_API void cuhd_get_time(void *h,
|
LIBLTE_API double cuhd_set_rx_freq_offset(void *h,
|
||||||
time_t *secs,
|
|
||||||
double *frac_secs);
|
|
||||||
|
|
||||||
LIBLTE_API double cuhd_set_tx_srate(void *h,
|
|
||||||
double freq);
|
|
||||||
|
|
||||||
LIBLTE_API void cuhd_set_tx_antenna(void *h,
|
|
||||||
char *name);
|
|
||||||
|
|
||||||
LIBLTE_API double cuhd_set_tx_gain(void *h,
|
|
||||||
double gain);
|
|
||||||
|
|
||||||
LIBLTE_API double cuhd_set_tx_freq(void *h,
|
|
||||||
double freq);
|
|
||||||
|
|
||||||
LIBLTE_API double cuhd_set_tx_freq_offset(void *h,
|
|
||||||
double freq,
|
double freq,
|
||||||
double off);
|
double off);
|
||||||
|
|
||||||
|
|
||||||
LIBLTE_API int cuhd_recv(void *h,
|
LIBLTE_API int cuhd_recv(void *h,
|
||||||
void *data,
|
void *data,
|
||||||
uint32_t nsamples,
|
uint32_t nsamples,
|
||||||
|
@ -94,22 +77,28 @@ LIBLTE_API int cuhd_recv(void *h,
|
||||||
LIBLTE_API int cuhd_recv_with_time(void *h,
|
LIBLTE_API int cuhd_recv_with_time(void *h,
|
||||||
void *data,
|
void *data,
|
||||||
uint32_t nsamples,
|
uint32_t nsamples,
|
||||||
|
bool blocking,
|
||||||
time_t *secs,
|
time_t *secs,
|
||||||
double *frac_secs);
|
double *frac_secs);
|
||||||
|
|
||||||
LIBLTE_API int cuhd_recv_timed(void *h,
|
LIBLTE_API double cuhd_set_tx_srate(void *h,
|
||||||
void *data,
|
double freq);
|
||||||
uint32_t nsamples,
|
|
||||||
time_t secs,
|
LIBLTE_API double cuhd_set_tx_gain(void *h,
|
||||||
double frac_secs);
|
double gain);
|
||||||
|
|
||||||
|
LIBLTE_API double cuhd_set_tx_freq(void *h,
|
||||||
|
double freq);
|
||||||
|
|
||||||
|
LIBLTE_API double cuhd_set_tx_freq_offset(void *h,
|
||||||
|
double freq,
|
||||||
|
double offset);
|
||||||
|
|
||||||
|
LIBLTE_API int cuhd_send(void *h,
|
||||||
|
void *data,
|
||||||
|
uint32_t nsamples,
|
||||||
|
bool blocking);
|
||||||
|
|
||||||
LIBLTE_API int cuhd_recv_timed2(void *h,
|
|
||||||
void *data,
|
|
||||||
uint32_t nsamples,
|
|
||||||
time_t secs,
|
|
||||||
double frac_secs,
|
|
||||||
bool is_start_of_burst,
|
|
||||||
bool is_end_of_burst);
|
|
||||||
|
|
||||||
LIBLTE_API int cuhd_send(void *h,
|
LIBLTE_API int cuhd_send(void *h,
|
||||||
void *data,
|
void *data,
|
||||||
|
@ -131,7 +120,6 @@ LIBLTE_API int cuhd_send_timed2(void *h,
|
||||||
bool is_start_of_burst,
|
bool is_start_of_burst,
|
||||||
bool is_end_of_burst);
|
bool is_end_of_burst);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -121,8 +121,9 @@ int cuhd_open(char *args, void **h)
|
||||||
{
|
{
|
||||||
cuhd_handler *handler = new cuhd_handler();
|
cuhd_handler *handler = new cuhd_handler();
|
||||||
std::string _args = std::string(args);
|
std::string _args = std::string(args);
|
||||||
handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=30720000");
|
handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=30720000" + ", num_recv_frames=512");
|
||||||
// "num_recv_frames=1,num_send_frames=1,recv_frame_size=15360,send_frame_size=15360");
|
|
||||||
|
// handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=50000000" + ", num_recv_frames=512");
|
||||||
handler->usrp->set_clock_source("internal");
|
handler->usrp->set_clock_source("internal");
|
||||||
|
|
||||||
#ifdef HIDE_MESSAGES
|
#ifdef HIDE_MESSAGES
|
||||||
|
@ -133,7 +134,6 @@ int cuhd_open(char *args, void **h)
|
||||||
otw = "sc16";
|
otw = "sc16";
|
||||||
cpu = "fc32";
|
cpu = "fc32";
|
||||||
uhd::stream_args_t stream_args(cpu, otw);
|
uhd::stream_args_t stream_args(cpu, otw);
|
||||||
stream_args.args["spp"] = "120"; // Set the property
|
|
||||||
handler->rx_stream = handler->usrp->get_rx_stream(stream_args);
|
handler->rx_stream = handler->usrp->get_rx_stream(stream_args);
|
||||||
handler->tx_stream = handler->usrp->get_tx_stream(stream_args);
|
handler->tx_stream = handler->usrp->get_tx_stream(stream_args);
|
||||||
|
|
||||||
|
@ -154,14 +154,6 @@ double cuhd_set_rx_srate(void *h, double freq)
|
||||||
{
|
{
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
||||||
handler->usrp->set_rx_rate(freq);
|
handler->usrp->set_rx_rate(freq);
|
||||||
|
|
||||||
double ret = handler->usrp->get_rx_rate();
|
|
||||||
/*
|
|
||||||
if ((int) ret != (int) freq) {
|
|
||||||
handler->usrp->set_master_clock_rate(freq);
|
|
||||||
handler->usrp->set_rx_rate(freq);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return freq;
|
return freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,9 +171,9 @@ double cuhd_set_rx_freq(void *h, double freq)
|
||||||
return freq;
|
return freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
double cuhd_set_rx_freq_offset(void *h, double freq, double off) {
|
double cuhd_set_rx_freq_offset(void *h, double freq, double off) {
|
||||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
||||||
handler->usrp->set_rx_freq(uhd::tune_request_t(freq,off));
|
handler->usrp->set_rx_freq(uhd::tune_request_t(freq, off));
|
||||||
return handler->usrp->get_rx_freq();
|
return handler->usrp->get_rx_freq();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,59 +209,41 @@ int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking)
|
||||||
int cuhd_recv_with_time(void *h,
|
int cuhd_recv_with_time(void *h,
|
||||||
void *data,
|
void *data,
|
||||||
uint32_t nsamples,
|
uint32_t nsamples,
|
||||||
|
bool blocking,
|
||||||
time_t *secs,
|
time_t *secs,
|
||||||
double *frac_secs)
|
double *frac_secs)
|
||||||
{
|
{
|
||||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
||||||
uhd::rx_metadata_t md;
|
uhd::rx_metadata_t md;
|
||||||
int p = handler->rx_stream->recv(data, nsamples, md, 0.0);
|
uint32_t nof_packets = 0;
|
||||||
|
int ret = -1;
|
||||||
|
if (blocking) {
|
||||||
|
int n = 0, p;
|
||||||
|
complex_t *data_c = (complex_t *) data;
|
||||||
|
do {
|
||||||
|
p = handler->rx_stream->recv(&data_c[n], nsamples - n, md);
|
||||||
|
if (p == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n += p;
|
||||||
|
#ifdef METADATA_VERBOSE
|
||||||
|
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) {
|
||||||
|
std::cout << "\nError code: " << md.to_pp_string() << "\n\n";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
nof_packets++;
|
||||||
|
} while (n < nsamples &&
|
||||||
|
md.error_code == uhd::rx_metadata_t::ERROR_CODE_NONE &&
|
||||||
|
nof_packets < 10);
|
||||||
|
ret = nsamples;
|
||||||
|
} else {
|
||||||
|
ret = handler->rx_stream->recv(data, nsamples, md, 0.0);
|
||||||
|
}
|
||||||
if (secs && frac_secs) {
|
if (secs && frac_secs) {
|
||||||
*secs = md.time_spec.get_full_secs();
|
*secs = md.time_spec.get_full_secs();
|
||||||
*frac_secs = md.time_spec.get_frac_secs();
|
*frac_secs = md.time_spec.get_frac_secs();
|
||||||
}
|
}
|
||||||
return p;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
int cuhd_recv_timed(void *h,
|
|
||||||
void *data,
|
|
||||||
uint32_t nsamples,
|
|
||||||
time_t secs,
|
|
||||||
double frac_secs)
|
|
||||||
{
|
|
||||||
return cuhd_recv_timed2(h, data, nsamples, secs, frac_secs, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int cuhd_recv_timed2(void *h,
|
|
||||||
void *data,
|
|
||||||
uint32_t nsamples,
|
|
||||||
time_t secs,
|
|
||||||
double frac_secs,
|
|
||||||
bool is_start_of_burst,
|
|
||||||
bool is_end_of_burst)
|
|
||||||
{
|
|
||||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
|
||||||
uhd::rx_metadata_t md;
|
|
||||||
md.start_of_burst = is_start_of_burst;
|
|
||||||
md.end_of_burst = is_end_of_burst;
|
|
||||||
md.has_time_spec = true;
|
|
||||||
md.time_spec = uhd::time_spec_t(secs, frac_secs);
|
|
||||||
|
|
||||||
return handler->rx_stream->recv(data, nsamples, md);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuhd_get_time(void *h, time_t *secs, double *frac_secs)
|
|
||||||
{
|
|
||||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
|
||||||
uhd::time_spec_t now = handler->usrp->get_time_now();
|
|
||||||
*secs = now.get_full_secs();
|
|
||||||
*frac_secs = now.get_frac_secs();
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuhd_set_tx_antenna(void *h, char *name)
|
|
||||||
{
|
|
||||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
|
||||||
handler->usrp->set_tx_antenna(name, 0);
|
|
||||||
}
|
}
|
||||||
double cuhd_set_tx_gain(void *h, double gain)
|
double cuhd_set_tx_gain(void *h, double gain)
|
||||||
{
|
{
|
||||||
|
@ -292,7 +266,8 @@ double cuhd_set_tx_freq(void *h, double freq)
|
||||||
return handler->usrp->get_tx_freq();
|
return handler->usrp->get_tx_freq();
|
||||||
}
|
}
|
||||||
|
|
||||||
double cuhd_set_tx_freq_offset(void *h, double freq, double off) {
|
|
||||||
|
double cuhd_set_tx_freq_offset(void *h, double freq, double off) {
|
||||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
||||||
handler->usrp->set_tx_freq(uhd::tune_request_t(freq, off));
|
handler->usrp->set_tx_freq(uhd::tune_request_t(freq, off));
|
||||||
return handler->usrp->get_tx_freq();
|
return handler->usrp->get_tx_freq();
|
||||||
|
@ -319,6 +294,7 @@ int cuhd_send(void *h, void *data, uint32_t nsamples, bool blocking)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int cuhd_send_timed(void *h,
|
int cuhd_send_timed(void *h,
|
||||||
void *data,
|
void *data,
|
||||||
int nsamples,
|
int nsamples,
|
||||||
|
|
|
@ -125,8 +125,6 @@ int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples, timestamp_t *q) {
|
||||||
return cuhd_recv(h, data, nsamples, 1);
|
return cuhd_recv(h, data, nsamples, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern float mean_exec_time;
|
|
||||||
|
|
||||||
enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state;
|
enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state;
|
||||||
|
|
||||||
#define MAX_SINFO 10
|
#define MAX_SINFO 10
|
||||||
|
@ -261,15 +259,15 @@ int main(int argc, char **argv) {
|
||||||
case DECODE_SIB:
|
case DECODE_SIB:
|
||||||
/* We are looking for SI Blocks, search only in appropiate places */
|
/* We are looking for SI Blocks, search only in appropiate places */
|
||||||
if ((ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
|
if ((ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
|
||||||
n = ue_dl_decode_sib(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync), SIRNTI,
|
n = ue_dl_decode_rnti_rv(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync), SIRNTI,
|
||||||
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
|
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
|
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
|
||||||
return -1;
|
return -1;
|
||||||
} else if (n == 0) {
|
} else if (n == 0) {
|
||||||
printf("CFO: %+6.4f KHz, SFO: %+6.4f Khz, ExecTime: %5.1f us, NOI: %.2f, PDCCH-Det: %.3f\r",
|
printf("CFO: %+6.4f KHz, SFO: %+6.4f Khz, NOI: %.2f, PDCCH-Det: %.3f\r",
|
||||||
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
|
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
|
||||||
mean_exec_time, sch_average_noi(&ue_dl.pdsch.dl_sch),
|
sch_average_noi(&ue_dl.pdsch.dl_sch),
|
||||||
(float) ue_dl.nof_pdcch_detected/nof_trials);
|
(float) ue_dl.nof_pdcch_detected/nof_trials);
|
||||||
nof_trials++;
|
nof_trials++;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -83,6 +83,7 @@ typedef struct {
|
||||||
uint32_t file_nof_prb;
|
uint32_t file_nof_prb;
|
||||||
char *uhd_args;
|
char *uhd_args;
|
||||||
float uhd_freq;
|
float uhd_freq;
|
||||||
|
float uhd_freq_offset;
|
||||||
float uhd_gain;
|
float uhd_gain;
|
||||||
int net_port;
|
int net_port;
|
||||||
char *net_address;
|
char *net_address;
|
||||||
|
@ -98,6 +99,7 @@ void args_default(prog_args_t *args) {
|
||||||
args->file_nof_prb = 6;
|
args->file_nof_prb = 6;
|
||||||
args->uhd_args = "";
|
args->uhd_args = "";
|
||||||
args->uhd_freq = -1.0;
|
args->uhd_freq = -1.0;
|
||||||
|
args->uhd_freq = 8000000.0;
|
||||||
args->uhd_gain = 60.0;
|
args->uhd_gain = 60.0;
|
||||||
args->net_port = -1;
|
args->net_port = -1;
|
||||||
args->net_address = "127.0.0.1";
|
args->net_address = "127.0.0.1";
|
||||||
|
@ -110,6 +112,7 @@ void usage(prog_args_t *args, char *prog) {
|
||||||
#ifndef DISABLE_UHD
|
#ifndef DISABLE_UHD
|
||||||
printf("\t-a UHD args [Default %s]\n", args->uhd_args);
|
printf("\t-a UHD args [Default %s]\n", args->uhd_args);
|
||||||
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->uhd_gain);
|
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->uhd_gain);
|
||||||
|
printf("\t-o UHD RX freq offset [Default %.1f MHz]\n", args->uhd_freq_offset/1000000);
|
||||||
#else
|
#else
|
||||||
printf("\t UHD is disabled. CUHD library not available\n");
|
printf("\t UHD is disabled. CUHD library not available\n");
|
||||||
#endif
|
#endif
|
||||||
|
@ -133,7 +136,7 @@ void usage(prog_args_t *args, char *prog) {
|
||||||
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, "aglipdnvrfuUsS")) != -1) {
|
while ((opt = getopt(argc, argv, "aoglipdnvrfuUsS")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'i':
|
case 'i':
|
||||||
args->input_file_name = argv[optind];
|
args->input_file_name = argv[optind];
|
||||||
|
@ -147,6 +150,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
|
||||||
case 'g':
|
case 'g':
|
||||||
args->uhd_gain = atof(argv[optind]);
|
args->uhd_gain = atof(argv[optind]);
|
||||||
break;
|
break;
|
||||||
|
case 'o':
|
||||||
|
args->uhd_freq_offset = atof(argv[optind]);
|
||||||
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
args->uhd_freq = atof(argv[optind]);
|
args->uhd_freq = atof(argv[optind]);
|
||||||
break;
|
break;
|
||||||
|
@ -261,7 +267,7 @@ int main(int argc, char **argv) {
|
||||||
cuhd_set_rx_gain(uhd, prog_args.uhd_gain);
|
cuhd_set_rx_gain(uhd, prog_args.uhd_gain);
|
||||||
|
|
||||||
/* set receiver frequency */
|
/* set receiver frequency */
|
||||||
cuhd_set_rx_freq(uhd, (double) prog_args.uhd_freq);
|
cuhd_set_rx_freq_offset(uhd, (double) prog_args.uhd_freq, prog_args.uhd_freq_offset);
|
||||||
cuhd_rx_wait_lo_locked(uhd);
|
cuhd_rx_wait_lo_locked(uhd);
|
||||||
printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000);
|
printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000);
|
||||||
|
|
||||||
|
@ -394,7 +400,7 @@ int main(int argc, char **argv) {
|
||||||
if (prog_args.rnti != SIRNTI) {
|
if (prog_args.rnti != SIRNTI) {
|
||||||
n = ue_dl_decode(&ue_dl, sf_buffer, data_packed, ue_sync_get_sfidx(&ue_sync));
|
n = ue_dl_decode(&ue_dl, sf_buffer, data_packed, ue_sync_get_sfidx(&ue_sync));
|
||||||
} else {
|
} else {
|
||||||
n = ue_dl_decode_sib(&ue_dl, sf_buffer, data_packed, ue_sync_get_sfidx(&ue_sync), SIRNTI,
|
n = ue_dl_decode_rnti_rv(&ue_dl, sf_buffer, data_packed, ue_sync_get_sfidx(&ue_sync), SIRNTI,
|
||||||
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
|
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
|
||||||
}
|
}
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
|
|
|
@ -151,7 +151,7 @@ void sig_int_handler(int signo)
|
||||||
|
|
||||||
int cuhd_recv_wrapper_timed(void *h, void *data, uint32_t nsamples, timestamp_t *uhd_time) {
|
int cuhd_recv_wrapper_timed(void *h, void *data, uint32_t nsamples, timestamp_t *uhd_time) {
|
||||||
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
|
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
|
||||||
return cuhd_recv_with_time(h, data, nsamples, &uhd_time->full_secs, &uhd_time->frac_secs);
|
return cuhd_recv_with_time(h, data, nsamples, true, &uhd_time->full_secs, &uhd_time->frac_secs);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern float mean_exec_time;
|
extern float mean_exec_time;
|
||||||
|
@ -314,7 +314,7 @@ int main(int argc, char **argv) {
|
||||||
uint32_t rar_window_start = 0, rar_trials = 0, rar_window_stop = 0;
|
uint32_t rar_window_start = 0, rar_trials = 0, rar_window_stop = 0;
|
||||||
timestamp_t uhd_time;
|
timestamp_t uhd_time;
|
||||||
timestamp_t next_tx_time;
|
timestamp_t next_tx_time;
|
||||||
const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6};
|
const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6, 0x00, 0x00, 0x00};
|
||||||
uint8_t data[100];
|
uint8_t data[100];
|
||||||
|
|
||||||
parse_args(&prog_args, argc, argv);
|
parse_args(&prog_args, argc, argv);
|
||||||
|
@ -327,7 +327,7 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
/* Set receiver gain */
|
/* Set receiver gain */
|
||||||
cuhd_set_rx_gain(uhd, prog_args.uhd_gain);
|
cuhd_set_rx_gain(uhd, prog_args.uhd_gain);
|
||||||
cuhd_set_tx_gain(uhd, prog_args.uhd_gain);
|
cuhd_set_tx_gain(uhd, prog_args.uhd_gain*2);
|
||||||
|
|
||||||
//cuhd_set_tx_antenna(uhd, "TX/RX");
|
//cuhd_set_tx_antenna(uhd, "TX/RX");
|
||||||
|
|
||||||
|
@ -336,7 +336,6 @@ int main(int argc, char **argv) {
|
||||||
cuhd_rx_wait_lo_locked(uhd);
|
cuhd_rx_wait_lo_locked(uhd);
|
||||||
printf("Tunning RX receiver to %.3f MHz\n", (double ) prog_args.uhd_rx_freq/1000000);
|
printf("Tunning RX receiver to %.3f MHz\n", (double ) prog_args.uhd_rx_freq/1000000);
|
||||||
|
|
||||||
cuhd_set_tx_freq(uhd, prog_args.uhd_tx_freq);
|
|
||||||
cuhd_set_tx_freq_offset(uhd, prog_args.uhd_tx_freq, prog_args.uhd_tx_freq_offset);
|
cuhd_set_tx_freq_offset(uhd, prog_args.uhd_tx_freq, prog_args.uhd_tx_freq_offset);
|
||||||
printf("Tunning TX receiver to %.3f MHz\n", (double ) prog_args.uhd_tx_freq/1000000);
|
printf("Tunning TX receiver to %.3f MHz\n", (double ) prog_args.uhd_tx_freq/1000000);
|
||||||
|
|
||||||
|
@ -383,24 +382,15 @@ int main(int argc, char **argv) {
|
||||||
generate_prach_sequences();
|
generate_prach_sequences();
|
||||||
|
|
||||||
refsignal_ul_t drms;
|
refsignal_ul_t drms;
|
||||||
refsignal_drms_pusch_cfg_t pusch_cfg;
|
|
||||||
bzero(&pusch_cfg, sizeof(refsignal_drms_pusch_cfg_t));
|
|
||||||
pusch_cfg.nof_prb = 3;
|
|
||||||
pusch_cfg.beta_pusch = 1.0;
|
|
||||||
if (refsignal_ul_init(&drms, cell)) {
|
if (refsignal_ul_init(&drms, cell)) {
|
||||||
fprintf(stderr, "Error initiating refsignal_ul\n");
|
fprintf(stderr, "Error initiating refsignal_ul\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
cf_t *drms_signal = vec_malloc(2*RE_X_RB*pusch_cfg.nof_prb*sizeof(cf_t));
|
cf_t *drms_signal = vec_malloc(2*RE_X_RB*cell.nof_prb*sizeof(cf_t));
|
||||||
if (!drms_signal) {
|
if (!drms_signal) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
for (uint32_t i=0;i<2;i++) {
|
|
||||||
if (refsignal_dmrs_pusch_gen(&drms, &pusch_cfg, 2*4+i, &drms_signal[i*RE_X_RB*pusch_cfg.nof_prb])) {
|
|
||||||
fprintf(stderr, "Error generating PUSCH DRMS signals\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pusch_init(&pusch, cell)) {
|
if (pusch_init(&pusch, cell)) {
|
||||||
fprintf(stderr, "Error initiating PUSCH\n");
|
fprintf(stderr, "Error initiating PUSCH\n");
|
||||||
|
@ -438,7 +428,7 @@ int main(int argc, char **argv) {
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ue_dl_init(&ue_dl, cell)) { // This is the User RNTI
|
if (ue_dl_init(&ue_dl, cell)) {
|
||||||
fprintf(stderr, "Error initiating UE downlink processing module\n");
|
fprintf(stderr, "Error initiating UE downlink processing module\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
@ -503,7 +493,7 @@ int main(int argc, char **argv) {
|
||||||
if ((sfn == rar_window_start && ue_sync_get_sfidx(&ue_sync) > 3) || sfn > rar_window_start) {
|
if ((sfn == rar_window_start && ue_sync_get_sfidx(&ue_sync) > 3) || sfn > rar_window_start) {
|
||||||
gettimeofday(&tdata[1], NULL);
|
gettimeofday(&tdata[1], NULL);
|
||||||
printf("Looking for RAR in sfn: %d sf_idx: %d\n", sfn, ue_sync_get_sfidx(&ue_sync));
|
printf("Looking for RAR in sfn: %d sf_idx: %d\n", sfn, ue_sync_get_sfidx(&ue_sync));
|
||||||
n = ue_dl_decode_rnti(&ue_dl, sf_buffer, data_rx, ra_rnti, ue_sync_get_sfidx(&ue_sync));
|
n = ue_dl_decode_rnti(&ue_dl, sf_buffer, data_rx, ue_sync_get_sfidx(&ue_sync), ra_rnti);
|
||||||
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) {
|
||||||
|
@ -522,7 +512,8 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
ra_ul_alloc(&prb_alloc, &ra_pusch, 0, cell.nof_prb);
|
ra_ul_alloc(&prb_alloc, &ra_pusch, 0, cell.nof_prb);
|
||||||
|
|
||||||
if (harq_setup_ul(&pusch_harq, ra_pusch.mcs, 0, (ue_sync_get_sfidx(&ue_sync)+6)%10, &prb_alloc)) {
|
uint32_t ul_sf_idx = (ue_sync_get_sfidx(&ue_sync)+6)%10;
|
||||||
|
if (harq_setup_ul(&pusch_harq, ra_pusch.mcs, 0, ul_sf_idx, &prb_alloc)) {
|
||||||
fprintf(stderr, "Error configuring HARQ process\n");
|
fprintf(stderr, "Error configuring HARQ process\n");
|
||||||
exit(-1);;
|
exit(-1);;
|
||||||
}
|
}
|
||||||
|
@ -532,12 +523,28 @@ int main(int argc, char **argv) {
|
||||||
fprintf(stderr, "Error encoding TB\n");
|
fprintf(stderr, "Error encoding TB\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refsignal_drms_pusch_cfg_t pusch_cfg;
|
||||||
|
bzero(&pusch_cfg, sizeof(refsignal_drms_pusch_cfg_t));
|
||||||
|
pusch_cfg.nof_prb = prb_alloc.L_prb;
|
||||||
|
pusch_cfg.beta_pusch = 1.0;
|
||||||
|
|
||||||
for (uint32_t i=0;i<2;i++) {
|
for (uint32_t i=0;i<2;i++) {
|
||||||
refsignal_drms_pusch_put(&drms, &pusch_cfg, &drms_signal[i*RE_X_RB*pusch_cfg.nof_prb], i, prb_alloc.n_prb[i], sf_symbols);
|
if (refsignal_dmrs_pusch_gen(&drms, &pusch_cfg, 2*ul_sf_idx+i, drms_signal)) {
|
||||||
|
fprintf(stderr, "Error generating PUSCH DRMS signals\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
refsignal_drms_pusch_put(&drms, &pusch_cfg, drms_signal, i,
|
||||||
|
prb_alloc.n_prb[i], sf_symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
lte_ifft_run_sf(&fft, sf_symbols, ul_signal);
|
lte_ifft_run_sf(&fft, sf_symbols, ul_signal);
|
||||||
|
|
||||||
|
cfo_correct(&ue_sync.sfind.cfocorr,
|
||||||
|
ul_signal, ul_signal,
|
||||||
|
sync_get_cfo(&ue_sync.strack) / lte_symbol_sz(cell.nof_prb));
|
||||||
|
|
||||||
|
|
||||||
gettimeofday(&tdata[2], NULL);
|
gettimeofday(&tdata[2], NULL);
|
||||||
get_time_interval(tdata);
|
get_time_interval(tdata);
|
||||||
printf("time exec UL: %d\n",tdata[0].tv_usec);
|
printf("time exec UL: %d\n",tdata[0].tv_usec);
|
||||||
|
@ -551,16 +558,16 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
ue_sync_get_last_timestamp(&ue_sync, &uhd_time);
|
ue_sync_get_last_timestamp(&ue_sync, &uhd_time);
|
||||||
|
|
||||||
float time_adv_sec = ((float) rar_msg.timing_adv_cmd - 31 - 25) * 16 /(15000*2048);
|
//float time_adv_sec = ((float) rar_msg.timing_adv_cmd - 31 - 25) * 16 /(15000*2048);
|
||||||
|
float time_adv_sec = ((float) rar_msg.timing_adv_cmd - 31) * 16 /(15000*2048);
|
||||||
vec_sc_prod_cfc(ul_signal, 2, ul_signal, SF_LEN_PRB(cell.nof_prb));
|
vec_sc_prod_cfc(ul_signal, 2, ul_signal, SF_LEN_PRB(cell.nof_prb));
|
||||||
|
|
||||||
vec_fprint_c(stdout, sf_symbols, 300);
|
|
||||||
|
|
||||||
timestamp_copy(&next_tx_time, &uhd_time);
|
timestamp_copy(&next_tx_time, &uhd_time);
|
||||||
timestamp_add(&next_tx_time, 0, 0.006 + time_adv_sec); // send after 6 sub-frames (6 ms)
|
timestamp_add(&next_tx_time, 0, 0.006 + time_adv_sec); // send after 6 sub-frames (6 ms)
|
||||||
printf("Send %d samples PUSCH sfn: %d. Last frame time = %.6f, send PUSCH time = %.6f TA: %f\n",
|
printf("Send %d samples PUSCH sfn: %d. Last frame time = %.6f"
|
||||||
SF_LEN_PRB(cell.nof_prb), sfn, timestamp_real(&uhd_time), timestamp_real(&next_tx_time), time_adv_sec);
|
"send PUSCH time = %.6f TA: %.1f us\n",
|
||||||
|
SF_LEN_PRB(cell.nof_prb), sfn, timestamp_real(&uhd_time),
|
||||||
|
timestamp_real(&next_tx_time), time_adv_sec*1000000);
|
||||||
cuhd_send_timed(uhd, ul_signal, SF_LEN_PRB(cell.nof_prb),
|
cuhd_send_timed(uhd, ul_signal, SF_LEN_PRB(cell.nof_prb),
|
||||||
next_tx_time.full_secs, next_tx_time.frac_secs);
|
next_tx_time.full_secs, next_tx_time.frac_secs);
|
||||||
|
|
||||||
|
@ -569,7 +576,7 @@ int main(int argc, char **argv) {
|
||||||
if (sfn >= rar_window_stop) {
|
if (sfn >= rar_window_stop) {
|
||||||
state = SEND_PRACH;
|
state = SEND_PRACH;
|
||||||
rar_trials++;
|
rar_trials++;
|
||||||
if (rar_trials >= 10) {
|
if (rar_trials >= 4) {
|
||||||
go_exit = 1;
|
go_exit = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ typedef struct {
|
||||||
cf_t *tmp_noise;
|
cf_t *tmp_noise;
|
||||||
cf_t *tmp_freqavg;
|
cf_t *tmp_freqavg;
|
||||||
cf_t *tmp_timeavg[CHEST_MAX_FILTER_TIME_LEN];
|
cf_t *tmp_timeavg[CHEST_MAX_FILTER_TIME_LEN];
|
||||||
|
cf_t *tmp_timeavg_mult;
|
||||||
|
|
||||||
interp_linvec_t interp_linvec;
|
interp_linvec_t interp_linvec;
|
||||||
interp_lin_t interp_lin;
|
interp_lin_t interp_lin;
|
||||||
|
|
|
@ -119,12 +119,13 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
|
||||||
|
|
||||||
typedef _Complex float cf_t;
|
typedef _Complex float cf_t;
|
||||||
|
|
||||||
typedef enum LIBLTE_API { PHICH_NORM, PHICH_EXT} phich_length_t;
|
typedef enum LIBLTE_API { PHICH_NORM = 0, PHICH_EXT} phich_length_t;
|
||||||
typedef enum LIBLTE_API { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
|
typedef enum LIBLTE_API { R_1_6 = 0, R_1_2, R_1, R_2} phich_resources_t;
|
||||||
|
|
||||||
typedef struct LIBLTE_API {
|
typedef struct LIBLTE_API {
|
||||||
uint32_t nof_prb;
|
uint32_t nof_prb;
|
||||||
uint32_t nof_ports;
|
uint32_t nof_ports;
|
||||||
|
uint32_t bw_idx;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
lte_cp_t cp;
|
lte_cp_t cp;
|
||||||
phich_length_t phich_length;
|
phich_length_t phich_length;
|
||||||
|
|
|
@ -80,14 +80,11 @@ LIBLTE_API int dci_msg_to_ra_dl(dci_msg_t *msg,
|
||||||
uint32_t cfi,
|
uint32_t cfi,
|
||||||
ra_pdsch_t *ra_dl);
|
ra_pdsch_t *ra_dl);
|
||||||
|
|
||||||
/* TODO
|
|
||||||
LIBLTE_API int dci_msg_to_ra_ul(dci_msg_t *msg,
|
LIBLTE_API int dci_msg_to_ra_ul(dci_msg_t *msg,
|
||||||
uint16_t msg_rnti,
|
|
||||||
uint16_t c_rnti,
|
|
||||||
lte_cell_t cell,
|
lte_cell_t cell,
|
||||||
uint32_t cfi,
|
uint32_t n_rb_ho,
|
||||||
ra_pusch_t *ra_ul);
|
ra_pusch_t *ra_ul);
|
||||||
*/
|
|
||||||
LIBLTE_API dci_format_t dci_format_from_string(char *str);
|
LIBLTE_API dci_format_t dci_format_from_string(char *str);
|
||||||
|
|
||||||
LIBLTE_API char* dci_format_string(dci_format_t format);
|
LIBLTE_API char* dci_format_string(dci_format_t format);
|
||||||
|
|
|
@ -51,8 +51,6 @@ typedef struct LIBLTE_API {
|
||||||
ra_ul_alloc_t ul_alloc;
|
ra_ul_alloc_t ul_alloc;
|
||||||
lte_cell_t cell;
|
lte_cell_t cell;
|
||||||
|
|
||||||
ra_ul_hopping_t ul_hopping;
|
|
||||||
|
|
||||||
uint32_t nof_re; // Number of RE per subframe
|
uint32_t nof_re; // Number of RE per subframe
|
||||||
uint32_t nof_bits; // Number of bits per subframe
|
uint32_t nof_bits; // Number of bits per subframe
|
||||||
uint32_t nof_symb; // Number of symbols per subframe
|
uint32_t nof_symb; // Number of symbols per subframe
|
||||||
|
|
|
@ -45,10 +45,24 @@
|
||||||
|
|
||||||
typedef _Complex float cf_t;
|
typedef _Complex float cf_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum {
|
||||||
|
hop_mode_inter_sf = 1,
|
||||||
|
hop_mode_intra_sf = 0
|
||||||
|
} hop_mode;
|
||||||
|
uint32_t current_tx_nb;
|
||||||
|
uint32_t hopping_offset;
|
||||||
|
uint32_t n_sb;
|
||||||
|
} pusch_hopping_cfg_t;
|
||||||
|
|
||||||
|
|
||||||
/* PUSCH object */
|
/* PUSCH object */
|
||||||
typedef struct LIBLTE_API {
|
typedef struct LIBLTE_API {
|
||||||
lte_cell_t cell;
|
lte_cell_t cell;
|
||||||
|
|
||||||
|
pusch_hopping_cfg_t hopping_cfg;
|
||||||
|
|
||||||
uint32_t max_re;
|
uint32_t max_re;
|
||||||
bool rnti_is_set;
|
bool rnti_is_set;
|
||||||
uint16_t rnti;
|
uint16_t rnti;
|
||||||
|
@ -77,13 +91,14 @@ typedef struct LIBLTE_API {
|
||||||
}pusch_t;
|
}pusch_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LIBLTE_API int pusch_init(pusch_t *q,
|
LIBLTE_API int pusch_init(pusch_t *q,
|
||||||
lte_cell_t cell);
|
lte_cell_t cell);
|
||||||
|
|
||||||
LIBLTE_API void pusch_free(pusch_t *q);
|
LIBLTE_API void pusch_free(pusch_t *q);
|
||||||
|
|
||||||
|
LIBLTE_API void pusch_set_hopping_cfg(pusch_t *q,
|
||||||
|
pusch_hopping_cfg_t *cfg);
|
||||||
|
|
||||||
LIBLTE_API int pusch_set_rnti(pusch_t *q,
|
LIBLTE_API int pusch_set_rnti(pusch_t *q,
|
||||||
uint16_t rnti);
|
uint16_t rnti);
|
||||||
|
|
||||||
|
|
|
@ -84,20 +84,11 @@ typedef struct LIBLTE_API {
|
||||||
|
|
||||||
typedef struct LIBLTE_API {
|
typedef struct LIBLTE_API {
|
||||||
uint32_t n_prb[2];
|
uint32_t n_prb[2];
|
||||||
|
uint32_t n_prb_tilde[2];
|
||||||
uint32_t L_prb;
|
uint32_t L_prb;
|
||||||
uint32_t freq_hopping;
|
uint32_t freq_hopping;
|
||||||
} ra_ul_alloc_t;
|
} ra_ul_alloc_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
enum {
|
|
||||||
hop_mode_inter_sf = 1,
|
|
||||||
hop_mode_intra_sf = 0
|
|
||||||
} hop_mode;
|
|
||||||
uint32_t current_tx_nb;
|
|
||||||
uint32_t hopping_offset;
|
|
||||||
uint32_t n_sb;
|
|
||||||
} ra_ul_hopping_t;
|
|
||||||
|
|
||||||
typedef struct LIBLTE_API {
|
typedef struct LIBLTE_API {
|
||||||
uint16_t rnti;
|
uint16_t rnti;
|
||||||
ra_type_t alloc_type;
|
ra_type_t alloc_type;
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
#include "liblte/phy/ue/ue_mib.h"
|
#include "liblte/phy/ue/ue_mib.h"
|
||||||
#include "liblte/phy/ue/ue_cell_search.h"
|
#include "liblte/phy/ue/ue_cell_search.h"
|
||||||
#include "liblte/phy/ue/ue_dl.h"
|
#include "liblte/phy/ue/ue_dl.h"
|
||||||
|
#include "liblte/phy/ue/ue_ul.h"
|
||||||
|
|
||||||
#include "liblte/phy/scrambling/scrambling.h"
|
#include "liblte/phy/scrambling/scrambling.h"
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
#include "liblte/phy/common/phy_common.h"
|
#include "liblte/phy/common/phy_common.h"
|
||||||
|
|
||||||
#include "liblte/phy/phch/dci.h"
|
#include "liblte/phy/phch/dci.h"
|
||||||
#include "liblte/phy/phch/pbch.h"
|
|
||||||
#include "liblte/phy/phch/pcfich.h"
|
#include "liblte/phy/phch/pcfich.h"
|
||||||
#include "liblte/phy/phch/pdcch.h"
|
#include "liblte/phy/phch/pdcch.h"
|
||||||
#include "liblte/phy/phch/pdsch.h"
|
#include "liblte/phy/phch/pdsch.h"
|
||||||
|
@ -57,7 +56,6 @@
|
||||||
#define NOF_HARQ_PROCESSES 8
|
#define NOF_HARQ_PROCESSES 8
|
||||||
|
|
||||||
typedef struct LIBLTE_API {
|
typedef struct LIBLTE_API {
|
||||||
pbch_t pbch;
|
|
||||||
pcfich_t pcfich;
|
pcfich_t pcfich;
|
||||||
pdcch_t pdcch;
|
pdcch_t pdcch;
|
||||||
pdsch_t pdsch;
|
pdsch_t pdsch;
|
||||||
|
@ -66,6 +64,8 @@ typedef struct LIBLTE_API {
|
||||||
lte_fft_t fft;
|
lte_fft_t fft;
|
||||||
chest_dl_t chest;
|
chest_dl_t chest;
|
||||||
|
|
||||||
|
ra_pdsch_t ra_dl;
|
||||||
|
|
||||||
lte_cell_t cell;
|
lte_cell_t cell;
|
||||||
|
|
||||||
cf_t *sf_symbols;
|
cf_t *sf_symbols;
|
||||||
|
@ -84,6 +84,25 @@ LIBLTE_API int ue_dl_init(ue_dl_t *q,
|
||||||
|
|
||||||
LIBLTE_API void ue_dl_free(ue_dl_t *q);
|
LIBLTE_API void ue_dl_free(ue_dl_t *q);
|
||||||
|
|
||||||
|
LIBLTE_API int ue_dl_decode_fft_estimate(ue_dl_t *q,
|
||||||
|
cf_t *input,
|
||||||
|
uint32_t sf_idx,
|
||||||
|
uint32_t *cfi);
|
||||||
|
|
||||||
|
LIBLTE_API int ue_dl_decode_rnti_rv_packet(ue_dl_t *q,
|
||||||
|
dci_msg_t *dci_msg,
|
||||||
|
uint8_t *data,
|
||||||
|
uint32_t cfi,
|
||||||
|
uint32_t sf_idx,
|
||||||
|
uint16_t rnti,
|
||||||
|
uint32_t rvidx);
|
||||||
|
|
||||||
|
LIBLTE_API int ue_dl_find_ul_dci(ue_dl_t *q,
|
||||||
|
dci_msg_t *dci_msg,
|
||||||
|
uint32_t cfi,
|
||||||
|
uint32_t sf_idx,
|
||||||
|
uint16_t rnti);
|
||||||
|
|
||||||
LIBLTE_API int ue_dl_decode(ue_dl_t * q,
|
LIBLTE_API int ue_dl_decode(ue_dl_t * q,
|
||||||
cf_t *input,
|
cf_t *input,
|
||||||
uint8_t *data,
|
uint8_t *data,
|
||||||
|
@ -92,15 +111,15 @@ LIBLTE_API int ue_dl_decode(ue_dl_t * q,
|
||||||
LIBLTE_API int ue_dl_decode_rnti(ue_dl_t * q,
|
LIBLTE_API int ue_dl_decode_rnti(ue_dl_t * q,
|
||||||
cf_t *input,
|
cf_t *input,
|
||||||
uint8_t *data,
|
uint8_t *data,
|
||||||
uint16_t rnti,
|
uint32_t sf_idx,
|
||||||
uint32_t sf_idx);
|
uint16_t rnti);
|
||||||
|
|
||||||
LIBLTE_API int ue_dl_decode_sib(ue_dl_t * q,
|
LIBLTE_API int ue_dl_decode_rnti_rv(ue_dl_t * q,
|
||||||
cf_t *input,
|
cf_t *input,
|
||||||
uint8_t * data,
|
uint8_t * data,
|
||||||
uint32_t sf_idx,
|
uint32_t sf_idx,
|
||||||
uint16_t rnti,
|
uint16_t rnti,
|
||||||
uint32_t rvidx);
|
uint32_t rvidx);
|
||||||
|
|
||||||
LIBLTE_API void ue_dl_reset(ue_dl_t *q);
|
LIBLTE_API void ue_dl_reset(ue_dl_t *q);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 UEUL_H
|
||||||
|
#define UEUL_H
|
||||||
|
|
||||||
|
/*******************************************************
|
||||||
|
*
|
||||||
|
* This module is a frontend to all the data and control channels processing
|
||||||
|
* modules.
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "liblte/phy/ch_estimation/chest_dl.h"
|
||||||
|
#include "liblte/phy/common/fft.h"
|
||||||
|
#include "liblte/phy/common/phy_common.h"
|
||||||
|
#include "liblte/phy/ch_estimation/refsignal_ul.h"
|
||||||
|
#include "liblte/phy/phch/pusch.h"
|
||||||
|
#include "liblte/phy/phch/ra.h"
|
||||||
|
#include "liblte/phy/sync/cfo.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 {
|
||||||
|
lte_fft_t fft;
|
||||||
|
cfo_t cfo;
|
||||||
|
lte_cell_t cell;
|
||||||
|
|
||||||
|
float current_cfo;
|
||||||
|
|
||||||
|
refsignal_drms_pusch_cfg_t pusch_drms_cfg;
|
||||||
|
|
||||||
|
refsignal_ul_t drms;
|
||||||
|
harq_t harq_process[NOF_HARQ_PROCESSES];
|
||||||
|
pusch_t pusch;
|
||||||
|
|
||||||
|
cf_t *refsignal;
|
||||||
|
cf_t *sf_symbols;
|
||||||
|
|
||||||
|
uint16_t current_rnti;
|
||||||
|
}ue_ul_t;
|
||||||
|
|
||||||
|
/* This function shall be called just after the initial synchronization */
|
||||||
|
LIBLTE_API int ue_ul_init(ue_ul_t *q,
|
||||||
|
lte_cell_t cell);
|
||||||
|
|
||||||
|
LIBLTE_API void ue_ul_free(ue_ul_t *q);
|
||||||
|
|
||||||
|
LIBLTE_API void ue_ul_set_cfo(ue_ul_t *q,
|
||||||
|
float cur_cfo);
|
||||||
|
|
||||||
|
LIBLTE_API void ue_ul_set_pusch_cfg(ue_ul_t *q,
|
||||||
|
refsignal_drms_pusch_cfg_t *pusch_drms_cfg,
|
||||||
|
pusch_hopping_cfg_t *pusch_hopping_cfg);
|
||||||
|
|
||||||
|
LIBLTE_API int ue_ul_pusch_encode(ue_ul_t *q,
|
||||||
|
ra_pusch_t *ra_ul,
|
||||||
|
uint8_t *data,
|
||||||
|
cf_t *output_signal);
|
||||||
|
|
||||||
|
LIBLTE_API int ue_ul_pusch_encode_rnti(ue_ul_t *q,
|
||||||
|
ra_pusch_t *ra_ul,
|
||||||
|
uint8_t *data,
|
||||||
|
uint16_t rnti,
|
||||||
|
cf_t *output_signal);
|
||||||
|
|
||||||
|
LIBLTE_API int ue_ul_pusch_uci_encode(ue_ul_t *q,
|
||||||
|
ra_pusch_t *ra_ul,
|
||||||
|
uint8_t *data,
|
||||||
|
uci_data_t uci_data,
|
||||||
|
cf_t *output_signal);
|
||||||
|
|
||||||
|
LIBLTE_API int ue_ul_pusch_uci_encode_rnti(ue_ul_t *q,
|
||||||
|
ra_pusch_t *ra_ul,
|
||||||
|
uint8_t *data,
|
||||||
|
uci_data_t uci_data,
|
||||||
|
uint16_t rnti,
|
||||||
|
cf_t *output_signal);
|
||||||
|
|
||||||
|
LIBLTE_API void ue_ul_reset(ue_ul_t *q);
|
||||||
|
|
||||||
|
LIBLTE_API void ue_ul_set_rnti(ue_ul_t *q,
|
||||||
|
uint16_t rnti);
|
||||||
|
|
||||||
|
#endif
|
|
@ -87,6 +87,12 @@ int chest_dl_init(chest_dl_t *q, lte_cell_t cell)
|
||||||
}
|
}
|
||||||
bzero(q->tmp_timeavg[i], sizeof(cf_t) * 2*cell.nof_prb);
|
bzero(q->tmp_timeavg[i], sizeof(cf_t) * 2*cell.nof_prb);
|
||||||
}
|
}
|
||||||
|
q->tmp_timeavg_mult = vec_malloc(sizeof(cf_t) * 2*cell.nof_prb);
|
||||||
|
if (!q->tmp_timeavg_mult) {
|
||||||
|
perror("malloc");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
bzero(q->tmp_timeavg_mult, sizeof(cf_t) * 2*cell.nof_prb);
|
||||||
|
|
||||||
for (int i=0;i<cell.nof_ports;i++) {
|
for (int i=0;i<cell.nof_ports;i++) {
|
||||||
q->pilot_estimates[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_NUM_SF(cell.nof_prb, i));
|
q->pilot_estimates[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_NUM_SF(cell.nof_prb, i));
|
||||||
|
@ -117,14 +123,14 @@ int chest_dl_init(chest_dl_t *q, lte_cell_t cell)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set default time/freq filters */
|
/* Set default time/freq filters */
|
||||||
float f[3]={0.15, 0.7, 0.15};
|
//float f[3]={0.1, 0.8, 0.1};
|
||||||
chest_dl_set_filter_freq(q, f, 3);
|
//chest_dl_set_filter_freq(q, f, 3);
|
||||||
|
|
||||||
//float f[5]={0.05, 0.15, 0.6, 0.15, 0.05};
|
float f[5]={0.05, 0.2, 0.5, 0.2, 0.05};
|
||||||
//chest_dl_set_filter_freq(q, f, 5);
|
chest_dl_set_filter_freq(q, f, 5);
|
||||||
|
|
||||||
float t[2]={0.2, 0.8};
|
float t[2]={0.2, 0.8};
|
||||||
chest_dl_set_filter_time(q, t, 2);
|
chest_dl_set_filter_time(q, t, 0);
|
||||||
|
|
||||||
q->cell = cell;
|
q->cell = cell;
|
||||||
}
|
}
|
||||||
|
@ -153,6 +159,9 @@ void chest_dl_free(chest_dl_t *q)
|
||||||
free(q->tmp_timeavg[i]);
|
free(q->tmp_timeavg[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (q->tmp_timeavg_mult) {
|
||||||
|
free(q->tmp_timeavg_mult);
|
||||||
|
}
|
||||||
interp_linear_vector_free(&q->interp_linvec);
|
interp_linear_vector_free(&q->interp_linvec);
|
||||||
interp_linear_free(&q->interp_lin);
|
interp_linear_free(&q->interp_lin);
|
||||||
|
|
||||||
|
@ -239,10 +248,11 @@ static void average_pilots(chest_dl_t *q, uint32_t port_id)
|
||||||
conv_same_cf(&pilot_est(0), q->filter_freq, &pilot_tmp(0), nref, q->filter_freq_len);
|
conv_same_cf(&pilot_est(0), q->filter_freq, &pilot_tmp(0), nref, q->filter_freq_len);
|
||||||
|
|
||||||
/* Adjust extremes using linear interpolation */
|
/* Adjust extremes using linear interpolation */
|
||||||
|
|
||||||
pilot_tmp(0) += interp_linear_onesample(pilot_est(1), pilot_est(0))
|
pilot_tmp(0) += interp_linear_onesample(pilot_est(1), pilot_est(0))
|
||||||
* q->filter_freq[q->filter_freq_len/2-1];
|
* q->filter_freq[q->filter_freq_len/2-1]*1.2;
|
||||||
pilot_tmp(nref-1) += interp_linear_onesample(pilot_est(nref-2), pilot_est(nref-1))
|
pilot_tmp(nref-1) += interp_linear_onesample(pilot_est(nref-2), pilot_est(nref-1))
|
||||||
* q->filter_freq[q->filter_freq_len/2+1];
|
* q->filter_freq[q->filter_freq_len/2+1]*1.2;
|
||||||
} else {
|
} else {
|
||||||
memcpy(&pilot_tmp(0), &pilot_est(0), nref * sizeof(cf_t));
|
memcpy(&pilot_tmp(0), &pilot_est(0), nref * sizeof(cf_t));
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,7 +243,11 @@ bool refsignal_drms_pusch_cfg_isvalid(refsignal_ul_t *q, refsignal_drms_pusch_cf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void refsignal_drms_pusch_put(refsignal_ul_t *q, refsignal_drms_pusch_cfg_t *cfg, cf_t *r_pusch, uint32_t ns_idx, uint32_t n_prb, cf_t *sf_symbols) {
|
void refsignal_drms_pusch_put(refsignal_ul_t *q, refsignal_drms_pusch_cfg_t *cfg,
|
||||||
|
cf_t *r_pusch,
|
||||||
|
uint32_t ns_idx, uint32_t n_prb,
|
||||||
|
cf_t *sf_symbols)
|
||||||
|
{
|
||||||
if (ns_idx < 2) {
|
if (ns_idx < 2) {
|
||||||
uint32_t L = (ns_idx+1)*CP_NSYMB(q->cell.cp)-4;
|
uint32_t L = (ns_idx+1)*CP_NSYMB(q->cell.cp)-4;
|
||||||
memcpy(&sf_symbols[RE_IDX(q->cell.nof_prb, L, n_prb*RE_X_RB)], r_pusch, cfg->nof_prb*RE_X_RB*sizeof(cf_t));
|
memcpy(&sf_symbols[RE_IDX(q->cell.nof_prb, L, n_prb*RE_X_RB)], r_pusch, cfg->nof_prb*RE_X_RB*sizeof(cf_t));
|
||||||
|
|
|
@ -97,6 +97,37 @@ int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dci_msg_to_ra_ul(dci_msg_t *msg, lte_cell_t cell, uint32_t n_rb_ho, ra_pusch_t *ra_ul)
|
||||||
|
{
|
||||||
|
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||||
|
|
||||||
|
if (msg != NULL &&
|
||||||
|
ra_ul != NULL &&
|
||||||
|
lte_cell_isvalid(&cell))
|
||||||
|
{
|
||||||
|
ret = LIBLTE_ERROR;
|
||||||
|
|
||||||
|
bzero(ra_ul, sizeof(ra_pusch_t));
|
||||||
|
|
||||||
|
if (dci_msg_unpack_pusch(msg, ra_ul, cell.nof_prb)) {
|
||||||
|
fprintf(stderr, "Can't unpack PDSCH message\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VERBOSE_ISINFO()) {
|
||||||
|
ra_pusch_fprint(stdout, ra_ul, cell.nof_prb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ra_ul_alloc(&ra_ul->prb_alloc, ra_ul, n_rb_ho, cell.nof_prb)) {
|
||||||
|
fprintf(stderr, "Error computing resource allocation\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = LIBLTE_SUCCESS;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE) {
|
int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE) {
|
||||||
if (L <= 3) {
|
if (L <= 3) {
|
||||||
c->L = L;
|
c->L = L;
|
||||||
|
|
|
@ -106,13 +106,13 @@ int harq_init(harq_t *q, lte_cell_t cell) {
|
||||||
if (ret != LIBLTE_ERROR) {
|
if (ret != LIBLTE_ERROR) {
|
||||||
q->max_cb = (uint32_t) ret / (MAX_LONG_CB - 24) + 1;
|
q->max_cb = (uint32_t) ret / (MAX_LONG_CB - 24) + 1;
|
||||||
|
|
||||||
q->pdsch_w_buff_f = malloc(sizeof(float*) * q->max_cb);
|
q->pdsch_w_buff_f = vec_malloc(sizeof(float*) * q->max_cb);
|
||||||
if (!q->pdsch_w_buff_f) {
|
if (!q->pdsch_w_buff_f) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
return LIBLTE_ERROR;
|
return LIBLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
q->pdsch_w_buff_c = malloc(sizeof(uint8_t*) * q->max_cb);
|
q->pdsch_w_buff_c = vec_malloc(sizeof(uint8_t*) * q->max_cb);
|
||||||
if (!q->pdsch_w_buff_c) {
|
if (!q->pdsch_w_buff_c) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
return LIBLTE_ERROR;
|
return LIBLTE_ERROR;
|
||||||
|
|
|
@ -42,9 +42,10 @@
|
||||||
#include "liblte/phy/utils/debug.h"
|
#include "liblte/phy/utils/debug.h"
|
||||||
|
|
||||||
const uint8_t crc_mask[4][16] = {
|
const uint8_t crc_mask[4][16] = {
|
||||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 1, 1, 1, 1,
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
|
||||||
0, 0 }, { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 } };
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||||
|
{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 } };
|
||||||
|
|
||||||
bool pbch_exists(int nframe, int nslot) {
|
bool pbch_exists(int nframe, int nslot) {
|
||||||
return (!(nframe % 5) && nslot == 1);
|
return (!(nframe % 5) && nslot == 1);
|
||||||
|
@ -246,10 +247,10 @@ void pbch_free(pbch_t *q) {
|
||||||
* msg buffer must be 24 byte length at least
|
* msg buffer must be 24 byte length at least
|
||||||
*/
|
*/
|
||||||
void pbch_mib_unpack(uint8_t *msg, lte_cell_t *cell, uint32_t *sfn) {
|
void pbch_mib_unpack(uint8_t *msg, lte_cell_t *cell, uint32_t *sfn) {
|
||||||
int bw, phich_res;
|
int phich_res;
|
||||||
|
|
||||||
bw = bit_unpack(&msg, 3);
|
cell->bw_idx = bit_unpack(&msg, 3);
|
||||||
switch (bw) {
|
switch (cell->bw_idx) {
|
||||||
case 0:
|
case 0:
|
||||||
cell->nof_prb = 6;
|
cell->nof_prb = 6;
|
||||||
break;
|
break;
|
||||||
|
@ -257,7 +258,7 @@ void pbch_mib_unpack(uint8_t *msg, lte_cell_t *cell, uint32_t *sfn) {
|
||||||
cell->nof_prb = 15;
|
cell->nof_prb = 15;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cell->nof_prb = (bw - 1) * 25;
|
cell->nof_prb = (cell->bw_idx - 1) * 25;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (*msg) {
|
if (*msg) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ static int f_hop_sum(pusch_t *q, uint32_t i) {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int f_hop(pusch_t *q, ra_ul_hopping_t *hopping, int i) {
|
static int f_hop(pusch_t *q, pusch_hopping_cfg_t *hopping, int i) {
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -71,7 +71,7 @@ static int f_hop(pusch_t *q, ra_ul_hopping_t *hopping, int i) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int f_m(pusch_t *q, ra_ul_hopping_t *hopping, uint32_t i) {
|
static int f_m(pusch_t *q, pusch_hopping_cfg_t *hopping, uint32_t i) {
|
||||||
if (hopping->n_sb == 1) {
|
if (hopping->n_sb == 1) {
|
||||||
if (hopping->hop_mode == hop_mode_inter_sf) {
|
if (hopping->hop_mode == hop_mode_inter_sf) {
|
||||||
return hopping->current_tx_nb%2;
|
return hopping->current_tx_nb%2;
|
||||||
|
@ -87,7 +87,7 @@ int pusch_cp(pusch_t *q, harq_t *harq, cf_t *input, cf_t *output, bool advance_i
|
||||||
{
|
{
|
||||||
cf_t *in_ptr = input;
|
cf_t *in_ptr = input;
|
||||||
cf_t *out_ptr = output;
|
cf_t *out_ptr = output;
|
||||||
ra_ul_hopping_t *hopping = &harq->ul_hopping;
|
pusch_hopping_cfg_t *hopping = &q->hopping_cfg;
|
||||||
|
|
||||||
uint32_t L_ref = 3;
|
uint32_t L_ref = 3;
|
||||||
if (CP_ISEXT(q->cell.cp)) {
|
if (CP_ISEXT(q->cell.cp)) {
|
||||||
|
@ -128,6 +128,7 @@ int pusch_cp(pusch_t *q, harq_t *harq, cf_t *input, cf_t *output, bool advance_i
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
harq->ul_alloc.n_prb_tilde[slot] = n_prb_tilde;
|
||||||
INFO("Allocating PUSCH %d PRB to index %d at slot %d\n",harq->ul_alloc.L_prb, n_prb_tilde,slot);
|
INFO("Allocating PUSCH %d PRB to index %d at slot %d\n",harq->ul_alloc.L_prb, n_prb_tilde,slot);
|
||||||
for (uint32_t l=0;l<CP_NSYMB(q->cell.cp);l++) {
|
for (uint32_t l=0;l<CP_NSYMB(q->cell.cp);l++) {
|
||||||
if (l != L_ref) {
|
if (l != L_ref) {
|
||||||
|
@ -278,6 +279,11 @@ void pusch_free(pusch_t *q) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pusch_set_hopping_cfg(pusch_t *q, pusch_hopping_cfg_t *cfg)
|
||||||
|
{
|
||||||
|
memcpy(&q->hopping_cfg, cfg, sizeof(pusch_hopping_cfg_t));
|
||||||
|
}
|
||||||
|
|
||||||
/* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while
|
/* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while
|
||||||
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
|
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
|
||||||
* For the connection procedure, use pusch_encode_rnti() or pusch_decode_rnti() functions */
|
* For the connection procedure, use pusch_encode_rnti() or pusch_decode_rnti() functions */
|
||||||
|
@ -412,9 +418,6 @@ int pusch_uci_encode_rnti(pusch_t *q, harq_t *harq, uint8_t *data, uci_data_t uc
|
||||||
return LIBLTE_ERROR;
|
return LIBLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("before scram: ");
|
|
||||||
vec_fprint_b(stdout, q->pusch_q, harq->nof_bits);
|
|
||||||
|
|
||||||
if (rnti != q->rnti) {
|
if (rnti != q->rnti) {
|
||||||
sequence_t seq;
|
sequence_t seq;
|
||||||
if (sequence_pusch(&seq, rnti, 2 * harq->sf_idx, q->cell.id, harq->nof_bits)) {
|
if (sequence_pusch(&seq, rnti, 2 * harq->sf_idx, q->cell.id, harq->nof_bits)) {
|
||||||
|
@ -426,9 +429,6 @@ int pusch_uci_encode_rnti(pusch_t *q, harq_t *harq, uint8_t *data, uci_data_t uc
|
||||||
scrambling_b_offset_pusch(&q->seq_pusch[harq->sf_idx], (uint8_t*) q->pusch_q, 0, harq->nof_bits);
|
scrambling_b_offset_pusch(&q->seq_pusch[harq->sf_idx], (uint8_t*) q->pusch_q, 0, harq->nof_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("after scram: ");
|
|
||||||
vec_fprint_b(stdout, q->pusch_q, harq->nof_bits);
|
|
||||||
|
|
||||||
mod_modulate(&q->mod[harq->mcs.mod], (uint8_t*) q->pusch_q, q->pusch_d, harq->nof_bits);
|
mod_modulate(&q->mod[harq->mcs.mod], (uint8_t*) q->pusch_q, q->pusch_d, harq->nof_bits);
|
||||||
|
|
||||||
dft_precoding(&q->dft_precoding, q->pusch_d, q->pusch_z,
|
dft_precoding(&q->dft_precoding, q->pusch_d, q->pusch_z,
|
||||||
|
|
|
@ -191,10 +191,13 @@ int main(int argc, char **argv) {
|
||||||
fprintf(stderr, "Error configuring HARQ process\n");
|
fprintf(stderr, "Error configuring HARQ process\n");
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
harq_process.ul_hopping.n_sb = 1;
|
pusch_hopping_cfg_t ul_hopping;
|
||||||
harq_process.ul_hopping.hopping_offset = 0;
|
ul_hopping.n_sb = 1;
|
||||||
harq_process.ul_hopping.hop_mode = hop_mode_inter_sf;
|
ul_hopping.hopping_offset = 0;
|
||||||
harq_process.ul_hopping.current_tx_nb = 0;
|
ul_hopping.hop_mode = hop_mode_inter_sf;
|
||||||
|
ul_hopping.current_tx_nb = 0;
|
||||||
|
|
||||||
|
pusch_set_hopping_cfg(&pusch, &ul_hopping);
|
||||||
|
|
||||||
uint32_t nof_re = RE_X_RB*cell.nof_prb*2*CP_NSYMB(cell.cp);
|
uint32_t nof_re = RE_X_RB*cell.nof_prb*2*CP_NSYMB(cell.cp);
|
||||||
sf_symbols = vec_malloc(sizeof(cf_t) * nof_re);
|
sf_symbols = vec_malloc(sizeof(cf_t) * nof_re);
|
||||||
|
|
|
@ -37,14 +37,7 @@
|
||||||
/*************** STATIC FUNCTIONS ***********************/
|
/*************** STATIC FUNCTIONS ***********************/
|
||||||
|
|
||||||
cf_t interp_linear_onesample(cf_t input0, cf_t input1) {
|
cf_t interp_linear_onesample(cf_t input0, cf_t input1) {
|
||||||
float mag0=0, mag1=0, arg0=0, arg1=0, mag=0, arg=0;
|
return 2*input1-input0;
|
||||||
mag0 = cabsf(input0);
|
|
||||||
mag1 = cabsf(input1);
|
|
||||||
arg0 = cargf(input0);
|
|
||||||
arg1 = cargf(input1);
|
|
||||||
mag = 2*mag1 -mag0;
|
|
||||||
arg = 2*arg1-arg0;
|
|
||||||
return mag * cexpf(I * arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cf_t interp_linear_onesample_cabs(cf_t input0, cf_t input1) {
|
cf_t interp_linear_onesample_cabs(cf_t input0, cf_t input1) {
|
||||||
|
|
|
@ -149,15 +149,7 @@ int sss_synch_N_id_1(sss_synch_t *q, uint32_t m0, uint32_t m1) {
|
||||||
} else {
|
} else {
|
||||||
N_id_1 = q->N_id_1_table[m1][m0 - 1];
|
N_id_1 = q->N_id_1_table[m1][m0 - 1];
|
||||||
}
|
}
|
||||||
if (N_id_1 == 0) {
|
return N_id_1;
|
||||||
if (m0 == 0 && m1 == 1) {
|
|
||||||
return N_id_1;
|
|
||||||
} else {
|
|
||||||
return LIBLTE_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return N_id_1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** High-level API */
|
/** High-level API */
|
||||||
|
|
|
@ -194,6 +194,7 @@ int main(int argc, char **argv) {
|
||||||
frame_cnt = 0;
|
frame_cnt = 0;
|
||||||
last_peak = 0;
|
last_peak = 0;
|
||||||
mean_peak = 0;
|
mean_peak = 0;
|
||||||
|
int peak_offset = 0;
|
||||||
float cfo;
|
float cfo;
|
||||||
float mean_cfo = 0;
|
float mean_cfo = 0;
|
||||||
uint32_t m0, m1;
|
uint32_t m0, m1;
|
||||||
|
@ -204,27 +205,12 @@ int main(int argc, char **argv) {
|
||||||
bzero(&ssync, sizeof(sync_t));
|
bzero(&ssync, sizeof(sync_t));
|
||||||
ssync.fft_size = fft_size;
|
ssync.fft_size = fft_size;
|
||||||
|
|
||||||
|
|
||||||
timestamp_t cur_time;
|
|
||||||
cuhd_get_time(uhd, &cur_time.full_secs, &cur_time.frac_secs);
|
|
||||||
|
|
||||||
// wait 1 sec to start
|
|
||||||
timestamp_add(&cur_time, 1, 0);
|
|
||||||
double period = 0.005; // 5 ms
|
|
||||||
double period_diff = 0;
|
|
||||||
double nsamples_offset_x_sf;
|
|
||||||
|
|
||||||
int last_peak_idx = 0;
|
|
||||||
bool is_first = true;
|
|
||||||
while(frame_cnt < nof_frames || nof_frames == -1) {
|
while(frame_cnt < nof_frames || nof_frames == -1) {
|
||||||
timestamp_add(&cur_time, 0, period + period_diff);
|
n = cuhd_recv(uhd, buffer, flen - peak_offset, 1);
|
||||||
|
|
||||||
n = cuhd_recv_timed2(uhd, buffer, flen, cur_time.full_secs, cur_time.frac_secs, is_first, false);
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
fprintf(stderr, "Error receiving samples\n");
|
fprintf(stderr, "Error receiving samples\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
is_first = false;
|
|
||||||
|
|
||||||
peak_idx = pss_synch_find_pss(&pss, buffer, &peak_value);
|
peak_idx = pss_synch_find_pss(&pss, buffer, &peak_value);
|
||||||
if (peak_idx < 0) {
|
if (peak_idx < 0) {
|
||||||
|
@ -237,12 +223,6 @@ int main(int argc, char **argv) {
|
||||||
if (peak_value >= threshold) {
|
if (peak_value >= threshold) {
|
||||||
nof_det++;
|
nof_det++;
|
||||||
|
|
||||||
if (last_peak_idx) {
|
|
||||||
nsamples_offset_x_sf = VEC_CMA(((double) peak_idx - (double) last_peak_idx ), nsamples_offset_x_sf, frame_cnt);
|
|
||||||
period_diff += nsamples_offset_x_sf / (flen*2*100);
|
|
||||||
}
|
|
||||||
last_peak_idx = peak_idx;
|
|
||||||
|
|
||||||
if (peak_idx >= fft_size) {
|
if (peak_idx >= fft_size) {
|
||||||
|
|
||||||
// Estimate CFO
|
// Estimate CFO
|
||||||
|
@ -308,10 +288,10 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
frame_cnt++;
|
frame_cnt++;
|
||||||
|
|
||||||
printf("[%5d]: Pos: %5d (%f), PSR: %4.1f (~%4.1f) Pdet: %4.2f, "
|
printf("[%5d]: Pos: %5d, PSR: %4.1f (~%4.1f) Pdet: %4.2f, "
|
||||||
"FA: %4.2f, CFO: %+4.1f KHz SSSmiss: %4.2f/%4.2f/%4.2f CPNorm: %.0f\%\r",
|
"FA: %4.2f, CFO: %+4.1f KHz SSSmiss: %4.2f/%4.2f/%4.2f CPNorm: %.0f\%\r",
|
||||||
frame_cnt,
|
frame_cnt,
|
||||||
peak_idx, period_diff*1000000,
|
peak_idx,
|
||||||
peak_value, mean_peak,
|
peak_value, mean_peak,
|
||||||
(float) nof_det/frame_cnt,
|
(float) nof_det/frame_cnt,
|
||||||
(float) nof_nopeakdet/frame_cnt, mean_cfo*15,
|
(float) nof_nopeakdet/frame_cnt, mean_cfo*15,
|
||||||
|
@ -408,4 +388,3 @@ void do_plots_sss(float *corr_m0, float *corr_m1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -66,10 +66,6 @@ int ue_dl_init(ue_dl_t *q,
|
||||||
fprintf(stderr, "Error initiating REGs\n");
|
fprintf(stderr, "Error initiating REGs\n");
|
||||||
goto clean_exit;
|
goto clean_exit;
|
||||||
}
|
}
|
||||||
if (pbch_init(&q->pbch, q->cell)) {
|
|
||||||
fprintf(stderr, "Error creating PBCH object\n");
|
|
||||||
goto clean_exit;
|
|
||||||
}
|
|
||||||
if (pcfich_init(&q->pcfich, &q->regs, q->cell)) {
|
if (pcfich_init(&q->pcfich, &q->regs, q->cell)) {
|
||||||
fprintf(stderr, "Error creating PCFICH object\n");
|
fprintf(stderr, "Error creating PCFICH object\n");
|
||||||
goto clean_exit;
|
goto clean_exit;
|
||||||
|
@ -121,7 +117,6 @@ void ue_dl_free(ue_dl_t *q) {
|
||||||
lte_fft_free(&q->fft);
|
lte_fft_free(&q->fft);
|
||||||
chest_dl_free(&q->chest);
|
chest_dl_free(&q->chest);
|
||||||
regs_free(&q->regs);
|
regs_free(&q->regs);
|
||||||
pbch_free(&q->pbch);
|
|
||||||
pcfich_free(&q->pcfich);
|
pcfich_free(&q->pcfich);
|
||||||
pdcch_free(&q->pdcch);
|
pdcch_free(&q->pdcch);
|
||||||
pdsch_free(&q->pdsch);
|
pdsch_free(&q->pdsch);
|
||||||
|
@ -155,8 +150,6 @@ void ue_dl_reset(ue_dl_t *q) {
|
||||||
harq_reset(&q->harq_process[0]);
|
harq_reset(&q->harq_process[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBLTE_API float mean_exec_time=0;
|
|
||||||
|
|
||||||
dci_format_t ue_formats[] = {Format1,Format1A}; // Format1B should go here also
|
dci_format_t ue_formats[] = {Format1,Format1A}; // Format1B should go here also
|
||||||
const uint32_t nof_ue_formats = 2;
|
const uint32_t nof_ue_formats = 2;
|
||||||
|
|
||||||
|
@ -171,48 +164,116 @@ const uint32_t nof_common_formats = 2;
|
||||||
* - PDSCH decoding: Decode TB scrambling with RNTI given by ue_dl_set_rnti()
|
* - PDSCH decoding: Decode TB scrambling with RNTI given by ue_dl_set_rnti()
|
||||||
*/
|
*/
|
||||||
int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx) {
|
int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx) {
|
||||||
return ue_dl_decode_sib(q, input, data, sf_idx, q->current_rnti, 0);
|
return ue_dl_decode_rnti_rv(q, input, data, sf_idx, q->current_rnti, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ue_dl_decode_rnti(ue_dl_t *q, cf_t *input, uint8_t *data, uint16_t rnti, uint32_t sf_idx) {
|
int ue_dl_decode_rnti(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint16_t rnti) {
|
||||||
return ue_dl_decode_sib(q, input, data, sf_idx, rnti, 0);
|
return ue_dl_decode_rnti_rv(q, input, data, sf_idx, rnti, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint16_t rnti, uint32_t rvidx)
|
int ue_dl_decode_fft_estimate(ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi) {
|
||||||
{
|
|
||||||
uint32_t cfi, i;
|
|
||||||
float cfi_corr;
|
float cfi_corr;
|
||||||
ra_pdsch_t ra_dl;
|
if (input && q && cfi && sf_idx < NSUBFRAMES_X_FRAME) {
|
||||||
dci_location_t locations[MAX_CANDIDATES];
|
|
||||||
dci_msg_t dci_msg;
|
/* Run FFT for all subframe data */
|
||||||
uint32_t nof_locations;
|
lte_fft_run_sf(&q->fft, input, q->sf_symbols);
|
||||||
uint16_t crc_rem;
|
|
||||||
|
/* Get channel estimates for each port */
|
||||||
|
chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, sf_idx);
|
||||||
|
|
||||||
|
/* First decode PCFICH and obtain CFI */
|
||||||
|
if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce,
|
||||||
|
chest_dl_get_noise_estimate(&q->chest), sf_idx, cfi, &cfi_corr)<0) {
|
||||||
|
fprintf(stderr, "Error decoding PCFICH\n");
|
||||||
|
return LIBLTE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
INFO("Decoded CFI=%d with correlation %.2f\n", cfi, cfi_corr);
|
||||||
|
|
||||||
|
if (regs_set_cfi(&q->regs, *cfi)) {
|
||||||
|
fprintf(stderr, "Error setting CFI\n");
|
||||||
|
return LIBLTE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract all PDCCH symbols and get LLRs */
|
||||||
|
if (pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, chest_dl_get_noise_estimate(&q->chest), sf_idx, *cfi)) {
|
||||||
|
fprintf(stderr, "Error extracting LLRs\n");
|
||||||
|
return LIBLTE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return LIBLTE_SUCCESS;
|
||||||
|
} else {
|
||||||
|
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ue_dl_decode_rnti_rv_packet(ue_dl_t *q, dci_msg_t *dci_msg, uint8_t *data,
|
||||||
|
uint32_t cfi, uint32_t sf_idx, uint16_t rnti, uint32_t rvidx)
|
||||||
|
{
|
||||||
int ret = LIBLTE_ERROR;
|
int ret = LIBLTE_ERROR;
|
||||||
struct timeval t[3];
|
|
||||||
uint32_t nof_formats;
|
|
||||||
dci_format_t *formats = NULL;
|
|
||||||
|
|
||||||
/* Run FFT for all subframe data */
|
q->nof_pdcch_detected++;
|
||||||
lte_fft_run_sf(&q->fft, input, q->sf_symbols);
|
if (dci_msg_to_ra_dl(dci_msg, rnti, q->cell, cfi, &q->ra_dl)) {
|
||||||
|
fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n");
|
||||||
gettimeofday(&t[1], NULL);
|
|
||||||
|
|
||||||
/* Get channel estimates for each port */
|
|
||||||
chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, sf_idx);
|
|
||||||
|
|
||||||
/* First decode PCFICH and obtain CFI */
|
|
||||||
if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce,
|
|
||||||
chest_dl_get_noise_estimate(&q->chest), sf_idx, &cfi, &cfi_corr)<0) {
|
|
||||||
fprintf(stderr, "Error decoding PCFICH\n");
|
|
||||||
return LIBLTE_ERROR;
|
return LIBLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
INFO("Decoded CFI=%d with correlation %.2f\n", cfi, cfi_corr);
|
if (rnti != SIRNTI) {
|
||||||
|
rvidx = q->ra_dl.rv_idx;
|
||||||
if (regs_set_cfi(&q->regs, cfi)) {
|
}
|
||||||
fprintf(stderr, "Error setting CFI\n");
|
if (harq_setup_dl(&q->harq_process[0], q->ra_dl.mcs, rvidx, sf_idx, &q->ra_dl.prb_alloc)) {
|
||||||
|
fprintf(stderr, "Error configuring HARQ process\n");
|
||||||
return LIBLTE_ERROR;
|
return LIBLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
if (q->harq_process[0].mcs.mod > 0 && q->harq_process[0].mcs.tbs >= 0) {
|
||||||
|
ret = pdsch_decode_rnti(&q->pdsch, &q->harq_process[0], q->sf_symbols,
|
||||||
|
q->ce, chest_dl_get_noise_estimate(&q->chest),
|
||||||
|
rnti, data);
|
||||||
|
if (ret == LIBLTE_ERROR) {
|
||||||
|
q->pkt_errors++;
|
||||||
|
} else if (ret == LIBLTE_ERROR_INVALID_INPUTS) {
|
||||||
|
fprintf(stderr, "Error calling pdsch_decode()\n");
|
||||||
|
} else if (ret == LIBLTE_SUCCESS) {
|
||||||
|
if (VERBOSE_ISINFO()) {
|
||||||
|
INFO("Decoded Message: ", 0);
|
||||||
|
vec_fprint_hex(stdout, data, q->ra_dl.mcs.tbs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q->pkts_total++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ue_dl_find_ul_dci(ue_dl_t *q, dci_msg_t *dci_msg, uint32_t cfi, uint32_t sf_idx, uint16_t rnti)
|
||||||
|
{
|
||||||
|
dci_location_t locations[MAX_CANDIDATES];
|
||||||
|
uint32_t nof_locations = pdcch_ue_locations(&q->pdcch, locations, MAX_CANDIDATES, sf_idx, cfi, rnti);
|
||||||
|
uint16_t crc_rem = 0;
|
||||||
|
for (uint32_t i=0;i<nof_locations && crc_rem != rnti;i++) {
|
||||||
|
if (pdcch_decode_msg(&q->pdcch, dci_msg, &locations[i], Format0, &crc_rem)) {
|
||||||
|
fprintf(stderr, "Error decoding DCI msg\n");
|
||||||
|
return LIBLTE_ERROR;
|
||||||
|
}
|
||||||
|
INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem);
|
||||||
|
}
|
||||||
|
return crc_rem == rnti;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ue_dl_decode_rnti_rv(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint16_t rnti, uint32_t rvidx)
|
||||||
|
{
|
||||||
|
uint32_t cfi, i;
|
||||||
|
dci_msg_t dci_msg;
|
||||||
|
dci_location_t locations[MAX_CANDIDATES];
|
||||||
|
uint32_t nof_locations;
|
||||||
|
uint16_t crc_rem;
|
||||||
|
int ret = LIBLTE_ERROR;
|
||||||
|
uint32_t nof_formats;
|
||||||
|
dci_format_t *formats = NULL;
|
||||||
|
|
||||||
|
if ((ret = ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate PDCCH candidates */
|
/* Generate PDCCH candidates */
|
||||||
if (rnti == SIRNTI) {
|
if (rnti == SIRNTI) {
|
||||||
|
@ -225,11 +286,6 @@ int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, ui
|
||||||
nof_formats = nof_ue_formats;
|
nof_formats = nof_ue_formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract all PDCCH symbols and get LLRs */
|
|
||||||
if (pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, chest_dl_get_noise_estimate(&q->chest), sf_idx, cfi)) {
|
|
||||||
fprintf(stderr, "Error extracting LLRs\n");
|
|
||||||
return LIBLTE_ERROR;
|
|
||||||
}
|
|
||||||
/* For all possible locations, try to decode a DCI message */
|
/* For all possible locations, try to decode a DCI message */
|
||||||
crc_rem = 0;
|
crc_rem = 0;
|
||||||
uint32_t found_dci = 0;
|
uint32_t found_dci = 0;
|
||||||
|
@ -242,50 +298,14 @@ int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, ui
|
||||||
INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem);
|
INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem);
|
||||||
|
|
||||||
if (crc_rem == rnti) {
|
if (crc_rem == rnti) {
|
||||||
|
|
||||||
found_dci++;
|
found_dci++;
|
||||||
q->nof_pdcch_detected++;
|
ret = ue_dl_decode_rnti_rv_packet(q, &dci_msg, data, cfi, sf_idx, rnti, rvidx);
|
||||||
if (dci_msg_to_ra_dl(&dci_msg, rnti, q->cell, cfi, &ra_dl)) {
|
|
||||||
fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n");
|
|
||||||
return LIBLTE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rnti != SIRNTI) {
|
|
||||||
rvidx = ra_dl.rv_idx;
|
|
||||||
}
|
|
||||||
if (harq_setup_dl(&q->harq_process[0], ra_dl.mcs, rvidx, sf_idx, &ra_dl.prb_alloc)) {
|
|
||||||
fprintf(stderr, "Error configuring HARQ process\n");
|
|
||||||
return LIBLTE_ERROR;
|
|
||||||
}
|
|
||||||
if (q->harq_process[0].mcs.mod > 0 && q->harq_process[0].mcs.tbs >= 0) {
|
|
||||||
ret = pdsch_decode_rnti(&q->pdsch, &q->harq_process[0], q->sf_symbols,
|
|
||||||
q->ce, chest_dl_get_noise_estimate(&q->chest),
|
|
||||||
rnti, data);
|
|
||||||
if (ret == LIBLTE_ERROR) {
|
|
||||||
q->pkt_errors++;
|
|
||||||
} else if (ret == LIBLTE_ERROR_INVALID_INPUTS) {
|
|
||||||
fprintf(stderr, "Error calling pdsch_decode()\n");
|
|
||||||
return LIBLTE_ERROR;
|
|
||||||
} else if (ret == LIBLTE_SUCCESS) {
|
|
||||||
if (VERBOSE_ISINFO()) {
|
|
||||||
INFO("Decoded Message: ", 0);
|
|
||||||
vec_fprint_hex(stdout, data, ra_dl.mcs.tbs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
q->pkts_total++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gettimeofday(&t[2], NULL);
|
|
||||||
get_time_interval(t);
|
|
||||||
mean_exec_time = (float) VEC_EMA((float) t[0].tv_usec, mean_exec_time, 0.01);
|
|
||||||
|
|
||||||
|
|
||||||
if (found_dci > 0 && ret == LIBLTE_SUCCESS) {
|
if (found_dci > 0 && ret == LIBLTE_SUCCESS) {
|
||||||
return ra_dl.mcs.tbs;
|
return q->ra_dl.mcs.tbs;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ int ue_mib_decode(ue_mib_t * q, cf_t *input,
|
||||||
/* Run FFT for the slot symbols */
|
/* Run FFT for the slot symbols */
|
||||||
lte_fft_run_sf(&q->fft, input, q->sf_symbols);
|
lte_fft_run_sf(&q->fft, input, q->sf_symbols);
|
||||||
|
|
||||||
/* Get channel estimates of slot #1 for each port */
|
/* Get channel estimates of sf idx #0 for each port */
|
||||||
ret = chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, 0);
|
ret = chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return LIBLTE_ERROR;
|
return LIBLTE_ERROR;
|
||||||
|
@ -214,9 +214,7 @@ int ue_mib_sync_decode(ue_mib_sync_t * q,
|
||||||
break;
|
break;
|
||||||
} else if (ue_sync_get_sfidx(&q->ue_sync) == 0) {
|
} else if (ue_sync_get_sfidx(&q->ue_sync) == 0) {
|
||||||
if (ret == 1) {
|
if (ret == 1) {
|
||||||
ue_mib_reset(&q->ue_mib);
|
|
||||||
mib_ret = ue_mib_decode(&q->ue_mib, sf_buffer, bch_payload, nof_tx_ports, sfn_offset);
|
mib_ret = ue_mib_decode(&q->ue_mib, sf_buffer, bch_payload, nof_tx_ports, sfn_offset);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
INFO("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt);
|
INFO("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt);
|
||||||
ue_mib_reset(&q->ue_mib);
|
ue_mib_reset(&q->ue_mib);
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#define MAX_TIME_OFFSET 128
|
#define MAX_TIME_OFFSET 128
|
||||||
cf_t dummy[MAX_TIME_OFFSET];
|
cf_t dummy[MAX_TIME_OFFSET];
|
||||||
|
|
||||||
#define TRACK_MAX_LOST 10
|
#define TRACK_MAX_LOST 4
|
||||||
#define TRACK_FRAME_SIZE 32
|
#define TRACK_FRAME_SIZE 32
|
||||||
#define FIND_NOF_AVG_FRAMES 2
|
#define FIND_NOF_AVG_FRAMES 2
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ int ue_sync_init(ue_sync_t *q,
|
||||||
sync_set_threshold(&q->sfind, 1.3);
|
sync_set_threshold(&q->sfind, 1.3);
|
||||||
sync_set_em_alpha(&q->sfind, 0.01);
|
sync_set_em_alpha(&q->sfind, 0.01);
|
||||||
q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES;
|
q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES;
|
||||||
sync_set_threshold(&q->strack, 1.2);
|
sync_set_threshold(&q->strack, 1.0);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
sync_set_N_id_2(&q->sfind, cell.id%3);
|
sync_set_N_id_2(&q->sfind, cell.id%3);
|
||||||
|
@ -155,8 +155,8 @@ int ue_sync_init(ue_sync_t *q,
|
||||||
*/
|
*/
|
||||||
sync_set_em_alpha(&q->sfind, 1);
|
sync_set_em_alpha(&q->sfind, 1);
|
||||||
q->nof_avg_find_frames = 1;
|
q->nof_avg_find_frames = 1;
|
||||||
sync_set_threshold(&q->sfind, 2.0);
|
sync_set_threshold(&q->sfind, 4.0);
|
||||||
sync_set_threshold(&q->strack, 1.2);
|
sync_set_threshold(&q->strack, 1.3);
|
||||||
|
|
||||||
/* Correct CFO in the find state but not in the track state, since is called only
|
/* Correct CFO in the find state but not in the track state, since is called only
|
||||||
* 1 every 5 subframes. Will do it in the ue_sync_get_buffer() function.
|
* 1 every 5 subframes. Will do it in the ue_sync_get_buffer() function.
|
||||||
|
@ -286,33 +286,33 @@ static int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
|
||||||
q->strack.m0, q->strack.m0_value, q->strack.m1, q->strack.m1_value);
|
q->strack.m0, q->strack.m0_value, q->strack.m1, q->strack.m1_value);
|
||||||
q->sf_idx = sync_get_sf_idx(&q->strack);
|
q->sf_idx = sync_get_sf_idx(&q->strack);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Adjust time offset
|
|
||||||
q->time_offset = ((int) track_idx - (int) q->strack.frame_size/2 - (int) q->strack.fft_size);
|
|
||||||
|
|
||||||
if (q->time_offset) {
|
|
||||||
INFO("Time offset adjustment: %d samples\n", q->time_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* compute cumulative moving average time offset */
|
|
||||||
q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_total_cnt);
|
|
||||||
|
|
||||||
/* If the PSS peak is beyond the frame (we sample too slowly),
|
|
||||||
discard the offseted samples to align next frame */
|
|
||||||
if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) {
|
|
||||||
INFO("\nPositive time offset %d samples. Mean time offset %f.\n", q->time_offset, q->mean_time_offset);
|
|
||||||
if (q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset, &q->last_timestamp) < 0) {
|
|
||||||
fprintf(stderr, "Error receiving from USRP\n");
|
|
||||||
return LIBLTE_ERROR;
|
|
||||||
}
|
|
||||||
q->time_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
q->peak_idx = q->sf_len/2 + q->time_offset;
|
|
||||||
q->frame_ok_cnt++;
|
|
||||||
q->frame_no_cnt = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust time offset
|
||||||
|
q->time_offset = ((int) track_idx - (int) q->strack.frame_size/2 - (int) q->strack.fft_size);
|
||||||
|
|
||||||
|
if (q->time_offset) {
|
||||||
|
INFO("Time offset adjustment: %d samples\n", q->time_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compute cumulative moving average time offset */
|
||||||
|
q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_total_cnt);
|
||||||
|
|
||||||
|
/* If the PSS peak is beyond the frame (we sample too slowly),
|
||||||
|
discard the offseted samples to align next frame */
|
||||||
|
if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) {
|
||||||
|
INFO("Positive time offset %d samples. Mean time offset %f.\n", q->time_offset, q->mean_time_offset);
|
||||||
|
if (q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset, &q->last_timestamp) < 0) {
|
||||||
|
fprintf(stderr, "Error receiving from USRP\n");
|
||||||
|
return LIBLTE_ERROR;
|
||||||
|
}
|
||||||
|
q->time_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
q->peak_idx = q->sf_len/2 + q->time_offset;
|
||||||
|
q->frame_ok_cnt++;
|
||||||
|
q->frame_no_cnt = 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,6 +456,13 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
|
||||||
-sync_get_cfo(&q->strack) / q->fft_size);
|
-sync_get_cfo(&q->strack) / q->fft_size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
if (track_idx > q->fft_size + q->strack.frame_size/2) {
|
||||||
|
*sf_symbols = &q->input_buffer[track_idx - q->fft_size - q->strack.frame_size/2];
|
||||||
|
} else {
|
||||||
|
*sf_symbols = q->input_buffer;
|
||||||
|
}
|
||||||
|
*/
|
||||||
*sf_symbols = q->input_buffer;
|
*sf_symbols = q->input_buffer;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 "liblte/phy/ue/ue_ul.h"
|
||||||
|
|
||||||
|
#include <complex.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb)
|
||||||
|
#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp)
|
||||||
|
|
||||||
|
#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)
|
||||||
|
#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp)
|
||||||
|
|
||||||
|
|
||||||
|
int ue_ul_init(ue_ul_t *q,
|
||||||
|
lte_cell_t cell)
|
||||||
|
{
|
||||||
|
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||||
|
|
||||||
|
if (q != NULL &&
|
||||||
|
lte_cell_isvalid(&cell))
|
||||||
|
{
|
||||||
|
ret = LIBLTE_ERROR;
|
||||||
|
|
||||||
|
bzero(q, sizeof(ue_ul_t));
|
||||||
|
|
||||||
|
q->cell = cell;
|
||||||
|
|
||||||
|
if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) {
|
||||||
|
fprintf(stderr, "Error initiating FFT\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
lte_fft_set_freq_shift(&q->fft, 0.5);
|
||||||
|
|
||||||
|
if (cfo_init(&q->cfo, CURRENT_SFLEN)) {
|
||||||
|
fprintf(stderr, "Error creating CFO object\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pusch_init(&q->pusch, q->cell)) {
|
||||||
|
fprintf(stderr, "Error creating PUSCH object\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
for (uint32_t i=0;i<NOF_HARQ_PROCESSES; i++) {
|
||||||
|
if (harq_init(&q->harq_process[i], q->cell)) {
|
||||||
|
fprintf(stderr, "Error initiating HARQ process\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (refsignal_ul_init(&q->drms, cell)) {
|
||||||
|
fprintf(stderr, "Error initiating refsignal_ul\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
q->sf_symbols = vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t));
|
||||||
|
if (!q->sf_symbols) {
|
||||||
|
perror("malloc");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
q->refsignal = vec_malloc(RE_X_RB * q->cell.nof_prb * sizeof(cf_t));
|
||||||
|
if (!q->refsignal) {
|
||||||
|
perror("malloc");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = LIBLTE_SUCCESS;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n",
|
||||||
|
cell.id, cell.nof_ports, cell.nof_prb);
|
||||||
|
}
|
||||||
|
|
||||||
|
clean_exit:
|
||||||
|
if (ret == LIBLTE_ERROR) {
|
||||||
|
ue_ul_free(q);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ue_ul_free(ue_ul_t *q) {
|
||||||
|
if (q) {
|
||||||
|
lte_fft_free(&q->fft);
|
||||||
|
pusch_free(&q->pusch);
|
||||||
|
for (uint32_t i=0;i<NOF_HARQ_PROCESSES; i++) {
|
||||||
|
harq_free(&q->harq_process[i]);
|
||||||
|
}
|
||||||
|
cfo_free(&q->cfo);
|
||||||
|
refsignal_ul_free(&q>drms);
|
||||||
|
if (q->sf_symbols) {
|
||||||
|
free(q->sf_symbols);
|
||||||
|
}
|
||||||
|
if (q->refsignal) {
|
||||||
|
free(q->refsignal);
|
||||||
|
}
|
||||||
|
bzero(q, sizeof(ue_ul_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ue_ul_set_cfo(ue_ul_t *q, float cur_cfo) {
|
||||||
|
q->current_cfo = cur_cfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while
|
||||||
|
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
|
||||||
|
* For the connection procedure, use pusch_encode_rnti() or pusch_decode_rnti() functions
|
||||||
|
*/
|
||||||
|
void ue_ul_set_rnti(ue_ul_t *q, uint16_t rnti) {
|
||||||
|
q->current_rnti = rnti;
|
||||||
|
pusch_set_rnti(&q->pusch, rnti);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ue_ul_reset(ue_ul_t *q) {
|
||||||
|
harq_reset(&q->harq_process[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ue_ul_set_pusch_cfg(ue_ul_t *q, refsignal_drms_pusch_cfg_t *pusch_drms_cfg, pusch_hopping_cfg_t *pusch_hopping_cfg)
|
||||||
|
{
|
||||||
|
pusch_set_hopping_cfg(&q->pusch, pusch_hopping_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ue_ul_pusch_encode(ue_ul_t *q, ra_pusch_t *ra_ul, uint8_t *data, uint32_t sf_idx, cf_t *output_signal)
|
||||||
|
{
|
||||||
|
uci_data_t uci_data;
|
||||||
|
bzero(&uci_data, sizeof(uci_data_t));
|
||||||
|
return ue_ul_pusch_uci_encode_rnti(q, ra_ul, data, uci_data, sf_idx, q->current_rnti, output_signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ue_ul_pusch_encode_rnti(ue_ul_t *q, ra_pusch_t *ra_ul, uint8_t *data, uint16_t rnti, uint32_t sf_idx, cf_t *output_signal)
|
||||||
|
{
|
||||||
|
uci_data_t uci_data;
|
||||||
|
bzero(&uci_data, sizeof(uci_data_t));
|
||||||
|
return ue_ul_pusch_uci_encode_rnti(q, ra_ul, data, uci_data, sf_idx, rnti, output_signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ue_ul_pusch_uci_encode(ue_ul_t *q, ra_pusch_t *ra_ul, uint8_t *data, uci_data_t uci_data, uint32_t sf_idx, cf_t *output_signal)
|
||||||
|
{
|
||||||
|
return ue_ul_pusch_uci_encode_rnti(q, ra_ul, data, uci_data, sf_idx, q->current_rnti, output_signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ue_ul_pusch_uci_encode_rnti(ue_ul_t *q, ra_pusch_t *ra_ul, uint8_t *data, uci_data_t uci_data,
|
||||||
|
uint32_t sf_idx, uint16_t rnti,
|
||||||
|
cf_t *output_signal)
|
||||||
|
{
|
||||||
|
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||||
|
|
||||||
|
if (q != NULL &&
|
||||||
|
ra_ul != NULL &&
|
||||||
|
data != NULL &&
|
||||||
|
output_signal != NULL)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (ra_ul->prb_alloc.L_prb == 0) {
|
||||||
|
fprintf(stderr, "Invalid UL PRB allocation (L_prb=0)\n" ;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = LIBLTE_ERROR;
|
||||||
|
|
||||||
|
if (harq_setup_ul(&q->harq_process[0], ra_ul->mcs, ra_ul->rv_idx, sf_idx, &ra_ul->prb_alloc)) {
|
||||||
|
fprintf(stderr, "Error configuring HARQ process\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pusch_encode_rnti(&q->pusch, &q->harq_process[0], data, rnti, q->sf_symbols)) {
|
||||||
|
fprintf(stderr, "Error encoding TB\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
q->pusch_drms_cfg.nof_prb = ra_ul->prb_alloc.L_prb;
|
||||||
|
|
||||||
|
for (uint32_t i=0;i<2;i++) {
|
||||||
|
// FIXME: Pregenerate for all possible number of prb
|
||||||
|
if (refsignal_dmrs_pusch_gen(&q->drms, &q->pusch_drms_cfg, 2*sf_idx+i, q->refsignal)) {
|
||||||
|
fprintf(stderr, "Error generating PUSCH DRMS signals\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
refsignal_drms_pusch_put(&q->drms, &q->pusch_drms_cfg, q->refsignal, i,
|
||||||
|
ra_ul->prb_alloc.n_prb_tilde[i], q->sf_symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
lte_ifft_run_sf(&q->fft, q->sf_symbols, output_signal);
|
||||||
|
|
||||||
|
cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / lte_symbol_sz(q->cell.nof_prb));
|
||||||
|
|
||||||
|
ret = LIBLTE_SUCCESS;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
clear
|
clear
|
||||||
ueConfig=struct('NCellID',0,'NULRB',25,'NSubframe',4,'RNTI',82,'CyclicPrefixUL','Normal','NTxAnts',1);
|
ueConfig=struct('NCellID',1,'NULRB',25,'NSubframe',4,'RNTI',82,'CyclicPrefixUL','Normal','NTxAnts',1);
|
||||||
puschConfig=struct('NLayers',1,'OrthCover','Off','PRBSet',[0 1 2]','Modulation','QPSK','RV',0,'Shortened',0);
|
puschConfig=struct('NLayers',1,'OrthCover','Off','PRBSet',[21:24]','Modulation','QPSK','RV',0,'Shortened',0);
|
||||||
|
|
||||||
addpath('../../debug/lte/phy/lib/phch/test')
|
addpath('../../debug/lte/phy/lib/phch/test')
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ addpath('../../debug/lte/phy/lib/phch/test')
|
||||||
% rvs=0;
|
% rvs=0;
|
||||||
% betas=0:3:11;
|
% betas=0:3:11;
|
||||||
|
|
||||||
TBs=56;
|
TBs=88;
|
||||||
cqilen=0;
|
cqilen=0;
|
||||||
mods={'QPSK'};
|
mods={'QPSK'};
|
||||||
rvs=0;
|
rvs=0;
|
||||||
|
|
Loading…
Reference in New Issue