mirror of https://github.com/PentHertz/srsLTE.git
Added PDCCH encoder/decoder. Tested with Amarisoft eNodeB
This commit is contained in:
parent
587ff2c7f8
commit
869b842415
|
@ -43,6 +43,7 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
|
|||
|
||||
#define SIRNTI 0xFFFF
|
||||
#define PRNTI 0xFFFE
|
||||
#define MRNTI 0xFFFD
|
||||
|
||||
#define MAX_NSYMB 7
|
||||
|
||||
|
@ -93,7 +94,7 @@ int lte_voffset(int symbol_id, int cell_id, int nof_ports);
|
|||
|
||||
typedef enum {
|
||||
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
|
||||
} mimo_type_t;
|
||||
} lte_mimo_type_t;
|
||||
|
||||
typedef enum { PHICH_NORM, PHICH_EXT} phich_length_t;
|
||||
typedef enum { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
|
||||
|
@ -113,8 +114,8 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int earfcn_start, int e
|
|||
int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_nelems);
|
||||
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems);
|
||||
|
||||
int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type);
|
||||
char *lte_mimotype2str(mimo_type_t type);
|
||||
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type);
|
||||
char *lte_mimotype2str(lte_mimo_type_t type);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,7 +38,7 @@ int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_sym
|
|||
int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
|
||||
int nof_symbols[MAX_CODEWORDS]);
|
||||
int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
|
||||
int nof_symbols[MAX_CODEWORDS], mimo_type_t type);
|
||||
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
|
||||
|
||||
|
||||
/* Generates the vector of data symbols "d" based on the vector of layer-mapped symbols "x"
|
||||
|
@ -48,6 +48,6 @@ int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_l
|
|||
int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
|
||||
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]);
|
||||
int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
|
||||
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], mimo_type_t type);
|
||||
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -41,7 +41,7 @@ typedef _Complex float cf_t;
|
|||
int precoding_single(cf_t *x, cf_t *y, int nof_symbols);
|
||||
int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols);
|
||||
int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports,
|
||||
int nof_symbols, mimo_type_t type);
|
||||
int nof_symbols, lte_mimo_type_t type);
|
||||
|
||||
|
||||
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "ce"
|
||||
|
@ -51,6 +51,6 @@ int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
|
|||
cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols);
|
||||
int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
|
||||
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols,
|
||||
mimo_type_t type);
|
||||
lte_mimo_type_t type);
|
||||
|
||||
#endif /* PRECODING_H_ */
|
||||
|
|
|
@ -40,7 +40,7 @@ typedef struct {
|
|||
}soft_table_t;
|
||||
|
||||
typedef struct {
|
||||
cf_t* symbol_table; // bit-to-symbol mapping
|
||||
cf_t* symbol_table; // bit-to-symbol mapping
|
||||
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
|
||||
int nsymbols; // number of modulation symbols
|
||||
int nbits_x_symbol; // number of bits per symbol
|
||||
|
@ -49,7 +49,7 @@ typedef struct {
|
|||
|
||||
// Modulation standards
|
||||
enum modem_std {
|
||||
LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64
|
||||
LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6
|
||||
};
|
||||
|
||||
void modem_table_init(modem_table_t* q);
|
||||
|
|
|
@ -25,11 +25,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DCI_
|
||||
#define DCI_
|
||||
|
||||
#include "lte/common/base.h"
|
||||
#include <stdint.h>
|
||||
#include "lte/phch/ra.h"
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
|
@ -37,77 +38,63 @@ typedef _Complex float cf_t;
|
|||
* DCI message generation according to the formats, as specified in
|
||||
* 36.212 Section 5.3.3.1
|
||||
*
|
||||
* Call the function dci_init(&q) to generate a collection of DCI messages
|
||||
* to be transmitted in a subframe. Each subsequent call to
|
||||
* dci_add_formatXX(&q, ...) generates the DCI message and appends the data
|
||||
* to the collection "q".
|
||||
*
|
||||
*/
|
||||
|
||||
#define DCI_MAX_BITS 45
|
||||
|
||||
#define DCI_MAX_BITS 57
|
||||
|
||||
typedef enum {
|
||||
FORMAT0,
|
||||
FORMAT1,
|
||||
FORMAT1A,
|
||||
/* ... */
|
||||
}dci_format_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;
|
||||
|
||||
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;
|
||||
DCI_COMMON = 0, DCI_UE = 1
|
||||
} dci_spec_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned char nof_bits;
|
||||
unsigned char L; // Aggregation level
|
||||
unsigned char ncce; // Position of first CCE of the dci
|
||||
unsigned short rnti;
|
||||
}dci_candidate_t;
|
||||
} dci_candidate_t;
|
||||
|
||||
typedef struct {
|
||||
char data[DCI_MAX_BITS];
|
||||
dci_candidate_t location;
|
||||
}dci_msg_t;
|
||||
} dci_msg_t;
|
||||
|
||||
typedef struct {
|
||||
dci_msg_t *msg;
|
||||
int nof_dcis;
|
||||
}dci_t;
|
||||
int max_dcis;
|
||||
} dci_t;
|
||||
|
||||
|
||||
int dci_init(dci_t *q, int nof_dci);
|
||||
int dci_init(dci_t *q, int max_dci);
|
||||
void dci_free(dci_t *q);
|
||||
char* dci_format_string(dci_format_t format);
|
||||
|
||||
int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti);
|
||||
void dci_candidate_fprint(FILE *f, dci_candidate_t *q);
|
||||
|
||||
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti);
|
||||
int dci_format0_sizeof(int nof_prb);
|
||||
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti);
|
||||
void dci_msg_type_fprint(FILE *f, dci_msg_type_t type);
|
||||
|
||||
int dci_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti);
|
||||
int dci_format1_sizeof(int nof_prb, int P);
|
||||
// For dci_msg_type_t = PUSCH_SCHED
|
||||
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb);
|
||||
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb);
|
||||
|
||||
int dci_format1A_add(dci_t *q, dci_format1_t *msg);
|
||||
int dci_format1A_sizeof(int nof_prb, bool random_access_initiated);
|
||||
// For dci_msg_type_t = PDSCH_SCHED
|
||||
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti);
|
||||
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti);
|
||||
|
||||
int dci_format1C_add(dci_t *q, dci_format1_t *msg);
|
||||
int dci_format1C_sizeof();
|
||||
int dci_format_sizeof(dci_format_t format, int nof_prb);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -59,36 +59,42 @@ typedef struct {
|
|||
int cell_id;
|
||||
int nof_prb;
|
||||
int max_ctrl_symbols;
|
||||
int cfi;
|
||||
int ngroups_phich;
|
||||
int refs_in_symbol1;
|
||||
int nof_ports;
|
||||
lte_cp_t cp;
|
||||
phich_resources_t phich_res;
|
||||
phich_length_t phich_len;
|
||||
int nof_cce;
|
||||
regs_ch_t pcfich;
|
||||
regs_ch_t *phich; // there are several phich
|
||||
regs_ch_t *pdcch; // there are several pdcch
|
||||
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
|
||||
the three possible CFI value */
|
||||
int nof_regs;
|
||||
regs_reg_t *regs;
|
||||
}regs_t;
|
||||
|
||||
int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
|
||||
int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
|
||||
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp);
|
||||
void regs_free(regs_t *h);
|
||||
int regs_set_cfi(regs_t *h, int nof_ctrl_symbols);
|
||||
|
||||
int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
|
||||
int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
|
||||
int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb);
|
||||
int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb);
|
||||
|
||||
int regs_pcfich_nregs(regs_t *h);
|
||||
int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols);
|
||||
int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM]);
|
||||
int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]);
|
||||
|
||||
int regs_phich_nregs(regs_t *h);
|
||||
int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols);
|
||||
int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup);
|
||||
int regs_phich_ngroups(regs_t *h);
|
||||
int regs_phich_reset(regs_t *h, cf_t *slot_symbols);
|
||||
|
||||
int regs_pdcch_nregs(regs_t *h);
|
||||
int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols);
|
||||
int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,6 +36,7 @@ uint32_t bit_unpack(char **bits, int nof_bits);
|
|||
void bit_pack(uint32_t value, char **bits, int nof_bits);
|
||||
void bit_fprint(FILE *stream, char *bits, int nof_bits);
|
||||
unsigned int bit_diff(char *x, char *y, int nbits);
|
||||
int bit_count(unsigned int n);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ void get_time_interval(struct timeval * tdata);
|
|||
|
||||
extern int verbose;
|
||||
|
||||
#define VERBOSE_ISINFO() (verbose==VERBOSE_INFO)
|
||||
#define VERBOSE_ISDEBUG() (verbose==VERBOSE_DEBUG)
|
||||
#define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO)
|
||||
#define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG)
|
||||
|
||||
#define PRINT_DEBUG verbose=VERBOSE_DEBUG
|
||||
#define PRINT_INFO verbose=VERBOSE_INFO
|
||||
|
|
|
@ -135,7 +135,7 @@ struct lte_band lte_bands[NOF_LTE_BANDS] = {
|
|||
};
|
||||
#define EOF_BAND 9919
|
||||
|
||||
int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type) {
|
||||
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) {
|
||||
if (!strcmp(mimo_type_str, "single")) {
|
||||
*type = SINGLE_ANTENNA;
|
||||
} else if (!strcmp(mimo_type_str, "diversity")) {
|
||||
|
@ -148,7 +148,7 @@ int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
char *lte_mimotype2str(mimo_type_t type) {
|
||||
char *lte_mimotype2str(lte_mimo_type_t type) {
|
||||
switch(type) {
|
||||
case SINGLE_ANTENNA:
|
||||
return "single";
|
||||
|
|
|
@ -78,7 +78,7 @@ int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw,
|
|||
* Returns the number of symbols per layer (M_symb^layer in the specs)
|
||||
*/
|
||||
int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
|
||||
int nof_symbols[MAX_CODEWORDS], mimo_type_t type) {
|
||||
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) {
|
||||
|
||||
if (nof_cw > MAX_CODEWORDS) {
|
||||
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
|
||||
|
@ -167,7 +167,7 @@ int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_la
|
|||
* nof_symbols. Returns -1 on error
|
||||
*/
|
||||
int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
|
||||
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], mimo_type_t type) {
|
||||
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) {
|
||||
|
||||
if (nof_cw > MAX_CODEWORDS) {
|
||||
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
|
||||
|
|
|
@ -85,7 +85,7 @@ int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports,
|
|||
|
||||
/* 36.211 v10.3.0 Section 6.3.4 */
|
||||
int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols,
|
||||
mimo_type_t type) {
|
||||
lte_mimo_type_t type) {
|
||||
|
||||
if (nof_ports > MAX_PORTS) {
|
||||
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports);
|
||||
|
@ -177,7 +177,7 @@ int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
|
|||
|
||||
/* 36.211 v10.3.0 Section 6.3.4 */
|
||||
int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
|
||||
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, mimo_type_t type) {
|
||||
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type) {
|
||||
|
||||
if (nof_ports > MAX_PORTS) {
|
||||
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports);
|
||||
|
|
|
@ -75,7 +75,7 @@ void parse_args(int argc, char **argv) {
|
|||
int main(int argc, char **argv) {
|
||||
int i, j, num_errors, symbols_layer;
|
||||
cf_t *d[MAX_CODEWORDS], *x[MAX_LAYERS], *dp[MAX_CODEWORDS];
|
||||
mimo_type_t type;
|
||||
lte_mimo_type_t type;
|
||||
int nof_symb_cw[MAX_CODEWORDS];
|
||||
int n[2];
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ int main(int argc, char **argv) {
|
|||
int i, j;
|
||||
float mse;
|
||||
cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS], *xr[MAX_LAYERS];
|
||||
mimo_type_t type;
|
||||
lte_mimo_type_t type;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ void demod_soft_alg_set(demod_soft_t *q, enum alg alg_type) {
|
|||
}
|
||||
|
||||
void demod_soft_sigma_set(demod_soft_t *q, float sigma) {
|
||||
q->sigma = sigma;
|
||||
q->sigma = 2*sigma;
|
||||
}
|
||||
|
||||
int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int nsymbols) {
|
||||
|
|
|
@ -41,14 +41,14 @@
|
|||
#include "lte/utils/vector.h"
|
||||
#include "lte/utils/debug.h"
|
||||
|
||||
|
||||
int dci_init(dci_t *q, int nof_dcis) {
|
||||
q->msg = calloc(sizeof(dci_msg_t), nof_dcis);
|
||||
int dci_init(dci_t *q, int max_dcis) {
|
||||
q->msg = calloc(sizeof(dci_msg_t), max_dcis);
|
||||
if (!q->msg) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
q->nof_dcis = nof_dcis;
|
||||
q->nof_dcis = 0;
|
||||
q->max_dcis = max_dcis;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -63,60 +63,755 @@ void dci_candidate_fprint(FILE *f, dci_candidate_t *q) {
|
|||
q->L, q->ncce, q->rnti, q->nof_bits);
|
||||
}
|
||||
|
||||
int dci_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti) {
|
||||
int i, j;
|
||||
i=0;
|
||||
while(i<q->nof_dcis && q->msg[i].location.nof_bits)
|
||||
i++;
|
||||
if (i == q->nof_dcis) {
|
||||
fprintf(stderr, "No more space in DCI container\n");
|
||||
int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) {
|
||||
if (L >= 0 && L <=3) {
|
||||
msg->location.L = (unsigned char) L;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid L %d\n", L);
|
||||
return -1;
|
||||
}
|
||||
q->msg[i].location.L = L;
|
||||
q->msg[i].location.ncce = nCCE;
|
||||
q->msg[i].location.nof_bits = dci_format1_sizeof(6, 1);
|
||||
q->msg[i].location.rnti = rnti;
|
||||
for (j=0;j<q->msg[i].location.nof_bits;j++) {
|
||||
q->msg[i].data[j] = rand()%2;
|
||||
if (nCCE >= 0 && nCCE <= 87) {
|
||||
msg->location.ncce = (unsigned char) nCCE;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid nCCE %d\n", nCCE);
|
||||
return -1;
|
||||
}
|
||||
msg->location.rnti = rnti;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti) {
|
||||
int i, j;
|
||||
i=0;
|
||||
while(i<q->nof_dcis && q->msg[i].location.nof_bits)
|
||||
i++;
|
||||
if (i == q->nof_dcis) {
|
||||
fprintf(stderr, "No more space in DCI container\n");
|
||||
return -1;
|
||||
}
|
||||
q->msg[i].location.L = L;
|
||||
q->msg[i].location.ncce = nCCE;
|
||||
q->msg[i].location.nof_bits = dci_format0_sizeof(msg->n_rb_ul);
|
||||
q->msg[i].location.rnti = rnti;
|
||||
for (j=0;j<q->msg[i].location.nof_bits;j++) {
|
||||
q->msg[i].data[j] = rand()%2;
|
||||
}
|
||||
return 0;
|
||||
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) {
|
||||
return 1+1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+2+3+1;
|
||||
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 P) {
|
||||
return (nof_prb>10)?1:0+(int) ceilf(log2f(nof_prb/P))+5+3+1+2+2;
|
||||
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_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(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;
|
||||
}
|
||||
}
|
||||
|
||||
int dci_format1C_sizeof() {
|
||||
return 10;
|
||||
|
||||
|
||||
/**********************************
|
||||
* 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) {
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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 {
|
||||
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;
|
||||
}
|
||||
|
||||
/* Format 1C for compact scheduling of PDSCH words
|
||||
*
|
||||
*/
|
||||
int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
|
||||
|
||||
/* pack bits */
|
||||
char *y = msg->data;
|
||||
|
||||
if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) {
|
||||
fprintf(stderr, "Format 1C accepts distributed type2 resource allocation only\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nof_prb >= 50) {
|
||||
*y++ = data->type2_alloc.n_gap;
|
||||
}
|
||||
int n_step = ra_type2_n_rb_step(nof_prb);
|
||||
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
|
||||
|
||||
if (data->type2_alloc.L_crb > ((int) n_vrb_dl/n_step)*n_step) {
|
||||
fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb,
|
||||
((int) n_vrb_dl/n_step)*n_step);
|
||||
return -1;
|
||||
}
|
||||
if (data->type2_alloc.L_crb % n_step) {
|
||||
fprintf(stderr, "L_crb must be multiple of n_step\n");
|
||||
return -1;
|
||||
}
|
||||
if (data->type2_alloc.RB_start % n_step) {
|
||||
fprintf(stderr, "RB_start must be multiple of n_step\n");
|
||||
return -1;
|
||||
}
|
||||
int L_p = data->type2_alloc.L_crb/n_step;
|
||||
int RB_p = data->type2_alloc.RB_start/n_step;
|
||||
int n_vrb_p = (int) n_vrb_dl / n_step;
|
||||
|
||||
uint32_t riv;
|
||||
if (data->type2_alloc.L_crb) {
|
||||
riv = ra_type2_to_riv(L_p, RB_p, n_vrb_p);
|
||||
} else {
|
||||
riv = data->type2_alloc.riv;
|
||||
}
|
||||
bit_pack(riv, &y, riv_nbits((int) n_vrb_dl/n_step));
|
||||
|
||||
// in format1C, MCS = TBS according to 7.1.7.2 of 36.213
|
||||
uint32_t mcs;
|
||||
if (data->mcs.mod == MOD_NULL) {
|
||||
mcs = data->mcs.mcs_idx;
|
||||
} else {
|
||||
if (data->mcs.tbs) {
|
||||
data->mcs.tbs_idx = ra_tbs_to_table_idx_format1c(data->mcs.tbs);
|
||||
}
|
||||
mcs = data->mcs.tbs_idx;
|
||||
}
|
||||
bit_pack(mcs, &y, 5);
|
||||
|
||||
msg->location.nof_bits = (y - msg->data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
|
||||
uint16_t L_p, RB_p;
|
||||
|
||||
/* pack bits */
|
||||
char *y = msg->data;
|
||||
|
||||
if (msg->location.nof_bits != dci_format_sizeof(Format1C, nof_prb)) {
|
||||
fprintf(stderr, "Invalid message length for format 1C\n");
|
||||
return -1;
|
||||
}
|
||||
data->alloc_type = alloc_type2;
|
||||
data->type2_alloc.mode = t2_dist;
|
||||
if (nof_prb >= 50) {
|
||||
data->type2_alloc.n_gap = *y++;
|
||||
}
|
||||
int n_step = ra_type2_n_rb_step(nof_prb);
|
||||
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
|
||||
|
||||
uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl/n_step));
|
||||
int n_vrb_p = (int) n_vrb_dl / n_step;
|
||||
|
||||
ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p);
|
||||
data->type2_alloc.L_crb = L_p * n_step;
|
||||
data->type2_alloc.RB_start = RB_p * n_step;
|
||||
data->type2_alloc.riv = riv;
|
||||
|
||||
data->mcs.mcs_idx = bit_unpack(&y, 5);
|
||||
data->mcs.tbs_idx = data->mcs.mcs_idx;
|
||||
data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs.tbs_idx);
|
||||
data->mcs.mod = QPSK;
|
||||
|
||||
msg->location.nof_bits = (y - msg->data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti) {
|
||||
switch(format) {
|
||||
case Format1:
|
||||
return dci_format1_pack(data, msg, nof_prb);
|
||||
case Format1A:
|
||||
return dci_format1As_pack(data, msg, nof_prb, crc_is_crnti);
|
||||
case Format1C:
|
||||
return dci_format1Cs_pack(data, msg, nof_prb);
|
||||
default:
|
||||
fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n", dci_format_string(format));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) {
|
||||
if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
|
||||
return dci_format1_unpack(msg, data, nof_prb);
|
||||
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
|
||||
return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti);
|
||||
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
|
||||
return dci_format1Cs_unpack(msg, data, nof_prb);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
|
||||
return dci_format0_pack(data, msg, nof_prb);
|
||||
}
|
||||
|
||||
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
|
||||
return dci_format0_unpack(msg, data, nof_prb);
|
||||
}
|
||||
|
||||
char* dci_format_string(dci_format_t format) {
|
||||
switch(format) {
|
||||
case Format0:
|
||||
return "Format0";
|
||||
case Format1:
|
||||
return "Format1";
|
||||
case Format1A:
|
||||
return "Format1A";
|
||||
case Format1C:
|
||||
return "Format1C";
|
||||
default:
|
||||
return "N/A"; // fatal error
|
||||
}
|
||||
}
|
||||
|
||||
void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) {
|
||||
switch(type.type) {
|
||||
case PUSCH_SCHED:
|
||||
fprintf(f,"%s PUSCH Scheduling\n", dci_format_string(type.format));
|
||||
break;
|
||||
case PDSCH_SCHED:
|
||||
fprintf(f,"%s PDSCH Scheduling\n", dci_format_string(type.format));
|
||||
break;
|
||||
case RA_PROC_PDCCH:
|
||||
fprintf(f,"%s Random access initiated by PDCCH\n", dci_format_string(type.format));
|
||||
break;
|
||||
case MCCH_CHANGE:
|
||||
fprintf(f,"%s MCCH change notification\n", dci_format_string(type.format));
|
||||
break;
|
||||
case TPC_COMMAND:
|
||||
fprintf(f,"%s TPC command\n", dci_format_string(type.format));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti) {
|
||||
if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb)
|
||||
&& !msg->data[0]) {
|
||||
type->type = PUSCH_SCHED;
|
||||
type->format = Format0;
|
||||
return 0;
|
||||
} else if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
|
||||
type->type = PDSCH_SCHED; // only these 2 types supported
|
||||
type->format = Format1;
|
||||
return 0;
|
||||
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
|
||||
if (msg->location.rnti == crnti) {
|
||||
type->type = RA_PROC_PDCCH;
|
||||
type->format = Format1A;
|
||||
} else {
|
||||
type->type = PDSCH_SCHED; // only these 2 types supported
|
||||
type->format = Format1A;
|
||||
}
|
||||
return 0;
|
||||
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
|
||||
if (msg->location.rnti == MRNTI) {
|
||||
type->type = MCCH_CHANGE;
|
||||
type->format = Format1C;
|
||||
} else {
|
||||
type->type = PDSCH_SCHED; // only these 2 types supported
|
||||
type->format = Format1C;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,15 +47,11 @@
|
|||
#define PDCCH_FORMAT_NOF_REGS(i) ((1<<i)*9)
|
||||
#define PDCCH_FORMAT_NOF_BITS(i) ((1<<i)*72)
|
||||
|
||||
int pdcch_put(cf_t *pdcch, cf_t *slot1_data, int nsymbols) {
|
||||
memcpy(slot1_data, pdcch, sizeof(cf_t) * nsymbols);
|
||||
return nsymbols;
|
||||
}
|
||||
#define NOF_COMMON_FORMATS 2
|
||||
const dci_format_t common_formats[NOF_COMMON_FORMATS] = {Format1A, Format1C};
|
||||
|
||||
int pdcch_get(cf_t *slot1_data, cf_t *pdcch, int nsymbols) {
|
||||
memcpy(pdcch, slot1_data, sizeof(cf_t) * nsymbols);
|
||||
return nsymbols;
|
||||
}
|
||||
#define NOF_UE_FORMATS 2
|
||||
const dci_format_t ue_formats[NOF_UE_FORMATS] = {Format0, Format1}; // 1A has the same payload as 0
|
||||
|
||||
#define MIN(a,b) ((a>b)?b:a)
|
||||
|
||||
|
@ -63,18 +59,18 @@ int pdcch_get(cf_t *slot1_data, cf_t *pdcch, int nsymbols) {
|
|||
* 36.213 9.1
|
||||
*/
|
||||
int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti) {
|
||||
int i, L, k;
|
||||
int i, l, L, k;
|
||||
k = 0;
|
||||
for (L = 2; L > 0; L--) {
|
||||
for (i = 0; i < MIN(nof_cce,16) / (4 * L); i++) {
|
||||
c[k].L = 4 * L;
|
||||
for (l = 3; l > 1; l--) {
|
||||
L = (1 << l);
|
||||
for (i = 0; i < MIN(nof_cce,16) / (L); i++) {
|
||||
c[k].L = l;
|
||||
c[k].nof_bits = nof_bits;
|
||||
c[k].rnti = rnti;
|
||||
c[k].ncce = (4 * L) * (i % (nof_cce / (4 * L)));
|
||||
k++;
|
||||
INFO(
|
||||
"Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
|
||||
c[k].ncce = (L) * (i % (nof_cce / (L)));
|
||||
INFO("Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
|
||||
k, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
return k;
|
||||
|
@ -88,6 +84,11 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short
|
|||
unsigned int Yk;
|
||||
const int S[4] = { 6, 12, 8, 16 };
|
||||
k = 0;
|
||||
if (!subframe) {
|
||||
INFO("UE-specific candidates for RNTI: 0x%x, NofBits: %d, NofCCE: %d\n",
|
||||
rnti, nof_bits, nof_cce);
|
||||
if (VERBOSE_ISINFO()) printf("[INFO]: ");
|
||||
}
|
||||
for (l = 3; l >= 0; l--) {
|
||||
L = (1 << l);
|
||||
for (i = 0; i < MIN(nof_cce/L,16/S[l]); i++) {
|
||||
|
@ -99,27 +100,35 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short
|
|||
Yk = (39827 * Yk) % 65537;
|
||||
}
|
||||
c[k].ncce = L * ((Yk + i) % (nof_cce / L));
|
||||
INFO("UE-specific SS Candidate %d: SF: %d, RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
|
||||
k, subframe, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
|
||||
if (!subframe) {
|
||||
if (VERBOSE_ISINFO()) {
|
||||
printf("(%d, %d), ", c[k].ncce, c[k].L);
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
if (!subframe) {
|
||||
if (VERBOSE_ISINFO()) printf("\n");
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) {
|
||||
int k;
|
||||
s->nof_candidates = 2*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
|
||||
int k, i;
|
||||
s->nof_candidates = NOF_COMMON_FORMATS*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
|
||||
if (s->nof_candidates) {
|
||||
s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
|
||||
dci_candidate_t *c = s->candidates[0];
|
||||
|
||||
s->nof_candidates = 0;
|
||||
if (c) {
|
||||
// Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16
|
||||
k = 0;
|
||||
k += gen_common_search(&c[k], q->nof_cce,
|
||||
dci_format1A_sizeof(q->nof_prb, true), SIRNTI);
|
||||
k += gen_common_search(&c[k], q->nof_cce,
|
||||
dci_format1C_sizeof(q->nof_prb), SIRNTI);
|
||||
for(i=0;i<NOF_COMMON_FORMATS;i++) {
|
||||
k += gen_common_search(&c[k], q->nof_cce,
|
||||
dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI);
|
||||
s->nof_candidates++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,11 +146,11 @@ void pdcch_init_search_si(pdcch_t *q) {
|
|||
* DCI Format 1A and 1 + PUSCH scheduling format 0
|
||||
*/
|
||||
void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
|
||||
int l, n, k;
|
||||
int l, n, k, i;
|
||||
pdcch_search_t *s = &q->search_mode[SEARCH_UE];
|
||||
s->nof_candidates = 0;
|
||||
for (l=0;l<3;l++) {
|
||||
s->nof_candidates += 3*(MIN(q->nof_cce,16) / (1<<l));
|
||||
s->nof_candidates += NOF_UE_FORMATS*(MIN(q->nof_cce,16) / (1<<l));
|
||||
}
|
||||
INFO("Initiating %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", s->nof_candidates, c_rnti);
|
||||
if (s->nof_candidates) {
|
||||
|
@ -152,12 +161,10 @@ void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
|
|||
if (c) {
|
||||
// Expect Formats 1, 1A, 0
|
||||
k = 0;
|
||||
k += gen_ue_search(&c[k], q->nof_cce,
|
||||
dci_format0_sizeof(q->nof_prb), c_rnti, n);
|
||||
k += gen_ue_search(&c[k], q->nof_cce,
|
||||
dci_format1_sizeof(q->nof_prb, 1), c_rnti, n);
|
||||
k += gen_ue_search(&c[k], q->nof_cce,
|
||||
dci_format1A_sizeof(q->nof_prb, true), c_rnti, n);
|
||||
for(i=0;i<NOF_UE_FORMATS;i++) {
|
||||
k += gen_ue_search(&c[k], q->nof_cce,
|
||||
dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,15 +207,16 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
|
|||
q->cp = cp;
|
||||
q->regs = regs;
|
||||
q->nof_ports = nof_ports;
|
||||
q->nof_prb = nof_prb;
|
||||
q->current_search_mode = SEARCH_NONE;
|
||||
|
||||
q->nof_regs = regs_pdcch_nregs(q->regs);
|
||||
q->nof_regs = (regs_pdcch_nregs(q->regs)/9)*9;
|
||||
q->nof_cce = q->nof_regs / 9;
|
||||
q->nof_symbols = 4 * q->nof_regs;
|
||||
q->nof_bits = 2 * q->nof_symbols;
|
||||
|
||||
INFO("Init PDCCH: %d REGs, %d bits, %d symbols, %d ports\n", q->nof_regs,
|
||||
q->nof_bits, q->nof_symbols, q->nof_ports);
|
||||
INFO("Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports\n", q->nof_cce,
|
||||
q->nof_regs, q->nof_bits, q->nof_symbols, q->nof_ports);
|
||||
|
||||
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
|
||||
goto clean;
|
||||
|
@ -314,11 +322,18 @@ unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
|
|||
int nof_bits) {
|
||||
|
||||
float tmp[3 * (DCI_MAX_BITS + 16)];
|
||||
unsigned short p_bits;
|
||||
unsigned short p_bits, crc_res;
|
||||
char *x;
|
||||
|
||||
assert(nof_bits < DCI_MAX_BITS);
|
||||
|
||||
/* char a[] = {1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0};
|
||||
|
||||
float *b = malloc(sizeof(E));
|
||||
for (int i=0;i<E;i++) {
|
||||
b[i] = a[i]?1:-1;
|
||||
}
|
||||
*/
|
||||
/* unrate matching */
|
||||
rm_conv_rx(e, tmp, E, 3 * (nof_bits + 16));
|
||||
|
||||
|
@ -330,24 +345,31 @@ unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
|
|||
/* viterbi decoder */
|
||||
viterbi_decode_f(decoder, tmp, data, nof_bits + 16);
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
bit_fprint(stdout, data, nof_bits+16);
|
||||
}
|
||||
|
||||
x = &data[nof_bits];
|
||||
p_bits = (unsigned short) bit_unpack(&x, 16);
|
||||
|
||||
return (p_bits
|
||||
^ ((unsigned short) crc(0, data, nof_bits, 16, LTE_CRC16, 0)
|
||||
& 0xffff));
|
||||
crc_res = ((unsigned short) crc(0, data, nof_bits, 16, LTE_CRC16, 0)
|
||||
& 0xffff);
|
||||
DEBUG("p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x\n", p_bits, crc_res, p_bits ^ crc_res);
|
||||
return (p_bits ^ crc_res);
|
||||
}
|
||||
|
||||
int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c,
|
||||
dci_msg_t *msg) {
|
||||
unsigned short crc_res;
|
||||
DEBUG("Trying Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
|
||||
c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L,
|
||||
c->rnti);
|
||||
crc_res = dci_decode(&q->decoder, &llr[72 * c->ncce], msg->data,
|
||||
PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits);
|
||||
|
||||
if (c->rnti == crc_res) {
|
||||
memcpy(&msg->location, c, sizeof(dci_candidate_t));
|
||||
INFO(
|
||||
"FOUND CAND: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
|
||||
"FOUND Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
|
||||
c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L,
|
||||
c->rnti);
|
||||
return 1;
|
||||
|
@ -379,25 +401,21 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
|||
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports));
|
||||
|
||||
/* extract symbols */
|
||||
if (q->nof_symbols
|
||||
!= pdcch_get(slot1_symbols, q->pdcch_symbols[0], q->nof_symbols)) {
|
||||
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
|
||||
int n = regs_pdcch_get(q->regs, slot1_symbols, q->pdcch_symbols[0]);
|
||||
if (q->nof_symbols != n) {
|
||||
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* extract channel estimates */
|
||||
for (i = 0; i < q->nof_ports; i++) {
|
||||
if (q->nof_symbols != pdcch_get(ce[i], q->ce[i], q->nof_symbols)) {
|
||||
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
|
||||
n = regs_pdcch_get(q->regs, ce[i], q->ce[i]);
|
||||
if (q->nof_symbols != n) {
|
||||
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG("pdcch_symbols: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_c(stdout, q->pdcch_symbols[0], q->nof_symbols);
|
||||
}
|
||||
|
||||
/* in control channels, only diversity is supported */
|
||||
if (q->nof_ports == 1) {
|
||||
/* no need for layer demapping */
|
||||
|
@ -410,13 +428,18 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
|||
q->nof_symbols / q->nof_ports);
|
||||
}
|
||||
|
||||
DEBUG("pdcch d symbols: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_c(stdout, q->pdcch_d, q->nof_symbols);
|
||||
}
|
||||
|
||||
/* demodulate symbols */
|
||||
demod_soft_sigma_set(&q->demod, ebno);
|
||||
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols);
|
||||
|
||||
DEBUG("llr: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_f(stdout, q->pdcch_llr, q->nof_symbols);
|
||||
vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits);
|
||||
}
|
||||
|
||||
/* descramble */
|
||||
|
@ -426,7 +449,6 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
|||
}
|
||||
|
||||
int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) {
|
||||
int dci_cnt;
|
||||
int k, i;
|
||||
|
||||
if (q->current_search_mode == SEARCH_UE) {
|
||||
|
@ -435,16 +457,15 @@ int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe)
|
|||
k = 0;
|
||||
}
|
||||
|
||||
dci_cnt = 0;
|
||||
for (i = 0; i < q->search_mode[q->current_search_mode].nof_candidates
|
||||
&& dci_cnt < dci->nof_dcis; i++) {
|
||||
&& dci->nof_dcis < dci->max_dcis; i++) {
|
||||
if (pdcch_decode_candidate(q, q->pdcch_llr,
|
||||
&q->search_mode[q->current_search_mode].candidates[k][i],
|
||||
&dci->msg[dci_cnt])) {
|
||||
dci_cnt++;
|
||||
&dci->msg[dci->nof_dcis])) {
|
||||
dci->nof_dcis++;
|
||||
}
|
||||
}
|
||||
return dci_cnt;
|
||||
return dci->nof_dcis;
|
||||
}
|
||||
|
||||
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) {
|
||||
|
@ -578,7 +599,7 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL],
|
|||
|
||||
/* mapping to resource elements */
|
||||
for (i = 0; i < q->nof_ports; i++) {
|
||||
pdcch_put(q->pdcch_symbols[i], slot1_symbols[i], q->nof_symbols);
|
||||
regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot1_symbols[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -37,29 +37,144 @@
|
|||
regs_reg_t *regs_find_reg(regs_t *h, int k, int l);
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* PDCCH REG ALLOCATION
|
||||
*
|
||||
***************************************************************/
|
||||
|
||||
void regs_pdcch_free(regs_t *h) {
|
||||
int i;
|
||||
for (i=0;i<3;i++) {
|
||||
if (h->pdcch[i].regs) {
|
||||
free(h->pdcch[i].regs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define PDCCH_NCOLS 32
|
||||
const unsigned char PDCCH_PERM[PDCCH_NCOLS] =
|
||||
{ 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8,
|
||||
24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 };
|
||||
|
||||
/** Initialize REGs for PDCCH
|
||||
* 36.211 10.3 section 6.8.5
|
||||
*/
|
||||
int regs_pdcch_init(regs_t *h) {
|
||||
return 0;
|
||||
}
|
||||
int i, m, cfi, nof_ctrl_symbols;
|
||||
int ret = -1;
|
||||
int nrows, ndummy, j, k, kp;
|
||||
regs_reg_t **tmp = NULL;
|
||||
|
||||
void regs_pdcch_free(regs_t *h) {
|
||||
if (h->pdcch) {
|
||||
free(h->pdcch);
|
||||
bzero(&h->pdcch, sizeof(regs_ch_t));
|
||||
|
||||
for (cfi=0;cfi<3;cfi++) {
|
||||
if (h->nof_prb < 10) {
|
||||
nof_ctrl_symbols = cfi+2;
|
||||
} else {
|
||||
nof_ctrl_symbols = cfi+1;
|
||||
}
|
||||
|
||||
tmp = malloc(sizeof(regs_reg_t*) * h->nof_regs);
|
||||
if (!tmp) {
|
||||
perror("malloc");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
|
||||
/* Number and count REGs for this CFI */
|
||||
m=0;
|
||||
for (i=0;i<h->nof_regs;i++) {
|
||||
if (h->regs[i].l < nof_ctrl_symbols && !h->regs[i].assigned) {
|
||||
tmp[m] = &h->regs[i];
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
h->pdcch[cfi].nof_regs = m;
|
||||
|
||||
h->pdcch[cfi].regs = malloc(sizeof(regs_reg_t*) * h->pdcch[cfi].nof_regs);
|
||||
if (!h->pdcch[cfi].regs) {
|
||||
perror("malloc");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
|
||||
/* Interleave REGs */
|
||||
nrows = (h->pdcch[cfi].nof_regs-1)/PDCCH_NCOLS+1;
|
||||
ndummy = PDCCH_NCOLS*nrows - h->pdcch[cfi].nof_regs;
|
||||
if (ndummy < 0) {
|
||||
ndummy = 0;
|
||||
}
|
||||
|
||||
k=0;
|
||||
for (j = 0; j < PDCCH_NCOLS; j++) {
|
||||
for (i = 0; i < nrows; i++) {
|
||||
if (i*PDCCH_NCOLS + PDCCH_PERM[j] >= ndummy) {
|
||||
m = i*PDCCH_NCOLS + PDCCH_PERM[j]-ndummy;
|
||||
kp = (k-h->cell_id)%h->pdcch[cfi].nof_regs;
|
||||
if (kp < 0) {
|
||||
kp += h->pdcch[cfi].nof_regs;
|
||||
}
|
||||
h->pdcch[cfi].regs[m] = tmp[kp];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
h->pdcch[cfi].nof_regs = (h->pdcch[cfi].nof_regs/9)*9;
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
if (VERBOSE_ISINFO() && cfi == 1) {
|
||||
for (i=0;i<h->pdcch[cfi].nof_regs;i++) {
|
||||
INFO("Logical PDCCH REG#%d:%d (%d,%d)\n", i%9,i/9,
|
||||
h->pdcch[cfi].regs[i]->k0, h->pdcch[cfi].regs[i]->l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
clean_and_exit:
|
||||
if (tmp) {
|
||||
free(tmp);
|
||||
}
|
||||
if (ret == -1) {
|
||||
regs_pdcch_free(h);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int regs_pdcch_nregs(regs_t *h) {
|
||||
return 9;
|
||||
if (h->cfi == -1) {
|
||||
fprintf(stderr, "Must call regs_set_cfi() first\n");
|
||||
return -1;
|
||||
} else {
|
||||
return h->pdcch[h->cfi].nof_regs;
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy quadruplets to REGs and cyclic shift them, according to the
|
||||
* second part of 6.8.5 in 36.211
|
||||
*/
|
||||
int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols) {
|
||||
if (h->cfi == -1) {
|
||||
fprintf(stderr, "Must call regs_set_cfi() first\n");
|
||||
return -1;
|
||||
}
|
||||
int i;
|
||||
for (i=0;i<h->pdcch[h->cfi].nof_regs;i++) {
|
||||
regs_put_reg(h->pdcch[h->cfi].regs[i], &pdcch_symbols[i*4], slot_symbols, h->nof_prb);
|
||||
}
|
||||
return h->pdcch[h->cfi].nof_regs*4;
|
||||
}
|
||||
|
||||
int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols) {
|
||||
if (h->cfi == -1) {
|
||||
fprintf(stderr, "Must call regs_set_cfi() first\n");
|
||||
return -1;
|
||||
}
|
||||
int i;
|
||||
for (i=0;i<h->pdcch[h->cfi].nof_regs;i++) {
|
||||
regs_get_reg(h->pdcch[h->cfi].regs[i], slot_symbols, &pdcch_symbols[i*4], h->nof_prb);
|
||||
}
|
||||
return h->pdcch[h->cfi].nof_regs*4;
|
||||
}
|
||||
|
||||
|
||||
|
@ -195,6 +310,16 @@ void regs_phich_free(regs_t *h) {
|
|||
}
|
||||
}
|
||||
|
||||
int regs_phich_nregs(regs_t *h) {
|
||||
int i, n;
|
||||
n=0;
|
||||
for (i=0;i<h->ngroups_phich;i++) {
|
||||
n += h->phich[i].nof_regs;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int regs_phich_ngroups(regs_t *h) {
|
||||
return h->ngroups_phich;
|
||||
}
|
||||
|
@ -274,10 +399,6 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* PCFICH REG ALLOCATION
|
||||
|
@ -330,6 +451,10 @@ void regs_pcfich_free(regs_t *h) {
|
|||
}
|
||||
}
|
||||
|
||||
int regs_pcfich_nregs(regs_t *h) {
|
||||
return h->pcfich.nof_regs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the PCFICH symbols to the resource grid pointed by slot_symbols
|
||||
*
|
||||
|
@ -392,13 +517,13 @@ regs_reg_t *regs_find_reg(regs_t *h, int k, int l) {
|
|||
* Returns the number of REGs in a PRB
|
||||
* 36.211 Section 6.2.4
|
||||
*/
|
||||
int regs_num_x_symbol(int symbol, int refs_in_symbol1, lte_cp_t cp) {
|
||||
int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) {
|
||||
|
||||
switch (symbol) {
|
||||
case 0:
|
||||
return 2;
|
||||
case 1:
|
||||
switch (refs_in_symbol1) {
|
||||
switch (nof_port) {
|
||||
case 1:
|
||||
case 2:
|
||||
return 3;
|
||||
|
@ -430,10 +555,10 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int
|
|||
|
||||
reg->l = symbol;
|
||||
reg->assigned = false;
|
||||
reg->k0 = k0 + nreg * 6;
|
||||
|
||||
switch (maxreg) {
|
||||
case 2:
|
||||
reg->k0 = k0 + nreg * 6;
|
||||
/* there are two references in the middle */
|
||||
j = z = 0;
|
||||
for (i = 0; i < vo; i++) {
|
||||
|
@ -456,6 +581,7 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int
|
|||
break;
|
||||
|
||||
case 3:
|
||||
reg->k0 = k0 + nreg * 4;
|
||||
/* there is no reference */
|
||||
for (i = 0; i < 4; i++) {
|
||||
reg->k[i] = k0 + nreg * 4 + i;
|
||||
|
@ -479,15 +605,33 @@ void regs_free(regs_t *h) {
|
|||
bzero(h, sizeof(regs_t));
|
||||
}
|
||||
|
||||
/** Sets the CFI value for this subframe (CFI must be in the range 1..3).
|
||||
*/
|
||||
int regs_set_cfi(regs_t *h, int cfi) {
|
||||
if (cfi > 0 && cfi <= 3) {
|
||||
if (h->phich_len == PHICH_EXT &&
|
||||
((h->nof_prb < 10 && cfi < 2) || (h->nof_prb >= 10 && cfi < 3))) {
|
||||
fprintf(stderr, "PHICH length is extended. The number of control symbols should be at least 3.\n");
|
||||
return -1;
|
||||
} else {
|
||||
h->cfi = cfi - 1;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Invalid CFI %d\n", cfi);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes REGs structure.
|
||||
* Sets all REG indices and initializes PCFICH, PHICH and PDCCH REGs
|
||||
* Returns 0 if OK, -1 on error
|
||||
*/
|
||||
int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
|
||||
int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
|
||||
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp) {
|
||||
int ret = -1;
|
||||
int i, j, n, p, k;
|
||||
int i, j[4], jmax, n[4], prb, k;
|
||||
int vo = cell_id % 3;
|
||||
int max_ctrl_symbols = nof_prb<10?4:3;
|
||||
|
||||
|
@ -496,18 +640,19 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
|
|||
h->cell_id = cell_id;
|
||||
h->nof_prb = nof_prb;
|
||||
h->max_ctrl_symbols = max_ctrl_symbols;
|
||||
h->cfi = -1; // not yet initialized
|
||||
h->phich_res = phich_res;
|
||||
h->phich_len = phich_len;
|
||||
h->cp = cp;
|
||||
h->refs_in_symbol1 = refs_in_symbol1;
|
||||
h->nof_ports = nof_ports;
|
||||
|
||||
h->nof_regs = 0;
|
||||
for (i = 0; i < max_ctrl_symbols; i++) {
|
||||
n = regs_num_x_symbol(i, refs_in_symbol1, cp);
|
||||
if (n == -1) {
|
||||
n[i] = regs_num_x_symbol(i, nof_ports, cp);
|
||||
if (n[i] == -1) {
|
||||
return -1;
|
||||
}
|
||||
h->nof_regs += nof_prb * n;
|
||||
h->nof_regs += nof_prb * n[i];
|
||||
}
|
||||
INFO("Indexing %d REGs. CellId: %d, %d PRB, CP: %s\n", h->nof_regs, h->cell_id, h->nof_prb,
|
||||
CP_ISNORM(cp)?"Normal":"Extended");
|
||||
|
@ -517,26 +662,36 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
|
|||
goto clean_and_exit;
|
||||
}
|
||||
|
||||
k = 0;
|
||||
for (i = 0; i < max_ctrl_symbols; i++) {
|
||||
n = regs_num_x_symbol(i, refs_in_symbol1, cp);
|
||||
for (p = 0; p < nof_prb; p++) {
|
||||
for (j = 0; j < n; j++) {
|
||||
if (regs_reg_init(&h->regs[k], i, j, p * RE_X_RB, n, vo)) {
|
||||
fprintf(stderr, "Error initializing REGs\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
DEBUG("Available REG #%3d: %d:%d:%d (k0=%d)\n", k, i, p, j,
|
||||
h->regs[k].k0);
|
||||
k++;
|
||||
/* Sort REGs according to PDCCH mapping, beggining from the lowest l index then k */
|
||||
bzero(j, sizeof(int) * 4);
|
||||
k = i = prb = jmax = 0;
|
||||
while (k < h->nof_regs) {
|
||||
if (n[i] == 3 || (n[i] == 2 && jmax != 1)) {
|
||||
if (regs_reg_init(&h->regs[k], i, j[i], prb * RE_X_RB, n[i], vo)) {
|
||||
fprintf(stderr, "Error initializing REGs\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i],
|
||||
h->regs[k].k0);
|
||||
j[i]++;
|
||||
k++;
|
||||
}
|
||||
i++;
|
||||
if (i == max_ctrl_symbols) {
|
||||
i = 0;
|
||||
jmax++;
|
||||
}
|
||||
if (jmax == 3) {
|
||||
prb++;
|
||||
bzero(j, sizeof(int) * 4);
|
||||
jmax = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (regs_pcfich_init(h)) {
|
||||
fprintf(stderr, "Error initializing PCFICH REGs\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
|
||||
if (regs_phich_init(h)) {
|
||||
fprintf(stderr, "Error initializing PHICH REGs\n");
|
||||
goto clean_and_exit;
|
||||
|
@ -548,7 +703,8 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
|
|||
|
||||
ret = 0;
|
||||
|
||||
clean_and_exit: if (ret == -1) {
|
||||
clean_and_exit:
|
||||
if (ret == -1) {
|
||||
regs_free(h);
|
||||
}
|
||||
return ret;
|
||||
|
@ -562,13 +718,8 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
|
|||
int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) {
|
||||
int i;
|
||||
for (i = 0; i < REGS_RE_X_REG; i++) {
|
||||
if (reg->assigned) {
|
||||
DEBUG("PUT REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l);
|
||||
slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i];
|
||||
} else {
|
||||
fprintf(stderr, "Error REG not assigned\n");
|
||||
return -1;
|
||||
}
|
||||
DEBUG("PUT REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l);
|
||||
slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i];
|
||||
}
|
||||
return REGS_RE_X_REG;
|
||||
}
|
||||
|
@ -580,15 +731,10 @@ int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr
|
|||
int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) {
|
||||
int i;
|
||||
for (i = 0; i < REGS_RE_X_REG; i++) {
|
||||
if (reg->assigned) {
|
||||
slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i];
|
||||
DEBUG("ADD REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
|
||||
__real__ slot_symbols[REG_IDX(reg, i, nof_prb)],
|
||||
__imag__ slot_symbols[REG_IDX(reg, i, nof_prb)]);
|
||||
} else {
|
||||
fprintf(stderr, "Error REG not assigned\n");
|
||||
return -1;
|
||||
}
|
||||
slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i];
|
||||
DEBUG("ADD REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
|
||||
__real__ slot_symbols[REG_IDX(reg, i, nof_prb)],
|
||||
__imag__ slot_symbols[REG_IDX(reg, i, nof_prb)]);
|
||||
}
|
||||
return REGS_RE_X_REG;
|
||||
}
|
||||
|
@ -600,13 +746,8 @@ int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr
|
|||
int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) {
|
||||
int i;
|
||||
for (i = 0; i < REGS_RE_X_REG; i++) {
|
||||
if (reg->assigned) {
|
||||
DEBUG("RESET REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l);
|
||||
slot_symbols[REG_IDX(reg, i, nof_prb)] = 0;
|
||||
} else {
|
||||
fprintf(stderr, "Error REG not assigned\n");
|
||||
return -1;
|
||||
}
|
||||
DEBUG("RESET REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l);
|
||||
slot_symbols[REG_IDX(reg, i, nof_prb)] = 0;
|
||||
}
|
||||
return REGS_RE_X_REG;
|
||||
}
|
||||
|
@ -617,14 +758,9 @@ int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) {
|
|||
int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb) {
|
||||
int i;
|
||||
for (i = 0; i < REGS_RE_X_REG; i++) {
|
||||
if (reg->assigned) {
|
||||
reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)];
|
||||
DEBUG("GET REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
|
||||
__real__ reg_data[i], __imag__ reg_data[i]);
|
||||
} else {
|
||||
fprintf(stderr, "Error REG not assigned\n");
|
||||
return -1;
|
||||
}
|
||||
reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)];
|
||||
//DEBUG("GET REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
|
||||
// __real__ reg_data[i], __imag__ reg_data[i]);
|
||||
}
|
||||
return REGS_RE_X_REG;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,11 @@ ADD_TEST(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2)
|
|||
ADD_EXECUTABLE(pdcch_test pdcch_test.c)
|
||||
TARGET_LINK_LIBRARIES(pdcch_test lte)
|
||||
|
||||
ADD_TEST(pdcch_test pdcch_test)
|
||||
|
||||
ADD_EXECUTABLE(dci_unpacking dci_unpacking.c)
|
||||
TARGET_LINK_LIBRARIES(dci_unpacking lte)
|
||||
|
||||
########################################################################
|
||||
# FILE TEST
|
||||
########################################################################
|
||||
|
@ -88,7 +93,11 @@ TARGET_LINK_LIBRARIES(pcfich_file_test lte)
|
|||
ADD_EXECUTABLE(phich_file_test phich_file_test.c)
|
||||
TARGET_LINK_LIBRARIES(phich_file_test lte)
|
||||
|
||||
ADD_EXECUTABLE(pdcch_file_test pdcch_file_test.c)
|
||||
TARGET_LINK_LIBRARIES(pdcch_file_test lte)
|
||||
|
||||
ADD_TEST(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat)
|
||||
ADD_TEST(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)
|
||||
ADD_TEST(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)
|
||||
ADD_TEST(pdcch_file_test pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat)
|
||||
|
|
@ -223,7 +223,8 @@ int main(int argc, char **argv) {
|
|||
} else {
|
||||
if (mib.nof_ports == 2 && mib.nof_prb == 50 && mib.phich_length == PHICH_NORM
|
||||
&& mib.phich_resources == R_1 && mib.sfn == 28) {
|
||||
printf("This is the pbch_test.dat file\n");
|
||||
pbch_mib_fprint(stdout, &mib);
|
||||
printf("This is the signal.1.92M.dat file\n");
|
||||
exit(0);
|
||||
} else {
|
||||
pbch_mib_fprint(stdout, &mib);
|
||||
|
|
|
@ -36,10 +36,12 @@
|
|||
int cell_id = 1;
|
||||
int nof_prb = 6;
|
||||
int nof_ports = 1;
|
||||
int cfi = 1;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [cpv]\n", prog);
|
||||
printf("\t-c cell id [Default %d]\n", cell_id);
|
||||
printf("\t-f cfi [Default %d]\n", cfi);
|
||||
printf("\t-p nof_ports [Default %d]\n", nof_ports);
|
||||
printf("\t-n nof_prb [Default %d]\n", nof_prb);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
|
@ -47,11 +49,14 @@ void usage(char *prog) {
|
|||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "cpnv")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "cpnfv")) != -1) {
|
||||
switch(opt) {
|
||||
case 'p':
|
||||
nof_ports = atoi(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
cfi = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
|
@ -68,10 +73,42 @@ void parse_args(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int test_dci_payload_size() {
|
||||
int i, j;
|
||||
int x[4];
|
||||
const dci_format_t formats[4] = {Format0, Format1, Format1A, Format1C};
|
||||
const int prb[6]={6, 15, 25, 50, 75, 100};
|
||||
const int dci_sz[6][5] = {
|
||||
{21, 19, 21, 8},
|
||||
{22, 23, 22, 10},
|
||||
{25, 27, 25, 12},
|
||||
{27, 31, 27, 13},
|
||||
{27, 33, 27, 14},
|
||||
{28, 39, 28, 15}
|
||||
};
|
||||
|
||||
printf("Testing DCI payload sizes...\n");
|
||||
printf(" PRB\t0\t1\t1A\t1C\n");
|
||||
for (i=0;i<6;i++) {
|
||||
int n=prb[i];
|
||||
for (j=0;j<4;j++) {
|
||||
x[j] = dci_format_sizeof(formats[j], n);
|
||||
if (x[j] != dci_sz[i][j]) {
|
||||
fprintf(stderr, "Invalid DCI payload size for %s\n", dci_format_string(formats[j]));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
printf(" %2d:\t%2d\t%2d\t%2d\t%2d\n",n,x[0],x[1],x[2],x[3]);
|
||||
}
|
||||
printf("Ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
pdcch_t pdcch;
|
||||
dci_t dci_tx, dci_rx;
|
||||
dci_format1_t dci_msg;
|
||||
ra_pdsch_t ra_dl;
|
||||
regs_t regs;
|
||||
int i, j;
|
||||
cf_t *ce[MAX_PORTS_CTRL];
|
||||
|
@ -84,6 +121,10 @@ int main(int argc, char **argv) {
|
|||
|
||||
nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
|
||||
|
||||
if (test_dci_payload_size()) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* init memory */
|
||||
for (i=0;i<MAX_PORTS_CTRL;i++) {
|
||||
ce[i] = malloc(sizeof(cf_t) * nof_re);
|
||||
|
@ -106,13 +147,34 @@ int main(int argc, char **argv) {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
if (pdcch_init(&pdcch, ®s, nof_prb, nof_ports, cell_id, CPNORM)) {
|
||||
fprintf(stderr, "Error creating PBCH object\n");
|
||||
if (regs_set_cfi(®s, cfi)) {
|
||||
fprintf(stderr, "Error setting CFI\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
dci_init(&dci_tx, 1);
|
||||
dci_format1_add(&dci_tx, &dci_msg, 1, 0, 1234);
|
||||
if (pdcch_init(&pdcch, ®s, nof_prb, nof_ports, cell_id, CPNORM)) {
|
||||
fprintf(stderr, "Error creating PDCCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
dci_init(&dci_tx, 2);
|
||||
bzero(&ra_dl, sizeof(ra_pdsch_t));
|
||||
ra_dl.harq_process = 0;
|
||||
//ra_pdsch_set_mcs_index(&ra_dl, 6);
|
||||
ra_pdsch_set_mcs(&ra_dl, QAM16, 5);
|
||||
ra_dl.ndi = 0;
|
||||
ra_dl.rv_idx = 0;
|
||||
ra_dl.alloc_type = alloc_type0;
|
||||
ra_dl.type0_alloc.rbg_bitmask = 0x5;
|
||||
|
||||
dci_msg_pack_pdsch(&ra_dl, &dci_tx.msg[0], Format1, nof_prb, false);
|
||||
dci_msg_candidate_set(&dci_tx.msg[0], 0, 0, 1234);
|
||||
dci_tx.nof_dcis++;
|
||||
|
||||
ra_pdsch_set_mcs(&ra_dl, QAM16, 15);
|
||||
dci_msg_pack_pdsch(&ra_dl, &dci_tx.msg[1], Format1, nof_prb, false);
|
||||
dci_msg_candidate_set(&dci_tx.msg[1], 0, 1, 1234);
|
||||
dci_tx.nof_dcis++;
|
||||
|
||||
pdcch_encode(&pdcch, &dci_tx, slot1_symbols, 0);
|
||||
|
||||
|
@ -125,13 +187,12 @@ int main(int argc, char **argv) {
|
|||
|
||||
pdcch_init_search_ue(&pdcch, 1234);
|
||||
|
||||
dci_init(&dci_rx, 1);
|
||||
dci_init(&dci_rx, 2);
|
||||
nof_dcis = pdcch_decode(&pdcch, slot1_symbols[0], ce, &dci_rx, 0, 1);
|
||||
if (nof_dcis < 0) {
|
||||
printf("Error decoding\n");
|
||||
} else if (nof_dcis == dci_tx.nof_dcis) {
|
||||
for (i=0;i<nof_dcis;i++) {
|
||||
|
||||
if (dci_tx.msg[i].location.L != dci_rx.msg[i].location.L
|
||||
|| dci_tx.msg[i].location.ncce != dci_rx.msg[i].location.ncce
|
||||
|| dci_tx.msg[i].location.nof_bits != dci_rx.msg[i].location.nof_bits
|
||||
|
@ -146,7 +207,6 @@ int main(int argc, char **argv) {
|
|||
printf("Error in DCI %d: Received data does not match\n", i);
|
||||
goto quit;
|
||||
}
|
||||
/* check more things ... */
|
||||
}
|
||||
} else {
|
||||
printf("Transmitted %d DCIs but got %d\n", dci_tx.nof_dcis, nof_dcis);
|
||||
|
|
|
@ -142,8 +142,13 @@ int rm_conv_rx(float *input, float *output, int in_len, int out_len) {
|
|||
d_i = (i + ndummy) / NCOLS;
|
||||
d_j = (i + ndummy) % NCOLS;
|
||||
for (j = 0; j < RATE; j++) {
|
||||
output[i * RATE + j] = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows
|
||||
+ d_i];
|
||||
float o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows
|
||||
+ d_i];
|
||||
if (o != RX_NULL) {
|
||||
output[i * RATE + j] = o;
|
||||
} else {
|
||||
output[i * RATE + j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -23,7 +23,7 @@ int main(int argc, char **argv) {
|
|||
resample_arb_init(&r, rate);
|
||||
|
||||
clock_t start = clock(), diff;
|
||||
int n_out = resample_arb_compute(&r, in, out, N);
|
||||
//int n_out = resample_arb_compute(&r, in, out, N);
|
||||
diff = clock() - start;
|
||||
|
||||
int msec = diff * 1000 / CLOCKS_PER_SEC;
|
||||
|
|
|
@ -71,3 +71,11 @@ unsigned int bit_diff(char *x, char *y, int nbits) {
|
|||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
// Counts the number of ones in a word. K&R book exercise 2.9
|
||||
int bit_count(unsigned int n) {
|
||||
int c;
|
||||
for (c = 0; n; c++)
|
||||
n &= n - 1;
|
||||
return c;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue