Added PDCCH encoder/decoder. Tested with Amarisoft eNodeB

master
ismagom 11 years ago
parent 587ff2c7f8
commit 869b842415

@ -43,6 +43,7 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SIRNTI 0xFFFF
#define PRNTI 0xFFFE
#define MRNTI 0xFFFD
#define MAX_NSYMB 7
@ -93,7 +94,7 @@ int lte_voffset(int symbol_id, int cell_id, int nof_ports);
typedef enum {
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
} mimo_type_t;
} lte_mimo_type_t;
typedef enum { PHICH_NORM, PHICH_EXT} phich_length_t;
typedef enum { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
@ -113,8 +114,8 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int earfcn_start, int e
int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_nelems);
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems);
int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type);
char *lte_mimotype2str(mimo_type_t type);
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type);
char *lte_mimotype2str(lte_mimo_type_t type);
#endif

@ -38,7 +38,7 @@ int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_sym
int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS]);
int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS], mimo_type_t type);
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
/* Generates the vector of data symbols "d" based on the vector of layer-mapped symbols "x"
@ -48,6 +48,6 @@ int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_l
int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]);
int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], mimo_type_t type);
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
#endif

@ -41,7 +41,7 @@ typedef _Complex float cf_t;
int precoding_single(cf_t *x, cf_t *y, int nof_symbols);
int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols);
int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports,
int nof_symbols, mimo_type_t type);
int nof_symbols, lte_mimo_type_t type);
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "ce"
@ -51,6 +51,6 @@ int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols);
int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols,
mimo_type_t type);
lte_mimo_type_t type);
#endif /* PRECODING_H_ */

@ -40,7 +40,7 @@ typedef struct {
}soft_table_t;
typedef struct {
cf_t* symbol_table; // bit-to-symbol mapping
cf_t* symbol_table; // bit-to-symbol mapping
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
int nsymbols; // number of modulation symbols
int nbits_x_symbol; // number of bits per symbol
@ -49,7 +49,7 @@ typedef struct {
// Modulation standards
enum modem_std {
LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64
LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6
};
void modem_table_init(modem_table_t* q);

@ -25,11 +25,12 @@
*
*/
#ifndef DCI_
#define DCI_
#include "lte/common/base.h"
#include <stdint.h>
#include "lte/phch/ra.h"
typedef _Complex float cf_t;
@ -37,77 +38,63 @@ typedef _Complex float cf_t;
* DCI message generation according to the formats, as specified in
* 36.212 Section 5.3.3.1
*
* Call the function dci_init(&q) to generate a collection of DCI messages
* to be transmitted in a subframe. Each subsequent call to
* dci_add_formatXX(&q, ...) generates the DCI message and appends the data
* to the collection "q".
*
*/
#define DCI_MAX_BITS 45
typedef enum {
FORMAT0,
FORMAT1,
FORMAT1A,
/* ... */
}dci_format_t;
#define DCI_MAX_BITS 57
typedef enum {
DCI_COMMON=0, DCI_UE=1
}dci_spec_t;
/** TODO: this is Release 8 */
typedef struct {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {hop_disabled, hop_half, hop_quart, hop_quart_neg, hop_type_2} freq_hop_fl;
int n_rb_ul; // number of resource blocks
int riv; // Resource Indication Value (36.213 8.1)
int mcs_and_rv; // MCS and RV value
enum {ndi_true=1, ndi_false=0} ndi; // New Data Indicator
int tpc; // Transmit Power Control
int dm_rs; // DM RS
enum {cqi_true=0, cqi_false=1} cqi_request;
}dci_format0_t;
Format0, Format1, Format1A, Format1C
} dci_format_t;
// Each type is for a different interface to packing/unpacking functions
typedef struct {
enum {
PUSCH_SCHED, PDSCH_SCHED, MCCH_CHANGE, TPC_COMMAND, RA_PROC_PDCCH
} type;
dci_format_t format;
}dci_msg_type_t;
}dci_format1_t;
typedef enum {
DCI_COMMON = 0, DCI_UE = 1
} dci_spec_t;
typedef struct {
unsigned char nof_bits;
unsigned char L; // Aggregation level
unsigned char ncce; // Position of first CCE of the dci
unsigned short rnti;
}dci_candidate_t;
} dci_candidate_t;
typedef struct {
char data[DCI_MAX_BITS];
dci_candidate_t location;
}dci_msg_t;
} dci_msg_t;
typedef struct {
dci_msg_t *msg;
int nof_dcis;
}dci_t;
int max_dcis;
} dci_t;
int dci_init(dci_t *q, int nof_dci);
int dci_init(dci_t *q, int max_dci);
void dci_free(dci_t *q);
char* dci_format_string(dci_format_t format);
int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti);
void dci_candidate_fprint(FILE *f, dci_candidate_t *q);
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti);
int dci_format0_sizeof(int nof_prb);
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti);
void dci_msg_type_fprint(FILE *f, dci_msg_type_t type);
int dci_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti);
int dci_format1_sizeof(int nof_prb, int P);
// For dci_msg_type_t = PUSCH_SCHED
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb);
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb);
int dci_format1A_add(dci_t *q, dci_format1_t *msg);
int dci_format1A_sizeof(int nof_prb, bool random_access_initiated);
// For dci_msg_type_t = PDSCH_SCHED
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti);
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti);
int dci_format1C_add(dci_t *q, dci_format1_t *msg);
int dci_format1C_sizeof();
int dci_format_sizeof(dci_format_t format, int nof_prb);
#endif

@ -59,36 +59,42 @@ typedef struct {
int cell_id;
int nof_prb;
int max_ctrl_symbols;
int cfi;
int ngroups_phich;
int refs_in_symbol1;
int nof_ports;
lte_cp_t cp;
phich_resources_t phich_res;
phich_length_t phich_len;
int nof_cce;
regs_ch_t pcfich;
regs_ch_t *phich; // there are several phich
regs_ch_t *pdcch; // there are several pdcch
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
the three possible CFI value */
int nof_regs;
regs_reg_t *regs;
}regs_t;
int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp);
void regs_free(regs_t *h);
int regs_set_cfi(regs_t *h, int nof_ctrl_symbols);
int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb);
int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb);
int regs_pcfich_nregs(regs_t *h);
int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols);
int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM]);
int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]);
int regs_phich_nregs(regs_t *h);
int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols);
int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup);
int regs_phich_ngroups(regs_t *h);
int regs_phich_reset(regs_t *h, cf_t *slot_symbols);
int regs_pdcch_nregs(regs_t *h);
int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols);
int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols);
#endif

@ -36,6 +36,7 @@ uint32_t bit_unpack(char **bits, int nof_bits);
void bit_pack(uint32_t value, char **bits, int nof_bits);
void bit_fprint(FILE *stream, char *bits, int nof_bits);
unsigned int bit_diff(char *x, char *y, int nbits);
int bit_count(unsigned int n);
#endif

@ -41,8 +41,8 @@ void get_time_interval(struct timeval * tdata);
extern int verbose;
#define VERBOSE_ISINFO() (verbose==VERBOSE_INFO)
#define VERBOSE_ISDEBUG() (verbose==VERBOSE_DEBUG)
#define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO)
#define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG)
#define PRINT_DEBUG verbose=VERBOSE_DEBUG
#define PRINT_INFO verbose=VERBOSE_INFO

