From 869b842415c05725099979f01f0f5c83eb082630 Mon Sep 17 00:00:00 2001 From: ismagom Date: Mon, 12 May 2014 18:43:14 +0100 Subject: [PATCH] Added PDCCH encoder/decoder. Tested with Amarisoft eNodeB --- lte/include/lte/common/base.h | 7 +- lte/include/lte/mimo/layermap.h | 4 +- lte/include/lte/mimo/precoding.h | 4 +- lte/include/lte/modem/modem_table.h | 4 +- lte/include/lte/phch/dci.h | 75 +- lte/include/lte/phch/regs.h | 16 +- lte/include/lte/utils/bit.h | 1 + lte/include/lte/utils/debug.h | 4 +- lte/lib/common/src/lte.c | 4 +- lte/lib/mimo/src/layermap.c | 4 +- lte/lib/mimo/src/precoding.c | 4 +- lte/lib/mimo/test/layermap_test.c | 2 +- lte/lib/mimo/test/precoding_test.c | 2 +- lte/lib/modem/src/demod_soft.c | 2 +- lte/lib/phch/src/dci.c | 775 ++++++++++++++++++- lte/lib/phch/src/pdcch.c | 141 ++-- lte/lib/phch/src/regs.c | 268 +++++-- lte/lib/phch/test/CMakeLists.txt | 9 + lte/lib/phch/test/pbch_file_test.c | 3 +- lte/lib/phch/test/pdcch_test.c | 76 +- lte/lib/ratematching/src/rm_conv.c | 9 +- lte/lib/resampling/test/resample_arb_bench.c | 2 +- lte/lib/utils/src/bit.c | 8 + 23 files changed, 1177 insertions(+), 247 deletions(-) diff --git a/lte/include/lte/common/base.h b/lte/include/lte/common/base.h index ef8c33519..a1f011d2b 100644 --- a/lte/include/lte/common/base.h +++ b/lte/include/lte/common/base.h @@ -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 diff --git a/lte/include/lte/mimo/layermap.h b/lte/include/lte/mimo/layermap.h index 9a2f6f9bb..3a472c34a 100644 --- a/lte/include/lte/mimo/layermap.h +++ b/lte/include/lte/mimo/layermap.h @@ -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 diff --git a/lte/include/lte/mimo/precoding.h b/lte/include/lte/mimo/precoding.h index ea68c5496..0a4cc18f7 100644 --- a/lte/include/lte/mimo/precoding.h +++ b/lte/include/lte/mimo/precoding.h @@ -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_ */ diff --git a/lte/include/lte/modem/modem_table.h b/lte/include/lte/modem/modem_table.h index 93a6aa230..f52bb1482 100644 --- a/lte/include/lte/modem/modem_table.h +++ b/lte/include/lte/modem/modem_table.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); diff --git a/lte/include/lte/phch/dci.h b/lte/include/lte/phch/dci.h index ee9224687..06c6a6f3d 100644 --- a/lte/include/lte/phch/dci.h +++ b/lte/include/lte/phch/dci.h @@ -25,11 +25,12 @@ * */ - #ifndef DCI_ #define DCI_ #include "lte/common/base.h" +#include +#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 diff --git a/lte/include/lte/phch/regs.h b/lte/include/lte/phch/regs.h index a439e2e61..657776650 100644 --- a/lte/include/lte/phch/regs.h +++ b/lte/include/lte/phch/regs.h @@ -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 diff --git a/lte/include/lte/utils/bit.h b/lte/include/lte/utils/bit.h index 00e2523f1..18ef23e9e 100644 --- a/lte/include/lte/utils/bit.h +++ b/lte/include/lte/utils/bit.h @@ -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 diff --git a/lte/include/lte/utils/debug.h b/lte/include/lte/utils/debug.h index f6f08d777..993bab615 100644 --- a/lte/include/lte/utils/debug.h +++ b/lte/include/lte/utils/debug.h @@ -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 diff --git a/lte/lib/common/src/lte.c b/lte/lib/common/src/lte.c index e475cf161..7163c41da 100644 --- a/lte/lib/common/src/lte.c +++ b/lte/lib/common/src/lte.c @@ -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"; diff --git a/lte/lib/mimo/src/layermap.c b/lte/lib/mimo/src/layermap.c index cd685dcd0..b178b953d 100644 --- a/lte/lib/mimo/src/layermap.c +++ b/lte/lib/mimo/src/layermap.c @@ -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); diff --git a/lte/lib/mimo/src/precoding.c b/lte/lib/mimo/src/precoding.c index dd136a01a..8cc033233 100644 --- a/lte/lib/mimo/src/precoding.c +++ b/lte/lib/mimo/src/precoding.c @@ -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); diff --git a/lte/lib/mimo/test/layermap_test.c b/lte/lib/mimo/test/layermap_test.c index 3e60737f0..0c701cc4b 100644 --- a/lte/lib/mimo/test/layermap_test.c +++ b/lte/lib/mimo/test/layermap_test.c @@ -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]; diff --git a/lte/lib/mimo/test/precoding_test.c b/lte/lib/mimo/test/precoding_test.c index 741bbd216..e913cc512 100644 --- a/lte/lib/mimo/test/precoding_test.c +++ b/lte/lib/mimo/test/precoding_test.c @@ -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); diff --git a/lte/lib/modem/src/demod_soft.c b/lte/lib/modem/src/demod_soft.c index 3180ff114..3b42467e3 100644 --- a/lte/lib/modem/src/demod_soft.c +++ b/lte/lib/modem/src/demod_soft.c @@ -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) { diff --git a/lte/lib/phch/src/dci.c b/lte/lib/phch/src/dci.c index 30d9feb93..c66abf6e1 100644 --- a/lte/lib/phch/src/dci.c +++ b/lte/lib/phch/src/dci.c @@ -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(inof_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;jmsg[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(inof_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;jmsg[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; +} + diff --git a/lte/lib/phch/src/pdcch.c b/lte/lib/phch/src/pdcch.c index 1dc8463ca..a98b6a47c 100644 --- a/lte/lib/phch/src/pdcch.c +++ b/lte/lib/phch/src/pdcch.c @@ -47,15 +47,11 @@ #define PDCCH_FORMAT_NOF_REGS(i) ((1<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;inof_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<nof_candidates += NOF_UE_FORMATS*(MIN(q->nof_cce,16) / (1<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;inof_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;inof_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; } diff --git a/lte/lib/phch/src/regs.c b/lte/lib/phch/src/regs.c index 06b9a0c79..6583dbdc3 100644 --- a/lte/lib/phch/src/regs.c +++ b/lte/lib/phch/src/regs.c @@ -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;inof_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;ipdcch[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;ipdcch[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;ipdcch[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;ingroups_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; } diff --git a/lte/lib/phch/test/CMakeLists.txt b/lte/lib/phch/test/CMakeLists.txt index 204441ba9..f7a6c00d1 100644 --- a/lte/lib/phch/test/CMakeLists.txt +++ b/lte/lib/phch/test/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/lte/lib/phch/test/pbch_file_test.c b/lte/lib/phch/test/pbch_file_test.c index 15cf7ace0..02ad61073 100644 --- a/lte/lib/phch/test/pbch_file_test.c +++ b/lte/lib/phch/test/pbch_file_test.c @@ -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); diff --git a/lte/lib/phch/test/pdcch_test.c b/lte/lib/phch/test/pdcch_test.c index 2263e9bfb..a6d0d9b42 100644 --- a/lte/lib/phch/test/pdcch_test.c +++ b/lte/lib/phch/test/pdcch_test.c @@ -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