From b934a270751cd009fe3dc50a2ba532ee28b6191c Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 27 Apr 2016 17:23:36 +0200 Subject: [PATCH] PUSCH + CQI (short and long) + HARQ + RI working in test --- cmake/modules/FindVolk.cmake | 8 + matlab/tests/pdsch_bler.m | 2 + srslte/include/srslte/fec/rm_conv.h | 8 + srslte/include/srslte/fec/viterbi.h | 9 + srslte/include/srslte/phch/pusch.h | 9 + srslte/include/srslte/phch/sch.h | 15 ++ srslte/include/srslte/phch/uci.h | 33 +++ srslte/include/srslte/utils/vector.h | 7 +- srslte/include/srslte/utils/vector_simd.h | 3 +- srslte/lib/fec/rm_conv.c | 67 +++++ srslte/lib/fec/viterbi.c | 24 ++ srslte/lib/phch/pusch.c | 47 ++-- srslte/lib/phch/sch.c | 136 ++++++++-- srslte/lib/phch/test/pusch_test.c | 53 ++-- srslte/lib/phch/uci.c | 301 ++++++++++++++++++++-- srslte/lib/utils/vector.c | 63 +++++ srslte/lib/utils/vector_simd.c | 42 +++ 17 files changed, 732 insertions(+), 95 deletions(-) diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index 4a5f028c5..5dbe17cd5 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -57,10 +57,18 @@ IF(VOLK_FOUND) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_multiply_32f HAVE_VOLK_MULT_REAL2_FUNCTION) + CHECK_FUNCTION_EXISTS_MATH(volk_16i_max_star_16i HAVE_VOLK_MAX_STAR_S_FUNCTION) + CHECK_FUNCTION_EXISTS_MATH(volk_8i_convert_16i HAVE_VOLK_CONVERT_CI_FUNCTION) SET(VOLK_DEFINITIONS "HAVE_VOLK") + IF(${HAVE_VOLK_CONVERT_CI_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_CI_FUNCTION") + ENDIF() + IF(${HAVE_VOLK_MAX_STAR_S_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_STAR_S_FUNCTION") + ENDIF() IF(${HAVE_VOLK_MAX_ABS_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_ABS_FUNCTION") ENDIF() diff --git a/matlab/tests/pdsch_bler.m b/matlab/tests/pdsch_bler.m index 4efc17348..44e0daa65 100644 --- a/matlab/tests/pdsch_bler.m +++ b/matlab/tests/pdsch_bler.m @@ -17,6 +17,8 @@ enbConfig.NDLRB = 100; enbConfig.CFI = 1; enbConfig.DuplexMode='FDD'; +lteCQIDecode + % Transmission mode configuration for PDSCH pdschConfig.NLayers = 1; pdschConfig.TxScheme = 'Port0'; diff --git a/srslte/include/srslte/fec/rm_conv.h b/srslte/include/srslte/fec/rm_conv.h index 265f74ae0..92e640e3a 100644 --- a/srslte/include/srslte/fec/rm_conv.h +++ b/srslte/include/srslte/fec/rm_conv.h @@ -55,4 +55,12 @@ SRSLTE_API int srslte_rm_conv_rx(float *input, float *output, uint32_t out_len); + +/************* FIX THIS. MOVE ALL PROCESSING TO INT16 AND HAVE ONLY 1 IMPLEMENTATION ******/ + +SRSLTE_API int srslte_rm_conv_rx_s(int16_t *input, + uint32_t in_len, + int16_t *output, + uint32_t out_len); + #endif diff --git a/srslte/include/srslte/fec/viterbi.h b/srslte/include/srslte/fec/viterbi.h index 7493730f5..c11545bf4 100644 --- a/srslte/include/srslte/fec/viterbi.h +++ b/srslte/include/srslte/fec/viterbi.h @@ -55,6 +55,7 @@ typedef struct SRSLTE_API{ uint32_t framebits; bool tail_biting; float gain_quant; + int16_t gain_quant_s; uint32_t poly[3]; int (*decode) (void*, uint8_t*, uint8_t*, uint32_t); int (*decode_f) (void*, float*, uint8_t*, uint32_t); @@ -72,6 +73,9 @@ SRSLTE_API int srslte_viterbi_init(srslte_viterbi_t *q, SRSLTE_API void srslte_viterbi_set_gain_quant(srslte_viterbi_t *q, float gain_quant); +SRSLTE_API void srslte_viterbi_set_gain_quant_s(srslte_viterbi_t *q, + int16_t gain_quant); + SRSLTE_API void srslte_viterbi_free(srslte_viterbi_t *q); SRSLTE_API int srslte_viterbi_decode_f(srslte_viterbi_t *q, @@ -79,6 +83,11 @@ SRSLTE_API int srslte_viterbi_decode_f(srslte_viterbi_t *q, uint8_t *data, uint32_t frame_length); +SRSLTE_API int srslte_viterbi_decode_s(srslte_viterbi_t *q, + int16_t *symbols, + uint8_t *data, + uint32_t frame_length); + SRSLTE_API int srslte_viterbi_decode_uc(srslte_viterbi_t *q, uint8_t *symbols, uint8_t *data, diff --git a/srslte/include/srslte/phch/pusch.h b/srslte/include/srslte/phch/pusch.h index ef65ab79a..7a59bfaf2 100644 --- a/srslte/include/srslte/phch/pusch.h +++ b/srslte/include/srslte/phch/pusch.h @@ -147,6 +147,15 @@ SRSLTE_API int srslte_pusch_decode(srslte_pusch_t *q, float noise_estimate, uint8_t *data); +SRSLTE_API int srslte_pusch_uci_decode(srslte_pusch_t *q, + srslte_pusch_cfg_t *cfg, + srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols, + cf_t *ce, + float noise_estimate, + uint8_t *data, + srslte_uci_data_t *uci_data); + SRSLTE_API float srslte_pusch_average_noi(srslte_pusch_t *q); SRSLTE_API uint32_t srslte_pusch_last_noi(srslte_pusch_t *q); diff --git a/srslte/include/srslte/phch/sch.h b/srslte/include/srslte/phch/sch.h index 41ece6b26..7c365120b 100644 --- a/srslte/include/srslte/phch/sch.h +++ b/srslte/include/srslte/phch/sch.h @@ -124,6 +124,21 @@ SRSLTE_API int srslte_ulsch_decode(srslte_sch_t *q, int16_t *g_bits, uint8_t *data); +SRSLTE_API int srslte_ulsch_uci_decode(srslte_sch_t *q, + srslte_pusch_cfg_t *cfg, + srslte_softbuffer_rx_t *softbuffer, + int16_t *q_bits, + int16_t *g_bits, + uint8_t *data, + srslte_uci_data_t *uci_data); + +SRSLTE_API int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, + srslte_pusch_cfg_t *cfg, + srslte_softbuffer_rx_t *softbuffer, + int16_t *q_bits, + uint8_t *c_seq, + srslte_uci_data_t *uci_data); + SRSLTE_API float srslte_sch_beta_cqi(uint32_t I_cqi); SRSLTE_API uint32_t srslte_sch_find_Ioffset_ack(float beta); diff --git a/srslte/include/srslte/phch/uci.h b/srslte/include/srslte/phch/uci.h index 174922580..4b0d24195 100644 --- a/srslte/include/srslte/phch/uci.h +++ b/srslte/include/srslte/phch/uci.h @@ -39,6 +39,7 @@ #include "srslte/common/phy_common.h" #include "srslte/phch/pusch_cfg.h" #include "srslte/fec/crc.h" +#include "srslte/fec/viterbi.h" #include "srslte/phch/cqi.h" #define SRSLTE_UCI_MAX_CQI_LEN_PUSCH 512 @@ -47,8 +48,12 @@ typedef struct SRSLTE_API { srslte_crc_t crc; + srslte_viterbi_t viterbi; uint8_t tmp_cqi[SRSLTE_UCI_MAX_CQI_LEN_PUSCH]; uint8_t encoded_cqi[3*SRSLTE_UCI_MAX_CQI_LEN_PUSCH]; + int16_t encoded_cqi_s[3*SRSLTE_UCI_MAX_CQI_LEN_PUSCH]; + uint8_t *cqi_table[11]; + int16_t *cqi_table_s[11]; } srslte_uci_cqi_pusch_t; typedef struct SRSLTE_API { @@ -61,6 +66,7 @@ typedef struct SRSLTE_API { uint32_t uci_ack_len; bool scheduling_request; bool channel_selection; + bool cqi_ack; } srslte_uci_data_t; typedef enum { @@ -84,6 +90,15 @@ SRSLTE_API int srslte_uci_encode_cqi_pusch(srslte_uci_cqi_pusch_t *q, uint32_t Q_prime_ri, uint8_t *q_bits); +SRSLTE_API int srslte_uci_decode_cqi_pusch(srslte_uci_cqi_pusch_t *q, + srslte_pusch_cfg_t *cfg, + int16_t *q_bits, + float beta, + uint32_t Q_prime_ri, + uint32_t cqi_len, + uint8_t *cqi_data, + bool *cqi_ack); + SRSLTE_API int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]); @@ -95,6 +110,15 @@ SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint32_t H_prime_total, srslte_uci_bit_t *ri_bits); +SRSLTE_API int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, + int16_t *q_bits, + uint8_t *c_seq, + float beta, + uint32_t H_prime_total, + uint32_t O_cqi, + srslte_uci_bit_t *ack_bits, + uint8_t *data); + SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, uint8_t data, uint32_t O_cqi, @@ -102,5 +126,14 @@ SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, uint32_t H_prime_total, srslte_uci_bit_t *ri_bits); +SRSLTE_API int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, + int16_t *q_bits, + uint8_t *c_seq, + float beta, + uint32_t H_prime_total, + uint32_t O_cqi, + srslte_uci_bit_t *ri_bits, + uint8_t *data); + #endif diff --git a/srslte/include/srslte/utils/vector.h b/srslte/include/srslte/utils/vector.h index 1b173dc5a..897adf789 100644 --- a/srslte/include/srslte/utils/vector.h +++ b/srslte/include/srslte/utils/vector.h @@ -96,6 +96,7 @@ SRSLTE_API void srslte_vec_square_dist(cf_t symbol, cf_t *points, float *distanc SRSLTE_API void srslte_vec_sc_add_fff(float *x, float h, float *z, uint32_t len); SRSLTE_API void srslte_vec_sc_add_cfc(cf_t *x, float h, cf_t *z, uint32_t len); SRSLTE_API void srslte_vec_sc_add_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len); +SRSLTE_API void srslte_vec_sc_add_sss(int16_t *x, int16_t h, int16_t *z, uint32_t len); /* scalar product */ SRSLTE_API void srslte_vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len); @@ -109,6 +110,7 @@ SRSLTE_API void srslte_vec_norm_cfc(cf_t *x, float amplitude, cf_t *y, uint32_t SRSLTE_API void srslte_vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len); SRSLTE_API void srslte_vec_convert_if(int16_t *x, float *z, float scale, uint32_t len); +SRSLTE_API void srslte_vec_convert_ci(int8_t *x, int16_t *z, uint32_t len); SRSLTE_API void srslte_vec_lut_fuf(float *x, uint32_t *lut, float *y, uint32_t len); SRSLTE_API void srslte_vec_lut_sss(short *x, unsigned short *lut, short *y, uint32_t len); @@ -136,6 +138,7 @@ SRSLTE_API cf_t srslte_vec_dot_prod_cfc(cf_t *x, float *y, uint32_t len); SRSLTE_API cf_t srslte_vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len); SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len); SRSLTE_API float srslte_vec_dot_prod_fff(float *x, float *y, uint32_t len); +SRSLTE_API int32_t srslte_vec_dot_prod_sss(int16_t *x, int16_t *y, uint32_t len); /* z=x/y vector division (element-wise) */ SRSLTE_API void srslte_vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, float *z_real, float *z_imag, uint32_t len); @@ -151,12 +154,14 @@ SRSLTE_API float srslte_vec_avg_power_cf(cf_t *x, uint32_t len); /* return the index of the maximum value in the vector */ SRSLTE_API uint32_t srslte_vec_max_fi(float *x, uint32_t len); SRSLTE_API uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len); +SRSLTE_API int16_t srslte_vec_max_star_si(int16_t *x, uint32_t len); /* maximum between two vectors */ SRSLTE_API void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len); -/* quantify vector of floats and convert to uint8_t */ +/* quantify vector of floats or int16 and convert to uint8_t */ SRSLTE_API void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len); +SRSLTE_API void srslte_vec_quant_suc(int16_t *in, uint8_t *out, int16_t norm, int16_t offset, int16_t clip, uint32_t len); /* magnitude of each vector element */ SRSLTE_API void srslte_vec_abs_cf(cf_t *x, float *abs, uint32_t len); diff --git a/srslte/include/srslte/utils/vector_simd.h b/srslte/include/srslte/utils/vector_simd.h index 361f98f5e..cd6eb4d28 100644 --- a/srslte/include/srslte/utils/vector_simd.h +++ b/srslte/include/srslte/utils/vector_simd.h @@ -35,7 +35,8 @@ extern "C" { #include #include "srslte/config.h" - +SRSLTE_API int srslte_vec_dot_prod_sss_simd(short *x, short *y, uint32_t len); + SRSLTE_API void srslte_vec_sum_sss_simd(short *x, short *y, short *z, uint32_t len); SRSLTE_API void srslte_vec_sub_sss_simd(short *x, short *y, short *z, uint32_t len); diff --git a/srslte/lib/fec/rm_conv.c b/srslte/lib/fec/rm_conv.c index 02294fcbc..f994c96fa 100644 --- a/srslte/lib/fec/rm_conv.c +++ b/srslte/lib/fec/rm_conv.c @@ -152,3 +152,70 @@ int srslte_rm_conv_rx(float *input, uint32_t in_len, float *output, uint32_t out return 0; } +/************* FIX THIS. MOVE ALL PROCESSING TO INT16 AND HAVE ONLY 1 IMPLEMENTATION ******/ + +/* Undoes Convolutional Code Rate Matching. + * 3GPP TS 36.212 v10.1.0 section 5.1.4.2 + */ +int srslte_rm_conv_rx_s(int16_t *input, uint32_t in_len, int16_t *output, uint32_t out_len) { + + int nrows, ndummy, K_p; + int i, j, k; + int d_i, d_j; + + int16_t tmp[3 * NCOLS * NROWS_MAX]; + + nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1; + if (nrows > NROWS_MAX) { + fprintf(stderr, "Output too large. Max output length is %d\n", + 3 * NCOLS * NROWS_MAX); + return -1; + } + K_p = nrows * NCOLS; + + ndummy = K_p - out_len / 3; + if (ndummy < 0) { + ndummy = 0; + } + + for (i = 0; i < 3 * K_p; i++) { + tmp[i] = SRSLTE_RX_NULL; + } + + /* Undo bit collection. Account for dummy bits */ + k = 0; + j = 0; + while (k < in_len) { + d_i = (j % K_p) / nrows; + d_j = (j % K_p) % nrows; + + if (d_j * NCOLS + RM_PERM_CC[d_i] >= ndummy) { + if (tmp[j] == SRSLTE_RX_NULL) { + tmp[j] = input[k]; + } else if (input[k] != SRSLTE_RX_NULL) { + tmp[j] += input[k]; /* soft combine LLRs */ + } + k++; + } + j++; + if (j == 3 * K_p) { + j = 0; + } + } + + /* interleaving and bit selection */ + for (i = 0; i < out_len / 3; i++) { + d_i = (i + ndummy) / NCOLS; + d_j = (i + ndummy) % NCOLS; + for (j = 0; j < 3; j++) { + int16_t o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows + d_i]; + if (o != SRSLTE_RX_NULL) { + output[i * 3 + j] = o; + } else { + output[i * 3 + j] = 0; + } + } + } + return 0; +} + diff --git a/srslte/lib/fec/viterbi.c b/srslte/lib/fec/viterbi.c index d9db9e935..08356e57a 100644 --- a/srslte/lib/fec/viterbi.c +++ b/srslte/lib/fec/viterbi.c @@ -133,6 +133,7 @@ int init37(srslte_viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_ q->R = 3; q->framebits = framebits; q->gain_quant = 32; + q->gain_quant_s = 4; q->tail_biting = tail_biting; q->decode = decode37; q->free = free37; @@ -169,6 +170,7 @@ int init37_sse(srslte_viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool t q->R = 3; q->framebits = framebits; q->gain_quant = 20; + q->gain_quant_s = 4; q->tail_biting = tail_biting; q->decode = decode37_sse; q->free = free37_sse; @@ -203,6 +205,10 @@ void srslte_viterbi_set_gain_quant(srslte_viterbi_t *q, float gain_quant) { q->gain_quant = gain_quant; } +void srslte_viterbi_set_gain_quant_s(srslte_viterbi_t *q, int16_t gain_quant) { + q->gain_quant_s = gain_quant; +} + int srslte_viterbi_init(srslte_viterbi_t *q, srslte_viterbi_type_t type, uint32_t poly[3], uint32_t max_frame_length, bool tail_bitting) { switch (type) { @@ -254,6 +260,24 @@ int srslte_viterbi_decode_f(srslte_viterbi_t *q, float *symbols, uint8_t *data, } } +/* symbols are int16 */ +int srslte_viterbi_decode_s(srslte_viterbi_t *q, int16_t *symbols, uint8_t *data, uint32_t frame_length) +{ + uint32_t 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 * frame_length; + } else { + len = 3 * (frame_length + q->K - 1); + } + srslte_vec_quant_suc(symbols, q->symbols_uc, q->gain_quant_s, 127, 255, len); + return srslte_viterbi_decode_uc(q, q->symbols_uc, data, frame_length); +} + int srslte_viterbi_decode_uc(srslte_viterbi_t *q, uint8_t *symbols, uint8_t *data, uint32_t frame_length) { diff --git a/srslte/lib/phch/pusch.c b/srslte/lib/phch/pusch.c index 448f99898..9bd5ce200 100644 --- a/srslte/lib/phch/pusch.c +++ b/srslte/lib/phch/pusch.c @@ -224,14 +224,14 @@ int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) { q->rnti_is_set = false; - // Allocate floats for reception (LLRs). Buffer casted to uint8_t for transmission - q->q = srslte_vec_malloc(sizeof(float) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); + // Allocate int16 for reception (LLRs). Buffer casted to uint8_t for transmission + q->q = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); if (!q->q) { goto clean; } - // Allocate floats for reception (LLRs). Buffer casted to uint8_t for transmission - q->g = srslte_vec_malloc(sizeof(float) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); + // Allocate int16 for reception (LLRs). Buffer casted to uint8_t for transmission + q->g = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); if (!q->g) { goto clean; } @@ -460,10 +460,6 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs return SRSLTE_ERROR; } - uint8_t tx_bits[10000]; - srslte_bit_unpack_vector(q->q, tx_bits, cfg->nbits.nof_bits); - srslte_vec_save_file("tx_bits", tx_bits, sizeof(uint8_t)*cfg->nbits.nof_bits); - if (rnti != q->rnti || !q->rnti_is_set) { srslte_sequence_t seq; if (srslte_sequence_pusch(&seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { @@ -475,7 +471,7 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs srslte_scrambling_bytes(&q->seq[cfg->sf_idx], (uint8_t*) q->q, cfg->nbits.nof_bits); } - // Correct UCI placeholder bits + // Correct UCI placeholder/repetition bits uint8_t *d = q->q; for (int i = 0; i < q->dl_sch.nof_ri_ack_bits; i++) { if (q->dl_sch.ack_ri_bits[i].type == UCI_BIT_PLACEHOLDER) { @@ -492,14 +488,10 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs } } } - srslte_bit_unpack_vector(q->q, tx_bits, cfg->nbits.nof_bits); - srslte_vec_save_file("tx_bits_scram", tx_bits, sizeof(uint8_t)*cfg->nbits.nof_bits); // Bit mapping srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->q, q->d, cfg->nbits.nof_bits); - srslte_vec_save_file("tx_symbols", q->d, sizeof(cf_t)*cfg->nbits.nof_re); - // DFT precoding srslte_dft_precoding(&q->dft_precoding, q->d, q->z, cfg->grant.L_prb, cfg->nbits.nof_symb); @@ -511,15 +503,26 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs return ret; } - -/** Decodes the PUSCH from the received symbols - */ int srslte_pusch_decode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, cf_t *sf_symbols, cf_t *ce, float noise_estimate, uint8_t *data) { + srslte_uci_data_t uci_data; + bzero(&uci_data, sizeof(srslte_uci_data_t)); + return srslte_pusch_uci_decode(q, cfg, softbuffer, sf_symbols, ce, noise_estimate, data, &uci_data); +} + + +/** Decodes the PUSCH from the received symbols + */ +int srslte_pusch_uci_decode(srslte_pusch_t *q, + srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols, + cf_t *ce, float noise_estimate, + uint8_t *data, srslte_uci_data_t *uci_data) +{ uint32_t n; @@ -554,19 +557,19 @@ int srslte_pusch_decode(srslte_pusch_t *q, // DFT predecoding srslte_dft_predecoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); - srslte_vec_save_file("rx_symbols", q->d, sizeof(cf_t)*cfg->nbits.nof_re); - // Soft demodulation srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->q, cfg->nbits.nof_re); - srslte_vec_save_file("rx_bits_scram", q->q, sizeof(int16_t)*cfg->nbits.nof_bits); + // Decode RI/HARQ bits before descrambling + if (srslte_ulsch_uci_decode_ri_ack(&q->dl_sch, cfg, softbuffer, q->q, q->seq[cfg->sf_idx].c, uci_data)) { + fprintf(stderr, "Error decoding RI/HARQ bits\n"); + return SRSLTE_ERROR; + } // Descrambling srslte_scrambling_s_offset(&q->seq[cfg->sf_idx], q->q, 0, cfg->nbits.nof_bits); - srslte_vec_save_file("rx_bits", q->q, sizeof(int16_t)*cfg->nbits.nof_bits); - - return srslte_ulsch_decode(&q->dl_sch, cfg, softbuffer, q->q, q->g, data); + return srslte_ulsch_uci_decode(&q->dl_sch, cfg, softbuffer, q->q, q->g, data, uci_data); } else { fprintf(stderr, "Must call srslte_pusch_set_rnti() before calling srslte_pusch_decode()\n"); return SRSLTE_ERROR; diff --git a/srslte/lib/phch/sch.c b/srslte/lib/phch/sch.c index 8e2518531..6d759783f 100644 --- a/srslte/lib/phch/sch.c +++ b/srslte/lib/phch/sch.c @@ -519,9 +519,6 @@ static void ulsch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, } } } - - printf("rows=%d, cols=%d, Qm=%d, total=%d, symb=%d\n", rows, cols, Qm, H_prime_total, N_pusch_symbs); - } /* UL-SCH channel interleaver according to 5.2.2.8 of 36.212 */ @@ -554,34 +551,130 @@ void ulsch_deinterleave(int16_t *q_bits, uint32_t Qm, uint32_t H_prime_total, uint32_t N_pusch_symbs, int16_t *g_bits, srslte_uci_bit_t *ri_bits, uint32_t nof_ri_bits, uint8_t *ri_present, uint16_t *inteleaver_lut) { + // Prepare ri_bits for fast search using temp_buffer + if (nof_ri_bits > 0) { + for (uint32_t i=0;i 0) { + for (uint32_t i=0;inbits.nof_bits; uint32_t Qm = cfg->grant.Qm; + + cfg->last_O_cqi = uci_data->uci_cqi_len; - // Interleave UL-SCH (and RI and CQI) + // Deinterleave and decode HARQ bits + if (uci_data->uci_ack_len > 0) { + float beta = beta_harq_offset[cfg->uci_cfg.I_offset_ack]; + if (cfg->cb_segm.tbs == 0) { + beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; + } + ret = srslte_uci_decode_ack(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ack); + if (ret < 0) { + return ret; + } + Q_prime_ack = (uint32_t) ret; + + // Set zeros to HARQ bits + for (uint32_t i=0;iack_ri_bits[i].position] = 0; + } + } + + // Deinterleave and decode RI bits + if (uci_data->uci_ri_len > 0) { + float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri]; + if (cfg->cb_segm.tbs == 0) { + beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; + } + ret = srslte_uci_decode_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri); + if (ret < 0) { + return ret; + } + Q_prime_ri = (uint32_t) ret; + } + + q->nof_ri_ack_bits = Q_prime_ri; + + return SRSLTE_SUCCESS; +} + +int srslte_ulsch_uci_decode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, + int16_t *q_bits, int16_t *g_bits, uint8_t *data, srslte_uci_data_t *uci_data) +{ + int ret = 0; + + uint32_t Q_prime_ri = q->nof_ri_ack_bits; + uint32_t Q_prime_cqi = 0; + uint32_t e_offset = 0; + + uint32_t nb_q = cfg->nbits.nof_bits; + uint32_t Qm = cfg->grant.Qm; + + // Deinterleave data and CQI in ULSCH ulsch_deinterleave(q_bits, Qm, nb_q/Qm, cfg->nbits.nof_symb, g_bits, q->ack_ri_bits, Q_prime_ri*Qm, q->temp_g_bits, q->ul_interleaver); - - printf("g_bits=["); - for (int i=0;i0); + + // Decode CQI (multiplexed at the front of ULSCH) + if (uci_data->uci_cqi_len > 0) { + struct timeval t[3]; + gettimeofday(&t[1], NULL); + ret = srslte_uci_decode_cqi_pusch(&q->uci_cqi, cfg, g_bits, + beta_cqi_offset[cfg->uci_cfg.I_offset_cqi], + Q_prime_ri, uci_data->uci_cqi_len, + uci_data->uci_cqi, &uci_data->cqi_ack); + gettimeofday(&t[2], NULL); + get_time_interval(t); + printf("texec=%d us\n", t[0].tv_usec); + + if (ret < 0) { + return ret; + } + Q_prime_cqi = (uint32_t) ret; } - printf("];\n"); - return decode_tb(q, softbuffer, &cfg->cb_segm, - cfg->grant.Qm, cfg->rv, cfg->nbits.nof_bits, - g_bits, data); + e_offset += Q_prime_cqi*Qm; + + // Decode ULSCH + if (cfg->cb_segm.tbs > 0) { + uint32_t G = nb_q/Qm - Q_prime_ri - Q_prime_cqi; + ret = decode_tb(q, softbuffer, &cfg->cb_segm, + Qm, cfg->rv, G*Qm, + &g_bits[e_offset], data); + if (ret) { + return ret; + } + } + return SRSLTE_SUCCESS; } int srslte_ulsch_encode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, @@ -619,8 +712,9 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q, } Q_prime_ri = (uint32_t) ret; } - cfg->last_O_cqi = uci_data.uci_cqi_len; + // Encode CQI + cfg->last_O_cqi = uci_data.uci_cqi_len; if (uci_data.uci_cqi_len > 0) { ret = srslte_uci_encode_cqi_pusch(&q->uci_cqi, cfg, uci_data.uci_cqi, uci_data.uci_cqi_len, @@ -648,17 +742,11 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q, } } - uint8_t kk[10000]; - srslte_bit_unpack_vector(g_bits, kk, nb_q); - srslte_vec_save_file("g_bits_tx", kk, nb_q); - printf("g_bits_tx="); - srslte_vec_fprint_b(stdout, kk, nb_q); - // Interleave UL-SCH (and RI and CQI) ulsch_interleave(g_bits, Qm, nb_q/Qm, cfg->nbits.nof_symb, q_bits, q->ack_ri_bits, Q_prime_ri*Qm, q->temp_g_bits, q->ul_interleaver); - // Encode (and interleave) ACK + // Encode (and interleave) ACK if (uci_data.uci_ack_len > 0) { float beta = beta_harq_offset[cfg->uci_cfg.I_offset_ack]; if (cfg->cb_segm.tbs == 0) { diff --git a/srslte/lib/phch/test/pusch_test.c b/srslte/lib/phch/test/pusch_test.c index abdfd28e2..0cdf6e64c 100644 --- a/srslte/lib/phch/test/pusch_test.c +++ b/srslte/lib/phch/test/pusch_test.c @@ -155,7 +155,7 @@ int main(int argc, char **argv) { printf("Encoding rv_idx=%d\n",rv_idx); srslte_uci_cfg_t uci_cfg; - uci_cfg.I_offset_cqi = 7; + uci_cfg.I_offset_cqi = 6; uci_cfg.I_offset_ri = 2; uci_cfg.I_offset_ack = 4; @@ -166,19 +166,19 @@ int main(int argc, char **argv) { srslte_pusch_set_rnti(&pusch, 1234); - srslte_uci_data_t uci_data; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - uci_data.uci_cqi_len = 0; - uci_data.uci_ri_len = 0; - uci_data.uci_ack_len = 0; - + srslte_uci_data_t uci_data_tx; + srslte_uci_data_t uci_data_rx; + bzero(&uci_data_tx, sizeof(srslte_uci_data_t)); + uci_data_tx.uci_cqi_len = 9; + uci_data_tx.uci_ri_len = 0; + uci_data_tx.uci_ack_len = 0; + memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t)); + for (uint32_t i=0;i<20;i++) { - uci_data.uci_cqi [i] = 1; + uci_data_tx.uci_cqi [i] = 1; } - uci_data.uci_ri = 0; - uci_data.uci_ack = 0; - - + uci_data_tx.uci_ri = 1; + uci_data_tx.uci_ack = 1; uint32_t nof_re = SRSLTE_NRE*cell.nof_prb*2*SRSLTE_CP_NSYMB(cell.cp); sf_symbols = srslte_vec_malloc(sizeof(cf_t) * nof_re); @@ -208,13 +208,13 @@ int main(int argc, char **argv) { uint32_t ntrials = 100; - if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data, sf_symbols)) { + if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, sf_symbols)) { fprintf(stderr, "Error encoding TB\n"); exit(-1); } if (rv_idx > 0) { cfg.rv = rv_idx; - if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data, sf_symbols)) { + if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, sf_symbols)) { fprintf(stderr, "Error encoding TB\n"); exit(-1); } @@ -230,22 +230,37 @@ int main(int argc, char **argv) { } gettimeofday(&t[1], NULL); - int r = srslte_pusch_decode(&pusch, &cfg, &softbuffer_rx, sf_symbols, ce, 0, data); + int r = srslte_pusch_uci_decode(&pusch, &cfg, &softbuffer_rx, sf_symbols, ce, 0, data, &uci_data_rx); gettimeofday(&t[2], NULL); get_time_interval(t); if (r) { printf("Error decoding\n"); ret = -1; - goto quit; } else { + ret = 0; printf("DECODED OK in %d:%d (TBS: %d bits, TX: %.2f Mbps, Processing: %.2f Mbps)\n", (int) t[0].tv_sec, (int) t[0].tv_usec/ntrials, cfg.grant.mcs.tbs, (float) cfg.grant.mcs.tbs/1000, - (float) cfg.grant.mcs.tbs/t[0].tv_usec*ntrials); + (float) cfg.grant.mcs.tbs/t[0].tv_usec*ntrials); } - - ret = 0; + if (uci_data_tx.uci_ack_len) { + if (uci_data_tx.uci_ack != uci_data_rx.uci_ack) { + printf("UCI ACK bit error: %d != %d\n", uci_data_tx.uci_ack, uci_data_rx.uci_ack); + } + } + if (uci_data_tx.uci_ri_len) { + if (uci_data_tx.uci_ri != uci_data_rx.uci_ri) { + printf("UCI RI bit error: %d != %d\n", uci_data_tx.uci_ri, uci_data_rx.uci_ri); + } + } + if (uci_data_tx.uci_cqi_len) { + printf("cqi_tx="); + srslte_vec_fprint_b(stdout, uci_data_tx.uci_cqi, uci_data_tx.uci_cqi_len); + printf("cqi_rx="); + srslte_vec_fprint_b(stdout, uci_data_rx.uci_cqi, uci_data_rx.uci_cqi_len); + } + quit: srslte_pusch_free(&pusch); srslte_softbuffer_tx_free(&softbuffer_tx); diff --git a/srslte/lib/phch/uci.c b/srslte/lib/phch/uci.c index ef8dc0968..28351414b 100644 --- a/srslte/lib/phch/uci.c +++ b/srslte/lib/phch/uci.c @@ -40,8 +40,10 @@ #include "srslte/fec/rm_conv.h" #include "srslte/common/phy_common.h" #include "srslte/utils/vector.h" +#include "srslte/utils/bit.h" #include "srslte/utils/debug.h" + /* Table 5.2.2.6.4-1: Basis sequence for (32, O) code */ static uint8_t M_basis_seq[32][11]={ {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, @@ -101,16 +103,65 @@ static uint8_t M_basis_seq_pucch[20][13]={ {1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, }; - + + +void encode_cqi_pusch_block(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t output[32]) { + for (int i=0;i<32;i++) { + output[i] = 0; + for (int n=0;ncqi_table[i] = srslte_vec_malloc(sizeof(uint8_t)*nwords*32); + q->cqi_table_s[i] = srslte_vec_malloc(sizeof(int16_t)*nwords*32); + for (uint32_t w=0;wcqi_table[i][32*w]); + for (int j=0;j<32;j++) { + q->cqi_table_s[i][32*w+j] = 2*q->cqi_table[i][32*w+j]-1; + } + } + } +} + +void cqi_pusch_pregen_free(srslte_uci_cqi_pusch_t *q) { + for (int i=0;i<11;i++) { + if (q->cqi_table[i]) { + free(q->cqi_table[i]); + } + if (q->cqi_table_s[i]) { + free(q->cqi_table_s[i]); + } + } +} + int srslte_uci_cqi_init(srslte_uci_cqi_pusch_t *q) { if (srslte_crc_init(&q->crc, SRSLTE_LTE_CRC8, 8)) { return SRSLTE_ERROR; } + uint32_t poly[3] = { 0x6D, 0x4F, 0x57 }; + if (srslte_viterbi_init(&q->viterbi, SRSLTE_VITERBI_37, poly, SRSLTE_UCI_MAX_CQI_LEN_PUSCH, true)) { + return SRSLTE_ERROR; + } + + cqi_pusch_pregen(q); + return SRSLTE_SUCCESS; } -void srslte_uci_cqi_free(srslte_uci_cqi_pusch_t *q) { +void srslte_uci_cqi_free(srslte_uci_cqi_pusch_t *q) +{ + srslte_viterbi_free(&q->viterbi); + cqi_pusch_pregen_free(q); } static uint32_t Q_prime_cqi(srslte_pusch_cfg_t *cfg, @@ -136,20 +187,17 @@ static uint32_t Q_prime_cqi(srslte_pusch_cfg_t *cfg, */ int encode_cqi_short(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t *q_bits, uint32_t Q) { - if (nof_bits < SRSLTE_UCI_MAX_CQI_LEN_PUSCH && - q != NULL && - data != NULL && + if (nof_bits <= 11 && + nof_bits > 0 && + q != NULL && + data != NULL && q_bits != NULL) { - for (int i=0;i<32;i++) { - q->encoded_cqi[i] = 0; - for (int n=0;nencoded_cqi[i] += (data[n] * M_basis_seq[i][n]); - } - } + uint8_t *ptr = data; + uint32_t w = srslte_bit_pack(&ptr, nof_bits); for (int i=0;iencoded_cqi[i%32]%2; + q_bits[i] = q->cqi_table[nof_bits-1][w*32+(i%32)]; } return SRSLTE_SUCCESS; } else { @@ -157,6 +205,46 @@ int encode_cqi_short(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits } } +// For decoding the block-encoded CQI we use ML decoding +int decode_cqi_short(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, uint8_t *data, uint32_t nof_bits) +{ + if (nof_bits <= 11 && + nof_bits > 0 && + q != NULL && + data != NULL && + q_bits != NULL) + { + // Accumulate all copies of the 32-length sequence + if (Q>32) { + int i=1; + for (;icqi_table_s[nof_bits-1][w*32], q_bits, 32); + if (corr > max_corr) { + max_corr = corr; + max_w = w; + } + } + // Convert word to bits again + uint8_t *ptr = data; + srslte_bit_unpack(max_w, &ptr, nof_bits); + + INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr); + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + /* Encode UCI CQI/PMI for payloads greater than 11 bits (go through CRC, conv coder and rate match) */ int encode_cqi_long(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t *q_bits, uint32_t Q) @@ -167,9 +255,7 @@ int encode_cqi_long(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, q != NULL && data != NULL && q_bits != NULL) - { - - + { int poly[3] = { 0x6D, 0x4F, 0x57 }; encoder.K = 7; encoder.R = 3; @@ -179,10 +265,14 @@ int encode_cqi_long(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, memcpy(q->tmp_cqi, data, sizeof(uint8_t) * nof_bits); srslte_crc_attach(&q->crc, q->tmp_cqi, nof_bits); + DEBUG("cqi_crc_tx=", 0); + if (SRSLTE_VERBOSE_ISDEBUG()) { + srslte_vec_fprint_b(stdout, q->tmp_cqi, nof_bits+8); + } + srslte_convcoder_encode(&encoder, q->tmp_cqi, q->encoded_cqi, nof_bits + 8); - DEBUG("CConv output: ", 0); - + DEBUG("cconv_tx=", 0); if (SRSLTE_VERBOSE_ISDEBUG()) { srslte_vec_fprint_b(stdout, q->encoded_cqi, 3 * (nof_bits + 8)); } @@ -195,6 +285,45 @@ int encode_cqi_long(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, } } +int decode_cqi_long(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, + uint8_t *data, uint32_t nof_bits) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (nof_bits + 8 < SRSLTE_UCI_MAX_CQI_LEN_PUSCH && + q != NULL && + data != NULL && + q_bits != NULL) + { + + srslte_rm_conv_rx_s(q_bits, Q, q->encoded_cqi_s, 3 * (nof_bits + 8)); + + // Set viterbi normalization based on amplitude + int16_t max = srslte_vec_max_star_si(q->encoded_cqi_s, 3 * (nof_bits + 8)); + srslte_viterbi_set_gain_quant_s(&q->viterbi, max/36); + + DEBUG("cconv_rx=", 0); + if (SRSLTE_VERBOSE_ISDEBUG()) { + srslte_vec_fprint_s(stdout, q->encoded_cqi_s, 3 * (nof_bits + 8)); + } + + srslte_viterbi_decode_s(&q->viterbi, q->encoded_cqi_s, q->tmp_cqi, nof_bits + 8); + + DEBUG("cqi_crc_rx=", 0); + if (SRSLTE_VERBOSE_ISDEBUG()) { + srslte_vec_fprint_b(stdout, q->tmp_cqi, nof_bits+8); + } + + ret = srslte_crc_checksum(&q->crc, q->tmp_cqi, nof_bits + 8); + if (ret == 0) { + memcpy(data, q->tmp_cqi, nof_bits*sizeof(uint8_t)); + ret = 1; + } else { + ret = 0; + } + } + return ret; +} + /* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212 */ int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]) @@ -213,6 +342,44 @@ int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_b } } +/* Encode UCI CQI/PMI + */ +int srslte_uci_decode_cqi_pusch(srslte_uci_cqi_pusch_t *q, srslte_pusch_cfg_t *cfg, + int16_t *q_bits, + float beta, uint32_t Q_prime_ri, uint32_t cqi_len, + uint8_t *cqi_data, bool *cqi_ack) +{ + if (beta < 0) { + fprintf(stderr, "Error beta is reserved\n"); + return -1; + } + uint32_t Q_prime = Q_prime_cqi(cfg, cqi_len, beta, Q_prime_ri); + + int ret = SRSLTE_ERROR; + if (cqi_len <= 11) { + ret = decode_cqi_short(q, q_bits, Q_prime*cfg->grant.Qm, cqi_data, cqi_len); + } else { + ret = decode_cqi_long(q, q_bits, Q_prime*cfg->grant.Qm, cqi_data, cqi_len); + if (ret == 1) { + if (cqi_ack) { + *cqi_ack = true; + } + ret = 0; + } else if (ret == 0) { + if (cqi_ack) { + *cqi_ack = false; + } + } + } + if (ret) { + return ret; + } else { + return (int) Q_prime; + } + + return Q_prime; +} + /* Encode UCI CQI/PMI as described in 5.2.2.6 of 36.212 */ int srslte_uci_encode_cqi_pusch(srslte_uci_cqi_pusch_t *q, srslte_pusch_cfg_t *cfg, @@ -240,22 +407,28 @@ int srslte_uci_encode_cqi_pusch(srslte_uci_cqi_pusch_t *q, srslte_pusch_cfg_t *c } } +static void uci_ulsch_interleave_put(srslte_uci_bit_type_t ack_coded_bits[6], uint32_t Qm, srslte_uci_bit_t *ack_bits) +{ + for(uint32_t k=0; k= 1+ack_q_bit_idx/4) { uint32_t row = H_prime_total/N_pusch_symbs-1-ack_q_bit_idx/4; uint32_t colidx = (3*ack_q_bit_idx)%4; uint32_t col = SRSLTE_CP_ISNORM(cp)?ack_column_set_norm[colidx]:ack_column_set_ext[colidx]; for(uint32_t k=0; kgrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); + rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, ack_bits); + } + + if (data) { + *data = rx_ack>0; + } + return (int) Qprime; +} /* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit HARQ @@ -331,7 +545,7 @@ static void encode_ri_ack(uint8_t data, srslte_uci_bit_type_t q_encoded_bits[6], int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t data, uint32_t O_cqi, float beta, uint32_t H_prime_total, srslte_uci_bit_t *ack_bits) -{ +{ if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); return -1; @@ -343,12 +557,42 @@ int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t data, encode_ri_ack(data, q_encoded_bits, cfg->grant.Qm); for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); + uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); + uci_ulsch_interleave_put(q_encoded_bits, cfg->grant.Qm, &ack_bits[cfg->grant.Qm*i]); } return (int) Qprime; } +/* Encode UCI RI bits as described in 5.2.2.6 of 36.212 + * Currently only supporting 1-bit RI + */ +int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, + float beta, uint32_t H_prime_total, + uint32_t O_cqi, srslte_uci_bit_t *ri_bits, uint8_t *data) +{ + int32_t rx_ri = 0; + + if (beta < 0) { + fprintf(stderr, "Error beta is reserved\n"); + return -1; + } + + uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); + + // Use the same interleaver function to get the HARQ bit position + for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); + rx_ri += (int32_t) decode_ri_ack(q_bits, c_seq, ri_bits); + } + + if (data) { + *data = rx_ri>0; + } + + return (int) Qprime; +} + /* Encode UCI RI bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit RI @@ -368,7 +612,8 @@ int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, encode_ri_ack(data, q_encoded_bits, cfg->grant.Qm); for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); + uci_ulsch_interleave_ri_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); + uci_ulsch_interleave_put(q_encoded_bits, cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]); } return (int) Qprime; diff --git a/srslte/lib/utils/vector.c b/srslte/lib/utils/vector.c index 26f4f073b..a9b4bb284 100644 --- a/srslte/lib/utils/vector.c +++ b/srslte/lib/utils/vector.c @@ -171,6 +171,13 @@ void srslte_vec_sc_add_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len) { } } +void srslte_vec_sc_add_sss(int16_t *x, int16_t h, int16_t *z, uint32_t len) { + int i; + for (i=0;im) { + m=x[i]; + } + } + return m; +#endif +} + void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len) { #ifdef HAVE_VOLK_MAX_VEC_FUNCTION volk_32f_x2_max_32f(z,x,y,len); @@ -715,3 +764,17 @@ void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, flo } } +void srslte_vec_quant_suc(int16_t *in, uint8_t *out, int16_t norm, int16_t offset, int16_t clip, uint32_t len) { + int i; + int16_t tmp; + + for (i=0;i clip) + tmp = clip; + out[i] = (uint8_t) tmp; + } +} + diff --git a/srslte/lib/utils/vector_simd.c b/srslte/lib/utils/vector_simd.c index ffe59db9f..1612f2c07 100644 --- a/srslte/lib/utils/vector_simd.c +++ b/srslte/lib/utils/vector_simd.c @@ -41,6 +41,48 @@ #endif + +int srslte_vec_dot_prod_sss_simd(short *x, short *y, uint32_t len) +{ + int result = 0; +#ifdef LV_HAVE_SSE + unsigned int number = 0; + const unsigned int points = len / 8; + + const __m128i* xPtr = (const __m128i*) x; + const __m128i* yPtr = (const __m128i*) y; + + __m128i dotProdVal = _mm_setzero_si128(); + + __m128i xVal, yVal, zVal; + for(;number < points; number++){ + + xVal = _mm_load_si128(xPtr); + yVal = _mm_load_si128(yPtr); + + zVal = _mm_mullo_epi16(xVal, yVal); + + dotProdVal = _mm_add_epi16(dotProdVal, zVal); + + xPtr ++; + yPtr ++; + } + + short dotProdVector[8]; + _mm_store_si128((__m128i*) dotProdVector, dotProdVal); + for (int i=0;i<8;i++) { + result += dotProdVector[i]; + } + + number = points * 8; + for(;number < len; number++){ + result += (x[number] * y[number]); + } + +#endif + return result; +} + void srslte_vec_sum_sss_simd(short *x, short *y, short *z, uint32_t len) { #ifdef LV_HAVE_SSE