@ -135,7 +135,7 @@ struct lte_band lte_bands[NOF_LTE_BANDS] = {
};
#define EOF_BAND 9919
int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type) {
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) {
if (!strcmp(mimo_type_str, "single")) {
*type = SINGLE_ANTENNA;
} else if (!strcmp(mimo_type_str, "diversity")) {
@ -148,7 +148,7 @@ int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type) {
return 0;
}
char *lte_mimotype2str(mimo_type_t type) {
char *lte_mimotype2str(lte_mimo_type_t type) {
switch(type) {
case SINGLE_ANTENNA:
return "single";

@ -78,7 +78,7 @@ int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw,
* Returns the number of symbols per layer (M_symb^layer in the specs)
*/
int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS], mimo_type_t type) {
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) {
if (nof_cw > MAX_CODEWORDS) {
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
@ -167,7 +167,7 @@ int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_la
* nof_symbols. Returns -1 on error
*/
int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], mimo_type_t type) {
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) {
if (nof_cw > MAX_CODEWORDS) {
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);

@ -85,7 +85,7 @@ int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports,
/* 36.211 v10.3.0 Section 6.3.4 */
int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols,
mimo_type_t type) {
lte_mimo_type_t type) {
if (nof_ports > MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports);
@ -177,7 +177,7 @@ int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
/* 36.211 v10.3.0 Section 6.3.4 */
int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, mimo_type_t type) {
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type) {
if (nof_ports > MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports);

@ -75,7 +75,7 @@ void parse_args(int argc, char **argv) {
int main(int argc, char **argv) {
int i, j, num_errors, symbols_layer;
cf_t *d[MAX_CODEWORDS], *x[MAX_LAYERS], *dp[MAX_CODEWORDS];
mimo_type_t type;
lte_mimo_type_t type;
int nof_symb_cw[MAX_CODEWORDS];
int n[2];

@ -78,7 +78,7 @@ int main(int argc, char **argv) {
int i, j;
float mse;
cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS], *xr[MAX_LAYERS];
mimo_type_t type;
lte_mimo_type_t type;
parse_args(argc, argv);

@ -47,7 +47,7 @@ void demod_soft_alg_set(demod_soft_t *q, enum alg alg_type) {
}
void demod_soft_sigma_set(demod_soft_t *q, float sigma) {
q->sigma = sigma;
q->sigma = 2*sigma;
}
int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int nsymbols) {

@ -41,14 +41,14 @@
#include "lte/utils/vector.h"
#include "lte/utils/debug.h"
int dci_init(dci_t *q, int nof_dcis) {
q->msg = calloc(sizeof(dci_msg_t), nof_dcis);
int dci_init(dci_t *q, int max_dcis) {
q->msg = calloc(sizeof(dci_msg_t), max_dcis);
if (!q->msg) {
perror("malloc");
return -1;
}
q->nof_dcis = nof_dcis;
q->nof_dcis = 0;
q->max_dcis = max_dcis;
return 0;
}
@ -63,60 +63,755 @@ void dci_candidate_fprint(FILE *f, dci_candidate_t *q) {
q->L, q->ncce, q->rnti, q->nof_bits);
}
int dci_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti) {
int i, j;
i=0;
while(i<q->nof_dcis && q->msg[i].location.nof_bits)
i++;
if (i == q->nof_dcis) {
fprintf(stderr, "No more space in DCI container\n");
int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) {
if (L >= 0 && L <=3) {
msg->location.L = (unsigned char) L;
} else {
fprintf(stderr, "Invalid L %d\n", L);
return -1;
}
q->msg[i].location.L = L;
q->msg[i].location.ncce = nCCE;
q->msg[i].location.nof_bits = dci_format1_sizeof(6, 1);
q->msg[i].location.rnti = rnti;
for (j=0;j<q->msg[i].location.nof_bits;j++) {
q->msg[i].data[j] = rand()%2;
if (nCCE >= 0 && nCCE <= 87) {
msg->location.ncce = (unsigned char) nCCE;
} else {
fprintf(stderr, "Invalid nCCE %d\n", nCCE);
return -1;
}
msg->location.rnti = rnti;
return 0;
}
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti) {
int i, j;
i=0;
while(i<q->nof_dcis && q->msg[i].location.nof_bits)
i++;
if (i == q->nof_dcis) {
fprintf(stderr, "No more space in DCI container\n");
int riv_nbits(int nof_prb) {
return (int) ceilf(log2f((float) nof_prb*((float) nof_prb+1)/2));
}
const int ambiguous_sizes[10] = {12, 14, 16, 20, 24, 26, 32, 40, 44, 56};
bool is_ambiguous_size(int size) {
int i;
for (i=0;i<10;i++) {
if (size == ambiguous_sizes[i]) {
return true;
}
}
return false;
}
/**********************************
* PAYLOAD sizeof functions
* ********************************/
int dci_format0_sizeof_(int nof_prb) {
return 1+1+riv_nbits(nof_prb)+5+1+2+3+1;
}
int dci_format1A_sizeof(int nof_prb) {
int n;
n = 1+1+riv_nbits(nof_prb)+5+3+1+2+2;
while(n < dci_format0_sizeof_(nof_prb)) {
n++;
}
if (is_ambiguous_size(n)) {
n++;
}
return n;
}
int dci_format0_sizeof(int nof_prb) {
int n = dci_format0_sizeof_(nof_prb);
while (n < dci_format1A_sizeof(nof_prb)) {
n++;
}
return n;
}
int dci_format1_sizeof(int nof_prb) {
int n = (int) ceilf((float) nof_prb/ra_type0_P(nof_prb))+5+3+1+2+2;
if (nof_prb > 10) {
n++;
}
while(n == dci_format0_sizeof(nof_prb)
|| n == dci_format1A_sizeof(nof_prb)
|| is_ambiguous_size(n)) {
n++;
}
return n;
}
int dci_format1C_sizeof(int nof_prb) {
int n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true);
int n_step = ra_type2_n_rb_step(nof_prb);
int n = + riv_nbits((int) n_vrb_dl_gap1/n_step) + 5;
if (nof_prb >= 50) {
n++;
}
return n;
}
int dci_format_sizeof(dci_format_t format, int nof_prb) {
switch(format) {
case Format0:
return dci_format0_sizeof(nof_prb);
case Format1:
return dci_format1_sizeof(nof_prb);
case Format1A:
return dci_format1A_sizeof(nof_prb);
case Format1C:
return dci_format1C_sizeof(nof_prb);
default:
return -1;
}
q->msg[i].location.L = L;
q->msg[i].location.ncce = nCCE;
q->msg[i].location.nof_bits = dci_format0_sizeof(msg->n_rb_ul);
q->msg[i].location.rnti = rnti;
for (j=0;j<q->msg[i].location.nof_bits;j++) {
q->msg[i].data[j] = rand()%2;
}
/**********************************
* DCI Resource Allocation functions
* ********************************/
/* Packs DCI format 0 data to a sequence of bits and store them in msg according
* to 36.212 5.3.3.1.1
*
* TODO: TPC and cyclic shift for DM RS not implemented
*/
int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
/* pack bits */
char *y = msg->data;
int n_ul_hop;
*y++ = 0; // format differentiation
if (data->freq_hop_fl == hop_disabled) { // frequency hopping
*y++ = 0;
n_ul_hop = 0;
} else {
*y++ = 1;
if (nof_prb < 50) {
n_ul_hop = 1; // Table 8.4-1 of 36.213
*y++ = data->freq_hop_fl & 1;
} else {
n_ul_hop = 2; // Table 8.4-1 of 36.213
*y++ = (data->freq_hop_fl & 2) >> 1;
*y++ = data->freq_hop_fl & 1;
}
}
/* pack RIV according to 8.1 of 36.213 */
uint32_t riv;
if (data->type2_alloc.L_crb) {
riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, nof_prb);
} else {
riv = data->type2_alloc.riv;
}
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
/* pack MCS according to 8.6.1 of 36.213 */
uint32_t mcs;
if (data->cqi_request) {
mcs = 29;
} else {
if (data->rv_idx) {
mcs = 28 + data->rv_idx;
} else {
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
if (data->mcs.tbs) {
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, ra_nprb_ul(data, nof_prb));
}
}
mcs = ra_mcs_to_table_idx(&data->mcs);
}
}
}
bit_pack(mcs, &y, 5);
*y++ = data->ndi;
// TCP commands not implemented
*y++ = 0;
*y++ = 0;
// DM RS not implemented
*y++ = 0;
*y++ = 0;
*y++ = 0;
// CQI request
*y++ = data->cqi_request;
// Padding with zeros
int n = dci_format0_sizeof(nof_prb);
while (y-msg->data < n) {
*y++ = 0;
}
msg->location.nof_bits = (y - msg->data);
return 0;
}
/* Unpacks DCI format 0 data and store result in msg according
* to 36.212 5.3.3.1.1
*
* TODO: TPC and cyclic shift for DM RS not implemented
*/
int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
int dci_format0_sizeof(int nof_prb) {
return 1+1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+2+3+1;
/* pack bits */
char *y = msg->data;
int n_ul_hop;
/* Make sure it's a Format0 message */
if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) {
fprintf(stderr, "Invalid message length for format 0\n");
return -1;
}
if (*y++ != 0) {
fprintf(stderr, "Invalid format differentiation field value. This is Format1A\n");
return -1;
}
if (*y++ == 0) {
data->freq_hop_fl = hop_disabled;
n_ul_hop = 0;
} else {
if (nof_prb < 50) {
n_ul_hop = 1; // Table 8.4-1 of 36.213
data->freq_hop_fl = *y++;
} else {
n_ul_hop = 2; // Table 8.4-1 of 36.213
data->freq_hop_fl = y[0]<<1 | y[1];
y += 2;
}
}
/* unpack RIV according to 8.1 of 36.213 */
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop);
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_prb);
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
data->type2_alloc.riv = riv;
/* unpack MCS according to 8.6 of 36.213 */
uint32_t mcs = bit_unpack(&y, 5);
data->ndi = *y++?true:false;
// TCP and DM RS commands not implemented
y+= 5;
// CQI request
data->cqi_request = *y++?true:false;
// 8.6.2 First paragraph
if (mcs <= 28) {
ra_mcs_from_idx_ul(mcs, &data->mcs);
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_ul(data, nof_prb));
}
// 8.6.1 and 8.6.2 36.213 second paragraph
if (mcs == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) {
data->mcs.mod = QPSK;
}
if (mcs > 29) {
// Else leave MOD_NULL and use the previously used PUSCH modulation
data->mcs.mod = MOD_NULL;
data->rv_idx = mcs - 28;
}
return 0;
}
/* Packs DCI format 1 data to a sequence of bits and store them in msg according
* to 36.212 5.3.3.1.2
*
* TODO: TPC commands
*/
int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
/* pack bits */
char *y = msg->data;
if (nof_prb > 10) {
*y++ = data->alloc_type;
}
/* Resource allocation: type0 or type 1 */
int P = ra_type0_P(nof_prb);
int alloc_size = (int) ceilf((float) nof_prb/P);
switch(data->alloc_type) {
case alloc_type0:
bit_pack(data->type0_alloc.rbg_bitmask, &y, alloc_size);
break;
case alloc_type1:
bit_pack(data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P)));
*y++ = data->type1_alloc.shift?1:0;
bit_pack(data->type1_alloc.vrb_bitmask, &y, alloc_size - (int) ceilf(log2f(P)) - 1);
break;
default:
fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
return -1;
}
/* pack MCS according to 7.1.7 of 36.213 */
uint32_t mcs;
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, ra_nprb_dl(data, nof_prb));
}
mcs = ra_mcs_to_table_idx(&data->mcs);
}
bit_pack(mcs, &y, 5);
/* harq process number */
bit_pack(data->harq_process, &y, 3);
*y++ = data->ndi;
// rv version
bit_pack(data->rv_idx, &y, 2);
// TPC not implemented
*y++ = 0;
*y++ = 0;
// Padding with zeros
int n = dci_format1_sizeof(nof_prb);
while (y-msg->data < n) {
*y++ = 0;
}
msg->location.nof_bits = (y - msg->data);
return 0;
}
int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
/* pack bits */
char *y = msg->data;
/* Make sure it's a Format1 message */
if (msg->location.nof_bits != dci_format_sizeof(Format1, nof_prb)) {
fprintf(stderr, "Invalid message length for format 1\n");
return -1;
}
if (nof_prb > 10) {
data->alloc_type = *y++;
} else {
data->alloc_type = alloc_type0;
}
/* Resource allocation: type0 or type 1 */
int P = ra_type0_P(nof_prb);
int alloc_size = (int) ceilf((float) nof_prb/P);
switch(data->alloc_type) {
case alloc_type0:
data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size);
break;
case alloc_type1:
data->type1_alloc.rbg_subset = bit_unpack(&y, (int) ceilf(log2f(P)));
data->type1_alloc.shift = *y++?true:false;
data->type1_alloc.vrb_bitmask = bit_unpack(&y, alloc_size - (int) ceilf(log2f(P)) - 1);
break;
default:
fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
return -1;
}
/* pack MCS according to 7.1.7 of 36.213 */
uint32_t mcs = bit_unpack(&y, 5);
data->mcs.mcs_idx = mcs;
ra_mcs_from_idx_dl(mcs, &data->mcs);
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb));
/* harq process number */
data->harq_process = bit_unpack(&y, 3);
data->ndi = *y++?true:false;
// rv version
data->rv_idx = bit_unpack(&y, 2);
// TPC not implemented
return 0;
}
int dci_format1_sizeof(int nof_prb, int P) {
return (nof_prb>10)?1:0+(int) ceilf(log2f(nof_prb/P))+5+3+1+2+2;
/* Packs DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
*
* TODO: RA procedure initiated by PDCCH, TPC commands
*/
int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_is_crnti) {
/* pack bits */
char *y = msg->data;
*y++ = 1; // format differentiation
if (data->alloc_type != alloc_type2) {
fprintf(stderr, "Format 1A accepts type2 resource allocation only\n");
return -1;
}
*y++ = data->type2_alloc.mode; // localized or distributed VRB assignment
if (data->type2_alloc.mode == t2_loc) {
if (data->type2_alloc.L_crb > nof_prb) {
fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n", data->type2_alloc.L_crb);
return -1;
}
} else {
int n_vrb_dl;
if (crc_is_crnti && nof_prb > 50) {
n_vrb_dl = 16;
} else {
n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
}
if (data->type2_alloc.L_crb > n_vrb_dl) {
fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb, n_vrb_dl);
return -1;
}
}
/* pack RIV according to 7.1.6.3 of 36.213 */
uint32_t riv;
if (data->type2_alloc.L_crb) {
riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, nof_prb);
} else {
riv = data->type2_alloc.riv;
}
int nb_gap = 0;
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1;
*y++ = data->type2_alloc.n_gap;
}
bit_pack(riv, &y, riv_nbits(nof_prb)-nb_gap);
// in format1A, MCS = TBS according to 7.1.7.2 of 36.213
uint32_t mcs;
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
// In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI
int n_prb;
if (!crc_is_crnti) {
n_prb = ra_nprb_dl(data, nof_prb);
} else {
n_prb = data->type2_alloc.n_prb1a==nprb1a_2?2:3;
}
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, n_prb);
}
mcs = data->mcs.tbs_idx;
}
bit_pack(mcs, &y, 5);
bit_pack(data->harq_process, &y, 3);
if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) {
*y++ = data->type2_alloc.n_gap;
} else {
y++; // bit reserved
}
// rv version
bit_pack(data->rv_idx, &y, 2);
if (crc_is_crnti) {
// TPC not implemented
*y++ = 0;
*y++ = 0;
} else {
y++; // MSB of TPC is reserved
*y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS
}
// Padding with zeros
int n = dci_format1A_sizeof(nof_prb);
while (y-msg->data < n) {
*y++ = 0;
}
msg->location.nof_bits = (y - msg->data);
return 0;
}
int dci_format1A_sizeof(int nof_prb, bool random_access_initiated) {
if (random_access_initiated) {
return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+6+4;
/* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
*
*/
int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) {
/* pack bits */
char *y = msg->data;
/* Make sure it's a Format0 message */
if (msg->location.nof_bits != dci_format_sizeof(Format1A, nof_prb)) {
fprintf(stderr, "Invalid message length for format 1A\n");
return -1;
}
if (*y++ != 1) {
fprintf(stderr, "Invalid format differentiation field value. This is Format0\n");
return -1;
}
data->alloc_type = alloc_type2;
data->type2_alloc.mode = *y++;
// by default, set N_gap to 1
data->type2_alloc.n_gap = t2_ng1;
/* unpack RIV according to 7.1.6.3 of 36.213 */
int nb_gap = 0;
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1;
data->type2_alloc.n_gap = *y++;
}
int nof_vrb;
if (data->type2_alloc.mode == t2_loc) {
nof_vrb = nof_prb;
} else {
return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+5+3+1+2+2;
nof_vrb = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
}
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - nb_gap);
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_vrb);
data->type2_alloc.riv = riv;
// unpack MCS
data->mcs.mcs_idx = bit_unpack(&y, 5);
data->harq_process = bit_unpack(&y, 3);
if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) {
data->type2_alloc.n_gap = *y++;
} else {
y++; // bit reserved
}
// rv version
bit_pack(data->rv_idx, &y, 2);
if (crc_is_crnti) {
// TPC not implemented
y++;
y++;
} else {
y++; // MSB of TPC is reserved
*y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS
}
data->mcs.tbs_idx = data->mcs.mcs_idx;
int n_prb;
if (crc_is_crnti) {
n_prb = ra_nprb_dl(data, nof_prb);
} else {
n_prb = data->type2_alloc.n_prb1a==nprb1a_2?2:3;
}
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, n_prb);
data->mcs.mod = QPSK;
return 0;
}
int dci_format1C_sizeof() {
return 10;
/* Format 1C for compact scheduling of PDSCH words
*
*/
int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
/* pack bits */
char *y = msg->data;
if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) {
fprintf(stderr, "Format 1C accepts distributed type2 resource allocation only\n");
return -1;
}
if (nof_prb >= 50) {
*y++ = data->type2_alloc.n_gap;
}
int n_step = ra_type2_n_rb_step(nof_prb);
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
if (data->type2_alloc.L_crb > ((int) n_vrb_dl/n_step)*n_step) {
fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb,
((int) n_vrb_dl/n_step)*n_step);
return -1;
}
if (data->type2_alloc.L_crb % n_step) {
fprintf(stderr, "L_crb must be multiple of n_step\n");
return -1;
}
if (data->type2_alloc.RB_start % n_step) {
fprintf(stderr, "RB_start must be multiple of n_step\n");
return -1;
}
int L_p = data->type2_alloc.L_crb/n_step;
int RB_p = data->type2_alloc.RB_start/n_step;
int n_vrb_p = (int) n_vrb_dl / n_step;
uint32_t riv;
if (data->type2_alloc.L_crb) {
riv = ra_type2_to_riv(L_p, RB_p, n_vrb_p);
} else {
riv = data->type2_alloc.riv;
}
bit_pack(riv, &y, riv_nbits((int) n_vrb_dl/n_step));
// in format1C, MCS = TBS according to 7.1.7.2 of 36.213
uint32_t mcs;
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
data->mcs.tbs_idx = ra_tbs_to_table_idx_format1c(data->mcs.tbs);
}
mcs = data->mcs.tbs_idx;
}
bit_pack(mcs, &y, 5);
msg->location.nof_bits = (y - msg->data);
return 0;
}
int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
uint16_t L_p, RB_p;
/* pack bits */
char *y = msg->data;
if (msg->location.nof_bits != dci_format_sizeof(Format1C, nof_prb)) {
fprintf(stderr, "Invalid message length for format 1C\n");
return -1;
}
data->alloc_type = alloc_type2;
data->type2_alloc.mode = t2_dist;
if (nof_prb >= 50) {
data->type2_alloc.n_gap = *y++;
}
int n_step = ra_type2_n_rb_step(nof_prb);
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl/n_step));
int n_vrb_p = (int) n_vrb_dl / n_step;
ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p);
data->type2_alloc.L_crb = L_p * n_step;
data->type2_alloc.RB_start = RB_p * n_step;
data->type2_alloc.riv = riv;
data->mcs.mcs_idx = bit_unpack(&y, 5);
data->mcs.tbs_idx = data->mcs.mcs_idx;
data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs.tbs_idx);
data->mcs.mod = QPSK;
msg->location.nof_bits = (y - msg->data);
return 0;
}
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti) {
switch(format) {
case Format1:
return dci_format1_pack(data, msg, nof_prb);
case Format1A:
return dci_format1As_pack(data, msg, nof_prb, crc_is_crnti);
case Format1C:
return dci_format1Cs_pack(data, msg, nof_prb);
default:
fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n", dci_format_string(format));
return -1;
}
}
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) {
if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
return dci_format1_unpack(msg, data, nof_prb);
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti);
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
return dci_format1Cs_unpack(msg, data, nof_prb);
} else {
return -1;
}
}
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
return dci_format0_pack(data, msg, nof_prb);
}
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
return dci_format0_unpack(msg, data, nof_prb);
}
char* dci_format_string(dci_format_t format) {
switch(format) {
case Format0:
return "Format0";
case Format1:
return "Format1";
case Format1A:
return "Format1A";
case Format1C:
return "Format1C";
default:
return "N/A"; // fatal error
}
}
void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) {
switch(type.type) {
case PUSCH_SCHED:
fprintf(f,"%s PUSCH Scheduling\n", dci_format_string(type.format));
break;
case PDSCH_SCHED:
fprintf(f,"%s PDSCH Scheduling\n", dci_format_string(type.format));
break;
case RA_PROC_PDCCH:
fprintf(f,"%s Random access initiated by PDCCH\n", dci_format_string(type.format));
break;
case MCCH_CHANGE:
fprintf(f,"%s MCCH change notification\n", dci_format_string(type.format));
break;
case TPC_COMMAND:
fprintf(f,"%s TPC command\n", dci_format_string(type.format));
break;
}
}
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti) {
if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb)
&& !msg->data[0]) {
type->type = PUSCH_SCHED;
type->format = Format0;
return 0;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1;
return 0;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
if (msg->location.rnti == crnti) {
type->type = RA_PROC_PDCCH;
type->format = Format1A;
} else {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1A;
}
return 0;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
if (msg->location.rnti == MRNTI) {
type->type = MCCH_CHANGE;
type->format = Format1C;
} else {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1C;
}
return 0;
}
return -1;
}

