|
|
|
@ -49,13 +49,7 @@ int srslte_pucch_init_(srslte_pucch_t* q, bool is_ue)
|
|
|
|
|
|
|
|
|
|
q->is_ue = is_ue;
|
|
|
|
|
|
|
|
|
|
q->users = calloc(sizeof(srslte_pucch_user_t*), q->is_ue ? 1 : (1 + SRSLTE_SIRNTI));
|
|
|
|
|
if (!q->users) {
|
|
|
|
|
perror("malloc");
|
|
|
|
|
goto clean_exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (srslte_sequence_init(&q->tmp_seq, 20)) {
|
|
|
|
|
if (srslte_sequence_init(&q->seq_f2, 20)) {
|
|
|
|
|
goto clean_exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -89,18 +83,7 @@ int srslte_pucch_init_enb(srslte_pucch_t* q)
|
|
|
|
|
|
|
|
|
|
void srslte_pucch_free(srslte_pucch_t* q)
|
|
|
|
|
{
|
|
|
|
|
if (q->users) {
|
|
|
|
|
if (q->is_ue) {
|
|
|
|
|
srslte_pucch_free_rnti(q, 0);
|
|
|
|
|
} else {
|
|
|
|
|
for (int rnti = 0; rnti <= SRSLTE_SIRNTI; rnti++) {
|
|
|
|
|
srslte_pucch_free_rnti(q, rnti);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(q->users);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
srslte_sequence_free(&q->tmp_seq);
|
|
|
|
|
srslte_sequence_free(&q->seq_f2);
|
|
|
|
|
|
|
|
|
|
srslte_uci_cqi_pucch_free(&q->cqi);
|
|
|
|
|
if (q->z) {
|
|
|
|
@ -139,58 +122,6 @@ int srslte_pucch_set_cell(srslte_pucch_t* q, srslte_cell_t cell)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void srslte_pucch_free_rnti(srslte_pucch_t* q, uint16_t rnti)
|
|
|
|
|
{
|
|
|
|
|
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
|
|
|
|
|
|
|
|
|
|
if (q->users[rnti_idx]) {
|
|
|
|
|
for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) {
|
|
|
|
|
srslte_sequence_free(&q->users[rnti_idx]->seq_f2[i]);
|
|
|
|
|
}
|
|
|
|
|
free(q->users[rnti_idx]);
|
|
|
|
|
q->users[rnti_idx] = NULL;
|
|
|
|
|
q->ue_rnti = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int srslte_pucch_set_rnti(srslte_pucch_t* q, uint16_t rnti)
|
|
|
|
|
{
|
|
|
|
|
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
|
|
|
|
|
|
|
|
|
|
// Decide whether re-generating the sequence
|
|
|
|
|
if (!q->users[rnti_idx]) {
|
|
|
|
|
// If the sequence is not allocated generate
|
|
|
|
|
q->users[rnti_idx] = calloc(1, sizeof(srslte_pdsch_user_t));
|
|
|
|
|
if (!q->users[rnti_idx]) {
|
|
|
|
|
ERROR("Alocating PDSCH user");
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
} else if (q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && !q->is_ue) {
|
|
|
|
|
// The sequence was generated, cell has not changed and it is eNb, save any efforts
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set sequence as not generated
|
|
|
|
|
q->users[rnti_idx]->sequence_generated = false;
|
|
|
|
|
|
|
|
|
|
// For each subframe
|
|
|
|
|
for (int sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) {
|
|
|
|
|
if (srslte_sequence_pucch(
|
|
|
|
|
&q->users[rnti_idx]->seq_f2[sf_idx], rnti, SRSLTE_NOF_SLOTS_PER_SF * sf_idx, q->cell.id)) {
|
|
|
|
|
ERROR("Error initializing PUCCH scrambling sequence");
|
|
|
|
|
srslte_pucch_free_rnti(q, rnti);
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save generation states
|
|
|
|
|
q->ue_rnti = rnti;
|
|
|
|
|
q->users[rnti_idx]->cell_id = q->cell.id;
|
|
|
|
|
q->users[rnti_idx]->sequence_generated = true;
|
|
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static cf_t uci_encode_format1()
|
|
|
|
|
{
|
|
|
|
|
return 1.0;
|
|
|
|
@ -218,34 +149,11 @@ static cf_t uci_encode_format1b(uint8_t bits[2])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static srslte_sequence_t* get_user_sequence(srslte_pucch_t* q, uint16_t rnti, uint32_t sf_idx)
|
|
|
|
|
{
|
|
|
|
|
uint32_t rnti_idx = q->is_ue ? 0 : rnti;
|
|
|
|
|
|
|
|
|
|
// The scrambling sequence is pregenerated for all RNTIs in the eNodeB but only for C-RNTI in the UE
|
|
|
|
|
if (rnti >= SRSLTE_CRNTI_START && rnti < SRSLTE_CRNTI_END) {
|
|
|
|
|
if (q->users[rnti_idx] && q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id &&
|
|
|
|
|
(!q->is_ue || q->ue_rnti == rnti)) {
|
|
|
|
|
return &q->users[rnti_idx]->seq_f2[sf_idx];
|
|
|
|
|
} else {
|
|
|
|
|
if (srslte_sequence_pucch(&q->tmp_seq, rnti, 2 * sf_idx, q->cell.id)) {
|
|
|
|
|
ERROR("Error computing PUCCH Format 2 scrambling sequence");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return &q->tmp_seq;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ERROR("Invalid RNTI=0x%x", rnti);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Encode PUCCH bits according to Table 5.4.1-1 in Section 5.4.1 of 36.211 */
|
|
|
|
|
static int
|
|
|
|
|
uci_mod_bits(srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, uint8_t bits[SRSLTE_PUCCH_MAX_BITS])
|
|
|
|
|
{
|
|
|
|
|
uint8_t tmp[2];
|
|
|
|
|
srslte_sequence_t* seq;
|
|
|
|
|
uint8_t tmp[2];
|
|
|
|
|
switch (cfg->format) {
|
|
|
|
|
case SRSLTE_PUCCH_FORMAT_1:
|
|
|
|
|
q->d[0] = uci_encode_format1();
|
|
|
|
@ -261,26 +169,22 @@ uci_mod_bits(srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg,
|
|
|
|
|
case SRSLTE_PUCCH_FORMAT_2:
|
|
|
|
|
case SRSLTE_PUCCH_FORMAT_2A:
|
|
|
|
|
case SRSLTE_PUCCH_FORMAT_2B:
|
|
|
|
|
seq = get_user_sequence(q, cfg->rnti, sf->tti % 10);
|
|
|
|
|
if (seq) {
|
|
|
|
|
memcpy(q->bits_scram, bits, SRSLTE_PUCCH2_NOF_BITS * sizeof(uint8_t));
|
|
|
|
|
srslte_scrambling_b_offset(seq, q->bits_scram, 0, SRSLTE_PUCCH2_NOF_BITS);
|
|
|
|
|
srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH2_NOF_BITS);
|
|
|
|
|
} else {
|
|
|
|
|
ERROR("Error modulating PUCCH2 bits: could not generate sequence");
|
|
|
|
|
return -1;
|
|
|
|
|
if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) {
|
|
|
|
|
ERROR("Error computing PUCCH Format 2 scrambling sequence\n");
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
srslte_vec_u8_copy(q->bits_scram, bits, SRSLTE_PUCCH2_NOF_BITS);
|
|
|
|
|
srslte_scrambling_b_offset(&q->seq_f2, q->bits_scram, 0, SRSLTE_PUCCH2_NOF_BITS);
|
|
|
|
|
srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH2_NOF_BITS);
|
|
|
|
|
break;
|
|
|
|
|
case SRSLTE_PUCCH_FORMAT_3:
|
|
|
|
|
seq = get_user_sequence(q, cfg->rnti, sf->tti % 10);
|
|
|
|
|
if (seq) {
|
|
|
|
|
memcpy(q->bits_scram, bits, SRSLTE_PUCCH3_NOF_BITS * sizeof(uint8_t));
|
|
|
|
|
srslte_scrambling_b_offset(seq, q->bits_scram, 0, SRSLTE_PUCCH3_NOF_BITS);
|
|
|
|
|
srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH3_NOF_BITS);
|
|
|
|
|
} else {
|
|
|
|
|
ERROR("Error modulating PUCCH3 bits: rnti not set");
|
|
|
|
|
if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) {
|
|
|
|
|
ERROR("Error computing PUCCH Format 2 scrambling sequence\n");
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
srslte_vec_u8_copy(q->bits_scram, bits, SRSLTE_PUCCH3_NOF_BITS);
|
|
|
|
|
srslte_scrambling_b_offset(&q->seq_f2, q->bits_scram, 0, SRSLTE_PUCCH3_NOF_BITS);
|
|
|
|
|
srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH3_NOF_BITS);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ERROR("PUCCH format %s not supported", srslte_pucch_format_text(cfg->format));
|
|
|
|
@ -632,19 +536,15 @@ static int decode_signal_format3(srslte_pucch_t* q,
|
|
|
|
|
|
|
|
|
|
srslte_vec_sc_prod_cfc(q->d, 2.0f / (N_sf_0 + N_sf_1), q->d, SRSLTE_NRE * 2);
|
|
|
|
|
|
|
|
|
|
srslte_sequence_t* seq = get_user_sequence(q, cfg->rnti, sf->tti % 10);
|
|
|
|
|
if (seq) {
|
|
|
|
|
srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->d, q->llr, SRSLTE_PUCCH3_NOF_BITS);
|
|
|
|
|
|
|
|
|
|
srslte_scrambling_s_offset(seq, q->llr, 0, SRSLTE_PUCCH3_NOF_BITS);
|
|
|
|
|
srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->d, q->llr, SRSLTE_PUCCH3_NOF_BITS);
|
|
|
|
|
|
|
|
|
|
return (int)srslte_block_decode_i16(q->llr, SRSLTE_PUCCH3_NOF_BITS, bits, SRSLTE_UCI_MAX_ACK_SR_BITS);
|
|
|
|
|
} else {
|
|
|
|
|
ERROR("Error modulating PUCCH3 bits: rnti not set");
|
|
|
|
|
if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) {
|
|
|
|
|
ERROR("Error computing PUCCH Format 2 scrambling sequence\n");
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
srslte_scrambling_s_offset(&q->seq_f2, q->llr, 0, SRSLTE_PUCCH3_NOF_BITS);
|
|
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
return (int)srslte_block_decode_i16(q->llr, SRSLTE_PUCCH3_NOF_BITS, bits, SRSLTE_UCI_MAX_ACK_SR_BITS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int encode_signal(srslte_pucch_t* q,
|
|
|
|
@ -716,8 +616,7 @@ static bool decode_signal(srslte_pucch_t* q,
|
|
|
|
|
float corr = 0, corr_max = -1e9;
|
|
|
|
|
uint8_t b_max = 0, b2_max = 0; // default bit value, eg. HI is NACK
|
|
|
|
|
|
|
|
|
|
srslte_sequence_t* seq;
|
|
|
|
|
cf_t ref[SRSLTE_PUCCH_MAX_SYMBOLS];
|
|
|
|
|
cf_t ref[SRSLTE_PUCCH_MAX_SYMBOLS];
|
|
|
|
|
|
|
|
|
|
switch (cfg->format) {
|
|
|
|
|
case SRSLTE_PUCCH_FORMAT_1:
|
|
|
|
@ -772,30 +671,28 @@ static bool decode_signal(srslte_pucch_t* q,
|
|
|
|
|
case SRSLTE_PUCCH_FORMAT_2:
|
|
|
|
|
case SRSLTE_PUCCH_FORMAT_2A:
|
|
|
|
|
case SRSLTE_PUCCH_FORMAT_2B:
|
|
|
|
|
seq = get_user_sequence(q, cfg->rnti, sf->tti % SRSLTE_NOF_SF_X_FRAME);
|
|
|
|
|
if (seq) {
|
|
|
|
|
encode_signal_format12(q, sf, cfg, NULL, ref, true);
|
|
|
|
|
srslte_vec_prod_conj_ccc(q->z, ref, q->z_tmp, SRSLTE_PUCCH_MAX_SYMBOLS);
|
|
|
|
|
for (int i = 0; i < (SRSLTE_PUCCH2_N_SF * SRSLTE_NOF_SLOTS_PER_SF); i++) {
|
|
|
|
|
q->z[i] = srslte_vec_acc_cc(&q->z_tmp[i * SRSLTE_NRE], SRSLTE_NRE) / SRSLTE_NRE;
|
|
|
|
|
}
|
|
|
|
|
srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS / 2);
|
|
|
|
|
srslte_scrambling_s_offset(seq, llr_pucch2, 0, SRSLTE_PUCCH2_NOF_BITS);
|
|
|
|
|
if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) {
|
|
|
|
|
ERROR("Error computing PUCCH Format 2 scrambling sequence\n");
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
encode_signal_format12(q, sf, cfg, NULL, ref, true);
|
|
|
|
|
srslte_vec_prod_conj_ccc(q->z, ref, q->z_tmp, SRSLTE_PUCCH_MAX_SYMBOLS);
|
|
|
|
|
for (int i = 0; i < (SRSLTE_PUCCH2_N_SF * SRSLTE_NOF_SLOTS_PER_SF); i++) {
|
|
|
|
|
q->z[i] = srslte_vec_acc_cc(&q->z_tmp[i * SRSLTE_NRE], SRSLTE_NRE) / SRSLTE_NRE;
|
|
|
|
|
}
|
|
|
|
|
srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS / 2);
|
|
|
|
|
srslte_scrambling_s_offset(&q->seq_f2, llr_pucch2, 0, SRSLTE_PUCCH2_NOF_BITS);
|
|
|
|
|
|
|
|
|
|
// Calculate the LLR RMS for normalising
|
|
|
|
|
float llr_pow = srslte_vec_avg_power_sf(llr_pucch2, SRSLTE_PUCCH2_NOF_BITS);
|
|
|
|
|
// Calculate the LLR RMS for normalising
|
|
|
|
|
float llr_pow = srslte_vec_avg_power_sf(llr_pucch2, SRSLTE_PUCCH2_NOF_BITS);
|
|
|
|
|
|
|
|
|
|
if (isnormal(llr_pow)) {
|
|
|
|
|
float llr_rms = sqrtf(llr_pow) * SRSLTE_PUCCH2_NOF_BITS;
|
|
|
|
|
corr = ((float)srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, pucch_bits, nof_uci_bits)) / (llr_rms);
|
|
|
|
|
} else {
|
|
|
|
|
corr = 0;
|
|
|
|
|
}
|
|
|
|
|
detected = true;
|
|
|
|
|
if (isnormal(llr_pow)) {
|
|
|
|
|
float llr_rms = sqrtf(llr_pow) * SRSLTE_PUCCH2_NOF_BITS;
|
|
|
|
|
corr = ((float)srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, pucch_bits, nof_uci_bits)) / (llr_rms);
|
|
|
|
|
} else {
|
|
|
|
|
ERROR("Decoding PUCCH2: could not generate sequence");
|
|
|
|
|
return -1;
|
|
|
|
|
corr = 0;
|
|
|
|
|
}
|
|
|
|
|
detected = true;
|
|
|
|
|
break;
|
|
|
|
|
case SRSLTE_PUCCH_FORMAT_3:
|
|
|
|
|
corr = (float)decode_signal_format3(q, sf, cfg, pucch_bits, q->z) / 4800.0f;
|
|
|
|
|