mirror of https://github.com/pvnis/srsRAN_4G.git
Merge branch 'uplink'
commit
0c1e2eb53d
@ -0,0 +1,686 @@
|
||||
/**
|
||||
*
|
||||
* \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 <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include "liblte/rrc/rrc.h"
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
#include "cuhd_utils.h"
|
||||
|
||||
cell_search_cfg_t cell_detect_config = {
|
||||
5000,
|
||||
100, // nof_frames_total
|
||||
16.0 // threshold
|
||||
};
|
||||
|
||||
#define B210_DEFAULT_GAIN 40.0
|
||||
#define B210_DEFAULT_GAIN_CORREC 110.0 // Gain of the Rx chain when the gain is set to 40
|
||||
|
||||
float gain_offset = B210_DEFAULT_GAIN_CORREC;
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* Program arguments processing
|
||||
***********************************************************************/
|
||||
typedef struct {
|
||||
int nof_subframes;
|
||||
int force_N_id_2;
|
||||
uint32_t file_nof_prb;
|
||||
uint32_t preamble_idx;
|
||||
float beta_prach;
|
||||
float ta_usec;
|
||||
float beta_pusch;
|
||||
char *uhd_args;
|
||||
float uhd_rx_freq;
|
||||
float uhd_tx_freq;
|
||||
float uhd_tx_freq_offset;
|
||||
float uhd_tx_gain;
|
||||
float uhd_rx_gain;
|
||||
}prog_args_t;
|
||||
|
||||
void args_default(prog_args_t *args) {
|
||||
args->nof_subframes = -1;
|
||||
args->force_N_id_2 = -1; // Pick the best
|
||||
args->file_nof_prb = 6;
|
||||
args->beta_prach = 0.005;
|
||||
args->beta_pusch = 2.0;
|
||||
args->ta_usec = -1.0;
|
||||
args->preamble_idx = 7;
|
||||
args->uhd_args = "";
|
||||
args->uhd_rx_freq = 2112500000.0;
|
||||
args->uhd_tx_freq = 1922500000.0;
|
||||
args->uhd_tx_freq_offset = 8000000.0;
|
||||
args->uhd_tx_gain = 60.0;
|
||||
args->uhd_rx_gain = 60.0;
|
||||
}
|
||||
|
||||
void usage(prog_args_t *args, char *prog) {
|
||||
printf("Usage: %s [agfFbrlpnv]\n", prog);
|
||||
printf("\t-a UHD args [Default %s]\n", args->uhd_args);
|
||||
printf("\t-g UHD TX/RX gain [Default %.2f dB]\n", args->uhd_rx_gain);
|
||||
printf("\t-G UHD TX/RX gain [Default %.2f dB]\n", args->uhd_tx_gain);
|
||||
printf("\t-f UHD RX freq [Default %.1f MHz]\n", args->uhd_rx_freq/1000000);
|
||||
printf("\t-F UHD TX freq [Default %.1f MHz]\n", args->uhd_tx_freq/1000000);
|
||||
printf("\t-b beta PRACH (transmission amplitude) [Default %f]\n",args->beta_prach);
|
||||
printf("\t-B beta PUSCH (transmission amplitude) [Default %f]\n",args->beta_pusch);
|
||||
printf("\t-t TA usec (time advance, -1 from RAR) [Default %f]\n",args->ta_usec);
|
||||
printf("\t-p PRACH preamble idx [Default %d]\n",args->preamble_idx);
|
||||
printf("\t-l Force N_id_2 [Default best]\n");
|
||||
printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes);
|
||||
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, "agGfFplnvbBt")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
args->uhd_args = argv[optind];
|
||||
break;
|
||||
case 'b':
|
||||
args->beta_prach = atof(argv[optind]);
|
||||
break;
|
||||
case 'B':
|
||||
args->beta_pusch = atof(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
args->ta_usec = atof(argv[optind]);
|
||||
break;
|
||||
case 'g':
|
||||
args->uhd_rx_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'G':
|
||||
args->uhd_tx_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
args->uhd_rx_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 'F':
|
||||
args->uhd_tx_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
args->nof_subframes = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
args->preamble_idx = atoi(argv[optind]);
|
||||
break;
|
||||
case 'l':
|
||||
args->force_N_id_2 = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(args, argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (args->uhd_tx_freq < 0 && args->uhd_rx_freq < 0) {
|
||||
usage(args, argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
/**********************************************************************/
|
||||
|
||||
/* TODO: Do something with the output data */
|
||||
uint8_t data_rx[20000];
|
||||
|
||||
bool go_exit = false;
|
||||
|
||||
void sig_int_handler(int signo)
|
||||
{
|
||||
if (signo == SIGINT) {
|
||||
go_exit = true;
|
||||
}
|
||||
}
|
||||
|
||||
int cuhd_recv_wrapper_timed(void *h, void *data, uint32_t nsamples, timestamp_t *uhd_time) {
|
||||
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
|
||||
return cuhd_recv_with_time(h, data, nsamples, true, &uhd_time->full_secs, &uhd_time->frac_secs);
|
||||
}
|
||||
|
||||
extern float mean_exec_time;
|
||||
|
||||
enum receiver_state { DECODE_MIB, SEND_PRACH, RECV_RAR, RECV_CONNSETUP} state;
|
||||
|
||||
#define NOF_PRACH_SEQUENCES 52
|
||||
|
||||
ue_dl_t ue_dl;
|
||||
ue_ul_t ue_ul;
|
||||
ue_sync_t ue_sync;
|
||||
prach_t prach;
|
||||
int prach_buffer_len;
|
||||
|
||||
prog_args_t prog_args;
|
||||
|
||||
uint32_t sfn = 0; // system frame number
|
||||
cf_t *sf_buffer = NULL;
|
||||
|
||||
|
||||
|
||||
typedef enum{
|
||||
rar_tpc_n6dB = 0,
|
||||
rar_tpc_n4dB,
|
||||
rar_tpc_n2dB,
|
||||
rar_tpc_0dB,
|
||||
rar_tpc_2dB,
|
||||
rar_tpc_4dB,
|
||||
rar_tpc_6dB,
|
||||
rar_tpc_8dB,
|
||||
rar_tpc_n_items,
|
||||
}rar_tpc_command_t;
|
||||
static const char tpc_command_text[rar_tpc_n_items][8] = {"-6dB", "-4dB", "-2dB", "0dB", "2dB", "4dB", "6dB", "8dB"};
|
||||
typedef enum{
|
||||
rar_header_type_bi = 0,
|
||||
rar_header_type_rapid,
|
||||
rar_header_type_n_items,
|
||||
}rar_header_t;
|
||||
static const char rar_header_text[rar_header_type_n_items][8] = {"BI", "RAPID"};
|
||||
|
||||
typedef struct {
|
||||
rar_header_t hdr_type;
|
||||
bool hopping_flag;
|
||||
rar_tpc_command_t tpc_command;
|
||||
bool ul_delay;
|
||||
bool csi_req;
|
||||
uint16_t rba;
|
||||
uint16_t timing_adv_cmd;
|
||||
uint16_t temp_c_rnti;
|
||||
uint8_t mcs;
|
||||
uint8_t RAPID;
|
||||
uint8_t BI;
|
||||
}rar_msg_t;
|
||||
|
||||
char *bool_to_string(bool x) {
|
||||
if (x) {
|
||||
return "Enabled";
|
||||
} else {
|
||||
return "Disabled";
|
||||
}
|
||||
}
|
||||
|
||||
void rar_msg_fprint(FILE *stream, rar_msg_t *msg)
|
||||
{
|
||||
fprintf(stream, "Header type: %s\n", rar_header_text[msg->hdr_type]);
|
||||
fprintf(stream, "Hopping flag: %s\n", bool_to_string(msg->hopping_flag));
|
||||
fprintf(stream, "TPC command: %s\n", tpc_command_text[msg->tpc_command]);
|
||||
fprintf(stream, "UL delay: %s\n", bool_to_string(msg->ul_delay));
|
||||
fprintf(stream, "CSI required: %s\n", bool_to_string(msg->csi_req));
|
||||
fprintf(stream, "RBA: %d\n", msg->rba);
|
||||
fprintf(stream, "TA: %d\n", msg->timing_adv_cmd);
|
||||
fprintf(stream, "T-CRNTI: %d\n", msg->temp_c_rnti);
|
||||
fprintf(stream, "MCS: %d\n", msg->mcs);
|
||||
fprintf(stream, "RAPID: %d\n", msg->RAPID);
|
||||
fprintf(stream, "BI: %d\n", msg->BI);
|
||||
}
|
||||
|
||||
int rar_unpack(uint8_t *buffer, rar_msg_t *msg)
|
||||
{
|
||||
int ret = LIBLTE_ERROR;
|
||||
uint8_t *ptr = buffer;
|
||||
|
||||
if(buffer != NULL &&
|
||||
msg != NULL)
|
||||
{
|
||||
ptr++;
|
||||
msg->hdr_type = *ptr++;
|
||||
if(msg->hdr_type == rar_header_type_bi) {
|
||||
ptr += 2;
|
||||
msg->BI = bit_unpack(&ptr, 4);
|
||||
ret = LIBLTE_SUCCESS;
|
||||
} else if (msg->hdr_type == rar_header_type_rapid) {
|
||||
msg->RAPID = bit_unpack(&ptr, 6);
|
||||
ptr++;
|
||||
|
||||
msg->timing_adv_cmd = bit_unpack(&ptr, 11);
|
||||
msg->hopping_flag = *ptr++;
|
||||
msg->rba = bit_unpack(&ptr, 10);
|
||||
msg->mcs = bit_unpack(&ptr, 4);
|
||||
msg->tpc_command = (rar_tpc_command_t) bit_unpack(&ptr, 3);
|
||||
msg->ul_delay = *ptr++;
|
||||
msg->csi_req = *ptr++;
|
||||
msg->temp_c_rnti = bit_unpack(&ptr, 16);
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
#define kk
|
||||
#define use_usrp
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ret;
|
||||
lte_cell_t cell;
|
||||
int64_t sf_cnt;
|
||||
ue_mib_t ue_mib;
|
||||
void *uhd;
|
||||
int n;
|
||||
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN];
|
||||
uint32_t sfn_offset;
|
||||
rar_msg_t rar_msg;
|
||||
ra_pusch_t ra_pusch;
|
||||
uint32_t rar_window_start = 0, rar_trials = 0, rar_window_stop = 0;
|
||||
timestamp_t uhd_time;
|
||||
timestamp_t next_tx_time;
|
||||
const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6, 0x00, 0x00, 0x00};
|
||||
uint8_t data[1000];
|
||||
cf_t *prach_buffer;
|
||||
|
||||
parse_args(&prog_args, argc, argv);
|
||||
|
||||
#ifdef use_usrp
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(prog_args.uhd_args, &uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Set receiver gain */
|
||||
float x = cuhd_set_rx_gain(uhd, prog_args.uhd_rx_gain);
|
||||
printf("Set RX gain to %.1f dB\n", x);
|
||||
x = cuhd_set_tx_gain(uhd, prog_args.uhd_tx_gain);
|
||||
printf("Set TX gain to %.1f dB\n", x);
|
||||
|
||||
/* set receiver frequency */
|
||||
cuhd_set_rx_freq(uhd, (double) prog_args.uhd_rx_freq);
|
||||
cuhd_rx_wait_lo_locked(uhd);
|
||||
printf("Tunning RX receiver to %.3f MHz\n", (double ) prog_args.uhd_rx_freq/1000000);
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef kk
|
||||
ret = cuhd_search_and_decode_mib(uhd, &cell_detect_config, prog_args.force_N_id_2, &cell);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error searching for cell\n");
|
||||
exit(-1);
|
||||
} else if (ret == 0) {
|
||||
printf("Cell not found\n");
|
||||
exit(0);
|
||||
}
|
||||
#else
|
||||
cell.id = 1;
|
||||
cell.nof_ports = 1;
|
||||
cell.nof_prb = 25;
|
||||
cell.cp = CPNORM;
|
||||
cell.phich_length = PHICH_NORM;
|
||||
cell.phich_resources = R_1;
|
||||
#endif
|
||||
|
||||
#ifdef use_usrp
|
||||
|
||||
/* set sampling frequency */
|
||||
int srate = lte_sampling_freq_hz(cell.nof_prb);
|
||||
if (srate != -1) {
|
||||
cuhd_set_rx_srate(uhd, (double) srate);
|
||||
cuhd_set_tx_srate(uhd, (double) srate);
|
||||
} else {
|
||||
fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
INFO("Stopping UHD and flushing buffer...\r",0);
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
cuhd_flush_buffer(uhd);
|
||||
|
||||
#endif
|
||||
|
||||
if (ue_mib_init(&ue_mib, cell)) {
|
||||
fprintf(stderr, "Error initaiting UE MIB decoder\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (prach_init(&prach, lte_symbol_sz(cell.nof_prb), 0, 0, false, 1)) {
|
||||
fprintf(stderr, "Error initializing PRACH\n");
|
||||
exit(-1);
|
||||
}
|
||||
prach_buffer_len = prach.N_seq + prach.N_cp;
|
||||
prach_buffer = vec_malloc(prach_buffer_len*sizeof(cf_t));
|
||||
if(!prach_buffer) {
|
||||
perror("maloc");
|
||||
exit(-1);
|
||||
}
|
||||
if(prach_gen(&prach, prog_args.preamble_idx, 0, prog_args.beta_prach, prach_buffer)){
|
||||
fprintf(stderr, "Error generating prach sequence\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ue_ul_init(&ue_ul, cell)) {
|
||||
fprintf(stderr, "Error initiating UE UL\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
pusch_hopping_cfg_t hop_cfg;
|
||||
bzero(&hop_cfg, sizeof(pusch_hopping_cfg_t));
|
||||
refsignal_drms_pusch_cfg_t drms_cfg;
|
||||
bzero(&drms_cfg, sizeof(refsignal_drms_pusch_cfg_t));
|
||||
drms_cfg.beta_pusch = 1.0;
|
||||
drms_cfg.group_hopping_en = false;
|
||||
drms_cfg.sequence_hopping_en = false;
|
||||
drms_cfg.delta_ss = 0;
|
||||
drms_cfg.cyclic_shift = 0;
|
||||
drms_cfg.cyclic_shift_for_drms = 0;
|
||||
drms_cfg.en_drms_2 = false;
|
||||
ue_ul_set_pusch_cfg(&ue_ul, &drms_cfg, &hop_cfg);
|
||||
|
||||
cf_t *ul_signal = vec_malloc(sizeof(cf_t) * SF_LEN_PRB(cell.nof_prb));
|
||||
if (!ul_signal) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
bzero(ul_signal, sizeof(cf_t) * SF_LEN_PRB(cell.nof_prb));
|
||||
|
||||
if (ue_dl_init(&ue_dl, cell)) {
|
||||
fprintf(stderr, "Error initiating UE downlink processing module\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Initialize subframe counter */
|
||||
sf_cnt = 0;
|
||||
|
||||
|
||||
#ifdef use_usrp
|
||||
if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper_timed, uhd)) {
|
||||
fprintf(stderr, "Error initiating ue_sync\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cuhd_start_rx_stream(uhd);
|
||||
#endif
|
||||
|
||||
uint16_t ra_rnti;
|
||||
uint32_t conn_setup_trial = 0;
|
||||
uint32_t ul_sf_idx = 0;
|
||||
#ifdef kk
|
||||
// Register Ctrl+C handler
|
||||
signal(SIGINT, sig_int_handler);
|
||||
state = DECODE_MIB;
|
||||
#else
|
||||
state = RECV_RAR;
|
||||
#endif
|
||||
/* Main loop */
|
||||
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
|
||||
|
||||
#ifdef kk
|
||||
ret = ue_sync_get_buffer(&ue_sync, &sf_buffer);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error calling ue_sync_work()\n");
|
||||
}
|
||||
#else
|
||||
ret = 1;
|
||||
timestamp_t rx_time, tx_time;
|
||||
cf_t dummy[4];
|
||||
#endif
|
||||
|
||||
/* ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */
|
||||
if (ret == 1) {
|
||||
|
||||
if (state != RECV_RAR) {
|
||||
/* Run FFT for all subframe data */
|
||||
lte_fft_run_sf(&ue_dl.fft, sf_buffer, ue_dl.sf_symbols);
|
||||
|
||||
/* Get channel estimates for each port */
|
||||
chest_dl_estimate(&ue_dl.chest, ue_dl.sf_symbols, ue_dl.ce, ue_sync_get_sfidx(&ue_sync));
|
||||
}
|
||||
|
||||
if (sf_cnt > 1000) {
|
||||
switch (state) {
|
||||
case DECODE_MIB:
|
||||
if (ue_sync_get_sfidx(&ue_sync) == 0) {
|
||||
pbch_decode_reset(&ue_mib.pbch);
|
||||
n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error decoding UE MIB\n");
|
||||
exit(-1);
|
||||
} else if (n == MIB_FOUND) {
|
||||
bit_unpack_vector(bch_payload_unpacked, bch_payload, BCH_PAYLOAD_LEN);
|
||||
bcch_bch_unpack(bch_payload, BCH_PAYLOAD_LEN, &cell, &sfn);
|
||||
printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset);
|
||||
sfn = (sfn + sfn_offset)%1024;
|
||||
state = SEND_PRACH;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SEND_PRACH:
|
||||
|
||||
#ifdef kk
|
||||
if (((sfn%2) == 1) && (ue_sync_get_sfidx(&ue_sync) == 1)) {
|
||||
ue_sync_get_last_timestamp(&ue_sync, &uhd_time);
|
||||
|
||||
timestamp_copy(&next_tx_time, &uhd_time);
|
||||
timestamp_add(&next_tx_time, 0, 0.01); // send next frame (10 ms)
|
||||
printf("Send prach sfn: %d. Last frame time = %.6f, send prach time = %.6f\n",
|
||||
sfn, timestamp_real(&uhd_time), timestamp_real(&next_tx_time));
|
||||
|
||||
cuhd_send_timed(uhd, prach_buffer, prach_buffer_len,
|
||||
next_tx_time.full_secs, next_tx_time.frac_secs);
|
||||
|
||||
ra_rnti = 2;
|
||||
rar_window_start = sfn+1;
|
||||
rar_window_stop = sfn+3;
|
||||
state = RECV_RAR;
|
||||
}
|
||||
#else
|
||||
cuhd_recv_with_time(uhd, dummy, 4, 1, &rx_time.full_secs, &rx_time.frac_secs);
|
||||
|
||||
timestamp_copy(&tx_time, &rx_time);
|
||||
printf("Transmitting PRACH...\n");
|
||||
vec_save_file("prach_tx", prach_buffers[7], prach_buffer_len*sizeof(cf_t));
|
||||
while(1) {
|
||||
timestamp_add(&tx_time, 0, 0.001); // send every (10 ms)
|
||||
cuhd_send_timed(uhd, prach_buffers[7], prach_buffer_len,
|
||||
tx_time.full_secs, tx_time.frac_secs);
|
||||
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case RECV_RAR:
|
||||
#ifdef kk
|
||||
|
||||
if ((sfn == rar_window_start && ue_sync_get_sfidx(&ue_sync) > 3) || sfn > rar_window_start) {
|
||||
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, ue_sync_get_sfidx(&ue_sync), ra_rnti);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
|
||||
} else if (n > 0) {
|
||||
|
||||
rar_unpack(data_rx, &rar_msg);
|
||||
//if (rar_msg.RAPID != prog_args.preamble_idx) {
|
||||
// printf("Found RAR for sequence %d\n", rar_msg.RAPID);
|
||||
//} else {
|
||||
//cuhd_stop_rx_stream(uhd);
|
||||
//cuhd_flush_buffer(uhd);
|
||||
rar_msg_fprint(stdout, &rar_msg);
|
||||
|
||||
dci_rar_to_ra_ul(rar_msg.rba, rar_msg.mcs, rar_msg.hopping_flag, cell.nof_prb, &ra_pusch);
|
||||
ra_pusch_fprint(stdout, &ra_pusch, cell.nof_prb);
|
||||
|
||||
ra_ul_alloc(&ra_pusch.prb_alloc, &ra_pusch, 0, cell.nof_prb);
|
||||
|
||||
ue_sync_get_last_timestamp(&ue_sync, &uhd_time);
|
||||
|
||||
bit_pack_vector((uint8_t*) conn_request_msg, data, ra_pusch.mcs.tbs);
|
||||
|
||||
uint32_t n_ta = lte_N_ta_new_rar(rar_msg.timing_adv_cmd);
|
||||
printf("ta: %d, n_ta: %d\n", rar_msg.timing_adv_cmd, n_ta);
|
||||
float time_adv_sec = TA_OFFSET+((float) n_ta)*LTE_TS;
|
||||
if (prog_args.ta_usec >= 0) {
|
||||
time_adv_sec = prog_args.ta_usec*1e-6;
|
||||
}
|
||||
#define N_TX 1
|
||||
const uint32_t rv[N_TX]={0,2,3,1,0};
|
||||
for (int i=0; i<N_TX;i++) {
|
||||
ra_pusch.rv_idx = rv[i];
|
||||
ul_sf_idx = (ue_sync_get_sfidx(&ue_sync)+6+i*8)%10;
|
||||
|
||||
n = ue_ul_pusch_encode_rnti(&ue_ul, &ra_pusch, data, ul_sf_idx, rar_msg.temp_c_rnti, ul_signal);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error encoding PUSCH\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
vec_sc_prod_cfc(ul_signal, prog_args.beta_pusch, ul_signal, SF_LEN_PRB(cell.nof_prb));
|
||||
|
||||
timestamp_copy(&next_tx_time, &uhd_time);
|
||||
timestamp_add(&next_tx_time, 0, 0.006 + i*0.008 - time_adv_sec); // send after 6 sub-frames (6 ms)
|
||||
printf("Send %d samples PUSCH sfn: %d. RV_idx=%d, Last frame time = %.6f "
|
||||
"send PUSCH time = %.6f TA: %.1f us\n",
|
||||
SF_LEN_PRB(cell.nof_prb), sfn, ra_pusch.rv_idx,
|
||||
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),
|
||||
next_tx_time.full_secs, next_tx_time.frac_secs);
|
||||
|
||||
//cuhd_start_rx_stream(uhd);
|
||||
state = RECV_CONNSETUP;
|
||||
conn_setup_trial = 0;
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
if (sfn >= rar_window_stop) {
|
||||
state = SEND_PRACH;
|
||||
rar_trials++;
|
||||
if (rar_trials >= 1) {
|
||||
go_exit = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
ra_pusch.mcs.mod = LTE_QPSK;
|
||||
ra_pusch.mcs.tbs = 94;
|
||||
ra_pusch.rv_idx = 0;
|
||||
ra_pusch.prb_alloc.freq_hopping = 0;
|
||||
ra_pusch.prb_alloc.L_prb = 4;
|
||||
ra_pusch.prb_alloc.n_prb[0] = 19;
|
||||
ra_pusch.prb_alloc.n_prb[1] = 19;
|
||||
|
||||
uint32_t ul_sf_idx = 4;
|
||||
printf("L: %d\n", ra_pusch.prb_alloc.L_prb);
|
||||
// ue_ul_set_cfo(&ue_ul, sync_get_cfo(&ue_sync.strack));
|
||||
bit_pack_vector((uint8_t*) conn_request_msg, data, ra_pusch.mcs.tbs);
|
||||
n = ue_ul_pusch_encode_rnti(&ue_ul, &ra_pusch, data, ul_sf_idx, 111, ul_signal);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error encoding PUSCH\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
vec_save_file("pusch_tx", ul_signal, SF_LEN_PRB(cell.nof_prb)*sizeof(cf_t));
|
||||
|
||||
#ifdef use_usrp
|
||||
cuhd_recv_with_time(uhd, dummy, 4, 1, &uhd_time.full_secs, &uhd_time.frac_secs);
|
||||
timestamp_copy(&next_tx_time, &uhd_time);
|
||||
while(1) {
|
||||
timestamp_add(&next_tx_time, 0, 0.002); // send every 2 ms
|
||||
cuhd_send_timed(uhd, ul_signal, SF_LEN_PRB(cell.nof_prb),
|
||||
next_tx_time.full_secs, next_tx_time.frac_secs);
|
||||
}
|
||||
#else
|
||||
exit(-1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
case RECV_CONNSETUP:
|
||||
if (ue_sync_get_sfidx(&ue_sync) == (ul_sf_idx+4)%10) {
|
||||
//verbose=VERBOSE_DEBUG;
|
||||
vec_save_file("connsetup",sf_buffer,SF_LEN_PRB(cell.nof_prb)*sizeof(cf_t));
|
||||
} else {
|
||||
//verbose=VERBOSE_NONE;
|
||||
}
|
||||
printf("Looking for ConnectionSetup in sfn: %d sf_idx: %d, RNTI: %d\n", sfn, ue_sync_get_sfidx(&ue_sync),rar_msg.temp_c_rnti);
|
||||
n = ue_dl_decode_rnti(&ue_dl, sf_buffer, data_rx, ue_sync_get_sfidx(&ue_sync), rar_msg.temp_c_rnti);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
|
||||
} else if (n > 0) {
|
||||
printf("Received ConnectionSetup len: %d.\n", n);
|
||||
vec_fprint_hex(stdout, data_rx, n);
|
||||
} else {
|
||||
conn_setup_trial++;
|
||||
if (conn_setup_trial == 20) {
|
||||
go_exit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if (ue_sync_get_sfidx(&ue_sync) == 9) {
|
||||
sfn++;
|
||||
if (sfn == 1024) {
|
||||
sfn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (ret == 0) {
|
||||
printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r",
|
||||
sync_get_peak_value(&ue_sync.sfind),
|
||||
ue_sync.frame_total_cnt, ue_sync.state);
|
||||
}
|
||||
|
||||
sf_cnt++;
|
||||
} // Main loop
|
||||
|
||||
ue_dl_free(&ue_dl);
|
||||
ue_sync_free(&ue_sync);
|
||||
|
||||
ue_mib_free(&ue_mib);
|
||||
cuhd_close(uhd);
|
||||
printf("\nBye\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,53 @@
|
||||
/**
|
||||
*
|
||||
* \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 TIMESTAMP_
|
||||
#define TIMESTAMP_
|
||||
|
||||
#include <time.h>
|
||||
#include "liblte/config.h"
|
||||
|
||||
/*!
|
||||
* A simple timestamp struct with separate variables for full and frac seconds.
|
||||
*
|
||||
* Separate variables are used to avoid loss of precision in our frac seconds.
|
||||
* Only positive timestamps are supported.
|
||||
*/
|
||||
|
||||
typedef struct LIBLTE_API{
|
||||
time_t full_secs;
|
||||
double frac_secs;
|
||||
}timestamp_t;
|
||||
|
||||
LIBLTE_API int timestamp_init(timestamp_t *t, time_t full_secs, double frac_secs);
|
||||
LIBLTE_API int timestamp_copy(timestamp_t *dest, timestamp_t *src);
|
||||
LIBLTE_API int timestamp_add(timestamp_t *t, time_t full_secs, double frac_secs);
|
||||
LIBLTE_API int timestamp_sub(timestamp_t *t, time_t full_secs, double frac_secs);
|
||||
LIBLTE_API double timestamp_real(timestamp_t *t);
|
||||
|
||||
#endif // TIMESTAMP_
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
*
|
||||
* \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 DFTPREC_
|
||||
#define DFTPREC_
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/utils/dft.h"
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
/* DFT-based Transform Precoding object */
|
||||
typedef struct LIBLTE_API {
|
||||
|
||||
uint32_t max_prb;
|
||||
dft_plan_t dft_plan[MAX_PRB];
|
||||
dft_plan_t idft_plan[MAX_PRB];
|
||||
|
||||
}dft_precoding_t;
|
||||
|
||||
LIBLTE_API int dft_precoding_init(dft_precoding_t *q,
|
||||
uint32_t max_prb);
|
||||
|
||||
LIBLTE_API void dft_precoding_free(dft_precoding_t *q);
|
||||
|
||||
LIBLTE_API bool dft_precoding_valid_prb(uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API int dft_precoding(dft_precoding_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output,
|
||||
uint32_t nof_prb,
|
||||
uint32_t nof_symbols);
|
||||
|
||||
LIBLTE_API int dft_predecoding(dft_precoding_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output,
|
||||
uint32_t nof_prb,
|
||||
uint32_t nof_symbols);
|
||||
|
||||
#endif
|
@ -0,0 +1,94 @@
|
||||
/**
|
||||
*
|
||||
* \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 CQI_
|
||||
#define CQI_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
|
||||
/**
|
||||
* CQI message generation according to 36.212 Sections 5.2.2.6 and 5.2.3.3
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Table 5.2.2.6.2-1: Fields for channel quality information feedback for higher layer configured subband
|
||||
CQI reports
|
||||
(transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and
|
||||
transmission mode 8 configured without PMI/RI reporting). */
|
||||
typedef struct LIBLTE_API {
|
||||
uint8_t wideband_cqi; // 4-bit width
|
||||
uint32_t subband_diff_cqi; // 2N-bit width
|
||||
} cqi_hl_subband_t;
|
||||
|
||||
/* Table 5.2.2.6.3-1: Fields for channel quality information feedback for UE selected subband CQI
|
||||
reports
|
||||
(transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and
|
||||
transmission mode 8 configured without PMI/RI reporting). */
|
||||
typedef struct LIBLTE_API {
|
||||
uint8_t wideband_cqi; // 4-bit width
|
||||
uint8_t subband_diff_cqi; // 2-bit width
|
||||
uint32_t position_subband; // L-bit width
|
||||
} cqi_ue_subband_t;
|
||||
|
||||
/* Table 5.2.3.3.1-1: Fields for channel quality information feedback for wideband CQI reports
|
||||
(transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and
|
||||
transmission mode 8 configured without PMI/RI reporting).
|
||||
This is for PUCCH Format 2 reports
|
||||
*/
|
||||
typedef struct LIBLTE_API {
|
||||
uint8_t wideband_cqi; // 4-bit width
|
||||
} cqi_format2_wideband_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
uint8_t subband_cqi; // 4-bit width
|
||||
uint8_t subband_label; // 1- or 2-bit width
|
||||
} cqi_format2_subband_t;
|
||||
|
||||
|
||||
LIBLTE_API int cqi_hl_subband_pack(cqi_hl_subband_t *msg,
|
||||
uint32_t N,
|
||||
uint8_t *buff,
|
||||
uint32_t buff_len);
|
||||
|
||||
LIBLTE_API int cqi_ue_subband_pack(cqi_ue_subband_t *msg,
|
||||
uint32_t L,
|
||||
uint8_t *buff,
|
||||
uint32_t buff_len);
|
||||
|
||||
LIBLTE_API int cqi_format2_wideband_pack(cqi_format2_wideband_t *msg,
|
||||
uint8_t *buff,
|
||||
uint32_t buff_len);
|
||||
|
||||
LIBLTE_API int cqi_format2_subband_pack(cqi_format2_subband_t *msg,
|
||||
uint8_t *buff,
|
||||
uint32_t buff_len);
|
||||
|
||||
#endif // CQI_
|
@ -0,0 +1,91 @@
|
||||
/**
|
||||
*
|
||||
* \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 HARQ_
|
||||
#define HARQ_
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/phch/ra.h"
|
||||
|
||||
|
||||
struct cb_segm {
|
||||
uint32_t F;
|
||||
uint32_t C;
|
||||
uint32_t K1;
|
||||
uint32_t K2;
|
||||
uint32_t C1;
|
||||
uint32_t C2;
|
||||
};
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
ra_mcs_t mcs;
|
||||
uint32_t rv;
|
||||
uint32_t sf_idx;
|
||||
ra_dl_alloc_t dl_alloc;
|
||||
ra_ul_alloc_t ul_alloc;
|
||||
lte_cell_t cell;
|
||||
|
||||
uint32_t nof_re; // Number of RE per subframe
|
||||
uint32_t nof_bits; // Number of bits per subframe
|
||||
uint32_t nof_symb; // Number of symbols per subframe
|
||||
uint32_t nof_prb; // Number of allocated PRB per subframe.
|
||||
|
||||
uint32_t max_cb;
|
||||
uint32_t w_buff_size;
|
||||
float **pdsch_w_buff_f;
|
||||
uint8_t **pdsch_w_buff_c;
|
||||
|
||||
struct cb_segm cb_segm;
|
||||
|
||||
} harq_t;
|
||||
|
||||
LIBLTE_API int harq_init(harq_t * q,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API int harq_setup_dl(harq_t *p,
|
||||
ra_mcs_t mcs,
|
||||
uint32_t rv,
|
||||
uint32_t sf_idx,
|
||||
ra_dl_alloc_t *prb_alloc);
|
||||
|
||||
LIBLTE_API int harq_setup_ul(harq_t *p,
|
||||
ra_mcs_t mcs,
|
||||
uint32_t rv,
|
||||
uint32_t sf_idx,
|
||||
ra_ul_alloc_t *prb_alloc);
|
||||
|
||||
LIBLTE_API void harq_reset(harq_t *p);
|
||||
|
||||
LIBLTE_API void harq_free(harq_t *p);
|
||||
|
||||
LIBLTE_API int codeblock_segmentation(struct cb_segm *s,
|
||||
uint32_t tbs);
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,109 @@
|
||||
/**
|
||||
*
|
||||
* \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 PUCCH_
|
||||
#define PUCCH_
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/mimo/precoding.h"
|
||||
#include "liblte/phy/mimo/layermap.h"
|
||||
#include "liblte/phy/modem/mod.h"
|
||||
#include "liblte/phy/modem/demod_soft.h"
|
||||
#include "liblte/phy/scrambling/scrambling.h"
|
||||
#include "liblte/phy/phch/regs.h"
|
||||
#include "liblte/phy/phch/sch.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
#include "liblte/phy/filter/dft_precoding.h"
|
||||
|
||||
#define TDEC_MAX_ITERATIONS 5
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
#define PUCCH_N_SEQ 12 // Only Format 1, 1a and 1b supported
|
||||
#define PUCCH_MAX_BITS 2
|
||||
#define PUCCH_N_SF_MAX 4
|
||||
|
||||
typedef enum LIBLTE_API {
|
||||
PUCCH_FORMAT_1 = 0,
|
||||
PUCCH_FORMAT_1A,
|
||||
PUCCH_FORMAT_1B,
|
||||
PUCCH_FORMAT_2,
|
||||
PUCCH_FORMAT_2A,
|
||||
PUCCH_FORMAT_2B,
|
||||
} pucch_format_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
pucch_format_t format;
|
||||
float beta_pucch;
|
||||
uint32_t delta_pucch_shift;
|
||||
uint32_t n_pucch;
|
||||
uint32_t N_cs;
|
||||
} pucch_cfg_t;
|
||||
|
||||
/* PUSCH object */
|
||||
typedef struct LIBLTE_API {
|
||||
lte_cell_t cell;
|
||||
pucch_cfg_t pucch_cfg;
|
||||
|
||||
uint32_t n_cs_cell[NSLOTS_X_FRAME][CPNORM_NSYMB];
|
||||
float tmp_arg[PUCCH_N_SF_MAX*PUCCH_N_SEQ];
|
||||
float y[PUCCH_N_SEQ];
|
||||
}pucch_t;
|
||||
|
||||
|
||||
LIBLTE_API int pucch_init(pucch_t *q,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API void pucch_free(pucch_t *q);
|
||||
|
||||
LIBLTE_API void pucch_set_cfg(pucch_t *q,
|
||||
pucch_cfg_t *cfg);
|
||||
|
||||
LIBLTE_API int pucch_set_rnti(pucch_t *q,
|
||||
uint16_t rnti);
|
||||
|
||||
LIBLTE_API int pucch_encode(pucch_t *q,
|
||||
pucch_cfg_t *cfg,
|
||||
uint8_t bits[PUCCH_MAX_BITS],
|
||||
cf_t *sf_symbols);
|
||||
|
||||
LIBLTE_API float pucch_get_alpha(uint32_t n_cs_cell[NSLOTS_X_FRAME][CPNORM_NSYMB],
|
||||
pucch_cfg_t *cfg,
|
||||
lte_cp_t cp,
|
||||
bool is_drms,
|
||||
uint32_t ns,
|
||||
uint32_t l,
|
||||
uint32_t *n_oc);
|
||||
|
||||
LIBLTE_API int generate_n_cs_cell(lte_cell_t cell,
|
||||
uint32_t n_cs_cell[NSLOTS_X_FRAME][CPNORM_NSYMB]);
|
||||
|
||||
LIBLTE_API bool pucch_cfg_isvalid(pucch_cfg_t *cfg);
|
||||
|
||||
#endif
|
@ -0,0 +1,140 @@
|
||||
/**
|
||||
*
|
||||
* \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 PUSCH_
|
||||
#define PUSCH_
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/mimo/precoding.h"
|
||||
#include "liblte/phy/mimo/layermap.h"
|
||||
#include "liblte/phy/modem/mod.h"
|
||||
#include "liblte/phy/modem/demod_soft.h"
|
||||
#include "liblte/phy/scrambling/scrambling.h"
|
||||
#include "liblte/phy/phch/regs.h"
|
||||
#include "liblte/phy/phch/sch.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
#include "liblte/phy/filter/dft_precoding.h"
|
||||
|
||||
#define TDEC_MAX_ITERATIONS 5
|
||||
|
||||
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 */
|
||||
typedef struct LIBLTE_API {
|
||||
lte_cell_t cell;
|
||||
|
||||
pusch_hopping_cfg_t hopping_cfg;
|
||||
|
||||
uint32_t max_re;
|
||||
bool rnti_is_set;
|
||||
uint16_t rnti;
|
||||
|
||||
dft_precoding_t dft_precoding;
|
||||
|
||||
precoding_t equalizer;
|
||||
|
||||
/* buffers */
|
||||
// void buffers are shared for tx and rx
|
||||
cf_t *ce;
|
||||
cf_t *pusch_z;
|
||||
cf_t *pusch_d;
|
||||
|
||||
void *pusch_q;
|
||||
void *pusch_g;
|
||||
|
||||
/* tx & rx objects */
|
||||
modem_table_t mod[4];
|
||||
demod_soft_t demod;
|
||||
sequence_t seq_pusch[NSUBFRAMES_X_FRAME];
|
||||
sequence_t seq_type2_fo;
|
||||
|
||||
sch_t dl_sch;
|
||||
|
||||
}pusch_t;
|
||||
|
||||
|
||||
LIBLTE_API int pusch_init(pusch_t *q,
|
||||
lte_cell_t cell);
|
||||
|
||||
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,
|
||||
uint16_t rnti);
|
||||
|
||||
LIBLTE_API int pusch_encode(pusch_t *q,
|
||||
harq_t *harq_process,
|
||||
uint8_t *data,
|
||||
cf_t *sf_symbols);
|
||||
|
||||
LIBLTE_API int pusch_encode_rnti(pusch_t *q,
|
||||
harq_t *harq_process,
|
||||
uint8_t *data,
|
||||
uint16_t rnti,
|
||||
cf_t *sf_symbols);
|
||||
|
||||
LIBLTE_API int pusch_uci_encode(pusch_t *q,
|
||||
harq_t *harq_process,
|
||||
uint8_t *data,
|
||||
uci_data_t uci_data,
|
||||
cf_t *sf_symbols);
|
||||
|
||||
LIBLTE_API int pusch_uci_encode_rnti(pusch_t *q,
|
||||
harq_t *harq,
|
||||
uint8_t *data,
|
||||
uci_data_t uci_data,
|
||||
uint16_t rnti,
|
||||
cf_t *sf_symbols);
|
||||
|
||||
LIBLTE_API int pusch_decode(pusch_t *q,
|
||||
harq_t *harq_process,
|
||||
cf_t *sf_symbols,
|
||||
cf_t *ce,
|
||||
float noise_estimate,
|
||||
uint8_t *data);
|
||||
|
||||
LIBLTE_API float pusch_average_noi(pusch_t *q);
|
||||
|
||||
LIBLTE_API uint32_t pusch_last_noi(pusch_t *q);
|
||||
|
||||
#endif
|
@ -0,0 +1,109 @@
|
||||
/**
|
||||
*
|
||||
* \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 SCH_
|
||||
#define SCH_
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/fec/rm_turbo.h"
|
||||
#include "liblte/phy/fec/turbocoder.h"
|
||||
#include "liblte/phy/fec/turbodecoder.h"
|
||||
#include "liblte/phy/fec/crc.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
#include "liblte/phy/phch/uci.h"
|
||||
|
||||
#define TDEC_MAX_ITERATIONS 5
|
||||
|
||||
|
||||
#ifndef RX_NULL
|
||||
#define RX_NULL 10000
|
||||
#endif
|
||||
|
||||
#ifndef TX_NULL
|
||||
#define TX_NULL 100
|
||||
#endif
|
||||
|
||||
/* DL-SCH AND UL-SCH common functions */
|
||||
typedef struct LIBLTE_API {
|
||||
|
||||
uint32_t nof_iterations;
|
||||
float average_nof_iterations;
|
||||
|
||||
/* buffers */
|
||||
uint8_t *cb_in;
|
||||
void *cb_out;
|
||||
void *pdsch_e;
|
||||
|
||||
tcod_t encoder;
|
||||
tdec_t decoder;
|
||||
crc_t crc_tb;
|
||||
crc_t crc_cb;
|
||||
|
||||
uci_cqi_pusch_t uci_cqi;
|
||||
|
||||
} sch_t;
|
||||
|
||||
LIBLTE_API int sch_init(sch_t *q);
|
||||
|
||||
LIBLTE_API void sch_free(sch_t *q);
|
||||
|
||||
|
||||
LIBLTE_API float sch_average_noi(sch_t *q);
|
||||
|
||||
LIBLTE_API uint32_t sch_last_noi(sch_t *q);
|
||||
|
||||
LIBLTE_API int dlsch_encode(sch_t *q,
|
||||
harq_t *harq_process,
|
||||
uint8_t *data,
|
||||
uint8_t *e_bits);
|
||||
|
||||
LIBLTE_API int dlsch_decode(sch_t *q,
|
||||
harq_t *harq_process,
|
||||
float *e_bits,
|
||||
uint8_t *data);
|
||||
|
||||
LIBLTE_API int ulsch_encode(sch_t *q,
|
||||
harq_t *harq_process,
|
||||
uint8_t *data,
|
||||
uint8_t *g_bits,
|
||||
uint8_t *q_bits);
|
||||
|
||||
LIBLTE_API int ulsch_uci_encode(sch_t *q,
|
||||
harq_t *harq_process,
|
||||
uint8_t *data,
|
||||
uci_data_t uci_data,
|
||||
uint8_t *g_bits,
|
||||
uint8_t *q_bits);
|
||||
|
||||
LIBLTE_API int ulsch_decode(sch_t *q,
|
||||
harq_t *harq_process,
|
||||
float *e_bits,
|
||||
uint8_t *data);
|
||||
|
||||
#endif
|
@ -0,0 +1,91 @@
|
||||
/**
|
||||
*
|
||||
* \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 UCI_
|
||||
#define UCI_
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
#include "liblte/phy/fec/crc.h"
|
||||
|
||||
#define MAX_CQI_LEN_PUSCH 512
|
||||
#define MAX_CQI_LEN_PUCCH 13
|
||||
#define CQI_CODED_PUCCH_B 20
|
||||
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
crc_t crc;
|
||||
uint8_t tmp_cqi[MAX_CQI_LEN_PUSCH];
|
||||
uint8_t encoded_cqi[3*MAX_CQI_LEN_PUSCH];
|
||||
} uci_cqi_pusch_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
uint8_t *uci_cqi;
|
||||
uint32_t uci_cqi_len;
|
||||
float beta_cqi;
|
||||
uint8_t uci_ri; // Only 1-bit supported for RI
|
||||
uint32_t uci_ri_len;
|
||||
float beta_ri;
|
||||
uint8_t uci_ack; // Only 1-bit supported for HARQ
|
||||
uint32_t uci_ack_len;
|
||||
float beta_ack;
|
||||
} uci_data_t;
|
||||
|
||||
LIBLTE_API int uci_cqi_init(uci_cqi_pusch_t *q);
|
||||
|
||||
LIBLTE_API void uci_cqi_free(uci_cqi_pusch_t *q);
|
||||
|
||||
LIBLTE_API int uci_encode_cqi_pusch(uci_cqi_pusch_t *q,
|
||||
uint8_t *cqi_data,
|
||||
uint32_t cqi_len,
|
||||
float beta,
|
||||
uint32_t Q_prime_ri,
|
||||
harq_t *harq_process,
|
||||
uint8_t *q_bits);
|
||||
|
||||
LIBLTE_API int uci_encode_cqi_pucch(uint8_t *cqi_data,
|
||||
uint32_t cqi_len,
|
||||
uint8_t b_bits[CQI_CODED_PUCCH_B]);
|
||||
|
||||
LIBLTE_API int uci_encode_ack(uint8_t data,
|
||||
uint32_t O_cqi,
|
||||
float beta,
|
||||
harq_t *harq_process,
|
||||
uint32_t H_prime_total,
|
||||
uint8_t *q_bits);
|
||||
|
||||
LIBLTE_API int uci_encode_ri(uint8_t data,
|
||||
uint32_t O_cqi,
|
||||
float beta,
|
||||
harq_t *harq_process,
|
||||
uint32_t H_prime_total,
|
||||
uint8_t *q_bits);
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,6 @@
|
||||
|
||||
class ue_mac_itf
|
||||
{
|
||||
public:
|
||||
virtual void ready_to_send() = 0;
|
||||
};
|
@ -0,0 +1,202 @@
|
||||
/**
|
||||
*
|
||||
* \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 "ue_mac_itf.h"
|
||||
#include "liblte/phy/utils/queue.h"
|
||||
|
||||
#ifndef UEPHY_H
|
||||
#define UEPHY_H
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
class ue_phy
|
||||
{
|
||||
public:
|
||||
|
||||
class pdcch_ul_search : public queue::element {
|
||||
public:
|
||||
set_crnti(uint16_t rnti);
|
||||
set_crnti_ra_procedure(uint16_t rnti);
|
||||
set_sps_crnti(uint16_t rnti);
|
||||
set_temporal_crnti(uint16_t rnti);
|
||||
set_tpc_pusch(uint16_t rnti);
|
||||
set_tpc_pucch(uint16_t rnti);
|
||||
private:
|
||||
uint16_t rnti;
|
||||
bool is_crnti = false;
|
||||
bool is_crnti_ra_procedure = false;
|
||||
bool is_sps_crnti = false;
|
||||
bool is_t_crnti = false;
|
||||
bool is_tpc_pusch = false;
|
||||
bool is_tpc_pucch = false;
|
||||
};
|
||||
|
||||
class pdcch_dl_search : public queue::element {
|
||||
public:
|
||||
set_crnti(uint16_t rnti);
|
||||
set_crnti_ra_procedure(uint16_t rnti);
|
||||
set_sps_crnti(uint16_t rnti);
|
||||
set_temporal_crnti(uint16_t rnti);
|
||||
set_tpc_pusch(uint16_t rnti);
|
||||
set_tpc_pucch(uint16_t rnti);
|
||||
private:
|
||||
uint16_t rnti;
|
||||
bool is_crnti = false;
|
||||
bool is_crnti_ra_procedure = false;
|
||||
bool is_sps_crnti = false;
|
||||
bool is_t_crnti = false;
|
||||
bool is_tpc_pusch = false;
|
||||
bool is_tpc_pucch = false;
|
||||
};
|
||||
|
||||
class ul_allocation {
|
||||
|
||||
};
|
||||
|
||||
class ul_assignment : public queue::element {
|
||||
public:
|
||||
ul_assignment(uint32_t nof_prb, uint32_t max_ulsch_bits);
|
||||
void set_allocation(ul_allocation allocation);
|
||||
uint8_t* get_ulsch_buffer();
|
||||
cf_t* get_signal_buffer();
|
||||
void set_uci_data();
|
||||
void generate_signal();
|
||||
private:
|
||||
cf_t* signal_buffer = NULL;
|
||||
uint8_t* ulsch_buffer;
|
||||
ul_allocation allocation;
|
||||
};
|
||||
|
||||
class dl_allocation {
|
||||
|
||||
};
|
||||
|
||||
class dl_assignment : public queue::element {
|
||||
public:
|
||||
void set_allocation(dl_allocation allocation);
|
||||
private:
|
||||
dl_allocation allocation;
|
||||
};
|
||||
|
||||
class phich_assignment {
|
||||
|
||||
};
|
||||
|
||||
class phich_assignment : public queue::element {
|
||||
public:
|
||||
phich_assignment();
|
||||
void set_allocation(phich_assignment assignment);
|
||||
private:
|
||||
phich_assignment assignment;
|
||||
};
|
||||
|
||||
class dl_tb : public queue::element {
|
||||
public:
|
||||
dl_tb(uint32_t max_dlsch_bits);
|
||||
uint16_t get_rnti();
|
||||
bool is_crc_valid();
|
||||
uint8_t* get_dlsch_payload();
|
||||
private:
|
||||
uint8_t* dlsch_buffer;
|
||||
uint16_t rnti;
|
||||
bool crc_result;
|
||||
};
|
||||
|
||||
class dl_grant : public queue::element {
|
||||
public:
|
||||
dl_allocation get_allocation();
|
||||
private:
|
||||
dl_allocation allocation;
|
||||
};
|
||||
|
||||
class ul_grant : public queue::element {
|
||||
public:
|
||||
ul_allocation get_allocation();
|
||||
private:
|
||||
ul_allocation allocation;
|
||||
|
||||
};
|
||||
|
||||
class ul_ack : public queue::element {
|
||||
public:
|
||||
bool get_ack();
|
||||
private:
|
||||
bool ack;
|
||||
};
|
||||
|
||||
class rx_buffer : public queue::element {
|
||||
public:
|
||||
rx_buffer(uint32_t nof_prb);
|
||||
cf_t* get_signal_buffer();
|
||||
private:
|
||||
uint32_t nof_prb;
|
||||
cf_t* signal_buffer;
|
||||
};
|
||||
|
||||
ue_phy(ue_mac_itf *mac);
|
||||
~ue_phy();
|
||||
|
||||
void measure(); // TBD
|
||||
void dl_bch();
|
||||
void start_rxtx();
|
||||
void stop_rxtx();
|
||||
void init_prach();
|
||||
void send_prach(/* prach_cfg_t in prach.h with power, seq idx, etc */);
|
||||
void set_param();
|
||||
|
||||
pdcch_ul_search* get_pdcch_ul_search(uint32_t tti);
|
||||
pdcch_dl_search* get_pdcch_dl_search(uint32_t tti);
|
||||
ul_assignment* get_ul_assignment(uint32_t tti);
|
||||
dl_assignment* get_dl_assignment(uint32_t tti);
|
||||
phich_assignment* get_phich_assignment(uint32_t tti);
|
||||
dl_tb* get_dl_tb(uint32_t tti);
|
||||
dl_grant* get_dl_grant(uint32_t tti);
|
||||
ul_grant* get_ul_grant(uint32_t tti);
|
||||
ul_ack* get_ul_ack(uint32_t tti);
|
||||
|
||||
private:
|
||||
enum {
|
||||
IDLE, MEASURE, RX_BCH, RXTX
|
||||
} phy_state;
|
||||
|
||||
bool prach_initiated = false;
|
||||
bool prach_ready_to_send = false;
|
||||
|
||||
queue pdcch_ul_search;
|
||||
queue pdcch_dl_search;
|
||||
queue ul_assignment;
|
||||
queue dl_assignment;
|
||||
queue phich_assignment;
|
||||
queue dl_tb;
|
||||
queue dl_grant;
|
||||
queue ul_grant;
|
||||
queue ul_grant;
|
||||
queue rx_buffer;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,122 @@
|
||||
/**
|
||||
*
|
||||
* \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/common/phy_common.h"
|
||||
#include "liblte/phy/ch_estimation/chest_dl.h"
|
||||
#include "liblte/phy/common/fft.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;
|
||||
|
||||
bool normalize_en;
|
||||
|
||||
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_normalization(ue_ul_t *q,
|
||||
bool enabled);
|
||||
|
||||
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,
|
||||
uint32_t sf_idx,
|
||||
cf_t *output_signal);
|
||||
|
||||
LIBLTE_API int ue_ul_pusch_encode_rnti(ue_ul_t *q,
|
||||
ra_pusch_t *ra_ul,
|
||||
uint8_t *data,
|
||||
uint32_t sf_idx,
|
||||
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,
|
||||
uint32_t sf_idx,
|
||||
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,
|
||||
uint32_t sf_idx,
|
||||
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
|
@ -0,0 +1,84 @@
|
||||
/**
|
||||
*
|
||||
* \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 "ue_mac_itf.h"
|
||||
|
||||
#ifndef QUEUE_H
|
||||
#define QUEUE_H
|
||||
|
||||
class queue
|
||||
{
|
||||
public:
|
||||
|
||||
class element
|
||||
{
|
||||
public:
|
||||
~element();
|
||||
bool release()
|
||||
{
|
||||
if (state == READY) {
|
||||
state = RELEASED;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool is_released()
|
||||
{
|
||||
return state == RELEASED;
|
||||
}
|
||||
bool ready_to_send() {
|
||||
if (state == RELEASED) {
|
||||
state = READY;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool is_ready_to_send() {
|
||||
return state == READY;
|
||||
}
|
||||
|
||||
protected:
|
||||
enum {
|
||||
RELEASED, READY
|
||||
} state;
|
||||
}
|
||||
|
||||
queue(uint32_t nof_elements, uint32_t element_size);
|
||||
~queue();
|
||||
|
||||
element* get(uint32_t idx);
|
||||
|
||||
private:
|
||||
uint32_t nof_elements;
|
||||
uint32_t element_size;
|
||||
void **buffer_of_elements;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -1,249 +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 <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <complex.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
lte_cell_t cell = {
|
||||
6, // nof_prb
|
||||
MAX_PORTS, // nof_ports
|
||||
1000, // cell_id
|
||||
CPNORM // cyclic prefix
|
||||
};
|
||||
|
||||
uint8_t *output_matlab = NULL;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [recov]\n", prog);
|
||||
|
||||
printf("\t-r nof_prb [Default %d]\n", cell.nof_prb);
|
||||
printf("\t-e extended cyclic prefix [Default normal]\n");
|
||||
|
||||
printf("\t-c cell_id (1000 tests all). [Default %d]\n", cell.id);
|
||||
|
||||
printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None");
|
||||
printf("\t-v increase verbosity\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "recov")) != -1) {
|
||||
switch(opt) {
|
||||
case 'r':
|
||||
cell.nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 'e':
|
||||
cell.cp = CPEXT;
|
||||
break;
|
||||
case 'c':
|
||||
cell.id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'o':
|
||||
output_matlab = argv[optind];
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int check_mse(float mod, float arg, int n_port) {
|
||||
INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port);
|
||||
switch(n_port) {
|
||||
case 0:
|
||||
if (mod > 0.029) {
|
||||
return -1;
|
||||
}
|
||||
if (arg > 0.029) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (mod > 0.012) {
|
||||
return -1;
|
||||
}
|
||||
if (arg > 0.012) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (mod > 3.33) {
|
||||
return -1;
|
||||
}
|
||||
if (arg > 0.63) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
chest_t eq;
|
||||
cf_t *input = NULL, *ce = NULL, *h = NULL;
|
||||
refsignal_t refs;
|
||||
int i, j, n_port, n_slot, cid, num_re;
|
||||
int ret = -1;
|
||||
int max_cid;
|
||||
FILE *fmatlab = NULL;
|
||||
float mse_mag, mse_phase;
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (output_matlab) {
|
||||
fmatlab=fopen(output_matlab, "w");
|
||||
if (!fmatlab) {
|
||||
perror("fopen");
|
||||
goto do_exit;
|
||||
}
|
||||
}
|
||||
|
||||
num_re = cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp);
|
||||
|
||||
input = malloc(num_re * sizeof(cf_t));
|
||||
if (!input) {
|
||||
perror("malloc");
|
||||
goto do_exit;
|
||||
}
|
||||
h = malloc(num_re * sizeof(cf_t));
|
||||
if (!h) {
|
||||
perror("malloc");
|
||||
goto do_exit;
|
||||
}
|
||||
ce = malloc(num_re * sizeof(cf_t));
|
||||
if (!ce) {
|
||||
perror("malloc");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
if (cell.id == 1000) {
|
||||
cid = 0;
|
||||
max_cid = 504;
|
||||
} else {
|
||||
cid = cell.id;
|
||||
max_cid = cell.id;
|
||||
}
|
||||
|
||||
while(cid <= max_cid) {
|
||||
cell.id = cid;
|
||||
if (chest_init_LTEUL(&eq, cell)) {
|
||||
fprintf(stderr, "Error initializing equalizer\n");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) {
|
||||
for (n_port=0;n_port<cell.nof_ports;n_port++) {
|
||||
|
||||
if (refsignal_init_LTEDL(&refs, n_port, n_slot, cell)) {
|
||||
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bzero(input, sizeof(cf_t) * num_re);
|
||||
for (i=0;i<num_re;i++) {
|
||||
input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX);
|
||||
}
|
||||
|
||||
bzero(ce, sizeof(cf_t) * num_re);
|
||||
bzero(h, sizeof(cf_t) * num_re);
|
||||
|
||||
refsignal_put(&refs, input);
|
||||
|
||||
for (i=0;i<CP_NSYMB(cell.cp);i++) {
|
||||
for (j=0;j<cell.nof_prb * RE_X_RB;j++) {
|
||||
float x = -1+(float) i/CP_NSYMB(cell.cp) + cosf(2 * M_PI * (float) j/cell.nof_prb/RE_X_RB);
|
||||
h[i*cell.nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
|
||||
input[i*cell.nof_prb * RE_X_RB+j] *= h[i*cell.nof_prb * RE_X_RB+j];
|
||||
}
|
||||
}
|
||||
|
||||
chest_ce_slot_port(&eq, input, ce, n_slot, n_port);
|
||||
|
||||
mse_mag = mse_phase = 0;
|
||||
for (i=0;i<num_re;i++) {
|
||||
mse_mag += (cabsf(h[i]) - cabsf(ce[i])) * (cabsf(h[i]) - cabsf(ce[i])) / num_re;
|
||||
mse_phase += (cargf(h[i]) - cargf(ce[i])) * (cargf(h[i]) - cargf(ce[i])) / num_re;
|
||||
}
|
||||
|
||||
if (check_mse(mse_mag, mse_phase, n_port)) {
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
if (fmatlab) {
|
||||
fprintf(fmatlab, "input=");
|
||||
vec_fprint_c(fmatlab, input, num_re);
|
||||
fprintf(fmatlab, ";\n");
|
||||
fprintf(fmatlab, "h=");
|
||||
vec_fprint_c(fmatlab, h, num_re);
|
||||
fprintf(fmatlab, ";\n");
|
||||
fprintf(fmatlab, "ce=");
|
||||
vec_fprint_c(fmatlab, ce, num_re);
|
||||
fprintf(fmatlab, ";\n");
|
||||
chest_fprint(&eq, fmatlab, n_slot, n_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
chest_free(&eq);
|
||||
cid+=10;
|
||||
INFO("cid=%d\n", cid);
|
||||
}
|
||||
|
||||
|
||||
ret = 0;
|
||||
|
||||
do_exit:
|
||||
|
||||
if (ce) {
|
||||
free(ce);
|
||||
}
|
||||
if (input) {
|
||||
free(input);
|
||||
}
|
||||
if (h) {
|
||||
free(h);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
printf("OK\n");
|
||||
} else {
|
||||
printf("Error at cid=%d, slot=%d, port=%d\n",cid, n_slot, n_port);
|
||||
}
|
||||
|
||||
exit(ret);
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
/**
|
||||
*
|
||||
* \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 "liblte/phy/phy.h"
|
||||
#include "liblte/mex/mexutils.h"
|
||||
|
||||
/** MEX function to be called from MATLAB to test the channel estimator
|
||||
*/
|
||||
|
||||
#define UECFG prhs[0]
|
||||
#define PUSCHCFG prhs[1]
|
||||
#define NOF_INPUTS 2
|
||||
|
||||
void help()
|
||||
{
|
||||
mexErrMsgTxt
|
||||
("[seq] = liblte_refsignal_pusch(ueConfig, puschConfig)\n\n");
|
||||
}
|
||||
|
||||
extern int indices[2048];
|
||||
|
||||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
lte_cell_t cell;
|
||||
refsignal_ul_t refs;
|
||||
refsignal_drms_pusch_cfg_t pusch_cfg;
|
||||
uint32_t sf_idx;
|
||||
|
||||
if (nrhs != NOF_INPUTS) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) {
|
||||
mexErrMsgTxt("Field NCellID not found in UE config\n");
|
||||
return;
|
||||
}
|
||||
if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) {
|
||||
mexErrMsgTxt("Field NCellID not found in UE config\n");
|
||||
return;
|
||||
}
|
||||
cell.cp = CPNORM;
|
||||
cell.nof_ports = 1;
|
||||
|
||||
if (mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx)) {
|
||||
mexErrMsgTxt("Field NSubframe not found in UE config\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bzero(&pusch_cfg, sizeof(refsignal_drms_pusch_cfg_t));
|
||||
|
||||
|
||||
pusch_cfg.group_hopping_en = false;
|
||||
pusch_cfg.sequence_hopping_en = false;
|
||||
char *tmp = mexutils_get_char_struct(UECFG, "Hopping");
|
||||
if (tmp) {
|
||||
if (!strcmp(tmp, "Group")) {
|
||||
pusch_cfg.group_hopping_en = true;
|
||||
} else if (!strcmp(tmp, "Sequence")) {
|
||||
pusch_cfg.sequence_hopping_en = true;
|
||||
}
|
||||
mxFree(tmp);
|
||||
}
|
||||
|
||||
|
||||
if (mexutils_read_uint32_struct(UECFG, "SeqGroup", &pusch_cfg.delta_ss)) {
|
||||
pusch_cfg.delta_ss = 0;
|
||||
}
|
||||
if (mexutils_read_uint32_struct(UECFG, "CyclicShift", &pusch_cfg.cyclic_shift)) {
|
||||
pusch_cfg.cyclic_shift = 0;
|
||||
}
|
||||
float *prbset;
|
||||
mxArray *p;
|
||||
p = mxGetField(PUSCHCFG, 0, "PRBSet");
|
||||
if (!p) {
|
||||
mexErrMsgTxt("Error field PRBSet not found in PUSCH config\n");
|
||||
return;
|
||||
}
|
||||
uint32_t nof_prb = mexutils_read_f(p, &prbset);
|
||||
|
||||
if (mexutils_read_uint32_struct(PUSCHCFG, "DynCyclicShift", &pusch_cfg.cyclic_shift_for_drms)) {
|
||||
pusch_cfg.cyclic_shift_for_drms = 0;
|
||||
pusch_cfg.en_drms_2 = false;
|
||||
} else {
|
||||
pusch_cfg.en_drms_2 = true;
|
||||
}
|
||||
|
||||
pusch_cfg.beta_pusch = 1.0;
|
||||
|
||||
if (refsignal_ul_init(&refs, cell)) {
|
||||
mexErrMsgTxt("Error initiating refsignal_ul\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mexPrintf("nof_prb: %d, ",nof_prb);
|
||||
mexPrintf("cyclic_shift: %d, ",pusch_cfg.cyclic_shift);
|
||||
mexPrintf("cyclic_shift_for_drms: %d, ",pusch_cfg.cyclic_shift_for_drms);
|
||||
mexPrintf("delta_ss: %d, ",pusch_cfg.delta_ss);
|
||||
|
||||
cf_t *signal = vec_malloc(2*RE_X_RB*nof_prb*sizeof(cf_t));
|
||||
if (!signal) {
|
||||
perror("malloc");
|
||||
return;
|
||||
}
|
||||
cf_t *sf_symbols = vec_malloc(SF_LEN_RE(cell.nof_prb, cell.cp)*sizeof(cf_t));
|
||||
if (!sf_symbols) {
|
||||
perror("malloc");
|
||||
return;
|
||||
}
|
||||
bzero(sf_symbols, SF_LEN_RE(cell.nof_prb, cell.cp)*sizeof(cf_t));
|
||||
//mexPrintf("Generating DRMS for ns=%d, nof_prb=%d\n", 2*sf_idx+i,pusch_cfg.nof_prb);
|
||||
refsignal_dmrs_pusch_gen(&refs, &pusch_cfg, nof_prb, sf_idx, signal);
|
||||
uint32_t n_prb[2];
|
||||
n_prb[0] = prbset[0];
|
||||
n_prb[1] = prbset[0];
|
||||
refsignal_drms_pusch_put(&refs, &pusch_cfg, signal, nof_prb, n_prb, sf_symbols);
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_cf(sf_symbols, &plhs[0], SF_LEN_RE(cell.nof_prb, cell.cp), 1);
|
||||
}
|
||||
|
||||
refsignal_ul_free(&refs);
|
||||
free(signal);
|
||||
free(prbset);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,149 @@
|
||||
/**
|
||||
*
|
||||
* \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 <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <complex.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
lte_cell_t cell = {
|
||||
100, // nof_prb
|
||||
MAX_PORTS, // nof_ports
|
||||
1, // cell_id
|
||||
CPNORM // cyclic prefix
|
||||
};
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [recv]\n", prog);
|
||||
|
||||
printf("\t-r nof_prb [Default %d]\n", cell.nof_prb);
|
||||
printf("\t-e extended cyclic prefix [Default normal]\n");
|
||||
|
||||
printf("\t-c cell_id (1000 tests all). [Default %d]\n", cell.id);
|
||||
|
||||
printf("\t-v increase verbosity\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "recv")) != -1) {
|
||||
switch(opt) {
|
||||
case 'r':
|
||||
cell.nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 'e':
|
||||
cell.cp = CPEXT;
|
||||
break;
|
||||
case 'c':
|
||||
cell.id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
refsignal_ul_t refs;
|
||||
refsignal_drms_pusch_cfg_t pusch_cfg;
|
||||
cf_t *signal = NULL;
|
||||
int ret = -1;
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
signal = malloc(2 * RE_X_RB * cell.nof_prb * sizeof(cf_t));
|
||||
if (!signal) {
|
||||
perror("malloc");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
if (refsignal_ul_init(&refs, cell)) {
|
||||
fprintf(stderr, "Error initializing UL reference signal\n");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
printf("Running tests for %d PRB\n", cell.nof_prb);
|
||||
|
||||
for (int n=6;n<cell.nof_prb;n++) {
|
||||
for (int delta_ss=29;delta_ss<NOF_DELTA_SS;delta_ss++) {
|
||||
for (int cshift=0;cshift<NOF_CSHIFT;cshift++) {
|
||||
for (int h=0;h<3;h++) {
|
||||
for (int sf_idx=0;sf_idx<NSLOTS_X_FRAME;sf_idx++) {
|
||||
for (int cshift_drms=0;cshift_drms<NOF_CSHIFT;cshift_drms++) {
|
||||
pusch_cfg.beta_pusch = 1.0;
|
||||
uint32_t nof_prb = n;
|
||||
pusch_cfg.cyclic_shift = cshift;
|
||||
pusch_cfg.cyclic_shift_for_drms = cshift_drms;
|
||||
pusch_cfg.delta_ss = delta_ss;
|
||||
if (!h) {
|
||||
pusch_cfg.group_hopping_en = false;
|
||||
pusch_cfg.sequence_hopping_en = false;
|
||||
} else if (h == 1) {
|
||||
pusch_cfg.group_hopping_en = false;
|
||||
pusch_cfg.sequence_hopping_en = true;
|
||||
} else if (h == 2) {
|
||||
pusch_cfg.group_hopping_en = true;
|
||||
pusch_cfg.sequence_hopping_en = false;
|
||||
}
|
||||
pusch_cfg.en_drms_2 = true;
|
||||
printf("Beta: %f, ",pusch_cfg.beta_pusch);
|
||||
printf("nof_prb: %d, ",nof_prb);
|
||||
printf("cyclic_shift: %d, ",pusch_cfg.cyclic_shift);
|
||||
printf("cyclic_shift_for_drms: %d, ",pusch_cfg.cyclic_shift_for_drms);
|
||||
printf("delta_ss: %d, ",pusch_cfg.delta_ss);
|
||||
printf("SF_idx: %d\n", sf_idx);
|
||||
refsignal_dmrs_pusch_gen(&refs, &pusch_cfg, nof_prb, sf_idx, signal);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
do_exit:
|
||||
|
||||
if (signal) {
|
||||
free(signal);
|
||||
}
|
||||
|
||||
refsignal_ul_free(&refs);
|
||||
|
||||
if (!ret) {
|
||||
printf("OK\n");
|
||||
}
|
||||
exit(ret);
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/**
|
||||
*
|
||||
* \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/common/timestamp.h"
|
||||
#include "math.h"
|
||||
|
||||
int timestamp_init(timestamp_t *t, time_t full_secs, double frac_secs){
|
||||
int ret = LIBLTE_ERROR;
|
||||
if(t != NULL && frac_secs >= 0.0){
|
||||
t->full_secs = full_secs;
|
||||
t->frac_secs = frac_secs;
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int timestamp_copy(timestamp_t *dest, timestamp_t *src){
|
||||
int ret = LIBLTE_ERROR;
|
||||
if(dest != NULL && src != NULL){
|
||||
dest->full_secs = src->full_secs;
|
||||
dest->frac_secs = src->frac_secs;
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int timestamp_add(timestamp_t *t, time_t full_secs, double frac_secs){
|
||||
int ret = LIBLTE_ERROR;
|
||||
if(t != NULL && frac_secs >= 0.0){
|
||||
t->frac_secs += frac_secs;
|
||||
t->full_secs += full_secs;
|
||||
double r = floor(t->frac_secs);
|
||||
t->full_secs += r;
|
||||
t->frac_secs -= r;
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int timestamp_sub(timestamp_t *t, time_t full_secs, double frac_secs){
|
||||
int ret = LIBLTE_ERROR;
|
||||
if(t != NULL && frac_secs >= 0.0){
|
||||
t->frac_secs -= frac_secs;
|
||||
t->full_secs -= full_secs;
|
||||
if(t->frac_secs < 0){
|
||||
t->frac_secs = 1-t->frac_secs;
|
||||
t->full_secs--;
|
||||
}
|
||||
if(t->full_secs < 0)
|
||||
return LIBLTE_ERROR;
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
double timestamp_real(timestamp_t *t){
|
||||
return t->frac_secs + t->full_secs;
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/**
|
||||
*
|
||||
* \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 "liblte/phy/phy.h"
|
||||
#include "liblte/mex/mexutils.h"
|
||||
|
||||
/** MEX function to be called from MATLAB to test the channel estimator
|
||||
*/
|
||||
|
||||
#define INPUT prhs[0]
|
||||
#define TRBLKLEN prhs[1]
|
||||
#define RV prhs[2]
|
||||
#define NOF_INPUTS 3
|
||||
|
||||
|
||||
void help()
|
||||
{
|
||||
mexErrMsgTxt
|
||||
("[out] = liblte_rm_turbo_rx(in, trblkin, rv)\n\n");
|
||||
}
|
||||
|
||||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
|
||||
float *input;
|
||||
float *output;
|
||||
uint32_t in_len, trblklen, cblen, rvidx;
|
||||
float *w_buff_f;
|
||||
|
||||
if (nrhs != NOF_INPUTS) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
// Read input symbols
|
||||
in_len = mexutils_read_f(INPUT, &input);
|
||||
if (in_len < 0) {
|
||||
mexErrMsgTxt("Error reading input bits\n");
|
||||
return;
|
||||
}
|
||||
|
||||
trblklen = (uint32_t) mxGetScalar(TRBLKLEN);
|
||||
rvidx = (uint32_t) mxGetScalar(RV);
|
||||
|
||||
struct cb_segm cbsegm;
|
||||
codeblock_segmentation(&cbsegm, trblklen);
|
||||
cblen = 3*cbsegm.K1+12;
|
||||
|
||||
w_buff_f = calloc(1,sizeof(float) * cblen * 10);
|
||||
if (!w_buff_f) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// allocate memory for output bits
|
||||
output = vec_malloc(cblen * sizeof(float));
|
||||
|
||||
rm_turbo_rx(w_buff_f, cblen * 10, input, in_len, output, cblen,
|
||||
rvidx,cbsegm.F);
|
||||
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_f(output, &plhs[0], cblen, 1);
|
||||
}
|
||||
if (nlhs >= 2) {
|
||||
mexutils_write_f(input, &plhs[1], in_len, 1);
|
||||
}
|
||||
|
||||
free(input);
|
||||
free(output);
|
||||
free(w_buff_f);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,128 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/utils/dft.h"
|
||||
#include "liblte/phy/filter/dft_precoding.h"
|
||||
|
||||
/* Create DFT plans for transform precoding */
|
||||
int dft_precoding_init(dft_precoding_t *q, uint32_t max_prb)
|
||||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
bzero(q, sizeof(dft_precoding_t));
|
||||
|
||||
if (max_prb <= MAX_PRB) {
|
||||
ret = LIBLTE_ERROR;
|
||||
for (uint32_t i=1;i<max_prb;i++) {
|
||||
if(dft_precoding_valid_prb(i)) {
|
||||
DEBUG("Initiating DFT precoding plan for %d PRBs\n", i);
|
||||
if (dft_plan_c(&q->dft_plan[i], i*RE_X_RB, FORWARD)) {
|
||||
fprintf(stderr, "Error: Creating DFT plan %d\n",i);
|
||||
goto clean_exit;
|
||||
}
|
||||
dft_plan_set_norm(&q->dft_plan[i], true);
|
||||
if (dft_plan_c(&q->idft_plan[i], i*RE_X_RB, BACKWARD)) {
|
||||
fprintf(stderr, "Error: Creating DFT plan %d\n",i);
|
||||
goto clean_exit;
|
||||
}
|
||||
dft_plan_set_norm(&q->idft_plan[i], true);
|
||||
}
|
||||
}
|
||||
q->max_prb = max_prb;
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
clean_exit:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
dft_precoding_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Free DFT plans for transform precoding */
|
||||
void dft_precoding_free(dft_precoding_t *q)
|
||||
{
|
||||
for (uint32_t i=1;i<q->max_prb;i++) {
|
||||
if(dft_precoding_valid_prb(i)) {
|
||||
DEBUG("Freeing DFT precoding plan for %d PRBs\n", i);
|
||||
dft_plan_free(&q->dft_plan[i]);
|
||||
dft_plan_free(&q->idft_plan[i]);
|
||||
}
|
||||
}
|
||||
bzero(q, sizeof(dft_precoding_t));
|
||||
}
|
||||
|
||||
bool dft_precoding_valid_prb(uint32_t nof_prb) {
|
||||
if (nof_prb == 1 || (nof_prb%2) == 0 || (nof_prb%3) == 0 || (nof_prb%5) == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int dft_precoding(dft_precoding_t *q, cf_t *input, cf_t *output,
|
||||
uint32_t nof_prb, uint32_t nof_symbols)
|
||||
{
|
||||
|
||||
if (!dft_precoding_valid_prb(nof_prb)) {
|
||||
fprintf(stderr, "Error invalid number of PRB (%d)\n", nof_prb);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
for (uint32_t i=0;i<nof_symbols;i++) {
|
||||
dft_run_c(&q->dft_plan[nof_prb], &input[i*RE_X_RB*nof_prb], &output[i*RE_X_RB*nof_prb]);
|
||||
}
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int dft_predecoding(dft_precoding_t *q, cf_t *input, cf_t *output,
|
||||
uint32_t nof_prb, uint32_t nof_symbols)
|
||||
{
|
||||
if (!dft_precoding_valid_prb(nof_prb)) {
|
||||
fprintf(stderr, "Error invalid number of PRB (%d)\n", nof_prb);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
for (uint32_t i=0;i<nof_symbols;i++) {
|
||||
dft_run_c(&q->dft_plan[nof_prb], &input[i*RE_X_RB*nof_prb], &output[i*RE_X_RB*nof_prb]);
|
||||
}
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/phch/cqi.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/utils/bit.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
|
||||
int cqi_hl_subband_pack(cqi_hl_subband_t *msg, uint32_t N, uint8_t *buff, uint32_t buff_len)
|
||||
{
|
||||
uint8_t *body_ptr = buff;
|
||||
bit_pack(msg->wideband_cqi, &body_ptr, 4);
|
||||
bit_pack(msg->subband_diff_cqi, &body_ptr, 2*N);
|
||||
|
||||
return 4+2*N;
|
||||
}
|
||||
|
||||
int cqi_ue_subband_pack(cqi_ue_subband_t *msg, uint32_t L, uint8_t *buff, uint32_t buff_len)
|
||||
{
|
||||
uint8_t *body_ptr = buff;
|
||||
bit_pack(msg->wideband_cqi, &body_ptr, 4);
|
||||
bit_pack(msg->subband_diff_cqi, &body_ptr, 2);
|
||||
bit_pack(msg->subband_diff_cqi, &body_ptr, L);
|
||||
|
||||
return 4+2+L;
|
||||
}
|
||||
|
||||
int cqi_format2_wideband_pack(cqi_format2_wideband_t *msg, uint8_t *buff, uint32_t buff_len)
|
||||
{
|
||||
uint8_t *body_ptr = buff;
|
||||
bit_pack(msg->wideband_cqi, &body_ptr, 4);
|
||||
return 4;
|
||||
}
|
||||
|
||||
int cqi_format2_subband_pack(cqi_format2_subband_t *msg, uint8_t *buff, uint32_t buff_len)
|
||||
{
|
||||
uint8_t *body_ptr = buff;
|
||||
bit_pack(msg->subband_cqi, &body_ptr, 4);
|
||||
bit_pack(msg->subband_label, &body_ptr, 1);
|
||||
return 4+1;
|
||||
}
|
||||
|
@ -0,0 +1,248 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/phch/ra.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
#include "liblte/phy/fec/turbodecoder.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
|
||||
#define MAX_PDSCH_RE(cp) (2 * CP_NSYMB(cp) * 12)
|
||||
|
||||
/* Calculate Codeblock Segmentation as in Section 5.1.2 of 36.212 */
|
||||
int codeblock_segmentation(struct cb_segm *s, uint32_t tbs) {
|
||||
uint32_t Bp, B, idx1;
|
||||
int ret;
|
||||
|
||||
if (tbs == 0) {
|
||||
bzero(s, sizeof(struct cb_segm));
|
||||
ret = LIBLTE_SUCCESS;
|
||||
} else {
|
||||
B = tbs + 24;
|
||||
|
||||
/* Calculate CB sizes */
|
||||
if (B <= MAX_LONG_CB) {
|
||||
s->C = 1;
|
||||
Bp = B;
|
||||
} else {
|
||||
s->C = (uint32_t) ceilf((float) B / (MAX_LONG_CB - 24));
|
||||
Bp = B + 24 * s->C;
|
||||
}
|
||||
ret = lte_find_cb_index((Bp-1) / s->C + 1);
|
||||
if (ret != LIBLTE_ERROR) {
|
||||
idx1 = (uint32_t) ret;
|
||||
ret = lte_cb_size(idx1);
|
||||
if (ret != LIBLTE_ERROR) {
|
||||
s->K1 = (uint32_t) ret;
|
||||
if (idx1 > 0) {
|
||||
ret = lte_cb_size(idx1 - 1);
|
||||
}
|
||||
if (ret != LIBLTE_ERROR) {
|
||||
if (s->C == 1) {
|
||||
s->K2 = 0;
|
||||
s->C2 = 0;
|
||||
s->C1 = 1;
|
||||
} else {
|
||||
s->K2 = (uint32_t) ret;
|
||||
s->C2 = (s->C * s->K1 - Bp) / (s->K1 - s->K2);
|
||||
s->C1 = s->C - s->C2;
|
||||
}
|
||||
s->F = s->C1 * s->K1 + s->C2 * s->K2 - Bp;
|
||||
INFO("CB Segmentation: TBS: %d, C=%d, C+=%d K+=%d, C-=%d, K-=%d, F=%d, Bp=%d\n",
|
||||
tbs, s->C, s->C1, s->K1, s->C2, s->K2, s->F, Bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int harq_init(harq_t *q, lte_cell_t cell) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL) {
|
||||
uint32_t i;
|
||||
bzero(q, sizeof(harq_t));
|
||||
|
||||
memcpy(&q->cell, &cell, sizeof(lte_cell_t));
|
||||
|
||||
ret = ra_tbs_from_idx(26, cell.nof_prb);
|
||||
if (ret != LIBLTE_ERROR) {
|
||||
q->max_cb = (uint32_t) ret / (MAX_LONG_CB - 24) + 1;
|
||||
|
||||
q->pdsch_w_buff_f = vec_malloc(sizeof(float*) * q->max_cb);
|
||||
if (!q->pdsch_w_buff_f) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
q->pdsch_w_buff_c = vec_malloc(sizeof(uint8_t*) * q->max_cb);
|
||||
if (!q->pdsch_w_buff_c) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
// FIXME: Use HARQ buffer limitation based on UE category
|
||||
q->w_buff_size = cell.nof_prb * MAX_PDSCH_RE(cell.cp) * 6 * 10;
|
||||
for (i=0;i<q->max_cb;i++) {
|
||||
q->pdsch_w_buff_f[i] = vec_malloc(sizeof(float) * q->w_buff_size);
|
||||
if (!q->pdsch_w_buff_f[i]) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
q->pdsch_w_buff_c[i] = vec_malloc(sizeof(uint8_t) * q->w_buff_size);
|
||||
if (!q->pdsch_w_buff_c[i]) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
bzero(q->pdsch_w_buff_c[i], sizeof(uint8_t) * q->w_buff_size);
|
||||
}
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void harq_free(harq_t *q) {
|
||||
if (q) {
|
||||
uint32_t i;
|
||||
if (q->pdsch_w_buff_f) {
|
||||
for (i=0;i<q->max_cb;i++) {
|
||||
if (q->pdsch_w_buff_f[i]) {
|
||||
free(q->pdsch_w_buff_f[i]);
|
||||
}
|
||||
}
|
||||
free(q->pdsch_w_buff_f);
|
||||
}
|
||||
if (q->pdsch_w_buff_c) {
|
||||
for (i=0;i<q->max_cb;i++) {
|
||||
if (q->pdsch_w_buff_c[i]) {
|
||||
free(q->pdsch_w_buff_c[i]);
|
||||
}
|
||||
}
|
||||
free(q->pdsch_w_buff_c);
|
||||
}
|
||||
bzero(q, sizeof(harq_t));
|
||||
}
|
||||
}
|
||||
|
||||
void harq_reset(harq_t *q) {
|
||||
int i;
|
||||
if (q->pdsch_w_buff_f) {
|
||||
for (i=0;i<q->max_cb;i++) {
|
||||
if (q->pdsch_w_buff_f[i]) {
|
||||
bzero(q->pdsch_w_buff_f[i], sizeof(float) * q->w_buff_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (q->pdsch_w_buff_c) {
|
||||
for (i=0;i<q->max_cb;i++) {
|
||||
if (q->pdsch_w_buff_c[i]) {
|
||||
bzero(q->pdsch_w_buff_c[i], sizeof(uint8_t) * q->w_buff_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
bzero(&q->mcs, sizeof(ra_mcs_t));
|
||||
bzero(&q->cb_segm, sizeof(struct cb_segm));
|
||||
bzero(&q->dl_alloc, sizeof(ra_dl_alloc_t));
|
||||
}
|
||||
|
||||
static int harq_setup_common(harq_t *q, ra_mcs_t mcs, uint32_t rv, uint32_t sf_idx) {
|
||||
if (mcs.tbs != q->mcs.tbs) {
|
||||
codeblock_segmentation(&q->cb_segm, mcs.tbs);
|
||||
if (q->cb_segm.C > q->max_cb) {
|
||||
fprintf(stderr, "Codeblock segmentation returned more CBs (%d) than allocated (%d)\n",
|
||||
q->cb_segm.C, q->max_cb);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
q->mcs = mcs;
|
||||
q->sf_idx = sf_idx;
|
||||
q->rv = rv;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int harq_setup_dl(harq_t *q, ra_mcs_t mcs, uint32_t rv, uint32_t sf_idx, ra_dl_alloc_t *dl_alloc) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
rv < 4 &&
|
||||
sf_idx < 10)
|
||||
{
|
||||
ret = harq_setup_common(q, mcs, rv, sf_idx);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
memcpy(&q->dl_alloc, dl_alloc, sizeof(ra_dl_alloc_t));
|
||||
|
||||
// Number of symbols, RE and bits per subframe for DL
|
||||
q->nof_re = q->dl_alloc.re_sf[q->sf_idx];
|
||||
q->nof_symb = 2*CP_NSYMB(q->cell.cp)-q->dl_alloc.lstart;
|
||||
q->nof_bits = q->nof_re * lte_mod_bits_x_symbol(q->mcs.mod);
|
||||
q->nof_prb = q->dl_alloc.slot[0].nof_prb;
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int harq_setup_ul(harq_t *q, ra_mcs_t mcs, uint32_t rv, uint32_t sf_idx, ra_ul_alloc_t *ul_alloc) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
rv < 4 &&
|
||||
sf_idx < 10)
|
||||
{
|
||||
ret = harq_setup_common(q, mcs, rv, sf_idx);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
memcpy(&q->ul_alloc, ul_alloc, sizeof(ra_ul_alloc_t));
|
||||
|
||||
// Number of symbols, RE and bits per subframe for UL
|
||||
q->nof_symb = 2*(CP_NSYMB(q->cell.cp)-1);
|
||||
q->nof_re = q->nof_symb*q->ul_alloc.L_prb*RE_X_RB;
|
||||
q->nof_bits = q->nof_re * lte_mod_bits_x_symbol(q->mcs.mod);
|
||||
q->nof_prb = q->ul_alloc.L_prb;
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,206 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/phch/pucch.h"
|
||||
#include "liblte/phy/phch/uci.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/utils/bit.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/filter/dft_precoding.h"
|
||||
|
||||
#define MAX_PUSCH_RE(cp) (2 * CP_NSYMB(cp) * 12)
|
||||
|
||||
bool pucch_cfg_isvalid(pucch_cfg_t *cfg) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Generates n_cs_cell according to Sec 5.4 of 36.211 */
|
||||
int generate_n_cs_cell(lte_cell_t cell, uint32_t n_cs_cell[NSLOTS_X_FRAME][CPNORM_NSYMB])
|
||||
{
|
||||
sequence_t seq;
|
||||
bzero(&seq, sizeof(sequence_t));
|
||||
|
||||
sequence_LTE_pr(&seq, 8*CP_NSYMB(cell.cp)*NSLOTS_X_FRAME, cell.id);
|
||||
|
||||
for (uint32_t ns=0;ns<NSLOTS_X_FRAME;ns++) {
|
||||
for (uint32_t l=0;l<CP_NSYMB(cell.cp);l++) {
|
||||
n_cs_cell[ns][l] = 0;
|
||||
for (uint32_t i=0;i<8;i++) {
|
||||
n_cs_cell[ns][l] += seq.c[8*CP_NSYMB(cell.cp)*ns+8*l+i]<<i;
|
||||
}
|
||||
}
|
||||
}
|
||||
sequence_free(&seq);
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Calculates alpha according to 5.5.2.2.2 of 36.211 */
|
||||
float pucch_get_alpha(uint32_t n_cs_cell[NSLOTS_X_FRAME][CPNORM_NSYMB],
|
||||
pucch_cfg_t *cfg,
|
||||
lte_cp_t cp, bool is_drms,
|
||||
uint32_t ns, uint32_t l,
|
||||
uint32_t *n_oc_ptr)
|
||||
{
|
||||
uint32_t c = CP_ISNORM(cp)?3:2;
|
||||
uint32_t N_prime = (cfg->n_pucch < c*cfg->N_cs/cfg->delta_pucch_shift)?cfg->N_cs:12;
|
||||
|
||||
uint32_t n_prime = cfg->n_pucch;
|
||||
if (cfg->n_pucch >= c*cfg->N_cs/cfg->delta_pucch_shift) {
|
||||
n_prime = (cfg->n_pucch-c*cfg->N_cs/cfg->delta_pucch_shift)%(cfg->N_cs/cfg->delta_pucch_shift);
|
||||
}
|
||||
|
||||
uint32_t n_oc_div = (!is_drms && CP_ISEXT(cp))?2:1;
|
||||
|
||||
uint32_t n_oc = n_prime*cfg->delta_pucch_shift/N_prime;
|
||||
if (!is_drms && CP_ISEXT(cp)) {
|
||||
n_oc *= 2;
|
||||
}
|
||||
if (n_oc_ptr) {
|
||||
*n_oc_ptr = n_oc;
|
||||
}
|
||||
uint32_t n_cs = 0;
|
||||
if (CP_ISNORM(cp)) {
|
||||
n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+(n_oc%cfg->delta_pucch_shift))%N_prime)%12;
|
||||
} else {
|
||||
n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+n_oc/n_oc_div)%N_prime)%12;
|
||||
}
|
||||
|
||||
return 2 * M_PI * (n_cs) / 12;
|
||||
}
|
||||
|
||||
int pucch_cp(pucch_t *q, harq_t *harq, cf_t *input, cf_t *output, bool advance_input)
|
||||
{
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
int pucch_put(pucch_t *q, harq_t *harq, cf_t *input, cf_t *output) {
|
||||
return pucch_cp(q, harq, input, output, true);
|
||||
}
|
||||
|
||||
int pucch_get(pucch_t *q, harq_t *harq, cf_t *input, cf_t *output) {
|
||||
return pucch_cp(q, harq, input, output, false);
|
||||
}
|
||||
|
||||
|
||||
/** Initializes the PDCCH transmitter and receiver */
|
||||
int pucch_init(pucch_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(pucch_t));
|
||||
|
||||
q->cell = cell;
|
||||
|
||||
if (generate_n_cs_cell(q->cell, q->n_cs_cell)) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pucch_free(pucch_t *q) {
|
||||
bzero(q, sizeof(pucch_t));
|
||||
}
|
||||
|
||||
/** Decodes the PUSCH from the received symbols
|
||||
*/
|
||||
int pucch_decode(pucch_t *q, harq_t *harq, cf_t *sf_symbols, cf_t *ce, float noise_estimate, uint8_t *data)
|
||||
{
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
static cf_t uci_encode_format1() {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
static cf_t uci_encode_format1a(uint8_t bit) {
|
||||
return bit?1.0:-1.0;
|
||||
}
|
||||
|
||||
static cf_t uci_encode_format1b(uint8_t bits[2]) {
|
||||
if (bits[0] == 0) {
|
||||
if (bits[1] == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return -I;
|
||||
}
|
||||
} else {
|
||||
if (bits[1] == 0) {
|
||||
return I;
|
||||
} else {
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void uci_mod_bits(pucch_t *q, pucch_cfg_t *cfg, uint8_t bits[PUCCH_MAX_BITS])
|
||||
{
|
||||
cf_t d_0 = 0;
|
||||
uint8_t tmp[2];
|
||||
switch(cfg->format) {
|
||||
case PUCCH_FORMAT_1:
|
||||
d_0 = uci_encode_format1();
|
||||
break;
|
||||
case PUCCH_FORMAT_1A:
|
||||
d_0 = uci_encode_format1a(bits[0]);
|
||||
break;
|
||||
case PUCCH_FORMAT_1B:
|
||||
tmp[0] = bits[0];
|
||||
tmp[1] = bits[1];
|
||||
d_0 = uci_encode_format1b(tmp);
|
||||
default:
|
||||
fprintf(stderr, "PUCCH format 2 not supported\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
for (uint32_t n=0;n<PUCCH_N_SEQ;n++) {
|
||||
q->y[n] = d_0+
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
int pucch_encode(pucch_t *q, pucch_cfg_t *cfg, uint8_t bits[PUCCH_MAX_BITS], cf_t *sf_symbols)
|
||||
{
|
||||
uci_mod_bits(q, cfg, bits);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,445 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/phch/pusch.h"
|
||||
#include "liblte/phy/phch/uci.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/utils/bit.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/filter/dft_precoding.h"
|
||||
|
||||
#define MAX_PUSCH_RE(cp) (2 * CP_NSYMB(cp) * 12)
|
||||
|
||||
|
||||
|
||||
const static lte_mod_t modulations[4] =
|
||||
{ LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64 };
|
||||
|
||||
static int f_hop_sum(pusch_t *q, uint32_t i) {
|
||||
uint32_t sum = 0;
|
||||
for (uint32_t k=i*10+1;k<i*10+9;i++) {
|
||||
sum += (q->seq_type2_fo.c[k]<<(k-(i*10+1)));
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
static int f_hop(pusch_t *q, pusch_hopping_cfg_t *hopping, int i) {
|
||||
if (i == -1) {
|
||||
return 0;
|
||||
} else {
|
||||
if (hopping->n_sb == 1) {
|
||||
return 0;
|
||||
} else if (hopping->n_sb == 2) {
|
||||
return (f_hop(q, hopping, i-1) + f_hop_sum(q, i))%2;
|
||||
} else {
|
||||
return (f_hop(q, hopping, i-1) + f_hop_sum(q, i)%(hopping->n_sb-1)+1)%hopping->n_sb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int f_m(pusch_t *q, pusch_hopping_cfg_t *hopping, uint32_t i) {
|
||||
if (hopping->n_sb == 1) {
|
||||
if (hopping->hop_mode == hop_mode_inter_sf) {
|
||||
return hopping->current_tx_nb%2;
|
||||
} else {
|
||||
return i%2;
|
||||
}
|
||||
} else {
|
||||
return q->seq_type2_fo.c[i*10];
|
||||
}
|
||||
}
|
||||
|
||||
int pusch_cp(pusch_t *q, harq_t *harq, cf_t *input, cf_t *output, bool advance_input)
|
||||
{
|
||||
cf_t *in_ptr = input;
|
||||
cf_t *out_ptr = output;
|
||||
pusch_hopping_cfg_t *hopping = &q->hopping_cfg;
|
||||
|
||||
uint32_t L_ref = 3;
|
||||
if (CP_ISEXT(q->cell.cp)) {
|
||||
L_ref = 2;
|
||||
}
|
||||
INFO("PUSCH Freq hopping: %d\n", harq->ul_alloc.freq_hopping);
|
||||
for (uint32_t slot=0;slot<2;slot++) {
|
||||
uint32_t n_prb_tilde = harq->ul_alloc.n_prb[slot];
|
||||
if (harq->ul_alloc.freq_hopping == 1) {
|
||||
if (hopping->hop_mode == hop_mode_inter_sf) {
|
||||
n_prb_tilde = harq->ul_alloc.n_prb[hopping->current_tx_nb%2];
|
||||
} else {
|
||||
n_prb_tilde = harq->ul_alloc.n_prb[slot];
|
||||
}
|
||||
}
|
||||
if (harq->ul_alloc.freq_hopping == 2) {
|
||||
/* Freq hopping type 2 as defined in 5.3.4 of 36.211 */
|
||||
uint32_t n_vrb_tilde = harq->ul_alloc.n_prb[0];
|
||||
if (hopping->n_sb > 1) {
|
||||
n_vrb_tilde -= (hopping->hopping_offset-1)/2+1;
|
||||
}
|
||||
int i=0;
|
||||
if (hopping->hop_mode == hop_mode_inter_sf) {
|
||||
i = harq->sf_idx;
|
||||
} else {
|
||||
i = 2*harq->sf_idx+slot;
|
||||
}
|
||||
uint32_t n_rb_sb = q->cell.nof_prb;
|
||||
if (hopping->n_sb > 1) {
|
||||
n_rb_sb = (n_rb_sb-hopping->hopping_offset-hopping->hopping_offset%2)/hopping->n_sb;
|
||||
}
|
||||
n_prb_tilde = (n_vrb_tilde+f_hop(q, hopping, i)*n_rb_sb+
|
||||
(n_rb_sb-1)-2*(n_vrb_tilde%n_rb_sb)*f_m(q, hopping, i))%(n_rb_sb*hopping->n_sb);
|
||||
|
||||
INFO("n_prb_tilde: %d, n_vrb_tilde: %d, n_rb_sb: %d, n_sb: %d\n",
|
||||
n_prb_tilde, n_vrb_tilde, n_rb_sb, hopping->n_sb);
|
||||
if (hopping->n_sb > 1) {
|
||||
n_prb_tilde += (hopping->hopping_offset-1)/2+1;
|
||||
}
|
||||
|
||||
}
|
||||
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);
|
||||
for (uint32_t l=0;l<CP_NSYMB(q->cell.cp);l++) {
|
||||
if (l != L_ref) {
|
||||
uint32_t idx = RE_IDX(q->cell.nof_prb, l+slot*CP_NSYMB(q->cell.cp),
|
||||
n_prb_tilde*RE_X_RB);
|
||||
if (advance_input) {
|
||||
out_ptr = &output[idx];
|
||||
} else {
|
||||
in_ptr = &input[idx];
|
||||
}
|
||||
memcpy(out_ptr, in_ptr, harq->ul_alloc.L_prb * RE_X_RB * sizeof(cf_t));
|
||||
if (advance_input) {
|
||||
in_ptr += harq->ul_alloc.L_prb*RE_X_RB;
|
||||
} else {
|
||||
out_ptr += harq->ul_alloc.L_prb*RE_X_RB;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return RE_X_RB*harq->ul_alloc.L_prb;
|
||||
}
|
||||
|
||||
int pusch_put(pusch_t *q, harq_t *harq, cf_t *input, cf_t *output) {
|
||||
return pusch_cp(q, harq, input, output, true);
|
||||
}
|
||||
|
||||
int pusch_get(pusch_t *q, harq_t *harq, cf_t *input, cf_t *output) {
|
||||
return pusch_cp(q, harq, input, output, false);
|
||||
}
|
||||
|
||||
|
||||
/** Initializes the PDCCH transmitter and receiver */
|
||||
int pusch_init(pusch_t *q, lte_cell_t cell) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
int i;
|
||||
|
||||
if (q != NULL &&
|
||||
lte_cell_isvalid(&cell))
|
||||
{
|
||||
|
||||
bzero(q, sizeof(pusch_t));
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
q->cell = cell;
|
||||
q->max_re = q->cell.nof_prb * MAX_PUSCH_RE(q->cell.cp);
|
||||
|
||||
INFO("Init PUSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports,
|
||||
q->cell.nof_prb, q->max_re);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (modem_table_lte(&q->mod[i], modulations[i], true)) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
/* Precompute sequence for type2 frequency hopping */
|
||||
if (sequence_LTE_pr(&q->seq_type2_fo, 210, q->cell.id)) {
|
||||
fprintf(stderr, "Error initiating type2 frequency hopping sequence\n");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
demod_soft_init(&q->demod, q->max_re);
|
||||
demod_soft_alg_set(&q->demod, APPROX);
|
||||
|
||||
sch_init(&q->dl_sch);
|
||||
|
||||
if (dft_precoding_init(&q->dft_precoding, cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initiating DFT transform precoding\n");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* This is for equalization at receiver */
|
||||
if (precoding_init(&q->equalizer, SF_LEN_RE(cell.nof_prb, cell.cp))) {
|
||||
fprintf(stderr, "Error initializing precoding\n");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->rnti_is_set = false;
|
||||
|
||||
// Allocate floats for reception (LLRs). Buffer casted to uint8_t for transmission
|
||||
q->pusch_q = vec_malloc(sizeof(float) * q->max_re * lte_mod_bits_x_symbol(LTE_QAM64));
|
||||
if (!q->pusch_q) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
// Allocate floats for reception (LLRs). Buffer casted to uint8_t for transmission
|
||||
q->pusch_g = vec_malloc(sizeof(float) * q->max_re * lte_mod_bits_x_symbol(LTE_QAM64));
|
||||
if (!q->pusch_g) {
|
||||
goto clean;
|
||||
}
|
||||
q->pusch_d = vec_malloc(sizeof(cf_t) * q->max_re);
|
||||
if (!q->pusch_d) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->ce = vec_malloc(sizeof(cf_t) * q->max_re);
|
||||
if (!q->ce) {
|
||||
goto clean;
|
||||
}
|
||||
q->pusch_z = vec_malloc(sizeof(cf_t) * q->max_re);
|
||||
if (!q->pusch_z) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
clean:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
pusch_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pusch_free(pusch_t *q) {
|
||||
int i;
|
||||
|
||||
if (q->pusch_q) {
|
||||
free(q->pusch_q);
|
||||
}
|
||||
if (q->pusch_d) {
|
||||
free(q->pusch_d);
|
||||
}
|
||||
if (q->pusch_g) {
|
||||
free(q->pusch_g);
|
||||
}
|
||||
if (q->ce) {
|
||||
free(q->ce);
|
||||
}
|
||||
if (q->pusch_z) {
|
||||
free(q->pusch_z);
|
||||
}
|
||||
|
||||
dft_precoding_free(&q->dft_precoding);
|
||||
|
||||
precoding_free(&q->equalizer);
|
||||
|
||||
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
|
||||
sequence_free(&q->seq_pusch[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
modem_table_free(&q->mod[i]);
|
||||
}
|
||||
demod_soft_free(&q->demod);
|
||||
sch_free(&q->dl_sch);
|
||||
|
||||
bzero(q, sizeof(pusch_t));
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
* 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 */
|
||||
int pusch_set_rnti(pusch_t *q, uint16_t rnti) {
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
|
||||
if (sequence_pusch(&q->seq_pusch[i], rnti, 2 * i, q->cell.id,
|
||||
q->max_re * lte_mod_bits_x_symbol(LTE_QAM64))) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
q->rnti_is_set = true;
|
||||
q->rnti = rnti;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/** Decodes the PUSCH from the received symbols
|
||||
*/
|
||||
int pusch_decode(pusch_t *q, harq_t *harq, cf_t *sf_symbols, cf_t *ce, float noise_estimate, uint8_t *data)
|
||||
{
|
||||
|
||||
uint32_t n;
|
||||
|
||||
if (q != NULL &&
|
||||
sf_symbols != NULL &&
|
||||
data != NULL &&
|
||||
harq != NULL)
|
||||
{
|
||||
|
||||
if (q->rnti_is_set) {
|
||||
INFO("Decoding PUSCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
|
||||
harq->sf_idx, lte_mod_string(harq->mcs.mod), harq->mcs.tbs, harq->nof_re, harq->nof_bits, harq->rv);
|
||||
|
||||
/* extract symbols */
|
||||
n = pusch_get(q, harq, sf_symbols, q->pusch_d);
|
||||
if (n != harq->nof_re) {
|
||||
fprintf(stderr, "Error expecting %d symbols but got %d\n", harq->nof_re, n);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* extract channel estimates */
|
||||
n = pusch_get(q, harq, ce, q->ce);
|
||||
if (n != harq->nof_re) {
|
||||
fprintf(stderr, "Error expecting %d symbols but got %d\n", harq->nof_re, n);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
predecoding_single(&q->equalizer, q->pusch_d, q->ce, q->pusch_z,
|
||||
harq->nof_re, noise_estimate);
|
||||
|
||||
dft_predecoding(&q->dft_precoding, q->pusch_z, q->pusch_d,
|
||||
harq->ul_alloc.L_prb, harq->nof_symb);
|
||||
|
||||
/* demodulate symbols
|
||||
* The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation,
|
||||
* thus we don't need tot set it in the LLRs normalization
|
||||
*/
|
||||
demod_soft_sigma_set(&q->demod, sqrt(0.5));
|
||||
demod_soft_table_set(&q->demod, &q->mod[harq->mcs.mod]);
|
||||
demod_soft_demodulate(&q->demod, q->pusch_d, q->pusch_q, harq->nof_re);
|
||||
|
||||
/* descramble */
|
||||
scrambling_f_offset(&q->seq_pusch[harq->sf_idx], q->pusch_q, 0, harq->nof_bits);
|
||||
|
||||
return ulsch_decode(&q->dl_sch, harq, q->pusch_q, data);
|
||||
} else {
|
||||
fprintf(stderr, "Must call pusch_set_rnti() before calling pusch_decode()\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
} else {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
int pusch_encode_rnti(pusch_t *q, harq_t *harq_process, uint8_t *data, uint16_t rnti, cf_t *sf_symbols)
|
||||
{
|
||||
uci_data_t uci_data;
|
||||
bzero(&uci_data, sizeof(uci_data_t));
|
||||
return pusch_uci_encode_rnti(q, harq_process, data, uci_data, rnti, sf_symbols);
|
||||
}
|
||||
|
||||
int pusch_encode(pusch_t *q, harq_t *harq_process, uint8_t *data, cf_t *sf_symbols)
|
||||
{
|
||||
if (q->rnti_is_set) {
|
||||
uci_data_t uci_data;
|
||||
bzero(&uci_data, sizeof(uci_data_t));
|
||||
return pusch_uci_encode_rnti(q, harq_process, data, uci_data, q->rnti, sf_symbols);
|
||||
} else {
|
||||
fprintf(stderr, "Must call pusch_set_rnti() to set the encoder/decoder RNTI\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int pusch_uci_encode(pusch_t *q, harq_t *harq, uint8_t *data, uci_data_t uci_data, cf_t *sf_symbols)
|
||||
{
|
||||
if (q->rnti_is_set) {
|
||||
return pusch_uci_encode_rnti(q, harq, data, uci_data, q->rnti, sf_symbols);
|
||||
} else {
|
||||
fprintf(stderr, "Must call pusch_set_rnti() to set the encoder/decoder RNTI\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts the PUSCH data bits to symbols mapped to the slot ready for transmission
|
||||
*/
|
||||
int pusch_uci_encode_rnti(pusch_t *q, harq_t *harq, uint8_t *data, uci_data_t uci_data, uint16_t rnti, cf_t *sf_symbols)
|
||||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
data != NULL &&
|
||||
harq != NULL)
|
||||
{
|
||||
if (harq->mcs.tbs > harq->nof_bits) {
|
||||
fprintf(stderr, "Invalid code rate %.2f\n", (float) harq->mcs.tbs / harq->nof_bits);
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
if (harq->nof_re > q->max_re) {
|
||||
fprintf(stderr, "Error too many RE per subframe (%d). PUSCH configured for %d RE (%d PRB)\n",
|
||||
harq->nof_re, q->max_re, q->cell.nof_prb);
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
INFO("Encoding PUSCH SF: %d, Mod %s, RNTI: %d, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
|
||||
harq->sf_idx, lte_mod_string(harq->mcs.mod), rnti, harq->mcs.tbs, harq->nof_re, harq->nof_bits, harq->rv);
|
||||
|
||||
bzero(q->pusch_q, harq->nof_bits);
|
||||
if (ulsch_uci_encode(&q->dl_sch, harq, data, uci_data, q->pusch_g, q->pusch_q)) {
|
||||
fprintf(stderr, "Error encoding TB\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
if (rnti != q->rnti) {
|
||||
sequence_t seq;
|
||||
if (sequence_pusch(&seq, rnti, 2 * harq->sf_idx, q->cell.id, harq->nof_bits)) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
scrambling_b_offset_pusch(&seq, (uint8_t*) q->pusch_q, 0, harq->nof_bits);
|
||||
sequence_free(&seq);
|
||||
} else {
|
||||
scrambling_b_offset_pusch(&q->seq_pusch[harq->sf_idx], (uint8_t*) q->pusch_q, 0, 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,
|
||||
harq->ul_alloc.L_prb, harq->nof_symb);
|
||||
|
||||
/* mapping to resource elements */
|
||||
pusch_put(q, harq, q->pusch_z, sf_symbols);
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -0,0 +1,517 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/phch/pusch.h"
|
||||
#include "liblte/phy/phch/sch.h"
|
||||
#include "liblte/phy/phch/uci.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/utils/bit.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
|
||||
int sch_init(sch_t *q) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
if (q) {
|
||||
bzero(q, sizeof(sch_t));
|
||||
|
||||
if (crc_init(&q->crc_tb, LTE_CRC24A, 24)) {
|
||||
fprintf(stderr, "Error initiating CRC\n");
|
||||
goto clean;
|
||||
}
|
||||
if (crc_init(&q->crc_cb, LTE_CRC24B, 24)) {
|
||||
fprintf(stderr, "Error initiating CRC\n");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if (tcod_init(&q->encoder, MAX_LONG_CB)) {
|
||||
fprintf(stderr, "Error initiating Turbo Coder\n");
|
||||
goto clean;
|
||||
}
|
||||
if (tdec_init(&q->decoder, MAX_LONG_CB)) {
|
||||
fprintf(stderr, "Error initiating Turbo Decoder\n");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
// Allocate floats for reception (LLRs)
|
||||
q->cb_in = vec_malloc(sizeof(uint8_t) * MAX_LONG_CB);
|
||||
if (!q->cb_in) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->cb_out = vec_malloc(sizeof(float) * (3 * MAX_LONG_CB + 12));
|
||||
if (!q->cb_out) {
|
||||
goto clean;
|
||||
}
|
||||
if (uci_cqi_init(&q->uci_cqi)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
clean:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
sch_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sch_free(sch_t *q) {
|
||||
if (q->cb_in) {
|
||||
free(q->cb_in);
|
||||
}
|
||||
if (q->cb_out) {
|
||||
free(q->cb_out);
|
||||
}
|
||||
tdec_free(&q->decoder);
|
||||
tcod_free(&q->encoder);
|
||||
uci_cqi_free(&q->uci_cqi);
|
||||
bzero(q, sizeof(sch_t));
|
||||
}
|
||||
|
||||
|
||||
float sch_average_noi(sch_t *q) {
|
||||
return q->average_nof_iterations;
|
||||
}
|
||||
|
||||
uint32_t sch_last_noi(sch_t *q) {
|
||||
return q->nof_iterations;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Encode a transport block according to 36.212 5.3.2
|
||||
*
|
||||
*/
|
||||
static int encode_tb(sch_t *q, harq_t *harq, uint8_t *data, uint8_t *e_bits, uint32_t nof_e_bits)
|
||||
{
|
||||
uint8_t parity[24];
|
||||
uint8_t *p_parity = parity;
|
||||
uint32_t par;
|
||||
uint32_t i;
|
||||
uint32_t cb_len, rp, wp, rlen, F, n_e;
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32_t Qm = lte_mod_bits_x_symbol(harq->mcs.mod);
|
||||
|
||||
if (q != NULL &&
|
||||
data != NULL &&
|
||||
harq != NULL)
|
||||
{
|
||||
|
||||
uint32_t Gp = nof_e_bits / Qm;
|
||||
|
||||
uint32_t gamma = Gp;
|
||||
if (harq->cb_segm.C > 0) {
|
||||
gamma = Gp%harq->cb_segm.C;
|
||||
}
|
||||
|
||||
if (harq->rv == 0) {
|
||||
/* Compute transport block CRC */
|
||||
par = crc_checksum(&q->crc_tb, data, harq->mcs.tbs);
|
||||
|
||||
/* parity bits will be appended later */
|
||||
bit_pack(par, &p_parity, 24);
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
DEBUG("DATA: ", 0);
|
||||
vec_fprint_b(stdout, data, harq->mcs.tbs);
|
||||
DEBUG("PARITY: ", 0);
|
||||
vec_fprint_b(stdout, parity, 24);
|
||||
}
|
||||
}
|
||||
|
||||
wp = 0;
|
||||
rp = 0;
|
||||
for (i = 0; i < harq->cb_segm.C; i++) {
|
||||
|
||||
/* Get read lengths */
|
||||
if (i < harq->cb_segm.C2) {
|
||||
cb_len = harq->cb_segm.K2;
|
||||
} else {
|
||||
cb_len = harq->cb_segm.K1;
|
||||
}
|
||||
if (harq->cb_segm.C > 1) {
|
||||
rlen = cb_len - 24;
|
||||
} else {
|
||||
rlen = cb_len;
|
||||
}
|
||||
if (i == 0) {
|
||||
F = harq->cb_segm.F;
|
||||
} else {
|
||||
F = 0;
|
||||
}
|
||||
if (i <= harq->cb_segm.C - gamma - 1) {
|
||||
n_e = Qm * (Gp/harq->cb_segm.C);
|
||||
} else {
|
||||
n_e = Qm * ((uint32_t) ceilf((float) Gp/harq->cb_segm.C));
|
||||
}
|
||||
|
||||
INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i,
|
||||
cb_len, rlen - F, wp, rp, F, n_e);
|
||||
|
||||
if (harq->rv == 0) {
|
||||
|
||||
/* Copy data to another buffer, making space for the Codeblock CRC */
|
||||
if (i < harq->cb_segm.C - 1) {
|
||||
// Copy data
|
||||
memcpy(&q->cb_in[F], &data[rp], (rlen - F) * sizeof(uint8_t));
|
||||
} else {
|
||||
INFO("Last CB, appending parity: %d from %d and 24 to %d\n",
|
||||
rlen - F - 24, rp, rlen - 24);
|
||||
/* Append Transport Block parity bits to the last CB */
|
||||
memcpy(&q->cb_in[F], &data[rp], (rlen - 24 - F) * sizeof(uint8_t));
|
||||
memcpy(&q->cb_in[rlen - 24], parity, 24 * sizeof(uint8_t));
|
||||
}
|
||||
/* Filler bits are treated like zeros for the CB CRC calculation */
|
||||
for (int j = 0; j < F; j++) {
|
||||
q->cb_in[j] = 0;
|
||||
}
|
||||
/* Attach Codeblock CRC */
|
||||
if (harq->cb_segm.C > 1) {
|
||||
crc_attach(&q->crc_cb, q->cb_in, rlen);
|
||||
}
|
||||
/* Set the filler bits to <NULL> */
|
||||
for (int j = 0; j < F; j++) {
|
||||
q->cb_in[j] = TX_NULL;
|
||||
}
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
DEBUG("CB#%d: ", i);
|
||||
vec_fprint_b(stdout, q->cb_in, cb_len);
|
||||
}
|
||||
|
||||
/* Turbo Encoding */
|
||||
tcod_encode(&q->encoder, q->cb_in, (uint8_t*) q->cb_out, cb_len);
|
||||
}
|
||||
|
||||
/* Rate matching */
|
||||
if (rm_turbo_tx(harq->pdsch_w_buff_c[i], harq->w_buff_size,
|
||||
(uint8_t*) q->cb_out, 3 * cb_len + 12,
|
||||
&e_bits[wp], n_e, harq->rv))
|
||||
{
|
||||
fprintf(stderr, "Error in rate matching\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* Set read/write pointers */
|
||||
rp += (rlen - F);
|
||||
wp += n_e;
|
||||
}
|
||||
INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp);
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Decode a transport block according to 36.212 5.3.2
|
||||
*
|
||||
*/
|
||||
static int decode_tb(sch_t *q, harq_t *harq, float *e_bits, uint8_t *data, uint32_t nof_e_bits)
|
||||
{
|
||||
uint8_t parity[24];
|
||||
uint8_t *p_parity = parity;
|
||||
uint32_t par_rx, par_tx;
|
||||
uint32_t i;
|
||||
uint32_t cb_len, rp, wp, rlen, F, n_e;
|
||||
uint32_t Qm = lte_mod_bits_x_symbol(harq->mcs.mod);
|
||||
|
||||
if (q != NULL &&
|
||||
data != NULL &&
|
||||
harq != NULL)
|
||||
{
|
||||
|
||||
if (harq->mcs.tbs == 0 || harq->cb_segm.C == 0) {
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
rp = 0;
|
||||
rp = 0;
|
||||
wp = 0;
|
||||
uint32_t Gp = nof_e_bits / Qm;
|
||||
uint32_t gamma=Gp;
|
||||
|
||||
if (harq->cb_segm.C>0) {
|
||||
gamma = Gp%harq->cb_segm.C;
|
||||
}
|
||||
|
||||
bool early_stop = true;
|
||||
for (i = 0; i < harq->cb_segm.C && early_stop; i++) {
|
||||
|
||||
/* Get read/write lengths */
|
||||
if (i < harq->cb_segm.C2) {
|
||||
cb_len = harq->cb_segm.K2;
|
||||
} else {
|
||||
cb_len = harq->cb_segm.K1;
|
||||
}
|
||||
if (harq->cb_segm.C == 1) {
|
||||
rlen = cb_len;
|
||||
} else {
|
||||
rlen = cb_len - 24;
|
||||
}
|
||||
if (i == 0) {
|
||||
F = harq->cb_segm.F;
|
||||
} else {
|
||||
F = 0;
|
||||
}
|
||||
|
||||
if (i <= harq->cb_segm.C - gamma - 1) {
|
||||
n_e = Qm * (Gp/harq->cb_segm.C);
|
||||
} else {
|
||||
n_e = Qm * ((uint32_t) ceilf((float) Gp/harq->cb_segm.C));
|
||||
}
|
||||
|
||||
INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i,
|
||||
cb_len, rlen - F, wp, rp, F, n_e);
|
||||
|
||||
/* Rate Unmatching */
|
||||
if (rm_turbo_rx(harq->pdsch_w_buff_f[i], harq->w_buff_size,
|
||||
&e_bits[rp], n_e,
|
||||
(float*) q->cb_out, 3 * cb_len + 12, harq->rv, F)) {
|
||||
fprintf(stderr, "Error in rate matching\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
DEBUG("CB#%d RMOUT: ", i);
|
||||
vec_fprint_f(stdout, q->cb_out, 3*cb_len+12);
|
||||
}
|
||||
|
||||
/* Turbo Decoding with CRC-based early stopping */
|
||||
q->nof_iterations = 0;
|
||||
uint32_t len_crc;
|
||||
uint8_t *cb_in_ptr;
|
||||
crc_t *crc_ptr;
|
||||
early_stop = false;
|
||||
|
||||
tdec_reset(&q->decoder, cb_len);
|
||||
|
||||
do {
|
||||
tdec_iteration(&q->decoder, (float*) q->cb_out, cb_len);
|
||||
q->nof_iterations++;
|
||||
|
||||
if (harq->cb_segm.C > 1) {
|
||||
len_crc = cb_len;
|
||||
cb_in_ptr = q->cb_in;
|
||||
crc_ptr = &q->crc_cb;
|
||||
} else {
|
||||
len_crc = harq->mcs.tbs+24;
|
||||
cb_in_ptr = &q->cb_in[F];
|
||||
crc_ptr = &q->crc_tb;
|
||||
}
|
||||
|
||||
tdec_decision(&q->decoder, q->cb_in, cb_len);
|
||||
|
||||
/* Check Codeblock CRC and stop early if incorrect */
|
||||
if (!crc_checksum(crc_ptr, cb_in_ptr, len_crc)) {
|
||||
early_stop = true;
|
||||
}
|
||||
|
||||
} while (q->nof_iterations < TDEC_MAX_ITERATIONS && !early_stop);
|
||||
q->average_nof_iterations = VEC_EMA((float) q->nof_iterations, q->average_nof_iterations, 0.2);
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
DEBUG("CB#%d IN: ", i);
|
||||
vec_fprint_b(stdout, q->cb_in, cb_len);
|
||||
}
|
||||
|
||||
// If CB CRC is not correct, early_stop will be false and wont continue with rest of CBs
|
||||
|
||||
/* Copy data to another buffer, removing the Codeblock CRC */
|
||||
if (i < harq->cb_segm.C - 1) {
|
||||
memcpy(&data[wp], &q->cb_in[F], (rlen - F) * sizeof(uint8_t));
|
||||
} else {
|
||||
DEBUG("Last CB, appending parity: %d to %d from %d and 24 from %d\n",
|
||||
rlen - F - 24, wp, F, rlen - 24);
|
||||
|
||||
/* Append Transport Block parity bits to the last CB */
|
||||
memcpy(&data[wp], &q->cb_in[F], (rlen - F - 24) * sizeof(uint8_t));
|
||||
memcpy(parity, &q->cb_in[rlen - 24], 24 * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
/* Set read/write pointers */
|
||||
wp += (rlen - F);
|
||||
rp += n_e;
|
||||
}
|
||||
|
||||
if (!early_stop) {
|
||||
INFO("CB %d failed. TB is erroneous.\n",i-1);
|
||||
return LIBLTE_ERROR;
|
||||
} else {
|
||||
INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp);
|
||||
|
||||
// Compute transport block CRC
|
||||
par_rx = crc_checksum(&q->crc_tb, data, harq->mcs.tbs);
|
||||
|
||||
// check parity bits
|
||||
par_tx = bit_unpack(&p_parity, 24);
|
||||
|
||||
if (!par_rx) {
|
||||
INFO("\n\tCAUTION!! Received all-zero transport block\n\n", 0);
|
||||
}
|
||||
|
||||
if (par_rx == par_tx) {
|
||||
INFO("TB decoded OK\n",i);
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
INFO("Error in TB parity\n",i);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
int dlsch_decode(sch_t *q, harq_t *harq, float *e_bits, uint8_t *data)
|
||||
{
|
||||
return decode_tb(q, harq, e_bits, data, harq->nof_bits);
|
||||
}
|
||||
|
||||
int dlsch_encode(sch_t *q, harq_t *harq, uint8_t *data, uint8_t *e_bits) {
|
||||
return encode_tb(q, harq, data, e_bits, harq->nof_bits);
|
||||
}
|
||||
|
||||
int ulsch_decode(sch_t *q, harq_t *harq, float *e_bits, uint8_t *data)
|
||||
{
|
||||
return decode_tb(q, harq, e_bits, data, harq->nof_bits);
|
||||
}
|
||||
|
||||
|
||||
/* UL-SCH channel interleaver according to 5.5.2.8 of 36.212 */
|
||||
void ulsch_interleave(uint8_t *g_bits, uint32_t Q_m, uint32_t H_prime_total, uint32_t N_pusch_symbs, uint8_t *q_bits)
|
||||
{
|
||||
|
||||
uint32_t rows = H_prime_total/N_pusch_symbs;
|
||||
uint32_t cols = N_pusch_symbs;
|
||||
|
||||
uint32_t idx = 0;
|
||||
for(uint32_t j=0; j<rows; j++) {
|
||||
for(uint32_t i=0; i<cols; i++) {
|
||||
for(uint32_t k=0; k<Q_m; k++) {
|
||||
if (q_bits[j*Q_m + i*rows*Q_m + k] >= 10) {
|
||||
q_bits[j*Q_m + i*rows*Q_m + k] -= 10;
|
||||
} else {
|
||||
q_bits[j*Q_m + i*rows*Q_m + k] = g_bits[idx];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int ulsch_encode(sch_t *q, harq_t *harq, uint8_t *data, uint8_t *g_bits, uint8_t *q_bits)
|
||||
{
|
||||
uci_data_t uci_data;
|
||||
bzero(&uci_data, sizeof(uci_data_t));
|
||||
return ulsch_uci_encode(q, harq, data, uci_data, g_bits, q_bits);
|
||||
}
|
||||
|
||||
|
||||
int ulsch_uci_encode(sch_t *q, harq_t *harq, uint8_t *data, uci_data_t uci_data, uint8_t *g_bits, uint8_t *q_bits)
|
||||
{
|
||||
int ret;
|
||||
|
||||
uint32_t e_offset = 0;
|
||||
uint32_t Q_prime_cqi = 0;
|
||||
uint32_t Q_prime_ack = 0;
|
||||
uint32_t Q_prime_ri = 0;
|
||||
uint32_t Q_m = lte_mod_bits_x_symbol(harq->mcs.mod);
|
||||
|
||||
uint32_t nof_symbols = 12*harq->ul_alloc.L_prb*RE_X_RB;
|
||||
uint32_t nb_q = nof_symbols * Q_m;
|
||||
|
||||
bzero(q_bits, sizeof(uint8_t) * nb_q);
|
||||
|
||||
// Encode RI
|
||||
if (uci_data.uci_ri_len > 0) {
|
||||
float beta = uci_data.beta_ri;
|
||||
if (harq->mcs.tbs == 0) {
|
||||
beta /= uci_data.beta_cqi;
|
||||
}
|
||||
ret = uci_encode_ri(uci_data.uci_ri, uci_data.uci_cqi_len, beta, harq, nb_q/Q_m, q_bits);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
Q_prime_ri = (uint32_t) ret;
|
||||
}
|
||||
|
||||
// Encode CQI
|
||||
if (uci_data.uci_cqi_len > 0) {
|
||||
|
||||
ret = uci_encode_cqi_pusch(&q->uci_cqi, uci_data.uci_cqi, uci_data.uci_cqi_len, uci_data.beta_cqi,
|
||||
Q_prime_ri, harq, g_bits);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
Q_prime_cqi = (uint32_t) ret;
|
||||
}
|
||||
|
||||
e_offset += Q_prime_cqi*Q_m;
|
||||
|
||||
// Encode UL-SCH
|
||||
if (harq->mcs.tbs > 0) {
|
||||
uint32_t G = nb_q/Q_m - Q_prime_ri - Q_prime_cqi;
|
||||
ret = encode_tb(q, harq, data, &g_bits[e_offset], G*Q_m);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// Interleave UL-SCH (and RI and CQI)
|
||||
ulsch_interleave(g_bits, Q_m, nb_q/Q_m, harq->nof_symb, q_bits);
|
||||
|
||||
// Encode (and interleave) ACK
|
||||
if (uci_data.uci_ack_len > 0) {
|
||||
float beta = uci_data.beta_ack;
|
||||
if (harq->mcs.tbs == 0) {
|
||||
beta /= uci_data.beta_cqi;
|
||||
}
|
||||
ret = uci_encode_ack(uci_data.uci_ack, uci_data.uci_cqi_len, beta, harq, nb_q/Q_m, q_bits);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
Q_prime_ack = (uint32_t) ret;
|
||||
}
|
||||
|
||||
INFO("Q_prime_ack=%d, Q_prime_cqi=%d, Q_prime_ri=%d\n",Q_prime_ack, Q_prime_cqi, Q_prime_ri);
|
||||
|
||||
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
@ -0,0 +1,358 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/phch/uci.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
#include "liblte/phy/fec/convcoder.h"
|
||||
#include "liblte/phy/fec/crc.h"
|
||||
#include "liblte/phy/fec/rm_conv.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
/* Table 5.2.2.6.4-1: Basis sequence for (32, O) code */
|
||||
static uint8_t M_basis_seq_pusch[32][11]={
|
||||
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 },
|
||||
{1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1 },
|
||||
{1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1 },
|
||||
{1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 },
|
||||
{1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1 },
|
||||
{1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 },
|
||||
{1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1 },
|
||||
{1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1 },
|
||||
{1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1 },
|
||||
{1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1 },
|
||||
{1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1 },
|
||||
{1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1 },
|
||||
{1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1 },
|
||||
{1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1 },
|
||||
{1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1 },
|
||||
{1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0 },
|
||||
{1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 },
|
||||
{1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0 },
|
||||
{1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
|
||||
{1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 },
|
||||
{1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1 },
|
||||
{1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1 },
|
||||
{1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1 },
|
||||
{1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 },
|
||||
{1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1 },
|
||||
{1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0 },
|
||||
{1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0 },
|
||||
{1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0 },
|
||||
{1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
|
||||
static uint8_t M_basis_seq_pucch[20][13]={
|
||||
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
|
||||
{1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0},
|
||||
{1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1},
|
||||
{1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1},
|
||||
{1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1},
|
||||
{1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1},
|
||||
{1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1},
|
||||
{1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1},
|
||||
{1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1},
|
||||
{1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1},
|
||||
{1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1},
|
||||
{1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1},
|
||||
{1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1},
|
||||
{1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1},
|
||||
{1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1},
|
||||
{1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1},
|
||||
{1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1},
|
||||
{1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1},
|
||||
{1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
|
||||
{1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
int uci_cqi_init(uci_cqi_pusch_t *q) {
|
||||
if (crc_init(&q->crc, LTE_CRC8, 8)) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void uci_cqi_free(uci_cqi_pusch_t *q) {
|
||||
|
||||
}
|
||||
|
||||
static uint32_t Q_prime_cqi(uint32_t O, float beta, uint32_t Q_prime_ri, harq_t *harq) {
|
||||
uint32_t M_sc = harq->ul_alloc.L_prb * RE_X_RB;
|
||||
|
||||
uint32_t K = harq->cb_segm.C1*harq->cb_segm.K1 +
|
||||
harq->cb_segm.C2*harq->cb_segm.K2;
|
||||
|
||||
uint32_t Q_prime = 0;
|
||||
if (K > 0) {
|
||||
uint32_t M_sc_init = harq->nof_prb * RE_X_RB;
|
||||
uint32_t L = (O<11)?0:8;
|
||||
uint32_t x = (uint32_t) ceilf((float) (O+L)*M_sc_init*harq->nof_symb*beta/K);
|
||||
|
||||
Q_prime = MIN(x, M_sc * harq->nof_symb - Q_prime_ri);
|
||||
} else {
|
||||
Q_prime = 12*harq->ul_alloc.L_prb*RE_X_RB - Q_prime_ri;
|
||||
}
|
||||
|
||||
return Q_prime;
|
||||
}
|
||||
|
||||
/* Encode UCI CQI/PMI for payloads equal or lower to 11 bits (Sec 5.2.2.6.4)
|
||||
*/
|
||||
int encode_cqi_short(uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t *q_bits, uint32_t Q)
|
||||
{
|
||||
if (nof_bits < MAX_CQI_LEN_PUSCH &&
|
||||
q != NULL &&
|
||||
data != NULL &&
|
||||
q_bits != NULL)
|
||||
{
|
||||
for (int i=0;i<32;i++) {
|
||||
q->encoded_cqi[i] = 0;
|
||||
for (int n=0;n<nof_bits;n++) {
|
||||
q->encoded_cqi[i] += (data[n] * M_basis_seq_pusch[i][n]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0;i<Q;i++) {
|
||||
q_bits[i] = q->encoded_cqi[i%32]%2;
|
||||
}
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encode UCI CQI/PMI for payloads greater than 11 bits (go through CRC, conv coder and rate match)
|
||||
*/
|
||||
int encode_cqi_long(uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t *q_bits, uint32_t Q)
|
||||
{
|
||||
convcoder_t encoder;
|
||||
|
||||
if (nof_bits + 8 < MAX_CQI_LEN_PUSCH &&
|
||||
q != NULL &&
|
||||
data != NULL &&
|
||||
q_bits != NULL)
|
||||
{
|
||||
|
||||
|
||||
int poly[3] = { 0x6D, 0x4F, 0x57 };
|
||||
encoder.K = 7;
|
||||
encoder.R = 3;
|
||||
encoder.tail_biting = true;
|
||||
memcpy(encoder.poly, poly, 3 * sizeof(int));
|
||||
|
||||
memcpy(q->tmp_cqi, data, sizeof(uint8_t) * nof_bits);
|
||||
crc_attach(&q->crc, q->tmp_cqi, nof_bits);
|
||||
|
||||
convcoder_encode(&encoder, q->tmp_cqi, q->encoded_cqi, nof_bits + 8);
|
||||
|
||||
DEBUG("CConv output: ", 0);
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_b(stdout, q->encoded_cqi, 3 * (nof_bits + 8));
|
||||
}
|
||||
|
||||
rm_conv_tx(q->encoded_cqi, 3 * (nof_bits + 8), q_bits, Q);
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212
|
||||
*/
|
||||
int uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[CQI_CODED_PUCCH_B])
|
||||
{
|
||||
if (cqi_len <= MAX_CQI_LEN_PUCCH) {
|
||||
for (uint32_t i=0;i<CQI_CODED_PUCCH_B;i++) {
|
||||
uint64_t x=0;
|
||||
for (uint32_t n=0;n<cqi_len;n++) {
|
||||
x += cqi_data[n]*M_basis_seq_pucch[n][i];
|
||||
}
|
||||
b_bits[i] = (uint8_t) (x%2);
|
||||
}
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encode UCI CQI/PMI as described in 5.2.2.6 of 36.212
|
||||
*/
|
||||
int uci_encode_cqi_pusch(uci_cqi_pusch_t *q, uint8_t *cqi_data, uint32_t cqi_len, float beta, uint32_t Q_prime_ri,
|
||||
harq_t *harq, uint8_t *q_bits)
|
||||
{
|
||||
|
||||
uint32_t Q_prime = Q_prime_cqi(cqi_len, beta, Q_prime_ri, harq);
|
||||
uint32_t Q_m = lte_mod_bits_x_symbol(harq->mcs.mod);
|
||||
|
||||
int ret = LIBLTE_ERROR;
|
||||
if (cqi_len <= 11) {
|
||||
ret = encode_cqi_short(q, cqi_data, cqi_len, q_bits, Q_prime*Q_m);
|
||||
} else {
|
||||
ret = encode_cqi_long(q, cqi_data, cqi_len, q_bits, Q_prime*Q_m);
|
||||
}
|
||||
if (ret) {
|
||||
return ret;
|
||||
} else {
|
||||
return (int) Q_prime;
|
||||
}
|
||||
}
|
||||
|
||||
/* Inserts UCI-ACK bits into the correct positions in the g buffer before interleaving */
|
||||
static int uci_ulsch_interleave_ack(uint8_t ack_coded_bits[6], uint32_t ack_q_bit_idx,
|
||||
uint32_t Q_m, uint32_t H_prime_total, uint32_t N_pusch_symbs, lte_cp_t cp,
|
||||
uint8_t *q_bits) {
|
||||
|
||||
const uint32_t ack_column_set_norm[4] = {2, 3, 8, 9};
|
||||
const uint32_t ack_column_set_ext[4] = {1, 2, 6, 7};
|
||||
|
||||
if (H_prime_total/N_pusch_symbs >= 1+ack_q_bit_idx/4) {
|
||||
uint32_t row = H_prime_total/N_pusch_symbs-1-ack_q_bit_idx/4;
|
||||
uint32_t colidx = (3*ack_q_bit_idx)%4;
|
||||
uint32_t col = CP_ISNORM(cp)?ack_column_set_norm[colidx]:ack_column_set_ext[colidx];
|
||||
for(uint32_t k=0; k<Q_m; k++) {
|
||||
q_bits[row *Q_m +
|
||||
(H_prime_total/N_pusch_symbs)*col*Q_m + k] = ack_coded_bits[k];
|
||||
}
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Error interleaving UCI-ACK bit idx %d for H_prime_total=%d and N_pusch_symbs=%d\n",
|
||||
ack_q_bit_idx, H_prime_total, N_pusch_symbs);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Inserts UCI-RI bits into the correct positions in the g buffer before interleaving */
|
||||
static int uci_ulsch_interleave_ri(uint8_t ri_coded_bits[6], uint32_t ri_q_bit_idx,
|
||||
uint32_t Q_m, uint32_t H_prime_total, uint32_t N_pusch_symbs, lte_cp_t cp,
|
||||
uint8_t *q_bits) {
|
||||
|
||||
static uint32_t ri_column_set_norm[4] = {1, 4, 7, 10};
|
||||
static uint32_t ri_column_set_ext[4] = {0, 3, 5, 8};
|
||||
|
||||
if (H_prime_total/N_pusch_symbs >= 1+ri_q_bit_idx/4) {
|
||||
uint32_t row = H_prime_total/N_pusch_symbs-1-ri_q_bit_idx/4;
|
||||
uint32_t colidx = (3*ri_q_bit_idx)%4;
|
||||
uint32_t col = CP_ISNORM(cp)?ri_column_set_norm[colidx]:ri_column_set_ext[colidx];
|
||||
printf("r=%d-%d\n",H_prime_total/N_pusch_symbs,1+ri_q_bit_idx/4);
|
||||
for(uint32_t k=0; k<Q_m; k++) {
|
||||
q_bits[row *Q_m + (H_prime_total/N_pusch_symbs)*col*Q_m + k] = 10+ri_coded_bits[k];
|
||||
}
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Error interleaving UCI-RI bit idx %d for H_prime_total=%d and N_pusch_symbs=%d\n",
|
||||
ri_q_bit_idx, H_prime_total, N_pusch_symbs);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static uint32_t Q_prime_ri_ack(uint32_t O, uint32_t O_cqi, float beta, harq_t *harq) {
|
||||
uint32_t M_sc = harq->ul_alloc.L_prb * RE_X_RB;
|
||||
|
||||
uint32_t K = harq->cb_segm.C1*harq->cb_segm.K1 +
|
||||
harq->cb_segm.C2*harq->cb_segm.K2;
|
||||
|
||||
// If not carrying UL-SCH, get Q_prime according to 5.2.4.1
|
||||
if (K == 0) {
|
||||
if (O_cqi <= 11) {
|
||||
K = O_cqi;
|
||||
} else {
|
||||
K = O_cqi+8;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t M_sc_init = harq->nof_prb * RE_X_RB;
|
||||
|
||||
uint32_t x = (uint32_t) ceilf((float) O*M_sc_init*harq->nof_symb*beta/K);
|
||||
|
||||
uint32_t Q_prime = MIN(x, 4*M_sc);
|
||||
|
||||
return Q_prime;
|
||||
}
|
||||
|
||||
static void encode_ri_ack(uint8_t data, uint8_t q_encoded_bits[6], uint8_t Q_m) {
|
||||
q_encoded_bits[0] = data;
|
||||
q_encoded_bits[1] = 2;
|
||||
for (uint32_t i=2;i<Q_m;i++) {
|
||||
q_encoded_bits[i] = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
|
||||
* Currently only supporting 1-bit HARQ
|
||||
*/
|
||||
int uci_encode_ack(uint8_t data, uint32_t O_cqi, float beta, harq_t *harq, uint32_t H_prime_total, uint8_t *q_bits)
|
||||
{
|
||||
uint32_t Q_m = lte_mod_bits_x_symbol(harq->mcs.mod);
|
||||
uint32_t Qprime = Q_prime_ri_ack(1, O_cqi, beta, harq);
|
||||
uint8_t q_encoded_bits[6];
|
||||
|
||||
encode_ri_ack(data, q_encoded_bits, Q_m);
|
||||
|
||||
for (uint32_t i=0;i<Qprime;i++) {
|
||||
uci_ulsch_interleave_ack(q_encoded_bits, i, Q_m, H_prime_total, harq->nof_symb, harq->cell.cp, q_bits);
|
||||
}
|
||||
|
||||
return (int) Qprime;
|
||||
}
|
||||
|
||||
|
||||
/* Encode UCI RI bits as described in 5.2.2.6 of 36.212
|
||||
* Currently only supporting 1-bit RI
|
||||
*/
|
||||
int uci_encode_ri(uint8_t data, uint32_t O_cqi, float beta, harq_t *harq, uint32_t H_prime_total, uint8_t *q_bits)
|
||||
{
|
||||
uint32_t Q_m = lte_mod_bits_x_symbol(harq->mcs.mod);
|
||||
uint32_t Qprime = Q_prime_ri_ack(1, O_cqi, beta, harq);
|
||||
uint8_t q_encoded_bits[6];
|
||||
|
||||
encode_ri_ack(data, q_encoded_bits, Q_m);
|
||||
|
||||
for (uint32_t i=0;i<Qprime;i++) {
|
||||
uci_ulsch_interleave_ri(q_encoded_bits, i, Q_m, H_prime_total, harq->nof_symb, harq->cell.cp, q_bits);
|
||||
}
|
||||
|
||||
return (int) Qprime;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
*
|
||||
* \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 "liblte/phy/phy.h"
|
||||
#include "liblte/mex/mexutils.h"
|
||||
|
||||
#define UECFG prhs[0]
|
||||
#define PUSCHCFG prhs[1]
|
||||
#define OUTLEN prhs[2]
|
||||
#define TRBLKIN prhs[3]
|
||||
#define NOF_INPUTS 4
|
||||
|
||||
void help()
|
||||
{
|
||||
mexErrMsgTxt
|
||||
("[cwout] = liblte_dlsch_encode(ue, chs, outlen, trblkin)\n\n");
|
||||
}
|
||||
|
||||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
sch_t dlsch;
|
||||
uint8_t *trblkin;
|
||||
ra_mcs_t mcs;
|
||||
ra_dl_alloc_t prb_alloc;
|
||||
harq_t harq_process;
|
||||
uint32_t rv;
|
||||
|
||||
if (nrhs < NOF_INPUTS) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sch_init(&dlsch)) {
|
||||
mexErrMsgTxt("Error initiating DL-SCH\n");
|
||||
return;
|
||||
}
|
||||
lte_cell_t cell;
|
||||
cell.nof_prb = 100;
|
||||
cell.id=1;
|
||||
if (harq_init(&harq_process, cell)) {
|
||||
mexErrMsgTxt("Error initiating HARQ\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin);
|
||||
if (mcs.tbs == 0) {
|
||||
mexErrMsgTxt("Error trblklen is zero\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &rv)) {
|
||||
mexErrMsgTxt("Field RV not found in dlsch config\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation");
|
||||
|
||||
if (!strcmp(mod_str, "QPSK")) {
|
||||
mcs.mod = LTE_QPSK;
|
||||
} else if (!strcmp(mod_str, "16QAM")) {
|
||||
mcs.mod = LTE_QAM16;
|
||||
} else if (!strcmp(mod_str, "64QAM")) {
|
||||
mcs.mod = LTE_QAM64;
|
||||
} else {
|
||||
mexErrMsgTxt("Unknown modulation\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mxFree(mod_str);
|
||||
|
||||
if (harq_setup_dl(&harq_process, mcs, rv, 0, &prb_alloc)) {
|
||||
mexErrMsgTxt("Error configuring HARQ process\n");
|
||||
return;
|
||||
}
|
||||
harq_process.nof_bits = mxGetScalar(OUTLEN);
|
||||
|
||||
uint8_t *e_bits = vec_malloc(harq_process.nof_bits* sizeof(uint8_t));
|
||||
if (!e_bits) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dlsch_encode(&dlsch, &harq_process, trblkin, e_bits)) {
|
||||
mexErrMsgTxt("Error encoding TB\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_uint8(e_bits, &plhs[0], harq_process.nof_bits, 1);
|
||||
}
|
||||
|
||||
sch_free(&dlsch);
|
||||
|
||||
free(trblkin);
|
||||
free(e_bits);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,116 @@
|
||||
/**
|
||||
*
|
||||
* \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 "liblte/phy/phy.h"
|
||||
#include "liblte/mex/mexutils.h"
|
||||
|
||||
/** MEX function to be called from MATLAB to test the channel estimator
|
||||
*/
|
||||
|
||||
#define UECFG prhs[0]
|
||||
#define PRACHCFG prhs[1]
|
||||
#define NOF_INPUTS 2
|
||||
|
||||
void help()
|
||||
{
|
||||
mexErrMsgTxt
|
||||
("waveform = liblte_prach(ueConfig, prachConfig)\n\n");
|
||||
}
|
||||
|
||||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
|
||||
if (nrhs != NOF_INPUTS) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t n_ul_rb = 0;
|
||||
if (mexutils_read_uint32_struct(UECFG, "NULRB", &n_ul_rb)) {
|
||||
mexErrMsgTxt("Field NULRB not found in UE config\n");
|
||||
return;
|
||||
}
|
||||
int r = lte_symbol_sz(n_ul_rb);
|
||||
if (r < 0) {
|
||||
mexErrMsgTxt("Invalid NULRB\n");
|
||||
return;
|
||||
}
|
||||
uint32_t N_ifft_ul = (uint32_t) r;
|
||||
|
||||
uint32_t sf_idx = 0;
|
||||
mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx);
|
||||
uint32_t nframe = 0;
|
||||
mexutils_read_uint32_struct(UECFG, "NFrame", &nframe);
|
||||
|
||||
uint32_t preamble_format = 0;
|
||||
mexutils_read_uint32_struct(PRACHCFG, "Format", &preamble_format);
|
||||
uint32_t root_seq_idx = 0;
|
||||
mexutils_read_uint32_struct(PRACHCFG, "SeqIdx", &root_seq_idx);
|
||||
uint32_t seq_idx = 0;
|
||||
mexutils_read_uint32_struct(PRACHCFG, "PreambleIdx", &seq_idx);
|
||||
uint32_t zero_corr_zone = 0;
|
||||
mexutils_read_uint32_struct(PRACHCFG, "CyclicShiftIdx", &zero_corr_zone);
|
||||
uint32_t high_speed_flag = 0;
|
||||
mexutils_read_uint32_struct(PRACHCFG, "HighSpeed", &high_speed_flag);
|
||||
uint32_t timing_offset = 0;
|
||||
mexutils_read_uint32_struct(PRACHCFG, "TimingOffset", &timing_offset);
|
||||
uint32_t frequency_offset = 0;
|
||||
mexutils_read_uint32_struct(PRACHCFG, "FreqOffset", &frequency_offset);
|
||||
|
||||
prach_t prach;
|
||||
if (prach_init(&prach, N_ifft_ul, preamble_format, root_seq_idx, high_speed_flag, zero_corr_zone)) {
|
||||
mexErrMsgTxt("Error initiating PRACH\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t nof_samples = lte_sampling_freq_hz(n_ul_rb) * 0.003;
|
||||
|
||||
cf_t *signal = vec_malloc(sizeof(cf_t) * nof_samples);
|
||||
if (!signal) {
|
||||
mexErrMsgTxt("malloc");
|
||||
return;
|
||||
}
|
||||
bzero(signal, sizeof(cf_t) * nof_samples);
|
||||
if (prach_gen(&prach, seq_idx, frequency_offset, 0.2, signal)) {
|
||||
mexErrMsgTxt("Error generating PRACH\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (nlhs >= 0) {
|
||||
mexutils_write_cf(signal, &plhs[0], nof_samples, 1);
|
||||
}
|
||||
|
||||
free(signal);
|
||||
|
||||
prach_free(&prach);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,225 @@
|
||||
/**
|
||||
*
|
||||
* \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 "liblte/phy/phy.h"
|
||||
#include "liblte/mex/mexutils.h"
|
||||
|
||||
/** MEX function to be called from MATLAB to test the channel estimator
|
||||
*/
|
||||
|
||||
#define UECFG prhs[0]
|
||||
#define PUSCHCFG prhs[1]
|
||||
#define TRBLKIN prhs[2]
|
||||
#define CQI prhs[3]
|
||||
#define RI prhs[4]
|
||||
#define ACK prhs[5]
|
||||
#define NOF_INPUTS 6
|
||||
|
||||
void help()
|
||||
{
|
||||
mexErrMsgTxt
|
||||
("sym=liblte_pusch_encode(ue, chs, trblkin, cqi, ri, ack)\n\n");
|
||||
}
|
||||
|
||||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
|
||||
if (nrhs != NOF_INPUTS) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
lte_cell_t cell;
|
||||
bzero(&cell, sizeof(lte_cell_t));
|
||||
cell.nof_ports = 1;
|
||||
if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) {
|
||||
mexErrMsgTxt("Field NCellID not found in UE config\n");
|
||||
return;
|
||||
}
|
||||
if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) {
|
||||
mexErrMsgTxt("Field NULRB not found in UE config\n");
|
||||
return;
|
||||
}
|
||||
pusch_t pusch;
|
||||
if (pusch_init(&pusch, cell)) {
|
||||
mexErrMsgTxt("Error initiating PUSCH\n");
|
||||
return;
|
||||
}
|
||||
uint32_t rnti32=0;
|
||||
if (mexutils_read_uint32_struct(UECFG, "RNTI", &rnti32)) {
|
||||
mexErrMsgTxt("Field RNTI not found in pusch config\n");
|
||||
return;
|
||||
}
|
||||
pusch_set_rnti(&pusch, (uint16_t) (rnti32 & 0xffff));
|
||||
|
||||
|
||||
|
||||
|
||||
uint32_t sf_idx=0;
|
||||
if (mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx)) {
|
||||
mexErrMsgTxt("Field NSubframe not found in UE config\n");
|
||||
return;
|
||||
}
|
||||
ra_mcs_t mcs;
|
||||
char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation");
|
||||
if (!strcmp(mod_str, "QPSK")) {
|
||||
mcs.mod = LTE_QPSK;
|
||||
} else if (!strcmp(mod_str, "16QAM")) {
|
||||
mcs.mod = LTE_QAM16;
|
||||
} else if (!strcmp(mod_str, "64QAM")) {
|
||||
mcs.mod = LTE_QAM64;
|
||||
} else {
|
||||
mexErrMsgTxt("Unknown modulation\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mxFree(mod_str);
|
||||
|
||||
float *prbset = NULL;
|
||||
mxArray *p;
|
||||
p = mxGetField(PUSCHCFG, 0, "PRBSet");
|
||||
if (!p) {
|
||||
mexErrMsgTxt("Error field PRBSet not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ra_ul_alloc_t prb_alloc;
|
||||
bzero(&prb_alloc, sizeof(ra_ul_alloc_t));
|
||||
prb_alloc.L_prb = mexutils_read_f(p, &prbset);
|
||||
prb_alloc.n_prb[0] = prbset[0];
|
||||
prb_alloc.n_prb[1] = prbset[0];
|
||||
free(prbset);
|
||||
|
||||
mexPrintf("L_prb: %d, n_prb: %d\n", prb_alloc.L_prb, prb_alloc.n_prb[2*sf_idx]);
|
||||
|
||||
uint8_t *trblkin = NULL;
|
||||
mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin);
|
||||
|
||||
harq_t harq_process;
|
||||
if (harq_init(&harq_process, cell)) {
|
||||
mexErrMsgTxt("Error initiating HARQ process\n");
|
||||
return;
|
||||
}
|
||||
if (harq_setup_ul(&harq_process, mcs, 0, sf_idx, &prb_alloc)) {
|
||||
mexErrMsgTxt("Error configuring HARQ process\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t nof_re = RE_X_RB*cell.nof_prb*2*CP_NSYMB(cell.cp);
|
||||
cf_t *sf_symbols = vec_malloc(sizeof(cf_t) * nof_re);
|
||||
if (!sf_symbols) {
|
||||
mexErrMsgTxt("malloc");
|
||||
return;
|
||||
}
|
||||
bzero(sf_symbols, sizeof(cf_t) * nof_re);
|
||||
|
||||
|
||||
uci_data_t uci_data;
|
||||
bzero(&uci_data, sizeof(uci_data_t));
|
||||
uci_data.uci_cqi_len = mexutils_read_uint8(CQI, &uci_data.uci_cqi);
|
||||
uint8_t *tmp;
|
||||
uci_data.uci_ri_len = mexutils_read_uint8(RI, &tmp);
|
||||
if (uci_data.uci_ri_len > 0) {
|
||||
uci_data.uci_ri = *tmp;
|
||||
}
|
||||
free(tmp);
|
||||
uci_data.uci_ack_len = mexutils_read_uint8(ACK, &tmp);
|
||||
if (uci_data.uci_ack_len > 0) {
|
||||
uci_data.uci_ack = *tmp;
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
|
||||
if (mexutils_read_float_struct(PUSCHCFG, "BetaCQI", &uci_data.beta_cqi)) {
|
||||
uci_data.beta_cqi = 2.0;
|
||||
}
|
||||
if (mexutils_read_float_struct(PUSCHCFG, "BetaRI", &uci_data.beta_ri)) {
|
||||
uci_data.beta_ri = 2.0;
|
||||
}
|
||||
if (mexutils_read_float_struct(PUSCHCFG, "BetaACK", &uci_data.beta_ack)) {
|
||||
uci_data.beta_ack = 2.0;
|
||||
}
|
||||
mexPrintf("Beta_CQI: %.1f, Beta_ACK: %.1f, Beta_RI: %.1f\n",
|
||||
uci_data.beta_cqi, uci_data.beta_ack, uci_data.beta_ri);
|
||||
mexPrintf("TRBL_len: %d, CQI_len: %d, ACK_len: %d (%d), RI_len: %d (%d)\n", mcs.tbs,
|
||||
uci_data.uci_cqi_len, uci_data.uci_ack_len, uci_data.uci_ack, uci_data.uci_ri_len, uci_data.uci_ri);
|
||||
|
||||
|
||||
mexPrintf("NofRE: %d, NofBits: %d, TBS: %d\n", harq_process.nof_re, harq_process.nof_bits, harq_process.mcs.tbs);
|
||||
int r = pusch_uci_encode(&pusch, &harq_process, trblkin, uci_data, sf_symbols);
|
||||
if (r < 0) {
|
||||
mexErrMsgTxt("Error encoding PUSCH\n");
|
||||
return;
|
||||
}
|
||||
uint32_t rv=0;
|
||||
if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &rv)) {
|
||||
mexErrMsgTxt("Field RV not found in pdsch config\n");
|
||||
return;
|
||||
}
|
||||
if (rv > 0) {
|
||||
if (harq_setup_ul(&harq_process, mcs, rv, sf_idx, &prb_alloc)) {
|
||||
mexErrMsgTxt("Error configuring HARQ process\n");
|
||||
return;
|
||||
}
|
||||
r = pusch_uci_encode(&pusch, &harq_process, trblkin, uci_data, sf_symbols);
|
||||
if (r < 0) {
|
||||
mexErrMsgTxt("Error encoding PUSCH\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cf_t *scfdma = vec_malloc(sizeof(cf_t) * SF_LEN_PRB(cell.nof_prb));
|
||||
bzero(scfdma, sizeof(cf_t) * SF_LEN_PRB(cell.nof_prb));
|
||||
lte_fft_t fft;
|
||||
lte_ifft_init(&fft, CPNORM, cell.nof_prb);
|
||||
lte_fft_set_normalize(&fft, true);
|
||||
lte_fft_set_freq_shift(&fft, 0.5);
|
||||
lte_ifft_run_sf(&fft, sf_symbols, scfdma);
|
||||
|
||||
// Matlab toolbox expects further normalization
|
||||
vec_sc_prod_cfc(scfdma, 1.0/sqrtf(lte_symbol_sz(cell.nof_prb)), scfdma, SF_LEN_PRB(cell.nof_prb));
|
||||
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_cf(scfdma, &plhs[0], SF_LEN_PRB(cell.nof_prb), 1);
|
||||
}
|
||||
if (nlhs >= 2) {
|
||||
mexutils_write_cf(sf_symbols, &plhs[1], nof_re, 1);
|
||||
}
|
||||
if (nlhs >= 3) {
|
||||
mexutils_write_cf(pusch.pusch_z, &plhs[2], harq_process.nof_re, 1);
|
||||
}
|
||||
pusch_free(&pusch);
|
||||
free(trblkin);
|
||||
free(uci_data.uci_cqi);
|
||||
free(sf_symbols);
|
||||
free(scfdma);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,274 @@
|
||||
/**
|
||||
*
|
||||
* \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 <sys/time.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
lte_cell_t cell = {
|
||||
6, // nof_prb
|
||||
1, // nof_ports
|
||||
0, // cell_id
|
||||
CPNORM, // cyclic prefix
|
||||
R_1_6, // PHICH resources
|
||||
PHICH_NORM // PHICH length
|
||||
};
|
||||
|
||||
uint32_t cfi = 2;
|
||||
uint32_t tbs = 0;
|
||||
uint32_t subframe = 1;
|
||||
lte_mod_t modulation = LTE_QPSK;
|
||||
uint32_t rv_idx = 0;
|
||||
uint32_t L_prb = 2;
|
||||
uint32_t n_prb = 0;
|
||||
int freq_hop = -1;
|
||||
int riv = -1;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [csrnfvmtLNF] -l TBS \n", prog);
|
||||
printf("\t-m modulation (1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64) [Default BPSK]\n");
|
||||
printf("\t-c cell id [Default %d]\n", cell.id);
|
||||
printf("\t-s subframe [Default %d]\n", subframe);
|
||||
printf("\t-L L_prb [Default %d]\n", L_prb);
|
||||
printf("\t-N n_prb [Default %d]\n", n_prb);
|
||||
printf("\t-F frequency hopping [Default %d]\n", freq_hop);
|
||||
printf("\t-R RIV [Default %d]\n", riv);
|
||||
printf("\t-r rv_idx [Default %d]\n", rv_idx);
|
||||
printf("\t-f cfi [Default %d]\n", cfi);
|
||||
printf("\t-n cell.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, "lcnfvmtsrLNFR")) != -1) {
|
||||
switch(opt) {
|
||||
case 'm':
|
||||
switch(atoi(argv[optind])) {
|
||||
case 1:
|
||||
modulation = LTE_BPSK;
|
||||
break;
|
||||
case 2:
|
||||
modulation = LTE_QPSK;
|
||||
break;
|
||||
case 4:
|
||||
modulation = LTE_QAM16;
|
||||
break;
|
||||
case 6:
|
||||
modulation = LTE_QAM64;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid modulation %d. Possible values: "
|
||||
"(1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64)\n", atoi(argv[optind]));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
subframe = atoi(argv[optind]);
|
||||
break;
|
||||
case 'L':
|
||||
L_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 'N':
|
||||
n_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 'R':
|
||||
riv = atoi(argv[optind]);
|
||||
break;
|
||||
case 'F':
|
||||
freq_hop = atoi(argv[optind]);
|
||||
break;
|
||||
case 'r':
|
||||
rv_idx = atoi(argv[optind]);
|
||||
break;
|
||||
case 'l':
|
||||
tbs = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
pusch_t pusch;
|
||||
uint8_t *data = NULL;
|
||||
cf_t *sf_symbols = NULL;
|
||||
int ret = -1;
|
||||
struct timeval t[3];
|
||||
ra_mcs_t mcs;
|
||||
ra_ul_alloc_t prb_alloc;
|
||||
harq_t harq_process;
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
mcs.tbs = tbs;
|
||||
mcs.mod = modulation;
|
||||
|
||||
bzero(&prb_alloc, sizeof(ra_ul_alloc_t));
|
||||
|
||||
if (pusch_init(&pusch, cell)) {
|
||||
fprintf(stderr, "Error creating PDSCH object\n");
|
||||
goto quit;
|
||||
}
|
||||
pusch_set_rnti(&pusch, 1234);
|
||||
|
||||
if (harq_init(&harq_process, cell)) {
|
||||
fprintf(stderr, "Error initiating HARQ process\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
printf("Encoding rv_idx=%d\n",rv_idx);
|
||||
|
||||
uint8_t tmp[20];
|
||||
for (uint32_t i=0;i<20;i++) {
|
||||
tmp[i] = 1;
|
||||
}
|
||||
uci_data_t uci_data;
|
||||
bzero(&uci_data, sizeof(uci_data_t));
|
||||
uci_data.beta_cqi = 2.0;
|
||||
uci_data.beta_ri = 2.0;
|
||||
uci_data.beta_ack = 2.0;
|
||||
|
||||
uci_data.uci_cqi_len = 0;
|
||||
uci_data.uci_ri_len = 0;
|
||||
uci_data.uci_ack_len = 0;
|
||||
|
||||
uci_data.uci_cqi = tmp;
|
||||
uci_data.uci_ri = 1;
|
||||
uci_data.uci_ack = 1;
|
||||
|
||||
ra_pusch_t pusch_dci;
|
||||
pusch_dci.freq_hop_fl = freq_hop;
|
||||
if (riv < 0) {
|
||||
pusch_dci.type2_alloc.L_crb = L_prb;
|
||||
pusch_dci.type2_alloc.RB_start = n_prb;
|
||||
} else {
|
||||
ra_type2_from_riv((uint32_t) riv, &pusch_dci.type2_alloc.L_crb, &pusch_dci.type2_alloc.RB_start, cell.nof_prb, cell.nof_prb);
|
||||
}
|
||||
ra_ul_alloc(&prb_alloc, &pusch_dci, 0, cell.nof_prb);
|
||||
|
||||
if (harq_setup_ul(&harq_process, mcs, 0, subframe, &prb_alloc)) {
|
||||
fprintf(stderr, "Error configuring HARQ process\n");
|
||||
goto quit;
|
||||
}
|
||||
pusch_hopping_cfg_t ul_hopping;
|
||||
ul_hopping.n_sb = 1;
|
||||
ul_hopping.hopping_offset = 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);
|
||||
sf_symbols = vec_malloc(sizeof(cf_t) * nof_re);
|
||||
if (!sf_symbols) {
|
||||
perror("malloc");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
data = malloc(sizeof(uint8_t) * mcs.tbs);
|
||||
if (!data) {
|
||||
perror("malloc");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
for (uint32_t i=0;i<mcs.tbs;i++) {
|
||||
data[i] = 1;
|
||||
}
|
||||
|
||||
if (pusch_uci_encode(&pusch, &harq_process, data, uci_data, sf_symbols)) {
|
||||
fprintf(stderr, "Error encoding TB\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (rv_idx > 0) {
|
||||
if (harq_setup_ul(&harq_process, mcs, rv_idx, subframe, &prb_alloc)) {
|
||||
fprintf(stderr, "Error configuring HARQ process\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (pusch_uci_encode(&pusch, &harq_process, data, uci_data, sf_symbols)) {
|
||||
fprintf(stderr, "Error encoding TB\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cf_t *scfdma = vec_malloc(sizeof(cf_t) * SF_LEN_PRB(cell.nof_prb));
|
||||
bzero(scfdma, sizeof(cf_t) * SF_LEN_PRB(cell.nof_prb));
|
||||
lte_fft_t fft;
|
||||
lte_ifft_init(&fft, CPNORM, cell.nof_prb);
|
||||
lte_fft_set_freq_shift(&fft, 0.5);
|
||||
lte_ifft_run_sf(&fft, sf_symbols, scfdma);
|
||||
|
||||
gettimeofday(&t[1], NULL);
|
||||
//int r = pusch_decode(&pusch, slot_symbols[0], ce, 0, data, subframe, &harq_process, rv);
|
||||
int r = 0;
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
if (r) {
|
||||
printf("Error decoding\n");
|
||||
ret = -1;
|
||||
goto quit;
|
||||
} else {
|
||||
printf("DECODED OK in %d:%d (%.2f Mbps)\n", (int) t[0].tv_sec, (int) t[0].tv_usec, (float) mcs.tbs/t[0].tv_usec);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
quit:
|
||||
pusch_free(&pusch);
|
||||
harq_free(&harq_process);
|
||||
|
||||
if (sf_symbols) {
|
||||
free(sf_symbols);
|
||||
}
|
||||
if (data) {
|
||||
free(data);
|
||||
}
|
||||
if (ret) {
|
||||
printf("Error\n");
|
||||
} else {
|
||||
printf("Ok\n");
|
||||
}
|
||||
exit(ret);
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
/**
|
||||
*
|
||||
* \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 "liblte/phy/phy.h"
|
||||
#include "liblte/mex/mexutils.h"
|
||||
|
||||
#define UECFG prhs[0]
|
||||
#define PUSCHCFG prhs[1]
|
||||
#define TRBLKIN prhs[2]
|
||||
#define CQI prhs[3]
|
||||
#define RI prhs[4]
|
||||
#define ACK prhs[5]
|
||||
#define NOF_INPUTS 6
|
||||
|
||||
void help()
|
||||
{
|
||||
mexErrMsgTxt
|
||||
("[cwout] = liblte_pusch_encode(ue, chs, trblkin, cqi, ri, ack)\n\n");
|
||||
}
|
||||
|
||||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
sch_t ulsch;
|
||||
uint8_t *trblkin;
|
||||
ra_mcs_t mcs;
|
||||
ra_ul_alloc_t prb_alloc;
|
||||
harq_t harq_process;
|
||||
uint32_t rv;
|
||||
uci_data_t uci_data;
|
||||
bzero(&uci_data, sizeof(uci_data_t));
|
||||
|
||||
if (nrhs < NOF_INPUTS) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
if (sch_init(&ulsch)) {
|
||||
mexErrMsgTxt("Error initiating ULSCH\n");
|
||||
return;
|
||||
}
|
||||
lte_cell_t cell;
|
||||
cell.nof_prb = 100;
|
||||
cell.id=1;
|
||||
cell.cp=CPNORM;
|
||||
if (harq_init(&harq_process, cell)) {
|
||||
mexErrMsgTxt("Error initiating HARQ\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin);
|
||||
|
||||
uci_data.uci_cqi_len = mexutils_read_uint8(CQI, &uci_data.uci_cqi);
|
||||
uint8_t *tmp;
|
||||
uci_data.uci_ri_len = mexutils_read_uint8(RI, &tmp);
|
||||
if (uci_data.uci_ri_len > 0) {
|
||||
uci_data.uci_ri = *tmp;
|
||||
}
|
||||
free(tmp);
|
||||
uci_data.uci_ack_len = mexutils_read_uint8(ACK, &tmp);
|
||||
if (uci_data.uci_ack_len > 0) {
|
||||
uci_data.uci_ack = *tmp;
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
mexPrintf("TRBL_len: %d, CQI_len: %d, ACK_len: %d, RI_len: %d\n", mcs.tbs,
|
||||
uci_data.uci_cqi_len, uci_data.uci_ack_len, uci_data.uci_ri_len);
|
||||
|
||||
if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &rv)) {
|
||||
mexErrMsgTxt("Field RV not found in pdsch config\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mexutils_read_float_struct(PUSCHCFG, "BetaCQI", &uci_data.beta_cqi)) {
|
||||
uci_data.beta_cqi = 2.0;
|
||||
}
|
||||
if (mexutils_read_float_struct(PUSCHCFG, "BetaRI", &uci_data.beta_ri)) {
|
||||
uci_data.beta_ri = 2.0;
|
||||
}
|
||||
if (mexutils_read_float_struct(PUSCHCFG, "BetaACK", &uci_data.beta_ack)) {
|
||||
uci_data.beta_ack = 2.0;
|
||||
}
|
||||
mexPrintf("Beta_CQI: %.1f, Beta_ACK: %.1f, Beta_RI: %.1f\n",
|
||||
uci_data.beta_cqi, uci_data.beta_ack, uci_data.beta_ri);
|
||||
|
||||
char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation");
|
||||
|
||||
if (!strcmp(mod_str, "QPSK")) {
|
||||
mcs.mod = LTE_QPSK;
|
||||
} else if (!strcmp(mod_str, "16QAM")) {
|
||||
mcs.mod = LTE_QAM16;
|
||||
} else if (!strcmp(mod_str, "64QAM")) {
|
||||
mcs.mod = LTE_QAM64;
|
||||
} else {
|
||||
mexErrMsgTxt("Unknown modulation\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mxFree(mod_str);
|
||||
|
||||
float *prbset;
|
||||
mxArray *p;
|
||||
p = mxGetField(PUSCHCFG, 0, "PRBSet");
|
||||
if (!p) {
|
||||
mexErrMsgTxt("Error field PRBSet not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
prb_alloc.L_prb = mexutils_read_f(p, &prbset);
|
||||
prb_alloc.n_prb[0] = prbset[0];
|
||||
prb_alloc.n_prb[1] = prbset[0];
|
||||
free(prbset);
|
||||
|
||||
mexPrintf("Q_m: %d, NPRB: %d, RV: %d\n", lte_mod_bits_x_symbol(mcs.mod), prb_alloc.L_prb, rv);
|
||||
|
||||
if (harq_setup_ul(&harq_process, mcs, 0, 0, &prb_alloc)) {
|
||||
mexErrMsgTxt("Error configuring HARQ process\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *q_bits = vec_malloc(harq_process.nof_bits * sizeof(uint8_t));
|
||||
if (!q_bits) {
|
||||
return;
|
||||
}
|
||||
uint8_t *g_bits = vec_malloc(harq_process.nof_bits * sizeof(uint8_t));
|
||||
if (!g_bits) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ulsch_uci_encode(&ulsch, &harq_process, trblkin, uci_data, g_bits, q_bits))
|
||||
{
|
||||
mexErrMsgTxt("Error encoding TB\n");
|
||||
return;
|
||||
}
|
||||
if (rv > 0) {
|
||||
if (harq_setup_ul(&harq_process, mcs, rv, 0, &prb_alloc)) {
|
||||
mexErrMsgTxt("Error configuring HARQ process\n");
|
||||
return;
|
||||
}
|
||||
if (ulsch_uci_encode(&ulsch, &harq_process, trblkin, uci_data, g_bits, q_bits)) {
|
||||
mexErrMsgTxt("Error encoding TB\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_uint8(q_bits, &plhs[0], harq_process.nof_bits, 1);
|
||||
}
|
||||
|
||||
sch_free(&ulsch);
|
||||
harq_free(&harq_process);
|
||||
|
||||
free(trblkin);
|
||||
free(g_bits);
|
||||
free(q_bits);
|
||||
free(uci_data.uci_cqi);
|
||||
|
||||
return;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue