Refactored NR HARQ-ACK feedback enqueue

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent bd11b66b6c
commit 991c6e7016

@ -167,4 +167,8 @@ SRSRAN_API int srsran_ue_dl_nr_gen_ack(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg
const srsran_pdsch_ack_nr_t* ack_info,
srsran_uci_data_nr_t* uci_data);
SRSRAN_API int srsran_ue_dl_nr_ack_insert_m(srsran_pdsch_ack_nr_t* ack_info, srsran_pdsch_ack_m_nr_t* m);
SRSRAN_API uint32_t srsran_ue_dl_nr_ack_info(const srsran_pdsch_ack_nr_t* ack_info, char* str, uint32_t str_len);
#endif // SRSRAN_UE_DL_NR_H

@ -14,6 +14,10 @@ add_executable(gen_ack_test gen_ack_test.c)
target_link_libraries(gen_ack_test srsran_phy)
add_test(gen_ack_test gen_ack_test)
add_executable(gen_ack_nr_test gen_ack_nr_test.c)
target_link_libraries(gen_ack_nr_test srsran_phy)
add_test(gen_ack_nr_test gen_ack_nr_test)
add_executable(pucch_resource_test pucch_resource_test.c)
target_link_libraries(pucch_resource_test srsran_phy)
add_test(pucch_resource_test pucch_resource_test)