@ -47,15 +47,11 @@
#define PDCCH_FORMAT_NOF_REGS(i) ((1<<i)*9)
#define PDCCH_FORMAT_NOF_BITS(i) ((1<<i)*72)
int pdcch_put(cf_t *pdcch, cf_t *slot1_data, int nsymbols) {
memcpy(slot1_data, pdcch, sizeof(cf_t) * nsymbols);
return nsymbols;
}
#define NOF_COMMON_FORMATS 2
const dci_format_t common_formats[NOF_COMMON_FORMATS] = {Format1A, Format1C};
int pdcch_get(cf_t *slot1_data, cf_t *pdcch, int nsymbols) {
memcpy(pdcch, slot1_data, sizeof(cf_t) * nsymbols);
return nsymbols;
}
#define NOF_UE_FORMATS 2
const dci_format_t ue_formats[NOF_UE_FORMATS] = {Format0, Format1}; // 1A has the same payload as 0
#define MIN(a,b) ((a>b)?b:a)
@ -63,18 +59,18 @@ int pdcch_get(cf_t *slot1_data, cf_t *pdcch, int nsymbols) {
* 36.213 9.1
*/
int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti) {
int i, L, k;
int i, l, L, k;
k = 0;
for (L = 2; L > 0; L--) {
for (i = 0; i < MIN(nof_cce,16) / (4 * L); i++) {
c[k].L = 4 * L;
for (l = 3; l > 1; l--) {
L = (1 << l);
for (i = 0; i < MIN(nof_cce,16) / (L); i++) {
c[k].L = l;
c[k].nof_bits = nof_bits;
c[k].rnti = rnti;
c[k].ncce = (4 * L) * (i % (nof_cce / (4 * L)));
k++;
INFO(
"Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
c[k].ncce = (L) * (i % (nof_cce / (L)));
INFO("Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
k, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
k++;
}
}
return k;
@ -88,6 +84,11 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short
unsigned int Yk;
const int S[4] = { 6, 12, 8, 16 };
k = 0;
if (!subframe) {
INFO("UE-specific candidates for RNTI: 0x%x, NofBits: %d, NofCCE: %d\n",
rnti, nof_bits, nof_cce);
if (VERBOSE_ISINFO()) printf("[INFO]: ");
}
for (l = 3; l >= 0; l--) {
L = (1 << l);
for (i = 0; i < MIN(nof_cce/L,16/S[l]); i++) {
@ -99,27 +100,35 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short
Yk = (39827 * Yk) % 65537;
}
c[k].ncce = L * ((Yk + i) % (nof_cce / L));
INFO("UE-specific SS Candidate %d: SF: %d, RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
k, subframe, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
if (!subframe) {
if (VERBOSE_ISINFO()) {
printf("(%d, %d), ", c[k].ncce, c[k].L);
}
}
k++;
}
}
if (!subframe) {
if (VERBOSE_ISINFO()) printf("\n");
}
return k;
}
void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) {
int k;
s->nof_candidates = 2*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
int k, i;
s->nof_candidates = NOF_COMMON_FORMATS*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
if (s->nof_candidates) {
s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
dci_candidate_t *c = s->candidates[0];
s->nof_candidates = 0;
if (c) {
// Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16
k = 0;
k += gen_common_search(&c[k], q->nof_cce,
dci_format1A_sizeof(q->nof_prb, true), SIRNTI);
k += gen_common_search(&c[k], q->nof_cce,
dci_format1C_sizeof(q->nof_prb), SIRNTI);
for(i=0;i<NOF_COMMON_FORMATS;i++) {
k += gen_common_search(&c[k], q->nof_cce,
dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI);
s->nof_candidates++;
}
}
}
}
@ -137,11 +146,11 @@ void pdcch_init_search_si(pdcch_t *q) {
* DCI Format 1A and 1 + PUSCH scheduling format 0
*/
void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
int l, n, k;
int l, n, k, i;
pdcch_search_t *s = &q->search_mode[SEARCH_UE];
s->nof_candidates = 0;
for (l=0;l<3;l++) {
s->nof_candidates += 3*(MIN(q->nof_cce,16) / (1<<l));
s->nof_candidates += NOF_UE_FORMATS*(MIN(q->nof_cce,16) / (1<<l));
}
INFO("Initiating %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", s->nof_candidates, c_rnti);
if (s->nof_candidates) {
@ -152,12 +161,10 @@ void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
if (c) {
// Expect Formats 1, 1A, 0
k = 0;
k += gen_ue_search(&c[k], q->nof_cce,
dci_format0_sizeof(q->nof_prb), c_rnti, n);
k += gen_ue_search(&c[k], q->nof_cce,
dci_format1_sizeof(q->nof_prb, 1), c_rnti, n);
k += gen_ue_search(&c[k], q->nof_cce,
dci_format1A_sizeof(q->nof_prb, true), c_rnti, n);
for(i=0;i<NOF_UE_FORMATS;i++) {
k += gen_ue_search(&c[k], q->nof_cce,
dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n);
}
}
}
}
@ -200,15 +207,16 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
q->cp = cp;
q->regs = regs;
q->nof_ports = nof_ports;
q->nof_prb = nof_prb;
q->current_search_mode = SEARCH_NONE;
q->nof_regs = regs_pdcch_nregs(q->regs);
q->nof_regs = (regs_pdcch_nregs(q->regs)/9)*9;
q->nof_cce = q->nof_regs / 9;
q->nof_symbols = 4 * q->nof_regs;
q->nof_bits = 2 * q->nof_symbols;
INFO("Init PDCCH: %d REGs, %d bits, %d symbols, %d ports\n", q->nof_regs,
q->nof_bits, q->nof_symbols, q->nof_ports);
INFO("Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports\n", q->nof_cce,
q->nof_regs, q->nof_bits, q->nof_symbols, q->nof_ports);
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
goto clean;
@ -314,11 +322,18 @@ unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
int nof_bits) {
float tmp[3 * (DCI_MAX_BITS + 16)];
unsigned short p_bits;
unsigned short p_bits, crc_res;
char *x;
assert(nof_bits < DCI_MAX_BITS);
/* char a[] = {1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0};
float *b = malloc(sizeof(E));
for (int i=0;i<E;i++) {
b[i] = a[i]?1:-1;
}
*/
/* unrate matching */
rm_conv_rx(e, tmp, E, 3 * (nof_bits + 16));
@ -330,24 +345,31 @@ unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
/* viterbi decoder */
viterbi_decode_f(decoder, tmp, data, nof_bits + 16);
if (VERBOSE_ISDEBUG()) {
bit_fprint(stdout, data, nof_bits+16);
}
x = &data[nof_bits];
p_bits = (unsigned short) bit_unpack(&x, 16);
return (p_bits
^ ((unsigned short) crc(0, data, nof_bits, 16, LTE_CRC16, 0)
& 0xffff));
crc_res = ((unsigned short) crc(0, data, nof_bits, 16, LTE_CRC16, 0)
& 0xffff);
DEBUG("p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x\n", p_bits, crc_res, p_bits ^ crc_res);
return (p_bits ^ crc_res);
}
int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c,
dci_msg_t *msg) {
unsigned short crc_res;
DEBUG("Trying Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L,
c->rnti);
crc_res = dci_decode(&q->decoder, &llr[72 * c->ncce], msg->data,
PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits);
if (c->rnti == crc_res) {
memcpy(&msg->location, c, sizeof(dci_candidate_t));
INFO(
"FOUND CAND: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
"FOUND Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L,
c->rnti);
return 1;
@ -379,25 +401,21 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports));
/* extract symbols */
if (q->nof_symbols
!= pdcch_get(slot1_symbols, q->pdcch_symbols[0], q->nof_symbols)) {
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
int n = regs_pdcch_get(q->regs, slot1_symbols, q->pdcch_symbols[0]);
if (q->nof_symbols != n) {
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n);
return -1;
}
/* extract channel estimates */
for (i = 0; i < q->nof_ports; i++) {
if (q->nof_symbols != pdcch_get(ce[i], q->ce[i], q->nof_symbols)) {
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
n = regs_pdcch_get(q->regs, ce[i], q->ce[i]);
if (q->nof_symbols != n) {
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n);
return -1;
}
}
DEBUG("pdcch_symbols: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_c(stdout, q->pdcch_symbols[0], q->nof_symbols);
}
/* in control channels, only diversity is supported */
if (q->nof_ports == 1) {
/* no need for layer demapping */
@ -410,13 +428,18 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
q->nof_symbols / q->nof_ports);
}
DEBUG("pdcch d symbols: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_c(stdout, q->pdcch_d, q->nof_symbols);
}
/* demodulate symbols */
demod_soft_sigma_set(&q->demod, ebno);
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols);
DEBUG("llr: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_f(stdout, q->pdcch_llr, q->nof_symbols);
vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits);
}
/* descramble */
@ -426,7 +449,6 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
}
int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) {
int dci_cnt;
int k, i;
if (q->current_search_mode == SEARCH_UE) {
@ -435,16 +457,15 @@ int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe)
k = 0;
}
dci_cnt = 0;
for (i = 0; i < q->search_mode[q->current_search_mode].nof_candidates
&& dci_cnt < dci->nof_dcis; i++) {
&& dci->nof_dcis < dci->max_dcis; i++) {
if (pdcch_decode_candidate(q, q->pdcch_llr,
&q->search_mode[q->current_search_mode].candidates[k][i],
&dci->msg[dci_cnt])) {
dci_cnt++;
&dci->msg[dci->nof_dcis])) {
dci->nof_dcis++;
}
}
return dci_cnt;
return dci->nof_dcis;
}
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) {
@ -578,7 +599,7 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL],
/* mapping to resource elements */
for (i = 0; i < q->nof_ports; i++) {
pdcch_put(q->pdcch_symbols[i], slot1_symbols[i], q->nof_symbols);
regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot1_symbols[i]);
}
return 0;
}

