Merge branch 'integration_2025_w36' into 'develop'
Integration: `2025.w36` * !3613 Speedup complex rotate for aarch64 * !3614 Ldpc encoder zc384 optimization * !3625 gNB scheduler small fixes * !3629 Fix for gNB max feedback time parameter * !3619 Fix RA 2-Step MgsB Ack at UE * !3626 Upgrade CI to Aerial 25-2 See merge request oai/openairinterface5g!3627
This commit is contained in:
+1
-1
@@ -170,7 +170,7 @@ endif()
|
||||
if (NOT CROSS_COMPILE)
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=native")
|
||||
else ()
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=armv8-a")
|
||||
set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=armv8.2-a")
|
||||
endif()
|
||||
|
||||
# add autotools definitions that were maybe used!
|
||||
|
||||
@@ -389,13 +389,13 @@ class Containerize():
|
||||
elif image != 'ran-build':
|
||||
cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}')
|
||||
if image == 'oai-gnb-aerial':
|
||||
cmd.run('cp -f /opt/nvidia-ipc/nvipc.src.2025.05.20.tar.gz .')
|
||||
cmd.run('cp -f /opt/nvidia-ipc/nvipc_src.2025.08.27.tar.gz .')
|
||||
logfile = f'{lSourcePath}/cmake_targets/log/{name}.docker.log'
|
||||
ret = cmd.run(f'{self.cli} build {self.cliBuildOptions} --target {image} --tag {name}:{imageTag} --file docker/Dockerfile.{pattern}{self.dockerfileprefix} {option} . > {logfile} 2>&1', timeout=1200)
|
||||
t = (name, archiveArtifact(cmd, ctx, logfile))
|
||||
log_files.append(t)
|
||||
if image == 'oai-gnb-aerial':
|
||||
cmd.run('rm -f nvipc.src.2025.05.20.tar.gz')
|
||||
cmd.run('rm -f nvipc_src.2025.08.27.tar.gz')
|
||||
# check the status of the build
|
||||
ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {name}:{imageTag}")
|
||||
if ret.returncode != 0:
|
||||
|
||||
@@ -23,7 +23,7 @@ services:
|
||||
- ../../../cmake_targets/share:/opt/cuBB/share
|
||||
userns_mode: host
|
||||
ipc: "shareable"
|
||||
image: cubb-build:25-1
|
||||
image: cubb-build:25-2
|
||||
environment:
|
||||
- cuBB_SDK=/opt/nvidia/cuBB
|
||||
command: bash -c "sudo rm -rf /tmp/phy.log && sudo chmod +x /opt/nvidia/cuBB/aerial_l1_entrypoint.sh && /opt/nvidia/cuBB/aerial_l1_entrypoint.sh"
|
||||
|
||||
@@ -230,10 +230,10 @@ After preparing the L1 software, the container needs to be committed to create a
|
||||
In this file the RU MAC address needs to be specified before commiting the image.
|
||||
|
||||
```bash
|
||||
~$ docker commit nv-cubb cubb-build:25-1
|
||||
~$ docker commit nv-cubb cubb-build:25-2
|
||||
~$ docker image ls
|
||||
..
|
||||
cubb-build 25-1 824156e0334c 2 weeks ago 23.9GB
|
||||
cubb-build 25-2 824156e0334c 2 weeks ago 23.9GB
|
||||
-..
|
||||
```
|
||||
|
||||
|
||||
@@ -37,20 +37,11 @@ RUN /bin/sh oaienv && \
|
||||
mkdir -p log ran_build/build ran_build/build-cross && \
|
||||
cd ran_build/build && \
|
||||
cmake ../../.. -GNinja && \
|
||||
echo "====== Start of log for host-tools ======" && \
|
||||
ninja ldpc_generators generate_T > ../../log/host-tools.txt 2>&1 && \
|
||||
echo "====== End of log for host-tools ======" && \
|
||||
ninja ldpc_generators generate_T && \
|
||||
cd ../build-cross/ && \
|
||||
# install missing libyaml-cpp-dev for arm64
|
||||
apt install -y libyaml-cpp-dev:arm64 && \
|
||||
cmake ../../.. -GNinja -DENABLE_TELNETSRV=ON \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../../../cmake_targets/cross-arm.cmake -DNATIVE_DIR=../build \
|
||||
-DCMAKE_C_FLAGS="-Werror" -DCMAKE_CXX_FLAGS="-Werror" && \
|
||||
echo "====== Start of log for cross-build executables ======" && \
|
||||
# making always passing so we can analyze the all.txt file
|
||||
ninja -k10 dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim lte-softmodem nr-softmodem nr-cuup oairu lte-uesoftmodem nr-uesoftmodem params_libconfig coding rfsimulator telnetsrv > ../../log/all.txt 2>&1; \
|
||||
# displaying errors and warnings
|
||||
grep -E -A3 "warning:|error:" ../../log/all.txt || true && \
|
||||
# will fail only if string "errors:" is found
|
||||
grep -E "error:" -vqz ../../log/all.txt && \
|
||||
echo "====== End of log for cross-build executables ======"
|
||||
ninja -k10 dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim lte-softmodem nr-softmodem nr-cuup oairu lte-uesoftmodem nr-uesoftmodem params_libconfig coding rfsimulator telnetsrv
|
||||
|
||||
@@ -45,7 +45,7 @@ WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
RUN /bin/sh oaienv && \
|
||||
tar -xvzf nvipc* && \
|
||||
tar -xvzf nvipc_src.*.tar.gz && \
|
||||
cd nvipc_src.* && \
|
||||
rm -rf build && mkdir build && cd build && \
|
||||
cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \
|
||||
|
||||
@@ -45,7 +45,7 @@ WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
RUN /bin/sh oaienv && \
|
||||
tar -xvzf nvipc* && \
|
||||
tar -xvzf nvipc_src.*.tar.gz && \
|
||||
cd nvipc_src.* && \
|
||||
rm -rf build && mkdir build && cd build && \
|
||||
cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -36,13 +36,27 @@
|
||||
#include "assertions.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
|
||||
#define USE_PERMUTEX
|
||||
#ifdef __aarch64__
|
||||
#define USE_ALIGNR
|
||||
#endif
|
||||
#ifdef __AVX512F__
|
||||
#if defined(__AVX512VBMI__) && defined(USE_PERMUTEX)
|
||||
// For AVX512 machines, use an AVX512 version of the encoder for Zc=384 only for now. This is used almost exclusively for
|
||||
// high-throughput cases. The version with "permutex2var" instruction uses less memory (i.e. 1/64th of the memory to store the
|
||||
// input), but uses more reads instead of creating 64 shifts of the input with memcpy
|
||||
#include "ldpc384_simd512_permutex_byte.c"
|
||||
#else
|
||||
#include "ldpc384_simd512_byte.c"
|
||||
#endif
|
||||
#else
|
||||
#include "ldpc384_byte.c"
|
||||
#endif
|
||||
#ifdef USE_ALIGNR
|
||||
#include "ldpc384_alignr_byte_128.c"
|
||||
#else
|
||||
#include "ldpc384_byte_128.c"
|
||||
#endif
|
||||
#include "ldpc352_byte.c"
|
||||
#include "ldpc352_byte_128.c"
|
||||
#include "ldpc320_byte.c"
|
||||
@@ -96,8 +110,13 @@ static void encode_parity_check_part_optim(uint8_t *cc, uint8_t *d, short BG,sho
|
||||
memcpy(&c[2 * i1 * Zc], &cc[i1 * Zc], Zc * sizeof(unsigned char));
|
||||
memcpy(&c[(2 * i1 + 1) * Zc], &cc[i1 * Zc], Zc * sizeof(unsigned char));
|
||||
}
|
||||
for (int i1 = 1; i1 < simd_size; i1++) {
|
||||
memcpy(&c[(2 * ncols * Zc * i1)], &c[i1], (2 * ncols * Zc * sizeof(unsigned char)) - i1);
|
||||
#if (defined(USE_PERMUTEX) && defined(__AVX512VBMI__)) || defined(USE_ALIGNR)
|
||||
if (Zc < 384 || BG == 2)
|
||||
#endif
|
||||
{
|
||||
for (int i1 = 1; i1 < simd_size; i1++) {
|
||||
memcpy(&c[(2 * ncols * Zc * i1)], &c[i1], (2 * ncols * Zc * sizeof(unsigned char)) - i1);
|
||||
}
|
||||
}
|
||||
if (BG == 1) {
|
||||
switch (Zc) {
|
||||
|
||||
@@ -828,6 +828,47 @@ static inline void rotate_cpx_vector(const c16_t *const x, const c16_t *const al
|
||||
// log2_amp - increase the output amplitude by a factor 2^log2_amp (default is 0)
|
||||
// WARNING: log2_amp>0 can cause overflow!!
|
||||
|
||||
|
||||
#ifdef __aarch64__
|
||||
if (output_shift == 15) { // allows specific NEON instruction
|
||||
|
||||
int16x8_t ar = (int16x8_t)vdupq_n_s16(alpha->r);
|
||||
int16x8_t ai = (int16x8_t)vdupq_n_s16(alpha->i);
|
||||
int16x8_t *y_128 = (int16x8_t *)y;
|
||||
int16x8_t *x_128 = (int16x8_t *)x;
|
||||
for (uint32_t i = 0; i < (N >> 2); i++) {
|
||||
// Split interleaved -> separate real/imag
|
||||
int16x8_t br = vuzp1q_s16(x_128[i], x_128[i]);
|
||||
int16x8_t bi = vuzp2q_s16(x_128[i], x_128[i]);
|
||||
|
||||
// Start with the two “diagonal” products using high-half, doubling, sat:
|
||||
// x = round( (2*ar*br) / 2^16 ), y = round( (2*ar*bi) / 2^16 )
|
||||
int16x8_t real = vqdmulhq_s16(ar, br);
|
||||
int16x8_t imag = vqdmulhq_s16(ar, bi);
|
||||
|
||||
// real -= round( (2*ai*bi) / 2^16 )
|
||||
real = vqrdmlshq_s16(real, ai, bi);
|
||||
|
||||
// imag += round( (2*ai*br) / 2^16 )
|
||||
imag = vqrdmlahq_s16(imag, ai, br);
|
||||
|
||||
// Re-interleave [real, imag]
|
||||
int16x8x2_t z = vzipq_s16(real, imag);
|
||||
|
||||
y_128[i] = z.val[0];
|
||||
/*
|
||||
printf("y : (%d %d) (%d %d) (%d %d) (%d %d)\n",
|
||||
vgetq_lane_s16(y_128[i],0),
|
||||
vgetq_lane_s16(y_128[i],1),
|
||||
vgetq_lane_s16(y_128[i],2),
|
||||
vgetq_lane_s16(y_128[i],3),
|
||||
vgetq_lane_s16(y_128[i],4),
|
||||
vgetq_lane_s16(y_128[i],5),
|
||||
vgetq_lane_s16(y_128[i],6),
|
||||
vgetq_lane_s16(y_128[i],7));*/
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
uint32_t i; // loop counter
|
||||
|
||||
simd_q15_t *y_128, alpha_128;
|
||||
@@ -859,7 +900,10 @@ static inline void rotate_cpx_vector(const c16_t *const x, const c16_t *const al
|
||||
shift));
|
||||
// print_ints("y_128[0]=", &y_128[0]);
|
||||
}
|
||||
#if defined(__x86__) || defined(__x86_64__)
|
||||
#ifdef __aarch64__
|
||||
}
|
||||
#endif //__aarch64__
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1032,6 +1032,7 @@ printf("%d\n", slot);
|
||||
reset_meas(&gNB->dlsch_rate_matching_stats);
|
||||
reset_meas(&gNB->dlsch_segmentation_stats);
|
||||
reset_meas(&gNB->dlsch_modulation_stats);
|
||||
reset_meas(&gNB->dlsch_precoding_stats);
|
||||
reset_meas(&gNB->dlsch_encoding_stats);
|
||||
reset_meas(&gNB->dci_generation_stats);
|
||||
reset_meas(&gNB->tinput);
|
||||
|
||||
@@ -856,6 +856,8 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP,
|
||||
}
|
||||
if (rbStart > (sched_pusch.bwp_info.bwpSize - ra->msg3_nb_rb)) {
|
||||
// cannot find free vrb_map for msg3 retransmission in this slot
|
||||
reset_beam_status(&nr_mac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_frame, beam_ul.new_beam);
|
||||
reset_beam_status(&nr_mac->beam_info, frame, slot, UE->UE_beam_index, slots_frame, beam_dci.new_beam);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -915,10 +917,11 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP,
|
||||
ss,
|
||||
coreset,
|
||||
&UE->UE_sched_ctrl.sched_pdcch,
|
||||
true,
|
||||
0);
|
||||
if (CCEIndex < 0) {
|
||||
LOG_E(NR_MAC, "UE %04x cannot find free CCE!\n", UE->rnti);
|
||||
reset_beam_status(&nr_mac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_frame, beam_ul.new_beam);
|
||||
reset_beam_status(&nr_mac->beam_info, frame, slot, UE->UE_beam_index, slots_frame, beam_dci.new_beam);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1507,7 +1510,7 @@ static void nr_generate_Msg2(module_id_t module_idP,
|
||||
}
|
||||
|
||||
uint8_t aggregation_level;
|
||||
int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, beam.idx, ss, coreset, &sched_ctrl->sched_pdcch, true, 0);
|
||||
int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, beam.idx, ss, coreset, &sched_ctrl->sched_pdcch, 0);
|
||||
|
||||
if (CCEIndex < 0) {
|
||||
LOG_W(NR_MAC, "UE %04x: %d.%d cannot find free CCE for Msg2!\n", UE->rnti, frameP, slotP);
|
||||
@@ -1707,7 +1710,6 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
|
||||
ss,
|
||||
coreset,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
true,
|
||||
0);
|
||||
|
||||
if (CCEIndex < 0) {
|
||||
@@ -1735,8 +1737,10 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
|
||||
TYPE_TC_RNTI_,
|
||||
coreset->controlResourceSetId,
|
||||
false);
|
||||
if (!msg4_tda.valid_tda)
|
||||
if (!msg4_tda.valid_tda) {
|
||||
reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam);
|
||||
return;
|
||||
}
|
||||
|
||||
NR_pdsch_dmrs_t dmrs_info = get_dl_dmrs_params(scc, dl_bwp, &msg4_tda, 1);
|
||||
bwp_info_t bwp_info = get_pdsch_bwp_start_size(nr_mac, UE);
|
||||
|
||||
@@ -551,7 +551,6 @@ static bool allocate_dl_retransmission(module_id_t module_id,
|
||||
sched_ctrl->search_space,
|
||||
sched_ctrl->coreset,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
false,
|
||||
sched_ctrl->pdcch_cl_adjust);
|
||||
if (CCEIndex<0) {
|
||||
sched_ctrl->dl_cce_fail++;
|
||||
@@ -798,6 +797,7 @@ static void pf_dl(module_id_t module_id,
|
||||
rbStart,
|
||||
max_rbSize,
|
||||
rbStop);
|
||||
reset_beam_status(&mac->beam_info, frame, slot, iterator->UE->UE_beam_index, slots_per_frame, beam.new_beam);
|
||||
iterator++;
|
||||
continue;
|
||||
}
|
||||
@@ -811,7 +811,6 @@ static void pf_dl(module_id_t module_id,
|
||||
sched_ctrl->search_space,
|
||||
sched_ctrl->coreset,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
false,
|
||||
sched_ctrl->pdcch_cl_adjust);
|
||||
if (CCEIndex < 0) {
|
||||
sched_ctrl->dl_cce_fail++;
|
||||
|
||||
@@ -139,7 +139,6 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot)
|
||||
sched_ctrl->search_space,
|
||||
sched_ctrl->coreset,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
false,
|
||||
0);
|
||||
AssertFatal(CCEIndex >= 0, "Could not find CCE for UE %04x\n", UE->rnti);
|
||||
|
||||
@@ -286,7 +285,6 @@ void nr_ul_preprocessor_phytest(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_p
|
||||
sched_ctrl->search_space,
|
||||
sched_ctrl->coreset,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
false,
|
||||
0);
|
||||
if (CCEIndex < 0) {
|
||||
LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__);
|
||||
|
||||
@@ -572,10 +572,9 @@ int get_cce_index(const gNB_MAC_INST *nrmac,
|
||||
const NR_SearchSpace_t *ss,
|
||||
const NR_ControlResourceSet_t *coreset,
|
||||
NR_sched_pdcch_t *sched_pdcch,
|
||||
bool is_common,
|
||||
float pdcch_cl_adjust)
|
||||
{
|
||||
const uint32_t Y = is_common ? 0 : get_Y(ss, slot, rnti);
|
||||
const uint32_t Y = get_Y(ss, slot, rnti);
|
||||
uint8_t nr_of_candidates;
|
||||
|
||||
int agg_level_search_order[NUM_PDCCH_AGG_LEVELS];
|
||||
@@ -2518,7 +2517,7 @@ void set_max_fb_time(NR_UE_UL_BWP_t *UL_BWP, const NR_UE_DL_BWP_t *DL_BWP)
|
||||
{
|
||||
UL_BWP->max_fb_time = 8; // default value
|
||||
// take the maximum in dl_DataToUL_ACK list
|
||||
if (DL_BWP->dci_format != NR_DL_DCI_FORMAT_1_0 && UL_BWP->pucch_Config) {
|
||||
if (UL_BWP->pucch_Config) {
|
||||
const struct NR_PUCCH_Config__dl_DataToUL_ACK *fb_times = UL_BWP->pucch_Config->dl_DataToUL_ACK;
|
||||
for (int i = 0; i < fb_times->list.count; i++) {
|
||||
if(*fb_times->list.array[i] > UL_BWP->max_fb_time)
|
||||
|
||||
@@ -1876,7 +1876,6 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
|
||||
sched_ctrl->search_space,
|
||||
sched_ctrl->coreset,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
false,
|
||||
sched_ctrl->pdcch_cl_adjust);
|
||||
if (CCEIndex<0) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for retransmission UL DCI UE\n", UE->rnti, frame, slot);
|
||||
@@ -2125,7 +2124,6 @@ static int pf_ul(gNB_MAC_INST *nrmac,
|
||||
sched_ctrl->search_space,
|
||||
sched_ctrl->coreset,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
false,
|
||||
sched_ctrl->pdcch_cl_adjust);
|
||||
|
||||
if (CCEIndex < 0) {
|
||||
@@ -2444,7 +2442,7 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE
|
||||
sched_ctrl->last_ul_slot = sched_pusch->slot;
|
||||
|
||||
LOG_D(NR_MAC,
|
||||
"ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS "
|
||||
"ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d TDA %2d dmrs_pos %x MCS "
|
||||
"Table %2d MCS %2d nrOfLayers %2d num_dmrs_cdm_grps_no_data %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched "
|
||||
"%6d est BSR %6d TPC %d\n",
|
||||
frame,
|
||||
@@ -2455,8 +2453,7 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE
|
||||
sched_ctrl->aggregation_level,
|
||||
sched_pusch->rbStart,
|
||||
sched_pusch->rbSize,
|
||||
sched_pusch->tda_info.startSymbolIndex,
|
||||
sched_pusch->tda_info.nrOfSymbols,
|
||||
sched_pusch->time_domain_allocation,
|
||||
sched_pusch->dmrs_info.ul_dmrs_symb_pos,
|
||||
current_BWP->mcs_table,
|
||||
sched_pusch->mcs,
|
||||
|
||||
@@ -431,7 +431,6 @@ int get_cce_index(const gNB_MAC_INST *nrmac,
|
||||
const NR_SearchSpace_t *ss,
|
||||
const NR_ControlResourceSet_t *coreset,
|
||||
NR_sched_pdcch_t *sched_pdcch,
|
||||
bool is_common,
|
||||
float pdcch_cl_adjust);
|
||||
|
||||
bool nr_find_nb_rb(uint16_t Qm,
|
||||
|
||||
@@ -1190,7 +1190,7 @@ void update_harq_status(NR_UE_MAC_INST_t *mac, uint8_t harq_pid, uint8_t ack_nac
|
||||
if (current_harq->active) {
|
||||
LOG_D(PHY,"Updating harq_status for harq_id %d, ack/nak %d\n", harq_pid, current_harq->ack);
|
||||
// we can prepare feedback for MSG4 in advance
|
||||
if (mac->ra.ra_state == nrRA_WAIT_CONTENTION_RESOLUTION)
|
||||
if (mac->ra.ra_state == nrRA_WAIT_CONTENTION_RESOLUTION || mac->ra.ra_state == nrRA_WAIT_MSGB)
|
||||
prepare_msg4_msgb_feedback(mac, harq_pid, ack_nack);
|
||||
else {
|
||||
current_harq->ack = ack_nack;
|
||||
|
||||
Reference in New Issue
Block a user