diff --git a/examples/pbch_enodeb.c b/examples/pbch_enodeb.c index be6dbbb11..21a10b514 100644 --- a/examples/pbch_enodeb.c +++ b/examples/pbch_enodeb.c @@ -152,7 +152,7 @@ void base_init() { fprintf(stderr, "Error creating iFFT object\n"); exit(-1); } - if (pbch_init(&pbch, cell_id, CPNORM)) { + if (pbch_init(&pbch, 6, cell_id, CPNORM)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } @@ -249,7 +249,7 @@ int main(int argc, char **argv) { sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM); break; case 1: // tx pbch - pbch_encode(&pbch, &mib, slot1_symbols, nof_prb, 1); + pbch_encode(&pbch, &mib, slot1_symbols, 1); break; default: // transmit zeros break; diff --git a/examples/pbch_ue.c b/examples/pbch_ue.c index c63a5f9c4..c07c769a0 100644 --- a/examples/pbch_ue.c +++ b/examples/pbch_ue.c @@ -274,7 +274,7 @@ int mib_decoder_init(int cell_id) { return -1; } - if (pbch_init(&pbch, cell_id, CPNORM)) { + if (pbch_init(&pbch, 6, cell_id, CPNORM)) { fprintf(stderr, "Error initiating PBCH\n"); return -1; } @@ -292,7 +292,7 @@ int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { } DEBUG("Decoding PBCH\n", 0); - n = pbch_decode(&pbch, fft_buffer, ce, 6, 1, mib); + n = pbch_decode(&pbch, fft_buffer, ce, 1, mib); #ifndef DISABLE_GRAPHICS diff --git a/examples/scan_mib.c b/examples/scan_mib.c index e94ad6c18..f092c046e 100644 --- a/examples/scan_mib.c +++ b/examples/scan_mib.c @@ -325,7 +325,7 @@ int mib_decoder_init(int cell_id) { return -1; } - if (pbch_init(&pbch, cell_id, CPNORM)) { + if (pbch_init(&pbch, 6, cell_id, CPNORM)) { fprintf(stderr, "Error initiating PBCH\n"); return -1; } @@ -343,7 +343,7 @@ int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { } DEBUG("Decoding PBCH\n", 0); - return pbch_decode(&pbch, fft_buffer, ce, 6, 1, mib); + return pbch_decode(&pbch, fft_buffer, ce, 1, mib); } int main(int argc, char **argv) { diff --git a/lte/include/lte.h b/lte/include/lte.h index 53415a8ef..b41d55122 100644 --- a/lte/include/lte.h +++ b/lte/include/lte.h @@ -72,6 +72,8 @@ #include "lte/mimo/layermap.h" #include "lte/phch/regs.h" +#include "lte/phch/dci.h" +#include "lte/phch/pdcch.h" #include "lte/phch/pbch.h" #include "lte/phch/pcfich.h" #include "lte/phch/phich.h" diff --git a/lte/include/lte/common/base.h b/lte/include/lte/common/base.h index 5592c3d5b..ef8c33519 100644 --- a/lte/include/lte/common/base.h +++ b/lte/include/lte/common/base.h @@ -32,6 +32,8 @@ #define NSUBFRAMES_X_FRAME 10 #define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME) +#define LTE_NIL_SYMBOL 2 + #define MAX_PORTS 4 #define MAX_PORTS_CTRL 4 #define MAX_LAYERS 8 @@ -39,6 +41,9 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; +#define SIRNTI 0xFFFF +#define PRNTI 0xFFFE + #define MAX_NSYMB 7 #define CPNORM_NSYMB 7 diff --git a/lte/include/lte/common/sequence.h b/lte/include/lte/common/sequence.h index c52f44602..e4fcca153 100644 --- a/lte/include/lte/common/sequence.h +++ b/lte/include/lte/common/sequence.h @@ -44,5 +44,6 @@ int sequence_LTEPRS(sequence_t *q, int len, int seed); int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id); int sequence_pcfich(sequence_t *seq, int nslot, int cell_id); int sequence_phich(sequence_t *seq, int nslot, int cell_id); +int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len); #endif diff --git a/lte/include/lte/fec/convcoder.h b/lte/include/lte/fec/convcoder.h index ac62a358e..54f9eb723 100644 --- a/lte/include/lte/fec/convcoder.h +++ b/lte/include/lte/fec/convcoder.h @@ -38,11 +38,10 @@ typedef struct { int R; int K; int poly[3]; - int framelength; bool tail_biting; }convcoder_t; -int convcoder_encode(convcoder_t *q, char *input, char *output); +int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length); /* High-level API */ diff --git a/lte/include/lte/fec/crc.h b/lte/include/lte/fec/crc.h index dd29d8868..5cc24ad23 100644 --- a/lte/include/lte/fec/crc.h +++ b/lte/include/lte/fec/crc.h @@ -30,6 +30,11 @@ #ifndef CRC_ #define CRC_ +#define LTE_CRC24A 0x1864CFB +#define LTE_CRC24B 0X1800063 +#define LTE_CRC16 0x11021 +#define LTE_CRC8 0x19B + unsigned int crc(unsigned int crc, char *bufptr, int len, int long_crc,unsigned int poly, int paste_word); diff --git a/lte/include/lte/fec/viterbi.h b/lte/include/lte/fec/viterbi.h index 9cf2cbb88..02bbe4383 100644 --- a/lte/include/lte/fec/viterbi.h +++ b/lte/include/lte/fec/viterbi.h @@ -42,16 +42,16 @@ typedef struct { unsigned int framebits; bool tail_biting; int poly[3]; - int (*decode) (void*, unsigned char*, char*); + int (*decode) (void*, unsigned char*, char*, int); void (*free) (void*); unsigned char *tmp; unsigned char *symbols_uc; }viterbi_t; -int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting); +int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting); void viterbi_free(viterbi_t *q); -int viterbi_decode_f(viterbi_t *q, float *symbols, char *data); -int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data); +int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length); +int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, int frame_length); /* High-level API */ diff --git a/lte/include/lte/phch/dci.h b/lte/include/lte/phch/dci.h new file mode 100644 index 000000000..a16d329e7 --- /dev/null +++ b/lte/include/lte/phch/dci.h @@ -0,0 +1,113 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#ifndef DCI_ +#define DCI_ + +#include "lte/common/base.h" + +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; + +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; + +typedef struct { + +}dci_format1_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; + +typedef struct { + char data[DCI_MAX_BITS]; + dci_candidate_t location; +}dci_msg_t; + +typedef struct { + dci_msg_t *msg; + int nof_dcis; +}dci_t; + + +int dci_init(dci_t *q, int nof_dci); +void dci_free(dci_t *q); +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_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti); +int dci_format1_sizeof(int nof_prb); + +int dci_format1A_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti); +int dci_format1A_sizeof(int nof_prb); + +int dci_format1C_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti); +int dci_format1C_sizeof(int nof_prb); + +#endif diff --git a/lte/include/lte/phch/pbch.h b/lte/include/lte/phch/pbch.h index 081388289..9cb3ae113 100644 --- a/lte/include/lte/phch/pbch.h +++ b/lte/include/lte/phch/pbch.h @@ -57,6 +57,7 @@ typedef struct { typedef struct { int cell_id; lte_cp_t cp; + int nof_prb; int nof_symbols; /* buffers */ @@ -82,11 +83,10 @@ typedef struct { }pbch_t; -int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp); +int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp); void pbch_free(pbch_t *q); -int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int nof_prb, float ebno, pbch_mib_t *mib); -void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], - int nof_prb, int nof_ports); +int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib); +void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports); void pbch_decode_reset(pbch_t *q); void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib); diff --git a/lte/include/lte/phch/pdcch.h b/lte/include/lte/phch/pdcch.h new file mode 100644 index 000000000..75c8e768c --- /dev/null +++ b/lte/include/lte/phch/pdcch.h @@ -0,0 +1,126 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#ifndef PDCCH_ +#define PDCCH_ + +#include "lte/common/base.h" +#include "lte/mimo/precoding.h" +#include "lte/mimo/layermap.h" +#include "lte/modem/mod.h" +#include "lte/modem/demod_soft.h" +#include "lte/scrambling/scrambling.h" +#include "lte/ratematching/rm_conv.h" +#include "lte/fec/convcoder.h" +#include "lte/fec/viterbi.h" +#include "lte/fec/crc.h" +#include "lte/phch/dci.h" +#include "lte/phch/regs.h" + +typedef _Complex float cf_t; + +#define PDCCH_NOF_SEARCH_MODES 3 + +typedef enum { + SEARCH_NONE=3, SEARCH_SI=0, SEARCH_RA=1, SEARCH_UE=2 +}pdcch_search_mode_t; + +/* + * A search mode is indicated by higher layers to look for SI/C/RA-RNTI + * DCI messages as defined in Section 7.1 of 36.213 + */ +typedef struct { + int nof_candidates; + dci_candidate_t *candidates[NSUBFRAMES_X_FRAME]; +}pdcch_search_t; + +/* PDCCH object */ +typedef struct { + int cell_id; + lte_cp_t cp; + int nof_prb; + int nof_bits; + int nof_symbols; + int nof_ports; + int nof_regs; + int nof_cce; + + pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES]; + pdcch_search_mode_t current_search_mode; + + regs_t *regs; + + /* buffers */ + cf_t *ce[MAX_PORTS_CTRL]; + cf_t *pdcch_symbols[MAX_PORTS_CTRL]; + cf_t *pdcch_x[MAX_PORTS_CTRL]; + cf_t *pdcch_d; + char *pdcch_e; + float *pdcch_llr; + + /* tx & rx objects */ + modem_table_t mod; + demod_soft_t demod; + sequence_t seq_pdcch[NSUBFRAMES_X_FRAME]; + viterbi_t decoder; + +}pdcch_t; + +int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp); +void pdcch_free(pdcch_t *q); + +/* Encoding functions */ +int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nsubframe); + + +/* Decoding functions */ + +/* There are two ways to decode the DCI messages: + * a) call pdcch_set_search_si/ue/ra and then call pdcch_decode() + * b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra + */ + +int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], + dci_t *dci, int nsubframe, float ebno); +int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float *llr, + int nsubframe, float ebno); + +void pdcch_init_search_si(pdcch_t *q); +void pdcch_set_search_si(pdcch_t *q); +int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci); + +void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti); +void pdcch_set_search_ue(pdcch_t *q); +int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe); + +void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti); +void pdcch_set_search_ra(pdcch_t *q); +int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci); + + +#endif diff --git a/lte/include/lte/phch/regs.h b/lte/include/lte/phch/regs.h index 1f7eef0ff..a439e2e61 100644 --- a/lte/include/lte/phch/regs.h +++ b/lte/include/lte/phch/regs.h @@ -89,5 +89,6 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_ 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); #endif diff --git a/lte/lib/fec/src/convcoder.c b/lte/lib/fec/src/convcoder.c index 183afeee3..4fbd3e203 100644 --- a/lte/lib/fec/src/convcoder.c +++ b/lte/lib/fec/src/convcoder.c @@ -33,27 +33,25 @@ #include "lte/fec/convcoder.h" #include "parity.h" -int convcoder_encode(convcoder_t *q, char *input, char *output) { +int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) { unsigned int sr; int i,j; - int len = q->tail_biting ? q->framelength : (q->framelength + q->K - 1); + int len = q->tail_biting ? frame_length : (frame_length + q->K - 1); if (q->tail_biting) { sr = 0; - for (i=q->framelength - q->K + 1; iframelength; i++) { + for (i=frame_length - q->K + 1; iframelength) ? (input[i] & 1) : 0; + int bit = (i < frame_length) ? (input[i] & 1) : 0; sr = (sr << 1) | bit; for (j=0;jR;j++) { output[q->R * i + j] = parity(sr & q->poly[j]); } - //printf("%3d - sr=%u\n", i, sr%64); } return q->R*len; @@ -69,12 +67,11 @@ int convcoder_work(convcoder_hl* hl) { hl->obj.K = hl->ctrl_in.constraint_length; hl->obj.R = hl->ctrl_in.rate; - hl->obj.framelength = hl->in_len; hl->obj.poly[0] = hl->ctrl_in.generator_0; hl->obj.poly[1] = hl->ctrl_in.generator_1; hl->obj.poly[2] = hl->ctrl_in.generator_2; hl->obj.tail_biting = hl->ctrl_in.tail_bitting?true:false; - hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output); + hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output, hl->in_len); return 0; } diff --git a/lte/lib/fec/src/viterbi.c b/lte/lib/fec/src/viterbi.c index 0b7351a10..98bfe7289 100644 --- a/lte/lib/fec/src/viterbi.c +++ b/lte/lib/fec/src/viterbi.c @@ -38,49 +38,62 @@ #define DEB 0 -int decode37(void *o, unsigned char *symbols, char *data) { +int decode37(void *o, unsigned char *symbols, char *data, int frame_length) { viterbi_t *q = o; int i; int best_state; + if (frame_length > q->framebits) { + fprintf(stderr, "Initialized decoder for max frame length %d bits\n", + q->framebits); + return -1; + } + /* Initialize Viterbi decoder */ - init_viterbi37_port(q->ptr, q->tail_biting?-1:0); + init_viterbi37_port(q->ptr, q->tail_biting ? -1 : 0); /* Decode block */ if (q->tail_biting) { - memcpy(q->tmp, symbols, 3 * q->framebits * sizeof(char)); - for (i=0;i<3*(q->K-1);i++) { - q->tmp[i+3*q->framebits] = q->tmp[i]; + memcpy(q->tmp, symbols, 3 * frame_length * sizeof(char)); + for (i = 0; i < 3 * (q->K - 1); i++) { + q->tmp[i + 3 * frame_length] = q->tmp[i]; } } else { q->tmp = symbols; } - update_viterbi37_blk_port(q->ptr, q->tmp, q->framebits + q->K - 1, q->tail_biting?&best_state:NULL); + update_viterbi37_blk_port(q->ptr, q->tmp, frame_length + q->K - 1, + q->tail_biting ? &best_state : NULL); /* Do Viterbi chainback */ - chainback_viterbi37_port(q->ptr, data, q->framebits, q->tail_biting?best_state:0); + chainback_viterbi37_port(q->ptr, data, frame_length, + q->tail_biting ? best_state : 0); return q->framebits; } -int decode39(void *o, unsigned char *symbols, char *data) { +int decode39(void *o, unsigned char *symbols, char *data, int frame_length) { viterbi_t *q = o; + if (frame_length > q->framebits) { + fprintf(stderr, "Initialized decoder for max frame length %d bits\n", + q->framebits); + return -1; + } + /* Initialize Viterbi decoder */ init_viterbi39_port(q->ptr, 0); /* Decode block */ - update_viterbi39_blk_port(q->ptr, symbols,q->framebits + q->K - 1); + update_viterbi39_blk_port(q->ptr, symbols, frame_length + q->K - 1); /* Do Viterbi chainback */ - chainback_viterbi39_port(q->ptr, data, q->framebits, 0); + chainback_viterbi39_port(q->ptr, data, frame_length, 0); return q->framebits; } - void free37(void *o) { viterbi_t *q = o; if (q->symbols_uc) { @@ -107,13 +120,13 @@ int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { q->tail_biting = tail_biting; q->decode = decode37; q->free = free37; - q->symbols_uc = malloc(3 * (q->framebits + q->K -1) * sizeof(char)); + q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char)); if (!q->symbols_uc) { perror("malloc"); return -1; } if (q->tail_biting) { - q->tmp = malloc(3 * (q->framebits + q->K -1) * sizeof(char)); + q->tmp = malloc(3 * (q->framebits + q->K - 1) * sizeof(char)); if (!q->tmp) { perror("malloc"); free37(q); @@ -140,10 +153,11 @@ int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { q->decode = decode39; q->free = free39; if (q->tail_biting) { - fprintf(stderr, "Error: Tailbitting not supported in 1/3 K=9 decoder\n"); + fprintf(stderr, + "Error: Tailbitting not supported in 1/3 K=9 decoder\n"); return -1; } - q->symbols_uc = malloc(3 * (q->framebits + q->K -1) * sizeof(char)); + q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char)); if (!q->symbols_uc) { perror("malloc"); return -1; @@ -157,12 +171,13 @@ int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { } } -int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting) { - switch(type) { +int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], + int max_frame_length, bool tail_bitting) { + switch (type) { case viterbi_37: - return init37(q, poly, framebits, tail_bitting); + return init37(q, poly, max_frame_length, tail_bitting); case viterbi_39: - return init39(q, poly, framebits, tail_bitting); + return init39(q, poly, max_frame_length, tail_bitting); default: fprintf(stderr, "Decoder not implemented\n"); return -1; @@ -174,22 +189,27 @@ void viterbi_free(viterbi_t *q) { } /* symbols are real-valued */ -int viterbi_decode_f(viterbi_t *q, float *symbols, char *data) { +int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) { int len; + if (frame_length > q->framebits) { + fprintf(stderr, "Initialized decoder for max frame length %d bits\n", + q->framebits); + return -1; + } if (q->tail_biting) { - len = 3 * q->framebits; + len = 3 * frame_length; } else { - len = 3 * (q->framebits + q->K - 1); + len = 3 * (frame_length + q->K - 1); } vec_quant_fuc(symbols, q->symbols_uc, 32, 127.5, 255, len); - return q->decode(q, q->symbols_uc, data); + return q->decode(q, q->symbols_uc, data, frame_length); } -int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data) { - return q->decode(q, symbols, data); +int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, + int frame_length) { + return q->decode(q, symbols, data, frame_length); } - int viterbi_initialize(viterbi_hl* h) { int poly[3]; viterbi_type_t type; @@ -222,15 +242,16 @@ int viterbi_initialize(viterbi_hl* h) { poly[1] = h->init.generator_1; poly[2] = h->init.generator_2; return viterbi_init(&h->obj, type, poly, h->init.frame_length, - h->init.tail_bitting?true:false); + h->init.tail_bitting ? true : false); } int viterbi_work(viterbi_hl* hl) { if (hl->in_len != hl->init.frame_length) { - fprintf(stderr, "Expected input length %d but got %d\n", hl->init.frame_length, hl->in_len); + fprintf(stderr, "Expected input length %d but got %d\n", + hl->init.frame_length, hl->in_len); return -1; } - return viterbi_decode_f(&hl->obj, hl->input, hl->output); + return viterbi_decode_f(&hl->obj, hl->input, hl->output, hl->init.frame_length); } int viterbi_stop(viterbi_hl* h) { diff --git a/lte/lib/fec/test/crc_test.h b/lte/lib/fec/test/crc_test.h index b55f15b39..926e79426 100644 --- a/lte/lib/fec/test/crc_test.h +++ b/lte/lib/fec/test/crc_test.h @@ -27,6 +27,8 @@ #include +#include "lte/fec/crc.h" + typedef struct { int n; int l; @@ -37,10 +39,10 @@ typedef struct { static expected_word_t expected_words[] = { - {5000, 24, 0x1864CFB, 1, 0x4D0836}, // LTE CRC24A (36.212 Sec 5.1.1) - {5000, 24, 0X1800063, 1, 0x9B68F8}, // LTE CRC24B - {5000, 16, 0x11021, 1, 0xBFFA}, // LTE CRC16 - {5000, 8, 0x19B, 1, 0xF8}, // LTE CRC8 + {5000, 24, LTE_CRC24A, 1, 0x4D0836}, // LTE CRC24A (36.212 Sec 5.1.1) + {5000, 24, LTE_CRC24B, 1, 0x9B68F8}, // LTE CRC24B + {5000, 16, LTE_CRC16, 1, 0xBFFA}, // LTE CRC16 + {5000, 8, LTE_CRC8, 1, 0xF8}, // LTE CRC8 {-1, -1, 0, 0, 0} }; diff --git a/lte/lib/fec/test/viterbi_test.c b/lte/lib/fec/test/viterbi_test.c index 43180f9e5..e7ee9e92c 100644 --- a/lte/lib/fec/test/viterbi_test.c +++ b/lte/lib/fec/test/viterbi_test.c @@ -187,7 +187,6 @@ int main(int argc, char **argv) { max_coded_length = 0; for (i=0;i max_coded_length) { max_coded_length = coded_length[i]; @@ -273,7 +272,7 @@ int main(int argc, char **argv) { /* coded BER */ for (n=0;n +#include +#include +#include +#include +#include +#include +#include + +#include "lte/phch/dci.h" +#include "lte/common/base.h" +#include "lte/utils/bit.h" +#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); + if (!q->msg) { + perror("malloc"); + return -1; + } + q->nof_dcis = nof_dcis; + return 0; +} + +void dci_free(dci_t *q) { + if (q->msg) { + free(q->msg); + } +} + +void dci_candidate_fprint(FILE *f, dci_candidate_t *q) { + fprintf(f, "L: %d, nCCE: %d, RNTI: 0x%x, nBits: %d\n", + q->L, q->ncce, q->rnti, q->nof_bits); +} + +int dci_format1_add(dci_t *q, dci_format1_t *msg) { + 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"); + return -1; + } + q->msg[i].location.L = 0; + q->msg[i].location.ncce = 0; + q->msg[i].location.nof_bits = dci_format1_sizeof(); + q->msg[i].location.rnti = 1234; + for (j=0;jmsg[i].location.nof_bits;j++) { + q->msg[i].data[j] = rand()%2; + } + 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"); + 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; + } + return 0; +} + +int dci_format0_sizeof(int nof_prb) { + return 1+1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+2+3+1; +} + +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; +} + +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; + } else { + return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+5+3+1+2+2; + } +} + +int dci_format1C_sizeof() { + return 10; +} diff --git a/lte/lib/phch/src/pbch.c b/lte/lib/phch/src/pbch.c index 4158cf855..a20684380 100644 --- a/lte/lib/phch/src/pbch.c +++ b/lte/lib/phch/src/pbch.c @@ -109,7 +109,7 @@ int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, int cell_id } /** Initializes the PBCH transmitter and receiver */ -int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) { +int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { int ret = -1; if (cell_id < 0) { return -1; @@ -117,6 +117,7 @@ int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) { bzero(q, sizeof(pbch_t)); q->cell_id = cell_id; q->cp = cp; + q->nof_prb = nof_prb; if (modem_table_std(&q->mod, LTE_QPSK, true)) { goto clean; @@ -134,7 +135,6 @@ int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) { } q->encoder.K = 7; q->encoder.R = 3; - q->encoder.framelength = 40; q->encoder.tail_biting = true; memcpy(q->encoder.poly, poly, 3 * sizeof(int)); @@ -360,7 +360,7 @@ int pbch_crc_check(char *bits, int nof_ports) { char data[40]; memcpy(data, bits, 40 * sizeof(char)); crc_set_mask(data, nof_ports); - return crc(0, data, 40, 16, 0x11021, 0); + return crc(0, data, 40, 16, LTE_CRC16, 0); } int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int nof_bits, int nof_ports) { @@ -389,7 +389,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n } /* decode */ - viterbi_decode_f(&q->decoder, q->pbch_rm_f, q->data); + viterbi_decode_f(&q->decoder, q->pbch_rm_f, q->data, 40); int c=0; for (j=0;j<40;j++) { @@ -420,7 +420,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n * * Returns 1 if successfully decoded MIB, 0 if not and -1 on error */ -int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int nof_prb, float ebno, pbch_mib_t *mib) { +int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib) { int src, dst, res, nb; int nant_[3] = {1, 2, 4}; int na, nant; @@ -437,7 +437,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no memset(&x[MAX_PORTS_CTRL], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS_CTRL)); /* extract symbols */ - if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], nof_prb, + if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], q->nof_prb, q->cp, q->cell_id)) { fprintf(stderr, "There was an error getting the PBCH symbols\n"); return -1; @@ -445,7 +445,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no /* extract channel estimates */ for (i=0;inof_symbols != pbch_get(ce[i], q->ce[i], nof_prb, + if (q->nof_symbols != pbch_get(ce[i], q->ce[i], q->nof_prb, q->cp, q->cell_id)) { fprintf(stderr, "There was an error getting the PBCH symbols\n"); return -1; @@ -503,8 +503,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no /** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission */ -void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], - int nof_prb, int nof_ports) { +void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports) { int i; int nof_bits = 2 * q->nof_symbols; @@ -527,7 +526,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL] crc(0, q->data, 24, 16, 0x11021, 1); crc_set_mask(q->data, nof_ports); - convcoder_encode(&q->encoder, q->data, q->data_enc); + convcoder_encode(&q->encoder, q->data, q->data_enc, 40); rm_conv_tx(q->data_enc, q->pbch_rm_b, 120, 4 * nof_bits); @@ -549,7 +548,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL] /* mapping to resource elements */ for (i=0;ipbch_symbols[i], slot1_symbols[i], nof_prb, q->cp, q->cell_id); + pbch_put(q->pbch_symbols[i], slot1_symbols[i], q->nof_prb, q->cp, q->cell_id); } q->frame_idx++; if (q->frame_idx == 4) { diff --git a/lte/lib/phch/src/pdcch.c b/lte/lib/phch/src/pdcch.c new file mode 100644 index 000000000..2c1af90f5 --- /dev/null +++ b/lte/lib/phch/src/pdcch.c @@ -0,0 +1,585 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lte/phch/dci.h" +#include "lte/phch/regs.h" +#include "lte/phch/pdcch.h" +#include "lte/common/base.h" +#include "lte/utils/bit.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" + +#define PDCCH_NOF_FORMATS 4 +#define PDCCH_FORMAT_NOF_CCE(i) (1<b)?b:a) + +/** + * 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; + k = 0; + for (L = 2; L > 0; L--) { + for (i = 0; i < MIN(nof_cce,16) / (4 * L); i++) { + c[k].L = 4 * 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", + k, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L); + } + } + return k; +} + +/** + * 36.213 9.1 + */ +int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti, int subframe) { + int i, l, L, k, m; + unsigned int Yk; + const int S[4] = { 6, 12, 8, 16 }; + k = 0; + for (l = 3; l >= 0; l--) { + L = (1 << l); + for (i = 0; i < MIN(nof_cce/L,16/S[l]); i++) { + c[k].L = l; + c[k].nof_bits = nof_bits; + c[k].rnti = rnti; + Yk = rnti; + for (m = 0; m < subframe; m++) { + 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); + k++; + } + } + 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); + if (s->nof_candidates) { + s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates); + dci_candidate_t *c = s->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), SIRNTI); + k += gen_common_search(&c[k], q->nof_cce, + dci_format1C_sizeof(q->nof_prb), SIRNTI); + } + } +} + +/** 36.213 v9.3 Table 7.1-1: System Information DCI messages + * Expect DCI formats 1C and 1A in the common search space + */ +void pdcch_init_search_si(pdcch_t *q) { + pdcch_init_common(q, &q->search_mode[SEARCH_SI], SIRNTI); + q->current_search_mode = SEARCH_SI; +} + +/** 36.213 v9.3 Table 7.1-5 + * user-specific search space. Currently supported transmission Mode 1: + * 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; + 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, c_rnti); + if (s->nof_candidates) { + for (n=0;ncandidates[n] = malloc(sizeof(dci_candidate_t) * s->nof_candidates); + dci_candidate_t *c = s->candidates[n]; + + 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), c_rnti, n); + k += gen_ue_search(&c[k], q->nof_cce, + dci_format1A_sizeof(q->nof_prb), c_rnti, n); + } + } + } + q->current_search_mode = SEARCH_UE; +} + +/** 36.213 v9.3 Table 7.1-3 + * Expect DCI formats 1C and 1A in the common search space + */ +void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti) { + pdcch_init_common(q, &q->search_mode[SEARCH_RA], ra_rnti); + q->current_search_mode = SEARCH_RA; +} + +void pdcch_set_search_si(pdcch_t *q) { + q->current_search_mode = SEARCH_SI; +} +void pdcch_set_search_ue(pdcch_t *q) { + q->current_search_mode = SEARCH_UE; +} +void pdcch_set_search_ra(pdcch_t *q) { + q->current_search_mode = SEARCH_RA; +} + +/** Initializes the PDCCH transmitter and receiver */ +int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, + int cell_id, lte_cp_t cp) { + int ret = -1; + int i; + + if (cell_id < 0) { + return -1; + } + if (nof_ports > MAX_PORTS_CTRL) { + fprintf(stderr, "Invalid number of ports %d\n", nof_ports); + return -1; + } + bzero(q, sizeof(pdcch_t)); + q->cell_id = cell_id; + q->cp = cp; + q->regs = regs; + q->nof_ports = nof_ports; + q->current_search_mode = SEARCH_NONE; + + q->nof_regs = regs_pdcch_nregs(q->regs); + 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); + + if (modem_table_std(&q->mod, LTE_QPSK, true)) { + goto clean; + } + + demod_soft_init(&q->demod); + demod_soft_table_set(&q->demod, &q->mod); + demod_soft_alg_set(&q->demod, APPROX); + + for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell_id, q->nof_bits)) { + goto clean; + } + } + + int poly[3] = { 0x6D, 0x4F, 0x57 }; + if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) { + goto clean; + } + + q->pdcch_e = malloc(sizeof(char) * q->nof_bits); + if (!q->pdcch_e) { + goto clean; + } + + q->pdcch_llr = malloc(sizeof(float) * q->nof_bits); + if (!q->pdcch_llr) { + goto clean; + } + + q->pdcch_d = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pdcch_d) { + goto clean; + } + + for (i = 0; i < MAX_PORTS_CTRL; i++) { + q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->ce[i]) { + goto clean; + } + q->pdcch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pdcch_x[i]) { + goto clean; + } + q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pdcch_symbols[i]) { + goto clean; + } + } + ret = 0; + clean: if (ret == -1) { + pdcch_free(q); + } + return ret; +} + +void pdcch_free(pdcch_t *q) { + int i, j; + + for (i=0;isearch_mode[i].candidates[j]) { + free(q->search_mode[i].candidates[j]); + } + } + } + if (q->pdcch_e) { + free(q->pdcch_e); + } + if (q->pdcch_llr) { + free(q->pdcch_llr); + } + if (q->pdcch_d) { + free(q->pdcch_d); + } + for (i = 0; i < MAX_PORTS_CTRL; i++) { + if (q->ce[i]) { + free(q->ce[i]); + } + if (q->pdcch_x[i]) { + free(q->pdcch_x[i]); + } + if (q->pdcch_symbols[i]) { + free(q->pdcch_symbols[i]); + } + } + + for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + sequence_free(&q->seq_pdcch[i]); + } + + modem_table_free(&q->mod); + viterbi_free(&q->decoder); +} + +/** 36.212 5.3.3.2 to 5.3.3.4 + * + * Returns XOR between parity and remainder bits + * + * TODO: UE transmit antenna selection CRC mask + */ +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; + char *x; + + assert(nof_bits < DCI_MAX_BITS); + + /* unrate matching */ + rm_conv_rx(e, tmp, E, 3 * (nof_bits + 16)); + + DEBUG("Viterbi input: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16)); + } + + /* viterbi decoder */ + viterbi_decode_f(decoder, tmp, 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)); +} + +int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c, + dci_msg_t *msg) { + unsigned short crc_res; + 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", + c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, + c->rnti); + return 1; + } + return 0; +} + +int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], + float *llr, int nsubframe, float ebno) { + + /* Set pointers for layermapping & precoding */ + int i; + cf_t *x[MAX_LAYERS]; + + if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid subframe %d\n", nsubframe); + return -1; + } + + if (ebno == 0.0) { + fprintf(stderr, "EbNo is Zero\n"); + return -1; + } + + /* number of layers equals number of ports */ + for (i = 0; i < q->nof_ports; i++) { + x[i] = q->pdcch_x[i]; + } + 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"); + 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"); + 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 */ + predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d, + q->nof_symbols); + } else { + predecoding_diversity_zf(q->pdcch_symbols, q->ce, x, q->nof_ports, + q->nof_symbols); + layerdemap_diversity(x, q->pdcch_d, q->nof_ports, + q->nof_symbols / q->nof_ports); + } + + /* 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); + } + + /* descramble */ + scrambling_f_offset(&q->seq_pdcch[nsubframe], llr, 0, q->nof_bits); + + return 0; +} + +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) { + k = subframe; + } else { + k = 0; + } + + dci_cnt = 0; + for (i = 0; i < q->search_mode[q->current_search_mode].nof_candidates + && dci_cnt < dci->nof_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++; + } + } + return dci_cnt; +} + +int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) { + pdcch_set_search_si(q); + return pdcch_decode_current_mode(q, llr, dci, 0); +} +int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci) { + pdcch_set_search_ra(q); + return pdcch_decode_current_mode(q, llr, dci, 0); +} +int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) { + pdcch_set_search_ue(q); + return pdcch_decode_current_mode(q, llr, dci, nsubframe); +} + + +/* Decodes PDCCH channels + * + * dci->nof_dcis is the size of the dci->msg buffer (ie max number of messages) + * + * Returns number of messages stored in dci + */ +int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], + dci_t *dci, int nsubframe, float ebno) { + + if (pdcch_extract_llr(q, slot1_symbols, ce, q->pdcch_llr, nsubframe, + ebno)) { + return -1; + } + + if (q->current_search_mode != SEARCH_NONE) { + return pdcch_decode_current_mode(q, q->pdcch_llr, dci, nsubframe); + } + + return 0; +} + +void crc_set_mask_rnti(char *crc, unsigned short rnti) { + int i; + char mask[16]; + char *r = mask; + + INFO("Mask CRC with RNTI 0x%x\n", rnti); + + bit_pack(rnti, &r, 16); + for (i = 0; i < 16; i++) { + crc[i] = (crc[i] + mask[i]) % 2; + } +} + +/** 36.212 5.3.3.2 to 5.3.3.4 + * TODO: UE transmit antenna selection CRC mask + */ +void dci_encode(char *data, char *e, int nof_bits, int E, unsigned short rnti) { + convcoder_t encoder; + char tmp[3 * (DCI_MAX_BITS + 16)]; + + assert(nof_bits < DCI_MAX_BITS); + + int poly[3] = { 0x6D, 0x4F, 0x57 }; + encoder.K = 7; + encoder.R = 3; + encoder.tail_biting = true; + memcpy(encoder.poly, poly, 3 * sizeof(int)); + + crc(0, data, nof_bits, 16, LTE_CRC16, 1); + crc_set_mask_rnti(&data[nof_bits], rnti); + + convcoder_encode(&encoder, data, tmp, nof_bits + 16); + + DEBUG("CConv output: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16)); + } + + rm_conv_tx(tmp, e, 3 * (nof_bits + 16), E); +} + +/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission + */ +int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], + int nsubframe) { + int i; + /* Set pointers for layermapping & precoding */ + cf_t *x[MAX_LAYERS]; + + if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid subframe %d\n", nsubframe); + return -1; + } + + /* number of layers equals number of ports */ + for (i = 0; i < q->nof_ports; i++) { + x[i] = q->pdcch_x[i]; + } + memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); + + /* should add elements? Or maybe random bits to facilitate power estimation */ + bzero(q->pdcch_e, q->nof_bits); + + /* Encode DCIs */ + for (i = 0; i < dci->nof_dcis; i++) { + /* do some sanity checks */ + if (dci->msg[i].location.ncce + PDCCH_FORMAT_NOF_CCE(dci->msg[i].location.L) > q->nof_cce + || dci->msg[i].location.L > 3 + || dci->msg[i].location.nof_bits > DCI_MAX_BITS) { + fprintf(stderr, "Illegal DCI message %d\n", i); + return -1; + } + INFO("Encoding DCI %d: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", + i, dci->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L), + dci->msg[i].location.ncce, dci->msg[i].location.L, dci->msg[i].location.rnti); + + dci_encode(dci->msg[i].data, &q->pdcch_e[72 * dci->msg[i].location.ncce], + dci->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L), + dci->msg[i].location.rnti); + } + + scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 0, q->nof_bits); + + mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->nof_bits); + + /* layer mapping & precoding */ + if (q->nof_ports > 1) { + layermap_diversity(q->pdcch_d, x, q->nof_ports, q->nof_symbols); + precoding_diversity(x, q->pdcch_symbols, q->nof_ports, + q->nof_symbols / q->nof_ports); + } else { + memcpy(q->pdcch_symbols[0], q->pdcch_d, q->nof_symbols * sizeof(cf_t)); + } + + /* mapping to resource elements */ + for (i = 0; i < q->nof_ports; i++) { + pdcch_put(q->pdcch_symbols[i], slot1_symbols[i], q->nof_symbols); + } + return 0; +} + diff --git a/lte/lib/phch/src/regs.c b/lte/lib/phch/src/regs.c index 9d38f4549..0e574d3c2 100644 --- a/lte/lib/phch/src/regs.c +++ b/lte/lib/phch/src/regs.c @@ -58,6 +58,9 @@ void regs_pdcch_free(regs_t *h) { } } +int regs_pdcch_nregs(regs_t *h) { + return 9; +} diff --git a/lte/lib/phch/src/sequences.c b/lte/lib/phch/src/sequences.c index 566d2c589..21a851300 100644 --- a/lte/lib/phch/src/sequences.c +++ b/lte/lib/phch/src/sequences.c @@ -54,3 +54,11 @@ int sequence_phich(sequence_t *seq, int nslot, int cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } + +/** + * 36.211 6.8.2 + */ +int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len) { + bzero(seq, sizeof(sequence_t)); + return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id); +} diff --git a/lte/lib/phch/test/CMakeLists.txt b/lte/lib/phch/test/CMakeLists.txt index e7f3a8fd5..204441ba9 100644 --- a/lte/lib/phch/test/CMakeLists.txt +++ b/lte/lib/phch/test/CMakeLists.txt @@ -68,6 +68,12 @@ ADD_TEST(phich_test_102 phich_test -p 2 -n 10 -g 2) ADD_TEST(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2) +######################################################################## +# PDCCH TEST +######################################################################## + +ADD_EXECUTABLE(pdcch_test pdcch_test.c) +TARGET_LINK_LIBRARIES(pdcch_test lte) ######################################################################## # FILE TEST @@ -79,6 +85,10 @@ TARGET_LINK_LIBRARIES(pbch_file_test lte) ADD_EXECUTABLE(pcfich_file_test pcfich_file_test.c) TARGET_LINK_LIBRARIES(pcfich_file_test lte) +ADD_EXECUTABLE(phich_file_test phich_file_test.c) +TARGET_LINK_LIBRARIES(phich_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) \ 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 bc03a0b34..15cf7ace0 100644 --- a/lte/lib/phch/test/pbch_file_test.c +++ b/lte/lib/phch/test/pbch_file_test.c @@ -141,7 +141,7 @@ int base_init() { return -1; } - if (pbch_init(&pbch, cell_id, cp)) { + if (pbch_init(&pbch, nof_prb, cell_id, cp)) { fprintf(stderr, "Error initiating PBCH\n"); return -1; } @@ -209,7 +209,7 @@ int main(int argc, char **argv) { INFO("Decoding PBCH\n", 0); - n = pbch_decode(&pbch, fft_buffer, ce, nof_prb, 1, &mib); + n = pbch_decode(&pbch, fft_buffer, ce, 1, &mib); base_free(); fftwf_cleanup(); diff --git a/lte/lib/phch/test/pbch_test.c b/lte/lib/phch/test/pbch_test.c index dc3db5122..7a4b9d3c0 100644 --- a/lte/lib/phch/test/pbch_test.c +++ b/lte/lib/phch/test/pbch_test.c @@ -99,7 +99,7 @@ int main(int argc, char **argv) { } } - if (pbch_init(&pbch, cell_id, CPNORM)) { + if (pbch_init(&pbch, nof_prb, cell_id, CPNORM)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } @@ -110,7 +110,7 @@ int main(int argc, char **argv) { mib_tx.phich_resources = R_1_6; mib_tx.sfn = 124; - pbch_encode(&pbch, &mib_tx, slot1_symbols, nof_prb, nof_ports); + pbch_encode(&pbch, &mib_tx, slot1_symbols, nof_ports); /* combine outputs */ for (i=1;i +#include +#include +#include +#include + +#include "lte.h" + +int cell_id = 1; +int nof_prb = 6; +int nof_ports = 1; + +void usage(char *prog) { + printf("Usage: %s [cpv]\n", prog); + printf("\t-c cell id [Default %d]\n", cell_id); + 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"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "cpnv")) != -1) { + switch(opt) { + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int main(int argc, char **argv) { + pdcch_t pdcch; + dci_t dci_tx, dci_rx; + dci_format1_t dci_msg; + regs_t regs; + int i, j; + cf_t *ce[MAX_PORTS_CTRL]; + int nof_re; + cf_t *slot1_symbols[MAX_PORTS_CTRL]; + int nof_dcis; + int ret = -1; + + parse_args(argc,argv); + + nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB; + + /* init memory */ + for (i=0;i +#include +#include +#include +#include + +#include "lte.h" + +char *input_file_name = NULL; +char *matlab_file_name = NULL; +int cell_id = 150; +lte_cp_t cp = CPNORM; +int nof_prb = 50; +int nof_ports = 2; +int flen; +int nof_ctrl_symbols = 1; +phich_resources_t phich_res = R_1; +phich_length_t phich_length = PHICH_NORM; +int numsubframe = 0; + +FILE *fmatlab = NULL; + +filesource_t fsrc; +cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; +phich_t phich; +regs_t regs; +lte_fft_t fft; +chest_t chest; + +void usage(char *prog) { + printf("Usage: %s [vcoe] -i input_file\n", prog); + printf("\t-o output matlab file name [Default Disabled]\n"); + printf("\t-c cell_id [Default %d]\n", cell_id); + printf("\t-p nof_ports [Default %d]\n", nof_ports); + printf("\t-n nof_prb [Default %d]\n", nof_prb); + printf("\t-f nof control symbols [Default %d]\n", nof_ctrl_symbols); + printf("\t-g phich ng factor: 1/6, 1/2, 1, 2 [Default 1]\n"); + printf("\t-e phich extended length [Default normal]\n"); + printf("\t-l extended cyclic prefix [Default normal]\n"); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "iovcenpfgl")) != -1) { + switch(opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'o': + matlab_file_name = argv[optind]; + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'f': + nof_ctrl_symbols = atoi(argv[optind]); + break; + case 'g': + if (!strcmp(argv[optind], "1/6")) { + phich_res = R_1_6; + } else if (!strcmp(argv[optind], "1/2")) { + phich_res = R_1_2; + } else if (!strcmp(argv[optind], "1")) { + phich_res = R_1; + } else if (!strcmp(argv[optind], "2")) { + phich_res = R_2; + } else { + fprintf(stderr, "Invalid phich ng factor %s. Setting to default.\n", argv[optind]); + } + break; + case 'e': + phich_length = PHICH_EXT; + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + case 'l': + cp = CPEXT; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!input_file_name) { + usage(argv[0]); + exit(-1); + } +} + +int base_init() { + int i; + + if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", input_file_name); + exit(-1); + } + + if (matlab_file_name) { + fmatlab = fopen(matlab_file_name, "w"); + if (!fmatlab) { + perror("fopen"); + return -1; + } + } else { + fmatlab = NULL; + } + + flen = SLOT_LEN(lte_symbol_sz(nof_prb), cp); + + input_buffer = malloc(flen * sizeof(cf_t)); + if (!input_buffer) { + perror("malloc"); + exit(-1); + } + + fft_buffer = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t)); + if (!fft_buffer) { + perror("malloc"); + return -1; + } + + for (i=0;i