@ -0,0 +1,150 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsran/common/test_common.h"
#include "srsran/phy/ue/ue_dl_nr.h"
#include <getopt.h>
static int test_case_1()
{
// Set configuration
srsran_ue_dl_nr_harq_ack_cfg_t cfg = {};
cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
// Generate ACK information
srsran_pdsch_ack_nr_t ack_info = {};
ack_info.nof_cc = 1;
ack_info.use_pusch = true;
srsran_pdsch_ack_m_nr_t m = {};
m.value[0] = 1;
m.present = true;
m.resource.k1 = 8;
m.resource.v_dai_dl = 0;
m.value[0] = 1;
m.present = true;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 5;
m.resource.v_dai_dl = 2;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 6;
m.resource.v_dai_dl = 1;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 4;
m.resource.v_dai_dl = 3;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 3;
m.resource.v_dai_dl = 0;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
// Print trace
char str[512] = {};
TESTASSERT(srsran_ue_dl_nr_ack_info(&ack_info, str, (uint32_t)sizeof(str)) > SRSRAN_SUCCESS);
INFO("%s", str);
// Generate UCI data
srsran_uci_data_nr_t uci_data = {};
TESTASSERT(srsran_ue_dl_nr_gen_ack(&cfg, &ack_info, &uci_data) == SRSRAN_SUCCESS);
// Assert UCI data
TESTASSERT(uci_data.cfg.o_ack == 5);
return SRSRAN_SUCCESS;
}
static int test_case_2()
{
// Set configuration
srsran_ue_dl_nr_harq_ack_cfg_t cfg = {};
cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
// Generate ACK information
srsran_pdsch_ack_nr_t ack_info = {};
ack_info.nof_cc = 1;
ack_info.use_pusch = true;
srsran_pdsch_ack_m_nr_t m = {};
m.value[0] = 1;
m.present = true;
m.resource.k1 = 7;
m.resource.v_dai_dl = 1;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 6;
m.resource.v_dai_dl = 2;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 8;
m.resource.v_dai_dl = 0;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 5;
m.resource.v_dai_dl = 3;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 4;
m.resource.v_dai_dl = 0;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
// Print trace
char str[512] = {};
TESTASSERT(srsran_ue_dl_nr_ack_info(&ack_info, str, (uint32_t)sizeof(str)) > SRSRAN_SUCCESS);
INFO("%s", str);
// Generate UCI data
srsran_uci_data_nr_t uci_data = {};
TESTASSERT(srsran_ue_dl_nr_gen_ack(&cfg, &ack_info, &uci_data) == SRSRAN_SUCCESS);
// Assert UCI data
TESTASSERT(uci_data.cfg.o_ack == 5);
return SRSRAN_SUCCESS;
}
static void usage(char* prog)
{
printf("Usage: %s [v]\n", prog);
printf("\t-v Increase srsran_verbose\n");
}
static void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "v")) != -1) {
switch (opt) {
case 'v':
srsran_verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int main(int argc, char** argv)
{
parse_args(argc, argv);
// Test only until Format1B - CS
TESTASSERT(test_case_1() == SRSRAN_SUCCESS);
TESTASSERT(test_case_2() == SRSRAN_SUCCESS);
printf("Ok\n");
return SRSRAN_SUCCESS;
}

@ -760,3 +760,72 @@ int srsran_ue_dl_nr_gen_ack(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg,
ERROR("No HARQ-ACK codebook determination is NOT implemented");
return SRSRAN_ERROR;
}
int srsran_ue_dl_nr_ack_insert_m(srsran_pdsch_ack_nr_t* ack_info, srsran_pdsch_ack_m_nr_t* m)
{
// Check inputs
if (ack_info == NULL || m == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Protect SCell index and extract information
if (m->resource.scell_idx >= SRSRAN_MAX_CARRIERS) {
ERROR("Serving cell index (%d) exceeds maximum", m->resource.scell_idx);
return SRSRAN_ERROR;
}
srsran_pdsch_ack_cc_nr_t* cc = &ack_info->cc[m->resource.scell_idx];
// Find insertion index
uint32_t idx = cc->M; // Append at the end by default
for (uint32_t i = 0; i < cc->M; i++) {
if (cc->m[i].resource.k1 < m->resource.k1) {
idx = i;
break;
}
}
// Increment count
cc->M += 1;
// Make space for insertion
for (uint32_t i = cc->M - 1; i > idx; i--) {
cc->m[i] = cc->m[i - 1];
}
// Actual insertion
cc->m[idx] = *m;
return SRSRAN_SUCCESS;
}
uint32_t srsran_ue_dl_nr_ack_info(const srsran_pdsch_ack_nr_t* ack_info, char* str, uint32_t str_len)
{
uint32_t len = 0;
if (ack_info == NULL || str == NULL) {
return 0;
}
// Print base info
len = srsran_print_check(
str, str_len, len, "use_pusch=%c nof_cc=%d\n", ack_info->use_pusch ? 'y' : 'n', ack_info->nof_cc);
// Iterate all carriers
for (uint32_t cc = 0; cc < ack_info->nof_cc; cc++) {
len = srsran_print_check(str, str_len, len, " CC %d: M=%d\n", cc, ack_info->cc[cc].M);
for (uint32_t m = 0; m < ack_info->cc[cc].M; m++) {
if (ack_info->cc[cc].m[m].present) {
len = srsran_print_check(str,
str_len,
len,
" m %d: k1=%d dai=%d ack=%d\n",
m,
ack_info->cc[cc].m[m].resource.k1,
ack_info->cc[cc].m[m].resource.v_dai_dl,
ack_info->cc[cc].m[m].value[0]);
}
}
}
return len;
}

@ -214,6 +214,12 @@ public:
// Calculate Receive TTI
uint32_t tti_tx = TTI_ADD(tti_rx, ack_resource.k1);
// Prepare ACK information
srsran_pdsch_ack_m_nr_t ack_m = {};
ack_m.resource = ack_resource;
ack_m.value[0] = crc_ok ? 1 : 0;
ack_m.present = true;
// Scope mutex to protect read/write the list
std::lock_guard<std::mutex> lock(pending_ack_mutex);
@ -221,15 +227,10 @@ public:
srsran_pdsch_ack_nr_t& ack = pending_ack[tti_tx];
ack.nof_cc = 1;
// Select serving cell
srsran_pdsch_ack_cc_nr_t& ack_cc = ack.cc[ack_resource.scell_idx];
srsran_pdsch_ack_m_nr_t& ack_m = ack_cc.m[ack_cc.M];
ack_cc.M++;
// Set PDSCH transmission information
ack_m.resource = ack_resource;
ack_m.value[0] = crc_ok ? 1 : 0;
ack_m.present = true;
// Insert PDSCH transmission information
if (srsran_ue_dl_nr_ack_insert_m(&ack, &ack_m) < SRSRAN_SUCCESS) {
ERROR("Error inserting ACK m value");
}
}
bool get_pending_ack(const uint32_t& tti_tx, srsran_pdsch_ack_nr_t& pdsch_ack)

@ -318,6 +318,14 @@ bool cc_worker::work_ul()
// If PDSCH UL ACK is available, load into UCI
if (has_ul_ack) {
pdsch_ack.use_pusch = has_pusch_grant;
if (logger.debug.enabled()) {
std::array<char, 512> str = {};
if (srsran_ue_dl_nr_ack_info(&pdsch_ack, str.data(), (uint32_t)str.size()) > 0) {
logger.debug("%s", str.data());
}
}
if (srsran_ue_dl_nr_gen_ack(&phy->cfg.harq_ack, &pdsch_ack, &uci_data) < SRSRAN_SUCCESS) {
ERROR("Filling UCI ACK bits");
return false;

Loading…
Cancel
Save