diff --git a/CMakeLists.txt b/CMakeLists.txt
index 898b387237..a71b1c3ea2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -194,26 +194,26 @@ set(CMAKE_CXX_FLAGS
"${C_FLAGS_PROCESSOR} ${commonOpts} -std=c++11 ${CMAKE_CXX_FLAGS}")
-add_boolean_option(SANITIZE_ADDRESS False "enable the address sanitizer (ASan)" ON)
+add_boolean_option(SANITIZE_ADDRESS OFF "enable the address sanitizer (ASan)" ON)
if (SANITIZE_ADDRESS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-common")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-common")
endif ()
-add_boolean_option(SANITIZE_THREAD False "enable the address sanitizer (TSan)" ON)
+add_boolean_option(SANITIZE_THREAD OFF "enable the address sanitizer (TSan)" ON)
if (SANITIZE_THREAD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -fno-omit-frame-pointer -fno-common")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -fno-omit-frame-pointer -fno-common")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
endif()
-add_boolean_option(SANITIZE_UNDEFINED False "enable the undefined behavior sanitizer (UBSan)" ON)
+add_boolean_option(SANITIZE_UNDEFINED OFF "enable the undefined behavior sanitizer (UBSan)" ON)
if (SANITIZE_UNDEFINED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
endif ()
-add_boolean_option(SANITIZE_MEMORY False "enable the memory sanitizer (MSan, requires clang, incompatible with ASan/UBSan)" ON)
+add_boolean_option(SANITIZE_MEMORY OFF "enable the memory sanitizer (MSan, requires clang, incompatible with ASan/UBSan)" ON)
if(SANITIZE_MEMORY)
if (SANITIZE_UNDEFINED OR SANITIZE_ADDRESS)
message(FATAL_ERROR "memory sanitizer cannot coexist with address sanitizer or undefined behavior sanitizer, please disable either MSan or ASan and UBSan")
@@ -278,14 +278,16 @@ endif()
# OAI uses this feature to re-use OAI LOG_I(ASN1, ...)
# see common/utils/config.h
add_boolean_option(TRACE_ASN1C_ENC_DEC OFF "Enable ASN1 encoder/decoder debug traces via OAI logging system" ON)
-add_boolean_option(T_TRACER True "Activate the T tracer, a debugging/monitoring framework" ON)
-add_boolean_option(ENABLE_LTTNG False "Activate the LTTNG tracer, a debugging/monitoring framework" ON)
-add_boolean_option(UE_DEBUG_TRACE False "Activate UE debug trace" ON)
-add_boolean_option(UE_TIMING_TRACE False "Activate UE timing trace" ON)
+add_boolean_option(T_TRACER ON "Activate the T tracer, a debugging/monitoring framework" ON)
+add_boolean_option(ENABLE_LTTNG OFF "Activate the LTTNG tracer, a debugging/monitoring framework" ON)
+add_boolean_option(UE_DEBUG_TRACE OFF "Activate UE debug trace" ON)
+add_boolean_option(UE_TIMING_TRACE OFF "Activate UE timing trace" ON)
add_boolean_option(TRACY_ENABLE OFF "Enable tracy instrumentation" ON)
if (TRACY_ENABLE)
- CPMAddPackage("gh:wolfpld/tracy#v0.11.1")
+ # the tracy version here should match the tracy server version
+ # below is latest release as of this commit
+ CPMAddPackage("gh:wolfpld/tracy#0.12.2")
endif()
set (OCP_ITTI ${OPENAIR_DIR}/common/utils/ocp_itti)
@@ -337,7 +339,6 @@ target_link_libraries(nr_rrc PUBLIC asn1_nr_rrc asn1_lte_rrc)
set(S1AP_DIR ${OPENAIR3_DIR}/S1AP)
include_directories ("${S1AP_DIR}")
add_library(s1ap
- ${S1AP_DIR}/s1ap_common.c
${S1AP_DIR}/s1ap_eNB.c
${S1AP_DIR}/s1ap_eNB_context_management_procedures.c
${S1AP_DIR}/s1ap_eNB_decoder.c
@@ -509,34 +510,34 @@ include_directories ("${OPENAIR_DIR}/radio/COMMON")
# ???!!! TO BE DOCUMENTED OPTIONS !!!???
##############################################################
-add_boolean_option(UE_EXPANSION False "enable UE_EXPANSION with max 256 UE" ON)
-add_boolean_option(PHY_TX_THREAD False "enable UE_EXPANSION with max 256 UE" ON)
-add_boolean_option(PRE_SCD_THREAD False "enable UE_EXPANSION with max 256 UE" ON)
+add_boolean_option(UE_EXPANSION OFF "enable UE_EXPANSION with max 256 UE" ON)
+add_boolean_option(PHY_TX_THREAD OFF "enable UE_EXPANSION with max 256 UE" ON)
+add_boolean_option(PRE_SCD_THREAD OFF "enable UE_EXPANSION with max 256 UE" ON)
##########################
# SCHEDULING/REAL-TIME/PERF options
##########################
-add_boolean_option(ENABLE_USE_CPU_EXECUTION_TIME False "Add data in vcd traces: disable it if perf issues" ON)
-add_boolean_option(ENABLE_VCD False "always true now, time measurements of proc calls and var displays" ON)
-add_boolean_option(ENABLE_VCD_FIFO False "time measurements of proc calls and var displays sent to FIFO (one more thread)" ON)
+add_boolean_option(ENABLE_USE_CPU_EXECUTION_TIME OFF "Add data in vcd traces: disable it if perf issues" ON)
+add_boolean_option(ENABLE_VCD OFF "always true now, time measurements of proc calls and var displays" ON)
+add_boolean_option(ENABLE_VCD_FIFO OFF "time measurements of proc calls and var displays sent to FIFO (one more thread)" ON)
##########################
# PHY options
##########################
-add_integer_option(MAX_NUM_CCs 1 "Carrier component data arrays size (oai doesn't support carrier aggreagtion for now)" ON)
-add_boolean_option(SMBV False "Rohde&Schwarz SMBV100A vector signal generator" ON)
-add_boolean_option(DEBUG_PHY False "Enable PHY layer debugging options" ON)
-add_boolean_option(DEBUG_PHY_PROC False "Enable debugging of PHY layer procedures" ON)
+add_integer_option(MAX_NUM_CCs 1 "Carrier component data arrays size (oai doesn't support carrier aggregation for now)" ON)
+add_boolean_option(SMBV OFF "Rohde&Schwarz SMBV100A vector signal generator" ON)
+add_boolean_option(DEBUG_PHY OFF "Enable PHY layer debugging options" ON)
+add_boolean_option(DEBUG_PHY_PROC OFF "Enable debugging of PHY layer procedures" ON)
##########################
# NAS LAYER OPTIONS
##########################
-add_boolean_option(NAS_BUILT_IN_UE True "UE NAS layer present in this executable" ON)
+add_boolean_option(NAS_BUILT_IN_UE ON "UE NAS layer present in this executable" ON)
##########################
# RRC LAYER OPTIONS
##########################
-add_boolean_option(RRC_DEFAULT_RAB_IS_AM True "set the LTE RLC mode to AM for the default bearer, otherwise it is UM." ON)
+add_boolean_option(RRC_DEFAULT_RAB_IS_AM ON "set the LTE RLC mode to AM for the default bearer, otherwise it is UM." ON)
# add the binary tree to the search path for include files
# We will find common/oai_version.h after generation in target directory
@@ -603,7 +604,7 @@ include_directories("${OPENAIR_DIR}")
###############
# include T directory even if the T is off because T macros are in the code
-# no matter what. Note: sone files are generated, so we have both source and
+# no matter what. Note: some files are generated, so we have both source and
# binary directories
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/common/utils/T
${CMAKE_CURRENT_BINARY_DIR}/common/utils/T)
@@ -1395,9 +1396,10 @@ include_directories("${OPENAIR1_DIR}/SCHED_NR_UE")
add_library (GTPV1U
${RRC_DIR}/rrc_eNB_GTPV1U.c
${OPENAIR3_DIR}/ocp-gtpu/gtp_itf.cpp
+ ${OPENAIR3_DIR}/ocp-gtpu/gtpu_extensions.c
)
target_link_libraries(GTPV1U PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
-target_link_libraries(GTPV1U PRIVATE SIMU)
+target_link_libraries(GTPV1U PRIVATE SIMU ds)
include_directories(${OPENAIR3_DIR}/ocp-gtp)
set (MME_APP_SRC
diff --git a/ci-scripts/xml_files/gnb_phytest_rfemulator_run_100_2x2.xml b/ci-scripts/xml_files/gnb_phytest_rfemulator_run_100_2x2.xml
new file mode 100644
index 0000000000..3d2efb5084
--- /dev/null
+++ b/ci-scripts/xml_files/gnb_phytest_rfemulator_run_100_2x2.xml
@@ -0,0 +1,70 @@
+
+
+ gNB-PHY-Test-100-2x2-RFemu
+ Timing phytest 100 MHz 2x2 RFemulator
+ tasks
+
+100000 390101 000001 390109 200000
+
+
+
+ Custom_Command
+ Disable Sleep States
+ caracal
+ sudo cpupower idle-set -D 0
+
+
+ Custom_Command
+ true
+ Enable Sleep States
+ caracal
+ sudo cpupower idle-set -E
+
+
+
+ Initialize_eNB
+ Initialize gNB USRP
+ caracal
+ -O ci-scripts/conf_files/gnb.band79.273prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 273 -t 23 -D 127 -m 23 -M 273 -l 2 --device.name rf_emulator --rf_emulator.noise_level_dBFS -36 --log_config.global_log_options level,nocolor,time
+ datalog_rt_stats.100.2x2.yaml
+ NR
+ numactl --cpunodebind=netdev:enp94s0f0np0 --membind=netdev:enp94s0f0np0
+
+
+
+ IdleSleep
+ Sleep
+ 60
+
+
+
+
+ Terminate_eNB
+ caracal
+ true
+ Terminate gNB
+ NR
+
+
+
diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai
index b1b305c596..658b0b858a 100755
--- a/cmake_targets/build_oai
+++ b/cmake_targets/build_oai
@@ -457,7 +457,7 @@ function main() {
# add some default libraries that should always be built
# for eNB, gNB, UEs, simulators
if [[ $gNB == 1 || $eNB == 1 || $UE == 1 || $nrUE == 1 || $SIMUS_PHY == 1 || $RU == 1 ]]; then
- TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim"
+ TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim rf_emulator"
fi
mkdir -p $DIR/$BUILD_DIR/build
diff --git a/common/config/DOC/config/rtusage.md b/common/config/DOC/config/rtusage.md
index 3b51e1afd2..7c42a6edcc 100644
--- a/common/config/DOC/config/rtusage.md
+++ b/common/config/DOC/config/rtusage.md
@@ -55,7 +55,6 @@ To get help on supported parameters you can use specific options:
--ulsch-max-errors: set the eNodeB max ULSCH erros
--phy-test: test UE phy layer, mac disabled
--usim-test: use XOR autentication algo in case of test usim mode
- --emulate-rf: Emulated RF enabled(disable by defult)
--clock: tells hardware to use a clock reference (0:internal, 1:external, 2:gpsdo)
--wait-for-sync: Help string not specified
-C: Set the downlink frequency for all component carriers
diff --git a/common/utils/ds/CMakeLists.txt b/common/utils/ds/CMakeLists.txt
index a5ae86c52f..b5f5efb47a 100644
--- a/common/utils/ds/CMakeLists.txt
+++ b/common/utils/ds/CMakeLists.txt
@@ -1,5 +1,6 @@
add_library(ds OBJECT
byte_array.c
+ byte_array_producer.c
seq_arr.c
)
diff --git a/common/utils/ds/byte_array_producer.c b/common/utils/ds/byte_array_producer.c
new file mode 100644
index 0000000000..07f46c363c
--- /dev/null
+++ b/common/utils/ds/byte_array_producer.c
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ * contact@openairinterface.org
+ */
+
+#include "byte_array_producer.h"
+
+/* create a byte array producer from an existing buffer */
+byte_array_producer_t byte_array_producer_from_buffer(uint8_t *buffer, int len)
+{
+ byte_array_producer_t result = { .b.len = len, .b.buf = buffer, .pos = 0 };
+ return result;
+}
+
+/* put a byte in a byte array if there is space
+ * returns 1 on success, 0 on error
+ */
+int byte_array_producer_put_byte(byte_array_producer_t *b, uint8_t byte)
+{
+ if (b->pos == b->b.len)
+ return 0;
+
+ b->b.buf[b->pos] = byte;
+ b->pos++;
+
+ return 1;
+}
+
+/* put an u32 number as big endian in a byte array if there is space
+ * returns 1 on success, 0 on error
+ */
+int byte_array_producer_put_u32_be(byte_array_producer_t *b, uint32_t v)
+{
+ return byte_array_producer_put_byte(b, (v >> 24) & 0xff)
+ && byte_array_producer_put_byte(b, (v >> 16) & 0xff)
+ && byte_array_producer_put_byte(b, (v >> 8) & 0xff)
+ && byte_array_producer_put_byte(b, v & 0xff);
+}
+
+/* put an u24 number as big endian in a byte array if there is space
+ * returns 1 on success, 0 on error
+ */
+int byte_array_producer_put_u24_be(byte_array_producer_t *b, uint32_t v)
+{
+ return byte_array_producer_put_byte(b, (v >> 16) & 0xff)
+ && byte_array_producer_put_byte(b, (v >> 8) & 0xff)
+ && byte_array_producer_put_byte(b, v & 0xff);
+}
diff --git a/common/utils/ds/byte_array_producer.h b/common/utils/ds/byte_array_producer.h
new file mode 100644
index 0000000000..2087c77af1
--- /dev/null
+++ b/common/utils/ds/byte_array_producer.h
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ * contact@openairinterface.org
+ */
+
+#ifndef BYTE_ARRAY_PRODUCER_H
+#define BYTE_ARRAY_PRODUCER_H
+
+#include
+
+#include "byte_array.h"
+
+typedef struct {
+ byte_array_t b;
+ size_t pos;
+} byte_array_producer_t;
+
+byte_array_producer_t byte_array_producer_from_buffer(uint8_t *buffer, int len);
+
+int byte_array_producer_put_byte(byte_array_producer_t *b, uint8_t v);
+int byte_array_producer_put_u32_be(byte_array_producer_t *b, uint32_t v);
+int byte_array_producer_put_u24_be(byte_array_producer_t *b, uint32_t v);
+
+#endif
diff --git a/common/utils/shm_iq_channel/shm_td_iq_channel.c b/common/utils/shm_iq_channel/shm_td_iq_channel.c
index 89e09ddb1f..ecebbaf494 100644
--- a/common/utils/shm_iq_channel/shm_td_iq_channel.c
+++ b/common/utils/shm_iq_channel/shm_td_iq_channel.c
@@ -40,7 +40,6 @@ typedef struct {
int num_antennas_tx;
int num_antennas_rx;
uint64_t timestamp;
- bool is_connected;
pthread_mutex_t mutex;
pthread_cond_t cond;
} ShmTDIQChannelData;
@@ -48,10 +47,10 @@ typedef struct {
typedef struct ShmTDIQChannel_s {
IQChannelType type;
ShmTDIQChannelData *data;
- uint64_t last_timestamp;
char name[256];
sample_t *tx_iq_data;
sample_t *rx_iq_data;
+ bool abort;
} ShmTDIQChannel;
ShmTDIQChannel *shm_td_iq_channel_create(const char *name, int num_tx_ant, int num_rx_ant)
@@ -75,14 +74,12 @@ ShmTDIQChannel *shm_td_iq_channel_create(const char *name, int num_tx_ant, int n
memset(shm_ptr, 0, total_size);
shm_ptr->num_antennas_tx = num_tx_ant;
shm_ptr->num_antennas_rx = num_rx_ant;
- shm_ptr->is_connected = false;
ShmTDIQChannel *channel = calloc_or_fail(1, sizeof(ShmTDIQChannel));
strncpy(channel->name, name, sizeof(channel->name) - 1);
channel->tx_iq_data = (sample_t *)(shm_ptr + 1);
channel->rx_iq_data = channel->tx_iq_data + tx_buffer_size / sizeof(sample_t);
channel->data = shm_ptr;
channel->type = IQ_CHANNEL_TYPE_SERVER;
- channel->last_timestamp = 0;
pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
int ret = pthread_mutexattr_init(&mutex_attr);
@@ -137,12 +134,10 @@ ShmTDIQChannel *shm_td_iq_channel_connect(const char *name, int timeout_in_secon
size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * channel->data->num_antennas_tx;
channel->rx_iq_data = channel->tx_iq_data + tx_buffer_size / sizeof(sample_t);
channel->type = IQ_CHANNEL_TYPE_CLIENT;
- channel->last_timestamp = 0;
while (shm_ptr->magic != SHM_MAGIC_NUMBER) {
printf("Waiting for server to initialize shared memory\n");
sleep(1);
}
- shm_ptr->is_connected = true;
close(fd);
return channel;
}
@@ -154,9 +149,6 @@ IQChannelErrorType shm_td_iq_channel_tx(ShmTDIQChannel *channel,
const sample_t *tx_iq_data)
{
ShmTDIQChannelData *data = channel->data;
- if (data->is_connected == false) {
- return CHANNEL_ERROR_NOT_CONNECTED;
- }
// timestamp in the past
uint64_t current_time = data->timestamp;
if (timestamp < current_time) {
@@ -193,9 +185,6 @@ IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel,
sample_t *tx_iq_data)
{
ShmTDIQChannelData *data = channel->data;
- if (data->is_connected == false) {
- return CHANNEL_ERROR_NOT_CONNECTED;
- }
// timestamp in the future
uint64_t current_time = data->timestamp;
if (timestamp > current_time) {
@@ -228,37 +217,54 @@ IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel,
void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, size_t num_samples)
{
ShmTDIQChannelData *data = channel->data;
- if (channel->type != IQ_CHANNEL_TYPE_SERVER) {
- return;
- }
- if (data->is_connected == false) {
- return;
- }
mutexlock(data->mutex);
data->timestamp += num_samples;
condbroadcast(data->cond);
mutexunlock(data->mutex);
}
-void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp)
+int shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_t timeout_uS)
{
ShmTDIQChannelData *data = channel->data;
- if (data->is_connected == false) {
- abort();
- return;
- }
-
size_t current_timestamp = data->timestamp;
if (current_timestamp >= timestamp) {
- return;
+ return 0;
}
- mutexlock(data->mutex);
- while (current_timestamp < timestamp) {
- condwait(data->cond, data->mutex);
- current_timestamp = data->timestamp;
+ if (timeout_uS == 0) {
+ mutexlock(data->mutex);
+ while (current_timestamp < timestamp && !channel->abort) {
+ condwait(data->cond, data->mutex);
+ current_timestamp = data->timestamp;
+ }
+ mutexunlock(data->mutex);
+ } else {
+ struct timespec ts = {.tv_sec = 0, .tv_nsec = 0};
+ if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
+ fprintf(stderr, "Error: clock_gettime failed: %s\n", strerror(errno));
+ return 1;
+ }
+
+ ts.tv_sec += timeout_uS / 1000000; // Convert microseconds to seconds
+ ts.tv_nsec += (timeout_uS % 1000000) * 1000; // Convert remaining microseconds to nanoseconds
+
+ mutexlock(data->mutex);
+ while (current_timestamp < timestamp && !channel->abort) {
+ int ret = pthread_cond_timedwait(&data->cond, &data->mutex, &ts);
+ if (ret == ETIMEDOUT) {
+ fprintf(stderr, "Error: Timed out waiting for samples.\n");
+ mutexunlock(data->mutex);
+ return 1;
+ } else if (ret != 0) {
+ fprintf(stderr, "Error: pthread_cond_timedwait failed: %s\n", strerror(ret));
+ mutexunlock(data->mutex);
+ return 1;
+ } else {
+ current_timestamp = data->timestamp;
+ }
+ }
+ mutexunlock(data->mutex);
}
- mutexunlock(data->mutex);
- return;
+ return 0;
}
uint64_t shm_td_iq_channel_get_current_sample(const ShmTDIQChannel *channel)
@@ -267,9 +273,18 @@ uint64_t shm_td_iq_channel_get_current_sample(const ShmTDIQChannel *channel)
return data->timestamp;
}
-bool shm_td_iq_channel_is_connected(const ShmTDIQChannel *channel)
+void shm_td_iq_channel_abort(ShmTDIQChannel *channel)
{
- return channel->data->is_connected;
+ ShmTDIQChannelData *data = channel->data;
+ mutexlock(data->mutex);
+ channel->abort = true;
+ condbroadcast(data->cond);
+ mutexunlock(data->mutex);
+}
+
+bool shm_td_iq_channel_is_aborted(const ShmTDIQChannel *channel)
+{
+ return channel->abort;
}
void shm_td_iq_channel_destroy(ShmTDIQChannel *channel)
@@ -278,9 +293,11 @@ void shm_td_iq_channel_destroy(ShmTDIQChannel *channel)
size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * data->num_antennas_tx;
size_t rx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * data->num_antennas_rx;
size_t total_size = sizeof(ShmTDIQChannelData) + tx_buffer_size + rx_buffer_size;
- munmap(data, total_size);
if (channel->type == IQ_CHANNEL_TYPE_SERVER) {
+ munmap(data, total_size);
shm_unlink(channel->name);
+ } else {
+ munmap(data, total_size);
}
free(channel);
}
diff --git a/common/utils/shm_iq_channel/shm_td_iq_channel.h b/common/utils/shm_iq_channel/shm_td_iq_channel.h
index 7c5a730914..b71720c1f9 100644
--- a/common/utils/shm_iq_channel/shm_td_iq_channel.h
+++ b/common/utils/shm_iq_channel/shm_td_iq_channel.h
@@ -118,16 +118,27 @@ void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, uint64_t num_sam
* @brief Wait until sample at the specified timestamp is available
*
* @param channel The ShmTDIQChannel structure.
+ * @param timestamp The timestamp for which to wait.
+ * @param timeout_uS The timeout in microseconds to wait for the sample. 0 means wait indefinitely.
+ *
+ * @return 0 if the sample is available, 1 if timed out
*/
-void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp);
+int shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_t timeout_uS);
/**
- * @brief Checks if the IQ channel is connected.
+ * @brief Aborts the IQ channel causing the wait to return immediately
*
* @param channel The ShmTDIQChannel structure.
- * @return True if the channel is connected, false otherwise.
*/
-bool shm_td_iq_channel_is_connected(const ShmTDIQChannel *channel);
+void shm_td_iq_channel_abort(ShmTDIQChannel *channel);
+
+/**
+ * @brief Checks if the IQ channel is aborted.
+ *
+ * @param channel The ShmTDIQChannel structure.
+ * @return True if the channel is aborted, false otherwise.
+ */
+bool shm_td_iq_channel_is_aborted(const ShmTDIQChannel *channel);
/**
* @brief Destroys the shared memory IQ channel.
diff --git a/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c b/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c
index f5170b8144..05140a0f63 100644
--- a/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c
+++ b/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c
@@ -87,15 +87,6 @@ void server(void)
int num_ant_tx = 1;
int num_ant_rx = 1;
ShmTDIQChannel *channel = shm_td_iq_channel_create(SHM_CHANNEL_NAME, num_ant_tx, num_ant_rx);
- for (int i = 0; i < 10; i++) {
- if (shm_td_iq_channel_is_connected(channel)) {
- printf("Server connected\n");
- break;
- }
- printf("Waiting for client\n");
- sleep(1);
- }
- AssertFatal(shm_td_iq_channel_is_connected(channel), "Server failed to connect\n");
pthread_t producer_thread;
int ret = pthread_create(&producer_thread, NULL, produce_symbols, channel);
@@ -104,7 +95,7 @@ void server(void)
uint64_t timestamp = 0;
int iq_contents = 0;
while (timestamp < num_samples_per_update * num_updates) {
- shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update);
+ shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update, 0);
uint64_t target_timestamp = timestamp + num_samples_per_update;
timestamp += num_samples_per_update;
uint32_t iq_data[num_samples_per_update];
@@ -127,21 +118,12 @@ int client(void)
{
int total_errors = 0;
ShmTDIQChannel *channel = shm_td_iq_channel_connect(SHM_CHANNEL_NAME, 10);
- for (int i = 0; i < 10; i++) {
- if (shm_td_iq_channel_is_connected(channel)) {
- printf("Client connected\n");
- break;
- }
- printf("Waiting for server\n");
- sleep(1);
- }
- AssertFatal(shm_td_iq_channel_is_connected(channel), "Client failed to connect\n");
uint64_t timestamp = 0;
int iq_contents = 0;
while (timestamp < num_samples_per_update * num_updates) {
- shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update);
+ shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update, 0);
// Server starts producing from second slot
if (timestamp > num_samples_per_update) {
uint64_t target_timestamp = timestamp - num_samples_per_update;
diff --git a/common/utils/time_meas.h b/common/utils/time_meas.h
index f7c2810b60..de79a0252d 100644
--- a/common/utils/time_meas.h
+++ b/common/utils/time_meas.h
@@ -193,6 +193,7 @@ static inline void merge_meas(time_stats_t *dst_ts, const time_stats_t *src_ts)
return;
dst_ts->trials += src_ts->trials;
dst_ts->diff += src_ts->diff;
+ dst_ts->diff_square += src_ts->diff_square;
if (src_ts->max > dst_ts->max)
dst_ts->max = src_ts->max;
}
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 2b6c1dd0bb..7f46dc1517 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_boolean_option(GENERATE_DOXYGEN False "Generate source code doc using doxygen" OFF)
+add_boolean_option(GENERATE_DOXYGEN OFF "Generate source code doc using doxygen" OFF)
if(GENERATE_DOXYGEN)
find_package(Doxygen REQUIRED)
diff --git a/doc/Doxyfile b/doc/Doxyfile
index f128e3eb88..e67078a043 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -1021,7 +1021,6 @@ INPUT = \
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_ue_context.h \
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_management_procedures.h \
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_context_management_procedures.c \
-@CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_common.c \
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_decoder.h \
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_management_procedures.c \
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_handlers.h \
diff --git a/doc/README.md b/doc/README.md
index f2049bac04..9bd89480af 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -118,6 +118,7 @@ Some directories under `radio` contain READMEs:
- [IQPlayer](../radio/iqplayer/DOC/iqrecordplayer_usage.md), and [general documentation](./iqrecordplayer_usage.md)
- [fhi_72](../radio/fhi_72/README.md)
- [vrtsim](../radio/vrtsim/README.md)
+- [rf_emulator](../radio/emulator/README.md)
The other SDRs (AW2S, LimeSDR, ...) have no READMEs.
diff --git a/executables/lte-ru.c b/executables/lte-ru.c
index 326e55b288..eed5a90eb9 100644
--- a/executables/lte-ru.c
+++ b/executables/lte-ru.c
@@ -531,44 +531,6 @@ volatile late_control_e late_control=STATE_BURST_NORMAL;
/* add fail safe for late command end */
-static void *emulatedRF_thread(void *param) {
- RU_proc_t *proc = (RU_proc_t *) param;
- int microsec = 500; // length of time to sleep, in miliseconds
- int numerology = 0 ;
- struct timespec req = {0};
- req.tv_sec = 0;
- req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2;
- cpu_set_t cpuset;
- CPU_ZERO(&cpuset);
- CPU_SET(1,&cpuset);
- pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
- int policy;
- int ret;
- struct sched_param sparam;
- memset(&sparam, 0, sizeof(sparam));
- sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
- policy = SCHED_FIFO ;
- pthread_setschedparam(pthread_self(), policy, &sparam);
- wait_sync("emulatedRF_thread");
-
- while(!oai_exit) {
- nanosleep(&req, (struct timespec *)NULL);
-
- if(proc->emulate_rf_busy ) {
- LOG_E(PHY,"rf being delayed in emulated RF\n");
- }
-
- proc->emulate_rf_busy = 1;
- AssertFatal((ret=pthread_mutex_lock(&proc->mutex_emulateRF))==0,"mutex_lock returns %d\n",ret);
- ++proc->instance_cnt_emulateRF;
- pthread_cond_signal(&proc->cond_emulateRF);
- AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_emulateRF))==0,"mutex_unlock returns %d\n",ret);
- }
-
- return 0;
-}
-
-
void rx_rf(RU_t *ru,
int *frame,
int *subframe) {
@@ -586,17 +548,7 @@ void rx_rf(RU_t *ru,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
old_ts = proc->timestamp_rx;
- if(ru->emulate_rf) {
- wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
- release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
- rxs = fp->samples_per_tti;
- } else {
- rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
- &ts,
- rxp,
- fp->samples_per_tti,
- ru->nb_rx);
- }
+ rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, fp->samples_per_tti, ru->nb_rx);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
ru->south_in_cnt++;
@@ -613,11 +565,7 @@ void rx_rf(RU_t *ru,
resynch=1;
}
- if(get_softmodem_params()->emulate_rf) {
- proc->timestamp_rx = old_ts + fp->samples_per_tti;
- } else {
- proc->timestamp_rx = ts-ru->ts_offset;
- }
+ proc->timestamp_rx = ts-ru->ts_offset;
// AssertFatal(rxs == fp->samples_per_tti,
// "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs);
@@ -1229,7 +1177,6 @@ void wakeup_L1s(RU_t *ru) {
// pthread_mutex_unlock(&proc->mutex_RU);
// LOG_D(PHY,"wakeup eNB top for for subframe %d\n", ru->proc.tti_rx);
// ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.tti_rx,string);
- ru->proc.emulate_rf_busy = 0;
}
@@ -1497,7 +1444,6 @@ static void *ru_thread_tx( void *param ) {
L1_rxtx_proc_t *L1_proc;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
- char filename[256];
thread_top_init("ru_thread_tx",1,400000,500000,500000);
//CPU_SET(5, &cpuset);
//pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
@@ -1530,24 +1476,12 @@ static void *ru_thread_tx( void *param ) {
// do OFDM if needed
if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru,frame_tx,tti_tx);
- if(!(ru->emulate_rf)) { //if(!emulate_rf){
- // do outgoing fronthaul (south) if needed
- if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru,frame_tx,tti_tx,timestamp_tx);
+ // do outgoing fronthaul (south) if needed
+ if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out))
+ ru->fh_south_out(ru, frame_tx, tti_tx, timestamp_tx);
- if (ru->fh_north_out) ru->fh_north_out(ru);
- } else {
- for (int i=0; inb_tx; i++) {
- if(frame_tx == 2) {
- sprintf(filename,"txdataF%d_frame%d_sf%d.m",i,frame_tx,tti_tx);
- LOG_M(filename,"txdataF_frame",ru->common.txdataF_BF[i],fp->symbols_per_tti*fp->ofdm_symbol_size, 1, 1);
- }
-
- if(frame_tx == 2 && tti_tx==0) {
- sprintf(filename,"txdata%d_frame%d.m",i,frame_tx);
- LOG_M(filename,"txdata_frame",ru->common.txdata[i],fp->samples_per_tti*10, 1, 1);
- }
- }
- }
+ if (ru->fh_north_out)
+ ru->fh_north_out(ru);
LOG_D(PHY,"ru_thread_tx: releasing RU TX in %d.%d\n", frame_tx, tti_tx);
release_thread(&proc->mutex_eNBs,&proc->instance_cnt_eNBs,"ru_thread_tx");
@@ -1612,7 +1546,6 @@ static void *ru_thread( void *param ) {
int ret;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
- char filename[256];
// set default return value
#if defined(PRE_SCD_THREAD)
dlsch_ue_select_tbl_in_use = 1;
@@ -1625,21 +1558,7 @@ static void *ru_thread( void *param ) {
LOG_I(PHY,"thread ru created id=%ld\n", syscall(__NR_gettid));
LOG_I(PHY,"Starting RU %d (%s,%s),\n", ru->idx, NB_functions[ru->function], NB_timing[ru->if_timing]);
- if(get_softmodem_params()->emulate_rf) {
- phy_init_RU(ru);
-
- if (setup_RU_buffers(ru)!=0) {
- LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n");
- exit(-1);
- }
-
- LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx);
- AssertFatal((ret=pthread_mutex_lock(ru->ru_mutex))==0,"mutex_lock returns %d\n",ret);
- *ru->ru_mask &= ~(1<idx);
- pthread_cond_signal(ru->ru_cond);
- AssertFatal((ret=pthread_mutex_unlock(ru->ru_mutex))==0,"mutex_unlock returns %d\n",ret);
- ru->state = RU_RUN;
- } else if (ru->has_ctrl_prt == 0) {
+ if (ru->has_ctrl_prt == 0) {
// There is no control port: start everything here
LOG_I(PHY, "RU %d has no OAI ctrl port\n",ru->idx);
@@ -1695,18 +1614,22 @@ static void *ru_thread( void *param ) {
} else wait_sync("ru_thread");
LOG_D(PHY,"RU %d: Got start from control thread\n",ru->idx);
- if(!(ru->emulate_rf)) {
- if (ru->is_slave == 0) AssertFatal(ru->state == RU_RUN,"ru-%d state = %s != RU_RUN\n",ru->idx,ru_states[ru->state]);
- else if (ru->is_slave == 1) AssertFatal(ru->state == RU_SYNC || ru->state == RU_RUN ||
- ru->state == RU_CHECK_SYNC,"ru %d state = %s != RU_SYNC or RU_RUN or RU_CHECK_SYNC\n",ru->idx,ru_states[ru->state]);
+ if (ru->is_slave == 0)
+ AssertFatal(ru->state == RU_RUN, "ru-%d state = %s != RU_RUN\n", ru->idx, ru_states[ru->state]);
+ else if (ru->is_slave == 1)
+ AssertFatal(ru->state == RU_SYNC || ru->state == RU_RUN || ru->state == RU_CHECK_SYNC,
+ "ru %d state = %s != RU_SYNC or RU_RUN or RU_CHECK_SYNC\n",
+ ru->idx,
+ ru_states[ru->state]);
- // Start RF device if any
- if (ru->start_rf) {
- if (ru->start_rf(ru) != 0)
- AssertFatal(1==0,"Could not start the RF device\n");
- else LOG_I(PHY,"RU %d rf device ready\n",ru->idx);
- } else LOG_D(PHY,"RU %d no rf device\n",ru->idx);
- }
+ // Start RF device if any
+ if (ru->start_rf) {
+ if (ru->start_rf(ru) != 0)
+ AssertFatal(1 == 0, "Could not start the RF device\n");
+ else
+ LOG_I(PHY, "RU %d rf device ready\n", ru->idx);
+ } else
+ LOG_D(PHY, "RU %d no rf device\n", ru->idx);
// if an asnych_rxtx thread exists
// wakeup the thread because the devices are ready at this point
@@ -1864,26 +1787,13 @@ static void *ru_thread( void *param ) {
// do OFDM if needed
if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru, proc->frame_tx, proc->tti_tx);
- if(!(ru->emulate_rf)) { //if(!emulate_rf){
- // do outgoing fronthaul (south) if needed
- if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru, proc->frame_tx, proc->tti_tx, proc->timestamp_tx);
+ // do outgoing fronthaul (south) if needed
+ if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out))
+ ru->fh_south_out(ru, proc->frame_tx, proc->tti_tx, proc->timestamp_tx);
- if ((ru->fh_north_out) && (ru->state!=RU_CHECK_SYNC)) ru->fh_north_out(ru);
- } else {
- for (int i=0; inb_tx; i++) {
- if(proc->frame_tx == 2) {
- sprintf(filename,"txdataF%d_frame%d_sf%d.m",i,proc->frame_tx,proc->tti_tx);
- LOG_M(filename,"txdataF_frame",ru->common.txdataF_BF[i],ru->frame_parms->symbols_per_tti*ru->frame_parms->ofdm_symbol_size, 1, 1);
- }
+ if ((ru->fh_north_out) && (ru->state != RU_CHECK_SYNC))
+ ru->fh_north_out(ru);
- if(proc->frame_tx == 2 && proc->tti_tx==0) {
- sprintf(filename,"txdata%d_frame%d.m",i,proc->frame_tx);
- LOG_M(filename,"txdata_frame",ru->common.txdata[i],ru->frame_parms->samples_per_tti*10, 1, 1);
- }
- }
- }
-
- proc->emulate_rf_busy = 0;
}
#else
@@ -1903,12 +1813,11 @@ static void *ru_thread( void *param ) {
LOG_I(PHY, "Exiting ru_thread \n");
- if (!(ru->emulate_rf)) {
- if (ru->stop_rf != NULL) {
- if (ru->stop_rf(ru) != 0)
- LOG_E(HW,"Could not stop the RF device\n");
- else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx);
- }
+ if (ru->stop_rf != NULL) {
+ if (ru->stop_rf(ru) != 0)
+ LOG_E(HW, "Could not stop the RF device\n");
+ else
+ LOG_I(PHY, "RU %d rf device stopped\n", ru->idx);
}
return NULL;
@@ -2128,12 +2037,12 @@ static void *rf_tx( void *param ) {
// do OFDM if needed
if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru,proc->frame_tx,proc->tti_tx);
- if(!ru->emulate_rf) {
- // do outgoing fronthaul (south) if needed
- if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru,proc->frame_tx,proc->tti_tx,proc->timestamp_tx);
+ // do outgoing fronthaul (south) if needed
+ if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out))
+ ru->fh_south_out(ru, proc->frame_tx, proc->tti_tx, proc->timestamp_tx);
- if (ru->fh_north_out) ru->fh_north_out(ru);
- }
+ if (ru->fh_north_out)
+ ru->fh_north_out(ru);
}
if (release_thread(&proc->mutex_rf_tx,&proc->instance_cnt_rf_tx,"rf_tx") < 0) break;
@@ -2205,7 +2114,7 @@ int start_write_thread(RU_t *ru) {
void init_RU_proc(RU_t *ru) {
int i=0;
RU_proc_t *proc;
- pthread_attr_t *attr_FH=NULL, *attr_FH1=NULL, *attr_prach=NULL, *attr_asynch=NULL, *attr_synch=NULL, *attr_emulateRF=NULL, *attr_ctrl=NULL, *attr_prach_br=NULL;
+ pthread_attr_t *attr_FH=NULL, *attr_FH1=NULL, *attr_prach=NULL, *attr_asynch=NULL, *attr_synch=NULL, *attr_ctrl=NULL, *attr_prach_br=NULL;
//pthread_attr_t *attr_fep=NULL;
LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]);
proc = &ru->proc;
@@ -2215,7 +2124,6 @@ void init_RU_proc(RU_t *ru) {
proc->instance_cnt_synch = -1;
proc->instance_cnt_FH = -1;
proc->instance_cnt_FH1 = -1;
- proc->instance_cnt_emulateRF = -1;
proc->instance_cnt_asynch_rxtx = -1;
proc->instance_cnt_ru = -1;
proc->instance_cnt_eNBs = -1;
@@ -2232,20 +2140,17 @@ void init_RU_proc(RU_t *ru) {
pthread_mutex_init( &proc->mutex_synch,NULL);
pthread_mutex_init( &proc->mutex_FH,NULL);
pthread_mutex_init( &proc->mutex_FH1,NULL);
- pthread_mutex_init( &proc->mutex_emulateRF,NULL);
pthread_mutex_init( &proc->mutex_eNBs, NULL);
pthread_mutex_init( &proc->mutex_ru,NULL);
pthread_cond_init( &proc->cond_prach, NULL);
pthread_cond_init( &proc->cond_FH, NULL);
pthread_cond_init( &proc->cond_FH1, NULL);
- pthread_cond_init( &proc->cond_emulateRF, NULL);
pthread_cond_init( &proc->cond_asynch_rxtx, NULL);
pthread_cond_init( &proc->cond_synch,NULL);
pthread_cond_init( &proc->cond_eNBs, NULL);
pthread_cond_init( &proc->cond_ru_thread,NULL);
pthread_attr_init( &proc->attr_FH);
pthread_attr_init( &proc->attr_FH1);
- pthread_attr_init( &proc->attr_emulateRF);
pthread_attr_init( &proc->attr_prach);
pthread_attr_init( &proc->attr_synch);
pthread_attr_init( &proc->attr_asynch_rxtx);
@@ -2289,9 +2194,6 @@ void init_RU_proc(RU_t *ru) {
pthread_create( &proc->pthread_rf_tx, NULL, rf_tx, (void *)ru );
#endif
- if (ru->emulate_rf)
- pthread_create( &proc->pthread_emulateRF, attr_emulateRF, emulatedRF_thread, (void *)proc );
-
if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)
pthread_create( &proc->pthread_FH1, attr_FH1, ru_thread_tx, (void *)ru );
diff --git a/executables/lte-softmodem.c b/executables/lte-softmodem.c
index 6a7e607586..25a3c25aa9 100644
--- a/executables/lte-softmodem.c
+++ b/executables/lte-softmodem.c
@@ -138,7 +138,6 @@ RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mas
RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mask,pthread_mutex_t *ru_mutex,pthread_cond_t *ru_cond);
int transmission_mode=1;
-int emulate_rf = 0;
int numerology = 0;
THREAD_STRUCT thread_struct;
@@ -204,55 +203,6 @@ void nr_slot_select() {};
void NR_UL_indication(NR_UL_IND_t *UL_INFO) {};
void gNB_dlsch_ulsch_scheduler() {};
-/*---------------------BMC: timespec helpers -----------------------------*/
-
-struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
-struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
-
-struct timespec clock_difftime(struct timespec start, struct timespec end) {
- struct timespec temp;
-
- if ((end.tv_nsec-start.tv_nsec)<0) {
- temp.tv_sec = end.tv_sec-start.tv_sec-1;
- temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
- } else {
- temp.tv_sec = end.tv_sec-start.tv_sec;
- temp.tv_nsec = end.tv_nsec-start.tv_nsec;
- }
-
- return temp;
-}
-
-void print_difftimes(void) {
-#ifdef DEBUG
- printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
-#else
- LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
-#endif
-}
-
-void update_difftimes(struct timespec start, struct timespec end) {
- struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 };
- int changed = 0;
- diff_time = clock_difftime(start, end);
-
- if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) {
- min_diff_time.tv_nsec = diff_time.tv_nsec;
- changed = 1;
- }
-
- if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) {
- max_diff_time.tv_nsec = diff_time.tv_nsec;
- changed = 1;
- }
-
-#if 1
-
- if (changed) print_difftimes();
-
-#endif
-}
-
/*------------------------------------------------------------------------*/
unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) {
diff --git a/executables/lte-softmodem.h b/executables/lte-softmodem.h
index 8c55f0dc65..db6136c351 100644
--- a/executables/lte-softmodem.h
+++ b/executables/lte-softmodem.h
@@ -127,7 +127,6 @@ extern int sync_var;
extern int transmission_mode;
extern double cpuf;
-extern int emulate_rf;
extern int numerology;
extern int usrp_tx_thread;
diff --git a/executables/lte-uesoftmodem.c b/executables/lte-uesoftmodem.c
index ea48edd801..b212ceb3f1 100644
--- a/executables/lte-uesoftmodem.c
+++ b/executables/lte-uesoftmodem.c
@@ -174,55 +174,6 @@ instance_t CUuniqInstance=0;
/* forward declarations */
void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]);
-/*---------------------BMC: timespec helpers -----------------------------*/
-
-struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
-struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
-
-struct timespec clock_difftime(struct timespec start, struct timespec end) {
- struct timespec temp;
-
- if ((end.tv_nsec-start.tv_nsec)<0) {
- temp.tv_sec = end.tv_sec-start.tv_sec-1;
- temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
- } else {
- temp.tv_sec = end.tv_sec-start.tv_sec;
- temp.tv_nsec = end.tv_nsec-start.tv_nsec;
- }
-
- return temp;
-}
-
-void print_difftimes(void) {
-#ifdef DEBUG
- printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
-#else
- LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
-#endif
-}
-
-void update_difftimes(struct timespec start, struct timespec end) {
- struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 };
- int changed = 0;
- diff_time = clock_difftime(start, end);
-
- if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) {
- min_diff_time.tv_nsec = diff_time.tv_nsec;
- changed = 1;
- }
-
- if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) {
- max_diff_time.tv_nsec = diff_time.tv_nsec;
- changed = 1;
- }
-
-#if 1
-
- if (changed) print_difftimes();
-
-#endif
-}
-
/*------------------------------------------------------------------------*/
unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) {
@@ -384,7 +335,8 @@ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
}
}
-void init_openair0(LTE_DL_FRAME_PARMS *frame_parms,int rxgain) {
+static void init_openair0(LTE_DL_FRAME_PARMS *frame_parms, int rxgain)
+{
int card;
int i;
diff --git a/executables/nr-cuup.c b/executables/nr-cuup.c
index 6467683cac..403f78ddb3 100644
--- a/executables/nr-cuup.c
+++ b/executables/nr-cuup.c
@@ -37,7 +37,6 @@ RAN_CONTEXT_t RC;
THREAD_STRUCT thread_struct;
uint64_t downlink_frequency[MAX_NUM_CCs][4];
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
-int asn1_xer_print;
int oai_exit = 0;
instance_t CUuniqInstance = 0;
diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c
index 345b58df7e..24870544b8 100644
--- a/executables/nr-gnb.c
+++ b/executables/nr-gnb.c
@@ -231,6 +231,9 @@ static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size
output += print_meas_log(&gNB->dlsch_resource_mapping_stats, "DLSCH resource mapping", NULL, NULL, output,end-output);
output += print_meas_log(&gNB->dlsch_precoding_stats, "DLSCH precoding", NULL, NULL, output,end-output);
output += print_meas_log(&gNB->phy_proc_rx, "L1 Rx processing", NULL, NULL, output, end - output);
+ output += print_meas_log(&gNB->ts_deinterleave, "UL segment deinterleaving", NULL, NULL, output, end - output);
+ output += print_meas_log(&gNB->ts_rate_unmatch, "UL segment rate recovery", NULL, NULL, output, end - output);
+ output += print_meas_log(&gNB->ts_ldpc_decode, "UL segments decoding", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->ul_indication_stats, "UL Indication", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->slot_indication_stats, "Slot Indication", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL, output, end - output);
@@ -288,6 +291,9 @@ void *nrL1_stats_thread(void *param) {
reset_meas(&gNB->phy_proc_tx);
reset_meas(&gNB->dlsch_encoding_stats);
reset_meas(&gNB->phy_proc_rx);
+ reset_meas(&gNB->ts_deinterleave);
+ reset_meas(&gNB->ts_rate_unmatch);
+ reset_meas(&gNB->ts_ldpc_decode);
reset_meas(&gNB->ul_indication_stats);
reset_meas(&gNB->slot_indication_stats);
reset_meas(&gNB->rx_pusch_stats);
diff --git a/executables/nr-ru.c b/executables/nr-ru.c
index c0da88e634..de3a4b7875 100644
--- a/executables/nr-ru.c
+++ b/executables/nr-ru.c
@@ -63,7 +63,6 @@ static int DEFRUTPCORES[] = {-1,-1,-1,-1};
#include
-
#include "T.h"
#include "nfapi_interface.h"
#include
@@ -74,63 +73,69 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg);
/*************************************************************/
/* Functions to attach and configure RRU */
-int attach_rru(RU_t *ru) {
- ssize_t msg_len,len;
+int attach_rru(RU_t *ru)
+{
RRU_CONFIG_msg_t rru_config_msg;
int received_capabilities=0;
wait_gNBs();
// Wait for capabilities
while (received_capabilities==0) {
- memset((void *)&rru_config_msg,0,sizeof(rru_config_msg));
- rru_config_msg.type = RAU_tick;
- rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE;
+ rru_config_msg = (RRU_CONFIG_msg_t){.type = RAU_tick, .len = sizeof(rru_config_msg.msg)};
LOG_D(PHY, "Sending RAU tick to RRU %d\n", ru->idx);
AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
"RU %d cannot access remote radio\n",ru->idx);
- msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
-
+ ssize_t msg_len = rru_config_msg.len + sizeof(RRU_capabilities_t);
// wait for answer with timeout
- if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
- &rru_config_msg,
- msg_len))<0) {
+ ssize_t len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, &rru_config_msg, msg_len);
+ if (len < 0) {
LOG_D(PHY, "Waiting for RRU %d\n", ru->idx);
} else if (rru_config_msg.type == RRU_capabilities) {
- AssertFatal(rru_config_msg.len==msg_len,"Received capabilities with incorrect length (%d!=%d)\n",(int)rru_config_msg.len,(int)msg_len);
- LOG_I(PHY,"Received capabilities from RRU %d (len %d/%d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",ru->idx,
- (int)rru_config_msg.len,(int)msg_len,
- ((RRU_capabilities_t *)&rru_config_msg.msg[0])->num_bands,
- ((RRU_capabilities_t *)&rru_config_msg.msg[0])->max_pdschReferenceSignalPower[0],
- ((RRU_capabilities_t *)&rru_config_msg.msg[0])->max_rxgain[0],
- ((RRU_capabilities_t *)&rru_config_msg.msg[0])->nb_tx[0],
- ((RRU_capabilities_t *)&rru_config_msg.msg[0])->nb_rx[0]);
+ AssertFatal(rru_config_msg.len == msg_len,
+ "Received capabilities with incorrect length (%ld!=%ld)\n",
+ rru_config_msg.len,
+ msg_len);
+ RRU_capabilities_t *cap = (RRU_capabilities_t *)rru_config_msg.msg;
+ LOG_I(PHY,
+ "Received capabilities from RRU %d (len %ld/%ld, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx "
+ "%d, nb_rx %d)\n",
+ ru->idx,
+ rru_config_msg.len,
+ msg_len,
+ cap->num_bands,
+ cap->max_pdschReferenceSignalPower[0],
+ cap->max_rxgain[0],
+ cap->nb_tx[0],
+ cap->nb_rx[0]);
received_capabilities=1;
} else {
LOG_E(PHY,"Received incorrect message %d from RRU %d\n",rru_config_msg.type,ru->idx);
}
}
- configure_ru(ru, (RRU_capabilities_t *)&rru_config_msg.msg[0]);
+ configure_ru(ru, (RRU_capabilities_t *)rru_config_msg.msg);
rru_config_msg.type = RRU_config;
rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t);
- LOG_I(PHY,"Sending Configuration to RRU %d (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n",ru->idx,
- ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands,
- ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]);
+ RRU_config_t *conf = (RRU_config_t *)rru_config_msg.msg;
+ LOG_I(PHY,
+ "Sending Configuration to RRU %d (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL "
+ "%d,3/4FS %d, prach_FO %d, prach_CI %d)\n",
+ ru->idx,
+ conf->num_bands,
+ conf->band_list[0],
+ conf->tx_freq[0],
+ conf->rx_freq[0],
+ conf->att_tx[0],
+ conf->att_rx[0],
+ conf->N_RB_DL[0],
+ conf->N_RB_UL[0],
+ conf->threequarter_fs[0],
+ conf->prach_FreqOffset[0],
+ conf->prach_ConfigIndex[0]);
AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
"RU %d failed send configuration to remote radio\n",ru->idx);
-
- if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
- &rru_config_msg,
- msg_len))<0) {
+ int len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, &rru_config_msg, sizeof(rru_config_msg.msg));
+ if (len < 0) {
LOG_I(PHY,"Waiting for RRU %d\n",ru->idx);
} else if (rru_config_msg.type == RRU_config_ok) {
LOG_I(PHY, "RRU_config_ok received\n");
@@ -142,58 +147,57 @@ int attach_rru(RU_t *ru) {
}
int connect_rau(RU_t *ru) {
- RRU_CONFIG_msg_t rru_config_msg;
- ssize_t msg_len;
- int tick_received = 0;
- int configuration_received = 0;
- RRU_capabilities_t *cap;
- int i;
- int len;
+ RRU_CONFIG_msg_t rru_config_msg;
// wait for RAU_tick
+ int tick_received = 0;
while (tick_received == 0) {
- msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE;
-
- if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
- &rru_config_msg,
- msg_len))<0) {
+ ssize_t msg_len = sizeof(rru_config_msg.msg);
+ int len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, &rru_config_msg, msg_len);
+ if (len < 0) {
LOG_I(PHY,"Waiting for RAU\n");
} else {
if (rru_config_msg.type == RAU_tick) {
LOG_I(PHY,"Tick received from RAU\n");
tick_received = 1;
- } else LOG_E(PHY,"Received erroneous message (%d)from RAU, expected RAU_tick\n",rru_config_msg.type);
+ } else
+ LOG_E(PHY, "Received erroneous message (%d)from RAU, expected RAU_tick\n", rru_config_msg.type);
}
}
// send capabilities
rru_config_msg.type = RRU_capabilities;
rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
- cap = (RRU_capabilities_t *)&rru_config_msg.msg[0];
- LOG_I(PHY,"Sending Capabilities (len %d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",
- (int)rru_config_msg.len,ru->num_bands,ru->max_pdschReferenceSignalPower,ru->max_rxgain,ru->nb_tx,ru->nb_rx);
+ RRU_capabilities_t *cap = (RRU_capabilities_t *)rru_config_msg.msg;
+ LOG_I(PHY,
+ "Sending Capabilities (len %ld, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",
+ rru_config_msg.len,
+ ru->num_bands,
+ ru->max_pdschReferenceSignalPower,
+ ru->max_rxgain,
+ ru->nb_tx,
+ ru->nb_rx);
switch (ru->function) {
case NGFI_RRU_IF4p5:
- cap->FH_fmt = OAI_IF4p5_only;
+ cap->FH_fmt = OAI_IF4p5_only;
break;
case NGFI_RRU_IF5:
- cap->FH_fmt = OAI_IF5_only;
+ cap->FH_fmt = OAI_IF5_only;
break;
case MBP_RRU_IF5:
- cap->FH_fmt = MBP_IF5;
+ cap->FH_fmt = MBP_IF5;
break;
default:
- AssertFatal(1==0,"RU_function is unknown %d\n",RC.ru[0]->function);
+ AssertFatal(false, "RU_function is unknown %d\n", RC.ru[0]->function);
break;
}
- cap->num_bands = ru->num_bands;
-
- for (i=0; inum_bands; i++) {
+ cap->num_bands = ru->num_bands;
+ for (int i = 0; i < ru->num_bands; i++) {
LOG_I(PHY,"Band %d: nb_rx %d nb_tx %d pdschReferenceSignalPower %d rxgain %d\n",
ru->band[i],ru->nb_rx,ru->nb_tx,ru->max_pdschReferenceSignalPower,ru->max_rxgain);
cap->band_list[i] = ru->band[i];
@@ -208,25 +212,28 @@ int connect_rau(RU_t *ru) {
// wait for configuration
rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t);
+ int configuration_received = 0;
while (configuration_received == 0) {
- if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
- &rru_config_msg,
- rru_config_msg.len))<0) {
+ int len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, &rru_config_msg, rru_config_msg.len);
+ if (len < 0) {
LOG_I(PHY,"Waiting for configuration from RAU\n");
} else {
- LOG_I(PHY,"Configuration received from RAU (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n",
- ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands,
- ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0],
- ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]);
- configure_rru(ru, (void *)&rru_config_msg.msg[0]);
+ RRU_config_t *conf = (RRU_config_t *)rru_config_msg.msg;
+ LOG_I(PHY,
+ "Configuration received from RAU (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL "
+ "%d,3/4FS %d, prach_FO %d, prach_CI %d)\n",
+ conf->num_bands,
+ conf->band_list[0],
+ conf->tx_freq[0],
+ conf->rx_freq[0],
+ conf->att_tx[0],
+ conf->att_rx[0],
+ conf->N_RB_DL[0],
+ conf->N_RB_UL[0],
+ conf->threequarter_fs[0],
+ conf->prach_FreqOffset[0],
+ conf->prach_ConfigIndex[0]);
+ configure_rru(ru, (void *)rru_config_msg.msg);
configuration_received = 1;
}
}
@@ -238,15 +245,23 @@ int connect_rau(RU_t *ru) {
// southbound IF5 fronthaul for 16-bit OAI format
void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
- if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
+ if (ru == RC.ru[0])
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx & 0xffffffff);
int offset = ru->nr_frame_parms->get_samples_slot_timestamp(slot,ru->nr_frame_parms,0);
void *buffs[ru->nb_tx];
for (int aid = 0; aid < ru->nb_tx; aid++)
buffs[aid] = (void*)&ru->common.txdata[aid][offset];
struct timespec txmeas;
clock_gettime(CLOCK_MONOTONIC, &txmeas);
- LOG_D(NR_PHY,"IF5 TX %d.%d, TS %llu, buffs[0] %p, buffs[1] %p ener0 %f dB, tx start %d\n",frame,slot,(unsigned long long)timestamp,buffs[0],buffs[1],
- 10*log10((double)signal_energy(buffs[0],ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms))),(int)txmeas.tv_nsec);
+ LOG_D(NR_PHY,
+ "IF5 TX %d.%d, TS %lu, buffs[0] %p, buffs[1] %p ener0 %f dB, tx start %d\n",
+ frame,
+ slot,
+ timestamp,
+ buffs[0],
+ buffs[1],
+ 10 * log10((double)signal_energy(buffs[0], ru->nr_frame_parms->get_samples_per_slot(slot, ru->nr_frame_parms))),
+ (int)txmeas.tv_nsec);
ru->ifdevice.trx_write_func2(&ru->ifdevice,
timestamp,
buffs,
@@ -258,13 +273,12 @@ void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
// southbound IF4p5 fronthaul
void fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
- nfapi_nr_config_request_scf_t *cfg = &ru->config;
-
- if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
+ if (ru == RC.ru[0])
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx & 0xffffffff);
LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.tti_tx);
- if ((nr_slot_select(cfg,ru->proc.frame_tx,ru->proc.tti_tx)&NR_DOWNLINK_SLOT) > 0)
+ if ((nr_slot_select(&ru->config, ru->proc.frame_tx, ru->proc.tti_tx) & NR_DOWNLINK_SLOT) > 0)
send_IF4p5(ru,frame, slot, IF4p5_PDLFFT);
}
@@ -281,11 +295,11 @@ void fh_if5_south_in(RU_t *ru,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF5, 1 );
start_meas(&ru->rx_fhaul);
- ru->ifdevice.trx_read_func2(&ru->ifdevice,&proc->timestamp_rx,NULL,fp->get_samples_per_slot(*tti,fp));
- if (proc->first_rx == 1) ru->ts_offset = proc->timestamp_rx;
- proc->frame_rx = ((proc->timestamp_rx-ru->ts_offset) / (fp->samples_per_subframe*10))&1023;
- proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx-ru->ts_offset,fp);
-
+ ru->ifdevice.trx_read_func2(&ru->ifdevice, &proc->timestamp_rx, NULL, fp->get_samples_per_slot(*tti, fp));
+ if (proc->first_rx == 1)
+ ru->ts_offset = proc->timestamp_rx;
+ proc->frame_rx = ((proc->timestamp_rx - ru->ts_offset) / (fp->samples_per_subframe * 10)) & 1023;
+ proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx - ru->ts_offset, fp);
if (proc->first_rx == 0) {
if (proc->tti_rx != *tti) {
@@ -311,8 +325,26 @@ void fh_if5_south_in(RU_t *ru,
struct timespec rxmeas;
clock_gettime(CLOCK_MONOTONIC, &rxmeas);
double fhtime = ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0);
- if (fhtime > 800) LOG_W(PHY,"IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %d\n",*frame,*tti,proc->frame_rx,proc->tti_rx,proc->first_rx,ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0),(int)rxmeas.tv_nsec);
- else LOG_D(PHY,"IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %d\n",*frame,*tti,proc->frame_rx,proc->tti_rx,proc->first_rx,ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0),(int)rxmeas.tv_nsec);
+ if (fhtime > 800)
+ LOG_W(PHY,
+ "IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %ld\n",
+ *frame,
+ *tti,
+ proc->frame_rx,
+ proc->tti_rx,
+ proc->first_rx,
+ ru->rx_fhaul.p_time / (cpu_freq_GHz * 1000.0),
+ rxmeas.tv_nsec);
+ else
+ LOG_D(PHY,
+ "IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %ld\n",
+ *frame,
+ *tti,
+ proc->frame_rx,
+ proc->tti_rx,
+ proc->first_rx,
+ ru->rx_fhaul.p_time / (cpu_freq_GHz * 1000.0),
+ rxmeas.tv_nsec);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF5, 0 );
@@ -329,21 +361,16 @@ void fh_if4p5_south_in(RU_t *ru,
uint32_t symbol_number=0;
uint32_t symbol_mask_full=0;
- /*
- if ((fp->frame_type == TDD) && (subframe_select(fp,*slot)==SF_S))
- symbol_mask_full = (1<ul_symbols_in_S_subframe)-1;
- else
- symbol_mask_full = (1<symbols_per_slot)-1;
-
- AssertFatal(proc->symbol_mask[*slot]==0,"rx_fh_if4p5: proc->symbol_mask[%d] = %x\n",*slot,proc->symbol_mask[*slot]);*/
do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
recv_IF4p5(ru, &f, &sl, &packet_type, &symbol_number);
if (packet_type == IF4p5_PULFFT) proc->symbol_mask[sl] = proc->symbol_mask[sl] | (1<first_rx==0) && (f!=*frame)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received frame %d != expected %d\n",f,*frame);
+ if ((proc->first_rx == 0) && (f != *frame))
+ LOG_E(PHY, "rx_fh_if4p5: PULTICK received frame %d != expected %d\n", f, *frame);
- if ((proc->first_rx==0) && (sl!=*slot)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received subframe %d != expected %d (first_rx %d)\n",sl,*slot,proc->first_rx);
+ if ((proc->first_rx == 0) && (sl != *slot))
+ LOG_E(PHY, "rx_fh_if4p5: PULTICK received subframe %d != expected %d (first_rx %d)\n", sl, *slot, proc->first_rx);
break;
} else if (packet_type == IF4p5_PRACH) {
@@ -359,7 +386,7 @@ void fh_if4p5_south_in(RU_t *ru,
proc->timestamp_rx = (proc->frame_rx * fp->samples_per_subframe * 10) + fp->get_samples_slot_timestamp(proc->tti_rx, fp, 0);
// proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_subframe);
proc->tti_tx = (sl+ru->sl_ahead)%fp->slots_per_frame;
- proc->frame_tx = (sl>(fp->slots_per_frame-1-(ru->sl_ahead))) ? (f+1)&1023 : f;
+ proc->frame_tx = (sl > (fp->slots_per_frame - 1 - (ru->sl_ahead))) ? (f + 1) & 1023 : f;
if (proc->first_rx == 0) {
if (proc->tti_rx != *slot) {
@@ -394,20 +421,12 @@ void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *slot) {
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
RU_proc_t *proc = &ru->proc;
uint16_t packet_type;
- uint32_t symbol_number,symbol_mask,prach_rx;
- // uint32_t got_prach_info=0;
- symbol_number = 0;
- symbol_mask = (1<<(fp->symbols_per_slot))-1;
- prach_rx = 0;
+ uint32_t symbol_number = 0;
+ uint32_t symbol_mask = (1 << fp->symbols_per_slot) - 1;
+ uint32_t prach_rx = 0;
do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
recv_IF4p5(ru, &proc->frame_rx, &proc->tti_rx, &packet_type, &symbol_number);
-
- // grab first prach information for this new subframe
- /*if (got_prach_info==0) {
- prach_rx = is_prach_subframe(fp, proc->frame_rx, proc->tti_rx);
- got_prach_info = 1;
- }*/
if (proc->first_rx != 0) {
*frame = proc->frame_rx;
*slot = proc->tti_rx;
@@ -417,22 +436,19 @@ void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *slot) {
LOG_E(PHY,"frame_rx %d is not what we expect %d\n",proc->frame_rx,*frame);
exit_fun("Exiting");
}
-
if (proc->tti_rx != *slot) {
LOG_E(PHY,"tti_rx %d is not what we expect %d\n",proc->tti_rx,*slot);
exit_fun("Exiting");
}
}
- if (packet_type == IF4p5_PULFFT) symbol_mask &= (~(1< 0) || (prach_rx >0)); // haven't received all PUSCH symbols and PRACH information
+ if (packet_type == IF4p5_PULFFT)
+ symbol_mask &= ~(1 << symbol_number);
+ else if (packet_type == IF4p5_PRACH)
+ prach_rx &= ~0x1;
+ } while (symbol_mask > 0 || prach_rx > 0); // haven't received all PUSCH symbols and PRACH information
}
-
-
-
-
/*************************************************************/
/* Input Fronthaul from North RRU */
@@ -459,26 +475,9 @@ void fh_if4p5_north_in(RU_t *ru,int *frame,int *slot) {
}
}
-void fh_if5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
- NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
- RU_proc_t *proc = &ru->proc;
- int tti_tx,frame_tx;
- openair0_timestamp timestamp_tx = 0;
+void fh_if5_north_asynch_in(RU_t *ru, int *frame, int *slot)
+{
AssertFatal(1 == 0, "Shouldn't get here\n");
- frame_tx = (timestamp_tx / (fp->samples_per_subframe*10))&1023;
- uint32_t idx_sf = timestamp_tx / fp->samples_per_subframe;
- tti_tx = (idx_sf * fp->slots_per_subframe + (int)round((float)(timestamp_tx % fp->samples_per_subframe) / fp->samples_per_slot0))%(fp->slots_per_frame);
-
- if (proc->first_tx != 0) {
- *slot = tti_tx;
- *frame = frame_tx;
- proc->first_tx = 0;
- } else {
- AssertFatal(tti_tx == *slot,
- "tti_tx %d is not what we expect %d\n",tti_tx,*slot);
- AssertFatal(frame_tx == *frame,
- "frame_tx %d is not what we expect %d\n",frame_tx,*frame);
- }
}
void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
@@ -486,17 +485,18 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
nfapi_nr_config_request_scf_t *cfg = &ru->config;
RU_proc_t *proc = &ru->proc;
uint16_t packet_type;
- uint32_t symbol_number,symbol_mask,symbol_mask_full=0;
+ uint32_t symbol_mask_full = 0;
int slot_tx,frame_tx;
LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru);
- symbol_number = 0;
- symbol_mask = 0;
+ uint32_t symbol_number = 0;
+ uint32_t symbol_mask = 0;
// symbol_mask_full = ((subframe_select(fp,*slot) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_slot))-1;
do {
recv_IF4p5(ru, &frame_tx, &slot_tx, &packet_type, &symbol_number);
- if (((nr_slot_select(cfg,frame_tx,slot_tx) & NR_DOWNLINK_SLOT) > 0) && (symbol_number == 0)) start_meas(&ru->rx_fhaul);
+ if (((nr_slot_select(cfg, frame_tx, slot_tx) & NR_DOWNLINK_SLOT) > 0) && (symbol_number == 0))
+ start_meas(&ru->rx_fhaul);
LOG_D(PHY,"slot %d (%d): frame %d, slot %d, symbol %d\n",
*slot,nr_slot_select(cfg,frame_tx,*slot),frame_tx,slot_tx,symbol_number);
@@ -505,7 +505,6 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
*frame = frame_tx;
*slot = slot_tx;
proc->first_tx = 0;
- //symbol_mask_full = ((subframe_select(fp,*slot) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_slot))-1;
} else {
AssertFatal(frame_tx == *frame,
"frame_tx %d is not what we expect %d\n",frame_tx,*frame);
@@ -515,18 +514,22 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
if (packet_type == IF4p5_PDLFFT) {
symbol_mask = symbol_mask | (1<0) stop_meas(&ru->rx_fhaul);
+ if ((nr_slot_select(cfg, frame_tx, slot_tx) & NR_DOWNLINK_SLOT) > 0)
+ stop_meas(&ru->rx_fhaul);
proc->tti_tx = slot_tx;
proc->frame_tx = frame_tx;
- if ((frame_tx == 0)&&(slot_tx == 0)) proc->frame_tx_unwrap += 1024;
+ if (frame_tx == 0 && slot_tx == 0)
+ proc->frame_tx_unwrap += 1024;
- proc->timestamp_tx = (((uint64_t)frame_tx + (uint64_t)proc->frame_tx_unwrap) * fp->samples_per_subframe * 10) + fp->get_samples_slot_timestamp(slot_tx, fp, 0);
- LOG_D(PHY,"RU %d/%d TST %llu, frame %d, subframe %d\n",ru->idx,0,(long long unsigned int)proc->timestamp_tx,frame_tx,slot_tx);
+ proc->timestamp_tx =
+ ((uint64_t)frame_tx + proc->frame_tx_unwrap) * fp->samples_per_subframe * 10 + fp->get_samples_slot_timestamp(slot_tx, fp, 0);
+ LOG_D(PHY, "RU %d/%d TST %lu, frame %d, subframe %d\n", ru->idx, 0, proc->timestamp_tx, frame_tx, slot_tx);
// dump VCD output for first RU in list
if (ru == RC.ru[0]) {
@@ -544,48 +547,20 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
void fh_if5_north_out(RU_t *ru) {
/// **** send_IF5 of rxdata to BBU **** ///
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 );
- AssertFatal(1==0,"Shouldn't get here\n");
- VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 0 );
+ AssertFatal(1 == 0, "Shouldn't get here\n");
}
// RRU IF4p5 northbound interface (RX)
void fh_if4p5_north_out(RU_t *ru) {
RU_proc_t *proc=&ru->proc;
+ if (ru->idx == 0)
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx);
- //NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
- //const int subframe = proc->tti_rx;
- if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx );
-
- /*
- if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) {
- /// **** in TDD during DL send_IF4 of ULTICK to RCC **** ///
- send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULTICK);
- return;
- }*/
start_meas(&ru->tx_fhaul);
send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULFFT);
stop_meas(&ru->tx_fhaul);
}
-void *emulatedRF_thread(void *param) {
- RU_proc_t *proc = (RU_proc_t *) param;
- int microsec = 500; // length of time to sleep, in miliseconds
- struct timespec req = {0};
- req.tv_sec = 0;
- req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2;
- wait_sync("emulatedRF_thread");
-
- while(!oai_exit) {
- nanosleep(&req, (struct timespec *)NULL);
- pthread_mutex_lock(&proc->mutex_emulateRF);
- ++proc->instance_cnt_emulateRF;
- pthread_mutex_unlock(&proc->mutex_emulateRF);
- pthread_cond_signal(&proc->cond_emulateRF);
- }
-
- return 0;
-}
-
static void rx_rf(RU_t *ru, int *frame, int *slot)
{
RU_proc_t *proc = &ru->proc;
@@ -606,20 +581,11 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
openair0_timestamp ts;
unsigned int rxs;
- if(emulate_rf) {
- wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
- release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
- rxs = samples_per_slot;
- ts = old_ts + rxs;
- } else {
- rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb);
- }
+ rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
proc->timestamp_rx = ts-ru->ts_offset;
- //AssertFatal(rxs == fp->samples_per_subframe,
- //"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_subframe,rxs);
if (rxs != samples_per_slot)
LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n", samples_per_slot, rxs);
@@ -636,23 +602,26 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
}
}
- //compute system frame number (SFN) according to O-RAN-WG4-CUS.0-v02.00 (using alpha=beta=0)
- // this assumes that the USRP has been synchronized to the GPS time
- // OAI uses timestamps in sample time stored in int64_t, but it will fit in double precision for many years to come.
- double gps_sec = ((double) ts)/cfg->sample_rate;
- //proc->frame_rx = ((int64_t) (gps_sec/0.01)) & 1023;
+ // compute system frame number (SFN) according to O-RAN-WG4-CUS.0-v02.00 (using alpha=beta=0)
+ // this assumes that the USRP has been synchronized to the GPS time
+ // OAI uses timestamps in sample time stored in int64_t, but it will fit in double precision for many years to come.
+ double gps_sec = ((double)ts) / cfg->sample_rate;
// in fact the following line is the same as long as the timestamp_rx is synchronized to GPS.
proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_subframe*10))&1023;
proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx,fp);
// synchronize first reception to frame 0 subframe 0
- LOG_D(PHY,"RU %d/%d TS %ld, GPS %f, SR %f, frame %d, slot %d.%d / %d\n",
+ LOG_D(PHY,
+ "RU %d/%d TS %ld, GPS %f, SR %f, frame %d, slot %d.%d / %d\n",
ru->idx,
0,
- ts, //(unsigned long long int)(proc->timestamp_rx+ru->ts_offset),
- gps_sec,
- cfg->sample_rate,
- proc->frame_rx,proc->tti_rx,proc->tti_tx,fp->slots_per_frame);
+ ts,
+ gps_sec,
+ cfg->sample_rate,
+ proc->frame_rx,
+ proc->tti_rx,
+ proc->tti_tx,
+ fp->slots_per_frame);
// dump VCD output for first RU in list
if (ru == RC.ru[0]) {
@@ -662,15 +631,19 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
if (proc->first_rx == 0) {
if (proc->tti_rx != *slot) {
- LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->tti_rx %d, slot %d)\n",(long long unsigned int)proc->timestamp_rx,proc->tti_rx,*slot);
+ LOG_E(PHY,
+ "Received Timestamp (%lu) doesn't correspond to the time we think it is (proc->tti_rx %d, slot %d)\n",
+ proc->timestamp_rx,
+ proc->tti_rx,
+ *slot);
exit_fun("Exiting");
}
if (proc->frame_rx != *frame) {
LOG_E(PHY,
- "Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d, proc->tti_rx %d, "
+ "Received Timestamp (%lu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d, proc->tti_rx %d, "
"slot %d)\n",
- (long long unsigned int)proc->timestamp_rx,
+ proc->timestamp_rx,
proc->frame_rx,
*frame,
proc->tti_rx,
@@ -683,10 +656,8 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
*slot = proc->tti_rx;
}
- if (!emulate_rf) {
- metadata mt = {.slot = *slot, .frame = *frame};
- gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt);
- }
+ metadata mt = {.slot = *slot, .frame = *frame};
+ gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, (proc->timestamp_rx+ru->ts_offset)&0xffffffff );
@@ -720,6 +691,7 @@ static radio_tx_gpio_flag_t get_gpio_flags(RU_t *ru, int slot)
}
}
break;
+
case RU_GPIO_CONTROL_INTERDIGITAL: {
// the beam index is written in bits 8-10 of the flags
// bit 11 enables the gpio programming
@@ -805,9 +777,7 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
flags_gpio = get_gpio_flags(ru, slot);
const int flags = flags_burst | (flags_gpio << 4);
-
- if (proc->first_tx == 1)
- proc->first_tx = 0;
+ proc->first_tx = 0;
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_WRITE_FLAGS, flags);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame);
@@ -828,10 +798,10 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
nt,
flags);
LOG_D(PHY,
- "[TXPATH] RU %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, "
+ "[TXPATH] RU %d tx_rf, writing to TS %lu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, "
"returned %d, E %f\n",
ru->idx,
- (long long unsigned int)(timestamp + ru->ts_offset - sf_extension),
+ timestamp + ru->ts_offset - sf_extension,
frame,
slot,
proc->frame_tx_unwrap,
@@ -841,7 +811,6 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
txs,
10 * log10((double)signal_energy(txp[0], siglen + sf_extension)));
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0);
- // AssertFatal(txs == 0,"trx write function error %d\n", txs);
}
static void fill_rf_config(RU_t *ru, char *rf_config_file)
@@ -880,12 +849,12 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file)
for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) {
if (ru->if_frequency == 0) {
- cfg->tx_freq[i] = (double)fp->dl_CarrierFreq;
+ cfg->tx_freq[i] = fp->dl_CarrierFreq;
} else if (ru->if_freq_offset) {
- cfg->tx_freq[i] = (double)(ru->if_frequency);
+ cfg->tx_freq[i] = ru->if_frequency;
LOG_I(PHY, "Setting IF TX frequency to %lu Hz with IF TX frequency offset %d Hz\n", ru->if_frequency, ru->if_freq_offset);
} else {
- cfg->tx_freq[i] = (double)ru->if_frequency;
+ cfg->tx_freq[i] = ru->if_frequency;
}
cfg->tx_gain[i] = ru->att_tx;
@@ -895,12 +864,12 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file)
for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) {
if (ru->if_frequency == 0) {
- cfg->rx_freq[i] = (double)fp->ul_CarrierFreq;
+ cfg->rx_freq[i] = fp->ul_CarrierFreq;
} else if (ru->if_freq_offset) {
- cfg->rx_freq[i] = (double)(ru->if_frequency + ru->if_freq_offset);
+ cfg->rx_freq[i] = ru->if_frequency + ru->if_freq_offset;
LOG_I(PHY, "Setting IF RX frequency to %lu Hz with IF RX frequency offset %d Hz\n", ru->if_frequency, ru->if_freq_offset);
} else {
- cfg->rx_freq[i] = (double)(ru->if_frequency+fp->ul_CarrierFreq-fp->dl_CarrierFreq);
+ cfg->rx_freq[i] = ru->if_frequency + fp->ul_CarrierFreq - fp->dl_CarrierFreq;
}
cfg->rx_gain[i] = ru->max_rxgain-ru->att_rx;
@@ -941,17 +910,11 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_
antennas are mapped to successive RF chains on the same card. */
int setup_RU_buffers(RU_t *ru)
{
- int card,ant;
- //uint16_t N_TA_offset = 0;
- NR_DL_FRAME_PARMS *fp;
+ if (!ru)
+ return (-1);
+
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nfapi_nr_config_request_scf_t *config = &ru->config;
-
- if (ru) {
- fp = ru->nr_frame_parms;
- } else {
- return(-1);
- }
-
int mu = config->ssb_config.scs_common.value;
int N_RB = config->carrier_config.dl_grid_size[config->ssb_config.scs_common.value].value;
@@ -963,8 +926,8 @@ int setup_RU_buffers(RU_t *ru)
if (ru->openair0_cfg.mmapped_dma == 1) {
// replace RX signal buffers with mmaped HW versions
for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) {
- card = i / 4;
- ant = i % 4;
+ int card = i / 4;
+ int ant = i % 4;
LOG_D(PHY, "Mapping RU id %u, rx_ant %d, on card %d, chain %d\n", ru->idx, i, ru->rf_map.card + card, ru->rf_map.chain + ant);
free(ru->common.rxdata[i]);
ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain + ant];
@@ -975,8 +938,8 @@ int setup_RU_buffers(RU_t *ru)
}
for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) {
- card = i / 4;
- ant = i % 4;
+ int card = i / 4;
+ int ant = i % 4;
LOG_D(PHY, "Mapping RU id %u, tx_ant %d, on card %d, chain %d\n", ru->idx, i, ru->rf_map.card + card, ru->rf_map.chain + ant);
free(ru->common.txdata[i]);
ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain + ant];
@@ -985,8 +948,9 @@ int setup_RU_buffers(RU_t *ru)
ru->common.txdata[i][j] = 16 - j;
}
}
- } else { // not memory-mapped DMA
- //nothing to do, everything already allocated in lte_init
+ } else {
+ // not memory-mapped DMA
+ // nothing to do, everything already allocated in lte_init
}
return(0);
@@ -996,58 +960,21 @@ void ru_tx_func(void *param)
{
processingData_RU_t *info = (processingData_RU_t *) param;
RU_t *ru = info->ru;
- NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int frame_tx = info->frame_tx;
int slot_tx = info->slot_tx;
- int print_frame = 8;
- char filename[40];
// do TX front-end processing if needed (precoding and/or IDFTs)
if (ru->feptx_prec)
ru->feptx_prec(ru,frame_tx,slot_tx);
// do OFDM with/without TX front-end processing if needed
- if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm))
+ if (ru->fh_north_asynch_in == NULL && ru->feptx_ofdm)
ru->feptx_ofdm(ru, frame_tx, slot_tx);
- if(!emulate_rf) {
- // do outgoing fronthaul (south) if needed
- if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out))
- ru->fh_south_out(ru, frame_tx, slot_tx, info->timestamp_tx);
-
- if (ru->fh_north_out)
- ru->fh_north_out(ru);
- } else {
- if(frame_tx == print_frame) {
- for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) {
- if(slot_tx == 0) {
- sprintf(filename,"gNBdataF_frame%d_sl%d.m", print_frame, slot_tx);
- LOG_M(filename,"txdataF_frame",&ru->gNB_list[0]->common_vars.txdataF[i][0],fp->samples_per_frame_wCP, 1, 1);
- sprintf(filename,"tx%ddataF_frame%d_sl%d.m", i, print_frame, slot_tx);
- LOG_M(filename,"txdataF_frame",&ru->common.txdataF[i][0],fp->samples_per_frame_wCP, 1, 1);
- sprintf(filename,"tx%ddataF_BF_frame%d_sl%d.m", i, print_frame, slot_tx);
- LOG_M(filename,"txdataF_BF_frame",&ru->common.txdataF_BF[i][0],fp->samples_per_subframe_wCP, 1, 1);
- }
-
- if(slot_tx == 9) {
- sprintf(filename,"tx%ddata_frame%d.m", i, print_frame);
- LOG_M(filename,"txdata_frame",&ru->common.txdata[i][0],fp->samples_per_frame, 1, 1);
- sprintf(filename,"tx%ddata_frame%d.dat", i, print_frame);
- FILE *output_fd = fopen(filename,"w");
-
- if (output_fd) {
- fwrite(&ru->common.txdata[i][0],
- sizeof(int32_t),
- fp->samples_per_frame,
- output_fd);
- fclose(output_fd);
- } else {
- LOG_E(PHY,"Cannot write to file %s\n",filename);
- }
- }//if(slot_tx == 9)
- }//for (i=0; inb_tx; i++)
- }//if(frame_tx == print_frame)
- }//else emulate_rf
+ if (ru->fh_north_asynch_in == NULL && ru->fh_south_out)
+ ru->fh_south_out(ru, frame_tx, slot_tx, info->timestamp_tx);
+ if (ru->fh_north_out)
+ ru->fh_north_out(ru);
}
/* @brief wait for the next RX TTI to be free
@@ -1111,7 +1038,7 @@ void *ru_thread(void *param)
// set default return value
sprintf(threadname,"ru_thread %u",ru->idx);
LOG_I(PHY,"Starting RU %d (%s,%s) on cpu %d\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing],sched_getcpu());
- memcpy((void *)&ru->config,(void *)&RC.gNB[0]->gNB_config,sizeof(ru->config));
+ ru->config = RC.gNB[0]->gNB_config;
nr_init_frame_parms(&ru->config, fp);
nr_dump_frame_parms(fp);
@@ -1119,54 +1046,52 @@ void *ru_thread(void *param)
fill_rf_config(ru, ru->rf_config_file);
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp->slots_per_frame, fp->ofdm_symbol_size);
- if(!emulate_rf) {
- // Start IF device if any
- if (ru->nr_start_if) {
- LOG_I(PHY, "starting transport\n");
- ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params);
- AssertFatal(ret == 0, "RU %u: openair0_transport_init() ret %d: cannot initialize transport protocol\n", ru->idx, ret);
-
- if (ru->ifdevice.get_internal_parameter != NULL) {
- /* it seems the device can "overwrite" (request?) to set the callbacks
- * for fh_south_in()/fh_south_out() differently */
- void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in");
- if (t != NULL)
- ru->fh_south_in = t;
- t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out");
- if (t != NULL)
- ru->fh_south_out = t;
- } else {
-
- malloc_IF4p5_buffer(ru);
- }
-
- int cpu = sched_getcpu();
- if (ru->ru_thread_core > -1 && cpu != ru->ru_thread_core) {
- /* we start the ru_thread using threadCreate(), which already sets CPU
- * affinity; let's force it here again as per feature request #732 */
- cpu_set_t cpuset;
- CPU_ZERO(&cpuset);
- CPU_SET(ru->ru_thread_core, &cpuset);
- int ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
- AssertFatal(ret == 0, "Error in pthread_getaffinity_np(): ret: %d, errno: %d", ret, errno);
- LOG_I(PHY, "RU %d: manually set CPU affinity to CPU %d\n", ru->idx, ru->ru_thread_core);
- }
-
- LOG_I(PHY,"Starting IF interface for RU %d, nb_rx %d\n",ru->idx,ru->nb_rx);
- AssertFatal(ru->nr_start_if(ru,NULL) == 0, "Could not start the IF device\n");
-
- if (ru->has_ctrl_prt > 0) {
- if (ru->if_south == LOCAL_RF) ret = connect_rau(ru);
- else ret = attach_rru(ru);
-
- AssertFatal(ret==0,"Cannot connect to remote radio\n");
- }
+ // Start IF device if any
+ if (ru->nr_start_if) {
+ LOG_I(PHY, "starting transport\n");
+ ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params);
+ AssertFatal(ret == 0, "RU %u: openair0_transport_init() ret %d: cannot initialize transport protocol\n", ru->idx, ret);
+ if (ru->ifdevice.get_internal_parameter != NULL) {
+ /* it seems the device can "overwrite" (request?) to set the callbacks
+ * for fh_south_in()/fh_south_out() differently */
+ void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in");
+ if (t != NULL)
+ ru->fh_south_in = t;
+ t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out");
+ if (t != NULL)
+ ru->fh_south_out = t;
+ } else {
+ malloc_IF4p5_buffer(ru);
}
- else if (ru->if_south == LOCAL_RF) { // configure RF parameters only
- ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
- AssertFatal(ret==0,"Cannot connect to local radio\n");
+
+ int cpu = sched_getcpu();
+ if (ru->ru_thread_core > -1 && cpu != ru->ru_thread_core) {
+ /* we start the ru_thread using threadCreate(), which already sets CPU
+ * affinity; let's force it here again as per feature request #732 */
+ cpu_set_t cpuset;
+ CPU_ZERO(&cpuset);
+ CPU_SET(ru->ru_thread_core, &cpuset);
+ int ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
+ AssertFatal(ret == 0, "Error in pthread_getaffinity_np(): ret: %d, errno: %d", ret, errno);
+ LOG_I(PHY, "RU %d: manually set CPU affinity to CPU %d\n", ru->idx, ru->ru_thread_core);
}
+
+ LOG_I(PHY, "Starting IF interface for RU %d, nb_rx %d\n", ru->idx, ru->nb_rx);
+ AssertFatal(ru->nr_start_if(ru, NULL) == 0, "Could not start the IF device\n");
+
+ if (ru->has_ctrl_prt > 0) {
+ if (ru->if_south == LOCAL_RF)
+ ret = connect_rau(ru);
+ else
+ ret = attach_rru(ru);
+
+ AssertFatal(ret == 0, "Cannot connect to remote radio\n");
+ }
+
+ } else if (ru->if_south == LOCAL_RF) { // configure RF parameters only
+ ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
+ AssertFatal(ret==0,"Cannot connect to local radio\n");
}
if (setup_RU_buffers(ru)!=0) {
@@ -1181,31 +1106,31 @@ void *ru_thread(void *param)
pthread_mutex_unlock(&RC.ru_mutex);
wait_sync("ru_thread");
- if(!emulate_rf) {
- // Start RF device if any
- if (ru->start_rf) {
- if (ru->start_rf(ru) != 0)
- LOG_E(HW,"Could not start the RF device\n");
- else LOG_I(PHY,"RU %d rf device ready\n",ru->idx);
- } else LOG_I(PHY,"RU %d no rf device\n",ru->idx);
+ // Start RF device if any
+ if (ru->start_rf) {
+ if (ru->start_rf(ru) != 0)
+ LOG_E(HW, "Could not start the RF device\n");
+ else
+ LOG_I(PHY, "RU %d rf device ready\n", ru->idx);
+ } else
+ LOG_I(PHY, "RU %d no rf device\n", ru->idx);
- LOG_I(PHY, "RU %d RF started cpu_meas_enabled %d\n", ru->idx, cpu_meas_enabled);
- // start trx write thread
- if(usrp_tx_thread == 1) {
- if (ru->start_write_thread) {
- if(ru->start_write_thread(ru) != 0) {
- LOG_E(HW,"Could not start tx write thread\n");
- } else {
- LOG_I(PHY,"tx write thread ready\n");
- }
+ LOG_I(PHY, "RU %d RF started cpu_meas_enabled %d\n", ru->idx, cpu_meas_enabled);
+ // start trx write thread
+ if (usrp_tx_thread == 1) {
+ if (ru->start_write_thread) {
+ if (ru->start_write_thread(ru) != 0) {
+ LOG_E(HW, "Could not start tx write thread\n");
+ } else {
+ LOG_I(PHY, "tx write thread ready\n");
}
}
}
// This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
struct timespec slot_start;
- clock_gettime(CLOCK_MONOTONIC, &slot_start);
-
+ clock_gettime(CLOCK_MONOTONIC, &slot_start);
+
while (!oai_exit) {
if (slot==(fp->slots_per_frame-1)) {
slot=0;
@@ -1222,8 +1147,8 @@ void *ru_thread(void *param)
// synchronization on input FH interface, acquire signals/data and block
LOG_D(PHY,"[RU_thread] read data: frame_rx = %d, tti_rx = %d\n", frame, slot);
- if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&slot);
- else AssertFatal(1==0, "No fronthaul interface at south port");
+ AssertFatal(ru->fh_south_in, "No fronthaul interface at south port");
+ ru->fh_south_in(ru, &frame, &slot);
if (initial_wait == 1 && proc->frame_rx < 300) {
if (proc->frame_rx > 0 && ((proc->frame_rx % 100) == 0) && proc->tti_rx == 0) {
@@ -1308,14 +1233,14 @@ void *ru_thread(void *param)
} // end if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) {
notifiedFIFO_elt_t *resTx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, NULL);
- processingData_L1tx_t *syncMsgTx = NotifiedFifoData(resTx);
- syncMsgTx->gNB = gNB;
- syncMsgTx->frame = proc->frame_tx;
- syncMsgTx->slot = proc->tti_tx;
- syncMsgTx->frame_rx = proc->frame_rx;
- syncMsgTx->slot_rx = proc->tti_rx;
- syncMsgTx->timestamp_tx = proc->timestamp_tx;
resTx->key = proc->tti_tx;
+ processingData_L1tx_t *syncMsgTx = NotifiedFifoData(resTx);
+ *syncMsgTx = (processingData_L1tx_t){.gNB = gNB,
+ .frame = proc->frame_tx,
+ .slot = proc->tti_tx,
+ .frame_rx = proc->frame_rx,
+ .slot_rx = proc->tti_rx,
+ .timestamp_tx = proc->timestamp_tx};
pushNotifiedFIFO(&gNB->L1_tx_out, resTx);
}
@@ -1325,15 +1250,16 @@ void *ru_thread(void *param)
int start_streaming(RU_t *ru) {
LOG_I(PHY,"Starting streaming on third-party RRU\n");
- return(ru->ifdevice.thirdparty_startstreaming(&ru->ifdevice));
+ return ru->ifdevice.thirdparty_startstreaming(&ru->ifdevice);
}
int nr_start_if(struct RU_t_s *ru, struct PHY_VARS_gNB_s *gNB) {
if (ru->if_south <= REMOTE_IF5)
- for (int i=0;inb_rx;i++) ru->openair0_cfg.rxbase[i] = ru->common.rxdata[i];
+ for (int i = 0; i < ru->nb_rx; i++)
+ ru->openair0_cfg.rxbase[i] = ru->common.rxdata[i];
ru->openair0_cfg.rxsize = ru->nr_frame_parms->samples_per_subframe*10;
reset_meas(&ru->ifdevice.tx_fhaul);
- return(ru->ifdevice.trx_start_func(&ru->ifdevice));
+ return ru->ifdevice.trx_start_func(&ru->ifdevice);
}
int start_rf(RU_t *ru) {
@@ -1349,29 +1275,12 @@ int stop_rf(RU_t *ru) {
}
int start_write_thread(RU_t *ru) {
- return(ru->rfdevice.trx_write_init(&ru->rfdevice));
+ return ru->rfdevice.trx_write_init(&ru->rfdevice);
}
-void init_RU_proc(RU_t *ru) {
- int i=0;
- RU_proc_t *proc;
- proc = &ru->proc;
- memset((void *)proc,0,sizeof(RU_proc_t));
- proc->ru = ru;
- proc->instance_cnt_emulateRF = -1;
- proc->first_rx = 1;
- proc->first_tx = 1;
- proc->frame_offset = 0;
- proc->num_slaves = 0;
- proc->frame_tx_unwrap = 0;
-
- for (i=0; i<10; i++) proc->symbol_mask[i]=0;
-
- pthread_mutex_init( &proc->mutex_emulateRF,NULL);
- pthread_cond_init( &proc->cond_emulateRF, NULL);
-
- if(emulate_rf)
- threadCreate( &proc->pthread_emulateRF, emulatedRF_thread, (void *)proc, "emulateRF", -1, OAI_PRIORITY_RT );
+void init_RU_proc(RU_t *ru)
+{
+ ru->proc = (RU_proc_t){.ru = ru, .first_rx = 1, .first_tx = 1};
LOG_I(PHY, "Initialized RU proc %d (%s,%s),\n", ru->idx, NB_functions[ru->function], NB_timing[ru->if_timing]);
}
@@ -1395,10 +1304,10 @@ void kill_NR_RU_proc(int inst) {
* mutex_fep/cond_fep. Thus, we unlocked above for pthread_FH above and do
* the same for FEP thread below again (using broadcast() to ensure both
* threads get the signal). This one will also destroy the mutex and cond. */
- pthread_mutex_lock(&proc->mutex_fep[0]);
+ pthread_mutex_lock(proc->mutex_fep);
proc->instance_cnt_fep[0] = 0;
- pthread_cond_broadcast(&proc->cond_fep[0]);
- pthread_mutex_unlock( &proc->mutex_fep[0] );
+ pthread_cond_broadcast(proc->cond_fep);
+ pthread_mutex_unlock(proc->mutex_fep);
pthread_join(proc->pthread_FH, NULL);
// everything should be stopped now, we can safely stop the RF device
@@ -1417,19 +1326,15 @@ void kill_NR_RU_proc(int inst) {
int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) {
FH_fmt_options_t fmt = cap->FH_fmt;
int i;
- int found_band=0;
LOG_I(PHY,"RRU %d, num_bands %d, looking for band %d\n",ru->idx,cap->num_bands,ru->nr_frame_parms->nr_band);
for (i=0; inum_bands; i++) {
LOG_I(PHY,"band %d on RRU %d\n",cap->band_list[i],ru->idx);
-
- if (ru->nr_frame_parms->nr_band == cap->band_list[i]) {
- found_band=1;
+ if (ru->nr_frame_parms->nr_band == cap->band_list[i])
break;
- }
}
- if (found_band == 0) {
+ if (i == cap->num_bands) {
LOG_I(PHY,"Couldn't find target NR band %d on RRU %d\n",ru->nr_frame_parms->nr_band,ru->idx);
return(-1);
}
@@ -1441,18 +1346,18 @@ int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) {
break;
case REMOTE_IF5:
- if (fmt == OAI_IF5_only || fmt == OAI_IF5_and_IF4p5) return(0);
-
+ if (fmt == OAI_IF5_only || fmt == OAI_IF5_and_IF4p5)
+ return (0);
break;
case REMOTE_IF4p5:
- if (fmt == OAI_IF4p5_only || fmt == OAI_IF5_and_IF4p5) return(0);
-
+ if (fmt == OAI_IF4p5_only || fmt == OAI_IF5_and_IF4p5)
+ return (0);
break;
case REMOTE_MBP_IF5:
- if (fmt == MBP_IF5) return(0);
-
+ if (fmt == MBP_IF5)
+ return (0);
break;
default:
@@ -1464,46 +1369,40 @@ int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) {
}
const char rru_format_options[4][20] = {"OAI_IF5_only", "OAI_IF4p5_only", "OAI_IF5_and_IF4p5", "MBP_IF5"};
-
const char rru_formats[3][20] = {"OAI_IF5", "MBP_IF5", "OAI_IF4p5"};
const char ru_if_formats[4][20] = {"LOCAL_RF", "REMOTE_OAI_IF5", "REMOTE_MBP_IF5", "REMOTE_OAI_IF4p5"};
void configure_ru(void *ruu, void *arg)
{
RU_t *ru = (RU_t *)ruu;
- RRU_config_t *config = (RRU_config_t *)arg;
- RRU_capabilities_t *capabilities = (RRU_capabilities_t *)arg;
nfapi_nr_config_request_scf_t *cfg = &ru->config;
int ret;
LOG_I(PHY, "Received capabilities from RRU %d\n", ru->idx);
- if (capabilities->FH_fmt < MAX_FH_FMTs) LOG_I(PHY, "RU FH options %s\n",rru_format_options[capabilities->FH_fmt]);
+ RRU_capabilities_t *capabilities = (RRU_capabilities_t *)arg;
+ if (capabilities->FH_fmt < MAX_FH_FMTs)
+ LOG_I(PHY, "RU FH options %s\n", rru_format_options[capabilities->FH_fmt]);
ret = check_capabilities(ru,capabilities);
AssertFatal(ret == 0, "Cannot configure RRU %d, check_capabilities returned %d\n", ru->idx, ret);
// take antenna capabilities of RRU
- ru->nb_tx = capabilities->nb_tx[0];
- ru->nb_rx = capabilities->nb_rx[0];
+ ru->nb_tx = capabilities->nb_tx[0];
+ ru->nb_rx = capabilities->nb_rx[0];
// Pass configuration to RRU
LOG_I(PHY, "Using %s fronthaul (%d), band %d \n",ru_if_formats[ru->if_south],ru->if_south,ru->nr_frame_parms->nr_band);
+
// wait for configuration
- config->FH_fmt = ru->if_south;
- config->num_bands = 1;
- config->band_list[0] = ru->nr_frame_parms->nr_band;
- config->tx_freq[0] = ru->nr_frame_parms->dl_CarrierFreq;
- config->rx_freq[0] = ru->nr_frame_parms->ul_CarrierFreq;
- //config->tdd_config[0] = ru->nr_frame_parms->tdd_config;
- //config->tdd_config_S[0] = ru->nr_frame_parms->tdd_config_S;
- config->att_tx[0] = ru->att_tx;
- config->att_rx[0] = ru->att_rx;
- config->N_RB_DL[0] = cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value;
- config->N_RB_UL[0] = cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value;
- config->threequarter_fs[0] = ru->nr_frame_parms->threequarter_fs;
- /* if (ru->if_south==REMOTE_IF4p5) {
- config->prach_FreqOffset[0] = ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset;
- config->prach_ConfigIndex[0] = ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
- LOG_I(PHY,"REMOTE_IF4p5: prach_FrequOffset %d, prach_ConfigIndex %d\n",
- config->prach_FreqOffset[0],config->prach_ConfigIndex[0]);*/
+ RRU_config_t *config = (RRU_config_t *)arg;
+ *config = (RRU_config_t){.FH_fmt = ru->if_south,
+ .num_bands = 1,
+ .band_list[0] = ru->nr_frame_parms->nr_band,
+ .tx_freq[0] = ru->nr_frame_parms->dl_CarrierFreq,
+ .rx_freq[0] = ru->nr_frame_parms->ul_CarrierFreq,
+ .att_tx[0] = ru->att_tx,
+ .att_rx[0] = ru->att_rx,
+ .N_RB_DL[0] = cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value,
+ .N_RB_UL[0] = cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value,
+ .threequarter_fs[0] = ru->nr_frame_parms->threequarter_fs};
nr_init_frame_parms(&ru->config, ru->nr_frame_parms);
nr_phy_init_RU(ru);
}
@@ -1513,37 +1412,31 @@ void configure_rru(void *ruu, void *arg)
RRU_config_t *config = (RRU_config_t *)arg;
RU_t *ru = (RU_t *)ruu;
nfapi_nr_config_request_scf_t *cfg = &ru->config;
- ru->nr_frame_parms->nr_band = config->band_list[0];
- ru->nr_frame_parms->dl_CarrierFreq = config->tx_freq[0];
- ru->nr_frame_parms->ul_CarrierFreq = config->rx_freq[0];
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
- if (ru->nr_frame_parms->dl_CarrierFreq == ru->nr_frame_parms->ul_CarrierFreq) {
- cfg->cell_config.frame_duplex_type.value = TDD;
- //ru->nr_frame_parms->tdd_config = config->tdd_config[0];
- //ru->nr_frame_parms->tdd_config_S = config->tdd_config_S[0];
+ fp->nr_band = config->band_list[0];
+ fp->dl_CarrierFreq = config->tx_freq[0];
+ fp->ul_CarrierFreq = config->rx_freq[0];
+
+ if (fp->dl_CarrierFreq == fp->ul_CarrierFreq) {
+ cfg->cell_config.frame_duplex_type.value = TDD;
} else
- cfg->cell_config.frame_duplex_type.value = FDD;
+ cfg->cell_config.frame_duplex_type.value = FDD;
- ru->att_tx = config->att_tx[0];
- ru->att_rx = config->att_rx[0];
+ ru->att_tx = config->att_tx[0];
+ ru->att_rx = config->att_rx[0];
int mu = cfg->ssb_config.scs_common.value;
- cfg->carrier_config.dl_grid_size[mu].value = config->N_RB_DL[0];
- cfg->carrier_config.dl_grid_size[mu].value = config->N_RB_UL[0];
- ru->nr_frame_parms->threequarter_fs = config->threequarter_fs[0];
+ cfg->carrier_config.dl_grid_size[mu].value = config->N_RB_DL[0];
+ cfg->carrier_config.dl_grid_size[mu].value = config->N_RB_UL[0];
+ fp->threequarter_fs = config->threequarter_fs[0];
- //ru->nr_frame_parms->pdsch_config_common.referenceSignalPower = ru->max_pdschReferenceSignalPower-config->att_tx[0];
if (ru->function==NGFI_RRU_IF4p5) {
- ru->nr_frame_parms->att_rx = ru->att_rx;
- ru->nr_frame_parms->att_tx = ru->att_tx;
- /*
- LOG_I(PHY,"Setting ru->function to NGFI_RRU_IF4p5, prach_FrequOffset %d, prach_ConfigIndex %d, att (%d,%d)\n",
- config->prach_FreqOffset[0],config->prach_ConfigIndex[0],ru->att_tx,ru->att_rx);
- ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset = config->prach_FreqOffset[0];
- ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex = config->prach_ConfigIndex[0]; */
+ fp->att_rx = ru->att_rx;
+ fp->att_tx = ru->att_tx;
}
fill_rf_config(ru,ru->rf_config_file);
- nr_init_frame_parms(&ru->config, ru->nr_frame_parms);
+ nr_init_frame_parms(&ru->config, fp);
nr_phy_init_RU(ru);
}
@@ -1600,17 +1493,6 @@ void set_function_spec_param(RU_t *ru)
ru->stop_rf = stop_rf;
ru->start_write_thread = start_write_thread; // starting RF TX in different thread
}
-
- /*
- fill_rf_config(ru,rf_config_file);
- init_frame_parms(&ru->frame_parms,1);
- nr_phy_init_RU(ru);
-
- ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
- if (setup_RU_buffers(ru)!=0) {
- exit(-1);
- }
- */
break;
case REMOTE_IF5: // the remote unit is IF5 RRU
@@ -1659,12 +1541,6 @@ void set_function_spec_param(RU_t *ru)
void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
{
- int ru_id;
- RU_t *ru;
- PHY_VARS_gNB *gNB_RC;
- PHY_VARS_gNB *gNB0= (PHY_VARS_gNB *)NULL;
- NR_DL_FRAME_PARMS *fp = (NR_DL_FRAME_PARMS *)NULL;
- int i;
// create status mask
RC.ru_mask = 0;
pthread_mutex_init(&RC.ru_mutex,NULL);
@@ -1674,9 +1550,9 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_nr_L1_inst,RC.nb_RU,get_nprocs());
LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU);
- for (ru_id=0; ru_idrf_config_file = rf_config_file;
ru->idx = ru_id;
ru->ts_offset = 0;
@@ -1693,23 +1569,18 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
}
}
- gNB_RC = RC.gNB[0];
- gNB0 = ru->gNB_list[0];
- fp = ru->nr_frame_parms;
+ PHY_VARS_gNB *gNB_RC = RC.gNB[0];
+ PHY_VARS_gNB *gNB0 = ru->gNB_list[0];
LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south);
if (gNB0) {
- if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5))
- AssertFatal(gNB0, "gNB0 is null!\n");
-
- if (gNB0 && gNB_RC) {
+ if (gNB_RC) {
LOG_D(PHY, "Copying frame parms from gNB in RC to gNB %d in ru %d and frame_parms in ru\n", gNB0->Mod_id, ru->idx);
- memcpy((void *)fp, &gNB_RC->frame_parms, sizeof(NR_DL_FRAME_PARMS));
- memcpy((void *)&gNB0->frame_parms, (void *)&gNB_RC->frame_parms, sizeof(NR_DL_FRAME_PARMS));
+ *ru->nr_frame_parms = gNB_RC->frame_parms;
+ gNB0->frame_parms = gNB_RC->frame_parms;
// attach all RU to all gNBs in its list/
LOG_D(PHY,"ru->num_gNB:%d gNB0->num_RU:%d\n", ru->num_gNB, gNB0->num_RU);
-
- for (i=0; inum_gNB; i++) {
+ for (int i = 0; i < ru->num_gNB; i++) {
gNB0 = ru->gNB_list[i];
gNB0->RU_list[gNB0->num_RU++] = ru;
}
@@ -1723,22 +1594,21 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
LOG_E(PHY, "Number of threads for gNB should be more than 1. Allocated only %d\n", threadCnt);
char pool[80];
int s_offset = sprintf(pool,"%d",ru->tpcores[0]);
- for (int icpu=1; icputpcores[icpu]);
+ for (int icpu = 1; icpu < threadCnt; icpu++) {
+ s_offset += sprintf(pool + s_offset, ",%d", ru->tpcores[icpu]);
}
LOG_I(PHY, "RU thread-pool core string %s (size %d)\n", pool, threadCnt);
- ru->threadPool = (tpool_t*)malloc(sizeof(tpool_t));
+ ru->threadPool = malloc(sizeof(tpool_t));
initTpool(pool, ru->threadPool, cpumeas(CPUMEAS_GETSTATE));
// FEP RX result FIFO
- ru->respfeprx = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t));
+ ru->respfeprx = malloc(sizeof(notifiedFIFO_t));
initNotifiedFIFO(ru->respfeprx);
// FEP TX result FIFO
- ru->respfeptx = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t));
+ ru->respfeptx = malloc(sizeof(notifiedFIFO_t));
initNotifiedFIFO(ru->respfeptx);
}
} // for ru_id
- // sleep(1);
LOG_D(HW,"[nr-softmodem.c] RU threads created\n");
}
@@ -1755,7 +1625,6 @@ void stop_RU(int nb_ru) {
}
}
-
/* --------------------------------------------------------*/
/* from here function to use configuration module */
static void NRRCconfig_RU(configmodule_interface_t *cfg)
@@ -1764,199 +1633,199 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg)
paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST, NULL, 0};
config_getlist(cfg, &RUParamList, RUParams, sizeofArray(RUParams), NULL);
- if (RUParamList.numelt > 0) {
- RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *));
- RC.ru_mask = (1 << RC.nb_RU) - 1;
+ if (RUParamList.numelt <= 0)
+ return;
- for (int j = 0; j < RC.nb_RU; j++) {
- RC.ru[j] = calloc(1, sizeof(*RC.ru[j]));
- RC.ru[j]->idx = j;
- RC.ru[j]->nr_frame_parms = calloc(1, sizeof(*RC.ru[j]->nr_frame_parms));
- RC.ru[j]->frame_parms = calloc(1, sizeof(*RC.ru[j]->frame_parms));
- RC.ru[j]->if_timing = synch_to_ext_device;
+ RC.ru = (RU_t **)malloc(RC.nb_RU * sizeof(RU_t *));
+ RC.ru_mask = (1 << RC.nb_RU) - 1;
- if (RC.nb_nr_L1_inst > 0)
- RC.ru[j]->num_gNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt;
- else
- RC.ru[j]->num_gNB = 0;
+ for (int j = 0; j < RC.nb_RU; j++) {
+ RU_t *ru = RC.ru[j] = calloc(1, sizeof(*RC.ru[j]));
+ ru->idx = j;
+ ru->nr_frame_parms = calloc(1, sizeof(*ru->nr_frame_parms));
+ ru->frame_parms = calloc(1, sizeof(*ru->frame_parms));
+ ru->if_timing = synch_to_ext_device;
+ paramdef_t *param = RUParamList.paramarray[j];
+ if (RC.nb_nr_L1_inst > 0)
+ ru->num_gNB = param[RU_ENB_LIST_IDX].numelt;
+ else
+ ru->num_gNB = 0;
- for (int i = 0; i < RC.ru[j]->num_gNB; i++)
- RC.ru[j]->gNB_list[i] = RC.gNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]];
+ for (int i = 0; i < ru->num_gNB; i++)
+ ru->gNB_list[i] = RC.gNB[param[RU_ENB_LIST_IDX].iptr[i]];
- if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) {
- RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr));
- }
+ if (config_isparamset(param, RU_SDR_ADDRS)) {
+ ru->openair0_cfg.sdr_addrs = strdup(*param[RU_SDR_ADDRS].strptr);
+ }
- if (config_isparamset(RUParamList.paramarray[j], RU_GPIO_CONTROL)) {
- if (strcmp(*RUParamList.paramarray[j][RU_GPIO_CONTROL].strptr, "generic") == 0) {
- RC.ru[j]->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_GENERIC;
- LOG_I(PHY, "RU GPIO control set as 'generic'\n");
- } else if (strcmp(*RUParamList.paramarray[j][RU_GPIO_CONTROL].strptr, "interdigital") == 0) {
- RC.ru[j]->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_INTERDIGITAL;
- LOG_I(PHY, "RU GPIO control set as 'interdigital'\n");
- } else {
- AssertFatal(false,
- "bad GPIO controller in configuration file: '%s'\n",
- *(RUParamList.paramarray[j][RU_GPIO_CONTROL].strptr));
- }
- } else
- RC.ru[j]->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_NONE;
-
- if (config_isparamset(RUParamList.paramarray[j], RU_TX_SUBDEV)) {
- RC.ru[j]->openair0_cfg.tx_subdev = strdup(*(RUParamList.paramarray[j][RU_TX_SUBDEV].strptr));
- LOG_I(PHY, "RU USRP tx subdev == %s\n", RC.ru[j]->openair0_cfg.tx_subdev);
- }
-
- if (config_isparamset(RUParamList.paramarray[j], RU_RX_SUBDEV)) {
- RC.ru[j]->openair0_cfg.rx_subdev = strdup(*(RUParamList.paramarray[j][RU_RX_SUBDEV].strptr));
- LOG_I(PHY, "RU USRP rx subdev == %s\n", RC.ru[j]->openair0_cfg.rx_subdev);
- }
-
- if (config_isparamset(RUParamList.paramarray[j], RU_SDR_CLK_SRC)) {
- if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "internal") == 0) {
- RC.ru[j]->openair0_cfg.clock_source = internal;
- LOG_I(PHY, "RU clock source set as internal\n");
- } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "external") == 0) {
- RC.ru[j]->openair0_cfg.clock_source = external;
- LOG_I(PHY, "RU clock source set as external\n");
- } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "gpsdo") == 0) {
- RC.ru[j]->openair0_cfg.clock_source = gpsdo;
- LOG_I(PHY, "RU clock source set as gpsdo\n");
- } else {
- LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr));
- }
+ if (config_isparamset(param, RU_GPIO_CONTROL)) {
+ char *str = *param[RU_GPIO_CONTROL].strptr;
+ if (strcmp(str, "generic") == 0) {
+ ru->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_GENERIC;
+ LOG_I(PHY, "RU GPIO control set as 'generic'\n");
+ } else if (strcmp(str, "interdigital") == 0) {
+ ru->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_INTERDIGITAL;
+ LOG_I(PHY, "RU GPIO control set as 'interdigital'\n");
} else {
- LOG_D(PHY, "Setting clock source to internal\n");
- RC.ru[j]->openair0_cfg.clock_source = internal;
+ AssertFatal(false, "bad GPIO controller in configuration file: '%s'\n", str);
}
+ } else
+ ru->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_NONE;
- if (config_isparamset(RUParamList.paramarray[j], RU_SDR_TME_SRC)) {
- if (strcmp(*(RUParamList.paramarray[j][RU_SDR_TME_SRC].strptr), "internal") == 0) {
- RC.ru[j]->openair0_cfg.time_source = internal;
- LOG_I(PHY, "RU time source set as internal\n");
- } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_TME_SRC].strptr), "external") == 0) {
- RC.ru[j]->openair0_cfg.time_source = external;
- LOG_I(PHY, "RU time source set as external\n");
- } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_TME_SRC].strptr), "gpsdo") == 0) {
- RC.ru[j]->openair0_cfg.time_source = gpsdo;
- LOG_I(PHY, "RU time source set as gpsdo\n");
- } else {
- LOG_E(PHY, "Erroneous RU time source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr));
- }
+ if (config_isparamset(param, RU_TX_SUBDEV)) {
+ ru->openair0_cfg.tx_subdev = strdup(*param[RU_TX_SUBDEV].strptr);
+ LOG_I(PHY, "RU USRP tx subdev == %s\n", ru->openair0_cfg.tx_subdev);
+ }
+
+ if (config_isparamset(param, RU_RX_SUBDEV)) {
+ ru->openair0_cfg.rx_subdev = strdup(*param[RU_RX_SUBDEV].strptr);
+ LOG_I(PHY, "RU USRP rx subdev == %s\n", ru->openair0_cfg.rx_subdev);
+ }
+
+ if (config_isparamset(param, RU_SDR_CLK_SRC)) {
+ char *str = *param[RU_SDR_CLK_SRC].strptr;
+ if (strcmp(str, "internal") == 0) {
+ ru->openair0_cfg.clock_source = internal;
+ LOG_I(PHY, "RU clock source set as internal\n");
+ } else if (strcmp(str, "external") == 0) {
+ ru->openair0_cfg.clock_source = external;
+ LOG_I(PHY, "RU clock source set as external\n");
+ } else if (strcmp(str, "gpsdo") == 0) {
+ ru->openair0_cfg.clock_source = gpsdo;
+ LOG_I(PHY, "RU clock source set as gpsdo\n");
} else {
- LOG_D(PHY, "Setting time source to internal\n");
- RC.ru[j]->openair0_cfg.time_source = internal;
+ LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", str);
+ }
+ } else {
+ LOG_D(PHY, "Setting clock source to internal\n");
+ ru->openair0_cfg.clock_source = internal;
+ }
+
+ if (config_isparamset(param, RU_SDR_TME_SRC)) {
+ char *str = *param[RU_SDR_TME_SRC].strptr;
+ if (strcmp(str, "internal") == 0) {
+ ru->openair0_cfg.time_source = internal;
+ LOG_I(PHY, "RU time source set as internal\n");
+ } else if (strcmp(str, "external") == 0) {
+ ru->openair0_cfg.time_source = external;
+ LOG_I(PHY, "RU time source set as external\n");
+ } else if (strcmp(str, "gpsdo") == 0) {
+ ru->openair0_cfg.time_source = gpsdo;
+ LOG_I(PHY, "RU time source set as gpsdo\n");
+ } else {
+ LOG_E(PHY, "Erroneous RU time source in the provided configuration file: '%s'\n", str);
+ }
+ } else {
+ LOG_D(PHY, "Setting time source to internal\n");
+ ru->openair0_cfg.time_source = internal;
+ }
+
+ ru->openair0_cfg.tune_offset = get_softmodem_params()->tune_offset;
+
+ if (strcmp(*param[RU_LOCAL_RF_IDX].strptr, "yes") == 0) {
+ if (!config_isparamset(param, RU_LOCAL_IF_NAME_IDX)) {
+ ru->if_south = LOCAL_RF;
+ ru->function = gNodeB_3GPP;
+ LOG_D(PHY, "Setting function for RU %d to gNodeB_3GPP\n", j);
+ } else {
+ ru->eth_params.local_if_name = strdup(*param[RU_LOCAL_IF_NAME_IDX].strptr);
+ ru->eth_params.my_addr = strdup(*param[RU_LOCAL_ADDRESS_IDX].strptr);
+ ru->eth_params.remote_addr = strdup(*param[RU_REMOTE_ADDRESS_IDX].strptr);
+ ru->eth_params.my_portc = *param[RU_LOCAL_PORTC_IDX].uptr;
+ ru->eth_params.remote_portc = *param[RU_REMOTE_PORTC_IDX].uptr;
+ ru->eth_params.my_portd = *param[RU_LOCAL_PORTD_IDX].uptr;
+ ru->eth_params.remote_portd = *param[RU_REMOTE_PORTD_IDX].uptr;
+ char *str = *param[RU_TRANSPORT_PREFERENCE_IDX].strptr;
+ if (strcmp(str, "udp") == 0) {
+ ru->if_south = LOCAL_RF;
+ ru->function = NGFI_RRU_IF5;
+ ru->eth_params.transp_preference = ETH_UDP_MODE;
+ LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (udp)\n", j);
+ } else if (strcmp(str, "raw") == 0) {
+ ru->if_south = LOCAL_RF;
+ ru->function = NGFI_RRU_IF5;
+ ru->eth_params.transp_preference = ETH_RAW_MODE;
+ LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (raw)\n", j);
+ } else if (strcmp(str, "udp_if4p5") == 0) {
+ ru->if_south = LOCAL_RF;
+ ru->function = NGFI_RRU_IF4p5;
+ ru->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
+ LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n", j);
+ } else if (strcmp(str, "raw_if4p5") == 0) {
+ ru->if_south = LOCAL_RF;
+ ru->function = NGFI_RRU_IF4p5;
+ ru->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
+ LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n", j);
+ }
}
- RC.ru[j]->openair0_cfg.tune_offset = get_softmodem_params()->tune_offset;
+ ru->max_pdschReferenceSignalPower = *param[RU_MAX_RS_EPRE_IDX].uptr;
+ ru->max_rxgain = *param[RU_MAX_RXGAIN_IDX].uptr;
+ ru->sf_extension = *param[RU_SF_EXTENSION_IDX].uptr;
+ } // strcmp(local_rf, "yes") == 0
+ else {
+ char *str = *param[RU_TRANSPORT_PREFERENCE_IDX].strptr;
+ LOG_D(PHY, "RU %d: Transport %s\n", j, str);
+ ru->eth_params.local_if_name = strdup(*param[RU_LOCAL_IF_NAME_IDX].strptr);
+ ru->eth_params.my_addr = strdup(*param[RU_LOCAL_ADDRESS_IDX].strptr);
+ ru->eth_params.remote_addr = strdup(*param[RU_REMOTE_ADDRESS_IDX].strptr);
+ ru->eth_params.my_portc = *param[RU_LOCAL_PORTC_IDX].uptr;
+ ru->eth_params.remote_portc = *param[RU_REMOTE_PORTC_IDX].uptr;
+ ru->eth_params.my_portd = *param[RU_LOCAL_PORTD_IDX].uptr;
+ ru->eth_params.remote_portd = *param[RU_REMOTE_PORTD_IDX].uptr;
- if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) {
- if (!(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX))) {
- RC.ru[j]->if_south = LOCAL_RF;
- RC.ru[j]->function = gNodeB_3GPP;
- LOG_D(PHY, "Setting function for RU %d to gNodeB_3GPP\n", j);
- } else {
- RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));
- RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr));
- RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr));
- RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr);
- RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr);
- RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr);
- RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr);
-
- if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) {
- RC.ru[j]->if_south = LOCAL_RF;
- RC.ru[j]->function = NGFI_RRU_IF5;
- RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE;
- LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (udp)\n", j);
- } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) {
- RC.ru[j]->if_south = LOCAL_RF;
- RC.ru[j]->function = NGFI_RRU_IF5;
- RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE;
- LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (raw)\n", j);
- } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) {
- RC.ru[j]->if_south = LOCAL_RF;
- RC.ru[j]->function = NGFI_RRU_IF4p5;
- RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
- LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n", j);
- } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) {
- RC.ru[j]->if_south = LOCAL_RF;
- RC.ru[j]->function = NGFI_RRU_IF4p5;
- RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
- LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n", j);
- }
- }
-
- RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);;
- RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr);
- RC.ru[j]->sf_extension = *(RUParamList.paramarray[j][RU_SF_EXTENSION_IDX].uptr);
- } //strcmp(local_rf, "yes") == 0
- else {
- LOG_D(PHY, "RU %d: Transport %s\n", j, *(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr));
- RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));
- RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr));
- RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr));
- RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr);
- RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr);
- RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr);
- RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr);
-
- if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) {
- RC.ru[j]->if_south = REMOTE_IF5;
- RC.ru[j]->function = NGFI_RAU_IF5;
- RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE;
- } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_ecpri_if5") == 0) {
- RC.ru[j]->if_south = REMOTE_IF5;
- RC.ru[j]->function = NGFI_RAU_IF5;
- RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF5_ECPRI_MODE;
- } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) {
- RC.ru[j]->if_south = REMOTE_IF5;
- RC.ru[j]->function = NGFI_RAU_IF5;
- RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE;
- } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) {
- RC.ru[j]->if_south = REMOTE_IF4p5;
- RC.ru[j]->function = NGFI_RAU_IF4p5;
- RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
- } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) {
- RC.ru[j]->if_south = REMOTE_IF4p5;
- RC.ru[j]->function = NGFI_RAU_IF4p5;
- RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
- }
- } /* strcmp(local_rf, "yes") != 0 */
-
- RC.ru[j]->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr);
- RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr);
- RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr);
- RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr);
- RC.ru[j]->if_frequency = *(RUParamList.paramarray[j][RU_IF_FREQUENCY].u64ptr);
- RC.ru[j]->if_freq_offset = *(RUParamList.paramarray[j][RU_IF_FREQ_OFFSET].iptr);
- RC.ru[j]->sl_ahead = *(RUParamList.paramarray[j][RU_SL_AHEAD].iptr);
- RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt;
- for (int i = 0; i < RC.ru[j]->num_bands; i++)
- RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i];
- RC.ru[j]->openair0_cfg.nr_flag = *(RUParamList.paramarray[j][RU_NR_FLAG].iptr);
- RC.ru[j]->openair0_cfg.nr_band = RC.ru[j]->band[0];
- RC.ru[j]->openair0_cfg.nr_scs_for_raster = *(RUParamList.paramarray[j][RU_NR_SCS_FOR_RASTER].iptr);
- LOG_D(PHY,
- "[RU %d] Setting nr_flag %d, nr_band %d, nr_scs_for_raster %d\n",
- j,
- RC.ru[j]->openair0_cfg.nr_flag,
- RC.ru[j]->openair0_cfg.nr_band,
- RC.ru[j]->openair0_cfg.nr_scs_for_raster);
- RC.ru[j]->openair0_cfg.rxfh_cores[0] = *(RUParamList.paramarray[j][RU_RXFH_CORE_ID].iptr);
- RC.ru[j]->openair0_cfg.txfh_cores[0] = *(RUParamList.paramarray[j][RU_TXFH_CORE_ID].iptr);
- RC.ru[j]->num_tpcores = *(RUParamList.paramarray[j][RU_NUM_TP_CORES].iptr);
- RC.ru[j]->half_slot_parallelization = *(RUParamList.paramarray[j][RU_HALF_SLOT_PARALLELIZATION].iptr);
- RC.ru[j]->ru_thread_core = *(RUParamList.paramarray[j][RU_RU_THREAD_CORE].iptr);
- LOG_D(PHY, "[RU %d] Setting half-slot parallelization to %d\n", j, RC.ru[j]->half_slot_parallelization);
- AssertFatal(RC.ru[j]->num_tpcores <= RUParamList.paramarray[j][RU_TP_CORES].numelt, "Number of TP cores should be <=16\n");
- for (int i = 0; i < RC.ru[j]->num_tpcores; i++)
- RC.ru[j]->tpcores[i] = RUParamList.paramarray[j][RU_TP_CORES].iptr[i];
- }// j=0..num_rus
- } else {
- RC.nb_RU = 0;
- } // setting != NULL
+ if (strcmp(str, "udp") == 0) {
+ ru->if_south = REMOTE_IF5;
+ ru->function = NGFI_RAU_IF5;
+ ru->eth_params.transp_preference = ETH_UDP_MODE;
+ } else if (strcmp(str, "udp_ecpri_if5") == 0) {
+ ru->if_south = REMOTE_IF5;
+ ru->function = NGFI_RAU_IF5;
+ ru->eth_params.transp_preference = ETH_UDP_IF5_ECPRI_MODE;
+ } else if (strcmp(str, "raw") == 0) {
+ ru->if_south = REMOTE_IF5;
+ ru->function = NGFI_RAU_IF5;
+ ru->eth_params.transp_preference = ETH_RAW_MODE;
+ } else if (strcmp(str, "udp_if4p5") == 0) {
+ ru->if_south = REMOTE_IF4p5;
+ ru->function = NGFI_RAU_IF4p5;
+ ru->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
+ } else if (strcmp(str, "raw_if4p5") == 0) {
+ ru->if_south = REMOTE_IF4p5;
+ ru->function = NGFI_RAU_IF4p5;
+ ru->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
+ }
+ } /* strcmp(local_rf, "yes") != 0 */
+ ru->nb_tx = *param[RU_NB_TX_IDX].uptr;
+ ru->nb_rx = *param[RU_NB_RX_IDX].uptr;
+ ru->att_tx = *param[RU_ATT_TX_IDX].uptr;
+ ru->att_rx = *param[RU_ATT_RX_IDX].uptr;
+ ru->if_frequency = *param[RU_IF_FREQUENCY].u64ptr;
+ ru->if_freq_offset = *param[RU_IF_FREQ_OFFSET].iptr;
+ ru->sl_ahead = *param[RU_SL_AHEAD].iptr;
+ ru->num_bands = param[RU_BAND_LIST_IDX].numelt;
+ for (int i = 0; i < ru->num_bands; i++)
+ ru->band[i] = param[RU_BAND_LIST_IDX].iptr[i];
+ ru->openair0_cfg.nr_flag = *param[RU_NR_FLAG].iptr;
+ ru->openair0_cfg.nr_band = ru->band[0];
+ ru->openair0_cfg.nr_scs_for_raster = *param[RU_NR_SCS_FOR_RASTER].iptr;
+ LOG_D(PHY,
+ "[RU %d] Setting nr_flag %d, nr_band %d, nr_scs_for_raster %d\n",
+ j,
+ ru->openair0_cfg.nr_flag,
+ ru->openair0_cfg.nr_band,
+ ru->openair0_cfg.nr_scs_for_raster);
+ ru->openair0_cfg.rxfh_cores[0] = *param[RU_RXFH_CORE_ID].iptr;
+ ru->openair0_cfg.txfh_cores[0] = *param[RU_TXFH_CORE_ID].iptr;
+ ru->num_tpcores = *param[RU_NUM_TP_CORES].iptr;
+ ru->half_slot_parallelization = *param[RU_HALF_SLOT_PARALLELIZATION].iptr;
+ ru->ru_thread_core = *param[RU_RU_THREAD_CORE].iptr;
+ LOG_D(PHY, "[RU %d] Setting half-slot parallelization to %d\n", j, ru->half_slot_parallelization);
+ AssertFatal(ru->num_tpcores <= param[RU_TP_CORES].numelt, "Number of TP cores should be <=16\n");
+ for (int i = 0; i < ru->num_tpcores; i++)
+ ru->tpcores[i] = param[RU_TP_CORES].iptr[i];
+ } // j=0..num_rus
return;
}
diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h
index 3ab6d1e73d..61823d43cd 100644
--- a/executables/nr-softmodem-common.h
+++ b/executables/nr-softmodem-common.h
@@ -133,7 +133,6 @@ extern int sync_var;
extern int transmission_mode;
extern double cpuf;
-extern int emulate_rf;
extern int numerology;
extern int usrp_tx_thread;
void wait_gNBs(void);
diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c
index 5cc5e3a4fc..d8df770cb8 100644
--- a/executables/nr-softmodem.c
+++ b/executables/nr-softmodem.c
@@ -24,7 +24,6 @@
#include "common/config/config_userapi.h"
#include "common/utils/load_module_shlib.h"
-#include "RRC/LTE/rrc_vars.h"
#ifdef SMBV
#include "PHY/TOOLS/smbv.h"
unsigned short config_frames[4] = {2,9,11,13};
@@ -119,7 +118,6 @@ double rx_gain_off = 0.0;
static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/;
int chain_offset = 0;
-int emulate_rf = 0;
int numerology = 0;
double cpuf;
@@ -130,52 +128,6 @@ void pdcp_run(const protocol_ctxt_t *const ctxt_pP)
abort();
}
-/*---------------------BMC: timespec helpers -----------------------------*/
-
-struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
-struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
-
-struct timespec clock_difftime(struct timespec start, struct timespec end) {
- struct timespec temp;
-
- if ((end.tv_nsec-start.tv_nsec)<0) {
- temp.tv_sec = end.tv_sec-start.tv_sec-1;
- temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
- } else {
- temp.tv_sec = end.tv_sec-start.tv_sec;
- temp.tv_nsec = end.tv_nsec-start.tv_nsec;
- }
-
- return temp;
-}
-
-void print_difftimes(void)
-{
- LOG_I(HW, "difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
-}
-
-void update_difftimes(struct timespec start, struct timespec end) {
- struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 };
- int changed = 0;
- diff_time = clock_difftime(start, end);
-
- if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) {
- min_diff_time.tv_nsec = diff_time.tv_nsec;
- changed = 1;
- }
-
- if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) {
- max_diff_time.tv_nsec = diff_time.tv_nsec;
- changed = 1;
- }
-
-#if 1
-
- if (changed) print_difftimes();
-
-#endif
-}
-
/*------------------------------------------------------------------------*/
unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) {
diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c
index 6ed407a507..8b331e4976 100644
--- a/executables/nr-uesoftmodem.c
+++ b/executables/nr-uesoftmodem.c
@@ -249,7 +249,7 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){
}
-void init_openair0()
+static void init_openair0()
{
int card;
int freq_off = 0;
@@ -261,7 +261,6 @@ void init_openair0()
for (card=0; cardthreequarter_fs;
openair0_cfg[card].sample_rate = frame_parms->samples_per_subframe * 1e3;
openair0_cfg[card].samples_per_frame = frame_parms->samples_per_frame;
diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h
index 33d4f4cf04..d122b1a1d5 100644
--- a/executables/softmodem-common.h
+++ b/executables/softmodem-common.h
@@ -96,7 +96,6 @@ extern "C"
#define CONFIG_HLP_NUMEROLOGY "adding numerology for 5G\n"
#define CONFIG_HLP_BAND "band index\n"
-#define CONFIG_HLP_EMULATE_RF "Emulated RF enabled(disable by defult)\n"
#define CONFIG_HLP_PARALLEL_CMD "three config for level of parallelism 'PARALLEL_SINGLE_THREAD', 'PARALLEL_RU_L1_SPLIT', or 'PARALLEL_RU_L1_TRX_SPLIT'\n"
#define CONFIG_HLP_WORKER_CMD "two option for worker 'WORKER_DISABLE' or 'WORKER_ENABLE'\n"
#define CONFIG_HLP_USRP_THREAD "having extra thead for usrp tx\n"
@@ -128,7 +127,6 @@ extern "C"
#define CHAIN_OFFSET softmodem_params.chain_offset
#define NUMEROLOGY softmodem_params.numerology
#define BAND softmodem_params.band
-#define EMULATE_RF softmodem_params.emulate_rf
#define CLOCK_SOURCE softmodem_params.clock_source
#define TIMING_SOURCE softmodem_params.timing_source
#define TUNE_OFFSET softmodem_params.tune_offset
@@ -164,7 +162,6 @@ extern int usrp_tx_thread;
{"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, .iptr=&cpu_meas_enabled, .defintval=0, TYPE_INT, 0}, \
{"numerology" , CONFIG_HLP_NUMEROLOGY, 0, .iptr=&NUMEROLOGY, .defintval=1, TYPE_INT, 0}, \
{"band" , CONFIG_HLP_BAND, 0, .iptr=&BAND, .defintval=78, TYPE_INT, 0}, \
- {"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, .iptr=&EMULATE_RF, .defintval=0, TYPE_INT, 0}, \
{"parallel-config", CONFIG_HLP_PARALLEL_CMD, 0, .strptr=¶llel_config, .defstrval=NULL, TYPE_STRING, 0}, \
{"worker-config", CONFIG_HLP_WORKER_CMD, 0, .strptr=&worker_config, .defstrval=NULL, TYPE_STRING, 0}, \
{"noS1", CONFIG_HLP_NOS1, PARAMFLAG_BOOL, .uptr=&noS1, .defintval=0, TYPE_UINT, 0}, \
@@ -217,7 +214,6 @@ extern int usrp_tx_thread;
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
- { .s5 = { NULL } }, \
{ .s3a = { config_checkstr_assign_integer, \
{"MONOLITHIC", "PNF", "VNF", "AERIAL","UE_STUB_PNF","UE_STUB_OFFNET","STANDALONE_PNF"}, \
{NFAPI_MONOLITHIC, NFAPI_MODE_PNF, NFAPI_MODE_VNF, NFAPI_MODE_AERIAL,NFAPI_UE_STUB_PNF,NFAPI_UE_STUB_OFFNET,NFAPI_MODE_STANDALONE_PNF}, \
@@ -320,7 +316,6 @@ typedef struct {
int phy_test;
int do_ra;
uint8_t sl_mode;
- int emulate_rf;
int chain_offset;
int numerology;
int band;
diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c
index 48e31b7264..3de11d8003 100644
--- a/nfapi/oai_integration/nfapi_pnf.c
+++ b/nfapi/oai_integration/nfapi_pnf.c
@@ -88,7 +88,6 @@ extern int nfapi_sync_var;
extern int sync_var;
nfapi_tx_request_pdu_t *tx_request_pdu[1023][10][10]; // [frame][subframe][max_num_pdus]
-nfapi_nr_pdu_t *tx_data_request[1023][20][10]; //[frame][slot][max_num_pdus]
uint8_t tx_pdus[32][8][4096];
nfapi_ue_release_request_body_t release_rntis;
diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c
index 62a20ef822..815ec9ce26 100644
--- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c
+++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c
@@ -815,6 +815,10 @@ static int pmd_lcore_ldpc_dec(void *arg)
AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments);
set_ldpc_dec_op(ops_enq, bufs->inputs, bufs->hard_outputs, bufs->harq_outputs, nrLDPC_slot_decoding_parameters);
+ // Start timer
+ // We report timing only once in (0,0) since the timers are merged at the end
+ start_meas(&nrLDPC_slot_decoding_parameters->TBs[0].segments[0].ts_ldpc_decode);
+
uint16_t enq = 0, deq = 0;
while (enq < num_segments) {
uint16_t num_to_enq = num_segments - enq;
@@ -828,6 +832,10 @@ static int pmd_lcore_ldpc_dec(void *arg)
DevAssert(time_out <= TIME_OUT_POLL);
}
+ // Stop timer
+ // We report timing only once in (0,0) since the timers are merged at the end
+ stop_meas(&nrLDPC_slot_decoding_parameters->TBs[0].segments[0].ts_ldpc_decode);
+
if (deq == enq) {
ret = retrieve_ldpc_dec_op(ops_deq, nrLDPC_slot_decoding_parameters);
AssertFatal(ret == 0, "LDPC offload decoder failed!");
diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c
index dcdc4ee433..60bc63dac4 100644
--- a/openair1/PHY/INIT/nr_init.c
+++ b/openair1/PHY/INIT/nr_init.c
@@ -131,7 +131,6 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
crcTableInit();
init_byte2m128i();
- init_byte2bit16();
init_pucch2_luts();
nr_init_fde(); // Init array for frequency equalization of transform precoding of PUSCH
diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c
index e220549045..90c9d63925 100644
--- a/openair1/PHY/LTE_TRANSPORT/prach.c
+++ b/openair1/PHY/LTE_TRANSPORT/prach.c
@@ -69,8 +69,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
uint32_t preamble_shift2;
uint16_t preamble_index0=0,n_shift_ra=0,n_shift_ra_bar;
uint16_t d_start=0;
- uint16_t numshift=0;
- uint16_t *prach_root_sequence_map;
+ uint16_t numshift = 0;
uint8_t not_found;
int k=0;
uint16_t u;
@@ -221,7 +220,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
if (eNB) start_meas(&eNB->rx_prach);
- prach_root_sequence_map = (prach_fmt < 4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
+ const uint16_t *prach_root_sequence_map = (prach_fmt < 4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
// PDP is oversampled, e.g. 1024 sample instead of 839
// Adapt the NCS (zero-correlation zones) with oversampling factor e.g. 1024/839
NCS2 = (N_ZC==839) ? ((NCS<<10)/839) : ((NCS<<8)/139);
@@ -495,7 +494,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
new_dft = 0;
if (br_flag == 1) {
- Xu=(c16_t *)eNB->X_u_br[ce_level][preamble_offset-first_nonzero_root_idx];
+ Xu = eNB->X_u_br[ce_level][preamble_offset - first_nonzero_root_idx];
prach_ifft = prach_ifftp[prach_ifft_cnt++];
if (eNB->prach_vars_br.repetition_number[ce_level]==1) memset(prach_ifft,0,((N_ZC==839)?2048:256)*sizeof(int32_t));
diff --git a/openair1/PHY/LTE_TRANSPORT/prach_common.c b/openair1/PHY/LTE_TRANSPORT/prach_common.c
index 2d9ef9d712..0939398c60 100644
--- a/openair1/PHY/LTE_TRANSPORT/prach_common.c
+++ b/openair1/PHY/LTE_TRANSPORT/prach_common.c
@@ -35,12 +35,13 @@
#include "PHY/phy_extern_ue.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "common/utils/lte/prach_utils.h"
+#include "openair1/PHY/LTE_TRANSPORT/prach_extern.h"
const uint16_t NCS_unrestricted[16] = {0, 13, 15, 18, 22, 26, 32, 38, 46, 59, 76, 93, 119, 167, 279, 419};
const uint16_t NCS_restricted[15] = {15, 18, 22, 26, 32, 38, 46, 55, 68, 82, 100, 128, 158, 202, 237}; // high-speed case
const uint16_t NCS_4[7] = {2, 4, 6, 8, 10, 12, 15};
-int16_t ru[2*839]; // quantized roots of unity
+c16_t root_unit[839]; // quantized roots of unity
static uint32_t ZC_inv[839]; // multiplicative inverse for roots u
uint16_t du[838];
@@ -367,13 +368,13 @@ int is_prach_subframe(LTE_DL_FRAME_PARMS *frame_parms, uint32_t frame, uint8_t s
return(prach_mask);
}
-
void compute_prach_seq(uint16_t rootSequenceIndex,
uint8_t prach_ConfigIndex,
uint8_t zeroCorrelationZoneConfig,
uint8_t highSpeedFlag,
frame_type_t frame_type,
- uint32_t X_u[64][839]) {
+ c16_t X_u[64][839])
+{
// Compute DFT of x_u => X_u[k] = x_u(inv(u)*k)^* X_u[k] = exp(j\pi u*inv(u)*k*(inv(u)*k+1)/N_ZC)
unsigned int k,inv_u,i,NCS=0,num_preambles;
int N_ZC;
@@ -495,7 +496,7 @@ void compute_prach_seq(uint16_t rootSequenceIndex,
for (k=0; kframe_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex,
ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset,
tdd_mapindex, Nf);
- prach_root_sequence_map = (prach_fmt<4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
+ const uint16_t *prach_root_sequence_map = (prach_fmt < 4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
/*
// this code is not part of get_prach_prb_offset
if (frame_type == TDD) { // TDD
@@ -215,20 +210,6 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1
#endif
// nsymb = (frame_parms->Ncp==0) ? 14:12;
// subframe_offset = (unsigned int)frame_parms->ofdm_symbol_size*subframe*nsymb;
- k = (12*n_ra_prb) - 6*ue->frame_parms.N_RB_UL;
-
- if (k<0)
- k+=ue->frame_parms.ofdm_symbol_size;
-
- k*=12;
- k+=13;
- Xu = (int16_t *)ue->X_u[preamble_offset-first_nonzero_root_idx];
- /*
- k+=(12*ue->frame_parms.first_carrier_offset);
- if (k>(12*ue->frame_parms.ofdm_symbol_size))
- k-=(12*ue->frame_parms.ofdm_symbol_size);
- */
- k*=2;
switch (ue->frame_parms.N_RB_UL) {
case 6:
@@ -259,20 +240,26 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1
break;
}
+ {
+ int k = (12 * n_ra_prb) - 6 * ue->frame_parms.N_RB_UL;
- for (offset=0,offset2=0; offset= N_ZC)
- offset2 -= N_ZC;
+ if (k < 0)
+ k += ue->frame_parms.ofdm_symbol_size;
- Xu_re = (((int32_t)Xu[offset<<1]*amp)>>15);
- Xu_im = (((int32_t)Xu[1+(offset<<1)]*amp)>>15);
- prachF[k++]= ((Xu_re*ru[offset2<<1]) - (Xu_im*ru[1+(offset2<<1)]))>>15;
- prachF[k++]= ((Xu_im*ru[offset2<<1]) + (Xu_re*ru[1+(offset2<<1)]))>>15;
+ k *= 12;
+ k += 13;
+ c16_t *Xu_ue = ue->X_u[preamble_offset - first_nonzero_root_idx];
+ c16_t *complex_prachF = (c16_t *)prachF;
+ for (int offset = 0, offset2 = 0; offset < N_ZC; offset++, offset2 += preamble_shift) {
+ if (offset2 >= N_ZC)
+ offset2 -= N_ZC;
+ c16_t Xu = c16mulRealShift(*Xu_ue++, amp, 15);
+ complex_prachF[k++] = c16mulShift(Xu, root_unit[offset2], 15);
- if (k==(12*2*ue->frame_parms.ofdm_symbol_size))
- k=0;
+ if (k == 12 * ue->frame_parms.ofdm_symbol_size)
+ k = 0;
+ }
}
-
switch (prach_fmt) {
case 0:
Ncp = 3168;
diff --git a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h
index 9aab56e52a..06bf87fc74 100644
--- a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h
+++ b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h
@@ -1649,8 +1649,7 @@ void compute_prach_seq(uint16_t rootSequenceIndex,
uint8_t zeroCorrelationZoneConfig,
uint8_t highSpeedFlag,
frame_type_t frame_type,
- uint32_t X_u[64][839]);
-
+ c16_t X_u[64][839]);
void init_prach_tables(int N_ZC);
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
index 667c7146b0..239b6f2f29 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
@@ -305,6 +305,10 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
LOG_D(PHY, "ULSCH %d in error\n", ULSCH_id);
}
offset += ((harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
+
+ merge_meas(&phy_vars_gNB->ts_deinterleave, &nrLDPC_segment_decoding_parameters.ts_deinterleave);
+ merge_meas(&phy_vars_gNB->ts_rate_unmatch, &nrLDPC_segment_decoding_parameters.ts_rate_unmatch);
+ merge_meas(&phy_vars_gNB->ts_ldpc_decode, &nrLDPC_segment_decoding_parameters.ts_ldpc_decode);
}
}
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
index e8d8efeb28..bd4ee92284 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
@@ -7,6 +7,7 @@
#include "PHY/NR_REFSIG/ptrs_nr.h"
#include "PHY/NR_ESTIMATION/nr_ul_estimation.h"
#include "PHY/defs_nr_common.h"
+#include "PHY/nr_phy_common/inc/nr_phy_common.h"
#include "common/utils/nr/nr_common.h"
#include
#include "PHY/sse_intrin.h"
@@ -210,31 +211,6 @@ static int get_nb_re_pusch (NR_DL_FRAME_PARMS *frame_parms, nfapi_nr_pusch_pdu_t
} else return(rel15_ul->rb_size * NR_NB_SC_PER_RB);
}
-// compute average channel_level on each (TX,RX) antenna pair
-static void nr_ulsch_channel_level(int size_est,
- int ul_ch_estimates_ext[][size_est],
- NR_DL_FRAME_PARMS *frame_parms,
- int32_t *avg,
- uint8_t symbol,
- uint32_t len,
- uint8_t nrOfLayers)
-{
- int16_t x = factor2(len);
- int16_t y = (len)>>x;
-
- for (int aatx = 0; aatx < nrOfLayers; aatx++) {
- for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
-
- simde__m128i *ul_ch128 = (simde__m128i *)&ul_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx + aarx][symbol * len];
-
- //compute average level
- avg[aatx * frame_parms->nb_antennas_rx + aarx] = simde_mm_average(ul_ch128, len, x, y);
- //LOG_D(PHY, "Channel level: %d\n", avg[aatx * frame_parms->nb_antennas_rx + aarx]);
- }
- }
-
-}
-
static void nr_ulsch_channel_compensation(uint32_t buffer_length,
int nb_rx_ant,
c16_t rxFext[][buffer_length],
@@ -1394,8 +1370,6 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
rel15_ul,
frame_parms);
- int avgs = 0;
- int avg[frame_parms->nb_antennas_rx*rel15_ul->nrOfLayers];
uint8_t shift_ch_ext = rel15_ul->nrOfLayers > 1 ? log2_approx(max_ch >> 11) : 0;
//----------------------------------------------------------
@@ -1410,15 +1384,17 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
rel15_ul->nrOfLayers,
rel15_ul->rb_size,
shift_ch_ext);
-
- nr_ulsch_channel_level(size_est,
- ul_ch_estimates_ext,
- frame_parms,
- avg,
- meas_symbol, // index of the start symbol
- nb_re_pusch, // number of the re in pusch
- rel15_ul->nrOfLayers);
+ int avg[frame_parms->nb_antennas_rx*rel15_ul->nrOfLayers];
+ nr_channel_level(meas_symbol,
+ size_est,
+ (c16_t (*)[size_est])ul_ch_estimates_ext,
+ frame_parms->nb_antennas_rx,
+ rel15_ul->nrOfLayers,
+ avg,
+ nb_re_pusch);
+
+ int avgs = 0;
for (int nl = 0; nl < rel15_ul->nrOfLayers; nl++)
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
avgs = cmax(avgs, avg[nl * frame_parms->nb_antennas_rx + aarx]);
diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
index b4e2c413cf..43b27e3932 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
@@ -36,6 +36,7 @@
#include "PHY/CODING/nrPolar_tools/nr_polar_dci_defs.h"
#include "PHY/phy_extern.h"
#include "PHY/CODING/coding_extern.h"
+#include "PHY/nr_phy_common/inc/nr_phy_common.h"
#include "PHY/sse_intrin.h"
#include "common/utils/nr/nr_common.h"
#include
@@ -197,20 +198,6 @@ static void nr_pdcch_llr(uint32_t sz, c16_t *rxF, c16_t *llr)
}
}
-//compute average channel_level on each (TX,RX) antenna pair
-static int32_t nr_pdcch_channel_level(int nb_re, int arraySz, c16_t dl_ch_estimates_ext[][arraySz], int nb_antennas_rx)
-{
- int32_t avgs = 0;
- for (int aarx = 0; aarx < nb_antennas_rx; aarx++) {
- simde__m128i *dl_ch128 = (simde__m128i *)&dl_ch_estimates_ext[aarx];
- // compute average level
- // if nb_re is not %4, some samples are missed inside simde_mm_average, so let's discard it
- int32_t tmp = simde_mm_average(dl_ch128, nb_re & ~3, 0, nb_re & ~3);
- avgs = cmax(avgs, tmp);
- }
- return avgs;
-}
-
// This function will extract the mapped DM-RS PDCCH REs as per 38.211 Section 7.4.1.3.2 (Mapping to physical resources)
static void nr_pdcch_extract_rbs_single(uint32_t rxdataF_sz,
uint32_t coreset_nbr_rb,
@@ -372,9 +359,13 @@ void nr_rx_pdcch(PHY_VARS_NR_UE *ue,
rel15->coreset.frequency_domain_resource,
rel15->BWPStart);
- LOG_D(NR_PHY_DCI, "in nr_pdcch_channel_level(dl_ch_estimates_ext -> dl_ch_estimates_ext)\n");
+ LOG_D(NR_PHY_DCI, "in channel level function (dl_ch_estimates_ext -> dl_ch_estimates_ext)\n");
// compute channel level based on ofdm symbol 0
- int32_t avgs = nr_pdcch_channel_level(n_rb, arraySz, pdcch_dl_ch_estimates_ext, antRx);
+ int avg[antRx];
+ nr_channel_level(0, arraySz, pdcch_dl_ch_estimates_ext, antRx, 1, avg, n_rb);
+ int avgs = avg[0];
+ for (int i = 1; i < antRx; i++)
+ avgs = cmax(avgs, avg[i]);
uint8_t log2_maxh = (log2_approx(avgs) / 2) + 5; //+antRx;
#ifdef UE_DEBUG_TRACE
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
index d0457b3bb9..1da2ef8d45 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
@@ -193,20 +193,6 @@ static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol,
unsigned char output_shift,
PHY_NR_MEASUREMENTS *measurements);
-/** \brief This function computes the average channel level over all allocated RBs and antennas (TX/RX) in order to compute output shift for compensated signal
- @param dl_ch_estimates_ext Channel estimates in allocated RBs
- @param frame_parms Pointer to frame descriptor
- @param avg Pointer to average signal strength
- @param pilots_flag Flag to indicate pilots in symbol
- @param nb_rb Number of allocated RBs
-*/
-static void nr_dlsch_channel_level(uint32_t rx_size_symbol,
- int32_t dl_ch_estimates_ext[][rx_size_symbol],
- uint8_t n_rx,
- uint8_t n_tx,
- int32_t avg[MAX_ANT][MAX_ANT],
- uint32_t len);
-
void nr_dlsch_scale_channel(uint32_t rx_size_symbol,
int32_t dl_ch_estimates_ext[][rx_size_symbol],
NR_DL_FRAME_PARMS *frame_parms,
@@ -538,25 +524,25 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
//----------------------------------------------------------
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS);
if (first_symbol_flag) {
- int32_t avg[MAX_ANT][MAX_ANT] = {};
+ int32_t avg[nl * n_rx];
if (nb_re_pdsch)
- nr_dlsch_channel_level(rx_size_symbol, dl_ch_estimates_ext, frame_parms->nb_antennas_rx, nl, avg, nb_re_pdsch);
+ nr_channel_level(0, rx_size_symbol, (c16_t (*)[rx_size_symbol])dl_ch_estimates_ext, n_rx, nl, avg, nb_re_pdsch);
else
LOG_E(NR_PHY, "Average channel level is 0: nb_rb_pdsch = %d, nb_re_pdsch = %d\n", nb_rb_pdsch, nb_re_pdsch);
int avgs = 0;
int32_t median[MAX_ANT][MAX_ANT];
- for (int aatx = 0; aatx < nl; aatx++)
+ for (int l = 0; l < nl; l++)
for (int aarx = 0; aarx < n_rx; aarx++) {
- avgs = cmax(avgs, avg[aatx][aarx]);
- LOG_D(PHY, "nb_rb %d avg_%d_%d Power per SC is %d\n", nb_rb_pdsch, aarx, aatx, avg[aatx][aarx]);
+ avgs = cmax(avgs, avg[l * n_rx + aarx]);
+ LOG_D(PHY, "nb_rb %d avg_%d_%d Power per SC is %d\n", nb_rb_pdsch, aarx, l, avg[l * n_rx + aarx]);
LOG_D(PHY, "avgs Power per SC is %d\n", avgs);
- median[aatx][aarx] = avg[aatx][aarx];
+ median[l][aarx] = avg[l * n_rx + aarx];
}
if (nl > 1) {
nr_dlsch_channel_level_median(rx_size_symbol, dl_ch_estimates_ext, median, nl, n_rx, nb_re_pdsch);
- for (int aatx = 0; aatx < nl; aatx++) {
+ for (int l = 0; l < nl; l++) {
for (int aarx = 0; aarx < n_rx; aarx++) {
- avgs = cmax(avgs, median[aatx][aarx]);
+ avgs = cmax(avgs, median[l][aarx]);
}
}
}
@@ -795,53 +781,6 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
return (0);
}
-void nr_dlsch_deinterleaving(uint8_t symbol,
- uint8_t start_symbol,
- uint16_t L,
- uint16_t *llr,
- uint16_t *llr_deint,
- uint16_t nb_rb_pdsch)
-{
-
- uint32_t bundle_idx, N_bundle, R, C, r,c;
- int32_t m,k;
- uint8_t nb_re;
-
- R=2;
- N_bundle = nb_rb_pdsch/L;
- C=N_bundle/R;
-
- uint32_t bundle_deint[N_bundle];
- memset(bundle_deint, 0 , sizeof(bundle_deint));
-
- printf("N_bundle %u L %d nb_rb_pdsch %d\n",N_bundle, L,nb_rb_pdsch);
-
- if (symbol==start_symbol)
- nb_re = 6;
- else
- nb_re = 12;
-
-
- AssertFatal(llr!=NULL,"nr_dlsch_deinterleaving: FATAL llr is Null\n");
-
-
- for (c =0; c< C; c++){
- for (r=0; r> x;
-
- uint32_t nb_rb_0 = len / NR_NB_SC_PER_RB + ((len % NR_NB_SC_PER_RB) ? 1 : 0);
- LOG_D(NR_PHY, "nb_rb_0 %d len %d = %d * 2^(%d)\n", nb_rb_0, len, y, x);
-
- for (int aatx = 0; aatx < n_tx; aatx++) {
- for (int aarx = 0; aarx < n_rx; aarx++) {
-
- simde__m128i *dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[(aatx * n_rx) + aarx];
-
- //compute average level
- avg[aatx][aarx] = simde_mm_average(dl_ch128, nb_rb_0 * 12, x, y);
- //LOG_D(PHY, "Channel level: %d\n", avg[aatx][aarx]);
- }
- }
-}
-
static void nr_dlsch_channel_level_median(uint32_t rx_size_symbol,
int32_t dl_ch_estimates_ext[][rx_size_symbol],
int32_t median[MAX_ANT][MAX_ANT],
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
index 298de612ee..8065da24b2 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
@@ -38,6 +38,7 @@
#include
#include
#include "openair1/PHY/NR_REFSIG/nr_refsig_common.h"
+#include "PHY/nr_phy_common/inc/nr_phy_common.h"
#include "instrumentation.h"
//#define DEBUG_PBCH
//#define DEBUG_PBCH_ENCODING
@@ -201,31 +202,6 @@ static uint16_t nr_pbch_extract(uint32_t rxdataF_sz,
return(0);
}
-//__m128i avg128;
-
-//compute average channel_level on each (TX,RX) antenna pair
-int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
- const NR_DL_FRAME_PARMS *frame_parms,
- int nb_re)
-{
- int32_t avg2 = 0;
-
- for (int aarx=0; aarxnb_antennas_rx; aarx++) {
-
- simde__m128i *dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[aarx];
-
- //compute average level
- int32_t avg1 = simde_mm_average(dl_ch128, nb_re, 0, nb_re);
-
- if (avg1>avg2)
- avg2 = avg1;
-
- //LOG_I(PHY,"Channel level : %d, %d\n",avg1, avg2);
- }
-
- return(avg2);
-}
-
void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL],
struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
int nb_re,
@@ -346,7 +322,6 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
const struct complex16 rxdataF[][rxdataFSize])
{
TracyCZone(ctx, true);
- int max_h=0;
int symbol;
uint8_t Lmax=frame_parms->Lmax;
int M = NR_POLAR_PBCH_E;
@@ -390,11 +365,14 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
LOG_I(PHY,"[PHY] PBCH starting channel_level\n");
#endif
+ int max_h = 0;
if (symbol == 1) {
- max_h = nr_pbch_channel_level(dl_ch_estimates_ext,
- frame_parms,
- nb_re);
- log2_maxh = 3+(log2_approx(max_h)/2);
+ int avg[frame_parms->nb_antennas_rx];
+ nr_channel_level(0, PBCH_MAX_RE_PER_SYMBOL, dl_ch_estimates_ext, frame_parms->nb_antennas_rx, 1, avg, nb_re);
+ max_h = avg[0];
+ for (int i = 1; i < frame_parms->nb_antennas_rx; i++)
+ max_h = cmax(avg[i], max_h);
+ log2_maxh = 3 + (log2_approx(max_h) / 2);
}
#ifdef DEBUG_PBCH
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c b/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c
index 7406855cc4..1010a6e5e8 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c
@@ -25,6 +25,7 @@
#include "common/utils/LOG/log.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "PHY/TOOLS/phy_scope_interface.h"
+#include "PHY/nr_phy_common/inc/nr_phy_common.h"
// #define DEBUG_PSBCH
@@ -158,8 +159,11 @@ int nr_rx_psbch(PHY_VARS_NR_UE *ue,
int max_h = 0;
if (symbol == 0) {
- max_h = nr_pbch_channel_level(dl_ch_estimates_ext, frame_parms, nb_re);
- // log2_maxh = 3+(log2_approx(max_h)/2);
+ int avg[frame_parms->nb_antennas_rx];
+ nr_channel_level(0, PBCH_MAX_RE_PER_SYMBOL, dl_ch_estimates_ext, frame_parms->nb_antennas_rx, 1, avg, nb_re);
+ max_h = avg[0];
+ for (int i = 1; i < frame_parms->nb_antennas_rx; i++)
+ max_h = cmax(avg[i], max_h);
log2_maxh = 5 + (log2_approx(max_h) / 2); // LLR32 crc error. LLR 16 CRC works
}
#ifdef DEBUG_PSBCH
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
index a4098394ac..44a3611bf0 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
@@ -59,13 +59,6 @@ typedef struct pdsch_scope_req_s {
*/
void nr_ue_dlsch_init(NR_UE_DLSCH_t *dlsch_list, int num_dlsch, uint8_t max_ldpc_iterations);
-void nr_dlsch_deinterleaving(uint8_t symbol,
- uint8_t start_symbol,
- uint16_t L,
- uint16_t *llr,
- uint16_t *llr_deint,
- uint16_t nb_rb_pdsch);
-
void nr_conjch0_mult_ch1(c16_t *ch0, c16_t *ch1, c16_t *ch0conj_ch1, unsigned short nb_rb, unsigned char output_shift0);
/** \brief This is the alternative top-level entry point for DLSCH decoding in UE.
@@ -346,9 +339,6 @@ void nr_tx_psbch(PHY_VARS_NR_UE *UE, uint32_t frame_tx, uint32_t slot_tx, sl_nr_
nr_initial_sync_t sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc, int num_frames);
// Reuse already existing PBCH functions
-int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
- const NR_DL_FRAME_PARMS *frame_parms,
- int nb_re);
void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL],
struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
int nb_re,
diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h
index a2c39852f5..e72465c4a9 100644
--- a/openair1/PHY/defs_RU.h
+++ b/openair1/PHY/defs_RU.h
@@ -255,7 +255,6 @@ typedef struct RU_proc_t_s {
int instance_cnt_feptx;
/// \internal This variable is protected by \ref mutex_ru_thread
int instance_cnt_ru;
- int instance_cnt_emulateRF;
/// pthread structure for RU FH processing thread
pthread_t pthread_FH;
pthread_t pthread_FH1;
@@ -271,8 +270,6 @@ typedef struct RU_proc_t_s {
pthread_t pthread_fep[8];
/// pthread struct for RU TX FEP worker thread
pthread_t pthread_feptx;
- /// pthread struct for emulated RF
- pthread_t pthread_emulateRF;
/// pthread structure for asychronous RX/TX processing thread
pthread_t pthread_asynch_rxtx;
/// flag to indicate first RX acquisition
@@ -296,8 +293,6 @@ typedef struct RU_proc_t_s {
pthread_attr_t attr_fep;
/// pthread attributes for worker feptx thread
pthread_attr_t attr_feptx;
- /// pthread attributes for emulated RF
- pthread_attr_t attr_emulateRF;
/// scheduling parameters for RU FH thread
struct sched_param sched_param_FH;
struct sched_param sched_param_FH1;
@@ -324,8 +319,6 @@ typedef struct RU_proc_t_s {
pthread_cond_t cond_fep[8];
/// condition varible for RU TX FEP thread
pthread_cond_t cond_feptx;
- /// condition varible for emulated RF
- pthread_cond_t cond_emulateRF;
/// condition variable for eNB signal
pthread_cond_t cond_eNBs;
/// condition variable for gNB signal
@@ -353,8 +346,6 @@ typedef struct RU_proc_t_s {
pthread_mutex_t mutex_feptx;
/// mutex for ru_thread
pthread_mutex_t mutex_ru;
- /// mutex for emulated RF thread
- pthread_mutex_t mutex_emulateRF;
/// symbol mask for IF4p5 reception per subframe
uint32_t symbol_mask[10];
/// time measurements for each subframe
@@ -394,7 +385,6 @@ typedef struct RU_proc_t_s {
/// pipeline ready state
int ru_rx_ready;
int ru_tx_ready;
- int emulate_rf_busy;
/// structure for precoding thread
RU_prec_t prec[16];
@@ -407,7 +397,6 @@ typedef enum {
REMOTE_IF4p5 =3,
REMOTE_IF1pp =4,
MAX_RU_IF_TYPES =5
- //EMULATE_RF =6
} RU_if_south_t;
@@ -453,8 +442,6 @@ typedef struct RU_t_s {
node_function_t function;
/// Ethernet parameters for fronthaul interface
eth_params_t eth_params;
- /// flag to indicate RF emulation mode
- int emulate_rf;
/// numerology index
int numerology;
/// flag to indicate the RU is in sync with a master reference
diff --git a/openair1/PHY/defs_UE.h b/openair1/PHY/defs_UE.h
index 17ae02610e..20d5a9ab8d 100644
--- a/openair1/PHY/defs_UE.h
+++ b/openair1/PHY/defs_UE.h
@@ -640,7 +640,7 @@ typedef struct {
/// mbsfn reference symbols
uint32_t lte_gold_mbsfn_khz_1dot25_table[10][150];
- uint32_t X_u[64][839];
+ c16_t X_u[64][839];
uint32_t high_speed_flag;
uint32_t perfect_ce;
diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h
index 68ebf65462..ef1db2e05f 100644
--- a/openair1/PHY/defs_eNB.h
+++ b/openair1/PHY/defs_eNB.h
@@ -255,11 +255,6 @@ typedef struct {
tpool_t *threadPool;
int nbDecode;
notifiedFIFO_t *respDecode;
- pthread_mutex_t mutex_emulateRF;
- int instance_cnt_emulateRF;
- pthread_t pthread_emulateRF;
- pthread_attr_t attr_emulateRF;
- pthread_cond_t cond_emulateRF;
int first_rx;
} L1_rxtx_proc_t;
@@ -600,8 +595,8 @@ typedef struct PHY_VARS_eNB_s {
// PUCCH1a/b energy detection parameters for eMTC per CE-level
int pucch1ab_DTX_threshold_emtc[4];
- uint32_t X_u[64][839];
- uint32_t X_u_br[4][64][839];
+ c16_t X_u[64][839];
+ c16_t X_u_br[4][64][839];
uint8_t pbch_configured;
uint8_t pbch_pdu[4]; //PBCH_PDU_SIZE
char eNB_generate_rar;
diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h
index ad17c243ae..987f77d953 100644
--- a/openair1/PHY/defs_gNB.h
+++ b/openair1/PHY/defs_gNB.h
@@ -521,6 +521,9 @@ typedef struct PHY_VARS_gNB_s {
time_stats_t slot_indication_stats;
time_stats_t schedule_response_stats;
time_stats_t ulsch_decoding_stats;
+ time_stats_t ts_deinterleave;
+ time_stats_t ts_rate_unmatch;
+ time_stats_t ts_ldpc_decode;
time_stats_t ulsch_deinterleaving_stats;
time_stats_t ulsch_channel_estimation_stats;
time_stats_t pusch_channel_estimation_antenna_processing_stats;
diff --git a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h
index d52b6d9c43..79e5b8746e 100644
--- a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h
+++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h
@@ -26,15 +26,8 @@
#include "PHY/NR_REFSIG/nr_refsig_common.h"
#include "PHY/MODULATION/nr_modulation.h"
-extern simde__m128i byte2bit16_lut[256];
-void init_byte2bit16(void);
void init_byte2m128i(void);
-static inline simde__m128i byte2bit16(uint8_t b)
-{
- return byte2bit16_lut[b];
-}
-
typedef struct {
int size;
int ports;
@@ -54,6 +47,13 @@ void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_si
void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay);
unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb);
void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size);
+void nr_channel_level(const int symbol,
+ const int size_est,
+ const c16_t ch_estimates_ext[][size_est],
+ const int nb_rx,
+ const int Nl,
+ int32_t avg[nb_rx * Nl],
+ const uint32_t len);
void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms,
const csi_mapping_parms_t *phy_csi_parms,
const int16_t amp,
diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common.c b/openair1/PHY/nr_phy_common/src/nr_phy_common.c
index e86652bd49..82418cbb53 100644
--- a/openair1/PHY/nr_phy_common/src/nr_phy_common.c
+++ b/openair1/PHY/nr_phy_common/src/nr_phy_common.c
@@ -26,22 +26,6 @@
#endif
#define PEAK_DETECT_THRESHOLD 15
-
-simde__m128i byte2bit16_lut[256];
-void init_byte2bit16(void)
-{
- for (int s = 0; s < 256; s++) {
- byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], s & 1, 0);
- byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 1) & 1, 1);
- byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 2) & 1, 2);
- byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 3) & 1, 3);
- byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 4) & 1, 4);
- byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 5) & 1, 5);
- byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 6) & 1, 6);
- byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 7) & 1, 7);
- }
-}
-
simde__m128i byte2m128i[256];
void init_byte2m128i(void)
{
@@ -420,6 +404,28 @@ unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, in
return (0);
}
+// compute average channel_level on each antenna
+void nr_channel_level(const int symbol,
+ const int size_est,
+ const c16_t ch_estimates_ext[][size_est],
+ const int nb_rx,
+ const int Nl,
+ int32_t avg[nb_rx * Nl],
+ const uint32_t len)
+{
+ int16_t x = factor2(len);
+ int16_t y = len >> x;
+ for (int aarx = 0; aarx < nb_rx; aarx++) {
+ for (int l = 0; l < Nl; l++) {
+ simde__m128i *ch128 = (simde__m128i *)&ch_estimates_ext[l * nb_rx + aarx][symbol * len];
+ //compute average level
+ avg[l * nb_rx + aarx] = simde_mm_average(ch128, len, x, y);
+ LOG_D(PHY, "Channel level: %d\n", avg[l * nb_rx + aarx]);
+ }
+ }
+}
+
+
void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size)
{
const double phase_inc = -fo_Hz / (samples_per_ms * 1000);
diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c
index 5e6140db9d..a593a0dfb4 100644
--- a/openair1/SIMULATION/LTE_PHY/dlsim.c
+++ b/openair1/SIMULATION/LTE_PHY/dlsim.c
@@ -90,7 +90,6 @@ static int cmpdouble(const void *p1, const void *p2) {
}
RAN_CONTEXT_t RC;
-int emulate_rf = 0;
void handler(int sig) {
void *array[10];
size_t size;
diff --git a/openair1/SIMULATION/LTE_PHY/mbmssim.c b/openair1/SIMULATION/LTE_PHY/mbmssim.c
index ac50bf62bd..dac151e4fe 100644
--- a/openair1/SIMULATION/LTE_PHY/mbmssim.c
+++ b/openair1/SIMULATION/LTE_PHY/mbmssim.c
@@ -89,8 +89,6 @@ int n_rx_dropped = 0; /*!< \brief initial max process time for rx */
THREAD_STRUCT thread_struct;
-int emulate_rf = 0;
-
void handler(int sig) {
void *array[10];
size_t size;
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index e355ca51c2..0f21fdb145 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -1341,7 +1341,7 @@ printf("%d\n", slot);
printStatIndent3(&gNB->tprep,"DLSCH LDPC input preparation time");
printStatIndent3(&gNB->tparity,"DLSCH LDPC parity generation time");
printStatIndent3(&gNB->toutput,"DLSCH LDPC output generation time");
- printStatIndent3(&gNB->dlsch_rate_matching_stats,"DLSCH Rate Mataching time");
+ printStatIndent3(&gNB->dlsch_rate_matching_stats,"DLSCH Rate Matching time");
printStatIndent3(&gNB->dlsch_interleaving_stats, "DLSCH Interleaving time");
printStatIndent2(&gNB->dlsch_modulation_stats,"DLSCH modulation time");
printStatIndent2(&gNB->dlsch_scrambling_stats, "DLSCH scrambling time");
diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c
index b2b2dc38bb..e5361a3e2d 100644
--- a/openair1/SIMULATION/NR_PHY/ulsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulsim.c
@@ -237,6 +237,8 @@ int main(int argc, char *argv[])
int max_ldpc_iterations = 5;
int num_antennas_per_thread = 1;
uint32_t log_format = 0;
+ int threequarter_fs = 0;
+
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) {
exit_fun("[NR_ULSIM] Error, configuration module init failed\n");
}
@@ -351,7 +353,7 @@ int main(int argc, char *argv[])
case 'k':
printf("Setting threequarter_fs_flag\n");
- openair0_cfg[0].threequarter_fs= 1;
+ threequarter_fs = 1;
break;
case 'm':
@@ -584,7 +586,7 @@ int main(int argc, char *argv[])
uint32_t samples;
get_samplerate_and_bw(mu,
N_RB_DL,
- openair0_cfg[0].threequarter_fs,
+ threequarter_fs,
&sampling_frequency,
&samples,
&tx_bandwidth,
@@ -1026,6 +1028,9 @@ int main(int argc, char *argv[])
reset_meas(&gNB->rx_pusch_init_stats);
reset_meas(&gNB->rx_pusch_symbol_processing_stats);
reset_meas(&gNB->ulsch_decoding_stats);
+ reset_meas(&gNB->ts_deinterleave);
+ reset_meas(&gNB->ts_rate_unmatch);
+ reset_meas(&gNB->ts_ldpc_decode);
reset_meas(&gNB->ulsch_channel_estimation_stats);
reset_meas(&gNB->pusch_channel_estimation_antenna_processing_stats);
reset_meas(&gNB->rx_srs_stats);
@@ -1587,6 +1592,9 @@ int main(int argc, char *argv[])
printStatIndent2(&gNB->rx_pusch_init_stats, "RX PUSCH Initialization time");
printStatIndent2(&gNB->rx_pusch_symbol_processing_stats, "RX PUSCH Symbol Processing time");
printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
+ printStatIndent2(&gNB->ts_deinterleave, "ULSCH segment deinterleaving time");
+ printStatIndent2(&gNB->ts_rate_unmatch, "ULSCH segment rate recovery time");
+ printStatIndent2(&gNB->ts_ldpc_decode, "ULSCH segments decoding time");
printf("\nUE TX\n");
for (int i = PHY_PROC_TX; i <= OFDM_MOD_STATS; i++) {
diff --git a/openair1/SIMULATION/TOOLS/sim.h b/openair1/SIMULATION/TOOLS/sim.h
index 98b4fb26c6..359df00b55 100644
--- a/openair1/SIMULATION/TOOLS/sim.h
+++ b/openair1/SIMULATION/TOOLS/sim.h
@@ -77,6 +77,8 @@ typedef struct {
struct complexd **a;
///interpolated (sample-spaced) channel impulse response. size(ch) = (n_tx * n_rx) * channel_length. ATTENTION: the dimensions of ch are the transposed ones of a. This is to allow the use of BLAS when applying the correlation matrices to the state.
struct complexd **ch;
+ ///Same as above but single precision
+ struct complexf **ch_ps;
///Sampled frequency response (90 kHz resolution)
struct complexd **chF;
///Maximum path delay in mus.
diff --git a/openair2/E1AP/e1ap_common.h b/openair2/E1AP/e1ap_common.h
index 452762965c..6c556a6cc6 100644
--- a/openair2/E1AP/e1ap_common.h
+++ b/openair2/E1AP/e1ap_common.h
@@ -41,8 +41,6 @@ typedef struct e1ap_upcp_inst_s {
e1ap_net_config_t net_config;
} e1ap_upcp_inst_t;
-extern int asn1_xer_print;
-
// forward declaration so we don't require E1AP ASN.1 when including this
// header
struct E1AP_E1AP_PDU;
diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h
index db04c5a8da..b751d78733 100644
--- a/openair2/GNB_APP/gnb_paramdef.h
+++ b/openair2/GNB_APP/gnb_paramdef.h
@@ -49,9 +49,6 @@
#define GNB_CONF_STRING_OTG_APP_TYPE "app_type"
#define GNB_CONF_STRING_OTG_BG_TRAFFIC "bg_traffic"
-extern int asn_debug;
-extern int asn1_xer_print;
-
#ifdef LIBCONFIG_LONG
#define libconfig_int long
#else
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
index cd51f6a48f..1a5431bdd2 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
@@ -1972,49 +1972,6 @@ static const int32_t table_6_4_1_1_3_4_pusch_dmrs_positions_l[12][8] = {
{0, 3072, -1, -1, 3, 1539, -1, -1}, // 14 // (DMRS l' position)
};
-// TS 38.212
-static const uint16_t table_7_3_1_1_2_2_1layer[28] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 32, 33,
- 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
-static const uint16_t table_7_3_1_1_2_2_2layers[22] = {4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24,
- 25, 26, 27, 48, 49, 50, 51, 52, 53, 54, 55};
-static const uint16_t table_7_3_1_1_2_2_3layers[7] = {10, 28, 29, 56, 57, 58, 59};
-static const uint16_t table_7_3_1_1_2_2_4layers[5] = {11, 30, 31, 60, 61};
-static const uint16_t table_7_3_1_1_2_2B_1layer[16] = {0, 1, 2, 3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 24, 25};
-static const uint16_t table_7_3_1_1_2_2B_2layers[14] = {4, 5, 6, 7, 8, 9, 13, 26, 27, 28, 29, 30, 31, 32};
-static const uint16_t table_7_3_1_1_2_2B_3layers[3] = {10, 14, 33};
-static const uint16_t table_7_3_1_1_2_2B_4layers[3] = {11, 34, 35};
-static const uint16_t table_7_3_1_1_2_2A_1layer[16] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 10, 21, 22};
-static const uint16_t table_7_3_1_1_2_2A_2layers[14] = {4, 5, 6, 7, 8, 9, 11, 23, 24, 25, 26, 27, 28, 29};
-static const uint16_t table_7_3_1_1_2_3A[16] = {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 14, 15};
-static const uint16_t table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[6] = {0, 1, 3, 4, 5, 6};
-static const uint16_t table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[3] = {2, 7, 8};
-static const uint16_t table_7_3_1_1_2_4A_1layer[3] = {0, 1, 3};
-static const uint16_t table_7_3_1_1_2_28[3][15] = {
- {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-};
-static const uint16_t table_7_3_1_1_2_29[3][15] = {
- {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0},
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0},
-};
-static const uint16_t table_7_3_1_1_2_30[3][15] = {
- {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0},
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0},
-};
-static const uint16_t table_7_3_1_1_2_31[3][15] = {
- {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0},
- {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
-};
-static const uint16_t table_7_3_1_1_2_32[3][15] = {
- {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-};
-
// the following tables contain 10 times the value reported in 214 (in line with SCF specification and to avoid fractional values)
//Table 5.1.3.1-1 of 38.214
static const uint16_t Table_51311[32][2] = {{2, 1200}, {2, 1570}, {2, 1930}, {2, 2510}, {2, 3080}, {2, 3790}, {2, 4490}, {2, 5260},
@@ -2503,61 +2460,61 @@ static int binomial(int n, int k)
return c;
}
+int srs_codebook_nb_res(NR_SRS_Config_t *srs_config)
+{
+ int count = 0;
+ for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) {
+ if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook)
+ count++;
+ }
+ return count;
+}
+
+int srs_non_codebook_nb_res(NR_SRS_Config_t *srs_config)
+{
+ int count = 0;
+ for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) {
+ if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook)
+ count++;
+ }
+ return count;
+}
+
+int srs_binomial_sum(int count, int Lmax)
+{
+ int lmin = 0;
+ int lsum = 0;
+ lmin = count < Lmax ? count : Lmax;
+ for (int k = 1; k <= lmin; k++)
+ lsum += binomial(count, k);
+ return lsum;
+}
+
// #define DEBUG_SRS_RESOURCE_IND
-uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers,
- NR_PUSCH_Config_t *pusch_Config,
- NR_SRS_Config_t *srs_config,
- nr_srs_feedback_t *srs_feedback,
- uint32_t *val)
+
+static uint8_t compute_srs_resource_indicator_size(long *maxMIMO_Layers, NR_PUSCH_Config_t *pusch_Config, NR_SRS_Config_t *srs_config)
{
uint8_t nbits = 0;
-
- // SRI occupies a number of bits which is dependent upon the uplink transmission scheme, and it is used to determine
- // the antenna ports and uplink transmission beam to use for PUSCH transmission. In the case of codebook based
- // transmission, the SRI is used to select between SRS Resources belonging to different antenna panels
- // (kind of directional antenna). There can be up to 2 SRS Resources (2 antenna panels). In the case of non-codebook
- // based transmission, the SRI is used to select one or more SRS Resources from a set of N_SRS resources. The number
- // of SRS Resources selected corresponds to the number of layers (rank) to be transmitted.
- if (val) {
- *val = 0;
- }
-
if (srs_config && pusch_Config && pusch_Config->txConfig != NULL) {
-
if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook) {
-
#ifdef DEBUG_SRS_RESOURCE_IND
LOG_I(NR_MAC, "*pusch_Config->txConfig = NR_PUSCH_Config__txConfig_codebook\n");
#endif
-
// TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(N_SRS)) bits according to
// Tables 7.3.1.1.2-32, 7.3.1.1.2-32A and 7.3.1.1.2-32B if the higher layer parameter txConfig = codebook,
// where N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer
// parameter srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value codeBook.
- int count = 0;
- for (int i=0; isrs_ResourceSetToAddModList->list.count; i++) {
- if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook) {
- count++;
- }
- }
- if (count>0) {
+ int count = srs_codebook_nb_res(srs_config);
+ if (count > 0)
nbits = ceil(log2(count));
- if (val && srs_feedback && count > 1) {
- *val = table_7_3_1_1_2_32[count-2][srs_feedback->sri];
- }
- }
-
#ifdef DEBUG_SRS_RESOURCE_IND
LOG_I(NR_MAC, "srs_config->srs_ResourceSetToAddModList->list.count = %i\n", srs_config->srs_ResourceSetToAddModList->list.count);
LOG_I(NR_MAC, "count = %i\n", count);
#endif
-
} else {
-
#ifdef DEBUG_SRS_RESOURCE_IND
LOG_I(NR_MAC, "*pusch_Config->txConfig = NR_PUSCH_Config__txConfig_nonCodebook\n");
#endif
-
// TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(sum(k = 1 until min(Lmax,N_SRS) of binomial(N_SRS,k))))
// bits according to Tables 7.3.1.1.2-28/29/30/31 if the higher layer parameter txConfig = nonCodebook, where
// N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer parameter
@@ -2572,68 +2529,29 @@ uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers,
if (maxMIMO_Layers != NULL)
Lmax = *maxMIMO_Layers;
else
- AssertFatal(1 == 0, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n");
- int lmin = 0;
- int lsum = 0;
- int count = 0;
- for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) {
- if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook) {
- count++;
- }
- }
- lmin = count < Lmax ? count : Lmax;
- for (int k=1;k<=lmin;k++) {
- lsum += binomial(count,k);
- }
- if (lsum>0) {
+ AssertFatal(false, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n");
+ int count = srs_non_codebook_nb_res(srs_config);
+ int lsum = srs_binomial_sum(count, Lmax);
+ if (lsum > 0)
nbits = ceil(log2(lsum));
- if (val && srs_feedback && nbits > 0) {
- switch(Lmax) {
- case 1:
- *val = table_7_3_1_1_2_28[count-2][srs_feedback->sri];
- break;
- case 2:
- *val = table_7_3_1_1_2_29[count-2][srs_feedback->sri];
- break;
- case 3:
- *val = table_7_3_1_1_2_30[count-2][srs_feedback->sri];
- break;
- case 4:
- *val = table_7_3_1_1_2_31[count-2][srs_feedback->sri];
- break;
- default:
- LOG_E(NR_MAC, "%s (%d) - Invalid Lmax %d\n", __FUNCTION__, __LINE__, Lmax);
- }
- }
- }
-
#ifdef DEBUG_SRS_RESOURCE_IND
LOG_I(NR_MAC, "srs_config->srs_ResourceSetToAddModList->list.count = %i\n", srs_config->srs_ResourceSetToAddModList->list.count);
LOG_I(NR_MAC, "count = %i\n", count);
LOG_I(NR_MAC, "Lmax = %i\n", Lmax);
LOG_I(NR_MAC, "lsum = %i\n", lsum);
#endif
-
}
}
-
return nbits;
}
-uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
- NR_SRS_Config_t *srs_config,
- dci_field_t srs_resource_indicator,
- nr_srs_feedback_t *srs_feedback,
- const uint8_t *nrOfLayers,
- int *tpmi,
- uint32_t *val)
+static uint8_t compute_precoding_info_size(NR_PUSCH_Config_t *pusch_Config,
+ NR_SRS_Config_t *srs_config,
+ dci_field_t srs_resource_indicator)
{
// It is only applicable to codebook based transmission. This field occupies 0 bits for non-codebook based
// transmission. It also occupies 0 bits for codebook based transmission using a single antenna port.
uint8_t nbits = 0;
- if (val) {
- *val = 0;
- }
uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, srs_resource_indicator);
if (!pusch_Config
@@ -2645,7 +2563,6 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
long max_rank = *pusch_Config->maxRank;
long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL;
long *codebookSubset = pusch_Config->codebookSubset;
- int ul_tpmi = tpmi ? *tpmi : srs_feedback ? srs_feedback->tpmi : -1;
if (pusch_antenna_ports == 2) {
@@ -2658,23 +2575,11 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
// of higher layer parameter codebookSubset;
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
nbits = 2;
- if (val && srs_feedback) {
- AssertFatal(ul_tpmi <= 2,"TPMI %d is invalid!\n", ul_tpmi);
- *val = ul_tpmi;
- }
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 1;
- if (val && srs_feedback) {
- AssertFatal(ul_tpmi <= 1,"TPMI %d is invalid!\n", ul_tpmi);
- *val = ul_tpmi;
- }
} else {
nbits = 3;
- if (val && srs_feedback) {
- AssertFatal(ul_tpmi <= 5,"TPMI %d is invalid!\n", ul_tpmi);
- *val = ul_tpmi;
- }
}
}
} else {
@@ -2685,27 +2590,11 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
// fullpowerMode1, transform precoder is disabled, maxRank=2, and codebookSubset=nonCoherent;
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
nbits = 2;
- if (val && srs_feedback) {
- AssertFatal((*nrOfLayers==1 && ul_tpmi <= 2) || (*nrOfLayers==2 && ul_tpmi == 0),
- "TPMI %d is invalid!\n", ul_tpmi);
- *val = *nrOfLayers==1 ? table_7_3_1_1_2_4A_1layer[ul_tpmi] : 2;
- }
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 2;
- if (val && srs_feedback) {
- AssertFatal((*nrOfLayers==1 && ul_tpmi <= 1) || (*nrOfLayers==2 && ul_tpmi == 0),
- "TPMI %d is invalid!\n", ul_tpmi);
- *val = *nrOfLayers==1 ? ul_tpmi : 2;
- }
} else {
nbits = 4;
- if (val && srs_feedback) {
- AssertFatal((*nrOfLayers==1 && ul_tpmi <= 5) || (*nrOfLayers==2 && ul_tpmi <= 2),
- "TPMI %d is invalid!\n", ul_tpmi);
- *val = *nrOfLayers==1 ? table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[ul_tpmi] :
- table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[ul_tpmi];
- }
}
}
}
@@ -2722,37 +2611,16 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 3;
- if (val && srs_feedback) {
- AssertFatal(ul_tpmi <= 3 || ul_tpmi == 13, "TPMI %d is invalid!\n", ul_tpmi);
- }
} else {
nbits = 4;
- if (val && srs_feedback) {
- AssertFatal(ul_tpmi <= 15, "TPMI %d is invalid!\n", ul_tpmi);
- }
- }
- if (val && srs_feedback) {
- *val = table_7_3_1_1_2_3A[ul_tpmi];
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 2;
- if (val && srs_feedback) {
- AssertFatal(ul_tpmi <= 3, "TPMI %d is invalid!\n", ul_tpmi);
- }
} else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
nbits = 4;
- if (val && srs_feedback) {
- AssertFatal(ul_tpmi <= 11, "TPMI %d is invalid!\n", ul_tpmi);
- }
} else {
nbits = 5;
- if (val && srs_feedback) {
- AssertFatal(ul_tpmi <= 27, "TPMI %d is invalid!\n", ul_tpmi);
- }
- }
- if (val && srs_feedback) {
- *val = ul_tpmi;
}
}
} else {
@@ -2769,99 +2637,26 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
if (max_rank == 2) {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 4;
- if (val && srs_feedback) {
- AssertFatal((*nrOfLayers==1 && (ul_tpmi <= 3 || ul_tpmi==13)) || (*nrOfLayers==2 && ul_tpmi <= 6),
- "TPMI %d is invalid!\n", ul_tpmi);
- }
} else {
nbits = 5;
- if (val && srs_feedback) {
- AssertFatal((*nrOfLayers==1 && ul_tpmi <= 15) || (*nrOfLayers==2 && ul_tpmi <= 13),
- "TPMI %d is invalid!\n", ul_tpmi);
- }
- }
- if (val && srs_feedback) {
- *val = *nrOfLayers==1 ? table_7_3_1_1_2_2A_1layer[ul_tpmi] : table_7_3_1_1_2_2A_2layers[ul_tpmi];
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 4;
- if (val && srs_feedback) {
- AssertFatal((*nrOfLayers==1 && (ul_tpmi <= 3 || ul_tpmi == 13)) || (*nrOfLayers==2 && ul_tpmi <= 6) ||
- (*nrOfLayers==3 && ul_tpmi <= 1) || (*nrOfLayers==4 && ul_tpmi == 0),
- "TPMI %d is invalid!\n", ul_tpmi);
- }
} else {
nbits = 6;
- if (val && srs_feedback) {
- AssertFatal((*nrOfLayers==1 && ul_tpmi <= 15) || (*nrOfLayers==2 && ul_tpmi <= 13) ||
- (*nrOfLayers==3 && ul_tpmi <= 2) || (*nrOfLayers==4 && ul_tpmi <= 2),
- "TPMI %d is invalid!\n", ul_tpmi);
- }
- }
- if (val && srs_feedback) {
- switch (*nrOfLayers) {
- case 1:
- *val = table_7_3_1_1_2_2B_1layer[ul_tpmi];
- break;
- case 2:
- *val = table_7_3_1_1_2_2B_2layers[ul_tpmi];
- break;
- case 3:
- *val = table_7_3_1_1_2_2B_3layers[ul_tpmi];
- break;
- case 4:
- *val = table_7_3_1_1_2_2B_4layers[ul_tpmi];
- break;
- default:
- LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
- }
}
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
nbits = 4;
- if (val && srs_feedback) {
- AssertFatal((*nrOfLayers==1 && ul_tpmi <= 3) || (*nrOfLayers==2 && ul_tpmi <= 5) ||
- (*nrOfLayers==3 && ul_tpmi == 0) || (*nrOfLayers==4 && ul_tpmi == 0),
- "TPMI %d is invalid!\n", ul_tpmi);
- }
} else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
nbits = 5;
- if (val && srs_feedback) {
- AssertFatal((*nrOfLayers==1 && ul_tpmi <= 11) || (*nrOfLayers==2 && ul_tpmi <= 13) ||
- (*nrOfLayers==3 && ul_tpmi <= 2) || (*nrOfLayers==4 && ul_tpmi <= 2),
- "TPMI %d is invalid!\n", ul_tpmi);
- }
} else {
nbits = 6;
- if (val && srs_feedback) {
- AssertFatal((*nrOfLayers==1 && ul_tpmi <= 28) || (*nrOfLayers==2 && ul_tpmi <= 22) ||
- (*nrOfLayers==3 && ul_tpmi <= 7) || (*nrOfLayers==4 && ul_tpmi <= 5),
- "TPMI %d is invalid!\n", ul_tpmi);
- }
- }
- if (val && srs_feedback) {
- switch (*nrOfLayers) {
- case 1:
- *val = table_7_3_1_1_2_2_1layer[ul_tpmi];
- break;
- case 2:
- *val = table_7_3_1_1_2_2_2layers[ul_tpmi];
- break;
- case 3:
- *val = table_7_3_1_1_2_2_3layers[ul_tpmi];
- break;
- case 4:
- *val = table_7_3_1_1_2_2_4layers[ul_tpmi];
- break;
- default:
- LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
- }
}
}
}
-
}
return nbits;
}
@@ -3100,12 +2895,11 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP,
}
// SRS resource indicator
dci_pdu->srs_resource_indicator.nbits =
- compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH, pusch_Config, srs_config, NULL, NULL);
+ compute_srs_resource_indicator_size(sc_info->maxMIMO_Layers_PUSCH, pusch_Config, srs_config);
size += dci_pdu->srs_resource_indicator.nbits;
LOG_D(NR_MAC, "dci_pdu->srs_resource_indicator.nbits %d\n", dci_pdu->srs_resource_indicator.nbits);
// Precoding info and number of layers
- dci_pdu->precoding_information.nbits =
- compute_precoding_information(pusch_Config, srs_config, dci_pdu->srs_resource_indicator, NULL, NULL, NULL, NULL);
+ dci_pdu->precoding_information.nbits = compute_precoding_info_size(pusch_Config, srs_config, dci_pdu->srs_resource_indicator);
size += dci_pdu->precoding_information.nbits;
LOG_D(NR_MAC, "dci_pdu->precoding_informaiton.nbits=%d\n", dci_pdu->precoding_information.nbits);
// Antenna ports
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
index ff6775df96..f76f54b158 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
@@ -41,6 +41,49 @@
#define NB_SRS_PERIOD (18)
static const uint16_t srs_period[NB_SRS_PERIOD] = { 0, 1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560};
+// TS 38.212
+static const uint16_t table_7_3_1_1_2_2_1layer[28] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
+static const uint16_t table_7_3_1_1_2_2_2layers[22] = {4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24,
+ 25, 26, 27, 48, 49, 50, 51, 52, 53, 54, 55};
+static const uint16_t table_7_3_1_1_2_2_3layers[7] = {10, 28, 29, 56, 57, 58, 59};
+static const uint16_t table_7_3_1_1_2_2_4layers[5] = {11, 30, 31, 60, 61};
+static const uint16_t table_7_3_1_1_2_2B_1layer[16] = {0, 1, 2, 3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 24, 25};
+static const uint16_t table_7_3_1_1_2_2B_2layers[14] = {4, 5, 6, 7, 8, 9, 13, 26, 27, 28, 29, 30, 31, 32};
+static const uint16_t table_7_3_1_1_2_2B_3layers[3] = {10, 14, 33};
+static const uint16_t table_7_3_1_1_2_2B_4layers[3] = {11, 34, 35};
+static const uint16_t table_7_3_1_1_2_2A_1layer[16] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 10, 21, 22};
+static const uint16_t table_7_3_1_1_2_2A_2layers[14] = {4, 5, 6, 7, 8, 9, 11, 23, 24, 25, 26, 27, 28, 29};
+static const uint16_t table_7_3_1_1_2_3A[16] = {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 14, 15};
+static const uint16_t table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[6] = {0, 1, 3, 4, 5, 6};
+static const uint16_t table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[3] = {2, 7, 8};
+static const uint16_t table_7_3_1_1_2_4A_1layer[3] = {0, 1, 3};
+static const uint16_t table_7_3_1_1_2_28[3][15] = {
+ {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+static const uint16_t table_7_3_1_1_2_29[3][15] = {
+ {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0},
+};
+static const uint16_t table_7_3_1_1_2_30[3][15] = {
+ {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0},
+};
+static const uint16_t table_7_3_1_1_2_31[3][15] = {
+ {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
+};
+static const uint16_t table_7_3_1_1_2_32[3][15] = {
+ {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
typedef enum {
pusch_dmrs_pos0 = 0,
pusch_dmrs_pos1 = 1,
@@ -81,20 +124,6 @@ void config_frame_structure(int mu,
uint8_t frame_type,
frame_structure_t *fs);
-uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers,
- NR_PUSCH_Config_t *pusch_Config,
- NR_SRS_Config_t *srs_config,
- nr_srs_feedback_t *srs_feedback,
- uint32_t *val);
-
-uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
- NR_SRS_Config_t *srs_config,
- dci_field_t srs_resource_indicator,
- nr_srs_feedback_t *srs_feedback,
- const uint8_t *nrOfLayers,
- int *tpmi,
- uint32_t *val);
-
NR_PDSCH_TimeDomainResourceAllocationList_t *get_dl_tdalist(const NR_UE_DL_BWP_t *DL_BWP,
int controlResourceSetId,
int ss_type,
@@ -197,7 +226,9 @@ uint32_t nr_get_code_rate_dl(uint8_t Imcs, uint8_t table_idx);
/** \brief Computes Q based on I_MCS PDSCH and table_idx for uplink. Implements MCS Tables from 38.214. */
uint8_t nr_get_Qm_ul(uint8_t Imcs, uint8_t table_idx);
uint32_t nr_get_code_rate_ul(uint8_t Imcs, uint8_t table_idx);
-
+int srs_binomial_sum(int count, int Lmax);
+int srs_codebook_nb_res(NR_SRS_Config_t *srs_config);
+int srs_non_codebook_nb_res(NR_SRS_Config_t *srs_config);
uint16_t get_nr_srs_offset(NR_SRS_PeriodicityAndOffset_t periodicityAndOffset);
void get_monitoring_period_offset(const NR_SearchSpace_t *ss, int *period, int *offset);
diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c
index 73bb02a575..d764f7cb86 100644
--- a/openair2/LAYER2/NR_MAC_UE/config_ue.c
+++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c
@@ -700,8 +700,11 @@ static void modlist_coreset(NR_ControlResourceSet_t *source, NR_ControlResourceS
if (id == *target->tci_StatesPDCCH_ToAddList->list.array[j])
break;
}
- if (j == target->tci_StatesPDCCH_ToAddList->list.count)
- ASN_SEQUENCE_ADD(&target->tci_StatesPDCCH_ToAddList->list, source->tci_StatesPDCCH_ToAddList->list.array[i]);
+ if (j == target->tci_StatesPDCCH_ToAddList->list.count) {
+ long *tci_id = calloc(1, sizeof(*tci_id));
+ *tci_id = id;
+ ASN_SEQUENCE_ADD(&target->tci_StatesPDCCH_ToAddList->list, tci_id);
+ }
}
} else
UPDATE_IE(target->tci_StatesPDCCH_ToAddList,
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
index 44d4affb08..c88ad3bd96 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
@@ -594,8 +594,15 @@ typedef struct UEsched_s {
NR_UE_info_t * UE;
} UEsched_t;
-static int comparator(const void *p, const void *q) {
- return ((UEsched_t*)p)->coef < ((UEsched_t*)q)->coef;
+static int comparator(const void *p, const void *q)
+{
+ const UEsched_t *pp = p;
+ const UEsched_t *qq = q;
+ if (pp->coef < qq->coef)
+ return 1;
+ else if (pp->coef > qq->coef)
+ return -1;
+ return 0;
}
static void pf_dl(module_id_t module_id,
@@ -613,7 +620,7 @@ static void pf_dl(module_id_t module_id,
int remainUEs[num_beams];
for (int i = 0; i < num_beams; i++)
remainUEs[i] = max_num_ue;
- int curUE = 0;
+ int numUE = 0;
int CC_id = 0;
int slots_per_frame = mac->frame_structure.numb_slots_frame;
@@ -704,13 +711,13 @@ static void pf_dl(module_id_t module_id,
tbs,
coeff_ue);
/* Create UE_sched list for UEs eligible for new transmission*/
- UE_sched[curUE].coef=coeff_ue;
- UE_sched[curUE].UE=UE;
- curUE++;
+ UE_sched[numUE].coef = coeff_ue;
+ UE_sched[numUE].UE = UE;
+ numUE++;
}
}
- qsort(UE_sched, sizeofArray(UE_sched), sizeof(UEsched_t), comparator);
+ qsort(UE_sched, numUE, sizeof(UEsched_t), comparator);
UEsched_t *iterator = UE_sched;
const int min_rbSize = 5;
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index 7e0f84e2fe..264150f314 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -895,6 +895,265 @@ dci_pdu_rel15_t prepare_dci_dl_payload(const gNB_MAC_INST *gNB_mac,
return dci_payload;
}
+static uint32_t compute_srs_resource_indicator(long *maxMIMO_Layers,
+ NR_PUSCH_Config_t *pusch_Config,
+ NR_SRS_Config_t *srs_config,
+ nr_srs_feedback_t *srs_feedback)
+{
+ uint32_t val = 0;
+ if (srs_config && pusch_Config && pusch_Config->txConfig != NULL) {
+ if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook) {
+
+ // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(N_SRS)) bits according to
+ // Tables 7.3.1.1.2-32, 7.3.1.1.2-32A and 7.3.1.1.2-32B if the higher layer parameter txConfig = codebook,
+ // where N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer
+ // parameter srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value codeBook.
+ int count = srs_codebook_nb_res(srs_config);
+ if (count > 1)
+ val = table_7_3_1_1_2_32[count - 2][srs_feedback->sri];
+ } else {
+ // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(sum(k = 1 until min(Lmax,N_SRS) of binomial(N_SRS,k))))
+ // bits according to Tables 7.3.1.1.2-28/29/30/31 if the higher layer parameter txConfig = nonCodebook, where
+ // N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer parameter
+ // srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value nonCodeBook and:
+ //
+ // - if UE supports operation with maxMIMO-Layers and the higher layer parameter maxMIMO-Layers of
+ // PUSCH-ServingCellConfig of the serving cell is configured, Lmax is given by that parameter;
+ //
+ // - otherwise, Lmax is given by the maximum number of layers for PUSCH supported by the UE for the serving cell
+ // for non-codebook based operation.
+ int Lmax = 0;
+ if (maxMIMO_Layers != NULL)
+ Lmax = *maxMIMO_Layers;
+ else
+ AssertFatal(false, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n");
+ int count = srs_non_codebook_nb_res(srs_config);
+ int lsum = srs_binomial_sum(count, Lmax);
+ if (lsum > 0 && ceil(log2(lsum)) > 0) {
+ switch(Lmax) {
+ case 1:
+ val = table_7_3_1_1_2_28[count-2][srs_feedback->sri];
+ break;
+ case 2:
+ val = table_7_3_1_1_2_29[count-2][srs_feedback->sri];
+ break;
+ case 3:
+ val = table_7_3_1_1_2_30[count-2][srs_feedback->sri];
+ break;
+ case 4:
+ val = table_7_3_1_1_2_31[count-2][srs_feedback->sri];
+ break;
+ default:
+ LOG_E(NR_MAC, "%s (%d) - Invalid Lmax %d\n", __FUNCTION__, __LINE__, Lmax);
+ }
+ }
+ }
+ }
+ return val;
+}
+
+static uint32_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
+ NR_SRS_Config_t *srs_config,
+ dci_field_t srs_resource_indicator,
+ nr_srs_feedback_t *srs_feedback,
+ const uint8_t *nrOfLayers,
+ int *tpmi)
+{
+ uint32_t val = 0;
+
+ uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, srs_resource_indicator);
+ if (!pusch_Config
+ || (pusch_Config->txConfig != NULL && *pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook)
+ || pusch_antenna_ports == 1) {
+ return val;
+ }
+
+ long max_rank = *pusch_Config->maxRank;
+ long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL;
+ long *codebookSubset = pusch_Config->codebookSubset;
+ int ul_tpmi = tpmi ? *tpmi : srs_feedback ? srs_feedback->tpmi : -1;
+
+ if (pusch_antenna_ports == 2) {
+
+ if (max_rank == 1) {
+ // - 1 or 3 bits according to Table 7.3.1.1.2-5 for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission
+ // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform
+ // precoder is enabled or disabled, and the values of higher layer parameters maxRank and codebookSubset;
+ // - 2 bits according to Table 7.3.1.1.2-5A for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission =
+ // fullpowerMode1, maxRank=1, and according to whether transform precoder is enabled or disabled, and the values
+ // of higher layer parameter codebookSubset;
+ if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
+ AssertFatal(ul_tpmi <= 2,"TPMI %d is invalid!\n", ul_tpmi);
+ val = ul_tpmi;
+ } else {
+ if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
+ AssertFatal(ul_tpmi <= 1,"TPMI %d is invalid!\n", ul_tpmi);
+ val = ul_tpmi;
+ } else {
+ AssertFatal(ul_tpmi <= 5,"TPMI %d is invalid!\n", ul_tpmi);
+ val = ul_tpmi;
+ }
+ }
+ } else {
+ // - 2 or 4 bits according to Table 7.3.1.1.2-4 for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission
+ // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform
+ // precoder is enabled or disabled, and the values of higher layer parameters maxRank and codebookSubset;
+ // - 2 bits according to Table 7.3.1.1.2-4A for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission =
+ // fullpowerMode1, transform precoder is disabled, maxRank=2, and codebookSubset=nonCoherent;
+ if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
+ AssertFatal((*nrOfLayers==1 && ul_tpmi <= 2)
+ || (*nrOfLayers==2 && ul_tpmi == 0),
+ "TPMI %d is invalid!\n",
+ ul_tpmi);
+ val = *nrOfLayers == 1 ? table_7_3_1_1_2_4A_1layer[ul_tpmi] : 2;
+ } else {
+ if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
+ AssertFatal((*nrOfLayers==1 && ul_tpmi <= 1)
+ || (*nrOfLayers==2 && ul_tpmi == 0),
+ "TPMI %d is invalid!\n",
+ ul_tpmi);
+ val = *nrOfLayers == 1 ? ul_tpmi : 2;
+ } else {
+ AssertFatal((*nrOfLayers==1 && ul_tpmi <= 5)
+ || (*nrOfLayers==2 && ul_tpmi <= 2),
+ "TPMI %d is invalid!\n",
+ ul_tpmi);
+ val = *nrOfLayers == 1 ? table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[ul_tpmi] :
+ table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[ul_tpmi];
+ }
+ }
+ }
+
+ } else if (pusch_antenna_ports == 4) {
+
+ if (max_rank == 1) {
+ // - 2, 4, or 5 bits according to Table 7.3.1.1.2-3 for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission
+ // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform
+ // precoder is enabled or disabled, and the values of higher layer parameters maxRank, and codebookSubset;
+ // - 3 or 4 bits according to Table 7.3.1.1.2-3A for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission =
+ // fullpowerMode1, maxRank=1, and according to whether transform precoder is enabled or disabled, and the values
+ // of higher layer parameter codebookSubset;
+ if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
+ if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
+ AssertFatal(ul_tpmi <= 3 || ul_tpmi == 13, "TPMI %d is invalid!\n", ul_tpmi);
+ } else {
+ AssertFatal(ul_tpmi <= 15, "TPMI %d is invalid!\n", ul_tpmi);
+ }
+ val = table_7_3_1_1_2_3A[ul_tpmi];
+ } else {
+ if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
+ AssertFatal(ul_tpmi <= 3, "TPMI %d is invalid!\n", ul_tpmi);
+ } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
+ AssertFatal(ul_tpmi <= 11, "TPMI %d is invalid!\n", ul_tpmi);
+ } else {
+ AssertFatal(ul_tpmi <= 27, "TPMI %d is invalid!\n", ul_tpmi);
+ }
+ val = ul_tpmi;
+ }
+ } else {
+ // - 4, 5, or 6 bits according to Table 7.3.1.1.2-2 for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission
+ // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform
+ // precoder is enabled or disabled, and the values of higher layer parameters maxRank, and codebookSubset;
+ // - 4 or 5 bits according to Table 7.3.1.1.2-2A for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission =
+ // fullpowerMode1, maxRank=2, transform precoder is disabled, and according to the values of higher layer parameter
+ // codebookSubset;
+ // - 4 or 6 bits according to Table 7.3.1.1.2-2B for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission =
+ // fullpowerMode1, maxRank=3 or 4, transform precoder is disabled, and according to the values of higher layer
+ // parameter codebookSubset;
+ if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
+ if (max_rank == 2) {
+ if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
+ AssertFatal((*nrOfLayers==1
+ && (ul_tpmi <= 3 || ul_tpmi == 13))
+ || (*nrOfLayers == 2 && ul_tpmi <= 6),
+ "TPMI %d is invalid!\n",
+ ul_tpmi);
+ } else {
+ AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 15)
+ || (*nrOfLayers == 2 && ul_tpmi <= 13),
+ "TPMI %d is invalid!\n",
+ ul_tpmi);
+ }
+ val = *nrOfLayers == 1 ? table_7_3_1_1_2_2A_1layer[ul_tpmi] : table_7_3_1_1_2_2A_2layers[ul_tpmi];
+ } else {
+ if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
+ AssertFatal((*nrOfLayers == 1
+ && (ul_tpmi <= 3 || ul_tpmi == 13))
+ || (*nrOfLayers == 2 && ul_tpmi <= 6)
+ || (*nrOfLayers == 3 && ul_tpmi <= 1)
+ || (*nrOfLayers == 4 && ul_tpmi == 0),
+ "TPMI %d is invalid!\n",
+ ul_tpmi);
+ } else {
+ AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 15)
+ || (*nrOfLayers == 2 && ul_tpmi <= 13)
+ || (*nrOfLayers == 3 && ul_tpmi <= 2)
+ || (*nrOfLayers == 4 && ul_tpmi <= 2),
+ "TPMI %d is invalid!\n",
+ ul_tpmi);
+ }
+ switch (*nrOfLayers) {
+ case 1:
+ val = table_7_3_1_1_2_2B_1layer[ul_tpmi];
+ break;
+ case 2:
+ val = table_7_3_1_1_2_2B_2layers[ul_tpmi];
+ break;
+ case 3:
+ val = table_7_3_1_1_2_2B_3layers[ul_tpmi];
+ break;
+ case 4:
+ val = table_7_3_1_1_2_2B_4layers[ul_tpmi];
+ break;
+ default:
+ LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
+ }
+ }
+ } else {
+ if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
+ AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 3)
+ || (*nrOfLayers == 2 && ul_tpmi <= 5)
+ || (*nrOfLayers == 3 && ul_tpmi == 0)
+ || (*nrOfLayers == 4 && ul_tpmi == 0),
+ "TPMI %d is invalid!\n",
+ ul_tpmi);
+ } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
+ AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 11)
+ || (*nrOfLayers == 2 && ul_tpmi <= 13)
+ || (*nrOfLayers == 3 && ul_tpmi <= 2)
+ || (*nrOfLayers == 4 && ul_tpmi <= 2),
+ "TPMI %d is invalid!\n",
+ ul_tpmi);
+ } else {
+ AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 28)
+ || (*nrOfLayers == 2 && ul_tpmi <= 22)
+ || (*nrOfLayers == 3 && ul_tpmi <= 7)
+ || (*nrOfLayers == 4 && ul_tpmi <= 5),
+ "TPMI %d is invalid!\n",
+ ul_tpmi);
+ }
+ switch (*nrOfLayers) {
+ case 1:
+ val = table_7_3_1_1_2_2_1layer[ul_tpmi];
+ break;
+ case 2:
+ val = table_7_3_1_1_2_2_2layers[ul_tpmi];
+ break;
+ case 3:
+ val = table_7_3_1_1_2_2_3layers[ul_tpmi];
+ break;
+ case 4:
+ val = table_7_3_1_1_2_2_4layers[ul_tpmi];
+ break;
+ default:
+ LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
+ }
+ }
+ }
+ }
+ return val;
+}
+
void config_uldci(const NR_UE_ServingCell_Info_t *sc_info,
const nfapi_nr_pusch_pdu_t *pusch_pdu,
dci_pdu_rel15_t *dci_pdu_rel15,
@@ -940,23 +1199,20 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info,
// bwp indicator as per table 7.3.1.1.2-1 in 38.212
dci_pdu_rel15->bwp_indicator.val = sc_info->n_ul_bwp < 4 ? bwp_id : bwp_id - 1;
// SRS resource indicator
- if (pusch_Config &&
- pusch_Config->txConfig != NULL) {
+ if (pusch_Config && pusch_Config->txConfig != NULL) {
AssertFatal(*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook,
"Non Codebook configuration non supported\n");
- compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH,
- pusch_Config,
- ul_bwp->srs_Config,
- srs_feedback,
- &dci_pdu_rel15->srs_resource_indicator.val);
+ dci_pdu_rel15->srs_resource_indicator.val = compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH,
+ pusch_Config,
+ ul_bwp->srs_Config,
+ srs_feedback);
}
- compute_precoding_information(pusch_Config,
- ul_bwp->srs_Config,
- dci_pdu_rel15->srs_resource_indicator,
- srs_feedback,
- &pusch_pdu->nrOfLayers,
- tpmi,
- &dci_pdu_rel15->precoding_information.val);
+ dci_pdu_rel15->precoding_information.val = compute_precoding_information(pusch_Config,
+ ul_bwp->srs_Config,
+ dci_pdu_rel15->srs_resource_indicator,
+ srs_feedback,
+ &pusch_pdu->nrOfLayers,
+ tpmi);
// antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4
// Antenna Ports
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
index e170e90823..4d1c0b5ba0 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
@@ -469,7 +469,7 @@ static void deliver_pdu_drb_gnb(void *deliver_pdu_data, ue_id_t ue_id, int rb_id
if (NODE_IS_CU(node_type)) {
LOG_D(PDCP, "%s() (drb %d) sending message to gtp size %d\n", __func__, rb_id, size);
extern instance_t CUuniqInstance;
- gtpv1uSendDirect(CUuniqInstance, ue_id, rb_id, (uint8_t *)buf, size, false, false);
+ gtpv1uSendDirectWithNRUSeqNum(CUuniqInstance, ue_id, rb_id, (uint8_t *)buf, size);
} else {
uint8_t *memblock = malloc16(size);
memcpy(memblock, buf, size);
diff --git a/openair2/M2AP/m2ap_common.c b/openair2/M2AP/m2ap_common.c
index aa090d124d..d9183df6fb 100644
--- a/openair2/M2AP/m2ap_common.c
+++ b/openair2/M2AP/m2ap_common.c
@@ -47,7 +47,7 @@ ssize_t m2ap_generate_initiating_message(
pdu.choice.initiatingMessage.criticality = criticality;
ANY_fromType_aper((ANY_t *)&pdu.choice.initiatingMessage.value, td, sptr);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, (void *)&pdu);
}
@@ -80,7 +80,7 @@ ssize_t m2ap_generate_unsuccessfull_outcome(
pdu.choice.successfulOutcome.criticality = criticality;
ANY_fromType_aper((ANY_t *)&pdu.choice.successfulOutcome.value, td, sptr);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, (void *)&pdu);
}
diff --git a/openair2/M2AP/m2ap_common.h b/openair2/M2AP/m2ap_common.h
index 266b303518..a875d8d078 100644
--- a/openair2/M2AP/m2ap_common.h
+++ b/openair2/M2AP/m2ap_common.h
@@ -50,8 +50,6 @@
# define M2AP_PORT 36423
#endif
-extern int asn1_xer_print;
-
#include "common/utils/LOG/log.h"
#include "m2ap_default_values.h"
#define M2AP_INFO(x, args...) LOG_I(M2AP, x, ##args)
diff --git a/openair2/M2AP/m2ap_decoder.c b/openair2/M2AP/m2ap_decoder.c
index 1237c4ec8e..4abd43f564 100644
--- a/openair2/M2AP/m2ap_decoder.c
+++ b/openair2/M2AP/m2ap_decoder.c
@@ -165,7 +165,7 @@ int m2ap_decode_pdu(M2AP_M2AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t
length,
0,
0);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, pdu);
}
diff --git a/openair2/M2AP/m2ap_encoder.c b/openair2/M2AP/m2ap_encoder.c
index 8f798ff55c..81a3bfce92 100644
--- a/openair2/M2AP/m2ap_encoder.c
+++ b/openair2/M2AP/m2ap_encoder.c
@@ -44,7 +44,7 @@ int m2ap_encode_pdu(M2AP_M2AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len)
DevAssert(buffer != NULL);
DevAssert(len != NULL);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, (void *)pdu);
}
diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c
index 75f6838a78..000c4f46cb 100644
--- a/openair2/RRC/NR/rrc_gNB.c
+++ b/openair2/RRC/NR/rrc_gNB.c
@@ -2305,13 +2305,19 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i
uper_decode_complete(NULL, &asn_DEF_NR_CellGroupConfig, (void **)&cellGroupConfig, (uint8_t *)cgc->buf, cgc->len);
AssertFatal(dec_rval.code == RC_OK && dec_rval.consumed > 0, "Cell group config decode error\n");
- if (UE->masterCellGroup) {
- ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
- LOG_I(RRC, "UE %04x replacing existing CellGroupConfig with new one received from DU\n", UE->rnti);
+ /* hack for interoperability with srsRAN: ignore cell group config if empty */
+ /* cell group config is empty if buffer length is 2 and content is all 0 */
+ bool cgc_is_empty = cgc->len == 2 && cgc->buf[0] == 0 && cgc->buf[1] == 0;
+ if (!cgc_is_empty) {
+ if (UE->masterCellGroup) {
+ ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
+ LOG_I(RRC, "UE %04x replacing existing CellGroupConfig with new one received from DU\n", UE->rnti);
+ }
+ UE->masterCellGroup = cellGroupConfig;
+ rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE);
+ } else {
+ LOG_W(NR_RRC, "hack: UE %d: ignore empty CellGroupConfig in UEContextModificationResponse\n", UE->rrc_ue_id);
}
- UE->masterCellGroup = cellGroupConfig;
-
- rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE);
}
// Reconfiguration should have been sent to the UE, so it will attempt the
diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c
index d0cc63062b..aa97a026e0 100644
--- a/openair2/RRC/NR/rrc_gNB_nsa.c
+++ b/openair2/RRC/NR/rrc_gNB_nsa.c
@@ -77,7 +77,7 @@
// and put it into a CG-ConfigInfo field
static int cg_config_info_from_ue_cap_file(uint32_t maxlen, uint8_t buf[maxlen])
{
- OCTET_STRING_t *os_cap = NULL;
+ OCTET_STRING_t *list_buf = NULL;
if (uecap_file != NULL) {
LOG_I(NR_RRC, "creating CG-ConfigInfo from UE capability file %s\n", uecap_file);
@@ -98,8 +98,17 @@ static int cg_config_info_from_ue_cap_file(uint32_t maxlen, uint8_t buf[maxlen])
DevAssert(dec_rval.code == RC_OK);
//xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, cap);
- os_cap = calloc_or_fail(1, sizeof(*os_cap));
- os_cap->size = uper_encode_to_new_buffer(&asn_DEF_NR_UE_NR_Capability, NULL, cap, (void **)&os_cap->buf);
+ uint8_t *buf = NULL;
+ int sizebuf = uper_encode_to_new_buffer(&asn_DEF_NR_UE_NR_Capability, NULL, cap, (void **)&buf);
+ NR_UE_CapabilityRAT_Container_t *cont = calloc_or_fail(1, sizeof(*cont));
+ cont->rat_Type = NR_RAT_Type_nr;
+ cont->ue_CapabilityRAT_Container.buf = buf;
+ cont->ue_CapabilityRAT_Container.size = sizebuf;
+ NR_UE_CapabilityRAT_ContainerList_t *clist = calloc_or_fail(1, sizeof(*clist));
+ asn1cSeqAdd(&clist->list, cont);
+ list_buf = calloc_or_fail(1, sizeof(*list_buf));
+ list_buf->size = uper_encode_to_new_buffer(&asn_DEF_NR_UE_CapabilityRAT_ContainerList, NULL, clist, (void **)&list_buf->buf);
+ ASN_STRUCT_FREE(asn_DEF_NR_UE_CapabilityRAT_ContainerList, clist);
}
NR_CG_ConfigInfo_t *cgci = calloc_or_fail(1, sizeof(*cgci));
@@ -108,7 +117,7 @@ static int cg_config_info_from_ue_cap_file(uint32_t maxlen, uint8_t buf[maxlen])
cgci->criticalExtensions.choice.c1->present = NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo;
NR_CG_ConfigInfo_IEs_t *cgci_ies = calloc_or_fail(1, sizeof(*cgci_ies));
cgci->criticalExtensions.choice.c1->choice.cg_ConfigInfo = cgci_ies;
- cgci_ies->ue_CapabilityInfo = os_cap;
+ cgci_ies->ue_CapabilityInfo = list_buf;
//xer_fprint(stdout, &asn_DEF_NR_CG_ConfigInfo, cgci);
asn_enc_rval_t rval = uper_encode_to_buffer(&asn_DEF_NR_CG_ConfigInfo, NULL, cgci, buf, maxlen);
diff --git a/openair2/X2AP/x2ap_common.c b/openair2/X2AP/x2ap_common.c
index a687b90666..0fc63b7de5 100644
--- a/openair2/X2AP/x2ap_common.c
+++ b/openair2/X2AP/x2ap_common.c
@@ -47,7 +47,7 @@ ssize_t x2ap_generate_initiating_message(
pdu.choice.initiatingMessage.criticality = criticality;
ANY_fromType_aper((ANY_t *)&pdu.choice.initiatingMessage.value, td, sptr);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, (void *)&pdu);
}
@@ -79,7 +79,7 @@ ssize_t x2ap_generate_successfull_outcome(
pdu.choice.successfulOutcome.criticality = criticality;
ANY_fromType_aper((ANY_t *)&pdu.choice.successfulOutcome.value, td, sptr);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, (void *)&pdu);
}
@@ -111,7 +111,7 @@ ssize_t x2ap_generate_unsuccessfull_outcome(
pdu.choice.successfulOutcome.criticality = criticality;
ANY_fromType_aper((ANY_t *)&pdu.choice.successfulOutcome.value, td, sptr);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, (void *)&pdu);
}
diff --git a/openair2/X2AP/x2ap_common.h b/openair2/X2AP/x2ap_common.h
index 81880cb71c..36dfe24287 100644
--- a/openair2/X2AP/x2ap_common.h
+++ b/openair2/X2AP/x2ap_common.h
@@ -49,8 +49,6 @@
# define X2AP_PORT 36422
#endif
-extern int asn1_xer_print;
-
#include "common/utils/LOG/log.h"
#define X2AP_INFO(x, args...) LOG_I(X2AP, x, ##args)
#define X2AP_ERROR(x, args...) LOG_E(X2AP, x, ##args)
diff --git a/openair2/X2AP/x2ap_eNB_decoder.c b/openair2/X2AP/x2ap_eNB_decoder.c
index 6d7897bf14..81cb77dfef 100644
--- a/openair2/X2AP/x2ap_eNB_decoder.c
+++ b/openair2/X2AP/x2ap_eNB_decoder.c
@@ -156,7 +156,7 @@ int x2ap_eNB_decode_pdu(X2AP_X2AP_PDU_t *pdu, const uint8_t *const buffer, uint3
length,
0,
0);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, pdu);
}
diff --git a/openair2/X2AP/x2ap_eNB_encoder.c b/openair2/X2AP/x2ap_eNB_encoder.c
index 8b1c030d35..a82eb03f9a 100644
--- a/openair2/X2AP/x2ap_eNB_encoder.c
+++ b/openair2/X2AP/x2ap_eNB_encoder.c
@@ -44,7 +44,7 @@ int x2ap_eNB_encode_pdu(X2AP_X2AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len)
DevAssert(buffer != NULL);
DevAssert(len != NULL);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, (void *)pdu);
}
diff --git a/openair3/M3AP/m3ap_common.c b/openair3/M3AP/m3ap_common.c
index e43275d96c..669d7eaa5e 100644
--- a/openair3/M3AP/m3ap_common.c
+++ b/openair3/M3AP/m3ap_common.c
@@ -47,7 +47,7 @@ ssize_t m3ap_generate_initiating_message(
pdu.choice.initiatingMessage.criticality = criticality;
ANY_fromType_aper((ANY_t *)&pdu.choice.initiatingMessage.value, td, sptr);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, (void *)&pdu);
}
@@ -80,7 +80,7 @@ ssize_t m3ap_generate_unsuccessfull_outcome(
pdu.choice.successfulOutcome.criticality = criticality;
ANY_fromType_aper((ANY_t *)&pdu.choice.successfulOutcome.value, td, sptr);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, (void *)&pdu);
}
diff --git a/openair3/M3AP/m3ap_common.h b/openair3/M3AP/m3ap_common.h
index 7c8ea18a5d..f5acb6bdf5 100644
--- a/openair3/M3AP/m3ap_common.h
+++ b/openair3/M3AP/m3ap_common.h
@@ -48,8 +48,6 @@
# define M3AP_PORT 36444
#endif
-extern int asn1_xer_print;
-
#include "common/utils/LOG/log.h"
#include "m3ap_default_values.h"
#define M3AP_INFO(x, args...) LOG_I(M3AP, x, ##args)
diff --git a/openair3/M3AP/m3ap_decoder.c b/openair3/M3AP/m3ap_decoder.c
index cee0a5ff41..36c8f64fae 100644
--- a/openair3/M3AP/m3ap_decoder.c
+++ b/openair3/M3AP/m3ap_decoder.c
@@ -188,7 +188,7 @@ int m3ap_decode_pdu(M3AP_M3AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t
length,
0,
0);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, pdu);
}
diff --git a/openair3/M3AP/m3ap_encoder.c b/openair3/M3AP/m3ap_encoder.c
index 2e1cbf80af..86a710ca90 100644
--- a/openair3/M3AP/m3ap_encoder.c
+++ b/openair3/M3AP/m3ap_encoder.c
@@ -44,7 +44,7 @@ int m3ap_encode_pdu(M3AP_M3AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len)
DevAssert(buffer != NULL);
DevAssert(len != NULL);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, (void *)pdu);
}
diff --git a/openair3/NAS/UE/API/USIM/aka_functions.c b/openair3/NAS/UE/API/USIM/aka_functions.c
index d2e3fc36c5..1f461c3bbf 100644
--- a/openair3/NAS/UE/API/USIM/aka_functions.c
+++ b/openair3/NAS/UE/API/USIM/aka_functions.c
@@ -303,7 +303,7 @@ void ComputeOPc(const u8 op[16], u8 op_c_pP[16])
return;
} /* end of function ComputeOPc */
/*-------------------- Rijndael round subkeys ---------------------*/
-u8 roundKeys[11][4][4];
+static u8 roundKeys[11][4][4];
/*--------------------- Rijndael S box table ----------------------*/
const u8 S[256] = {
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240,
diff --git a/openair3/NGAP/ngap_common.c b/openair3/NGAP/ngap_common.c
index 7b960fed0b..82c2ccaf2a 100644
--- a/openair3/NGAP/ngap_common.c
+++ b/openair3/NGAP/ngap_common.c
@@ -31,8 +31,6 @@
#include "conversions.h"
#include "ngap_common.h"
-int asn1_xer_print = 0;
-
void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in)
{
switch (in->type) {
diff --git a/openair3/NGAP/ngap_common.h b/openair3/NGAP/ngap_common.h
index 82a8fe9234..dd7fdebc54 100644
--- a/openair3/NGAP/ngap_common.h
+++ b/openair3/NGAP/ngap_common.h
@@ -48,9 +48,6 @@
#define NGAP_UE_ID_FMT "0x%06"PRIX32
-extern int asn_debug;
-extern int asn1_xer_print;
-
# include "common/utils/LOG/log.h"
# include "ngap_gNB_default_values.h"
# define NGAP_ERROR(x, args...) LOG_E(NGAP, x, ##args)
diff --git a/openair3/NGAP/ngap_gNB_encoder.c b/openair3/NGAP/ngap_gNB_encoder.c
index ee3b37e07d..c3c095541d 100644
--- a/openair3/NGAP/ngap_gNB_encoder.c
+++ b/openair3/NGAP/ngap_gNB_encoder.c
@@ -115,7 +115,7 @@ int ngap_gNB_encode_pdu(NGAP_NGAP_PDU_t *pdu, uint8_t **buffer, uint32_t *len)
DevAssert(pdu != NULL);
DevAssert(buffer != NULL);
DevAssert(len != NULL);
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, (void *)pdu);
}
switch (pdu->present) {
diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c
index 1aafeca8c9..b291f6b96c 100644
--- a/openair3/NGAP/ngap_gNB_nas_procedures.c
+++ b/openair3/NGAP/ngap_gNB_nas_procedures.c
@@ -690,7 +690,7 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r
// ie->value.choice.CriticalityDiagnostics =;
}
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, &pdu);
}
@@ -772,7 +772,7 @@ int ngap_gNB_initial_ctxt_fail(instance_t instance, ngap_initial_context_setup_f
ie->value.present = NGAP_InitialContextSetupFailureIEs__value_PR_Cause;
encode_ngap_cause(&ie->value.choice.Cause, &initial_ctxt_fail->cause);
}
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, &pdu);
}
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
diff --git a/openair3/S1AP/s1ap_common.h b/openair3/S1AP/s1ap_common.h
index 797bc7be8a..7ef7e589ca 100644
--- a/openair3/S1AP/s1ap_common.h
+++ b/openair3/S1AP/s1ap_common.h
@@ -52,8 +52,6 @@
#define S1AP_UE_ID_FMT "0x%06"PRIX32
-extern int asn1_xer_print;
-
#include "common/utils/LOG/log.h"
#include "s1ap_eNB_default_values.h"
#define S1AP_ERROR(x, args...) LOG_E(S1AP, x, ##args)
@@ -89,10 +87,4 @@ extern int asn1_xer_print;
**/
typedef int (*s1ap_message_decoded_callback)(sctp_assoc_t assoc_id, uint32_t stream, S1AP_S1AP_PDU_t *pdu);
-/** \brief Handle criticality
- \param criticality Criticality of the IE
- @returns void
- **/
-void s1ap_handle_criticality(S1AP_Criticality_t criticality);
-/** @}*/
#endif /* S1AP_COMMON_H_ */
diff --git a/openair3/S1AP/s1ap_eNB_encoder.c b/openair3/S1AP/s1ap_eNB_encoder.c
index 8317f02731..6ff837a7f1 100644
--- a/openair3/S1AP/s1ap_eNB_encoder.c
+++ b/openair3/S1AP/s1ap_eNB_encoder.c
@@ -129,7 +129,7 @@ int s1ap_eNB_encode_initiating(S1AP_S1AP_PDU_t *pdu,
return -1;
}
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_S1AP_S1AP_PDU, (void *)pdu);
}
@@ -183,7 +183,7 @@ int s1ap_eNB_encode_successfull_outcome(S1AP_S1AP_PDU_t *pdu,
return -1;
}
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_S1AP_S1AP_PDU, (void *)pdu);
}
@@ -214,7 +214,7 @@ int s1ap_eNB_encode_unsuccessfull_outcome(S1AP_S1AP_PDU_t *pdu,
return -1;
}
- if (asn1_xer_print) {
+ if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_S1AP_S1AP_PDU, (void *)pdu);
}
diff --git a/openair3/TEST/test_s1ap.c b/openair3/TEST/test_s1ap.c
index 8e61c338ac..1ecb30d476 100644
--- a/openair3/TEST/test_s1ap.c
+++ b/openair3/TEST/test_s1ap.c
@@ -154,10 +154,6 @@ void doit (void)
{
int i;
break_on_error = 1;
-
- // asn1_xer_print = 1;
- // asn_debug = 1;
-
for (i = 0; i < sizeof(s1ap_test) / sizeof(s1ap_test_t); i++) {
S1AP_S1AP_PDU_t pdu;
uint8_t *buffer;
diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp
index 9e07a44747..9be1873612 100644
--- a/openair3/ocp-gtpu/gtp_itf.cpp
+++ b/openair3/ocp-gtpu/gtp_itf.cpp
@@ -21,6 +21,7 @@ extern "C" {
#include
#include
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
+#include "openair3/ocp-gtpu/gtpu_extensions.h"
#include "sim.h"
#pragma pack(1)
@@ -112,6 +113,7 @@ typedef struct gtpv1u_bearer_s {
teid_t teid_outgoing;
uint16_t seqNum;
uint8_t npduNum;
+ int32_t nru_sequence_number;
int outgoing_qfi;
} gtpv1u_bearer_t;
@@ -230,11 +232,9 @@ static int gtpv1uCreateAndSendMsg(gtpv1u_bearer_t *bearer,
int msgLen,
bool seqNumFlag,
bool npduNumFlag,
- int extHdrType,
- uint8_t *extensionHeader_buffer,
- uint8_t extensionHeader_length)
+ gtpu_extension_header_t *extensions,
+ int extensions_count)
{
-
DevAssert(msgLen + HDR_MAX < 65536); // maximum size of UDP packet
uint8_t buffer[msgLen + HDR_MAX];
uint8_t *curPtr = buffer;
@@ -242,7 +242,7 @@ static int gtpv1uCreateAndSendMsg(gtpv1u_bearer_t *bearer,
// N should be 0 for us (it was used only in 2G and 3G)
msgHdr->PN = npduNumFlag;
msgHdr->S = seqNumFlag;
- msgHdr->E = extHdrType != NO_MORE_EXT_HDRS;
+ msgHdr->E = extensions_count != 0;
msgHdr->spare = 0;
// PT=0 is for GTP' TS 32.295 (charging)
msgHdr->PT = 1;
@@ -252,32 +252,32 @@ static int gtpv1uCreateAndSendMsg(gtpv1u_bearer_t *bearer,
curPtr += sizeof(Gtpv1uMsgHeaderT);
- if (seqNumFlag || (extHdrType != NO_MORE_EXT_HDRS) || npduNumFlag) {
+ if (msgHdr->PN || msgHdr->S || msgHdr->E) {
*(uint16_t *)curPtr = seqNumFlag ? bearer->seqNum : 0x0000;
curPtr += sizeof(uint16_t);
*(uint8_t *)curPtr = npduNumFlag ? bearer->npduNum : 0x00;
curPtr++;
- *(uint8_t *)curPtr = extHdrType;
+ *curPtr = extensions_count ? serialize_gtpu_extension_type(extensions[0].type) : 0;
curPtr++;
}
- // Bug: if there is more than one extension, infinite loop on extensionHeader_buffer
- while (extHdrType != NO_MORE_EXT_HDRS) {
- if (extensionHeader_length > 0) {
- memcpy(curPtr, extensionHeader_buffer, extensionHeader_length);
- curPtr += extensionHeader_length;
- LOG_D(GTPU,
- "Extension Header for DDD added. The length is: %d, extension header type is: %x \n",
- extensionHeader_length,
- *((uint8_t *)(buffer + 11)));
- extHdrType = extensionHeader_buffer[extensionHeader_length - 1];
- LOG_D(GTPU, "Next extension header type is: %x \n", *((uint8_t *)(buffer + 11)));
- } else {
- LOG_W(GTPU, "Extension header type not supported, returning... \n");
+ for (int i = 0; i < extensions_count; i++) {
+ int available_size = sizeof(buffer) - (curPtr - buffer);
+ gtpu_extension_header_type_t next = i == extensions_count - 1 ? GTPU_EXT_NONE : extensions[i + 1].type;
+ int len = serialize_extension(&extensions[i], next, curPtr, available_size);
+ if (len == -1) {
+ LOG_E(GTPU, "GTP extension serialization: buffer too small\n");
+ return GTPNOK;
}
+ curPtr += len;
}
if (Msg != NULL) {
+ int available_size = sizeof(buffer) - (curPtr - buffer);
+ if (msgLen > available_size) {
+ LOG_E(GTPU, "GTP message creation: buffer too small\n");
+ return GTPNOK;
+ }
memcpy(curPtr, Msg, msgLen);
curPtr += msgLen;
}
@@ -307,13 +307,14 @@ static int gtpv1uCreateAndSendMsg(gtpv1u_bearer_t *bearer,
return !GTPNOK;
}
-void gtpv1uSendDirect(instance_t instance,
- ue_id_t ue_id,
- int bearer_id,
- uint8_t *buf,
- size_t len,
- bool seqNumFlag,
- bool npduNumFlag)
+static void _gtpv1uSendDirect(instance_t instance,
+ ue_id_t ue_id,
+ int bearer_id,
+ uint8_t *buf,
+ size_t len,
+ bool seqNumFlag,
+ bool npduNumFlag,
+ int32_t nru_seqnum)
{
pthread_mutex_lock(&globGtp.gtp_lock);
getInstRetVoid(compatInst(instance));
@@ -347,18 +348,44 @@ void gtpv1uSendDirect(instance_t instance,
gtpv1u_bearer_t bearer = ptr2->second;
pthread_mutex_unlock(&globGtp.gtp_lock);
- Gtpv1uExtHeaderT *opt_ext = NULL;
- Gtpv1uExtHeaderT ext = {0};
+ int extension_count = 0;
+ gtpu_extension_header_t ext[2];
if (bearer.outgoing_qfi != -1) {
- opt_ext = &ext;
- ext.ExtHeaderLen = 1; // in quad bytes EXT_HDR_LNTH_OCTET_UNITS
- ext.pdusession_cntr.spare = 0;
- ext.pdusession_cntr.PDU_type = UL_PDU_SESSION_INFORMATION;
- ext.pdusession_cntr.QFI = bearer.outgoing_qfi;
- ext.pdusession_cntr.Reflective_QoS_activation = false;
- ext.pdusession_cntr.Paging_Policy_Indicator = false;
- ext.NextExtHeaderType = NO_MORE_EXT_HDRS;
+ /* 29.281 Figure 5.2.1-3 note 4 says PDU Session Container must come first.
+ * GTPU_EXT_UL_PDU_SESSION_INFORMATION is within a PDU Session Container
+ * so it must be put before any other extension.
+ */
+ ext[extension_count] = {
+ .type = GTPU_EXT_UL_PDU_SESSION_INFORMATION,
+ .ul_pdu_session_information = {
+ .qmp = false,
+ .dl_delay_ind = false,
+ .ul_delay_ind = false,
+ .snp = false,
+ .n3n9_delay_ind = false,
+ .new_ie_flag = false,
+ .qfi = bearer.outgoing_qfi
+ }
+ };
+ extension_count++;
+ }
+ if (nru_seqnum != -1) {
+ ext[extension_count] = {
+ .type = GTPU_EXT_DL_USER_DATA,
+ .dl_user_data = {
+ .dl_discard_blocks = false,
+ .dl_flush = false,
+ .report_polling = false,
+ .request_out_of_seq_report = false,
+ .report_delivered = false,
+ .user_data_existence_flag = false,
+ .assistance_info_report_polling_flag = false,
+ .retransmission_flag = false,
+ .nru_sequence_number = (uint32_t)nru_seqnum
+ }
+ };
+ extension_count++;
}
DevAssert(compatInst(instance) == bearer.sock_fd);
@@ -368,9 +395,81 @@ void gtpv1uSendDirect(instance_t instance,
len,
seqNumFlag,
npduNumFlag,
- opt_ext ? PDU_SESSION_CONTAINER : NO_MORE_EXT_HDRS,
- (uint8_t *)opt_ext,
- sizeof(*opt_ext));
+ ext,
+ extension_count);
+}
+
+void gtpv1uSendDirect(instance_t instance,
+ ue_id_t ue_id,
+ int bearer_id,
+ uint8_t *buf,
+ size_t len,
+ bool seqNumFlag,
+ bool npduNumFlag)
+{
+ _gtpv1uSendDirect(instance,
+ ue_id,
+ bearer_id,
+ buf,
+ len,
+ seqNumFlag,
+ npduNumFlag,
+ -1);
+}
+
+void gtpv1uSendDirectWithNRUSeqNum(instance_t instance,
+ ue_id_t ue_id,
+ int bearer_id,
+ uint8_t *buf,
+ size_t len)
+{
+ pthread_mutex_lock(&globGtp.gtp_lock);
+ getInstRetVoid(compatInst(instance));
+ getUeRetVoid(inst, ue_id);
+ auto ptr2 = ptrUe->second.bearers.find(bearer_id);
+
+ if (ptr2 == ptrUe->second.bearers.end()) {
+ LOG_E(GTPU, "[%ld] GTP-U instance: sending a packet to a non existant UE:RAB: %lx/%x\n", instance, ue_id, bearer_id);
+ pthread_mutex_unlock(&globGtp.gtp_lock);
+ return;
+ }
+
+ int32_t nru_seqnum = ptr2->second.nru_sequence_number;
+ ptr2->second.nru_sequence_number++;
+ ptr2->second.nru_sequence_number &= (1 << 24) - 1;
+
+ pthread_mutex_unlock(&globGtp.gtp_lock);
+
+ _gtpv1uSendDirect(instance,
+ ue_id,
+ bearer_id,
+ buf,
+ len,
+ false,
+ false,
+ nru_seqnum);
+}
+
+static void fillDlDeliveryStatusReport(gtpu_extension_header_t *ext, uint32_t RLC_buffer_availability, uint32_t NR_PDCP_PDU_SN)
+{
+ *ext = {
+ .type = GTPU_EXT_DL_DATA_DELIVERY_STATUS,
+ .dl_data_delivery_status = {
+ /* previous version of the code was sending highest_transmitted_nr_pdcp_sn if
+ * it is != 0, let's do the same for the moment */
+ .highest_transmitted_nr_pdcp_sn_ind = NR_PDCP_PDU_SN != 0,
+ .highest_delivered_nr_pdcp_sn_ind = false,
+ .final_frame_ind = false,
+ .lost_packet_report = false,
+ .delivered_nr_pdcp_sn_range_ind = false,
+ .data_rate_ind = false,
+ .retransmitted_nr_pdcp_sn_ind = false,
+ .delivered_retransmitted_nr_pdcp_ind = false,
+ .cause_report = false,
+ .desired_buffer_size = RLC_buffer_availability,
+ .highest_transmitted_nr_pdcp_sn = NR_PDCP_PDU_SN
+ }
+ };
}
static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_end_marker_req_t *req)
@@ -950,7 +1049,6 @@ static int Gtpv1uHandleEchoReq(int h, uint8_t *msgBuf, uint32_t msgBufLen, const
sizeof recovery,
true,
false,
- NO_MORE_EXT_HDRS,
NULL,
0);
}
@@ -1168,37 +1266,8 @@ static int Gtpv1uHandleGpdu(int h, uint8_t *msgBuf, uint32_t msgBufLen, const st
LOG_D(GTPU, "Create and send DL DATA Delivery status for the previously received PDU, NR_PDCP_PDU_SN: %u \n", NR_PDCP_PDU_SN);
int rlc_tx_buffer_space = nr_rlc_get_available_tx_space(ctxt.rntiMaybeUEid, rb_id + 3);
LOG_D(GTPU, "Available buffer size in RLC for Tx: %d \n", rlc_tx_buffer_space);
- /*Total size of DDD_status PDU = 1 octet to report extension header length
- * size of mandatory part + 3 octets for highest transmitted/delivered PDCP SN
- * 1 octet for padding + 1 octet for next extension header type,
- * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/
- extensionHeader_t *extensionHeader;
- extensionHeader = (extensionHeader_t *)calloc(1, sizeof(extensionHeader_t));
- extensionHeader->buffer[0] = (1 + sizeof(DlDataDeliveryStatus_flagsT) + 3 + 1 + 1) / 4;
- DlDataDeliveryStatus_flagsT DlDataDeliveryStatus;
- DlDataDeliveryStatus.deliveredPdcpSn = 0;
- DlDataDeliveryStatus.transmittedPdcpSn = 1;
- DlDataDeliveryStatus.pduType = 1;
- DlDataDeliveryStatus.drbBufferSize =
- htonl(rlc_tx_buffer_space); // htonl(10000000); //hardcoded for now but normally we should extract it from RLC
- memcpy(extensionHeader->buffer + 1, &DlDataDeliveryStatus, sizeof(DlDataDeliveryStatus_flagsT));
- uint8_t offset = sizeof(DlDataDeliveryStatus_flagsT) + 1;
-
- extensionHeader->buffer[offset] = (NR_PDCP_PDU_SN >> 16) & 0xff;
- extensionHeader->buffer[offset + 1] = (NR_PDCP_PDU_SN >> 8) & 0xff;
- extensionHeader->buffer[offset + 2] = NR_PDCP_PDU_SN & 0xff;
- LOG_D(GTPU,
- "Octets reporting NR_PDCP_PDU_SN, extensionHeader-> %u:%u:%u \n",
- extensionHeader->buffer[offset],
- extensionHeader->buffer[offset + 1],
- extensionHeader->buffer[offset + 2]);
- extensionHeader->buffer[offset + 3] = 0x00; // Padding octet
- extensionHeader->buffer[offset + 4] = 0x00; // No more extension headers
- /*Total size of DDD_status PDU = size of mandatory part +
- * 3 octets for highest transmitted/delivered PDCP SN +
- * 1 octet for padding + 1 octet for next extension header type,
- * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/
- extensionHeader->length = 1 + sizeof(DlDataDeliveryStatus_flagsT) + 3 + 1 + 1;
+ gtpu_extension_header_t ext;
+ fillDlDeliveryStatusReport(&ext, rlc_tx_buffer_space, NR_PDCP_PDU_SN);
uint32_t teid = globGtp.te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid;
gtpv1u_bearer_t bearer = create_bearer(h, addr, teid, 0);
gtpv1uCreateAndSendMsg(&bearer,
@@ -1207,9 +1276,8 @@ static int Gtpv1uHandleGpdu(int h, uint8_t *msgBuf, uint32_t msgBufLen, const st
0,
false,
false,
- NR_RAN_CONTAINER,
- extensionHeader->buffer,
- extensionHeader->length);
+ &ext,
+ 1);
}
LOG_D(GTPU, "[%d] Received a %d bytes packet for: teid:%x\n", h, msgBufLen - offset, ntohl(msgHdr->teid));
diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h
index d341acb311..4fcb8190e4 100644
--- a/openair3/ocp-gtpu/gtp_itf.h
+++ b/openair3/ocp-gtpu/gtp_itf.h
@@ -128,6 +128,11 @@ typedef struct gtpv1u_gnb_delete_tunnel_req_s gtpv1u_gnb_delete_tunnel_req_t;
int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id);
void gtpv1uSendDirect(instance_t instance, ue_id_t ue_id, int bearer_id, uint8_t *buf, size_t len, bool seqNumFlag, bool npduNumFlag);
+ void gtpv1uSendDirectWithNRUSeqNum(instance_t instance,
+ ue_id_t ue_id,
+ int bearer_id,
+ uint8_t *buf,
+ size_t len);
instance_t gtpv1Init(openAddr_t context);
void *gtpv1uTask(void *args);
diff --git a/openair3/ocp-gtpu/gtpu_extensions.c b/openair3/ocp-gtpu/gtpu_extensions.c
new file mode 100644
index 0000000000..13f0cee053
--- /dev/null
+++ b/openair3/ocp-gtpu/gtpu_extensions.c
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ * contact@openairinterface.org
+ */
+
+#include "gtpu_extensions.h"
+#include "common/utils/assertions.h"
+#include "common/utils/ds/byte_array_producer.h"
+#include "LOG/log.h"
+
+/* 29.281 Figure 5.2.1-3 */
+#define NR_RAN_CONTAINER 0x84
+#define PDU_SESSION_CONTAINER 0x85
+
+/* from an extension type, returns its "extension header type"
+ * as defined in 29.281 Figure 5.2.1-3
+ */
+int serialize_gtpu_extension_type(gtpu_extension_header_type_t type)
+{
+ switch (type) {
+ case GTPU_EXT_NONE:
+ /* 0, no more extension */
+ return 0;
+ case GTPU_EXT_UL_PDU_SESSION_INFORMATION:
+ return PDU_SESSION_CONTAINER;
+ case GTPU_EXT_DL_DATA_DELIVERY_STATUS:
+ case GTPU_EXT_DL_USER_DATA:
+ return NR_RAN_CONTAINER;
+ default:
+ AssertFatal(0, "unknown GTPU extension type %d\n", type);
+ }
+}
+
+/* returns 0 on error, 1 on success */
+static int serialize_ul_pdu_session_information(byte_array_producer_t *b, ul_pdu_session_information_t *ext)
+{
+ /* see 38.415 5.5.2.2 */
+ AssertFatal(!ext->qmp && !ext->dl_delay_ind && !ext->ul_delay_ind
+ && !ext->snp && !ext->n3n9_delay_ind && !ext->new_ie_flag,
+ "todo\n");
+
+ uint8_t b1 = (1 << 4) | (ext->qmp << 3) | (ext->dl_delay_ind << 2) | (ext->ul_delay_ind << 1) | ext->snp;
+ uint8_t b2 = (ext->n3n9_delay_ind << 7) | (ext->new_ie_flag << 6) | ext->qfi;
+ return byte_array_producer_put_byte(b, b1) && byte_array_producer_put_byte(b, b2);
+}
+
+/* returns 0 on error, 1 on success */
+static int serialize_dl_data_delivery_status(byte_array_producer_t *b, dl_data_delivery_status_t *ext)
+{
+ /* see 38.425 5.5.2.2 */
+ AssertFatal(!ext->highest_delivered_nr_pdcp_sn_ind && !ext->final_frame_ind
+ && !ext->lost_packet_report && !ext->delivered_nr_pdcp_sn_range_ind
+ && !ext->data_rate_ind && !ext->retransmitted_nr_pdcp_sn_ind
+ && !ext->delivered_retransmitted_nr_pdcp_ind && !ext->cause_report,
+ "todo\n");
+
+ uint8_t b1 = (1 << 4)
+ | (ext->highest_transmitted_nr_pdcp_sn_ind << 3)
+ | (ext->highest_delivered_nr_pdcp_sn_ind << 2)
+ | (ext->final_frame_ind << 1)
+ | ext->lost_packet_report;
+ uint8_t b2 = (ext->delivered_nr_pdcp_sn_range_ind << 4)
+ | (ext->data_rate_ind << 3)
+ | (ext->retransmitted_nr_pdcp_sn_ind << 2)
+ | (ext->delivered_retransmitted_nr_pdcp_ind << 1)
+ | ext->cause_report;
+ if (!byte_array_producer_put_byte(b, b1) || !byte_array_producer_put_byte(b, b2))
+ return 0;
+
+ if (!byte_array_producer_put_u32_be(b, ext->desired_buffer_size))
+ return 0;
+
+ if (ext->highest_transmitted_nr_pdcp_sn_ind)
+ if (!byte_array_producer_put_u24_be(b, ext->highest_transmitted_nr_pdcp_sn))
+ return 0;
+
+ return 1;
+}
+
+/* returns 0 on error, 1 on success */
+static int serialize_dl_user_data(byte_array_producer_t *b, dl_user_data_t *ext)
+{
+ /* see 38.425 5.5.2.1 */
+ AssertFatal(!ext->dl_discard_blocks && !ext->dl_flush && !ext->report_polling
+ && !ext->request_out_of_seq_report && !ext->report_delivered
+ && !ext->user_data_existence_flag && !ext->assistance_info_report_polling_flag
+ && !ext->retransmission_flag,
+ "todo\n");
+
+ uint8_t b1 = (0 << 4) | (ext->dl_discard_blocks << 2) | (ext->dl_flush << 1) | ext->report_polling;
+ uint8_t b2 = (ext->request_out_of_seq_report << 4)
+ | (ext->report_delivered << 3)
+ | (ext->user_data_existence_flag << 2)
+ | (ext->assistance_info_report_polling_flag << 1)
+ | ext->retransmission_flag;
+ if (!byte_array_producer_put_byte(b, b1) || !byte_array_producer_put_byte(b, b2))
+ return 0;
+
+ if (!byte_array_producer_put_u24_be(b, ext->nru_sequence_number))
+ return 0;
+
+ return 1;
+}
+
+/* returns -1 on error, number of serialized bytes on success */
+int serialize_extension(gtpu_extension_header_t *ext, gtpu_extension_header_type_t next, uint8_t *out_buf, int out_len)
+{
+ byte_array_producer_t b;
+
+ b = byte_array_producer_from_buffer(out_buf, out_len);
+ /* length - will be set later */
+ if (!byte_array_producer_put_byte(&b, 0))
+ goto error;
+
+ switch (ext->type) {
+ case GTPU_EXT_UL_PDU_SESSION_INFORMATION:
+ if (!serialize_ul_pdu_session_information(&b, &ext->ul_pdu_session_information))
+ goto error;
+ break;
+ case GTPU_EXT_DL_DATA_DELIVERY_STATUS:
+ if (!serialize_dl_data_delivery_status(&b, &ext->dl_data_delivery_status))
+ goto error;
+ break;
+ case GTPU_EXT_DL_USER_DATA:
+ if (!serialize_dl_user_data(&b, &ext->dl_user_data))
+ goto error;
+ break;
+ default:
+ LOG_E(GTPU, "unknown extension type %d\n", ext->type);
+ return -1;
+ }
+
+ /* padding */
+ while ((b.pos & 3) != 3)
+ if (!byte_array_producer_put_byte(&b, 0))
+ goto error;
+
+ /* next */
+ if (!byte_array_producer_put_byte(&b, serialize_gtpu_extension_type(next)))
+ goto error;
+
+ /* length is now know */
+ DevAssert(b.pos / 4 <= 255);
+ out_buf[0] = b.pos / 4;
+
+ return b.pos;
+
+error:
+ LOG_E(GTPU, "error serializing extension\n");
+ return -1;
+}
diff --git a/openair3/ocp-gtpu/gtpu_extensions.h b/openair3/ocp-gtpu/gtpu_extensions.h
new file mode 100644
index 0000000000..b621d27e14
--- /dev/null
+++ b/openair3/ocp-gtpu/gtpu_extensions.h
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ * contact@openairinterface.org
+ */
+
+#ifndef GTPU_EXTENSIONS_H
+#define GTPU_EXTENSIONS_H
+
+#include
+#include
+
+typedef enum {
+ GTPU_EXT_NONE,
+ /* 38.415 */
+ GTPU_EXT_UL_PDU_SESSION_INFORMATION,
+ /* 38.425 */
+ GTPU_EXT_DL_DATA_DELIVERY_STATUS,
+ GTPU_EXT_DL_USER_DATA,
+} gtpu_extension_header_type_t;
+
+/* 38.415 */
+typedef struct {
+ /* not all fields are present, to be refined if needed */
+ bool qmp;
+ bool dl_delay_ind;
+ bool ul_delay_ind;
+ bool snp;
+ bool n3n9_delay_ind;
+ bool new_ie_flag;
+ int qfi;
+} ul_pdu_session_information_t;
+
+/* 38.425 */
+typedef struct {
+ /* not all fields are present, to be refined if needed */
+ bool highest_transmitted_nr_pdcp_sn_ind;
+ bool highest_delivered_nr_pdcp_sn_ind;
+ bool final_frame_ind;
+ bool lost_packet_report;
+ bool delivered_nr_pdcp_sn_range_ind;
+ bool data_rate_ind;
+ bool retransmitted_nr_pdcp_sn_ind;
+ bool delivered_retransmitted_nr_pdcp_ind;
+ bool cause_report;
+ uint32_t desired_buffer_size;
+ uint32_t highest_transmitted_nr_pdcp_sn;
+} dl_data_delivery_status_t;
+
+/* 38.425 */
+typedef struct {
+ /* not all fields are present, to be refined if needed */
+ bool dl_discard_blocks;
+ bool dl_flush;
+ bool report_polling;
+ bool request_out_of_seq_report;
+ bool report_delivered;
+ bool user_data_existence_flag;
+ bool assistance_info_report_polling_flag;
+ bool retransmission_flag;
+ uint32_t nru_sequence_number;
+} dl_user_data_t;
+
+typedef struct {
+ gtpu_extension_header_type_t type;
+ union {
+ ul_pdu_session_information_t ul_pdu_session_information;
+ dl_data_delivery_status_t dl_data_delivery_status;
+ dl_user_data_t dl_user_data;
+ };
+} gtpu_extension_header_t;
+
+int serialize_gtpu_extension_type(gtpu_extension_header_type_t type);
+int serialize_extension(gtpu_extension_header_t *ext, gtpu_extension_header_type_t next, uint8_t *out_buf, int out_len);
+
+#endif /* GTPU_EXTENSIONS_H */
diff --git a/radio/CMakeLists.txt b/radio/CMakeLists.txt
index 654fb037f0..1159416afa 100644
--- a/radio/CMakeLists.txt
+++ b/radio/CMakeLists.txt
@@ -38,7 +38,12 @@ if(OAI_USRP)
add_subdirectory(USRP)
endif()
-add_boolean_option(VRTSIM_RADIO ON "Activate OAI's shared memory radio driver" OFF)
-if(VRTSIM_RADIO)
+add_boolean_option(OAI_VRTSIM ON "Activate OAI's shared memory radio driver" OFF)
+if(OAI_VRTSIM)
add_subdirectory(vrtsim)
endif()
+
+add_boolean_option(OAI_RF_EMULATOR ON "Activate OAI's RF emulator" OFF)
+if(OAI_RF_EMULATOR)
+ add_subdirectory(emulator)
+endif()
diff --git a/radio/COMMON/common_lib.h b/radio/COMMON/common_lib.h
index 86d09b00fb..f928d554a8 100644
--- a/radio/COMMON/common_lib.h
+++ b/radio/COMMON/common_lib.h
@@ -204,8 +204,6 @@ typedef struct split7_config {
typedef struct openair0_config {
//! Module ID for this configuration
int Mod_id;
- //! device log level
- int log_level;
//! duplexing mode
duplex_mode_t duplex_mode;
//! number of downlink resource blocks
@@ -292,8 +290,6 @@ typedef struct openair0_config {
double rx_sample_rate;
//! the sample rate for transmit.
double tx_sample_rate;
- //! check for threequarter sampling rate
- int8_t threequarter_fs;
//! Flag to indicate this configuration is for NR
int nr_flag;
//! NR band number
diff --git a/radio/ETHERNET/ethernet_lib.c b/radio/ETHERNET/ethernet_lib.c
index eb23ef28cc..2a4d021afc 100644
--- a/radio/ETHERNET/ethernet_lib.c
+++ b/radio/ETHERNET/ethernet_lib.c
@@ -617,7 +617,6 @@ void dump_dev(openair0_device *device)
eth_state_t *eth = (eth_state_t*)device->priv;
printf("Ethernet device interface %i configuration:\n" ,device->openair0_cfg->Mod_id);
- printf(" Log level is %i :\n" ,device->openair0_cfg->log_level);
printf(" RB number: %i, sample rate: %lf \n" ,
device->openair0_cfg->num_rb_dl, device->openair0_cfg->sample_rate);
printf(" RAU configured for %i tx/%i rx channels)\n",
diff --git a/radio/emulator/CMakeLists.txt b/radio/emulator/CMakeLists.txt
new file mode 100644
index 0000000000..42b196ee95
--- /dev/null
+++ b/radio/emulator/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(rf_emulator MODULE rf_emulator.c)
+set_target_properties(rf_emulator PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+target_link_libraries(rf_emulator PRIVATE noise_device)
+add_dependencies(rf_emulator generate_T)
diff --git a/radio/emulator/README.md b/radio/emulator/README.md
new file mode 100644
index 0000000000..b3b58ba6a7
--- /dev/null
+++ b/radio/emulator/README.md
@@ -0,0 +1,25 @@
+# RF emulator library
+
+The RF emulator is a simple network stack terminator on the RF side.
+It is meant to run the network stack without real radio and without RF simulation.
+It simply drops TX signal and generate noise as an RX signal.
+It can be used in `phy-test` mode to simply benchmark the network stack in a determined scenario.
+It synchronizes the network stack on the real time clock of the host to guarantee a realistic behavior of the network stack.
+It detects and report late samples reads and writes to assess the real time behavior of the network stack.
+
+## Building
+
+`librf_emulator.so` is built by default by the `build_oai.sh` script.
+It is then located in the root build directory (usually `cmake_targets/ran_build/build`).
+
+## Usage
+
+### Enabling `rf_emulator`
+
+Use the option `--device.name rf_emulator` of the softmodem to use the RF emulator.
+
+### Options
+
+Two options are available to configure the RF emulator:
+* `--rf_emulator.enable_noise ` Enables (enable = 1) or disables (enable = 0) noise generation on RX. By default noise generation is enabled.
+* `--rf_emulator.noise_level_dBFS ` Sets the level of noise generated in dB. If omitted no noise is generated.
diff --git a/radio/emulator/rf_emulator.c b/radio/emulator/rf_emulator.c
new file mode 100644
index 0000000000..861daab2ba
--- /dev/null
+++ b/radio/emulator/rf_emulator.c
@@ -0,0 +1,369 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ * contact@openairinterface.org
+ */
+
+/*! \file radio/emulator/rf_emulator.c
+ * \brief RF library that does nothing to be used in benchmarks with phy-test without RF
+ */
+
+#include
+#include
+
+#include
+#include
+#include "common/utils/threadPool/pthread_utils.h"
+#include "common_lib.h"
+#include "radio/vrtsim/noise_device.h"
+#include "simde/x86/avx512.h"
+#include "SIMULATION/TOOLS/sim.h"
+
+#define RF_EMULATOR_SECTION "rf_emulator"
+// clang-format off
+#define RF_EMULATOR_PARAMS_DESC \
+ { \
+ {"enable_noise", "Enable noise injection", 0, .iptr = &emulator_state->enable_noise, .defintval = 1, TYPE_INT, 0},\
+ {"noise_level_dBFS", "Noise level", 0, .iptr = &emulator_state->noise_level_dBFS, .defintval = INVALID_DBFS_VALUE, TYPE_INT, 0},\
+ };
+// clang-format on
+
+// structures and timing thread job for timing
+typedef struct {
+ uint64_t timestamp;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ uint64_t late_reads;
+ uint64_t late_writes;
+} emulator_timestamp_t;
+
+typedef struct {
+ uint64_t last_received_sample;
+ double timescale;
+ double sample_rate;
+ emulator_timestamp_t emulator_timestamp;
+ pthread_t timing_thread;
+ bool run_timing_thread;
+ int enable_noise;
+ int noise_level_dBFS;
+} emulator_state_t;
+
+static void *emulator_timing_job(void *arg)
+{
+ emulator_state_t *emulator_state = (emulator_state_t *)arg;
+ struct timespec timestamp;
+ if (clock_gettime(CLOCK_REALTIME, ×tamp)) {
+ LOG_E(UTIL, "clock_gettime failed\n");
+ exit(1);
+ }
+ double leftover_samples = 0;
+ while (emulator_state->run_timing_thread) {
+ struct timespec current_time;
+ if (clock_gettime(CLOCK_REALTIME, ¤t_time)) {
+ LOG_E(UTIL, "clock_gettime failed\n");
+ exit(1);
+ }
+
+ emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp;
+ if (current_time.tv_sec != timestamp.tv_sec) {
+ if (emulator_timestamp->late_reads != 0) {
+ LOG_W(HW, "%ld RF reads were late\n", emulator_timestamp->late_reads);
+ }
+ emulator_timestamp->late_reads = 0;
+ if (emulator_timestamp->late_writes != 0) {
+ LOG_W(HW, "%ld RF writes were late\n", emulator_timestamp->late_writes);
+ }
+ emulator_timestamp->late_writes = 0;
+ }
+
+ uint64_t diff = (current_time.tv_sec - timestamp.tv_sec) * 1000000000 + (current_time.tv_nsec - timestamp.tv_nsec);
+ timestamp = current_time;
+ double samples_to_produce = emulator_state->sample_rate * emulator_state->timescale * diff / 1e9;
+
+ // Attempt to correct compounding rounding error
+ leftover_samples += samples_to_produce - (uint64_t)samples_to_produce;
+ if (leftover_samples > 1.0f) {
+ samples_to_produce += 1;
+ leftover_samples -= 1;
+ }
+
+ mutexlock(emulator_timestamp->mutex);
+ emulator_timestamp->timestamp += samples_to_produce;
+ condbroadcast(emulator_timestamp->cond);
+ mutexunlock(emulator_timestamp->mutex);
+
+ usleep(1);
+ }
+ return 0;
+}
+
+/*! \brief Called to start the RF transceiver. Return 0 if OK, < 0 if error
+ * \param device pointer to the device structure specific to the RF hardware target
+ */
+static int emulator_start(openair0_device *device)
+{
+ // Start the timing thread and the noise device
+ emulator_state_t *emulator_state = (emulator_state_t *)device->priv;
+ if (!emulator_state->run_timing_thread) {
+ if (emulator_state->enable_noise > 0) {
+ float noise_level = emulator_state->noise_level_dBFS == INVALID_DBFS_VALUE
+ ? 0.0f
+ : (32767.0 / powf(10.0, .05 * -(emulator_state->noise_level_dBFS)));
+ init_noise_device(noise_level);
+ LOG_I(HW, "Using noise level with %d dBFS/%f\n", emulator_state->noise_level_dBFS, noise_level);
+ }
+
+ emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp;
+ memset(emulator_timestamp, 0, sizeof(emulator_timestamp_t));
+
+ pthread_mutexattr_t mutex_attr;
+ pthread_condattr_t cond_attr;
+ int ret = pthread_mutexattr_init(&mutex_attr);
+ AssertFatal(ret == 0, "pthread_mutexattr_init() failed: errno %d, %s\n", errno, strerror(errno));
+
+ ret = pthread_condattr_init(&cond_attr);
+ AssertFatal(ret == 0, "pthread_condattr_init() failed: errno %d, %s\n", errno, strerror(errno));
+
+ ret = pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
+ AssertFatal(ret == 0, "pthread_mutexattr_setpshared() failed: errno %d, %s\n", errno, strerror(errno));
+
+ ret = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
+ AssertFatal(ret == 0, "pthread_condattr_setpshared() failed: errno %d, %s\n", errno, strerror(errno));
+
+ ret = pthread_mutex_init(&emulator_timestamp->mutex, &mutex_attr);
+ AssertFatal(ret == 0, "pthread_mutex_init() failed: errno %d, %s\n", errno, strerror(errno));
+
+ ret = pthread_cond_init(&emulator_timestamp->cond, &cond_attr);
+ AssertFatal(ret == 0, "pthread_cond_init() failed: errno %d, %s\n", errno, strerror(errno));
+
+ emulator_state->run_timing_thread = true;
+ ret = pthread_create(&emulator_state->timing_thread, NULL, emulator_timing_job, emulator_state);
+ AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno));
+ }
+
+ return 0;
+}
+
+/*! \brief print the RF statistics
+ * \param device pointer to the device structure specific to the RF hardware target
+ * \returns 0 on success
+ */
+int emulator_get_stats(openair0_device *device)
+{
+ return (0);
+}
+
+/*! \brief Reset the RF statistics
+ * \param device pointer to the device structure specific to the RF hardware target
+ * \returns 0 on success
+ */
+int emulator_reset_stats(openair0_device *device)
+{
+ return (0);
+}
+
+/*! \brief Terminate operation of the RF transceiver -- free all associated resources (if any)
+ * \param pointer to the device structure specific to the RF hardware target
+ */
+static void emulator_end(openair0_device *device)
+{
+ // Stop the timing thread and the noise device
+ emulator_state_t *emulator_state = (emulator_state_t *)device->priv;
+ if (emulator_state->run_timing_thread) {
+ emulator_state->run_timing_thread = false;
+ int ret = pthread_join(emulator_state->timing_thread, NULL);
+ AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno));
+ if (emulator_state->enable_noise > 0) {
+ free_noise_device();
+ }
+ }
+}
+
+/*! \brief Stop RF
+ * \param device pointer to the device structure specific to the RF hardware target
+ */
+int emulator_stop(openair0_device *device)
+{
+ return (0);
+}
+
+/*! \brief Set Gains (TX/RX)
+ * \param device pointer to the device structure specific to the RF hardware target
+ * \param openair0_cfg RF frontend parameters set by application
+ * \returns 0 in success
+ */
+int emulator_set_gains(openair0_device *device, openair0_config_t *openair0_cfg)
+{
+ return (0);
+}
+
+/*! \brief Set frequencies (TX/RX).
+ * \param device pointer to the device structure specific to the RF hardware target
+ * \param openair0_cfg RF frontend parameters set by application
+ * \returns 0 in success
+ */
+int emulator_set_freq(openair0_device *device, openair0_config_t *openair0_cfg)
+{
+ return (0);
+}
+
+int emulator_write_init(openair0_device *device)
+{
+ return (0);
+}
+
+/*! \brief Called to send samples to the RF target
+ * \param device pointer to the device structure specific to the RF hardware target
+ * \param timestamp The timestamp at which the first sample MUST be sent
+ * \param buff Buffer which holds the samples
+ * \param nsamps number of samples to be sent
+ * \param nbAnt number of antennas
+ * \param flags flags must be set to true if timestamp parameter needs to be applied
+ */
+static int emulator_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int nbAnt, int flags)
+{
+ emulator_state_t *emulator_state = (emulator_state_t *)device->priv;
+
+ // timestamp in the past
+ emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp;
+ uint64_t current_timestamp = emulator_timestamp->timestamp;
+ if (timestamp < current_timestamp) {
+ mutexlock(emulator_timestamp->mutex);
+ emulator_timestamp->late_writes++;
+ mutexunlock(emulator_timestamp->mutex);
+ }
+
+ return 0;
+}
+
+/*! \brief Store noise in the buffer buff
+ * \param[out] buff A buffer for received samples.
+ * The buffers must be large enough to hold the number of samples \ref nsamps.
+ * \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
+ */
+static void read_noise(void *buff, int nsamps)
+{
+ int aligned_nsamps = ceil_mod(nsamps, (512 / 8) / sizeof(cf_t));
+ cf_t samples[aligned_nsamps] __attribute__((aligned(64)));
+ // Apply noise from global settings
+ get_noise_vector((float *)samples, nsamps * 2);
+
+ // Convert to c16_t
+ c16_t samples_out[aligned_nsamps] __attribute__((aligned(64)));
+#if defined(__AVX512F__)
+ for (int i = 0; i < aligned_nsamps / 8; i++) {
+ simde__m512 *in = (simde__m512 *)&samples[i * 8];
+ simde__m256i *out = (simde__m256i *)&samples_out[i * 8];
+ *out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in));
+ }
+#elif defined(__AVX2__)
+ for (int i = 0; i < aligned_nsamps / 4; i++) {
+ simde__m256 *in = (simde__m256 *)&samples[i * 4];
+ simde__m128i *out = (simde__m128i *)&samples_out[i * 4];
+ *out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in));
+ }
+#else
+ for (int i = 0; i < nsamps; i++) {
+ samples_out[i].r = lroundf(samples[i].r);
+ samples_out[i].i = lroundf(samples[i].i);
+ }
+#endif
+ memcpy(buff, samples_out, nsamps * sizeof(c16_t));
+}
+
+/*! \brief Receive samples from hardware.
+ * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
+ * the first channel.
+ * \param[out] ptimestamp time at which the first sample was received.
+ * \param device pointer to the device structure specific to the RF hardware target
+ * \param[out] ptimestamp the time at which the first sample was received.
+ * \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of
+ * samples \ref nsamps. \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
+ * \param nbAnt number of antennas
+ * \returns the number of samples read
+ */
+static int emulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int nbAnt)
+{
+ emulator_state_t *emulator_state = (emulator_state_t *)device->priv;
+
+ emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp;
+ uint64_t timestamp = emulator_state->last_received_sample + nsamps;
+ uint64_t current_timestamp = emulator_timestamp->timestamp;
+ if (current_timestamp < timestamp) {
+ mutexlock(emulator_timestamp->mutex);
+ while (current_timestamp < timestamp) {
+ condwait(emulator_timestamp->cond, emulator_timestamp->mutex);
+ current_timestamp = emulator_timestamp->timestamp;
+ }
+ mutexunlock(emulator_timestamp->mutex);
+ } else {
+ mutexlock(emulator_timestamp->mutex);
+ emulator_timestamp->late_reads++;
+ mutexunlock(emulator_timestamp->mutex);
+ }
+ *ptimestamp = emulator_state->last_received_sample;
+ emulator_state->last_received_sample += nsamps;
+
+ if (emulator_state->enable_noise > 0) {
+ for (int i = 0; i < nbAnt; i++) {
+ read_noise(buff[i], nsamps);
+ }
+ } else {
+ for (int i = 0; i < nbAnt; i++) {
+ memset(buff[i], 0, nsamps * sizeof(c16_t));
+ }
+ }
+
+ return nsamps;
+}
+
+static void emulator_readconfig(emulator_state_t *emulator_state)
+{
+ paramdef_t emulator_params[] = RF_EMULATOR_PARAMS_DESC;
+ int ret = config_get(config_get_if(), emulator_params, sizeofArray(emulator_params), RF_EMULATOR_SECTION);
+ AssertFatal(ret >= 0, "configuration couldn't be performed\n");
+}
+
+int device_init(openair0_device *device, openair0_config_t *openair0_cfg)
+{
+ LOG_I(HW, "This is emulator RF that does nothing\n");
+
+ emulator_state_t *emulator_state = calloc_or_fail(1, sizeof(emulator_state_t));
+ emulator_state->last_received_sample = 0;
+ emulator_state->timescale = 1.0;
+ emulator_state->sample_rate = openair0_cfg->sample_rate;
+ emulator_state->run_timing_thread = false;
+
+ device->priv = emulator_state;
+ device->openair0_cfg = openair0_cfg;
+ device->trx_start_func = emulator_start;
+ device->trx_get_stats_func = emulator_get_stats;
+ device->trx_reset_stats_func = emulator_reset_stats;
+ device->trx_end_func = emulator_end;
+ device->trx_stop_func = emulator_stop;
+ device->trx_set_freq_func = emulator_set_freq;
+ device->trx_set_gains_func = emulator_set_gains;
+ device->trx_write_init = emulator_write_init;
+ device->type = RFSIMULATOR;
+ device->trx_write_func = emulator_write;
+ device->trx_read_func = emulator_read;
+
+ emulator_readconfig(emulator_state);
+
+ return 0;
+}
diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c
index 4eff24aacf..89c1838fa3 100644
--- a/radio/fhi_72/oran-config.c
+++ b/radio/fhi_72/oran-config.c
@@ -884,8 +884,6 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
for (int i = 1; i < oai0->rx_num_channels; ++i)
DevAssert(oai0->rx_freq[0] == oai0->rx_freq[i]);
DevAssert(oai0->nr_band > 0);
- AssertFatal(oai0->threequarter_fs == 0, "cannot use three-quarter sampling with O-RAN 7.2 split\n");
-
paramdef_t FHconfigs[] = ORAN_FH_DESC;
paramlist_def_t FH_ConfigList = {CONFIG_STRING_ORAN_FH};
char aprefix[MAX_OPTNAME_SIZE] = {0};
diff --git a/radio/vrtsim/CMakeLists.txt b/radio/vrtsim/CMakeLists.txt
index 79eb4d88da..c5ee458666 100644
--- a/radio/vrtsim/CMakeLists.txt
+++ b/radio/vrtsim/CMakeLists.txt
@@ -1,4 +1,31 @@
-add_library(vrtsim MODULE vrtsim.c noise_device.c)
+add_library(noise_device STATIC noise_device.c)
+
+add_library(vrtsim MODULE vrtsim.c)
set_target_properties(vrtsim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
-target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor)
+target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor noise_device)
add_dependencies(vrtsim generate_T)
+
+add_boolean_option(OAI_VRTSIM_TAPS_CLIENT OFF "Enable taps client" ON)
+if (OAI_VRTSIM_TAPS_CLIENT)
+ target_link_libraries(vrtsim PRIVATE taps_client)
+ file(DOWNLOAD
+ "https://gitlab.eurecom.fr/oai/raytracing-channel-emulator/-/raw/59589ad2a534881810b2aa7dd81e63066245bb8d/server/api/taps.fbs?inline=false"
+ ${CMAKE_SOURCE_DIR}/taps.fbs
+ )
+
+ set(TAPS_IF_PATH ${CMAKE_SOURCE_DIR}/taps.fbs)
+ set(TAPS_API_HEADER taps_generated.h)
+
+ add_custom_command(OUTPUT ${TAPS_API_HEADER}
+ COMMAND flatc -c ${TAPS_IF_PATH}
+ DEPENDS ${TAPS_IF_PATH}
+ COMMENT "Generating flatbuffers API from ${TAPS_IF_PATH}"
+ )
+ add_library(taps_api INTERFACE)
+ target_include_directories(taps_api INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
+
+ add_library(taps_client taps_client.cpp ${TAPS_API_HEADER})
+ target_include_directories(taps_client PUBLIC .)
+ find_package(Flatbuffers REQUIRED)
+ target_link_libraries(taps_client PUBLIC flatbuffers taps_api SIMU nanomsg)
+endif()
diff --git a/radio/vrtsim/README.md b/radio/vrtsim/README.md
index 71455175c3..2cd90e7886 100644
--- a/radio/vrtsim/README.md
+++ b/radio/vrtsim/README.md
@@ -4,12 +4,24 @@ This implements a shared memory realtime and near-realtime radio interface.
This is performed using `shm_td_iq_channel` which handles the shared memory
interface.
+# Architecture
+
+The `vrtsim` architecture follows a server-client model:
+
+- **Server (gNB)**: On startup, the server writes a file, default location is
+ `/tmp/vrtsim_connection`. This file contains information required by the client
+ to establish communication.
+- **Client (UE)**: The client reads this file from, verifies its contents, and uses
+ the provided information to open and connect to the shared memory channel.
+- **Shared Memory Channel**: Both server and client use the `shm_td_iq_channel` to
+ exchange IQ samples and control data in real time or near-real time.
+
+## Channel modelling:
+
+
# Limitations
- Only 1gNB to 1nrUE: gNB as a server, UE as a client.
- - Server only accepts connections during device bringup. This means that
- restarting the client will not make it reconnect, the server has to be
- restarted as well.
# Usage
@@ -21,5 +33,63 @@ is the default and means realtime.
Channel modelling can be enabled by adding `vrtsim.chanmod 1` to the
command line and should work the same as channel modelling in rfsimulator,
-see rfsimulator [documentation](../rfsimulator/README.md), provided that your
-CPU is fast enough.
+see rfsimulator [documentation](../rfsimulator/README.md) with a slight difference:
+channel modelling is done on transmission instead of reception. To refect this,
+the model names are slightly different: the server expects a model named
+`server_tx_channel_model` while the client expects a model named `client_tx_channel_model`
+
+Additionally, `taps_client` is available in vrtsim. This allows to connect to
+channel emulation server and receive external taps (or channel impulse responses).
+To use external taps, use `--taps-socket` and provide a nanomsg PUB socket address
+that will publish the taps.
+
+# Debugging
+
+## Realtime issues
+
+Realtime issues can prevent the UE from connecting to the gNB, especially with
+channel modelling enabled. Consider adjusting `timescale` parameter until
+the UE can connect reliably.
+
+On exit, vrtsim will output a histogram of the measured transmission budget, which
+is defined as the number of microseconds before the transmitted samples could be
+read by peer.
+
+Example:
+
+```
+[HW] VRTSIM: Average TX budget 939.210 uS (more is better)
+[HW] VRTSIM: TX budget histogram: 216 samples
+[HW] Bin 0 [0.0 - 100.0uS]: 0
+[HW] Bin 1 [100.0 - 200.0uS]: 0
+[HW] Bin 2 [200.0 - 300.0uS]: 0
+[HW] Bin 3 [300.0 - 400.0uS]: 0
+[HW] Bin 4 [400.0 - 500.0uS]: 0
+[HW] Bin 5 [500.0 - 600.0uS]: 0
+[HW] Bin 6 [600.0 - 700.0uS]: 0
+[HW] Bin 7 [700.0 - 800.0uS]: 0
+[HW] Bin 8 [800.0 - 900.0uS]: 0
+[HW] Bin 9 [900.0 - 1000.0uS]: 117
+[HW] Bin 10 [1000.0 - 1100.0uS]: 0
+[HW] Bin 11 [1100.0 - 1200.0uS]: 0
+[HW] Bin 12 [1200.0 - 1300.0uS]: 0
+[HW] Bin 13 [1300.0 - 1400.0uS]: 0
+[HW] Bin 14 [1400.0 - 1500.0uS]: 0
+[HW] Bin 15 [1500.0 - 1600.0uS]: 0
+[HW] Bin 16 [1600.0 - 1700.0uS]: 0
+[HW] Bin 17 [1700.0 - 1800.0uS]: 0
+[HW] Bin 18 [1800.0 - 1900.0uS]: 0
+[HW] Bin 19 [1900.0 - 2000.0uS]: 0
+[HW] Bin 20 [2000.0 - 2100.0uS]: 0
+[HW] Bin 21 [2100.0 - 2200.0uS]: 0
+[HW] Bin 22 [2200.0 - 2300.0uS]: 0
+[HW] Bin 23 [2300.0 - 2400.0uS]: 0
+[HW] Bin 24 [2400.0 - 2500.0uS]: 0
+[HW] Bin 25 [2500.0 - 2600.0uS]: 0
+[HW] Bin 26 [2600.0 - 2700.0uS]: 0
+[HW] Bin 27 [2700.0 - 2800.0uS]: 0
+[HW] Bin 28 [2800.0 - 2900.0uS]: 0
+[HW] Bin 29 [2900.0 - 3000.0uS]: 0
+```
+
+Samples in bin 0 indicate realtime issues.
diff --git a/radio/vrtsim/noise_device.c b/radio/vrtsim/noise_device.c
index 2e15944d4a..acb3a2b5da 100644
--- a/radio/vrtsim/noise_device.c
+++ b/radio/vrtsim/noise_device.c
@@ -18,6 +18,7 @@
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
+#include "assertions.h"
#include
#include
#include "noise_device.h"
@@ -74,7 +75,8 @@ void init_noise_device(float noise_power)
void free_noise_device(void)
{
state.running = false;
- pthread_join(state.noise_device_thread, NULL);
+ int ret = pthread_join(state.noise_device_thread, NULL);
+ AssertFatal(ret == 0, "pthread_join failed: %d, errno %d (%s)\n", ret, errno, strerror(errno));
}
void get_noise_vector(float *noise_vector, int length)
diff --git a/radio/vrtsim/taps_client.cpp b/radio/vrtsim/taps_client.cpp
new file mode 100644
index 0000000000..c314c3981c
--- /dev/null
+++ b/radio/vrtsim/taps_client.cpp
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ * contact@openairinterface.org
+ */
+#include
+#include
+#include
+#include
+#include
+#include "pthread.h"
+#include "taps_generated.h"
+#include "SIMULATION/TOOLS/sim.h"
+extern "C" {
+#include "assertions.h"
+#include "common/utils/LOG/log.h"
+#include "sim.h"
+#include "utils.h"
+}
+#include
+
+#define NUM_TAPS_BUFFERS 4
+#define MAX_TAPS_LEN 100
+#define MAX_TAPS_MSG_SIZE (sizeof(struct complexf) * MAX_TAPS_LEN * 4 * 4 + 20)
+
+static pthread_t client_thread;
+static bool should_run = true;
+typedef struct {
+ int id;
+ int sock;
+ uint32_t num_tx_antennas;
+ uint32_t num_rx_antennas;
+ channel_desc_t **channel_desc;
+} client_thread_args_t;
+
+typedef struct {
+ void *taps_msg;
+ channel_desc_t *channel_desc;
+} taps_buffer_t;
+
+typedef struct {
+ taps_buffer_t taps_buffers[NUM_TAPS_BUFFERS];
+ int current_buffer;
+} taps_storage_t;
+
+void ascii_line_plot(const float *data, size_t size, char *buffer)
+{
+ const char levels[] = "_.-=#"; // ASCII characters for different levels
+ size_t num_levels = sizeof(levels) - 1; // Number of levels (excluding the null terminator)
+
+ // Calculate min and max values from the data
+ float min_val = FLT_MAX;
+ float max_val = FLT_MIN;
+ for (size_t i = 0; i < size; i++) {
+ if (data[i] < min_val)
+ min_val = data[i];
+ if (data[i] > max_val)
+ max_val = data[i];
+ }
+
+ // Handle edge case where all values are the same
+ if (min_val == max_val) {
+ min_val -= 1.0f;
+ max_val += 1.0f;
+ }
+
+ // Normalize and map data to levels
+ for (size_t i = 0; i < size; i++) {
+ float normalized = (data[i] - min_val) / (max_val - min_val); // Normalize to [0, 1]
+ size_t level_index = (size_t)(normalized * num_levels); // Map to level index
+ if (level_index > num_levels)
+ level_index = num_levels; // Clamp to valid range
+ snprintf(buffer + i, 2, "%c", levels[level_index]);
+ }
+}
+
+static void init_taps_storage(taps_storage_t *storage, int num_tx_antennas, int num_rx_antennas)
+{
+ for (int i = 0; i < NUM_TAPS_BUFFERS; i++) {
+ storage->taps_buffers[i].taps_msg = calloc_or_fail(1, MAX_TAPS_MSG_SIZE);
+ storage->taps_buffers[i].channel_desc = (channel_desc_t *)calloc_or_fail(1, sizeof(channel_desc_t));
+ storage->taps_buffers[i].channel_desc->ch_ps =
+ (struct complexf **)calloc_or_fail(num_rx_antennas * num_tx_antennas, sizeof(struct complexf *));
+ }
+ storage->current_buffer = 0;
+}
+
+static taps_storage_t taps_storage;
+
+void *client_thread_func(void *args)
+{
+ client_thread_args_t *client_thread_args = (client_thread_args_t *)args;
+ while (should_run) {
+ int next_buffer = (taps_storage.current_buffer + 1) % NUM_TAPS_BUFFERS;
+ taps_buffer_t *taps_buffer = &taps_storage.taps_buffers[next_buffer];
+ int ret = nn_recv(client_thread_args->sock, taps_buffer->taps_msg, MAX_TAPS_MSG_SIZE, NN_DONTWAIT);
+ if (ret < 0) {
+ if (errno == EAGAIN) {
+ // Timeout: no message available, sleep briefly and continue
+ usleep(100);
+ continue;
+ }
+ LOG_E(HW, "nn_recv() failed: errno: %d, %s\n", errno, strerror(errno));
+ continue;
+ }
+ auto taps_message = Phy::GetTaps(taps_buffer->taps_msg);
+ if (taps_message->num_rx_antennas() != client_thread_args->num_rx_antennas
+ || taps_message->num_tx_antennas() != client_thread_args->num_tx_antennas) {
+ LOG_E(HW,
+ "Number of antennas mismatch: expected %d x %d, got %d x %d\n",
+ client_thread_args->num_rx_antennas,
+ client_thread_args->num_tx_antennas,
+ taps_message->num_rx_antennas(),
+ taps_message->num_tx_antennas());
+ continue;
+ }
+ channel_desc_t *channel_desc = taps_buffer->channel_desc;
+ const flatbuffers::Vector *taps = taps_message->taps();
+ struct complexf *base_pointer = (struct complexf *)taps->data();
+ int taps_len = taps_message->taps_len();
+ AssertFatal(taps_len < MAX_TAPS_LEN, "Too many samples in the taps array, taps_len = %d\n", taps_len);
+ for (unsigned int aarx = 0U; aarx < client_thread_args->num_rx_antennas; aarx++) {
+ for (unsigned int aatx = 0U; aatx < client_thread_args->num_tx_antennas; aatx++) {
+ channel_desc->ch_ps[aarx + (client_thread_args->num_rx_antennas * aatx)] =
+ &base_pointer[(aarx + (client_thread_args->num_rx_antennas * aatx)) * taps_len];
+ }
+ }
+ channel_desc->path_loss_dB = 0;
+ channel_desc->channel_length = taps_len;
+ *client_thread_args->channel_desc = channel_desc;
+ taps_storage.current_buffer = next_buffer;
+ LOG_A(HW, "Receved new taps message, channel_length %d, buffer %d\n", channel_desc->channel_length, next_buffer);
+ for (unsigned int aarx = 0; aarx < client_thread_args->num_rx_antennas; aarx++) {
+ for (unsigned int aatx = 0; aatx < client_thread_args->num_tx_antennas; aatx++) {
+ char buffer[MAX_TAPS_LEN + 1];
+ memset(buffer, 0, sizeof(buffer));
+ float magnitudes[MAX_TAPS_LEN];
+ cf_t *channel = channel_desc->ch_ps[aarx + (client_thread_args->num_rx_antennas * aatx)];
+ for (int i = 0; i < channel_desc->channel_length; i++) {
+ magnitudes[i] = sqrtf(powf(channel[i].r, 2) + powf(channel[i].i, 2));
+ }
+ ascii_line_plot(magnitudes, channel_desc->channel_length, buffer);
+ LOG_A(HW, "Taps message %d, channel %d x %d: %s\n", client_thread_args->id, aarx, aatx, buffer);
+ }
+ }
+ }
+ return NULL;
+}
+
+extern "C" void taps_client_connect(int id,
+ const char *socket_path,
+ int num_tx_antennas,
+ int num_rx_antennas,
+ channel_desc_t **channel_desc)
+{
+ // Create a socket
+ int sock = nn_socket(AF_SP, NN_SUB);
+ AssertFatal(sock >= 0, "nn_socket() failed: errno: %d, %s\n", errno, strerror(errno));
+
+ int ret = nn_connect(sock, socket_path);
+ AssertFatal(ret >= 0, "nn_connect() failed: errno: %d, %s\n", errno, strerror(errno));
+
+ // Subscribe to all messages
+ ret = nn_setsockopt(sock, NN_SUB, NN_SUB_SUBSCRIBE, "", 0);
+ AssertFatal(ret == 0, "nn_setsockopt() failed, errno %d, %s\n", errno, strerror(errno));
+
+ init_taps_storage(&taps_storage, num_tx_antennas, num_rx_antennas);
+
+ client_thread_args_t *client_thread_args = static_cast(malloc(sizeof(client_thread_args_t)));
+ client_thread_args->id = id;
+ client_thread_args->sock = sock;
+ client_thread_args->num_rx_antennas = num_rx_antennas;
+ client_thread_args->num_tx_antennas = num_tx_antennas;
+ client_thread_args->channel_desc = channel_desc;
+ ret = pthread_create(&client_thread, NULL, client_thread_func, client_thread_args);
+ AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno));
+}
+
+extern "C" void taps_client_stop()
+{
+ should_run = false;
+ pthread_join(client_thread, NULL);
+ for (int i = 0; i < NUM_TAPS_BUFFERS; i++) {
+ free(taps_storage.taps_buffers[i].taps_msg);
+ free(taps_storage.taps_buffers[i].channel_desc->ch_ps);
+ free(taps_storage.taps_buffers[i].channel_desc);
+ }
+}
diff --git a/openair3/S1AP/s1ap_common.c b/radio/vrtsim/taps_client.h
similarity index 75%
rename from openair3/S1AP/s1ap_common.c
rename to radio/vrtsim/taps_client.h
index d31c6e5839..c0a577c787 100644
--- a/openair3/S1AP/s1ap_common.c
+++ b/radio/vrtsim/taps_client.h
@@ -19,23 +19,20 @@
* contact@openairinterface.org
*/
-/*! \file s1ap_common.c
- * \brief s1ap procedures for both eNB and MME
- * \author Sebastien ROUX and Navid Nikaein
- * \email navid.nikaein@eurecom.fr
- * \date 2012-2015
- * \version 0.1
- */
+#ifndef TAPS_CLIENT_H
+#define TAPS_CLIENT_H
-#include
+#ifdef __cplusplus
+extern "C" {
+#endif
-#include "s1ap_common.h"
-#include "S1AP_S1AP-PDU.h"
+#include "sim.h"
+void taps_client_connect(int id, const char *socket_path, int num_tx_antennas, int num_rx_antennas, channel_desc_t **channel_desc);
+void taps_client_stop();
-int asn1_xer_print = 0;
-
-
-void s1ap_handle_criticality(S1AP_Criticality_t criticality)
-{
+#ifdef __cplusplus
}
+#endif
+
+#endif
diff --git a/radio/vrtsim/vrtsim.c b/radio/vrtsim/vrtsim.c
index f0e0151aa6..9e678a5305 100644
--- a/radio/vrtsim/vrtsim.c
+++ b/radio/vrtsim/vrtsim.c
@@ -19,6 +19,7 @@
* contact@openairinterface.org
*/
+#include "PHY/TOOLS/tools_defs.h"
#include
#include
#include
@@ -34,6 +35,7 @@
#include
#include
#include
+#include
#include
#include
@@ -46,11 +48,13 @@
#include "actor.h"
#include "noise_device.h"
#include "simde/x86/avx512.h"
+#include "taps_client.h"
// Simulator role
typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role;
-#define NUM_CHANMOD_THREADS 1
+#define MAX_NUM_ANTENNAS_TX 4
+#define MAX_CHANNEL_LENGTH (1 << 20)
#define ROLE_CLIENT_STRING "client"
#define ROLE_SERVER_STRING "server"
@@ -58,14 +62,21 @@ typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role;
#define VRTSIM_SECTION "vrtsim"
#define TIME_SCALE_HLP \
"sample time scale. 1.0 means realtime. Values > 1 mean faster than realtime. Values < 1 mean slower than realtime\n"
+#define TAPS_SOCKET_HLP "Socket to connect to the channel emulation server\n"
+#define CLIENT_NUM_RX_HLP "Number of RX antennas of the client, specified on the server\n"
+#define CONNECTION_DESCRIPTOR_HLP "Path to the file written by the server that the client can use to connect."
+#define DEFAULT_CHANNEL_NAME "vrtsim_channel"
+#define DEFAULT_DESCRIPTOR "/tmp/vrtsim_connection"
// clang-format off
#define VRTSIM_PARAMS_DESC \
{ \
- {"channel_name", "shared memory channel name\n", 0, .strptr = &channel_name, .defstrval = "vrtsim_channel", TYPE_STRING, 0}, \
- {"role", "either client or server\n", 0, .strptr = &role, .defstrval = ROLE_CLIENT_STRING, TYPE_STRING, 0}, \
- {"timescale", TIME_SCALE_HLP, 0, .dblptr = &vrtsim_state->timescale, .defdblval = 1.0, TYPE_DOUBLE, 0}, \
- {"chanmod", "Enable channel modelling", 0, .iptr = &vrtsim_state->chanmod, .defintval = 0, TYPE_INT, 0}, \
+ {"connection_descriptor", CONNECTION_DESCRIPTOR_HLP, 0, .strptr = &vrtsim_state->connection_descriptor, .defstrval = DEFAULT_DESCRIPTOR, TYPE_STRING, 0}, \
+ {"role", "either client or server\n", 0, .strptr = &role, .defstrval = ROLE_CLIENT_STRING, TYPE_STRING, 0}, \
+ {"timescale", TIME_SCALE_HLP, 0, .dblptr = &vrtsim_state->timescale, .defdblval = 1.0, TYPE_DOUBLE, 0}, \
+ {"chanmod", "Enable channel modelling", 0, .iptr = &vrtsim_state->chanmod, .defintval = 0, TYPE_INT, 0}, \
+ {"taps-socket", TAPS_SOCKET_HLP, 0, .strptr = &vrtsim_state->taps_socket, .defstrval = NULL, TYPE_STRING, 0}, \
+ {"client-num-rx-antennas", CLIENT_NUM_RX_HLP, 0, .iptr = &vrtsim_state->client_num_rx_antennas, .defintval = 1, TYPE_INT, 0}, \
};
// clang-format on
@@ -91,7 +102,7 @@ typedef struct tx_timing_s {
typedef struct {
int role;
- char channel_name[40];
+ char *connection_descriptor;
ShmTDIQChannel *channel;
uint64_t last_received_sample;
pthread_t timing_thread;
@@ -110,8 +121,13 @@ typedef struct {
int rx_num_channels;
channel_desc_t *channel_desc;
Actor_t *channel_modelling_actors;
+ char *taps_socket;
+ int client_num_rx_antennas;
} vrtsim_state_t;
+// Sample history for channel impulse response
+static c16_t saved_samples[MAX_NUM_ANTENNAS_TX][MAX_CHANNEL_LENGTH] __attribute__((aligned(32))) = {0};
+
static void histogram_add(histogram_t *histogram, double diff)
{
histogram->num_samples++;
@@ -149,18 +165,26 @@ static void load_channel_model(vrtsim_state_t *vrtsim_state)
vrtsim_state->tx_bw);
char *model_name = vrtsim_state->role == ROLE_CLIENT ? "client_tx_channel_model" : "server_tx_channel_model";
vrtsim_state->channel_desc = find_channel_desc_fromname(model_name);
+ AssertFatal(vrtsim_state->channel_desc != NULL,
+ "Could not find model name %s. Make sure it is present in the config file",
+ model_name);
+ LOG_I(HW,
+ "Channel model %s parameters: path_loss_dB=%.2f, nb_tx=%d, nb_rx=%d, channel_length=%d\n",
+ model_name,
+ vrtsim_state->channel_desc->path_loss_dB,
+ vrtsim_state->channel_desc->nb_tx,
+ vrtsim_state->channel_desc->nb_rx,
+ vrtsim_state->channel_desc->channel_length);
random_channel(vrtsim_state->channel_desc, 0);
AssertFatal(vrtsim_state->channel_desc != NULL, "Could not find channel model %s\n", model_name);
}
static void vrtsim_readconfig(vrtsim_state_t *vrtsim_state)
{
- char *channel_name = NULL;
char *role = NULL;
paramdef_t vrtsim_params[] = VRTSIM_PARAMS_DESC;
int ret = config_get(config_get_if(), vrtsim_params, sizeofArray(vrtsim_params), VRTSIM_SECTION);
AssertFatal(ret >= 0, "configuration couldn't be performed\n");
- strncpy(vrtsim_state->channel_name, channel_name, sizeof(vrtsim_state->channel_name) - 1);
if (strncmp(role, ROLE_CLIENT_STRING, strlen(ROLE_CLIENT_STRING)) == 0) {
vrtsim_state->role = ROLE_CLIENT;
} else if (strncmp(role, ROLE_SERVER_STRING, strlen(ROLE_SERVER_STRING)) == 0) {
@@ -168,6 +192,15 @@ static void vrtsim_readconfig(vrtsim_state_t *vrtsim_state)
} else {
AssertFatal(false, "Invalid role configuration\n");
}
+#ifdef ENABLE_TAPS_CLIENT
+ if (vrtsim_state->taps_socket) {
+ LOG_A(HW, "VRTSIM: will use taps socket %s\n", vrtsim_state->taps_socket);
+ }
+#else
+ if (vrtsim_state->taps_socket) {
+ AssertFatal(false, "Invalid configuration: Build with ENABLE_TAPS_CLIENT to use taps socket\n");
+ }
+#endif
}
static void *vrtsim_timing_job(void *arg)
@@ -195,128 +228,105 @@ static void *vrtsim_timing_job(void *arg)
samples_to_produce += 1;
leftover_samples -= 1;
}
+ AssertFatal(samples_to_produce >= 0, "Negative samples to produce: %f\n", samples_to_produce);
shm_td_iq_channel_produce_samples(vrtsim_state->channel, samples_to_produce);
usleep(1);
}
return 0;
}
+typedef struct client_info_s {
+ int server_num_rx_antennas;
+ int client_num_rx_antennas;
+} client_info_t;
+
/**
- * @brief Exchanges peer information between the server and the client.
+ * @brief Publishes the client information information to a file for the client to read.
*
- * This function sets up a Unix domain socket server, waits for a client to connect,
- * and exchanges peer information (number of RX antennas) with the client.
+ * The server writes its client_info (number of RX antennas) to a file, which the client reads.
+ * The server does not wait for the client to write back; the client can connect at any point.
*
- * @param peer_info The peer information to send to the client.
- * @return The peer information received from the client.
- *
- * @note This function will block until a client connects and the information is exchanged.
+ * @param client_info The client information to publish.
+ * @return The peer information (same as input, server is authoritative).
*/
-static peer_info_t server_exchange_peer_info(peer_info_t peer_info)
+static void server_publish_client_info(client_info_t client_info, char *descriptor_file)
{
- int server_fd, client_fd;
-
- // Create a Unix domain socket
- server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- AssertFatal(server_fd >= 0, "socket() failed: errno: %d, %s\n", errno, strerror(errno));
-
- // Bind the socket to a file path
- struct sockaddr_un addr = {.sun_family = AF_UNIX};
- strncpy(addr.sun_path, "/tmp/vrtsim_socket", sizeof(addr.sun_path) - 1);
- unlink(addr.sun_path); // Ensure the path does not already exist
- int ret = bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
- AssertFatal(ret == 0, "bind() failed: errno: %d, %s\n", errno, strerror(errno));
-
- // Listen for incoming connections
- ret = listen(server_fd, 1);
- AssertFatal(ret == 0, "listen() failed: errno: %d, %s\n", errno, strerror(errno));
-
- // Accept a connection from a client
- socklen_t addr_len = sizeof(addr);
- client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
- AssertFatal(client_fd >= 0, "accept() failed: errno: %d, %s\n", errno, strerror(errno));
-
- // Send the antenna info to the server
- ssize_t bytes_sent = send(client_fd, &peer_info, sizeof(peer_info), 0);
- AssertFatal(bytes_sent == sizeof(peer_info), "send() failed: errno: %d, %s\n", errno, strerror(errno));
-
- ssize_t bytes_received = recv(client_fd, &peer_info, sizeof(peer_info), 0);
- AssertFatal(bytes_received == sizeof(peer_info), "recv() failed: errno: %d, %s\n", errno, strerror(errno));
-
- LOG_I(HW, "Received client info: RX %d\n", peer_info.num_rx_antennas);
-
- // Close the client and server sockets
- close(client_fd);
- close(server_fd);
- return peer_info;
+ FILE *fp = fopen(descriptor_file, "wb");
+ AssertFatal(fp != NULL, "Failed to open client info file for writing: %s\n", strerror(errno));
+ size_t written = fwrite(&client_info, sizeof(client_info), 1, fp);
+ AssertFatal(written == 1, "Failed to write client info to file\n");
+ fclose(fp);
}
-/**
- * @brief Exchanges peer information between the client and the server.
- *
- * This function connects to a Unix domain socket server, exchanges peer information
- * (number of RX antennas) with the server, and returns the peer information received
- * from the server.
- *
- * @param peer_info The peer information to send to the server.
- * @return The peer information received from the server.
- *
- * @note This function will block until the information is exchanged.
- */
-static peer_info_t client_exchange_peer_info(peer_info_t peer_info)
+static client_info_t client_read_info(char *descriptor_file)
{
- int client_fd;
-
- // Create a Unix domain socket
- client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- AssertFatal(client_fd >= 0, "socket() failed: errno: %d, %s\n", errno, strerror(errno));
-
- // Connect to the server
- struct sockaddr_un addr = {.sun_family = AF_UNIX};
- strncpy(addr.sun_path, "/tmp/vrtsim_socket", sizeof(addr.sun_path) - 1);
- int ret = -1;
+ client_info_t client_info;
int tries = 0;
- while (ret != 0 && tries < 10) {
- ret = connect(client_fd, (struct sockaddr *)&addr, sizeof(addr));
- tries++;
+ while (tries < 10) {
+ FILE *fp = fopen(descriptor_file, "rb");
+ if (fp) {
+ size_t read = fread(&client_info, sizeof(client_info), 1, fp);
+ fclose(fp);
+ if (read == 1) {
+ return client_info;
+ }
+ }
sleep(1);
+ tries++;
}
- AssertFatal(ret == 0, "connect() failed: errno: %d, %s\n", errno, strerror(errno));
-
- peer_info_t peer_info_received;
- ssize_t bytes_received = recv(client_fd, &peer_info_received, sizeof(peer_info_received), 0);
- AssertFatal(bytes_received == sizeof(peer_info_received), "recv() failed: errno: %d, %s\n", errno, strerror(errno));
-
- // Send the antenna info to the server
- ssize_t bytes_sent = send(client_fd, &peer_info, sizeof(peer_info), 0);
- AssertFatal(bytes_sent == sizeof(peer_info), "send() failed: errno: %d, %s\n", errno, strerror(errno));
-
- LOG_I(HW, "Received peer info: RX %d\n", peer_info_received.num_rx_antennas);
-
- // Close the client socket
- close(client_fd);
- return peer_info_received;
+ AssertFatal(0, "Timeout waiting for client info\n");
+ return client_info;
}
static int vrtsim_connect(openair0_device *device)
{
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
- // Exchange peer info
- peer_info_t peer_info = {.num_rx_antennas = device->openair0_cfg[0].rx_num_channels};
+
+ // Setup a shared memory channel
if (vrtsim_state->role == ROLE_SERVER) {
- vrtsim_state->peer_info = server_exchange_peer_info(peer_info);
+ vrtsim_state->peer_info.num_rx_antennas = vrtsim_state->client_num_rx_antennas;
+ vrtsim_state->channel = shm_td_iq_channel_create(DEFAULT_CHANNEL_NAME,
+ vrtsim_state->peer_info.num_rx_antennas,
+ device->openair0_cfg[0].rx_num_channels);
+ // Exchange peer info
+ client_info_t client_info = {
+ .server_num_rx_antennas = device->openair0_cfg[0].rx_num_channels,
+ .client_num_rx_antennas = vrtsim_state->client_num_rx_antennas,
+ };
+ server_publish_client_info(client_info, vrtsim_state->connection_descriptor);
+
+ vrtsim_state->run_timing_thread = true;
+ int ret = pthread_create(&vrtsim_state->timing_thread, NULL, vrtsim_timing_job, vrtsim_state);
+ AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno));
} else {
- vrtsim_state->peer_info = client_exchange_peer_info(peer_info);
+ client_info_t client_info = client_read_info(vrtsim_state->connection_descriptor);
+ AssertFatal(client_info.server_num_rx_antennas > 0, "Server did not publish valid client info, aborting client connection\n");
+ AssertFatal(
+ client_info.client_num_rx_antennas == device->openair0_cfg[0].rx_num_channels,
+ "Server expects different number of RX antennas. %d != %d. Use server command line option --client-num-rx-antennas\n",
+ client_info.client_num_rx_antennas,
+ device->openair0_cfg[0].rx_num_channels);
+ vrtsim_state->channel = shm_td_iq_channel_connect(DEFAULT_CHANNEL_NAME, 10);
+ vrtsim_state->peer_info.num_rx_antennas = client_info.server_num_rx_antennas;
+ vrtsim_state->last_received_sample = shm_td_iq_channel_get_current_sample(vrtsim_state->channel);
}
// Handle channel modelling after number of RX antennas are known
int num_tx_stats = 1;
- if (vrtsim_state->chanmod) {
+ if (vrtsim_state->chanmod || vrtsim_state->taps_socket) {
vrtsim_state->channel_modelling_actors = calloc_or_fail(vrtsim_state->peer_info.num_rx_antennas, sizeof(Actor_t));
for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) {
init_actor(&vrtsim_state->channel_modelling_actors[i], "chanmod", -1);
}
- load_channel_model(vrtsim_state);
+ if (vrtsim_state->taps_socket) {
+ taps_client_connect(0,
+ vrtsim_state->taps_socket,
+ device->openair0_cfg[0].tx_num_channels,
+ vrtsim_state->peer_info.num_rx_antennas,
+ &vrtsim_state->channel_desc);
+ } else {
+ load_channel_model(vrtsim_state);
+ }
num_tx_stats = vrtsim_state->peer_info.num_rx_antennas;
}
vrtsim_state->tx_timing = calloc_or_fail(num_tx_stats, sizeof(tx_timing_t));
@@ -326,22 +336,6 @@ static int vrtsim_connect(openair0_device *device)
vrtsim_state->tx_timing[i].tx_histogram.range = 3000.0;
}
- // Setup a shared memory channel
- if (vrtsim_state->role == ROLE_SERVER) {
- vrtsim_state->channel = shm_td_iq_channel_create(vrtsim_state->channel_name,
- vrtsim_state->peer_info.num_rx_antennas,
- device->openair0_cfg[0].rx_num_channels);
- vrtsim_state->run_timing_thread = true;
- while (!shm_td_iq_channel_is_connected(vrtsim_state->channel)) {
- LOG_I(HW, "Waiting for client\n");
- sleep(1);
- }
- int ret = pthread_create(&vrtsim_state->timing_thread, NULL, vrtsim_timing_job, vrtsim_state);
- AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno));
- } else {
- vrtsim_state->channel = shm_td_iq_channel_connect(vrtsim_state->channel_name, 10);
- }
-
return 0;
}
@@ -376,7 +370,7 @@ static int vrtsim_write_internal(vrtsim_state_t *vrtsim_state,
typedef struct {
vrtsim_state_t *vrtsim_state;
openair0_timestamp timestamp;
- c16_t *samples[4];
+ c16_t *samples[MAX_NUM_ANTENNAS_TX];
int nsamps;
int nbAnt;
int flags;
@@ -386,6 +380,7 @@ typedef struct {
static void perform_channel_modelling(void *arg)
{
channel_modelling_args_t *channel_modelling_args = arg;
+ vrtsim_state_t *vrtsim_state = channel_modelling_args->vrtsim_state;
int nsamps = channel_modelling_args->nsamps;
int aarx = channel_modelling_args->aarx;
int nb_tx_ant = channel_modelling_args->nbAnt;
@@ -396,31 +391,43 @@ static void perform_channel_modelling(void *arg)
// Apply noise from global settings
get_noise_vector((float *)samples, nsamps * 2);
- channel_desc_t *channel_desc = channel_modelling_args->vrtsim_state->channel_desc;
- const float pathloss_linear = powf(10, channel_desc->path_loss_dB / 20.0);
+ channel_desc_t *channel_desc = vrtsim_state->channel_desc;
+
+ if (channel_desc == NULL) {
+ return;
+ }
- // Convert channel impulse response to float + apply pathloss
cf_t channel_impulse_response[nb_tx_ant][channel_desc->channel_length];
- for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
- const struct complexd *channelModel = channel_desc->ch[aarx + (aatx * channel_desc->nb_rx)];
- for (int i = 0; i < channel_desc->channel_length; i++) {
- channel_impulse_response[aatx][i].r = channelModel[i].r * pathloss_linear;
- channel_impulse_response[aatx][i].i = channelModel[i].i * pathloss_linear;
+ cf_t *channel_impulse_response_p[nb_tx_ant];
+ if (!vrtsim_state->taps_socket) {
+ const float pathloss_linear = powf(10, channel_desc->path_loss_dB / 20.0);
+ // Convert channel impulse response to float + apply pathloss
+ for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
+ const struct complexd *channelModel = channel_desc->ch[aarx + (aatx * channel_desc->nb_rx)];
+ for (int i = 0; i < channel_desc->channel_length; i++) {
+ channel_impulse_response[aatx][i].r = channelModel[i].r * pathloss_linear;
+ channel_impulse_response[aatx][i].i = channelModel[i].i * pathloss_linear;
+ }
+ channel_impulse_response_p[aatx] = channel_impulse_response[aatx];
+ }
+ } else {
+ for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
+ struct complexf *channelModel = channel_desc->ch_ps[aarx + (aatx * channel_desc->nb_rx)];
+ channel_impulse_response_p[aatx] = channelModel;
}
}
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
+ c16_t *previous_samples = saved_samples[aatx];
for (int i = 0; i < nsamps; i++) {
- cf_t *impulse_response = channel_impulse_response[aatx];
+ cf_t *impulse_response = channel_impulse_response_p[aatx];
for (int l = 0; l < channel_desc->channel_length; l++) {
int idx = i - l;
- // TODO: Use AVX512 for this
- // TODO: What are the previously sent samples (for impulse response)
- if (idx >= 0) {
- c16_t tx_input = input_samples[aatx][idx];
- samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i;
- samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i;
- }
+ // TODO: Use AVX2 for this
+ c16_t tx_input = idx >= 0 ? input_samples[aatx][idx]
+ : previous_samples[(channel_modelling_args->timestamp + i + idx) % MAX_CHANNEL_LENGTH];
+ samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i;
+ samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i;
}
}
}
@@ -462,6 +469,7 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state,
int nbAnt,
int flags)
{
+ AssertFatal(nbAnt < MAX_NUM_ANTENNAS_TX, "Number of antennas %d exceeds maximum %d\n", nbAnt, MAX_NUM_ANTENNAS_TX);
for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) {
notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling);
channel_modelling_args_t *args = (channel_modelling_args_t *)NotifiedFifoData(task);
@@ -476,21 +484,68 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state,
}
pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task);
}
+ int start_index = timestamp % MAX_CHANNEL_LENGTH;
+ int end_index = min(start_index + nsamps, MAX_CHANNEL_LENGTH);
+ int cp_nsamps = end_index - start_index;
+ for (int aatx = 0; aatx < nbAnt; aatx++) {
+ c16_t *samples = (c16_t *)samplesVoid[aatx];
+ memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * cp_nsamps);
+ }
+
+ if (end_index < start_index + nsamps) {
+ // wrap around condition, write at beginning of buffer
+ cp_nsamps = nsamps - cp_nsamps; // remaining samples
+ start_index = 0;
+ for (int aatx = 0; aatx < nbAnt; aatx++) {
+ c16_t *samples = (c16_t *)samplesVoid[aatx];
+ memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * cp_nsamps);
+ }
+ }
return nsamps;
}
static int vrtsim_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags)
{
+ AssertFatal(nsamps > 0, "Number of samples must be greater than 0\n");
+ AssertFatal(nbAnt > 0 && nbAnt <= MAX_NUM_ANTENNAS_TX,
+ "Number of antennas %d must be between 1 and %d\n",
+ nbAnt,
+ MAX_NUM_ANTENNAS_TX);
+ AssertFatal(timestamp >= 0, "Timestamp must be non-negative, got %ld\n", timestamp);
timestamp -= device->openair0_cfg->command_line_sample_advance;
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
- return vrtsim_state->chanmod ? vrtsim_write_with_chanmod(vrtsim_state, timestamp, samplesVoid, nsamps, nbAnt, flags)
- : vrtsim_write_internal(vrtsim_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0);
+ bool channel_modelling = vrtsim_state->chanmod || vrtsim_state->taps_socket;
+ return channel_modelling ? vrtsim_write_with_chanmod(vrtsim_state, timestamp, samplesVoid, nsamps, nbAnt, flags)
+ : vrtsim_write_internal(vrtsim_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0);
}
static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt)
{
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
- shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps);
+ if (shm_td_iq_channel_is_aborted(vrtsim_state->channel)) {
+ return 0;
+ }
+ if (vrtsim_state->role == ROLE_SERVER) {
+ uint64_t timeout_uS = 0; // 0 means no timeout
+ shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps, timeout_uS);
+ } else {
+ uint64_t start_sample = shm_td_iq_channel_get_current_sample(vrtsim_state->channel);
+ uint64_t timeout_uS = 2 * 1000 * 1000; // 2 seconds timeout waiting for sample number to change
+ //
+ while (shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps, timeout_uS) == 1) {
+ uint64_t sample = shm_td_iq_channel_get_current_sample(vrtsim_state->channel);
+ if (sample == start_sample) {
+ LOG_E(HW,
+ "VRTSIM: Read timeout waiting for sample %lu to change, aborting channel\n",
+ vrtsim_state->last_received_sample + nsamps);
+ shm_td_iq_channel_abort(vrtsim_state->channel);
+ break;
+ } else {
+ start_sample = sample;
+ }
+ }
+ }
+
int ret = shm_td_iq_channel_rx(vrtsim_state->channel, vrtsim_state->last_received_sample, nsamps, 0, samplesVoid[0]);
if (ret == CHANNEL_ERROR_TOO_LATE) {
vrtsim_state->rx_samples_late += nsamps;
@@ -506,14 +561,14 @@ static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp,
static void vrtsim_end(openair0_device *device)
{
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
- if (vrtsim_state->role == ROLE_SERVER) {
+ if (vrtsim_state->role == ROLE_SERVER && vrtsim_state->run_timing_thread) {
vrtsim_state->run_timing_thread = false;
int ret = pthread_join(vrtsim_state->timing_thread, NULL);
AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno));
}
tx_timing_t *tx_timing = vrtsim_state->tx_timing;
- if (vrtsim_state->chanmod) {
+ if (vrtsim_state->chanmod || vrtsim_state->taps_socket) {
for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) {
shutdown_actor(&vrtsim_state->channel_modelling_actors[i]);
}
@@ -526,9 +581,12 @@ static void vrtsim_end(openair0_device *device)
tx_timing->tx_samples_total += tx_timing[i].tx_samples_total;
}
tx_timing->average_tx_budget /= vrtsim_state->peer_info.num_rx_antennas;
+ free_noise_device();
+ if (vrtsim_state->taps_socket) {
+ taps_client_stop();
+ }
}
- // produce 1 second of extra samples so threads can finish
- shm_td_iq_channel_produce_samples(vrtsim_state->channel, vrtsim_state->sample_rate);
+ shm_td_iq_channel_abort(vrtsim_state->channel);
sleep(1);
shm_td_iq_channel_destroy(vrtsim_state->channel);
@@ -540,9 +598,18 @@ static void vrtsim_end(openair0_device *device)
"VRTSIM: Read/write too early (suspected radio implementaton error) TX: %lu, RX: %lu\n",
tx_timing->tx_early,
vrtsim_state->rx_early);
- LOG_I(HW, "VRTSIM: Average TX budget %.3lf uS\n", tx_timing->average_tx_budget);
+ LOG_I(HW, "VRTSIM: Average TX budget %.3lf uS (more is better)\n", tx_timing->average_tx_budget);
histogram_print(&tx_timing->tx_histogram);
free(vrtsim_state->tx_timing);
+
+ if (vrtsim_state->role == ROLE_SERVER) {
+ int ret = remove(vrtsim_state->connection_descriptor);
+ if (ret != 0) {
+ LOG_E(HW, "Failed to remove connection descriptor file %s: %s\n", vrtsim_state->connection_descriptor, strerror(errno));
+ } else {
+ LOG_A(HW, "Removed connection descriptor file %s\n", vrtsim_state->connection_descriptor);
+ }
+ }
}
static int vrtsim_stub(openair0_device *device)
@@ -588,10 +655,11 @@ __attribute__((__visibility__("default"))) int device_init(openair0_device *devi
vrtsim_state->tx_num_channels = openair0_cfg->tx_num_channels;
vrtsim_state->rx_num_channels = openair0_cfg->rx_num_channels;
- if (vrtsim_state->chanmod) {
+ if (vrtsim_state->chanmod || vrtsim_state->taps_socket) {
init_channelmod();
int noise_power_dBFS = get_noise_power_dBFS();
int16_t noise_power = noise_power_dBFS == INVALID_DBFS_VALUE ? 0 : (int16_t)(32767.0 / powf(10.0, .05 * -noise_power_dBFS));
+ LOG_A(HW, "VRTSIM: Noise power %d sample value\n", noise_power);
init_noise_device(noise_power);
}
return 0;