@ -37,29 +37,144 @@
regs_reg_t *regs_find_reg(regs_t *h, int k, int l);
/***************************************************************
*
* PDCCH REG ALLOCATION
*
***************************************************************/
void regs_pdcch_free(regs_t *h) {
int i;
for (i=0;i<3;i++) {
if (h->pdcch[i].regs) {
free(h->pdcch[i].regs);
}
}
}
#define PDCCH_NCOLS 32
const unsigned char PDCCH_PERM[PDCCH_NCOLS] =
{ 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8,
24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 };
/** Initialize REGs for PDCCH
* 36.211 10.3 section 6.8.5
*/
int regs_pdcch_init(regs_t *h) {
return 0;
}
int i, m, cfi, nof_ctrl_symbols;
int ret = -1;
int nrows, ndummy, j, k, kp;
regs_reg_t **tmp = NULL;
void regs_pdcch_free(regs_t *h) {
if (h->pdcch) {
free(h->pdcch);
bzero(&h->pdcch, sizeof(regs_ch_t));
for (cfi=0;cfi<3;cfi++) {
if (h->nof_prb < 10) {
nof_ctrl_symbols = cfi+2;
} else {
nof_ctrl_symbols = cfi+1;
}
tmp = malloc(sizeof(regs_reg_t*) * h->nof_regs);
if (!tmp) {
perror("malloc");
goto clean_and_exit;
}
/* Number and count REGs for this CFI */
m=0;
for (i=0;i<h->nof_regs;i++) {
if (h->regs[i].l < nof_ctrl_symbols && !h->regs[i].assigned) {
tmp[m] = &h->regs[i];
m++;
}
}
h->pdcch[cfi].nof_regs = m;
h->pdcch[cfi].regs = malloc(sizeof(regs_reg_t*) * h->pdcch[cfi].nof_regs);
if (!h->pdcch[cfi].regs) {
perror("malloc");
goto clean_and_exit;
}
/* Interleave REGs */
nrows = (h->pdcch[cfi].nof_regs-1)/PDCCH_NCOLS+1;
ndummy = PDCCH_NCOLS*nrows - h->pdcch[cfi].nof_regs;
if (ndummy < 0) {
ndummy = 0;
}
k=0;
for (j = 0; j < PDCCH_NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (i*PDCCH_NCOLS + PDCCH_PERM[j] >= ndummy) {
m = i*PDCCH_NCOLS + PDCCH_PERM[j]-ndummy;
kp = (k-h->cell_id)%h->pdcch[cfi].nof_regs;
if (kp < 0) {
kp += h->pdcch[cfi].nof_regs;
}
h->pdcch[cfi].regs[m] = tmp[kp];
k++;
}
}
}
h->pdcch[cfi].nof_regs = (h->pdcch[cfi].nof_regs/9)*9;
free(tmp);
tmp = NULL;
if (VERBOSE_ISINFO() && cfi == 1) {
for (i=0;i<h->pdcch[cfi].nof_regs;i++) {
INFO("Logical PDCCH REG#%d:%d (%d,%d)\n", i%9,i/9,
h->pdcch[cfi].regs[i]->k0, h->pdcch[cfi].regs[i]->l);
}
}
}
ret = 0;
clean_and_exit:
if (tmp) {
free(tmp);
}
if (ret == -1) {
regs_pdcch_free(h);
}
return ret;
}
int regs_pdcch_nregs(regs_t *h) {
return 9;
if (h->cfi == -1) {
fprintf(stderr, "Must call regs_set_cfi() first\n");
return -1;
} else {
return h->pdcch[h->cfi].nof_regs;
}
}
/** Copy quadruplets to REGs and cyclic shift them, according to the
* second part of 6.8.5 in 36.211
*/
int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols) {
if (h->cfi == -1) {
fprintf(stderr, "Must call regs_set_cfi() first\n");
return -1;
}
int i;
for (i=0;i<h->pdcch[h->cfi].nof_regs;i++) {
regs_put_reg(h->pdcch[h->cfi].regs[i], &pdcch_symbols[i*4], slot_symbols, h->nof_prb);
}
return h->pdcch[h->cfi].nof_regs*4;
}
int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols) {
if (h->cfi == -1) {
fprintf(stderr, "Must call regs_set_cfi() first\n");
return -1;
}
int i;
for (i=0;i<h->pdcch[h->cfi].nof_regs;i++) {
regs_get_reg(h->pdcch[h->cfi].regs[i], slot_symbols, &pdcch_symbols[i*4], h->nof_prb);
}
return h->pdcch[h->cfi].nof_regs*4;
}
@ -195,6 +310,16 @@ void regs_phich_free(regs_t *h) {
}
}
int regs_phich_nregs(regs_t *h) {
int i, n;
n=0;
for (i=0;i<h->ngroups_phich;i++) {
n += h->phich[i].nof_regs;
}
return n;
}
int regs_phich_ngroups(regs_t *h) {
return h->ngroups_phich;
}
@ -274,10 +399,6 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_
/***************************************************************
*
* PCFICH REG ALLOCATION
@ -330,6 +451,10 @@ void regs_pcfich_free(regs_t *h) {
}
}
int regs_pcfich_nregs(regs_t *h) {
return h->pcfich.nof_regs;
}
/**
* Maps the PCFICH symbols to the resource grid pointed by slot_symbols
*
@ -392,13 +517,13 @@ regs_reg_t *regs_find_reg(regs_t *h, int k, int l) {
* Returns the number of REGs in a PRB
* 36.211 Section 6.2.4
*/
int regs_num_x_symbol(int symbol, int refs_in_symbol1, lte_cp_t cp) {
int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) {
switch (symbol) {
case 0:
return 2;
case 1:
switch (refs_in_symbol1) {
switch (nof_port) {
case 1:
case 2:
return 3;
@ -430,10 +555,10 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int
reg->l = symbol;
reg->assigned = false;
reg->k0 = k0 + nreg * 6;
switch (maxreg) {
case 2:
reg->k0 = k0 + nreg * 6;
/* there are two references in the middle */
j = z = 0;
for (i = 0; i < vo; i++) {
@ -456,6 +581,7 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int
break;
case 3:
reg->k0 = k0 + nreg * 4;
/* there is no reference */
for (i = 0; i < 4; i++) {
reg->k[i] = k0 + nreg * 4 + i;
@ -479,15 +605,33 @@ void regs_free(regs_t *h) {
bzero(h, sizeof(regs_t));
}
/** Sets the CFI value for this subframe (CFI must be in the range 1..3).
*/
int regs_set_cfi(regs_t *h, int cfi) {
if (cfi > 0 && cfi <= 3) {
if (h->phich_len == PHICH_EXT &&
((h->nof_prb < 10 && cfi < 2) || (h->nof_prb >= 10 && cfi < 3))) {
fprintf(stderr, "PHICH length is extended. The number of control symbols should be at least 3.\n");
return -1;
} else {
h->cfi = cfi - 1;
return 0;
}
} else {
fprintf(stderr, "Invalid CFI %d\n", cfi);
return -1;
}
}
/**
* Initializes REGs structure.
* Sets all REG indices and initializes PCFICH, PHICH and PDCCH REGs
* Returns 0 if OK, -1 on error
*/
int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp) {
int ret = -1;
int i, j, n, p, k;
int i, j[4], jmax, n[4], prb, k;
int vo = cell_id % 3;
int max_ctrl_symbols = nof_prb<10?4:3;
@ -496,18 +640,19 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
h->cell_id = cell_id;
h->nof_prb = nof_prb;
h->max_ctrl_symbols = max_ctrl_symbols;
h->cfi = -1; // not yet initialized
h->phich_res = phich_res;
h->phich_len = phich_len;
h->cp = cp;
h->refs_in_symbol1 = refs_in_symbol1;
h->nof_ports = nof_ports;
h->nof_regs = 0;
for (i = 0; i < max_ctrl_symbols; i++) {
n = regs_num_x_symbol(i, refs_in_symbol1, cp);
if (n == -1) {
n[i] = regs_num_x_symbol(i, nof_ports, cp);
if (n[i] == -1) {
return -1;
}
h->nof_regs += nof_prb * n;
h->nof_regs += nof_prb * n[i];
}
INFO("Indexing %d REGs. CellId: %d, %d PRB, CP: %s\n", h->nof_regs, h->cell_id, h->nof_prb,
CP_ISNORM(cp)?"Normal":"Extended");
@ -517,26 +662,36 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
goto clean_and_exit;
}
k = 0;
for (i = 0; i < max_ctrl_symbols; i++) {
n = regs_num_x_symbol(i, refs_in_symbol1, cp);
for (p = 0; p < nof_prb; p++) {
for (j = 0; j < n; j++) {
if (regs_reg_init(&h->regs[k], i, j, p * RE_X_RB, n, vo)) {
fprintf(stderr, "Error initializing REGs\n");
goto clean_and_exit;
}
DEBUG("Available REG #%3d: %d:%d:%d (k0=%d)\n", k, i, p, j,
h->regs[k].k0);
k++;
/* Sort REGs according to PDCCH mapping, beggining from the lowest l index then k */
bzero(j, sizeof(int) * 4);
k = i = prb = jmax = 0;
while (k < h->nof_regs) {
if (n[i] == 3 || (n[i] == 2 && jmax != 1)) {
if (regs_reg_init(&h->regs[k], i, j[i], prb * RE_X_RB, n[i], vo)) {
fprintf(stderr, "Error initializing REGs\n");
goto clean_and_exit;
}
DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i],
h->regs[k].k0);
j[i]++;
k++;
}
i++;
if (i == max_ctrl_symbols) {
i = 0;
jmax++;
}
if (jmax == 3) {
prb++;
bzero(j, sizeof(int) * 4);
jmax = 0;
}
}
if (regs_pcfich_init(h)) {
fprintf(stderr, "Error initializing PCFICH REGs\n");
goto clean_and_exit;
}
if (regs_phich_init(h)) {
fprintf(stderr, "Error initializing PHICH REGs\n");
goto clean_and_exit;
@ -548,7 +703,8 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
ret = 0;
clean_and_exit: if (ret == -1) {
clean_and_exit:
if (ret == -1) {
regs_free(h);
}
return ret;
@ -562,13 +718,8 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) {
int i;
for (i = 0; i < REGS_RE_X_REG; i++) {
if (reg->assigned) {
DEBUG("PUT REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l);
slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i];
} else {
fprintf(stderr, "Error REG not assigned\n");
return -1;
}
DEBUG("PUT REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l);
slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i];
}
return REGS_RE_X_REG;
}
@ -580,15 +731,10 @@ int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr
int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) {
int i;
for (i = 0; i < REGS_RE_X_REG; i++) {
if (reg->assigned) {
slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i];
DEBUG("ADD REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
__real__ slot_symbols[REG_IDX(reg, i, nof_prb)],
__imag__ slot_symbols[REG_IDX(reg, i, nof_prb)]);
} else {
fprintf(stderr, "Error REG not assigned\n");
return -1;
}
slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i];
DEBUG("ADD REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
__real__ slot_symbols[REG_IDX(reg, i, nof_prb)],
__imag__ slot_symbols[REG_IDX(reg, i, nof_prb)]);
}
return REGS_RE_X_REG;
}
@ -600,13 +746,8 @@ int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr
int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) {
int i;
for (i = 0; i < REGS_RE_X_REG; i++) {
if (reg->assigned) {
DEBUG("RESET REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l);
slot_symbols[REG_IDX(reg, i, nof_prb)] = 0;
} else {
fprintf(stderr, "Error REG not assigned\n");
return -1;
}
DEBUG("RESET REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l);
slot_symbols[REG_IDX(reg, i, nof_prb)] = 0;
}
return REGS_RE_X_REG;
}
@ -617,14 +758,9 @@ int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) {
int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb) {
int i;
for (i = 0; i < REGS_RE_X_REG; i++) {
if (reg->assigned) {
reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)];
DEBUG("GET REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
__real__ reg_data[i], __imag__ reg_data[i]);
} else {
fprintf(stderr, "Error REG not assigned\n");
return -1;
}
reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)];
//DEBUG("GET REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
// __real__ reg_data[i], __imag__ reg_data[i]);
}
return REGS_RE_X_REG;
}

@ -75,6 +75,11 @@ ADD_TEST(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2)
ADD_EXECUTABLE(pdcch_test pdcch_test.c)
TARGET_LINK_LIBRARIES(pdcch_test lte)
ADD_TEST(pdcch_test pdcch_test)
ADD_EXECUTABLE(dci_unpacking dci_unpacking.c)
TARGET_LINK_LIBRARIES(dci_unpacking lte)
########################################################################
# FILE TEST
########################################################################
@ -88,7 +93,11 @@ TARGET_LINK_LIBRARIES(pcfich_file_test lte)
ADD_EXECUTABLE(phich_file_test phich_file_test.c)
TARGET_LINK_LIBRARIES(phich_file_test lte)
ADD_EXECUTABLE(pdcch_file_test pdcch_file_test.c)
TARGET_LINK_LIBRARIES(pdcch_file_test lte)
ADD_TEST(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat)
ADD_TEST(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)
ADD_TEST(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)
ADD_TEST(pdcch_file_test pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat)

@ -223,7 +223,8 @@ int main(int argc, char **argv) {
} else {
if (mib.nof_ports == 2 && mib.nof_prb == 50 && mib.phich_length == PHICH_NORM
&& mib.phich_resources == R_1 && mib.sfn == 28) {
printf("This is the pbch_test.dat file\n");
pbch_mib_fprint(stdout, &mib);
printf("This is the signal.1.92M.dat file\n");
exit(0);
} else {
pbch_mib_fprint(stdout, &mib);

@ -36,10 +36,12 @@
int cell_id = 1;
int nof_prb = 6;
int nof_ports = 1;
int cfi = 1;
void usage(char *prog) {
printf("Usage: %s [cpv]\n", prog);
printf("\t-c cell id [Default %d]\n", cell_id);
printf("\t-f cfi [Default %d]\n", cfi);
printf("\t-p nof_ports [Default %d]\n", nof_ports);
printf("\t-n nof_prb [Default %d]\n", nof_prb);
printf("\t-v [set verbose to debug, default none]\n");
@ -47,11 +49,14 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "cpnv")) != -1) {
while ((opt = getopt(argc, argv, "cpnfv")) != -1) {
switch(opt) {
case 'p':
nof_ports = atoi(argv[optind]);
break;
case 'f':
cfi = atoi(argv[optind]);
break;
case 'n':
nof_prb = atoi(argv[optind]);
break;
@ -68,10 +73,42 @@ void parse_args(int argc, char **argv) {
}
}
int test_dci_payload_size() {
int i, j;
int x[4];
const dci_format_t formats[4] = {Format0, Format1, Format1A, Format1C};
const int prb[6]={6, 15, 25, 50, 75, 100};
const int dci_sz[6][5] = {
{21, 19, 21, 8},
{22, 23, 22, 10},
{25, 27, 25, 12},
{27, 31, 27, 13},
{27, 33, 27, 14},
{28, 39, 28, 15}
};
printf("Testing DCI payload sizes...\n");
printf(" PRB\t0\t1\t1A\t1C\n");
for (i=0;i<6;i++) {
int n=prb[i];
for (j=0;j<4;j++) {
x[j] = dci_format_sizeof(formats[j], n);
if (x[j] != dci_sz[i][j]) {
fprintf(stderr, "Invalid DCI payload size for %s\n", dci_format_string(formats[j]));
return -1;
}
}
printf(" %2d:\t%2d\t%2d\t%2d\t%2d\n",n,x[0],x[1],x[2],x[3]);
}
printf("Ok\n");
return 0;
}
int main(int argc, char **argv) {
pdcch_t pdcch;
dci_t dci_tx, dci_rx;
dci_format1_t dci_msg;
ra_pdsch_t ra_dl;
regs_t regs;
int i, j;
cf_t *ce[MAX_PORTS_CTRL];
@ -84,6 +121,10 @@ int main(int argc, char **argv) {
nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
if (test_dci_payload_size()) {
exit(-1);
}
/* init memory */
for (i=0;i<MAX_PORTS_CTRL;i++) {
ce[i] = malloc(sizeof(cf_t) * nof_re);
@ -106,13 +147,34 @@ int main(int argc, char **argv) {
exit(-1);
}
if (regs_set_cfi(&regs, cfi)) {
fprintf(stderr, "Error setting CFI\n");
exit(-1);
}
if (pdcch_init(&pdcch, &regs, nof_prb, nof_ports, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n");
fprintf(stderr, "Error creating PDCCH object\n");
exit(-1);
}
dci_init(&dci_tx, 1);
dci_format1_add(&dci_tx, &dci_msg, 1, 0, 1234);
dci_init(&dci_tx, 2);
bzero(&ra_dl, sizeof(ra_pdsch_t));
ra_dl.harq_process = 0;
//ra_pdsch_set_mcs_index(&ra_dl, 6);
ra_pdsch_set_mcs(&ra_dl, QAM16, 5);
ra_dl.ndi = 0;
ra_dl.rv_idx = 0;
ra_dl.alloc_type = alloc_type0;
ra_dl.type0_alloc.rbg_bitmask = 0x5;
dci_msg_pack_pdsch(&ra_dl, &dci_tx.msg[0], Format1, nof_prb, false);
dci_msg_candidate_set(&dci_tx.msg[0], 0, 0, 1234);
dci_tx.nof_dcis++;
ra_pdsch_set_mcs(&ra_dl, QAM16, 15);
dci_msg_pack_pdsch(&ra_dl, &dci_tx.msg[1], Format1, nof_prb, false);
dci_msg_candidate_set(&dci_tx.msg[1], 0, 1, 1234);
dci_tx.nof_dcis++;
pdcch_encode(&pdcch, &dci_tx, slot1_symbols, 0);
@ -125,13 +187,12 @@ int main(int argc, char **argv) {
pdcch_init_search_ue(&pdcch, 1234);
dci_init(&dci_rx, 1);
dci_init(&dci_rx, 2);
nof_dcis = pdcch_decode(&pdcch, slot1_symbols[0], ce, &dci_rx, 0, 1);
if (nof_dcis < 0) {
printf("Error decoding\n");
} else if (nof_dcis == dci_tx.nof_dcis) {
for (i=0;i<nof_dcis;i++) {
if (dci_tx.msg[i].location.L != dci_rx.msg[i].location.L
|| dci_tx.msg[i].location.ncce != dci_rx.msg[i].location.ncce
|| dci_tx.msg[i].location.nof_bits != dci_rx.msg[i].location.nof_bits
@ -146,7 +207,6 @@ int main(int argc, char **argv) {
printf("Error in DCI %d: Received data does not match\n", i);
goto quit;
}
/* check more things ... */
}
} else {
printf("Transmitted %d DCIs but got %d\n", dci_tx.nof_dcis, nof_dcis);

@ -142,8 +142,13 @@ int rm_conv_rx(float *input, float *output, int in_len, int out_len) {
d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS;
for (j = 0; j < RATE; j++) {
output[i * RATE + j] = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows
+ d_i];
float o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows
+ d_i];
if (o != RX_NULL) {
output[i * RATE + j] = o;
} else {
output[i * RATE + j] = 0;
}
}
}
return 0;

@ -23,7 +23,7 @@ int main(int argc, char **argv) {
resample_arb_init(&r, rate);
clock_t start = clock(), diff;
int n_out = resample_arb_compute(&r, in, out, N);
//int n_out = resample_arb_compute(&r, in, out, N);
diff = clock() - start;
int msec = diff * 1000 / CLOCKS_PER_SEC;

@ -71,3 +71,11 @@ unsigned int bit_diff(char *x, char *y, int nbits) {
}
return errors;
}
// Counts the number of ones in a word. K&R book exercise 2.9
int bit_count(unsigned int n) {
int c;
for (c = 0; n; c++)
n &= n - 1;
return c;
}

Loading…
Cancel
Save